Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Election flush #3265

Merged
merged 5 commits into from
May 6, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion nano/core_test/election_scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,11 @@ TEST (election_scheduler, no_vacancy)
.work (*system.work.generate (key.pub))
.build_shared ();
ASSERT_EQ (nano::process_result::progress, node.process (*send).code);
nano::blocks_confirm (node, { send }, true);
ASSERT_TIMELY (1s, node.active.empty ());
ASSERT_EQ (nano::process_result::progress, node.process (*receive).code);
nano::blocks_confirm (node, { send, receive }, true);
nano::blocks_confirm (node, { receive }, true);
ASSERT_TIMELY (1s, node.active.empty ());

// Second, process two eligble transactions
auto block0 = builder.make_block ()
Expand Down Expand Up @@ -118,3 +121,28 @@ TEST (election_scheduler, no_vacancy)
auto election4 = node.active.election (block1->qualified_root ());
ASSERT_NE (nullptr, election4);
}

// Ensure that election_scheduler::flush terminates even if no elections can currently be queued e.g. shutdown or no active_transactions vacancy
TEST (election_scheduler, flush_vacancy)
thsfs marked this conversation as resolved.
Show resolved Hide resolved
{
nano::system system;
nano::node_config config{ nano::get_available_port (), system.logging };
// No elections can be activated
config.active_elections_size = 0;
auto & node = *system.add_node (config);
nano::state_block_builder builder;
nano::keypair key;

auto send = builder.make_block ()
.account (nano::dev_genesis_key.pub)
.previous (nano::genesis_hash)
.representative (nano::dev_genesis_key.pub)
.link (key.pub)
.balance (nano::genesis_amount - nano::Gxrb_ratio)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (nano::genesis_hash))
.build_shared ();
node.scheduler.manual (send);
// Ensure this call does not block, even though no elections can be activated.
node.scheduler.flush ();
}
23 changes: 13 additions & 10 deletions nano/node/election_scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ void nano::election_scheduler::manual (std::shared_ptr<nano::block> const & bloc
{
nano::lock_guard<nano::mutex> lock{ mutex };
manual_queue.push_back (std::make_tuple (block_a, previous_balance_a, election_behavior_a, confirmation_action_a));
observe ();
notify ();
}

void nano::election_scheduler::activate (nano::account const & account_a, nano::transaction const & transaction)
Expand All @@ -39,7 +39,7 @@ void nano::election_scheduler::activate (nano::account const & account_a, nano::
{
nano::lock_guard<nano::mutex> lock{ mutex };
priority.push (account_info.modified, block);
observe ();
notify ();
}
}
}
Expand All @@ -49,20 +49,18 @@ void nano::election_scheduler::stop ()
{
nano::unique_lock<nano::mutex> lock{ mutex };
stopped = true;
observe ();
notify ();
}

void nano::election_scheduler::flush ()
{
nano::unique_lock<nano::mutex> lock{ mutex };
auto priority_target = priority_queued + priority.size ();
auto manual_target = manual_queued + manual_queue.size ();
condition.wait (lock, [this, &priority_target, &manual_target] () {
return priority_queued >= priority_target && manual_queued >= manual_target;
condition.wait (lock, [this] () {
return stopped || empty_locked () || node.active.vacancy () <= 0;
});
}

void nano::election_scheduler::observe ()
void nano::election_scheduler::notify ()
{
condition.notify_all ();
}
Expand All @@ -73,10 +71,15 @@ size_t nano::election_scheduler::size () const
return priority.size () + manual_queue.size ();
}

bool nano::election_scheduler::empty_locked () const
{
return priority.empty () && manual_queue.empty ();
}

bool nano::election_scheduler::empty () const
{
nano::lock_guard<nano::mutex> lock{ mutex };
return priority.empty () && manual_queue.empty ();
return empty_locked ();
}

size_t nano::election_scheduler::priority_queue_size () const
Expand Down Expand Up @@ -120,7 +123,7 @@ void nano::election_scheduler::run ()
manual_queue.pop_front ();
++manual_queued;
}
observe ();
notify ();
}
}
}
3 changes: 2 additions & 1 deletion nano/node/election_scheduler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@ class election_scheduler final
void activate (nano::account const &, nano::transaction const &);
void stop ();
void flush ();
void observe ();
void notify ();
size_t size () const;
bool empty () const;
size_t priority_queue_size () const;

private:
void run ();
bool empty_locked () const;
nano::prioritization priority;
uint64_t priority_queued{ 0 };
std::deque<std::tuple<std::shared_ptr<nano::block>, boost::optional<nano::uint128_t>, nano::election_behavior, std::function<void (std::shared_ptr<nano::block>)>>> manual_queue;
Expand Down
2 changes: 1 addition & 1 deletion nano/node/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ nano::node::node (boost::asio::io_context & io_ctx_a, boost::filesystem::path co
{
telemetry->start ();

active.vacancy_update = [this] () { scheduler.observe (); };
active.vacancy_update = [this] () { scheduler.notify (); };

if (config.websocket_config.enabled)
{
Expand Down