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), lastHeartbeat_(), 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
62
63void
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 lastHeartbeat = lastHeartbeat_;
122 auto const armed = armed_;
123 sl.unlock();
124
125 // Measure the amount of time we have been stalled, in seconds.
126 using namespace std::chrono;
127 auto const timeSpentStalled =
128 duration_cast<seconds>(steady_clock::now() - lastHeartbeat);
129
130 constexpr auto reportingIntervalSeconds = 10s;
131 constexpr auto stallFatalLogMessageTimeLimit = 90s;
132 constexpr auto stallLogicErrorTimeLimit = 600s;
133
134 if (armed && (timeSpentStalled >= reportingIntervalSeconds))
135 {
136 // Report the stalled condition every reportingIntervalSeconds
137 if ((timeSpentStalled % reportingIntervalSeconds) == 0s)
138 {
139 if (timeSpentStalled < stallFatalLogMessageTimeLimit)
140 {
141 JLOG(journal_.warn())
142 << "Server stalled for " << timeSpentStalled.count()
143 << " seconds.";
144
146 {
147 JLOG(journal_.warn())
148 << "JobQueue: " << app_.getJobQueue().getJson(0);
149 }
150 }
151 else
152 {
153 JLOG(journal_.fatal())
154 << "Server stalled for " << timeSpentStalled.count()
155 << " seconds.";
156 JLOG(journal_.fatal())
157 << "JobQueue: " << app_.getJobQueue().getJson(0);
158 }
159 }
160
161 // If we go over the stallLogicErrorTimeLimit spent stalled, it
162 // means that the stall resolution code has failed, which qualifies
163 // as a LogicError
164 if (timeSpentStalled >= stallLogicErrorTimeLimit)
165 {
166 JLOG(journal_.fatal())
167 << "LogicError: Fatal server stall detected. Stalled time: "
168 << timeSpentStalled.count() << "s";
169 JLOG(journal_.fatal())
170 << "JobQueue: " << app_.getJobQueue().getJson(0);
171 LogicError("Fatal server stall detected");
172 }
173 }
174 }
175
176 bool change = false;
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: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
Json::Value getJson(int c=0)
Definition JobQueue.cpp:214
Manages load sources.
Definition LoadManager.h:46
std::chrono::steady_clock::time_point lastHeartbeat_
std::condition_variable cv_
std::thread thread_
void activateStallDetector()
Turn on stall detection.
beast::Journal const journal_
Definition LoadManager.h:98
Application & app_
Definition LoadManager.h:97
void heartbeat()
Reset the stall detection timer.
~LoadManager()
Destroy the manager.
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:25
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.
T unlock(T... args)
T what(T... args)