Replace UptimeTimer with UptimeClock

* UptimeClock is a chrono-compatible seconds-precision clock.

* Like UptimeTimer, its purpose is to make it possible for clients
  to query the uptime thousands of times per second without a
  significant performance hit.

* UptimeClock decouples itself from LoadManager by managing its
  own once-per-second update loop.

* Clients now traffic in chrono time_points and durations instead
  of int.
This commit is contained in:
Howard Hinnant
2018-04-23 13:46:37 -04:00
committed by seelabs
parent 717f874767
commit 7d163a45dc
14 changed files with 159 additions and 186 deletions

View File

@@ -21,7 +21,7 @@
#include <ripple/app/main/Application.h>
#include <ripple/app/misc/LoadFeeTrack.h>
#include <ripple/app/misc/NetworkOPs.h>
#include <ripple/basics/UptimeTimer.h>
#include <ripple/basics/UptimeClock.h>
#include <ripple/json/to_string.h>
#include <ripple/beast/core/CurrentThreadName.h>
#include <memory>
@@ -35,18 +35,16 @@ LoadManager::LoadManager (
: Stoppable ("LoadManager", parent)
, app_ (app)
, journal_ (journal)
, deadLock_ (0)
, deadLock_ ()
, armed_ (false)
, stop_ (false)
{
UptimeTimer::getInstance ().beginManualUpdates ();
}
LoadManager::~LoadManager ()
{
try
{
UptimeTimer::getInstance ().endManualUpdates ();
onStop ();
}
catch (std::exception const& ex)
@@ -67,9 +65,7 @@ void LoadManager::activateDeadlockDetector ()
void LoadManager::resetDeadlockDetector ()
{
auto const elapsedSeconds =
UptimeTimer::getInstance ().getElapsedSeconds ();
auto const elapsedSeconds = UptimeClock::now();
std::lock_guard<std::mutex> sl (mutex_);
deadLock_ = elapsedSeconds;
}
@@ -108,24 +104,14 @@ void LoadManager::run ()
{
beast::setCurrentThreadName ("LoadManager");
using clock_type = std::chrono::steady_clock;
using clock_type = std::chrono::system_clock;
// Initialize the clock to the current time.
auto t = clock_type::now();
bool stop = false;
while (! (stop || isStopping ()))
{
{
// VFALCO NOTE I think this is to reduce calls to the operating
// system for retrieving the current time.
//
// TODO Instead of incrementing can't we just retrieve the
// current time again?
//
// Manually update the timer.
UptimeTimer::getInstance ().incrementElapsedTime ();
// Copy out shared data under a lock. Use copies outside lock.
std::unique_lock<std::mutex> sl (mutex_);
auto const deadLock = deadLock_;
@@ -134,29 +120,24 @@ void LoadManager::run ()
sl.unlock();
// Measure the amount of time we have been deadlocked, in seconds.
//
// VFALCO NOTE deadLock_ is a canary for detecting the condition.
int const timeSpentDeadlocked =
UptimeTimer::getInstance ().getElapsedSeconds () - deadLock;
auto const timeSpentDeadlocked = UptimeClock::now() - deadLock;
// VFALCO NOTE I think that "armed" refers to the deadlock detector.
//
int const reportingIntervalSeconds = 10;
auto const reportingIntervalSeconds = 10s;
if (armed && (timeSpentDeadlocked >= reportingIntervalSeconds))
{
// Report the deadlocked condition every 10 seconds
if ((timeSpentDeadlocked % reportingIntervalSeconds) == 0)
if ((timeSpentDeadlocked % reportingIntervalSeconds) == 0s)
{
JLOG(journal_.warn())
<< "Server stalled for "
<< timeSpentDeadlocked << " seconds.";
<< timeSpentDeadlocked.count() << " seconds.";
}
// If we go over 500 seconds spent deadlocked, it means that
// the deadlock resolution code has failed, which qualifies
// as undefined behavior.
//
assert (timeSpentDeadlocked < 500);
assert (timeSpentDeadlocked < 500s);
}
}
@@ -178,18 +159,17 @@ void LoadManager::run ()
app_.getOPs ().reportFeeChange ();
}
t += std::chrono::seconds (1);
t += 1s;
auto const duration = t - clock_type::now();
if ((duration < std::chrono::seconds (0)) ||
(duration > std::chrono::seconds (1)))
if ((duration < 0s) || (duration > 1s))
{
JLOG(journal_.warn()) << "time jump";
t = clock_type::now();
}
else
{
alertable_sleep_for(duration);
alertable_sleep_until(t);
}
}
@@ -202,7 +182,7 @@ std::unique_ptr<LoadManager>
make_LoadManager (Application& app,
Stoppable& parent, beast::Journal journal)
{
return std::make_unique<LoadManager>(app, parent, journal);
return std::unique_ptr<LoadManager>{new LoadManager{app, parent, journal}};
}
} // ripple