From c75f04fcf157276cd72acf90f12bf272f86fcca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20W=C3=B3jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Wed, 1 Feb 2023 12:20:08 +0100 Subject: [PATCH] Add start & stop to `election_scheduler` (#4090) --- nano/node/election_scheduler.cpp | 36 +++++++++++------- nano/node/election_scheduler.hpp | 16 ++++++-- nano/node/node.cpp | 63 +++++++++++++++++--------------- 3 files changed, 69 insertions(+), 46 deletions(-) diff --git a/nano/node/election_scheduler.cpp b/nano/node/election_scheduler.cpp index 966f931f..62c3b999 100644 --- a/nano/node/election_scheduler.cpp +++ b/nano/node/election_scheduler.cpp @@ -2,16 +2,34 @@ #include nano::election_scheduler::election_scheduler (nano::node & node) : - node{ node }, - stopped{ false }, - thread{ [this] () { run (); } } + node{ node } { } nano::election_scheduler::~election_scheduler () { - stop (); - thread.join (); + // Thread must be stopped before destruction + debug_assert (!thread.joinable ()); +} + +void nano::election_scheduler::start () +{ + debug_assert (!thread.joinable ()); + + thread = std::thread{ [this] () { + nano::thread_role::set (nano::thread_role::name::election_scheduler); + run (); + } }; +} + +void nano::election_scheduler::stop () +{ + { + nano::lock_guard lock{ mutex }; + stopped = true; + } + notify (); + nano::join_or_pass (thread); } void nano::election_scheduler::manual (std::shared_ptr const & block_a, boost::optional const & previous_balance_a, nano::election_behavior election_behavior_a, std::function const &)> const & confirmation_action_a) @@ -49,13 +67,6 @@ bool nano::election_scheduler::activate (nano::account const & account_a, nano:: return false; // Not activated } -void nano::election_scheduler::stop () -{ - nano::unique_lock lock{ mutex }; - stopped = true; - notify (); -} - void nano::election_scheduler::flush () { nano::unique_lock lock{ mutex }; @@ -113,7 +124,6 @@ bool nano::election_scheduler::overfill_predicate () const void nano::election_scheduler::run () { - nano::thread_role::set (nano::thread_role::name::election_scheduler); nano::unique_lock lock{ mutex }; while (!stopped) { diff --git a/nano/node/election_scheduler.hpp b/nano/node/election_scheduler.hpp index 82eafdf4..9136c11b 100644 --- a/nano/node/election_scheduler.hpp +++ b/nano/node/election_scheduler.hpp @@ -15,11 +15,16 @@ namespace nano { class block; class node; + class election_scheduler final { public: - election_scheduler (nano::node & node); + election_scheduler (nano::node &); ~election_scheduler (); + + void start (); + void stop (); + // Manualy start an election for a block // Call action with confirmed block, may be different than what we started with void manual (std::shared_ptr const &, boost::optional const & = boost::none, nano::election_behavior = nano::election_behavior::normal, std::function const &)> const & = nullptr); @@ -28,7 +33,6 @@ public: * @return true if account was activated */ bool activate (nano::account const &, nano::transaction const &); - void stop (); // Blocks until no more elections can be activated or there are no more elections to activate void flush (); void notify (); @@ -37,16 +41,20 @@ public: std::size_t priority_queue_size () const; std::unique_ptr collect_container_info (std::string const &); +private: // Dependencies + nano::node & node; + private: void run (); bool empty_locked () const; bool priority_queue_predicate () const; bool manual_queue_predicate () const; bool overfill_predicate () const; + nano::prioritization priority; std::deque, boost::optional, nano::election_behavior, std::function)>>> manual_queue; - nano::node & node; - bool stopped; + + bool stopped{ false }; nano::condition_variable condition; mutable nano::mutex mutex; std::thread thread; diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 70eb5a9a..9402b942 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -696,6 +696,7 @@ void nano::node::start () active.start (); generator.start (); final_generator.start (); + scheduler.start (); backlog.start (); hinting.start (); bootstrap_server.start (); @@ -704,37 +705,41 @@ void nano::node::start () void nano::node::stop () { - if (!stopped.exchange (true)) + // Ensure stop can only be called once + if (stopped.exchange (true)) { - logger.always_log ("Node stopping"); - // Cancels ongoing work generation tasks, which may be blocking other threads - // No tasks may wait for work generation in I/O threads, or termination signal capturing will be unable to call node::stop() - distributed_work.stop (); - backlog.stop (); - unchecked.stop (); - block_processor.stop (); - aggregator.stop (); - vote_processor.stop (); - scheduler.stop (); - hinting.stop (); - active.stop (); - generator.stop (); - final_generator.stop (); - confirmation_height_processor.stop (); - network.stop (); - telemetry->stop (); - websocket.stop (); - bootstrap_server.stop (); - bootstrap_initiator.stop (); - tcp_listener.stop (); - port_mapping.stop (); - checker.stop (); - wallets.stop (); - stats.stop (); - epoch_upgrader.stop (); - workers.stop (); - // work pool is not stopped on purpose due to testing setup + return; } + + logger.always_log ("Node stopping"); + + // Cancels ongoing work generation tasks, which may be blocking other threads + // No tasks may wait for work generation in I/O threads, or termination signal capturing will be unable to call node::stop() + distributed_work.stop (); + backlog.stop (); + unchecked.stop (); + block_processor.stop (); + aggregator.stop (); + vote_processor.stop (); + scheduler.stop (); + hinting.stop (); + active.stop (); + generator.stop (); + final_generator.stop (); + confirmation_height_processor.stop (); + network.stop (); + telemetry->stop (); + websocket.stop (); + bootstrap_server.stop (); + bootstrap_initiator.stop (); + tcp_listener.stop (); + port_mapping.stop (); + checker.stop (); + wallets.stop (); + stats.stop (); + epoch_upgrader.stop (); + workers.stop (); + // work pool is not stopped on purpose due to testing setup } void nano::node::keepalive_preconfigured (std::vector const & peers_a)