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#include <xrpl/basics/UptimeClock.h>
25#include <xrpl/beast/core/CurrentThreadName.h>
26#include <xrpl/json/to_string.h>
27#include <memory>
28#include <mutex>
29#include <thread>
30
31namespace ripple {
32
34 : app_(app), journal_(journal), deadLock_(), armed_(false)
35{
36}
37
39{
40 try
41 {
42 stop();
43 }
44 catch (std::exception const& ex)
45 {
46 // Swallow the exception in a destructor.
47 JLOG(journal_.warn())
48 << "std::exception in ~LoadManager. " << ex.what();
49 }
50}
51
52//------------------------------------------------------------------------------
53
54void
56{
58 armed_ = true;
60}
61
62void
64{
65 auto const detector_start = std::chrono::steady_clock::now();
67 deadLock_ = detector_start;
68}
69
70//------------------------------------------------------------------------------
71
72void
74{
75 JLOG(journal_.debug()) << "Starting";
76 XRPL_ASSERT(
78 "ripple::LoadManager::start : thread not joinable");
79
81}
82
83void
85{
86 {
88 stop_ = true;
89 // There is at most one thread waiting on this condition.
91 }
92 if (thread_.joinable())
93 {
94 JLOG(journal_.debug()) << "Stopping";
95 thread_.join();
96 }
97}
98
99//------------------------------------------------------------------------------
100
101void
103{
104 beast::setCurrentThreadName("LoadManager");
105
106 using namespace std::chrono_literals;
107 using clock_type = std::chrono::steady_clock;
108
109 auto t = clock_type::now();
110
111 while (true)
112 {
113 t += 1s;
114
116 if (cv_.wait_until(sl, t, [this] { return stop_; }))
117 break;
118
119 // Copy out shared data under a lock. Use copies outside lock.
120 auto const deadLock = deadLock_;
121 auto const armed = armed_;
122 sl.unlock();
123
124 // Measure the amount of time we have been deadlocked, in seconds.
125 using namespace std::chrono;
126 auto const timeSpentDeadlocked =
127 duration_cast<seconds>(steady_clock::now() - deadLock);
128
129 constexpr auto reportingIntervalSeconds = 10s;
130 constexpr auto deadlockFatalLogMessageTimeLimit = 90s;
131 constexpr auto deadlockLogicErrorTimeLimit = 600s;
132
133 if (armed && (timeSpentDeadlocked >= reportingIntervalSeconds))
134 {
135 // Report the deadlocked condition every
136 // reportingIntervalSeconds
137 if ((timeSpentDeadlocked % reportingIntervalSeconds) == 0s)
138 {
139 if (timeSpentDeadlocked < deadlockFatalLogMessageTimeLimit)
140 {
141 JLOG(journal_.warn())
142 << "Server stalled for " << timeSpentDeadlocked.count()
143 << " seconds.";
145 {
146 JLOG(journal_.warn()) << app_.getJobQueue().getJson(0);
147 }
148 }
149 else
150 {
151 JLOG(journal_.fatal())
152 << "Deadlock detected. Deadlocked time: "
153 << timeSpentDeadlocked.count() << "s";
154 JLOG(journal_.fatal())
155 << "JobQueue: " << app_.getJobQueue().getJson(0);
156 }
157 }
158
159 // If we go over the deadlockTimeLimit spent deadlocked, it
160 // means that the deadlock resolution code has failed, which
161 // qualifies as undefined behavior.
162 //
163 if (timeSpentDeadlocked >= deadlockLogicErrorTimeLimit)
164 {
165 JLOG(journal_.fatal())
166 << "LogicError: Deadlock detected. Deadlocked time: "
167 << timeSpentDeadlocked.count() << "s";
168 JLOG(journal_.fatal())
169 << "JobQueue: " << app_.getJobQueue().getJson(0);
170 LogicError("Deadlock detected");
171 }
172 }
173 }
174
175 bool change;
176
178 {
179 JLOG(journal_.info()) << "Raising local fee (JQ overload): "
180 << app_.getJobQueue().getJson(0);
181 change = app_.getFeeTrack().raiseLocalFee();
182 }
183 else
184 {
185 change = app_.getFeeTrack().lowerLocalFee();
186 }
187
188 if (change)
189 {
190 // VFALCO TODO replace this with a Listener / observer and
191 // subscribe in NetworkOPs or Application.
193 }
194}
195
196//------------------------------------------------------------------------------
197
200{
201 return std::unique_ptr<LoadManager>{new LoadManager{app, journal}};
202}
203
204} // namespace ripple
A generic endpoint for log messages.
Definition: Journal.h:59
Stream fatal() const
Definition: Journal.h:341
Stream debug() const
Definition: Journal.h:317
Stream info() const
Definition: Journal.h:323
Stream warn() const
Definition: Journal.h:329
virtual LoadFeeTrack & getFeeTrack()=0
virtual JobQueue & getJobQueue()=0
virtual NetworkOPs & getOPs()=0
bool isOverloaded()
Definition: JobQueue.cpp:204
Json::Value getJson(int c=0)
Definition: JobQueue.cpp:212
Manages load sources.
Definition: LoadManager.h:46
void resetDeadlockDetector()
Reset the deadlock detection timer.
Definition: LoadManager.cpp:63
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:55
std::chrono::steady_clock::time_point deadLock_
Definition: LoadManager.h:106
~LoadManager()
Destroy the manager.
Definition: LoadManager.cpp:38
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:48
T unlock(T... args)
T what(T... args)