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  : 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 
54 void
56 {
58  armed_ = true;
60 }
61 
62 void
64 {
65  auto const detector_start = std::chrono::steady_clock::now();
67  deadLock_ = detector_start;
68 }
69 
70 //------------------------------------------------------------------------------
71 
72 void
74 {
75  JLOG(journal_.debug()) << "Starting";
76  assert(!thread_.joinable());
77 
79 }
80 
81 void
83 {
84  {
85  std::lock_guard lock(mutex_);
86  stop_ = true;
87  // There is at most one thread waiting on this condition.
88  cv_.notify_all();
89  }
90  if (thread_.joinable())
91  {
92  JLOG(journal_.debug()) << "Stopping";
93  thread_.join();
94  }
95 }
96 
97 //------------------------------------------------------------------------------
98 
99 void
101 {
102  beast::setCurrentThreadName("LoadManager");
103 
104  using namespace std::chrono_literals;
105  using clock_type = std::chrono::steady_clock;
106 
107  auto t = clock_type::now();
108 
109  while (true)
110  {
111  {
112  t += 1s;
114  if (cv_.wait_until(sl, t, [this] { return stop_; }))
115  {
116  break;
117  }
118  // Copy out shared data under a lock. Use copies outside lock.
119  auto const deadLock = deadLock_;
120  auto const armed = armed_;
121  sl.unlock();
122 
123  // Measure the amount of time we have been deadlocked, in seconds.
124  using namespace std::chrono;
125  auto const timeSpentDeadlocked =
126  duration_cast<seconds>(steady_clock::now() - deadLock);
127 
128  constexpr auto reportingIntervalSeconds = 10s;
129  constexpr auto deadlockFatalLogMessageTimeLimit = 90s;
130  constexpr auto deadlockLogicErrorTimeLimit = 600s;
131  if (armed && (timeSpentDeadlocked >= reportingIntervalSeconds))
132  {
133  // Report the deadlocked condition every
134  // reportingIntervalSeconds
135  if ((timeSpentDeadlocked % reportingIntervalSeconds) == 0s)
136  {
137  if (timeSpentDeadlocked < deadlockFatalLogMessageTimeLimit)
138  {
139  JLOG(journal_.warn())
140  << "Server stalled for "
141  << timeSpentDeadlocked.count() << " seconds.";
142  }
143  else
144  {
145  JLOG(journal_.fatal())
146  << "Deadlock detected. Deadlocked time: "
147  << timeSpentDeadlocked.count() << "s";
148  if (app_.getJobQueue().isOverloaded())
149  {
150  JLOG(journal_.fatal())
151  << app_.getJobQueue().getJson(0);
152  }
153  }
154  }
155 
156  // If we go over the deadlockTimeLimit spent deadlocked, it
157  // means that the deadlock resolution code has failed, which
158  // qualifies as undefined behavior.
159  //
160  if (timeSpentDeadlocked >= deadlockLogicErrorTimeLimit)
161  {
162  JLOG(journal_.fatal())
163  << "LogicError: Deadlock detected. Deadlocked time: "
164  << timeSpentDeadlocked.count() << "s";
165  if (app_.getJobQueue().isOverloaded())
166  {
167  JLOG(journal_.fatal()) << app_.getJobQueue().getJson(0);
168  }
169  LogicError("Deadlock detected");
170  }
171  }
172  }
173 
174  bool change = false;
175  if (app_.getJobQueue().isOverloaded())
176  {
177  JLOG(journal_.info()) << app_.getJobQueue().getJson(0);
178  change = app_.getFeeTrack().raiseLocalFee();
179  }
180  else
181  {
182  change = app_.getFeeTrack().lowerLocalFee();
183  }
184 
185  if (change)
186  {
187  // VFALCO TODO replace this with a Listener / observer and
188  // subscribe in NetworkOPs or Application.
190  }
191  }
192 }
193 
194 //------------------------------------------------------------------------------
195 
198 {
199  return std::unique_ptr<LoadManager>{new LoadManager{app, journal}};
200 }
201 
202 } // namespace ripple
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:339
ripple::Application
Definition: Application.h:103
std::chrono::steady_clock
ripple::LoadManager::activateDeadlockDetector
void activateDeadlockDetector()
Turn on deadlock detection.
Definition: LoadManager.cpp:55
ripple::LoadManager
Manages load sources.
Definition: LoadManager.h:45
std::exception
STL class.
ripple::LoadManager::start
void start()
Definition: LoadManager.cpp:73
ripple::JobQueue::getJson
Json::Value getJson(int c=0)
Definition: JobQueue.cpp:203
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
std::lock_guard
STL class.
ripple::LoadManager::journal_
const beast::Journal journal_
Definition: LoadManager.h:98
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:97
thread
ripple::LoadManager::mutex_
std::mutex mutex_
Definition: LoadManager.h:101
ripple::LoadManager::stop
void stop()
Definition: LoadManager.cpp:82
ripple::LoadManager::~LoadManager
~LoadManager()
Destroy the manager.
Definition: LoadManager.cpp:38
ripple::JobQueue::isOverloaded
bool isOverloaded()
Definition: JobQueue.cpp:189
std::unique_lock
STL class.
ripple::NetworkOPs::reportFeeChange
virtual void reportFeeChange()=0
ripple::LoadManager::thread_
std::thread thread_
Definition: LoadManager.h:100
ripple::LoadManager::cv_
std::condition_variable cv_
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
ripple::LoadManager::make_LoadManager
friend std::unique_ptr< LoadManager > make_LoadManager(Application &app, beast::Journal journal)
Definition: LoadManager.cpp:197
memory
ripple::LoadManager::resetDeadlockDetector
void resetDeadlockDetector()
Reset the deadlock detection timer.
Definition: LoadManager.cpp:63
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::LoadFeeTrack::raiseLocalFee
bool raiseLocalFee()
Definition: LoadFeeTrack.cpp:37
std::condition_variable::wait_until
T wait_until(T... args)
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:100
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:103
std::unique_ptr
STL class.
ripple::LoadManager::deadLock_
std::chrono::steady_clock::time_point deadLock_
Definition: LoadManager.h:106
std::condition_variable::notify_all
T notify_all(T... args)
std::thread::join
T join(T... args)
std::exception::what
T what(T... args)
std::chrono
std::chrono::steady_clock::now
T now(T... args)