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:
Sergey Kroshnin 2019-10-31 16:53:58 +03:00 committed by GitHub
commit 62db44d4d6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 113 additions and 79 deletions

View file

@ -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 ();
}

View file

@ -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;
};
}

View file

@ -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 ())
{

View file

@ -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>

View file

@ -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 ();
}

View file

@ -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 ());

View file

@ -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 */

View file

@ -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 */