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  t += 1s;
112 
114  if (cv_.wait_until(sl, t, [this] { return stop_; }))
115  break;
116 
117  // Copy out shared data under a lock. Use copies outside lock.
118  auto const deadLock = deadLock_;
119  auto const armed = armed_;
120  sl.unlock();
121 
122  // Measure the amount of time we have been deadlocked, in seconds.
123  using namespace std::chrono;
124  auto const timeSpentDeadlocked =
125  duration_cast<seconds>(steady_clock::now() - deadLock);
126 
127  constexpr auto reportingIntervalSeconds = 10s;
128  constexpr auto deadlockFatalLogMessageTimeLimit = 90s;
129  constexpr auto deadlockLogicErrorTimeLimit = 600s;
130 
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 " << timeSpentDeadlocked.count()
141  << " seconds.";
142  if (app_.getJobQueue().isOverloaded())
143  {
144  JLOG(journal_.warn()) << app_.getJobQueue().getJson(0);
145  }
146  }
147  else
148  {
149  JLOG(journal_.fatal())
150  << "Deadlock detected. Deadlocked time: "
151  << timeSpentDeadlocked.count() << "s";
152  JLOG(journal_.fatal())
153  << "JobQueue: " << app_.getJobQueue().getJson(0);
154  }
155  }
156 
157  // If we go over the deadlockTimeLimit spent deadlocked, it
158  // means that the deadlock resolution code has failed, which
159  // qualifies as undefined behavior.
160  //
161  if (timeSpentDeadlocked >= deadlockLogicErrorTimeLimit)
162  {
163  JLOG(journal_.fatal())
164  << "LogicError: Deadlock detected. Deadlocked time: "
165  << timeSpentDeadlocked.count() << "s";
166  JLOG(journal_.fatal())
167  << "JobQueue: " << app_.getJobQueue().getJson(0);
168  LogicError("Deadlock detected");
169  }
170  }
171  }
172 
173  bool change;
174 
175  if (app_.getJobQueue().isOverloaded())
176  {
177  JLOG(journal_.info()) << "Raising local fee (JQ overload): "
178  << 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 
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:115
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:196
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:188
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)