From 3480bfb68bfe9c5fca9e7c144a008d37c6b829fb Mon Sep 17 00:00:00 2001 From: Colin LeMahieu Date: Fri, 8 Sep 2023 12:16:00 +0100 Subject: [PATCH] Split nano::scheduler::bucket in to its own class and file --- nano/node/CMakeLists.txt | 2 + nano/node/scheduler/bucket.cpp | 67 +++++++++++++++++++++++++++++++++ nano/node/scheduler/bucket.hpp | 40 ++++++++++++++++++++ nano/node/scheduler/buckets.cpp | 54 +++++++++++--------------- nano/node/scheduler/buckets.hpp | 18 +++------ 5 files changed, 137 insertions(+), 44 deletions(-) create mode 100644 nano/node/scheduler/bucket.cpp create mode 100644 nano/node/scheduler/bucket.hpp diff --git a/nano/node/CMakeLists.txt b/nano/node/CMakeLists.txt index df13b9208b..ccb4d4fe76 100644 --- a/nano/node/CMakeLists.txt +++ b/nano/node/CMakeLists.txt @@ -194,6 +194,8 @@ add_library( rocksdb/rocksdb_iterator.hpp rocksdb/rocksdb_txn.hpp rocksdb/rocksdb_txn.cpp + scheduler/bucket.cpp + scheduler/bucket.hpp scheduler/buckets.cpp scheduler/buckets.hpp scheduler/component.hpp diff --git a/nano/node/scheduler/bucket.cpp b/nano/node/scheduler/bucket.cpp new file mode 100644 index 0000000000..4b1c8b4994 --- /dev/null +++ b/nano/node/scheduler/bucket.cpp @@ -0,0 +1,67 @@ +#include +#include + +bool nano::scheduler::bucket::value_type::operator< (value_type const & other_a) const +{ + return time < other_a.time || (time == other_a.time && block->hash () < other_a.block->hash ()); +} + +bool nano::scheduler::bucket::value_type::operator== (value_type const & other_a) const +{ + return time == other_a.time && block->hash () == other_a.block->hash (); +} + +nano::scheduler::bucket::bucket (size_t maximum) : + maximum{ maximum } +{ + debug_assert (maximum > 0); +} + +nano::scheduler::bucket::~bucket () +{ +} + +bool nano::scheduler::bucket::available () const +{ + return !queue.empty (); +} + +std::shared_ptr nano::scheduler::bucket::top () const +{ + debug_assert (!queue.empty ()); + return queue.begin ()->block; +} + +void nano::scheduler::bucket::pop () +{ + debug_assert (!queue.empty ()); + queue.erase (queue.begin ()); +} + +void nano::scheduler::bucket::push (uint64_t time, std::shared_ptr block) +{ + queue.insert ({ time, block }); + if (queue.size () > maximum) + { + debug_assert (!queue.empty ()); + queue.erase (--queue.end ()); + } +} + +size_t nano::scheduler::bucket::size () const +{ + return queue.size (); +} + +bool nano::scheduler::bucket::empty () const +{ + return queue.empty (); +} + +void nano::scheduler::bucket::dump () const +{ + for (auto const & item : queue) + { + std::cerr << item.time << ' ' << item.block->hash ().to_string () << '\n'; + } +} diff --git a/nano/node/scheduler/bucket.hpp b/nano/node/scheduler/bucket.hpp new file mode 100644 index 0000000000..d167c0b9dd --- /dev/null +++ b/nano/node/scheduler/bucket.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include +#include + +namespace nano +{ +class block; +} +namespace nano::scheduler +{ +/** A class which holds an ordered set of blocks to be scheduled, ordered by their block arrival time + */ +class bucket final +{ + class value_type + { + public: + uint64_t time; + std::shared_ptr block; + bool operator< (value_type const & other_a) const; + bool operator== (value_type const & other_a) const; + }; + std::set queue; + size_t const maximum; + +public: + bucket (size_t maximum); + ~bucket (); + bool available () const; + std::shared_ptr top () const; + void pop (); + void push (uint64_t time, std::shared_ptr block); + size_t size () const; + bool empty () const; + void dump () const; +}; +} // namespace nano::scheduler diff --git a/nano/node/scheduler/buckets.cpp b/nano/node/scheduler/buckets.cpp index c01bbbd77b..60ec50110f 100644 --- a/nano/node/scheduler/buckets.cpp +++ b/nano/node/scheduler/buckets.cpp @@ -1,19 +1,10 @@ #include #include +#include #include #include -bool nano::scheduler::buckets::value_type::operator< (value_type const & other_a) const -{ - return time < other_a.time || (time == other_a.time && block->hash () < other_a.block->hash ()); -} - -bool nano::scheduler::buckets::value_type::operator== (value_type const & other_a) const -{ - return time == other_a.time && block->hash () == other_a.block->hash (); -} - /** Moves the bucket pointer to the next bucket */ void nano::scheduler::buckets::next () { @@ -28,7 +19,7 @@ void nano::scheduler::buckets::next () void nano::scheduler::buckets::seek () { next (); - for (std::size_t i = 0, n = schedule.size (); buckets_m[*current].empty () && i < n; ++i) + for (std::size_t i = 0, n = schedule.size (); !buckets_m[*current]->available () && i < n; ++i) { next (); } @@ -67,11 +58,19 @@ nano::scheduler::buckets::buckets (uint64_t maximum) : build_region (uint128_t{ 1 } << 112, uint128_t{ 1 } << 116, 4); build_region (uint128_t{ 1 } << 116, uint128_t{ 1 } << 120, 2); minimums.push_back (uint128_t{ 1 } << 120); - buckets_m.resize (minimums.size ()); + auto bucket_max = std::max (1u, maximum / minimums.size ()); + for (size_t i = 0u, n = minimums.size (); i < n; ++i) + { + buckets_m.push_back (std::make_unique (bucket_max)); + } populate_schedule (); current = schedule.begin (); } +nano::scheduler::buckets::~buckets () +{ +} + std::size_t nano::scheduler::buckets::index (nano::uint128_t const & balance) const { auto index = std::upper_bound (minimums.begin (), minimums.end (), balance) - minimums.begin () - 1; @@ -86,11 +85,7 @@ void nano::scheduler::buckets::push (uint64_t time, std::shared_ptr { auto was_empty = empty (); auto & bucket = buckets_m[index (priority.number ())]; - bucket.emplace (value_type{ time, block }); - if (bucket.size () > std::max (decltype (maximum){ 1 }, maximum / buckets_m.size ())) - { - bucket.erase (--bucket.end ()); - } + bucket->push (time, block); if (was_empty) { seek (); @@ -101,8 +96,8 @@ void nano::scheduler::buckets::push (uint64_t time, std::shared_ptr std::shared_ptr nano::scheduler::buckets::top () const { debug_assert (!empty ()); - debug_assert (!buckets_m[*current].empty ()); - auto result = buckets_m[*current].begin ()->block; + debug_assert (buckets_m[*current]->available ()); + auto result = buckets_m[*current]->top (); return result; } @@ -110,9 +105,9 @@ std::shared_ptr nano::scheduler::buckets::top () const void nano::scheduler::buckets::pop () { debug_assert (!empty ()); - debug_assert (!buckets_m[*current].empty ()); + debug_assert (buckets_m[*current]->available ()); auto & bucket = buckets_m[*current]; - bucket.erase (bucket.begin ()); + bucket->pop (); seek (); } @@ -120,9 +115,9 @@ void nano::scheduler::buckets::pop () std::size_t nano::scheduler::buckets::size () const { std::size_t result{ 0 }; - for (auto const & queue : buckets_m) + for (auto const & bucket : buckets_m) { - result += queue.size (); + result += bucket->size (); } return result; } @@ -136,24 +131,21 @@ std::size_t nano::scheduler::buckets::bucket_count () const /** Returns number of items in bucket with index 'index' */ std::size_t nano::scheduler::buckets::bucket_size (std::size_t index) const { - return buckets_m[index].size (); + return buckets_m[index]->size (); } /** Returns true if all buckets are empty */ bool nano::scheduler::buckets::empty () const { - return std::all_of (buckets_m.begin (), buckets_m.end (), [] (priority const & bucket_a) { return bucket_a.empty (); }); + return std::all_of (buckets_m.begin (), buckets_m.end (), [] (auto const & bucket) { return bucket->empty (); }); } /** Print the state of the class in stderr */ void nano::scheduler::buckets::dump () const { - for (auto const & i : buckets_m) + for (auto const & bucket : buckets_m) { - for (auto const & j : i) - { - std::cerr << j.time << ' ' << j.block->hash ().to_string () << '\n'; - } + bucket->dump (); } std::cerr << "current: " << std::to_string (*current) << '\n'; } @@ -164,7 +156,7 @@ std::unique_ptr nano::scheduler::buckets::collec for (auto i = 0; i < buckets_m.size (); ++i) { auto const & bucket = buckets_m[i]; - composite->add_component (std::make_unique (container_info{ std::to_string (i), bucket.size (), 0 })); + composite->add_component (std::make_unique (container_info{ std::to_string (i), bucket->size (), 0 })); } return composite; } diff --git a/nano/node/scheduler/buckets.hpp b/nano/node/scheduler/buckets.hpp index 5b6cc9e43f..0c4b745ac8 100644 --- a/nano/node/scheduler/buckets.hpp +++ b/nano/node/scheduler/buckets.hpp @@ -3,8 +3,9 @@ #include #include -#include +#include #include +#include namespace nano { @@ -12,6 +13,7 @@ class block; } namespace nano::scheduler { +class bucket; /** A container for holding blocks and their arrival/creation time. * * The container consists of a number of buckets. Each bucket holds an ordered set of 'value_type' items. @@ -24,19 +26,8 @@ namespace nano::scheduler */ class buckets final { - class value_type - { - public: - uint64_t time; - std::shared_ptr block; - bool operator< (value_type const & other_a) const; - bool operator== (value_type const & other_a) const; - }; - - using priority = std::set; - /** container for the buckets to be read in round robin fashion */ - std::deque buckets_m; + std::deque> buckets_m; /** thresholds that define the bands for each bucket, the minimum balance an account must have to enter a bucket, * the container writes a block to the lowest indexed bucket that has balance larger than the bucket's minimum value */ @@ -57,6 +48,7 @@ class buckets final public: buckets (uint64_t maximum = 250000u); + ~buckets (); void push (uint64_t time, std::shared_ptr block, nano::amount const & priority); std::shared_ptr top () const; void pop ();