Comments and cleanup

This commit is contained in:
Piotr Wójcik 2024-09-26 17:07:58 +02:00
commit 4b65877fe5
4 changed files with 97 additions and 84 deletions

View file

@ -136,6 +136,7 @@ std::unique_ptr<nano::container_info_component> nano::bootstrap_ascending::front
boost::multiprecision::cpp_dec_float_50 next{ head.next.number ().str () };
boost::multiprecision::cpp_dec_float_50 end{ head.end.number ().str () };
// Progress in the range [0, 1000000] since we can only represent `size_t` integers in the container_info data
boost::multiprecision::cpp_dec_float_50 progress = (next - start) * boost::multiprecision::cpp_dec_float_50 (1000000) / (end - start);
composite->add_component (std::make_unique<container_info_leaf> (container_info{ std::to_string (n), progress.convert_to<std::uint64_t> (), 6 }));

View file

@ -19,6 +19,10 @@ namespace mi = boost::multi_index;
namespace nano::bootstrap_ascending
{
/*
* Frontier scan divides the account space into ranges and scans each range for outdated frontiers in parallel.
* This class is used to track the progress of each range.
*/
class frontier_scan
{
public:
@ -34,6 +38,7 @@ private: // Dependencies
nano::stats & stats;
private:
// Represents a range of accounts to scan, once the full range is scanned (goes past `end`) the head wraps around (to the `start`)
struct frontier_head
{
frontier_head (nano::account start_a, nano::account end_a) :
@ -44,9 +49,10 @@ private:
}
// The range of accounts to scan is [start, end)
nano::account start;
nano::account end;
nano::account const start;
nano::account const end;
// We scan the range by querying frontiers starting at 'next' and gathering candidates
nano::account next;
std::set<nano::account> candidates;
@ -54,6 +60,11 @@ private:
unsigned completed{ 0 };
std::chrono::steady_clock::time_point timestamp{};
size_t processed{ 0 }; // Total number of accounts processed
nano::account index () const
{
return start;
}
};
// clang-format off
@ -65,7 +76,7 @@ private:
mi::indexed_by<
mi::random_access<mi::tag<tag_sequenced>>,
mi::ordered_unique<mi::tag<tag_start>,
mi::member<frontier_head, nano::account, &frontier_head::start>>,
mi::const_mem_fun<frontier_head, nano::account, &frontier_head::index>>,
mi::ordered_non_unique<mi::tag<tag_timestamp>,
mi::member<frontier_head, std::chrono::steady_clock::time_point, &frontier_head::timestamp>>
>>;

View file

@ -635,86 +635,6 @@ void nano::bootstrap_ascending::service::run_frontiers ()
}
}
void nano::bootstrap_ascending::service::process_frontiers (std::deque<std::pair<nano::account, nano::block_hash>> const & frontiers)
{
release_assert (!frontiers.empty ());
// Accounts must be passed in ascending order
debug_assert (std::adjacent_find (frontiers.begin (), frontiers.end (), [] (auto const & lhs, auto const & rhs) {
return lhs.first.number () >= rhs.first.number ();
})
== frontiers.end ());
stats.inc (nano::stat::type::bootstrap_ascending, nano::stat::detail::process_frontiers);
size_t outdated = 0;
size_t pending = 0;
// Accounts with outdated frontiers to sync
std::deque<nano::account> result;
{
auto transaction = ledger.tx_begin_read ();
auto const start = frontiers.front ().first;
account_database_crawler account_crawler{ ledger.store, transaction, start };
pending_database_crawler pending_crawler{ ledger.store, transaction, start };
auto block_exists = [&] (nano::block_hash const & hash) {
return ledger.any.block_exists_or_pruned (transaction, hash);
};
auto should_prioritize = [&] (nano::account const & account, nano::block_hash const & frontier) {
account_crawler.advance_to (account);
pending_crawler.advance_to (account);
// Check if account exists in our ledger
if (account_crawler.current && account_crawler.current->first == account)
{
// Check for frontier mismatch
if (account_crawler.current->second.head != frontier)
{
// Check if frontier block exists in our ledger
if (!block_exists (frontier))
{
outdated++;
return true; // Frontier is outdated
}
}
return false; // Account exists and frontier is up-to-date
}
// Check if account has pending blocks in our ledger
if (pending_crawler.current && pending_crawler.current->first.account == account)
{
pending++;
return true; // Account doesn't exist but has pending blocks in the ledger
}
return false; // Account doesn't exist in the ledger and has no pending blocks, can't be prioritized right now
};
for (auto const & [account, frontier] : frontiers)
{
if (should_prioritize (account, frontier))
{
result.push_back (account);
}
}
}
stats.add (nano::stat::type::bootstrap_ascending, nano::stat::detail::frontiers_processed, frontiers.size ());
stats.add (nano::stat::type::bootstrap_ascending, nano::stat::detail::frontiers_prioritized, result.size ());
stats.add (nano::stat::type::bootstrap_ascending, nano::stat::detail::frontiers_outdated, outdated);
stats.add (nano::stat::type::bootstrap_ascending, nano::stat::detail::frontiers_pending, pending);
nano::lock_guard<nano::mutex> guard{ mutex };
for (auto const & account : result)
{
accounts.priority_set (account);
}
}
void nano::bootstrap_ascending::service::cleanup_and_sync ()
{
debug_assert (!mutex.try_lock ());
@ -968,6 +888,86 @@ void nano::bootstrap_ascending::service::process (const nano::empty_payload & re
debug_assert (false, "empty payload"); // Should not happen
}
void nano::bootstrap_ascending::service::process_frontiers (std::deque<std::pair<nano::account, nano::block_hash>> const & frontiers)
{
release_assert (!frontiers.empty ());
// Accounts must be passed in ascending order
debug_assert (std::adjacent_find (frontiers.begin (), frontiers.end (), [] (auto const & lhs, auto const & rhs) {
return lhs.first.number () >= rhs.first.number ();
})
== frontiers.end ());
stats.inc (nano::stat::type::bootstrap_ascending, nano::stat::detail::process_frontiers);
size_t outdated = 0;
size_t pending = 0;
// Accounts with outdated frontiers to sync
std::deque<nano::account> result;
{
auto transaction = ledger.tx_begin_read ();
auto const start = frontiers.front ().first;
account_database_crawler account_crawler{ ledger.store, transaction, start };
pending_database_crawler pending_crawler{ ledger.store, transaction, start };
auto block_exists = [&] (nano::block_hash const & hash) {
return ledger.any.block_exists_or_pruned (transaction, hash);
};
auto should_prioritize = [&] (nano::account const & account, nano::block_hash const & frontier) {
account_crawler.advance_to (account);
pending_crawler.advance_to (account);
// Check if account exists in our ledger
if (account_crawler.current && account_crawler.current->first == account)
{
// Check for frontier mismatch
if (account_crawler.current->second.head != frontier)
{
// Check if frontier block exists in our ledger
if (!block_exists (frontier))
{
outdated++;
return true; // Frontier is outdated
}
}
return false; // Account exists and frontier is up-to-date
}
// Check if account has pending blocks in our ledger
if (pending_crawler.current && pending_crawler.current->first.account == account)
{
pending++;
return true; // Account doesn't exist but has pending blocks in the ledger
}
return false; // Account doesn't exist in the ledger and has no pending blocks, can't be prioritized right now
};
for (auto const & [account, frontier] : frontiers)
{
if (should_prioritize (account, frontier))
{
result.push_back (account);
}
}
}
stats.add (nano::stat::type::bootstrap_ascending, nano::stat::detail::frontiers_processed, frontiers.size ());
stats.add (nano::stat::type::bootstrap_ascending, nano::stat::detail::frontiers_prioritized, result.size ());
stats.add (nano::stat::type::bootstrap_ascending, nano::stat::detail::frontiers_outdated, outdated);
stats.add (nano::stat::type::bootstrap_ascending, nano::stat::detail::frontiers_pending, pending);
nano::lock_guard<nano::mutex> guard{ mutex };
for (auto const & account : result)
{
accounts.priority_set (account);
}
}
nano::bootstrap_ascending::service::verify_result nano::bootstrap_ascending::service::verify (const nano::asc_pull_ack::blocks_payload & response, const nano::bootstrap_ascending::service::async_tag & tag) const
{
auto const & blocks = response.blocks;

View file

@ -109,7 +109,6 @@ namespace bootstrap_ascending
void run_frontiers ();
void run_timeouts ();
void cleanup_and_sync ();
void process_frontiers (std::deque<std::pair<nano::account, nano::block_hash>> const & frontiers);
/* Waits for a condition to be satisfied with incremental backoff */
void wait (std::function<bool ()> const & predicate) const;
@ -142,6 +141,8 @@ namespace bootstrap_ascending
void process (nano::asc_pull_ack::frontiers_payload const & response, async_tag const & tag);
void process (nano::empty_payload const & response, async_tag const & tag);
void process_frontiers (std::deque<std::pair<nano::account, nano::block_hash>> const & frontiers);
enum class verify_result
{
ok,