119 lines
3.5 KiB
C++
119 lines
3.5 KiB
C++
#include <nano/lib/thread_roles.hpp>
|
|
#include <nano/node/confirming_set.hpp>
|
|
#include <nano/secure/ledger.hpp>
|
|
#include <nano/store/component.hpp>
|
|
#include <nano/store/write_queue.hpp>
|
|
|
|
nano::confirming_set::confirming_set (nano::ledger & ledger, std::chrono::milliseconds batch_time) :
|
|
ledger{ ledger },
|
|
batch_time{ batch_time }
|
|
{
|
|
}
|
|
|
|
nano::confirming_set::~confirming_set ()
|
|
{
|
|
debug_assert (!thread.joinable ());
|
|
}
|
|
|
|
void nano::confirming_set::add (nano::block_hash const & hash)
|
|
{
|
|
std::lock_guard lock{ mutex };
|
|
set.insert (hash);
|
|
condition.notify_all ();
|
|
}
|
|
|
|
void nano::confirming_set::start ()
|
|
{
|
|
thread = std::thread{ [this] () { run (); } };
|
|
}
|
|
|
|
void nano::confirming_set::stop ()
|
|
{
|
|
{
|
|
std::lock_guard lock{ mutex };
|
|
stopped = true;
|
|
condition.notify_all ();
|
|
}
|
|
if (thread.joinable ())
|
|
{
|
|
thread.join ();
|
|
}
|
|
}
|
|
|
|
bool nano::confirming_set::exists (nano::block_hash const & hash) const
|
|
{
|
|
std::lock_guard lock{ mutex };
|
|
return set.count (hash) != 0 || processing.count (hash) != 0;
|
|
}
|
|
|
|
std::size_t nano::confirming_set::size () const
|
|
{
|
|
std::lock_guard lock{ mutex };
|
|
return set.size () + processing.size ();
|
|
}
|
|
|
|
void nano::confirming_set::run ()
|
|
{
|
|
nano::thread_role::set (nano::thread_role::name::confirmation_height_processing);
|
|
std::unique_lock lock{ mutex };
|
|
// Run the confirmation loop until stopped
|
|
while (!stopped)
|
|
{
|
|
condition.wait (lock, [&] () { return !set.empty () || stopped; });
|
|
// Loop if there are items to process
|
|
if (!stopped && !set.empty ())
|
|
{
|
|
std::deque<std::shared_ptr<nano::block>> cemented;
|
|
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
|
|
processing = std::move (this->set);
|
|
// Process all items in the back buffer
|
|
for (auto i = processing.begin (), n = processing.end (); !stopped && i != n;)
|
|
{
|
|
lock.unlock (); // Waiting for db write is potentially slow
|
|
auto guard = ledger.store.write_queue.wait (nano::store::writer::confirmation_height);
|
|
auto tx = ledger.tx_begin_write ({ nano::tables::confirmation_height });
|
|
lock.lock ();
|
|
// 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)
|
|
{
|
|
auto item = *i;
|
|
lock.unlock ();
|
|
auto added = ledger.confirm (tx, item);
|
|
if (!added.empty ())
|
|
{
|
|
// Confirming this block may implicitly confirm more
|
|
cemented.insert (cemented.end (), added.begin (), added.end ());
|
|
}
|
|
else
|
|
{
|
|
already.push_back (item);
|
|
}
|
|
lock.lock ();
|
|
}
|
|
}
|
|
lock.unlock ();
|
|
for (auto const & i : cemented)
|
|
{
|
|
cemented_observers.notify (i);
|
|
}
|
|
for (auto const & i : already)
|
|
{
|
|
block_already_cemented_observers.notify (i);
|
|
}
|
|
lock.lock ();
|
|
// Clear and free back buffer by re-initializing
|
|
processing = decltype (processing){};
|
|
}
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<nano::container_info_component> nano::confirming_set::collect_container_info (std::string const & name) const
|
|
{
|
|
std::lock_guard guard{ mutex };
|
|
|
|
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{ "processing", processing.size (), sizeof (typename decltype (processing)::value_type) }));
|
|
return composite;
|
|
}
|