Lazy bootstrap retry limit (#2362)
- different retry limit for lazy destinations and possible links from state blocks (add retry limit to nano::bulk_pull) - start lazy pulls for all known destinations in lazy bootstrap attempt - dynamic bulk pull blocks limit for lazy bootstrap based on lazy blocks ratio (total processed blocks / lazy blocks) - don't clean unchecked for longest bootstrap attempts - use bootstrap network params - improve lock in process_block_lazy () - increase max lazy bootstrap duration - change max lazy keys limit - increase bootstrap_max_new_connections - fix: stop lazy bootstrap with stopped node - fix: proper reuse of of connections after lazy pull stop
This commit is contained in:
parent
ec289c134a
commit
62db44d4d6
8 changed files with 113 additions and 79 deletions
|
@ -12,9 +12,8 @@
|
|||
#include <algorithm>
|
||||
|
||||
constexpr double nano::bootstrap_limits::bootstrap_connection_scale_target_blocks;
|
||||
constexpr double nano::bootstrap_limits::bootstrap_connection_scale_target_blocks_lazy;
|
||||
constexpr double nano::bootstrap_limits::bootstrap_minimum_blocks_per_sec;
|
||||
constexpr unsigned nano::bootstrap_limits::bootstrap_frontier_retry_limit;
|
||||
constexpr unsigned nano::bootstrap_limits::bootstrap_lazy_retry_limit;
|
||||
constexpr double nano::bootstrap_limits::bootstrap_minimum_termination_time_sec;
|
||||
constexpr unsigned nano::bootstrap_limits::bootstrap_max_new_connections;
|
||||
constexpr size_t nano::bootstrap_limits::bootstrap_max_confirm_frontiers;
|
||||
|
@ -23,8 +22,9 @@ constexpr unsigned nano::bootstrap_limits::frontier_confirmation_blocks_limit;
|
|||
constexpr unsigned nano::bootstrap_limits::requeued_pulls_limit;
|
||||
constexpr unsigned nano::bootstrap_limits::requeued_pulls_limit_test;
|
||||
constexpr std::chrono::seconds nano::bootstrap_limits::lazy_flush_delay_sec;
|
||||
constexpr unsigned nano::bootstrap_limits::bootstrap_lazy_destinations_request_limit;
|
||||
constexpr std::chrono::seconds nano::bootstrap_limits::lazy_destinations_flush_delay_sec;
|
||||
constexpr unsigned nano::bootstrap_limits::lazy_destinations_request_limit;
|
||||
constexpr uint64_t nano::bootstrap_limits::lazy_batch_pull_count_resize_blocks_limit;
|
||||
constexpr double nano::bootstrap_limits::lazy_batch_pull_count_resize_ratio;
|
||||
constexpr std::chrono::hours nano::bootstrap_excluded_peers::exclude_time_hours;
|
||||
constexpr std::chrono::hours nano::bootstrap_excluded_peers::exclude_remove_hours;
|
||||
|
||||
|
@ -147,9 +147,7 @@ void nano::bootstrap_attempt::request_pull (nano::unique_lock<std::mutex> & lock
|
|||
if (mode != nano::bootstrap_mode::legacy)
|
||||
{
|
||||
// Check if pull is obsolete (head was processed)
|
||||
nano::lock_guard<std::mutex> lazy_lock (lazy_mutex);
|
||||
auto transaction (node->store.tx_begin_read ());
|
||||
while (!pulls.empty () && !pull.head.is_zero () && (lazy_blocks.find (pull.head) != lazy_blocks.end () || node->store.block_exists (transaction, pull.head)))
|
||||
while (!pulls.empty () && !pull.head.is_zero () && lazy_processed_or_exists (pull.head))
|
||||
{
|
||||
pull = pulls.front ();
|
||||
pulls.pop_front ();
|
||||
|
@ -270,6 +268,7 @@ void nano::bootstrap_attempt::run ()
|
|||
{
|
||||
lock.unlock ();
|
||||
mode = nano::bootstrap_mode::wallet_lazy;
|
||||
total_blocks = 0;
|
||||
wallet_run ();
|
||||
lock.lock ();
|
||||
}
|
||||
|
@ -278,6 +277,7 @@ void nano::bootstrap_attempt::run ()
|
|||
{
|
||||
lock.unlock ();
|
||||
mode = nano::bootstrap_mode::lazy;
|
||||
total_blocks = 0;
|
||||
lazy_run ();
|
||||
lock.lock ();
|
||||
}
|
||||
|
@ -335,7 +335,8 @@ unsigned nano::bootstrap_attempt::target_connections (size_t pulls_remaining)
|
|||
}
|
||||
|
||||
// Only scale up to bootstrap_connections_max for large pulls.
|
||||
double step_scale = std::min (1.0, std::max (0.0, (double)pulls_remaining / nano::bootstrap_limits::bootstrap_connection_scale_target_blocks));
|
||||
double target_blocks = (mode == nano::bootstrap_mode::lazy) ? nano::bootstrap_limits::bootstrap_connection_scale_target_blocks_lazy : nano::bootstrap_limits::bootstrap_connection_scale_target_blocks;
|
||||
double step_scale = std::min (1.0, std::max (0.0, (double)pulls_remaining / target_blocks));
|
||||
double lazy_term = (mode == nano::bootstrap_mode::lazy) ? (double)node->config.bootstrap_connections : 0.0;
|
||||
double target = (double)node->config.bootstrap_connections + (double)(node->config.bootstrap_connections_max - node->config.bootstrap_connections) * step_scale + lazy_term;
|
||||
return std::max (1U, (unsigned)(target + 0.5f));
|
||||
|
@ -501,7 +502,7 @@ void nano::bootstrap_attempt::pool_connection (std::shared_ptr<nano::bootstrap_c
|
|||
// Idle bootstrap client socket
|
||||
client_a->channel->socket->start_timer (node->network_params.node.idle_timeout);
|
||||
// Push into idle deque
|
||||
idle.push_front (client_a);
|
||||
idle.push_back (client_a);
|
||||
}
|
||||
condition.notify_all ();
|
||||
}
|
||||
|
@ -559,13 +560,13 @@ void nano::bootstrap_attempt::requeue_pull (nano::pull_info const & pull_a, bool
|
|||
++pull.attempts;
|
||||
}
|
||||
++requeued_pulls;
|
||||
if (pull.attempts < (!node->network_params.network.is_test_network () ? nano::bootstrap_limits::bootstrap_frontier_retry_limit : 1 + (pull.processed / 10000)))
|
||||
if (mode != nano::bootstrap_mode::lazy && pull.attempts < pull.retry_limit + (pull.processed / 10000))
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (mutex);
|
||||
pulls.push_front (pull);
|
||||
condition.notify_all ();
|
||||
}
|
||||
else if (mode == nano::bootstrap_mode::lazy && (pull.confirmed_head || pull.attempts <= (!node->network_params.network.is_test_network () ? nano::bootstrap_limits::bootstrap_lazy_retry_limit : (nano::bootstrap_limits::bootstrap_frontier_retry_limit / 8) + (pull.processed / node->network_params.bootstrap.lazy_max_pull_blocks))))
|
||||
else if (mode == nano::bootstrap_mode::lazy && (pull.retry_limit == std::numeric_limits<unsigned>::max () || pull.attempts <= pull.retry_limit + (pull.processed / node->network_params.bootstrap.lazy_max_pull_blocks)))
|
||||
{
|
||||
assert (pull.account_or_head == pull.head);
|
||||
if (!lazy_processed_or_exists (pull.account_or_head))
|
||||
|
@ -589,7 +590,7 @@ void nano::bootstrap_attempt::requeue_pull (nano::pull_info const & pull_a, bool
|
|||
{
|
||||
assert (pull.account_or_head == pull.head);
|
||||
nano::lock_guard<std::mutex> lazy_lock (lazy_mutex);
|
||||
lazy_add (pull.account_or_head, pull.confirmed_head);
|
||||
lazy_add (pull.account_or_head, pull.retry_limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -765,22 +766,22 @@ void nano::bootstrap_attempt::confirm_frontiers (nano::unique_lock<std::mutex> &
|
|||
void nano::bootstrap_attempt::lazy_start (nano::hash_or_account const & hash_or_account_a, bool confirmed)
|
||||
{
|
||||
nano::lock_guard<std::mutex> lazy_lock (lazy_mutex);
|
||||
// Add start blocks, limit 1024 (32k with disabled legacy bootstrap)
|
||||
size_t max_keys (node->flags.disable_legacy_bootstrap ? 32 * 1024 : 1024);
|
||||
// Add start blocks, limit 1024 (4k with disabled legacy bootstrap)
|
||||
size_t max_keys (node->flags.disable_legacy_bootstrap ? 4 * 1024 : 1024);
|
||||
if (lazy_keys.size () < max_keys && lazy_keys.find (hash_or_account_a) == lazy_keys.end () && lazy_blocks.find (hash_or_account_a) == lazy_blocks.end ())
|
||||
{
|
||||
lazy_keys.insert (hash_or_account_a);
|
||||
lazy_pulls.emplace_back (hash_or_account_a, confirmed);
|
||||
lazy_pulls.emplace_back (hash_or_account_a, confirmed ? std::numeric_limits<unsigned>::max () : node->network_params.bootstrap.lazy_retry_limit);
|
||||
}
|
||||
}
|
||||
|
||||
void nano::bootstrap_attempt::lazy_add (nano::hash_or_account const & hash_or_account_a, bool confirmed_head)
|
||||
void nano::bootstrap_attempt::lazy_add (nano::hash_or_account const & hash_or_account_a, unsigned retry_limit)
|
||||
{
|
||||
// Add only unknown blocks
|
||||
assert (!lazy_mutex.try_lock ());
|
||||
if (lazy_blocks.find (hash_or_account_a) == lazy_blocks.end ())
|
||||
{
|
||||
lazy_pulls.emplace_back (hash_or_account_a, confirmed_head);
|
||||
lazy_pulls.emplace_back (hash_or_account_a, retry_limit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -793,7 +794,7 @@ void nano::bootstrap_attempt::lazy_requeue (nano::block_hash const & hash_a, nan
|
|||
{
|
||||
lazy_blocks.erase (existing);
|
||||
lazy_mutex.unlock ();
|
||||
requeue_pull (nano::pull_info (hash_a, hash_a, previous_a, static_cast<nano::pull_info::count_t> (1), confirmed_a));
|
||||
requeue_pull (nano::pull_info (hash_a, hash_a, previous_a, static_cast<nano::pull_info::count_t> (1), confirmed_a ? std::numeric_limits<unsigned>::max () : node->network_params.bootstrap.lazy_destinations_retry_limit));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -802,14 +803,28 @@ void nano::bootstrap_attempt::lazy_pull_flush ()
|
|||
assert (!mutex.try_lock ());
|
||||
last_lazy_flush = std::chrono::steady_clock::now ();
|
||||
nano::lock_guard<std::mutex> lazy_lock (lazy_mutex);
|
||||
assert (node->network_params.bootstrap.lazy_max_pull_blocks <= std::numeric_limits<nano::pull_info::count_t>::max ());
|
||||
nano::pull_info::count_t batch_count (node->network_params.bootstrap.lazy_max_pull_blocks);
|
||||
if (total_blocks > nano::bootstrap_limits::lazy_batch_pull_count_resize_blocks_limit && !lazy_blocks.empty ())
|
||||
{
|
||||
double lazy_blocks_ratio (total_blocks / lazy_blocks.size ());
|
||||
if (lazy_blocks_ratio > nano::bootstrap_limits::lazy_batch_pull_count_resize_ratio)
|
||||
{
|
||||
// Increasing blocks ratio weight as more important (^3). Small batch count should lower blocks ratio below target
|
||||
double lazy_blocks_factor (std::pow (lazy_blocks_ratio / nano::bootstrap_limits::lazy_batch_pull_count_resize_ratio, 3.0));
|
||||
// Decreasing total block count weight as less important (sqrt)
|
||||
double total_blocks_factor (std::sqrt (total_blocks / nano::bootstrap_limits::lazy_batch_pull_count_resize_blocks_limit));
|
||||
uint32_t batch_count_min (node->network_params.bootstrap.lazy_max_pull_blocks / (lazy_blocks_factor * total_blocks_factor));
|
||||
batch_count = std::max (node->network_params.bootstrap.lazy_min_pull_blocks, batch_count_min);
|
||||
}
|
||||
}
|
||||
auto transaction (node->store.tx_begin_read ());
|
||||
for (auto & pull_start : lazy_pulls)
|
||||
{
|
||||
// Recheck if block was already processed
|
||||
if (lazy_blocks.find (pull_start.first) == lazy_blocks.end () && !node->store.block_exists (transaction, pull_start.first))
|
||||
{
|
||||
assert (node->network_params.bootstrap.lazy_max_pull_blocks <= std::numeric_limits<nano::pull_info::count_t>::max ());
|
||||
pulls.emplace_back (pull_start.first, pull_start.first, nano::block_hash (0), static_cast<nano::pull_info::count_t> (node->network_params.bootstrap.lazy_max_pull_blocks), pull_start.second);
|
||||
pulls.emplace_back (pull_start.first, pull_start.first, nano::block_hash (0), batch_count, pull_start.second);
|
||||
}
|
||||
}
|
||||
lazy_pulls.clear ();
|
||||
|
@ -817,6 +832,10 @@ void nano::bootstrap_attempt::lazy_pull_flush ()
|
|||
|
||||
bool nano::bootstrap_attempt::lazy_finished ()
|
||||
{
|
||||
if (stopped)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool result (true);
|
||||
auto transaction (node->store.tx_begin_read ());
|
||||
nano::lock_guard<std::mutex> lazy_lock (lazy_mutex);
|
||||
|
@ -838,6 +857,11 @@ bool nano::bootstrap_attempt::lazy_finished ()
|
|||
{
|
||||
result = true;
|
||||
}
|
||||
// Don't close lazy bootstrap until all destinations are processed
|
||||
if (result && !lazy_destinations.empty ())
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -857,7 +881,7 @@ void nano::bootstrap_attempt::lazy_run ()
|
|||
assert (!node->flags.disable_lazy_bootstrap);
|
||||
populate_connections ();
|
||||
auto start_time (std::chrono::steady_clock::now ());
|
||||
auto max_time (std::chrono::minutes (node->flags.disable_legacy_bootstrap ? 48 * 60 : 30));
|
||||
auto max_time (std::chrono::minutes (node->flags.disable_legacy_bootstrap ? 7 * 24 * 60 : 30));
|
||||
nano::unique_lock<std::mutex> lock (mutex);
|
||||
while ((still_pulling () || !lazy_finished ()) && std::chrono::steady_clock::now () - start_time < max_time)
|
||||
{
|
||||
|
@ -873,7 +897,7 @@ void nano::bootstrap_attempt::lazy_run ()
|
|||
lazy_pull_flush ();
|
||||
if (pulls.empty ())
|
||||
{
|
||||
condition.wait_for (lock, std::chrono::seconds (2));
|
||||
condition.wait_for (lock, std::chrono::seconds (1));
|
||||
}
|
||||
}
|
||||
++iterations;
|
||||
|
@ -882,16 +906,20 @@ void nano::bootstrap_attempt::lazy_run ()
|
|||
{
|
||||
lazy_pull_flush ();
|
||||
}
|
||||
// Start destinations check & backlog cleanup
|
||||
if (iterations % 200 == 0 && pulls.empty ())
|
||||
// Start backlog cleanup
|
||||
if (iterations % 200 == 0)
|
||||
{
|
||||
lazy_backlog_cleanup ();
|
||||
}
|
||||
// Destinations check
|
||||
if (pulls.empty () && lazy_destinations_flushed)
|
||||
{
|
||||
lazy_destinations_flush ();
|
||||
}
|
||||
}
|
||||
// Flushing lazy pulls
|
||||
lazy_pull_flush ();
|
||||
// Check if some blocks required for backlog were processed
|
||||
// Check if some blocks required for backlog were processed. Start destinations check
|
||||
if (pulls.empty ())
|
||||
{
|
||||
lazy_backlog_cleanup ();
|
||||
|
@ -931,12 +959,12 @@ void nano::bootstrap_attempt::lazy_run ()
|
|||
idle.clear ();
|
||||
}
|
||||
|
||||
bool nano::bootstrap_attempt::process_block (std::shared_ptr<nano::block> block_a, nano::account const & known_account_a, uint64_t pull_blocks, bool block_expected, bool confirmed_head)
|
||||
bool nano::bootstrap_attempt::process_block (std::shared_ptr<nano::block> block_a, nano::account const & known_account_a, uint64_t pull_blocks, nano::bulk_pull::count_t max_blocks, bool block_expected, unsigned retry_limit)
|
||||
{
|
||||
bool stop_pull (false);
|
||||
if (mode != nano::bootstrap_mode::legacy && block_expected)
|
||||
{
|
||||
stop_pull = process_block_lazy (block_a, known_account_a, pull_blocks, confirmed_head);
|
||||
stop_pull = process_block_lazy (block_a, known_account_a, pull_blocks, max_blocks, retry_limit);
|
||||
}
|
||||
else if (mode != nano::bootstrap_mode::legacy)
|
||||
{
|
||||
|
@ -951,24 +979,22 @@ bool nano::bootstrap_attempt::process_block (std::shared_ptr<nano::block> block_
|
|||
return stop_pull;
|
||||
}
|
||||
|
||||
bool nano::bootstrap_attempt::process_block_lazy (std::shared_ptr<nano::block> block_a, nano::account const & known_account_a, uint64_t pull_blocks, bool confirmed_head)
|
||||
bool nano::bootstrap_attempt::process_block_lazy (std::shared_ptr<nano::block> block_a, nano::account const & known_account_a, uint64_t pull_blocks, nano::bulk_pull::count_t max_blocks, unsigned retry_limit)
|
||||
{
|
||||
bool stop_pull (false);
|
||||
auto hash (block_a->hash ());
|
||||
nano::lock_guard<std::mutex> lazy_lock (lazy_mutex);
|
||||
nano::unique_lock<std::mutex> lazy_lock (lazy_mutex);
|
||||
// Processing new blocks
|
||||
if (lazy_blocks.find (hash) == lazy_blocks.end ())
|
||||
{
|
||||
nano::unchecked_info info (block_a, known_account_a, 0, nano::signature_verification::unknown, confirmed_head);
|
||||
node->block_processor.add (info);
|
||||
// Search for new dependencies
|
||||
if (!block_a->source ().is_zero () && !node->ledger.block_exists (block_a->source ()) && block_a->source () != node->network_params.ledger.genesis_account)
|
||||
{
|
||||
lazy_add (block_a->source (), confirmed_head);
|
||||
lazy_add (block_a->source (), retry_limit);
|
||||
}
|
||||
else if (block_a->type () == nano::block_type::state)
|
||||
{
|
||||
lazy_block_state (block_a, confirmed_head);
|
||||
lazy_block_state (block_a, retry_limit);
|
||||
}
|
||||
else if (block_a->type () == nano::block_type::send)
|
||||
{
|
||||
|
@ -990,16 +1016,19 @@ bool nano::bootstrap_attempt::process_block_lazy (std::shared_ptr<nano::block> b
|
|||
lazy_balances.erase (block_a->previous ());
|
||||
}
|
||||
lazy_block_state_backlog_check (block_a, hash);
|
||||
lazy_lock.unlock ();
|
||||
nano::unchecked_info info (block_a, known_account_a, 0, nano::signature_verification::unknown, retry_limit == std::numeric_limits<unsigned>::max ());
|
||||
node->block_processor.add (info);
|
||||
}
|
||||
// Force drop lazy bootstrap connection for long bulk_pull
|
||||
if (pull_blocks > node->network_params.bootstrap.lazy_max_pull_blocks)
|
||||
if (pull_blocks > max_blocks)
|
||||
{
|
||||
stop_pull = true;
|
||||
}
|
||||
return stop_pull;
|
||||
}
|
||||
|
||||
void nano::bootstrap_attempt::lazy_block_state (std::shared_ptr<nano::block> block_a, bool confirmed_head)
|
||||
void nano::bootstrap_attempt::lazy_block_state (std::shared_ptr<nano::block> block_a, unsigned retry_limit)
|
||||
{
|
||||
std::shared_ptr<nano::state_block> block_l (std::static_pointer_cast<nano::state_block> (block_a));
|
||||
if (block_l != nullptr)
|
||||
|
@ -1014,14 +1043,14 @@ void nano::bootstrap_attempt::lazy_block_state (std::shared_ptr<nano::block> blo
|
|||
// If state block previous is 0 then source block required
|
||||
if (previous.is_zero ())
|
||||
{
|
||||
lazy_add (link, confirmed_head);
|
||||
lazy_add (link, retry_limit);
|
||||
}
|
||||
// In other cases previous block balance required to find out subtype of state block
|
||||
else if (node->store.block_exists (transaction, previous))
|
||||
{
|
||||
if (node->ledger.balance (transaction, previous) <= balance)
|
||||
{
|
||||
lazy_add (link, confirmed_head);
|
||||
lazy_add (link, retry_limit);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1036,7 +1065,7 @@ void nano::bootstrap_attempt::lazy_block_state (std::shared_ptr<nano::block> blo
|
|||
{
|
||||
if (previous_balance->second <= balance)
|
||||
{
|
||||
lazy_add (link, confirmed_head);
|
||||
lazy_add (link, retry_limit);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1048,7 +1077,7 @@ void nano::bootstrap_attempt::lazy_block_state (std::shared_ptr<nano::block> blo
|
|||
// Insert in backlog state blocks if previous wasn't already processed
|
||||
else
|
||||
{
|
||||
lazy_state_backlog.emplace (previous, nano::lazy_state_backlog_item{ link, balance, confirmed_head });
|
||||
lazy_state_backlog.emplace (previous, nano::lazy_state_backlog_item{ link, balance, retry_limit });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1066,7 +1095,7 @@ void nano::bootstrap_attempt::lazy_block_state_backlog_check (std::shared_ptr<na
|
|||
{
|
||||
if (block_a->balance ().number () <= next_block.balance) // balance
|
||||
{
|
||||
lazy_add (next_block.link, next_block.confirmed); // link
|
||||
lazy_add (next_block.link, next_block.retry_limit); // link
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1076,7 +1105,7 @@ void nano::bootstrap_attempt::lazy_block_state_backlog_check (std::shared_ptr<na
|
|||
// Assumption for other legacy block types
|
||||
else if (lazy_undefined_links.find (next_block.link) == lazy_undefined_links.end ())
|
||||
{
|
||||
lazy_add (next_block.link, false); // Head is not confirmed. It can be account or hash or non-existing
|
||||
lazy_add (next_block.link, node->network_params.bootstrap.lazy_retry_limit); // Head is not confirmed. It can be account or hash or non-existing
|
||||
lazy_undefined_links.insert (next_block.link);
|
||||
}
|
||||
lazy_state_backlog.erase (find_state);
|
||||
|
@ -1094,7 +1123,7 @@ void nano::bootstrap_attempt::lazy_backlog_cleanup ()
|
|||
auto next_block (it->second);
|
||||
if (node->ledger.balance (transaction, it->first) <= next_block.balance) // balance
|
||||
{
|
||||
lazy_add (next_block.link, next_block.confirmed); // link
|
||||
lazy_add (next_block.link, next_block.retry_limit); // link
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1104,7 +1133,7 @@ void nano::bootstrap_attempt::lazy_backlog_cleanup ()
|
|||
}
|
||||
else
|
||||
{
|
||||
lazy_add (it->first, it->second.confirmed);
|
||||
lazy_add (it->first, it->second.retry_limit);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
@ -1128,20 +1157,14 @@ void nano::bootstrap_attempt::lazy_destinations_increment (nano::account const &
|
|||
|
||||
void nano::bootstrap_attempt::lazy_destinations_flush ()
|
||||
{
|
||||
lazy_destinations_flushed = true;
|
||||
size_t count (0);
|
||||
nano::lock_guard<std::mutex> lazy_lock (lazy_mutex);
|
||||
if (last_lazy_destinations_flush + nano::bootstrap_limits::lazy_destinations_flush_delay_sec < std::chrono::steady_clock::now ())
|
||||
for (auto it (lazy_destinations.get<count_tag> ().begin ()), end (lazy_destinations.get<count_tag> ().end ()); it != end && count < nano::bootstrap_limits::lazy_destinations_request_limit && !stopped;)
|
||||
{
|
||||
for (auto it (lazy_destinations.get<count_tag> ().begin ()), end (lazy_destinations.get<count_tag> ().end ()); it != end && count < nano::bootstrap_limits::bootstrap_lazy_destinations_request_limit && !stopped;)
|
||||
{
|
||||
lazy_add (it->account, false);
|
||||
it = lazy_destinations.get<count_tag> ().erase (it);
|
||||
++count;
|
||||
}
|
||||
if (count > nano::bootstrap_limits::bootstrap_lazy_destinations_request_limit / 4)
|
||||
{
|
||||
last_lazy_destinations_flush = std::chrono::steady_clock::now ();
|
||||
}
|
||||
lazy_add (it->account, node->network_params.bootstrap.lazy_destinations_retry_limit);
|
||||
it = lazy_destinations.get<count_tag> ().erase (it);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1232,6 +1255,7 @@ void nano::bootstrap_attempt::wallet_run ()
|
|||
if (!lazy_finished ())
|
||||
{
|
||||
lock.unlock ();
|
||||
total_blocks = 0;
|
||||
lazy_run ();
|
||||
lock.lock ();
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ class lazy_state_backlog_item final
|
|||
public:
|
||||
nano::link link{ 0 };
|
||||
nano::uint128_t balance{ 0 };
|
||||
bool confirmed{ false };
|
||||
unsigned retry_limit{ 0 };
|
||||
};
|
||||
class lazy_destinations_item final
|
||||
{
|
||||
|
@ -81,17 +81,17 @@ public:
|
|||
void add_bulk_push_target (nano::block_hash const &, nano::block_hash const &);
|
||||
void attempt_restart_check (nano::unique_lock<std::mutex> &);
|
||||
void confirm_frontiers (nano::unique_lock<std::mutex> &);
|
||||
bool process_block (std::shared_ptr<nano::block>, nano::account const &, uint64_t, bool, bool);
|
||||
bool process_block (std::shared_ptr<nano::block>, nano::account const &, uint64_t, nano::bulk_pull::count_t, bool, unsigned);
|
||||
/** Lazy bootstrap */
|
||||
void lazy_run ();
|
||||
void lazy_start (nano::hash_or_account const &, bool confirmed = true);
|
||||
void lazy_add (nano::hash_or_account const &, bool = true);
|
||||
void lazy_add (nano::hash_or_account const &, unsigned = std::numeric_limits<unsigned>::max ());
|
||||
void lazy_requeue (nano::block_hash const &, nano::block_hash const &, bool);
|
||||
bool lazy_finished ();
|
||||
void lazy_pull_flush ();
|
||||
void lazy_clear ();
|
||||
bool process_block_lazy (std::shared_ptr<nano::block>, nano::account const &, uint64_t, bool);
|
||||
void lazy_block_state (std::shared_ptr<nano::block>, bool);
|
||||
bool process_block_lazy (std::shared_ptr<nano::block>, nano::account const &, uint64_t, nano::bulk_pull::count_t, unsigned);
|
||||
void lazy_block_state (std::shared_ptr<nano::block>, unsigned);
|
||||
void lazy_block_state_backlog_check (std::shared_ptr<nano::block>, nano::block_hash const &);
|
||||
void lazy_backlog_cleanup ();
|
||||
void lazy_destinations_increment (nano::account const &);
|
||||
|
@ -136,7 +136,7 @@ public:
|
|||
std::unordered_set<nano::block_hash> lazy_undefined_links;
|
||||
std::unordered_map<nano::block_hash, nano::uint128_t> lazy_balances;
|
||||
std::unordered_set<nano::block_hash> lazy_keys;
|
||||
std::deque<std::pair<nano::hash_or_account, bool>> lazy_pulls;
|
||||
std::deque<std::pair<nano::hash_or_account, unsigned>> lazy_pulls;
|
||||
std::chrono::steady_clock::time_point last_lazy_flush{ std::chrono::steady_clock::now () };
|
||||
class account_tag
|
||||
{
|
||||
|
@ -150,7 +150,7 @@ public:
|
|||
boost::multi_index::ordered_non_unique<boost::multi_index::tag<count_tag>, boost::multi_index::member<lazy_destinations_item, uint64_t, &lazy_destinations_item::count>, std::greater<uint64_t>>,
|
||||
boost::multi_index::hashed_unique<boost::multi_index::tag<account_tag>, boost::multi_index::member<lazy_destinations_item, nano::account, &lazy_destinations_item::account>>>>
|
||||
lazy_destinations;
|
||||
std::chrono::steady_clock::time_point last_lazy_destinations_flush{ std::chrono::steady_clock::time_point{} };
|
||||
std::atomic<bool> lazy_destinations_flushed{ false };
|
||||
std::mutex lazy_mutex;
|
||||
// Wallet lazy bootstrap
|
||||
std::deque<nano::account> wallet_accounts;
|
||||
|
@ -264,14 +264,13 @@ class bootstrap_limits final
|
|||
{
|
||||
public:
|
||||
static constexpr double bootstrap_connection_scale_target_blocks = 50000.0;
|
||||
static constexpr double bootstrap_connection_scale_target_blocks_lazy = bootstrap_connection_scale_target_blocks / 5;
|
||||
static constexpr double bootstrap_connection_warmup_time_sec = 5.0;
|
||||
static constexpr double bootstrap_minimum_blocks_per_sec = 10.0;
|
||||
static constexpr double bootstrap_minimum_elapsed_seconds_blockrate = 0.02;
|
||||
static constexpr double bootstrap_minimum_frontier_blocks_per_sec = 1000.0;
|
||||
static constexpr unsigned bootstrap_frontier_retry_limit = 16;
|
||||
static constexpr unsigned bootstrap_lazy_retry_limit = bootstrap_frontier_retry_limit * 10;
|
||||
static constexpr double bootstrap_minimum_termination_time_sec = 30.0;
|
||||
static constexpr unsigned bootstrap_max_new_connections = 10;
|
||||
static constexpr unsigned bootstrap_max_new_connections = 32;
|
||||
static constexpr size_t bootstrap_max_confirm_frontiers = 70;
|
||||
static constexpr double required_frontier_confirmation_ratio = 0.8;
|
||||
static constexpr unsigned frontier_confirmation_blocks_limit = 128 * 1024;
|
||||
|
@ -279,7 +278,8 @@ public:
|
|||
static constexpr unsigned requeued_pulls_limit_test = 2;
|
||||
static constexpr unsigned bulk_push_cost_limit = 200;
|
||||
static constexpr std::chrono::seconds lazy_flush_delay_sec = std::chrono::seconds (5);
|
||||
static constexpr unsigned bootstrap_lazy_destinations_request_limit = 200;
|
||||
static constexpr std::chrono::seconds lazy_destinations_flush_delay_sec = std::chrono::minutes (2);
|
||||
static constexpr unsigned lazy_destinations_request_limit = 256 * 1024;
|
||||
static constexpr uint64_t lazy_batch_pull_count_resize_blocks_limit = 4 * 1024 * 1024;
|
||||
static constexpr double lazy_batch_pull_count_resize_ratio = 2.0;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
#include <nano/node/node.hpp>
|
||||
#include <nano/node/transport/tcp.hpp>
|
||||
|
||||
nano::pull_info::pull_info (nano::hash_or_account const & account_or_head_a, nano::block_hash const & head_a, nano::block_hash const & end_a, count_t count_a, bool confirmed_head_a) :
|
||||
nano::pull_info::pull_info (nano::hash_or_account const & account_or_head_a, nano::block_hash const & head_a, nano::block_hash const & end_a, count_t count_a, unsigned retry_limit_a) :
|
||||
account_or_head (account_or_head_a),
|
||||
head (head_a),
|
||||
head_original (head_a),
|
||||
end (end_a),
|
||||
count (count_a),
|
||||
confirmed_head (confirmed_head_a)
|
||||
retry_limit (retry_limit_a)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ nano::bulk_pull_client::~bulk_pull_client ()
|
|||
|
||||
void nano::bulk_pull_client::request ()
|
||||
{
|
||||
assert (!pull.head.is_zero () || !pull.confirmed_head);
|
||||
assert (!pull.head.is_zero () || pull.retry_limit != std::numeric_limits<unsigned>::max ());
|
||||
expected = pull.head;
|
||||
nano::bulk_pull req;
|
||||
if (pull.head == pull.head_original)
|
||||
|
@ -182,7 +182,7 @@ void nano::bulk_pull_client::received_type ()
|
|||
case nano::block_type::not_a_block:
|
||||
{
|
||||
// Avoid re-using slow peers, or peers that sent the wrong blocks.
|
||||
if (!connection->pending_stop && expected == pull.end)
|
||||
if (!connection->pending_stop && (expected == pull.end || (pull.count != 0 && pull.count == pull_blocks)))
|
||||
{
|
||||
connection->attempt->pool_connection (connection);
|
||||
}
|
||||
|
@ -216,7 +216,7 @@ void nano::bulk_pull_client::received_block (boost::system::error_code const & e
|
|||
}
|
||||
// Is block expected?
|
||||
bool block_expected (false);
|
||||
bool unconfirmed_account_head (pull_blocks == 0 && !pull.confirmed_head && expected == pull.account_or_head && block->account () == pull.account_or_head);
|
||||
bool unconfirmed_account_head (pull_blocks == 0 && pull.retry_limit != std::numeric_limits<unsigned>::max () && expected == pull.account_or_head && block->account () == pull.account_or_head);
|
||||
if (hash == expected || unconfirmed_account_head)
|
||||
{
|
||||
expected = block->previous ();
|
||||
|
@ -235,7 +235,7 @@ void nano::bulk_pull_client::received_block (boost::system::error_code const & e
|
|||
connection->start_time = std::chrono::steady_clock::now ();
|
||||
}
|
||||
connection->attempt->total_blocks++;
|
||||
bool stop_pull (connection->attempt->process_block (block, known_account, pull_blocks, block_expected, pull.confirmed_head));
|
||||
bool stop_pull (connection->attempt->process_block (block, known_account, pull_blocks, pull.count, block_expected, pull.retry_limit));
|
||||
pull_blocks++;
|
||||
if (!stop_pull && !connection->hard_stop.load ())
|
||||
{
|
||||
|
|
|
@ -12,7 +12,7 @@ class pull_info
|
|||
public:
|
||||
using count_t = nano::bulk_pull::count_t;
|
||||
pull_info () = default;
|
||||
pull_info (nano::hash_or_account const &, nano::block_hash const &, nano::block_hash const &, count_t = 0, bool = false);
|
||||
pull_info (nano::hash_or_account const &, nano::block_hash const &, nano::block_hash const &, count_t = 0, unsigned = 16);
|
||||
nano::hash_or_account account_or_head{ 0 };
|
||||
nano::block_hash head{ 0 };
|
||||
nano::block_hash head_original{ 0 };
|
||||
|
@ -20,7 +20,7 @@ public:
|
|||
count_t count{ 0 };
|
||||
unsigned attempts{ 0 };
|
||||
uint64_t processed{ 0 };
|
||||
bool confirmed_head{ false };
|
||||
unsigned retry_limit{ 0 };
|
||||
};
|
||||
class bootstrap_client;
|
||||
class bulk_pull_client final : public std::enable_shared_from_this<nano::bulk_pull_client>
|
||||
|
|
|
@ -144,7 +144,7 @@ void nano::frontier_req_client::received_frontier (boost::system::error_code con
|
|||
}
|
||||
else
|
||||
{
|
||||
connection->attempt->add_pull (nano::pull_info (account, latest, frontier));
|
||||
connection->attempt->add_pull (nano::pull_info (account, latest, frontier, 0, connection->node->network_params.bootstrap.frontier_retry_limit));
|
||||
// Either we're behind or there's a fork we differ on
|
||||
// Either way, bulk pushing will probably not be effective
|
||||
bulk_push_cost += 5;
|
||||
|
@ -155,12 +155,12 @@ void nano::frontier_req_client::received_frontier (boost::system::error_code con
|
|||
else
|
||||
{
|
||||
assert (account < current);
|
||||
connection->attempt->add_pull (nano::pull_info (account, latest, nano::block_hash (0)));
|
||||
connection->attempt->add_pull (nano::pull_info (account, latest, nano::block_hash (0), 0, connection->node->network_params.bootstrap.frontier_retry_limit));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
connection->attempt->add_pull (nano::pull_info (account, latest, nano::block_hash (0)));
|
||||
connection->attempt->add_pull (nano::pull_info (account, latest, nano::block_hash (0), 0, connection->node->network_params.bootstrap.frontier_retry_limit));
|
||||
}
|
||||
receive_frontier ();
|
||||
}
|
||||
|
|
|
@ -901,8 +901,10 @@ void nano::node::bootstrap_wallet ()
|
|||
void nano::node::unchecked_cleanup ()
|
||||
{
|
||||
std::deque<nano::unchecked_key> cleaning_list;
|
||||
auto attempt (bootstrap_initiator.current_attempt ());
|
||||
bool long_attempt (attempt != nullptr && std::chrono::duration_cast<std::chrono::seconds> (std::chrono::steady_clock::now () - attempt->attempt_start).count () > config.unchecked_cutoff_time.count ());
|
||||
// Collect old unchecked keys
|
||||
if (!flags.disable_unchecked_cleanup && ledger.block_count_cache >= ledger.bootstrap_weight_max_blocks)
|
||||
if (!flags.disable_unchecked_cleanup && ledger.block_count_cache >= ledger.bootstrap_weight_max_blocks && !long_attempt)
|
||||
{
|
||||
auto now (nano::seconds_since_epoch ());
|
||||
auto transaction (store.tx_begin_read ());
|
||||
|
|
|
@ -142,6 +142,10 @@ nano::portmapping_constants::portmapping_constants (nano::network_constants & ne
|
|||
nano::bootstrap_constants::bootstrap_constants (nano::network_constants & network_constants)
|
||||
{
|
||||
lazy_max_pull_blocks = network_constants.is_test_network () ? 2 : 512;
|
||||
lazy_min_pull_blocks = network_constants.is_test_network () ? 1 : 32;
|
||||
frontier_retry_limit = network_constants.is_test_network () ? 2 : 16;
|
||||
lazy_retry_limit = network_constants.is_test_network () ? 2 : frontier_retry_limit * 10;
|
||||
lazy_destinations_retry_limit = network_constants.is_test_network () ? 1 : frontier_retry_limit / 4;
|
||||
}
|
||||
|
||||
/* Convenience constants for core_test which is always on the test network */
|
||||
|
|
|
@ -423,7 +423,11 @@ class bootstrap_constants
|
|||
{
|
||||
public:
|
||||
bootstrap_constants (nano::network_constants & network_constants);
|
||||
uint64_t lazy_max_pull_blocks;
|
||||
uint32_t lazy_max_pull_blocks;
|
||||
uint32_t lazy_min_pull_blocks;
|
||||
unsigned frontier_retry_limit;
|
||||
unsigned lazy_retry_limit;
|
||||
unsigned lazy_destinations_retry_limit;
|
||||
};
|
||||
|
||||
/** Constants whose value depends on the active network */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue