rippled
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 <ripple/app/main/Application.h>
21 #include <ripple/app/main/LoadManager.h>
22 #include <ripple/app/misc/LoadFeeTrack.h>
23 #include <ripple/app/misc/NetworkOPs.h>
24 #include <ripple/basics/UptimeClock.h>
25 #include <ripple/beast/core/CurrentThreadName.h>
26 #include <ripple/json/to_string.h>
27 #include <memory>
28 #include <mutex>
29 #include <thread>
30 
31 namespace ripple {
32 
34  Application& app,
35  Stoppable& parent,
36  beast::Journal journal)
37  : Stoppable("LoadManager", parent)
38  , app_(app)
39  , journal_(journal)
40  , deadLock_()
41  , armed_(false)
42  , stop_(false)
43 {
44 }
45 
47 {
48  try
49  {
50  onStop();
51  }
52  catch (std::exception const& ex)
53  {
54  // Swallow the exception in a destructor.
55  JLOG(journal_.warn())
56  << "std::exception in ~LoadManager. " << ex.what();
57  }
58 }
59 
60 //------------------------------------------------------------------------------
61 
62 void
64 {
66  armed_ = true;
68 }
69 
70 void
72 {
73  auto const detector_start = std::chrono::steady_clock::now();
75  deadLock_ = detector_start;
76 }
77 
78 //------------------------------------------------------------------------------
79 
80 void
82 {
83 }
84 
85 void
87 {
88  JLOG(journal_.debug()) << "Starting";
89  assert(!thread_.joinable());
90 
92 }
93 
94 void
96 {
97  if (thread_.joinable())
98  {
99  JLOG(journal_.debug()) << "Stopping";
100  {
102  stop_ = true;
103  }
104  thread_.join();
105  }
106  stopped();
107 }
108 
109 //------------------------------------------------------------------------------
110 
111 void
113 {
114  beast::setCurrentThreadName("LoadManager");
115 
116  using namespace std::chrono_literals;
117  using clock_type = std::chrono::system_clock;
118 
119  auto t = clock_type::now();
120  bool stop = false;
121 
122  while (!(stop || isStopping()))
123  {
124  {
125  // Copy out shared data under a lock. Use copies outside lock.
127  auto const deadLock = deadLock_;
128  auto const armed = armed_;
129  stop = stop_;
130  sl.unlock();
131 
132  // Measure the amount of time we have been deadlocked, in seconds.
133  using namespace std::chrono;
134  auto const timeSpentDeadlocked =
135  duration_cast<seconds>(steady_clock::now() - deadLock);
136 
137  constexpr auto reportingIntervalSeconds = 10s;
138  constexpr auto deadlockFatalLogMessageTimeLimit = 90s;
139  constexpr auto deadlockLogicErrorTimeLimit = 600s;
140  if (armed && (timeSpentDeadlocked >= reportingIntervalSeconds))
141  {
142  // Report the deadlocked condition every
143  // reportingIntervalSeconds
144  if ((timeSpentDeadlocked % reportingIntervalSeconds) == 0s)
145  {
146  if (timeSpentDeadlocked < deadlockFatalLogMessageTimeLimit)
147  {
148  JLOG(journal_.warn())
149  << "Server stalled for "
150  << timeSpentDeadlocked.count() << " seconds.";
151  }
152  else
153  {
154  JLOG(journal_.fatal())
155  << "Deadlock detected. Deadlocked time: "
156  << timeSpentDeadlocked.count() << "s";
157  if (app_.getJobQueue().isOverloaded())
158  {
159  JLOG(journal_.fatal())
160  << app_.getJobQueue().getJson(0);
161  }
162  }
163  }
164 
165  // If we go over the deadlockTimeLimit spent deadlocked, it
166  // means that the deadlock resolution code has failed, which
167  // qualifies as undefined behavior.
168  //
169  if (timeSpentDeadlocked >= deadlockLogicErrorTimeLimit)
170  {
171  JLOG(journal_.fatal())
172  << "LogicError: Deadlock detected. Deadlocked time: "
173  << timeSpentDeadlocked.count() << "s";
174  if (app_.getJobQueue().isOverloaded())
175  {
176  JLOG(journal_.fatal()) << app_.getJobQueue().getJson(0);
177  }
178  LogicError("Deadlock detected");
179  }
180  }
181  }
182 
183  bool change = false;
184  if (app_.getJobQueue().isOverloaded())
185  {
186  JLOG(journal_.info()) << app_.getJobQueue().getJson(0);
187  change = app_.getFeeTrack().raiseLocalFee();
188  }
189  else
190  {
191  change = app_.getFeeTrack().lowerLocalFee();
192  }
193 
194  if (change)
195  {
196  // VFALCO TODO replace this with a Listener / observer and
197  // subscribe in NetworkOPs or Application.
199  }
200 
201  t += 1s;
202  auto const duration = t - clock_type::now();
203 
204  if ((duration < 0s) || (duration > 1s))
205  {
206  JLOG(journal_.warn()) << "time jump";
207  t = clock_type::now();
208  }
209  else
210  {
212  }
213  }
214 
215  stopped();
216 }
217 
218 //------------------------------------------------------------------------------
219 
222 {
223  return std::unique_ptr<LoadManager>{new LoadManager{app, parent, journal}};
224 }
225 
226 } // namespace ripple
std::chrono::system_clock
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:339
ripple::Application
Definition: Application.h:94
ripple::LoadManager::activateDeadlockDetector
void activateDeadlockDetector()
Turn on deadlock detection.
Definition: LoadManager.cpp:63
ripple::LoadManager
Manages load sources.
Definition: LoadManager.h:43
std::exception
STL class.
ripple::Stoppable::stopped
void stopped()
Called by derived classes to indicate that the stoppable has stopped.
Definition: Stoppable.cpp:72
ripple::Stoppable::alertable_sleep_until
bool alertable_sleep_until(std::chrono::system_clock::time_point const &t)
Sleep or wake up on stop.
Definition: Stoppable.h:454
std::chrono::duration
ripple::JobQueue::getJson
Json::Value getJson(int c=0)
Definition: JobQueue.cpp:218
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
std::lock_guard
STL class.
ripple::LoadManager::onStop
void onStop() override
Override called when the stop notification is issued.
Definition: LoadManager.cpp:95
ripple::LoadManager::journal_
const beast::Journal journal_
Definition: LoadManager.h:100
ripple::Application::getOPs
virtual NetworkOPs & getOPs()=0
ripple::Application::getFeeTrack
virtual LoadFeeTrack & getFeeTrack()=0
std::unique_lock::unlock
T unlock(T... args)
std::thread::joinable
T joinable(T... args)
ripple::LoadManager::app_
Application & app_
Definition: LoadManager.h:99
ripple::Stoppable
Provides an interface for starting and stopping.
Definition: Stoppable.h:200
thread
ripple::LoadManager::mutex_
std::mutex mutex_
Definition: LoadManager.h:103
ripple::LoadManager::~LoadManager
~LoadManager()
Destroy the manager.
Definition: LoadManager.cpp:46
ripple::JobQueue::isOverloaded
bool isOverloaded()
Definition: JobQueue.cpp:204
std::unique_lock
STL class.
ripple::NetworkOPs::reportFeeChange
virtual void reportFeeChange()=0
ripple::LoadManager::thread_
std::thread thread_
Definition: LoadManager.h:102
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
ripple::LoadManager::armed_
bool armed_
Definition: LoadManager.h:107
beast::Journal::info
Stream info() const
Definition: Journal.h:321
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
memory
ripple::LoadManager::resetDeadlockDetector
void resetDeadlockDetector()
Reset the deadlock detection timer.
Definition: LoadManager.cpp:71
ripple::LoadManager::onStart
void onStart() override
Override called during start.
Definition: LoadManager.cpp:86
beast::setCurrentThreadName
void setCurrentThreadName(std::string_view name)
Changes the name of the caller thread.
Definition: CurrentThreadName.cpp:119
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::LoadManager::make_LoadManager
friend std::unique_ptr< LoadManager > make_LoadManager(Application &app, Stoppable &parent, beast::Journal journal)
Definition: LoadManager.cpp:221
ripple::LoadFeeTrack::raiseLocalFee
bool raiseLocalFee()
Definition: LoadFeeTrack.cpp:37
ripple::LogicError
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
Definition: contract.cpp:48
ripple::LoadManager::LoadManager
LoadManager()=delete
ripple::LoadManager::run
void run()
Definition: LoadManager.cpp:112
mutex
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::LoadFeeTrack::lowerLocalFee
bool lowerLocalFee()
Definition: LoadFeeTrack.cpp:65
ripple::LoadManager::stop_
bool stop_
Definition: LoadManager.h:108
std::unique_ptr
STL class.
ripple::LoadManager::onPrepare
void onPrepare() override
Override called during preparation.
Definition: LoadManager.cpp:81
ripple::LoadManager::deadLock_
std::chrono::steady_clock::time_point deadLock_
Definition: LoadManager.h:106
std::thread::join
T join(T... args)
std::exception::what
T what(T... args)
ripple::Stoppable::isStopping
bool isStopping() const
Returns true if the stoppable should stop.
Definition: Stoppable.cpp:54
std::chrono
std::chrono::steady_clock::now
T now(T... args)