rippled
Loading...
Searching...
No Matches
LoadManager.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/app/main/Application.h>
21#include <xrpld/app/main/LoadManager.h>
22#include <xrpld/app/misc/LoadFeeTrack.h>
23#include <xrpld/app/misc/NetworkOPs.h>
24
25#include <xrpl/beast/core/CurrentThreadName.h>
26#include <xrpl/json/to_string.h>
27
28#include <memory>
29#include <mutex>
30#include <thread>
31
32namespace ripple {
33
35 : app_(app), journal_(journal), deadLock_(), armed_(false)
36{
37}
38
40{
41 try
42 {
43 stop();
44 }
45 catch (std::exception const& ex)
46 {
47 // Swallow the exception in a destructor.
48 JLOG(journal_.warn())
49 << "std::exception in ~LoadManager. " << ex.what();
50 }
51}
52
53//------------------------------------------------------------------------------
54
55void
57{
59 armed_ = true;
61}
62
63void
65{
66 auto const detector_start = std::chrono::steady_clock::now();
68 deadLock_ = detector_start;
69}
70
71//------------------------------------------------------------------------------
72
73void
75{
76 JLOG(journal_.debug()) << "Starting";
77 XRPL_ASSERT(
79 "ripple::LoadManager::start : thread not joinable");
80
82}
83
84void
86{
87 {
89 stop_ = true;
90 // There is at most one thread waiting on this condition.
92 }
93 if (thread_.joinable())
94 {
95 JLOG(journal_.debug()) << "Stopping";
96 thread_.join();
97 }
98}
99
100//------------------------------------------------------------------------------
101
102void
104{
105 beast::setCurrentThreadName("LoadManager");
106
107 using namespace std::chrono_literals;
108 using clock_type = std::chrono::steady_clock;
109
110 auto t = clock_type::now();
111
112 while (true)
113 {
114 t += 1s;
115
117 if (cv_.wait_until(sl, t, [this] { return stop_; }))
118 break;
119
120 // Copy out shared data under a lock. Use copies outside lock.
121 auto const deadLock = deadLock_;
122 auto const armed = armed_;
123 sl.unlock();
124
125 // Measure the amount of time we have been deadlocked, in seconds.
126 using namespace std::chrono;
127 auto const timeSpentDeadlocked =
128 duration_cast<seconds>(steady_clock::now() - deadLock);
129
130 constexpr auto reportingIntervalSeconds = 10s;
131 constexpr auto deadlockFatalLogMessageTimeLimit = 90s;
132 constexpr auto deadlockLogicErrorTimeLimit = 600s;
133
134 if (armed && (timeSpentDeadlocked >= reportingIntervalSeconds))
135 {
136 // Report the deadlocked condition every
137 // reportingIntervalSeconds
138 if ((timeSpentDeadlocked % reportingIntervalSeconds) == 0s)
139 {
140 if (timeSpentDeadlocked < deadlockFatalLogMessageTimeLimit)
141 {
142 JLOG(journal_.warn())
143 << "Server stalled for " << timeSpentDeadlocked.count()
144 << " seconds.";
146 {
147 JLOG(journal_.warn()) << app_.getJobQueue().getJson(0);
148 }
149 }
150 else
151 {
152 JLOG(journal_.fatal())
153 << "Deadlock detected. Deadlocked time: "
154 << timeSpentDeadlocked.count() << "s";
155 JLOG(journal_.fatal())
156 << "JobQueue: " << app_.getJobQueue().getJson(0);
157 }
158 }
159
160 // If we go over the deadlockTimeLimit spent deadlocked, it
161 // means that the deadlock resolution code has failed, which
162 // qualifies as undefined behavior.
163 //
164 if (timeSpentDeadlocked >= deadlockLogicErrorTimeLimit)
165 {
166 JLOG(journal_.fatal())
167 << "LogicError: Deadlock detected. Deadlocked time: "
168 << timeSpentDeadlocked.count() << "s";
169 JLOG(journal_.fatal())
170 << "JobQueue: " << app_.getJobQueue().getJson(0);
171 LogicError("Deadlock detected");
172 }
173 }
174 }
175
176 bool change;
177
179 {
180 JLOG(journal_.info()) << "Raising local fee (JQ overload): "
181 << app_.getJobQueue().getJson(0);
182 change = app_.getFeeTrack().raiseLocalFee();
183 }
184 else
185 {
186 change = app_.getFeeTrack().lowerLocalFee();
187 }
188
189 if (change)
190 {
191 // VFALCO TODO replace this with a Listener / observer and
192 // subscribe in NetworkOPs or Application.
194 }
195}
196
197//------------------------------------------------------------------------------
198
201{
202 return std::unique_ptr<LoadManager>{new LoadManager{app, journal}};
203}
204
205} // namespace ripple
A generic endpoint for log messages.
Definition: Journal.h:60
Stream fatal() const
Definition: Journal.h:352
Stream debug() const
Definition: Journal.h:328
Stream info() const
Definition: Journal.h:334
Stream warn() const
Definition: Journal.h:340
virtual LoadFeeTrack & getFeeTrack()=0
virtual JobQueue & getJobQueue()=0
virtual NetworkOPs & getOPs()=0
bool isOverloaded()
Definition: JobQueue.cpp:206
Json::Value getJson(int c=0)
Definition: JobQueue.cpp:214
Manages load sources.
Definition: LoadManager.h:46
void resetDeadlockDetector()
Reset the deadlock detection timer.
Definition: LoadManager.cpp:64
std::condition_variable cv_
Definition: LoadManager.h:102
std::thread thread_
Definition: LoadManager.h:100
beast::Journal const journal_
Definition: LoadManager.h:98
Application & app_
Definition: LoadManager.h:97
void activateDeadlockDetector()
Turn on deadlock detection.
Definition: LoadManager.cpp:56
std::chrono::steady_clock::time_point deadLock_
Definition: LoadManager.h:106
~LoadManager()
Destroy the manager.
Definition: LoadManager.cpp:39
virtual void reportFeeChange()=0
T join(T... args)
T joinable(T... args)
void setCurrentThreadName(std::string_view newThreadName)
Changes the name of the caller thread.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::unique_ptr< LoadManager > make_LoadManager(Application &app, beast::Journal journal)
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
Definition: contract.cpp:50
T unlock(T... args)
T what(T... args)