Migrate more code into the chrono type system:

Changes include:

  *  Database::tune and all tune overrides
  *  TaggedCache TargetAge
  *  KeyCache TargetAge
This commit is contained in:
Howard Hinnant
2018-06-25 12:27:59 -04:00
committed by Nik Bougalis
parent 574ea2c14d
commit d257d1b2c9
24 changed files with 76 additions and 73 deletions

View File

@@ -32,9 +32,7 @@ namespace ripple {
#define CACHED_LEDGER_NUM 96 #define CACHED_LEDGER_NUM 96
#endif #endif
#ifndef CACHED_LEDGER_AGE std::chrono::seconds constexpr CachedLedgerAge = std::chrono::minutes{2};
#define CACHED_LEDGER_AGE 120
#endif
// FIXME: Need to clean up ledgers by index at some point // FIXME: Need to clean up ledgers by index at some point
@@ -44,9 +42,9 @@ LedgerHistory::LedgerHistory (
: app_ (app) : app_ (app)
, collector_ (collector) , collector_ (collector)
, mismatch_counter_ (collector->make_counter ("ledger.history", "mismatch")) , mismatch_counter_ (collector->make_counter ("ledger.history", "mismatch"))
, m_ledgers_by_hash ("LedgerCache", CACHED_LEDGER_NUM, CACHED_LEDGER_AGE, , m_ledgers_by_hash ("LedgerCache", CACHED_LEDGER_NUM, CachedLedgerAge,
stopwatch(), app_.journal("TaggedCache")) stopwatch(), app_.journal("TaggedCache"))
, m_consensus_validated ("ConsensusValidated", 64, 300, , m_consensus_validated ("ConsensusValidated", 64, 5min,
stopwatch(), app_.journal("TaggedCache")) stopwatch(), app_.journal("TaggedCache"))
, j_ (app.journal ("LedgerHistory")) , j_ (app.journal ("LedgerHistory"))
{ {
@@ -517,7 +515,7 @@ bool LedgerHistory::fixIndex (
return true; return true;
} }
void LedgerHistory::tune (int size, int age) void LedgerHistory::tune (int size, std::chrono::seconds age)
{ {
m_ledgers_by_hash.setTargetSize (size); m_ledgers_by_hash.setTargetSize (size);
m_ledgers_by_hash.setTargetAge (age); m_ledgers_by_hash.setTargetAge (age);

View File

@@ -69,7 +69,7 @@ public:
@param size The target size of the cache @param size The target size of the cache
@param age The target age of the cache, in seconds @param age The target age of the cache, in seconds
*/ */
void tune (int size, int age); void tune (int size, std::chrono::seconds age);
/** Remove stale cache entries /** Remove stale cache entries
*/ */

View File

@@ -188,7 +188,7 @@ public:
bool getFullValidatedRange ( bool getFullValidatedRange (
std::uint32_t& minVal, std::uint32_t& maxVal); std::uint32_t& minVal, std::uint32_t& maxVal);
void tune (int size, int age); void tune (int size, std::chrono::seconds age);
void sweep (); void sweep ();
float getCacheHitRate (); float getCacheHitRate ();

View File

@@ -73,7 +73,7 @@ LedgerMaster::LedgerMaster (Application& app, Stopwatch& stopwatch,
app_.config().FETCH_DEPTH)) app_.config().FETCH_DEPTH))
, ledger_history_ (app_.config().LEDGER_HISTORY) , ledger_history_ (app_.config().LEDGER_HISTORY)
, ledger_fetch_size_ (app_.config().getSize (siLedgerFetch)) , ledger_fetch_size_ (app_.config().getSize (siLedgerFetch))
, fetch_packs_ ("FetchPack", 65536, 45, stopwatch, , fetch_packs_ ("FetchPack", 65536, 45s, stopwatch,
app_.journal("TaggedCache")) app_.journal("TaggedCache"))
{ {
} }
@@ -1459,7 +1459,7 @@ LedgerMaster::setLedgerRangePresent (std::uint32_t minV, std::uint32_t maxV)
} }
void void
LedgerMaster::tune (int size, int age) LedgerMaster::tune (int size, std::chrono::seconds age)
{ {
mLedgerHistory.tune (size, age); mLedgerHistory.tune (size, age);
} }

View File

@@ -28,7 +28,7 @@ namespace ripple {
TransactionMaster::TransactionMaster (Application& app) TransactionMaster::TransactionMaster (Application& app)
: mApp (app) : mApp (app)
, mCache ("TransactionCache", 65536, 1800, stopwatch(), , mCache ("TransactionCache", 65536, 30min, stopwatch(),
mApp.journal("TaggedCache")) mApp.journal("TaggedCache"))
{ {
} }

View File

@@ -111,11 +111,11 @@ public:
AppFamily (Application& app, NodeStore::Database& db, AppFamily (Application& app, NodeStore::Database& db,
CollectorManager& collectorManager) CollectorManager& collectorManager)
: app_ (app) : app_ (app)
, treecache_ ("TreeNodeCache", 65536, 60, stopwatch(), , treecache_ ("TreeNodeCache", 65536, 1min, stopwatch(),
app.journal("TaggedCache")) app.journal("TaggedCache"))
, fullbelow_ ("full_below", stopwatch(), , fullbelow_ ("full_below", stopwatch(),
collectorManager.collector(), collectorManager.collector(),
fullBelowTargetSize, fullBelowExpirationSeconds) fullBelowTargetSize, fullBelowExpiration)
, db_ (db) , db_ (db)
, shardBacked_ ( , shardBacked_ (
dynamic_cast<NodeStore::DatabaseShard*>(&db) != nullptr) dynamic_cast<NodeStore::DatabaseShard*>(&db) != nullptr)
@@ -416,7 +416,7 @@ public:
, accountIDCache_(128000) , accountIDCache_(128000)
, m_tempNodeCache ("NodeCache", 16384, 90, stopwatch(), , m_tempNodeCache ("NodeCache", 16384, 90s, stopwatch(),
logs_->journal("TaggedCache")) logs_->journal("TaggedCache"))
, m_collectorManager (CollectorManager::New ( , m_collectorManager (CollectorManager::New (
@@ -470,7 +470,7 @@ public:
gotTXSet (set, fromAcquire); gotTXSet (set, fromAcquire);
})) }))
, m_acceptedLedgerCache ("AcceptedLedger", 4, 60, stopwatch(), , m_acceptedLedgerCache ("AcceptedLedger", 4, 1min, stopwatch(),
logs_->journal("TaggedCache")) logs_->journal("TaggedCache"))
, m_networkOPs (make_NetworkOPs (*this, stopwatch(), , m_networkOPs (make_NetworkOPs (*this, stopwatch(),
@@ -984,8 +984,9 @@ public:
} }
})) }))
{ {
sweepTimer_.expires_from_now ( using namespace std::chrono;
std::chrono::seconds {config_->getSize (siSweepInterval)}); sweepTimer_.expires_from_now(
seconds{config_->getSize(siSweepInterval)});
sweepTimer_.async_wait (std::move (*optionalCountedHandler)); sweepTimer_.async_wait (std::move (*optionalCountedHandler));
} }
} }
@@ -1254,16 +1255,21 @@ bool ApplicationImp::setup()
return false; return false;
} }
m_nodeStore->tune (config_->getSize (siNodeCacheSize), config_->getSize (siNodeCacheAge)); using namespace std::chrono;
m_ledgerMaster->tune (config_->getSize (siLedgerSize), config_->getSize (siLedgerAge)); m_nodeStore->tune(config_->getSize(siNodeCacheSize),
family().treecache().setTargetSize (config_->getSize (siTreeCacheSize)); seconds{config_->getSize(siNodeCacheAge)});
family().treecache().setTargetAge (config_->getSize (siTreeCacheAge)); m_ledgerMaster->tune(config_->getSize(siLedgerSize),
seconds{config_->getSize(siLedgerAge)});
family().treecache().setTargetSize(config_->getSize (siTreeCacheSize));
family().treecache().setTargetAge(
seconds{config_->getSize(siTreeCacheAge)});
if (shardStore_) if (shardStore_)
{ {
shardStore_->tune(config_->getSize(siNodeCacheSize), shardStore_->tune(config_->getSize(siNodeCacheSize),
config_->getSize(siNodeCacheAge)); seconds{config_->getSize(siNodeCacheAge)});
sFamily_->treecache().setTargetSize(config_->getSize(siTreeCacheSize)); sFamily_->treecache().setTargetSize(config_->getSize(siTreeCacheSize));
sFamily_->treecache().setTargetAge(config_->getSize(siTreeCacheAge)); sFamily_->treecache().setTargetAge(
seconds{config_->getSize(siTreeCacheAge)});
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -1586,7 +1592,8 @@ ApplicationImp::loadLedgerFromFile (
} }
if (ledger.get().isMember ("close_time_resolution")) if (ledger.get().isMember ("close_time_resolution"))
{ {
closeTimeResolution = std::chrono::seconds{ using namespace std::chrono;
closeTimeResolution = seconds{
ledger.get()["close_time_resolution"].asUInt()}; ledger.get()["close_time_resolution"].asUInt()};
} }
if (ledger.get().isMember ("close_time_estimated")) if (ledger.get().isMember ("close_time_estimated"))

View File

@@ -22,11 +22,8 @@
namespace ripple { namespace ripple {
enum constexpr std::size_t fullBelowTargetSize = 524288;
{ constexpr std::chrono::seconds fullBelowExpiration = std::chrono::minutes{10};
fullBelowTargetSize = 524288
,fullBelowExpirationSeconds = 600
};
} }

View File

@@ -102,27 +102,28 @@ public:
*/ */
KeyCache (std::string const& name, clock_type& clock, KeyCache (std::string const& name, clock_type& clock,
beast::insight::Collector::ptr const& collector, size_type target_size = 0, beast::insight::Collector::ptr const& collector, size_type target_size = 0,
clock_type::rep expiration_seconds = 120) std::chrono::seconds expiration = std::chrono::minutes{2})
: m_stats (name, : m_stats (name,
std::bind (&KeyCache::collect_metrics, this), std::bind (&KeyCache::collect_metrics, this),
collector) collector)
, m_clock (clock) , m_clock (clock)
, m_name (name) , m_name (name)
, m_target_size (target_size) , m_target_size (target_size)
, m_target_age (std::chrono::seconds (expiration_seconds)) , m_target_age (expiration)
{ {
} }
// VFALCO TODO Use a forwarding constructor call here // VFALCO TODO Use a forwarding constructor call here
KeyCache (std::string const& name, clock_type& clock, KeyCache (std::string const& name, clock_type& clock,
size_type target_size = 0, clock_type::rep expiration_seconds = 120) size_type target_size = 0,
std::chrono::seconds expiration = std::chrono::minutes{2})
: m_stats (name, : m_stats (name,
std::bind (&KeyCache::collect_metrics, this), std::bind (&KeyCache::collect_metrics, this),
beast::insight::NullCollector::New ()) beast::insight::NullCollector::New ())
, m_clock (clock) , m_clock (clock)
, m_name (name) , m_name (name)
, m_target_size (target_size) , m_target_size (target_size)
, m_target_age (std::chrono::seconds (expiration_seconds)) , m_target_age (expiration)
{ {
} }
@@ -168,10 +169,10 @@ public:
m_target_size = s; m_target_size = s;
} }
void setTargetAge (size_type s) void setTargetAge (std::chrono::seconds s)
{ {
lock_guard lock (m_mutex); lock_guard lock (m_mutex);
m_target_age = std::chrono::seconds (s); m_target_age = s;
} }
/** Returns `true` if the key was found. /** Returns `true` if the key was found.

View File

@@ -70,9 +70,8 @@ public:
using clock_type = beast::abstract_clock <std::chrono::steady_clock>; using clock_type = beast::abstract_clock <std::chrono::steady_clock>;
public: public:
// VFALCO TODO Change expiration_seconds to clock_type::duration
TaggedCache (std::string const& name, int size, TaggedCache (std::string const& name, int size,
clock_type::rep expiration_seconds, clock_type& clock, beast::Journal journal, clock_type::duration expiration, clock_type& clock, beast::Journal journal,
beast::insight::Collector::ptr const& collector = beast::insight::NullCollector::New ()) beast::insight::Collector::ptr const& collector = beast::insight::NullCollector::New ())
: m_journal (journal) : m_journal (journal)
, m_clock (clock) , m_clock (clock)
@@ -81,7 +80,7 @@ public:
collector) collector)
, m_name (name) , m_name (name)
, m_target_size (size) , m_target_size (size)
, m_target_age (std::chrono::seconds (expiration_seconds)) , m_target_age (expiration)
, m_cache_count (0) , m_cache_count (0)
, m_hits (0) , m_hits (0)
, m_misses (0) , m_misses (0)
@@ -113,16 +112,16 @@ public:
m_name << " target size set to " << s; m_name << " target size set to " << s;
} }
clock_type::rep getTargetAge () const clock_type::duration getTargetAge () const
{ {
lock_guard lock (m_mutex); lock_guard lock (m_mutex);
return m_target_age.count(); return m_target_age;
} }
void setTargetAge (clock_type::rep s) void setTargetAge (clock_type::duration s)
{ {
lock_guard lock (m_mutex); lock_guard lock (m_mutex);
m_target_age = std::chrono::seconds (s); m_target_age = s;
JLOG(m_journal.debug()) << JLOG(m_journal.debug()) <<
m_name << " target age set to " << m_target_age.count(); m_name << " target age set to " << m_target_age.count();
} }
@@ -186,8 +185,7 @@ public:
} }
else else
{ {
when_expire = now - clock_type::duration ( when_expire = now - m_target_age*m_target_size/m_cache.size();
m_target_age.count() * m_target_size / m_cache.size ());
clock_type::duration const minimumAge ( clock_type::duration const minimumAge (
std::chrono::seconds (1)); std::chrono::seconds (1));

View File

@@ -177,7 +177,7 @@ public:
*/ */
virtual virtual
void void
tune(int size, int age) = 0; tune(int size, std::chrono::seconds age) = 0;
/** Remove expired entries from the positive and negative caches. */ /** Remove expired entries from the positive and negative caches. */
virtual virtual

View File

@@ -52,7 +52,7 @@ DatabaseNodeImp::asyncFetch(uint256 const& hash,
} }
void void
DatabaseNodeImp::tune(int size, int age) DatabaseNodeImp::tune(int size, std::chrono::seconds age)
{ {
pCache_->setTargetSize(size); pCache_->setTargetSize(size);
pCache_->setTargetAge(age); pCache_->setTargetAge(age);

View File

@@ -43,9 +43,9 @@ public:
beast::Journal j) beast::Journal j)
: Database(name, parent, scheduler, readThreads, config, j) : Database(name, parent, scheduler, readThreads, config, j)
, pCache_(std::make_shared<TaggedCache<uint256, NodeObject>>( , pCache_(std::make_shared<TaggedCache<uint256, NodeObject>>(
name, cacheTargetSize, cacheTargetSeconds, stopwatch(), j)) name, cacheTargetSize, cacheTargetAge, stopwatch(), j))
, nCache_(std::make_shared<KeyCache<uint256>>( , nCache_(std::make_shared<KeyCache<uint256>>(
name, stopwatch(), cacheTargetSize, cacheTargetSeconds)) name, stopwatch(), cacheTargetSize, cacheTargetAge))
, backend_(std::move(backend)) , backend_(std::move(backend))
{ {
assert(backend_); assert(backend_);
@@ -109,7 +109,7 @@ public:
getCacheHitRate() override {return pCache_->getHitRate();} getCacheHitRate() override {return pCache_->getHitRate();}
void void
tune(int size, int age) override; tune(int size, std::chrono::seconds age) override;
void void
sweep() override; sweep() override;

View File

@@ -35,9 +35,9 @@ DatabaseRotatingImp::DatabaseRotatingImp(
beast::Journal j) beast::Journal j)
: DatabaseRotating(name, parent, scheduler, readThreads, config, j) : DatabaseRotating(name, parent, scheduler, readThreads, config, j)
, pCache_(std::make_shared<TaggedCache<uint256, NodeObject>>( , pCache_(std::make_shared<TaggedCache<uint256, NodeObject>>(
name, cacheTargetSize, cacheTargetSeconds, stopwatch(), j)) name, cacheTargetSize, cacheTargetAge, stopwatch(), j))
, nCache_(std::make_shared<KeyCache<uint256>>( , nCache_(std::make_shared<KeyCache<uint256>>(
name, stopwatch(), cacheTargetSize, cacheTargetSeconds)) name, stopwatch(), cacheTargetSize, cacheTargetAge))
, writableBackend_(std::move(writableBackend)) , writableBackend_(std::move(writableBackend))
, archiveBackend_(std::move(archiveBackend)) , archiveBackend_(std::move(archiveBackend))
{ {
@@ -86,7 +86,7 @@ DatabaseRotatingImp::asyncFetch(uint256 const& hash,
} }
void void
DatabaseRotatingImp::tune(int size, int age) DatabaseRotatingImp::tune(int size, std::chrono::seconds age)
{ {
pCache_->setTargetSize(size); pCache_->setTargetSize(size);
pCache_->setTargetAge(age); pCache_->setTargetAge(age);

View File

@@ -111,7 +111,7 @@ public:
getCacheHitRate() override {return pCache_->getHitRate();} getCacheHitRate() override {return pCache_->getHitRate();}
void void
tune(int size, int age) override; tune(int size, std::chrono::seconds age) override;
void void
sweep() override; sweep() override;

View File

@@ -677,7 +677,7 @@ DatabaseShardImp::getCacheHitRate()
} }
void void
DatabaseShardImp::tune(int size, int age) DatabaseShardImp::tune(int size, std::chrono::seconds age)
{ {
std::lock_guard<std::mutex> l(m_); std::lock_guard<std::mutex> l(m_);
assert(init_); assert(init_);

View File

@@ -134,7 +134,7 @@ public:
getCacheHitRate() override; getCacheHitRate() override;
void void
tune(int size, int age) override; tune(int size, std::chrono::seconds age) override;
void void
sweep() override; sweep() override;
@@ -176,7 +176,7 @@ private:
// Shard cache tuning // Shard cache tuning
int cacheSz_ {shardCacheSz}; int cacheSz_ {shardCacheSz};
PCache::clock_type::rep cacheAge_ {shardCacheSeconds}; std::chrono::seconds cacheAge_ {shardCacheAge};
// File name used to mark shards being imported from node store // File name used to mark shards being imported from node store
static constexpr auto importMarker_ = "import"; static constexpr auto importMarker_ = "import";

View File

@@ -28,7 +28,7 @@ namespace ripple {
namespace NodeStore { namespace NodeStore {
Shard::Shard(DatabaseShard const& db, std::uint32_t index, Shard::Shard(DatabaseShard const& db, std::uint32_t index,
int cacheSz, PCache::clock_type::rep cacheAge, beast::Journal& j) int cacheSz, std::chrono::seconds cacheAge, beast::Journal& j)
: index_(index) : index_(index)
, firstSeq_(db.firstLedgerSeq(index)) , firstSeq_(db.firstLedgerSeq(index))
, lastSeq_(std::max(firstSeq_, db.lastLedgerSeq(index))) , lastSeq_(std::max(firstSeq_, db.lastLedgerSeq(index)))
@@ -228,8 +228,8 @@ Shard::validate(Application& app)
"-" << lastSeq_; "-" << lastSeq_;
// Use a short age to keep memory consumption low // Use a short age to keep memory consumption low
PCache::clock_type::rep const savedAge {pCache_->getTargetAge()}; auto const savedAge {pCache_->getTargetAge()};
pCache_->setTargetAge(1); pCache_->setTargetAge(1s);
// Validate every ledger stored in this shard // Validate every ledger stored in this shard
std::shared_ptr<Ledger const> next; std::shared_ptr<Ledger const> next;

View File

@@ -48,7 +48,7 @@ class Shard
{ {
public: public:
Shard(DatabaseShard const& db, std::uint32_t index, int cacheSz, Shard(DatabaseShard const& db, std::uint32_t index, int cacheSz,
PCache::clock_type::rep cacheAge, beast::Journal& j); std::chrono::seconds cacheAge, beast::Journal& j);
bool bool
open(Section config, Scheduler& scheduler, open(Section config, Scheduler& scheduler,

View File

@@ -28,15 +28,14 @@ enum
// Target cache size of the TaggedCache used to hold nodes // Target cache size of the TaggedCache used to hold nodes
cacheTargetSize = 16384 cacheTargetSize = 16384
// Expiration time for cached nodes
,cacheTargetSeconds = 300
// Fraction of the cache one query source can take // Fraction of the cache one query source can take
,asyncDivider = 8 ,asyncDivider = 8
}; };
// Expiration time for cached nodes
std::chrono::seconds constexpr cacheTargetAge = std::chrono::minutes{5};
auto constexpr shardCacheSz = 16384; auto constexpr shardCacheSz = 16384;
auto constexpr shardCacheSeconds = 60; std::chrono::seconds constexpr shardCacheAge = std::chrono::minutes{1};
} }
} }

View File

@@ -43,7 +43,6 @@ public:
enum enum
{ {
defaultCacheTargetSize = 0 defaultCacheTargetSize = 0
,defaultCacheExpirationSeconds = 120
}; };
using key_type = Key; using key_type = Key;
@@ -61,9 +60,9 @@ public:
beast::insight::Collector::ptr const& collector = beast::insight::Collector::ptr const& collector =
beast::insight::NullCollector::New (), beast::insight::NullCollector::New (),
std::size_t target_size = defaultCacheTargetSize, std::size_t target_size = defaultCacheTargetSize,
std::size_t expiration_seconds = defaultCacheExpirationSeconds) std::chrono::seconds expiration = std::chrono::minutes{2})
: m_cache (name, clock, collector, target_size, : m_cache (name, clock, collector, target_size,
expiration_seconds) expiration)
, m_gen (1) , m_gen (1)
{ {
} }

View File

@@ -29,6 +29,7 @@ class KeyCache_test : public beast::unit_test::suite
public: public:
void run () override void run () override
{ {
using namespace std::chrono_literals;
TestStopwatch clock; TestStopwatch clock;
clock.set (0); clock.set (0);
@@ -37,7 +38,7 @@ public:
// Insert an item, retrieve it, and age it so it gets purged. // Insert an item, retrieve it, and age it so it gets purged.
{ {
Cache c ("test", clock, 1, 2); Cache c ("test", clock, 1, 2s);
BEAST_EXPECT(c.size () == 0); BEAST_EXPECT(c.size () == 0);
BEAST_EXPECT(c.insert ("one")); BEAST_EXPECT(c.insert ("one"));
@@ -58,7 +59,7 @@ public:
// Insert two items, have one expire // Insert two items, have one expire
{ {
Cache c ("test", clock, 2, 2); Cache c ("test", clock, 2, 2s);
BEAST_EXPECT(c.insert ("one")); BEAST_EXPECT(c.insert ("one"));
BEAST_EXPECT(c.size () == 1); BEAST_EXPECT(c.size () == 1);
@@ -76,7 +77,7 @@ public:
// Insert three items (1 over limit), sweep // Insert three items (1 over limit), sweep
{ {
Cache c ("test", clock, 2, 3); Cache c ("test", clock, 2, 3s);
BEAST_EXPECT(c.insert ("one")); BEAST_EXPECT(c.insert ("one"));
++clock; ++clock;

View File

@@ -39,6 +39,7 @@ class TaggedCache_test : public beast::unit_test::suite
public: public:
void run () override void run () override
{ {
using namespace std::chrono_literals;
beast::Journal const j; beast::Journal const j;
TestStopwatch clock; TestStopwatch clock;
@@ -48,7 +49,7 @@ public:
using Value = std::string; using Value = std::string;
using Cache = TaggedCache <Key, Value>; using Cache = TaggedCache <Key, Value>;
Cache c ("test", 1, 1, clock, j); Cache c ("test", 1, 1s, clock, j);
// Insert an item, retrieve it, and age it so it gets purged. // Insert an item, retrieve it, and age it so it gets purged.
{ {

View File

@@ -249,9 +249,10 @@ public:
void testMoreThan256Closed() void testMoreThan256Closed()
{ {
using namespace test::jtx; using namespace test::jtx;
using namespace std::chrono_literals;
Env env {*this}; Env env {*this};
Account const gw {"gateway"}; Account const gw {"gateway"};
env.app().getLedgerMaster().tune(0, 3600); env.app().getLedgerMaster().tune(0, 1h);
auto const USD = gw["USD"]; auto const USD = gw["USD"];
env.fund(XRP(100000), gw); env.fund(XRP(100000), gw);

View File

@@ -43,7 +43,8 @@ private:
public: public:
TestFamily (beast::Journal j) TestFamily (beast::Journal j)
: treecache_ ("TreeNodeCache", 65536, 60, clock_, j) : treecache_ ("TreeNodeCache", 65536, std::chrono::minutes{1},
clock_, j)
, fullbelow_ ("full_below", clock_) , fullbelow_ ("full_below", clock_)
, parent_ ("TestRootStoppable") , parent_ ("TestRootStoppable")
, j_ (j) , j_ (j)