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  JLOG(journal_.debug()) << "Starting";
84  assert(!thread_.joinable());
85 
87 }
88 
89 void
91 {
92  if (thread_.joinable())
93  {
94  JLOG(journal_.debug()) << "Stopping";
95  {
97  stop_ = true;
98  }
99  thread_.join();
100  }
101  stopped();
102 }
103 
104 //------------------------------------------------------------------------------
105 
106 void
108 {
109  beast::setCurrentThreadName("LoadManager");
110 
111  using namespace std::chrono_literals;
112  using clock_type = std::chrono::system_clock;
113 
114  auto t = clock_type::now();
115  bool stop = false;
116 
117  while (!(stop || isStopping()))
118  {
119  {
120  // Copy out shared data under a lock. Use copies outside lock.
122  auto const deadLock = deadLock_;
123  auto const armed = armed_;
124  stop = stop_;
125  sl.unlock();
126 
127  // Measure the amount of time we have been deadlocked, in seconds.
128  using namespace std::chrono;
129  auto const timeSpentDeadlocked =
130  duration_cast<seconds>(steady_clock::now() - deadLock);
131 
132  constexpr auto reportingIntervalSeconds = 10s;
133  constexpr auto deadlockFatalLogMessageTimeLimit = 90s;
134  constexpr auto deadlockLogicErrorTimeLimit = 600s;
135  if (armed && (timeSpentDeadlocked >= reportingIntervalSeconds))
136  {
137  // Report the deadlocked condition every
138  // reportingIntervalSeconds
139  if ((timeSpentDeadlocked % reportingIntervalSeconds) == 0s)
140  {
141  if (timeSpentDeadlocked < deadlockFatalLogMessageTimeLimit)
142  {
143  JLOG(journal_.warn())
144  << "Server stalled for "
145  << timeSpentDeadlocked.count() << " seconds.";
146  }
147  else
148  {
149  JLOG(journal_.fatal())
150  << "Deadlock detected. Deadlocked time: "
151  << timeSpentDeadlocked.count() << "s";
152  if (app_.getJobQueue().isOverloaded())
153  {
154  JLOG(journal_.fatal())
155  << app_.getJobQueue().getJson(0);
156  }
157  }
158  }
159 
160  // If we go over the deadlockTimeLimit spent deadlocked, it
161  // means that the deadlock resolution code has failed, which
162  // qualifies as undefined behavior.
163  //
164  if (timeSpentDeadlocked >= deadlockLogicErrorTimeLimit)
165  {
166  JLOG(journal_.fatal())
167  << "LogicError: Deadlock detected. Deadlocked time: "
168  << timeSpentDeadlocked.count() << "s";
169  if (app_.getJobQueue().isOverloaded())
170  {
171  JLOG(journal_.fatal()) << app_.getJobQueue().getJson(0);
172  }
173  LogicError("Deadlock detected");
174  }
175  }
176  }
177 
178  bool change = false;
179  if (app_.getJobQueue().isOverloaded())
180  {
181  JLOG(journal_.info()) << app_.getJobQueue().getJson(0);
182  change = app_.getFeeTrack().raiseLocalFee();
183  }
184  else
185  {
186  change = app_.getFeeTrack().lowerLocalFee();
187  }
188 
189  if (change)
190  {
191  // VFALCO TODO replace this with a Listener / observer and
192  // subscribe in NetworkOPs or Application.
194  }
195 
196  t += 1s;
197  auto const duration = t - clock_type::now();
198 
199  if ((duration < 0s) || (duration > 1s))
200  {
201  JLOG(journal_.warn()) << "time jump";
202  t = clock_type::now();
203  }
204  else
205  {
207  }
208  }
209 
210  stopped();
211 }
212 
213 //------------------------------------------------------------------------------
214 
217 {
218  return std::unique_ptr<LoadManager>{new LoadManager{app, parent, journal}};
219 }
220 
221 } // namespace ripple
std::chrono::system_clock
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:339
ripple::Application
Definition: Application.h:97
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:440
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:90
ripple::LoadManager::journal_
const beast::Journal journal_
Definition: LoadManager.h:97
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:96
ripple::Stoppable
Provides an interface for starting and stopping.
Definition: Stoppable.h:201
thread
ripple::LoadManager::mutex_
std::mutex mutex_
Definition: LoadManager.h:100
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:99
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
ripple::LoadManager::armed_
bool armed_
Definition: LoadManager.h:104
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:81
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:216
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:107
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:105
std::unique_ptr
STL class.
ripple::LoadManager::deadLock_
std::chrono::steady_clock::time_point deadLock_
Definition: LoadManager.h:103
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)