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