Confirming set background
This commit is contained in:
parent
30f2de0439
commit
ec8f324a3f
8 changed files with 130 additions and 60 deletions
|
|
@ -19,13 +19,13 @@ using namespace std::chrono_literals;
|
||||||
TEST (confirming_set, construction)
|
TEST (confirming_set, construction)
|
||||||
{
|
{
|
||||||
auto ctx = nano::test::context::ledger_empty ();
|
auto ctx = nano::test::context::ledger_empty ();
|
||||||
nano::confirming_set confirming_set (ctx.ledger ());
|
nano::confirming_set confirming_set (ctx.ledger (), ctx.stats ());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST (confirming_set, add_exists)
|
TEST (confirming_set, add_exists)
|
||||||
{
|
{
|
||||||
auto ctx = nano::test::context::ledger_send_receive ();
|
auto ctx = nano::test::context::ledger_send_receive ();
|
||||||
nano::confirming_set confirming_set (ctx.ledger ());
|
nano::confirming_set confirming_set (ctx.ledger (), ctx.stats ());
|
||||||
auto send = ctx.blocks ()[0];
|
auto send = ctx.blocks ()[0];
|
||||||
confirming_set.add (send->hash ());
|
confirming_set.add (send->hash ());
|
||||||
ASSERT_TRUE (confirming_set.exists (send->hash ()));
|
ASSERT_TRUE (confirming_set.exists (send->hash ()));
|
||||||
|
|
@ -34,7 +34,7 @@ TEST (confirming_set, add_exists)
|
||||||
TEST (confirming_set, process_one)
|
TEST (confirming_set, process_one)
|
||||||
{
|
{
|
||||||
auto ctx = nano::test::context::ledger_send_receive ();
|
auto ctx = nano::test::context::ledger_send_receive ();
|
||||||
nano::confirming_set confirming_set (ctx.ledger ());
|
nano::confirming_set confirming_set (ctx.ledger (), ctx.stats ());
|
||||||
std::atomic<int> count = 0;
|
std::atomic<int> count = 0;
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
std::condition_variable condition;
|
std::condition_variable condition;
|
||||||
|
|
@ -50,7 +50,7 @@ TEST (confirming_set, process_one)
|
||||||
TEST (confirming_set, process_multiple)
|
TEST (confirming_set, process_multiple)
|
||||||
{
|
{
|
||||||
auto ctx = nano::test::context::ledger_send_receive ();
|
auto ctx = nano::test::context::ledger_send_receive ();
|
||||||
nano::confirming_set confirming_set (ctx.ledger ());
|
nano::confirming_set confirming_set (ctx.ledger (), ctx.stats ());
|
||||||
std::atomic<int> count = 0;
|
std::atomic<int> count = 0;
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
std::condition_variable condition;
|
std::condition_variable condition;
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ enum class type
|
||||||
socket,
|
socket,
|
||||||
confirmation_height,
|
confirmation_height,
|
||||||
confirmation_observer,
|
confirmation_observer,
|
||||||
|
confirming_set,
|
||||||
drop,
|
drop,
|
||||||
aggregator,
|
aggregator,
|
||||||
requests,
|
requests,
|
||||||
|
|
@ -114,6 +115,8 @@ enum class detail
|
||||||
rebroadcast,
|
rebroadcast,
|
||||||
queue_overflow,
|
queue_overflow,
|
||||||
triggered,
|
triggered,
|
||||||
|
notify,
|
||||||
|
duplicate,
|
||||||
|
|
||||||
// processing queue
|
// processing queue
|
||||||
queue,
|
queue,
|
||||||
|
|
@ -440,6 +443,9 @@ enum class detail
|
||||||
tier_2,
|
tier_2,
|
||||||
tier_3,
|
tier_3,
|
||||||
|
|
||||||
|
// confirming_set
|
||||||
|
confirmed,
|
||||||
|
|
||||||
_last // Must be the last enum
|
_last // Must be the last enum
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ namespace nano
|
||||||
class thread_pool final
|
class thread_pool final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit thread_pool (unsigned, nano::thread_role::name);
|
explicit thread_pool (unsigned num_threads, nano::thread_role::name);
|
||||||
~thread_pool ();
|
~thread_pool ();
|
||||||
|
|
||||||
/** This will run when there is an available thread for execution */
|
/** This will run when there is an available thread for execution */
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,9 @@ std::string nano::thread_role::get_string (nano::thread_role::name role)
|
||||||
case nano::thread_role::name::confirmation_height_processing:
|
case nano::thread_role::name::confirmation_height_processing:
|
||||||
thread_role_name_string = "Conf height";
|
thread_role_name_string = "Conf height";
|
||||||
break;
|
break;
|
||||||
|
case nano::thread_role::name::confirmation_height_notifications:
|
||||||
|
thread_role_name_string = "Conf notif";
|
||||||
|
break;
|
||||||
case nano::thread_role::name::worker:
|
case nano::thread_role::name::worker:
|
||||||
thread_role_name_string = "Worker";
|
thread_role_name_string = "Worker";
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ enum class name
|
||||||
rpc_request_processor,
|
rpc_request_processor,
|
||||||
rpc_process_container,
|
rpc_process_container,
|
||||||
confirmation_height_processing,
|
confirmation_height_processing,
|
||||||
|
confirmation_height_notifications,
|
||||||
worker,
|
worker,
|
||||||
bootstrap_worker,
|
bootstrap_worker,
|
||||||
request_aggregator,
|
request_aggregator,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include "node.hpp"
|
||||||
|
|
||||||
#include <nano/lib/thread_roles.hpp>
|
#include <nano/lib/thread_roles.hpp>
|
||||||
#include <nano/node/confirming_set.hpp>
|
#include <nano/node/confirming_set.hpp>
|
||||||
#include <nano/secure/ledger.hpp>
|
#include <nano/secure/ledger.hpp>
|
||||||
|
|
@ -5,9 +7,11 @@
|
||||||
#include <nano/store/component.hpp>
|
#include <nano/store/component.hpp>
|
||||||
#include <nano/store/write_queue.hpp>
|
#include <nano/store/write_queue.hpp>
|
||||||
|
|
||||||
nano::confirming_set::confirming_set (nano::ledger & ledger, std::chrono::milliseconds batch_time) :
|
nano::confirming_set::confirming_set (nano::ledger & ledger, nano::stats & stats, std::chrono::milliseconds batch_time) :
|
||||||
ledger{ ledger },
|
ledger{ ledger },
|
||||||
batch_time{ batch_time }
|
stats{ stats },
|
||||||
|
batch_time{ batch_time },
|
||||||
|
workers{ 1, nano::thread_role::name::confirmation_height_notifications }
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -17,15 +21,30 @@ nano::confirming_set::~confirming_set ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void nano::confirming_set::add (nano::block_hash const & hash)
|
void nano::confirming_set::add (nano::block_hash const & hash)
|
||||||
|
{
|
||||||
|
bool added = false;
|
||||||
{
|
{
|
||||||
std::lock_guard lock{ mutex };
|
std::lock_guard lock{ mutex };
|
||||||
set.insert (hash);
|
auto [it, inserted] = set.insert (hash);
|
||||||
|
added = inserted;
|
||||||
|
}
|
||||||
|
if (added)
|
||||||
|
{
|
||||||
condition.notify_all ();
|
condition.notify_all ();
|
||||||
|
stats.inc (nano::stat::type::confirming_set, nano::stat::detail::insert);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stats.inc (nano::stat::type::confirming_set, nano::stat::detail::duplicate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nano::confirming_set::start ()
|
void nano::confirming_set::start ()
|
||||||
{
|
{
|
||||||
thread = std::thread{ [this] () { run (); } };
|
thread = std::thread{ [this] () {
|
||||||
|
nano::thread_role::set (nano::thread_role::name::confirmation_height_processing);
|
||||||
|
run ();
|
||||||
|
} };
|
||||||
}
|
}
|
||||||
|
|
||||||
void nano::confirming_set::stop ()
|
void nano::confirming_set::stop ()
|
||||||
|
|
@ -39,6 +58,7 @@ void nano::confirming_set::stop ()
|
||||||
{
|
{
|
||||||
thread.join ();
|
thread.join ();
|
||||||
}
|
}
|
||||||
|
workers.stop ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nano::confirming_set::exists (nano::block_hash const & hash) const
|
bool nano::confirming_set::exists (nano::block_hash const & hash) const
|
||||||
|
|
@ -55,45 +75,73 @@ std::size_t nano::confirming_set::size () const
|
||||||
|
|
||||||
void nano::confirming_set::run ()
|
void nano::confirming_set::run ()
|
||||||
{
|
{
|
||||||
nano::thread_role::set (nano::thread_role::name::confirmation_height_processing);
|
|
||||||
std::unique_lock lock{ mutex };
|
std::unique_lock lock{ mutex };
|
||||||
// Run the confirmation loop until stopped
|
|
||||||
while (!stopped)
|
while (!stopped)
|
||||||
{
|
{
|
||||||
condition.wait (lock, [&] () { return !set.empty () || stopped; });
|
stats.inc (nano::stat::type::confirming_set, nano::stat::detail::loop);
|
||||||
// Loop if there are items to process
|
|
||||||
if (!stopped && !set.empty ())
|
if (!set.empty ())
|
||||||
{
|
{
|
||||||
|
run_batch (lock);
|
||||||
|
debug_assert (lock.owns_lock ());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
condition.wait (lock, [&] () { return !set.empty () || stopped; });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nano::confirming_set::run_batch (std::unique_lock<std::mutex> & lock)
|
||||||
|
{
|
||||||
|
debug_assert (lock.owns_lock ());
|
||||||
|
debug_assert (!mutex.try_lock ());
|
||||||
|
debug_assert (!set.empty ());
|
||||||
|
|
||||||
std::deque<std::shared_ptr<nano::block>> cemented;
|
std::deque<std::shared_ptr<nano::block>> cemented;
|
||||||
std::deque<nano::block_hash> already;
|
std::deque<nano::block_hash> already;
|
||||||
|
|
||||||
// Move items in to back buffer and release lock so more items can be added to the front buffer
|
// Move items in to back buffer and release lock so more items can be added to the front buffer
|
||||||
processing = std::move (this->set);
|
release_assert (processing.empty ());
|
||||||
|
swap (set, processing);
|
||||||
|
|
||||||
// Process all items in the back buffer
|
// Process all items in the back buffer
|
||||||
for (auto i = processing.begin (), n = processing.end (); !stopped && i != n;)
|
for (auto i = processing.begin (), n = processing.end (); !stopped && i != n;)
|
||||||
{
|
{
|
||||||
lock.unlock (); // Waiting for db write is potentially slow
|
lock.unlock (); // Waiting for db write is potentially slow
|
||||||
|
|
||||||
auto guard = ledger.store.write_queue.wait (nano::store::writer::confirmation_height);
|
auto guard = ledger.store.write_queue.wait (nano::store::writer::confirmation_height);
|
||||||
auto tx = ledger.tx_begin_write ({ nano::tables::confirmation_height });
|
auto tx = ledger.tx_begin_write ({ nano::tables::confirmation_height });
|
||||||
|
|
||||||
lock.lock ();
|
lock.lock ();
|
||||||
// Process items in the back buffer within a single transaction for a limited amount of time
|
// Process items in the back buffer within a single transaction for a limited amount of time
|
||||||
for (auto timeout = std::chrono::steady_clock::now () + batch_time; !stopped && std::chrono::steady_clock::now () < timeout && i != n; ++i)
|
for (auto timeout = std::chrono::steady_clock::now () + batch_time; !stopped && std::chrono::steady_clock::now () < timeout && i != n; ++i)
|
||||||
{
|
{
|
||||||
auto item = *i;
|
auto item = *i;
|
||||||
lock.unlock ();
|
lock.unlock ();
|
||||||
|
|
||||||
auto added = ledger.confirm (tx, item);
|
auto added = ledger.confirm (tx, item);
|
||||||
if (!added.empty ())
|
if (!added.empty ())
|
||||||
{
|
{
|
||||||
// Confirming this block may implicitly confirm more
|
// Confirming this block may implicitly confirm more
|
||||||
cemented.insert (cemented.end (), added.begin (), added.end ());
|
cemented.insert (cemented.end (), added.begin (), added.end ());
|
||||||
|
stats.add (nano::stat::type::confirming_set, nano::stat::detail::confirmed, added.size ());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
already.push_back (item);
|
already.push_back (item);
|
||||||
|
stats.inc (nano::stat::type::confirming_set, nano::stat::detail::already_confirmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
lock.lock ();
|
lock.lock ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lock.unlock ();
|
lock.unlock ();
|
||||||
|
|
||||||
|
workers.push_task ([this, cemented = std::move (cemented), already = std::move (already)] () {
|
||||||
|
stats.inc (nano::stat::type::confirming_set, nano::stat::detail::notify);
|
||||||
|
|
||||||
for (auto const & i : cemented)
|
for (auto const & i : cemented)
|
||||||
{
|
{
|
||||||
cemented_observers.notify (i);
|
cemented_observers.notify (i);
|
||||||
|
|
@ -102,11 +150,11 @@ void nano::confirming_set::run ()
|
||||||
{
|
{
|
||||||
block_already_cemented_observers.notify (i);
|
block_already_cemented_observers.notify (i);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
lock.lock ();
|
lock.lock ();
|
||||||
// Clear and free back buffer by re-initializing
|
|
||||||
processing = decltype (processing){};
|
processing.clear ();
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<nano::container_info_component> nano::confirming_set::collect_container_info (std::string const & name) const
|
std::unique_ptr<nano::container_info_component> nano::confirming_set::collect_container_info (std::string const & name) const
|
||||||
|
|
@ -116,5 +164,6 @@ std::unique_ptr<nano::container_info_component> nano::confirming_set::collect_co
|
||||||
auto composite = std::make_unique<container_info_composite> (name);
|
auto composite = std::make_unique<container_info_composite> (name);
|
||||||
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "set", set.size (), sizeof (typename decltype (set)::value_type) }));
|
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "set", set.size (), sizeof (typename decltype (set)::value_type) }));
|
||||||
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "processing", processing.size (), sizeof (typename decltype (processing)::value_type) }));
|
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "processing", processing.size (), sizeof (typename decltype (processing)::value_type) }));
|
||||||
|
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "notifications", workers.num_queued_tasks (), sizeof (std::function<void ()>) }));
|
||||||
return composite;
|
return composite;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <nano/lib/numbers.hpp>
|
#include <nano/lib/numbers.hpp>
|
||||||
#include <nano/lib/observer_set.hpp>
|
#include <nano/lib/observer_set.hpp>
|
||||||
|
#include <nano/lib/thread_pool.hpp>
|
||||||
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
@ -11,8 +12,10 @@
|
||||||
|
|
||||||
namespace nano
|
namespace nano
|
||||||
{
|
{
|
||||||
|
class node;
|
||||||
class block;
|
class block;
|
||||||
class ledger;
|
class ledger;
|
||||||
|
class stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace nano
|
namespace nano
|
||||||
|
|
@ -26,8 +29,9 @@ class confirming_set final
|
||||||
friend class confirmation_height_pruned_source_Test;
|
friend class confirmation_height_pruned_source_Test;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
confirming_set (nano::ledger & ledger, std::chrono::milliseconds batch_time = std::chrono::milliseconds{ 500 });
|
confirming_set (nano::ledger &, nano::stats &, std::chrono::milliseconds batch_time = std::chrono::milliseconds{ 500 });
|
||||||
~confirming_set ();
|
~confirming_set ();
|
||||||
|
|
||||||
// Adds a block to the set of blocks to be confirmed
|
// Adds a block to the set of blocks to be confirmed
|
||||||
void add (nano::block_hash const & hash);
|
void add (nano::block_hash const & hash);
|
||||||
void start ();
|
void start ();
|
||||||
|
|
@ -43,10 +47,17 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void run ();
|
void run ();
|
||||||
|
void run_batch (std::unique_lock<std::mutex> &);
|
||||||
|
|
||||||
nano::ledger & ledger;
|
nano::ledger & ledger;
|
||||||
std::chrono::milliseconds batch_time;
|
nano::stats & stats;
|
||||||
|
|
||||||
|
std::chrono::milliseconds const batch_time;
|
||||||
std::unordered_set<nano::block_hash> set;
|
std::unordered_set<nano::block_hash> set;
|
||||||
std::unordered_set<nano::block_hash> processing;
|
std::unordered_set<nano::block_hash> processing;
|
||||||
|
|
||||||
|
nano::thread_pool workers;
|
||||||
|
|
||||||
bool stopped{ false };
|
bool stopped{ false };
|
||||||
mutable std::mutex mutex;
|
mutable std::mutex mutex;
|
||||||
std::condition_variable condition;
|
std::condition_variable condition;
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ nano::node::node (std::shared_ptr<boost::asio::io_context> io_ctx_a, std::filesy
|
||||||
application_path (application_path_a),
|
application_path (application_path_a),
|
||||||
port_mapping (*this),
|
port_mapping (*this),
|
||||||
block_processor (*this),
|
block_processor (*this),
|
||||||
confirming_set_impl{ std::make_unique<nano::confirming_set> (ledger, config.confirming_set_batch_time) },
|
confirming_set_impl{ std::make_unique<nano::confirming_set> (ledger, stats, config.confirming_set_batch_time) },
|
||||||
confirming_set{ *confirming_set_impl },
|
confirming_set{ *confirming_set_impl },
|
||||||
active_impl{ std::make_unique<nano::active_elections> (*this, confirming_set, block_processor) },
|
active_impl{ std::make_unique<nano::active_elections> (*this, confirming_set, block_processor) },
|
||||||
active{ *active_impl },
|
active{ *active_impl },
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue