Avoid long read transactions for bootstrap (#2513)
* Avoid long transactions holding for bootstrap clients: frontier_req_client, bulk_push_client. Also avoid direct transactions usage if possible (use wrapper functions) * Use nano::transaction::refresh () function to not open read transactions for too long
This commit is contained in:
parent
188dc985c7
commit
f8888f6513
7 changed files with 39 additions and 23 deletions
|
@ -884,6 +884,7 @@ void nano::bootstrap_attempt::lazy_pull_flush ()
|
|||
batch_count = std::max (node->network_params.bootstrap.lazy_min_pull_blocks, batch_count_min);
|
||||
}
|
||||
}
|
||||
uint64_t read_count (0);
|
||||
size_t count (0);
|
||||
auto transaction (node->store.tx_begin_read ());
|
||||
while (!lazy_pulls.empty () && count < max_pulls)
|
||||
|
@ -896,6 +897,12 @@ void nano::bootstrap_attempt::lazy_pull_flush ()
|
|||
++count;
|
||||
}
|
||||
lazy_pulls.pop_front ();
|
||||
// We don't want to open read transactions for too long
|
||||
++read_count;
|
||||
if (read_count % batch_read_size == 0)
|
||||
{
|
||||
transaction.refresh ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -907,6 +914,7 @@ bool nano::bootstrap_attempt::lazy_finished ()
|
|||
return true;
|
||||
}
|
||||
bool result (true);
|
||||
uint64_t read_count (0);
|
||||
auto transaction (node->store.tx_begin_read ());
|
||||
nano::lock_guard<std::mutex> lazy_lock (lazy_mutex);
|
||||
for (auto it (lazy_keys.begin ()), end (lazy_keys.end ()); it != end && !stopped;)
|
||||
|
@ -921,6 +929,12 @@ bool nano::bootstrap_attempt::lazy_finished ()
|
|||
break;
|
||||
// No need to increment `it` as we break above.
|
||||
}
|
||||
// We don't want to open read transactions for too long
|
||||
++read_count;
|
||||
if (read_count % batch_read_size == 0)
|
||||
{
|
||||
transaction.refresh ();
|
||||
}
|
||||
}
|
||||
// Finish lazy bootstrap without lazy pulls (in combination with still_pulling ())
|
||||
if (!result && lazy_pulls.empty () && lazy_state_backlog.empty ())
|
||||
|
@ -1201,6 +1215,7 @@ void nano::bootstrap_attempt::lazy_block_state_backlog_check (std::shared_ptr<na
|
|||
|
||||
void nano::bootstrap_attempt::lazy_backlog_cleanup ()
|
||||
{
|
||||
uint64_t read_count (0);
|
||||
auto transaction (node->store.tx_begin_read ());
|
||||
nano::lock_guard<std::mutex> lazy_lock (lazy_mutex);
|
||||
for (auto it (lazy_state_backlog.begin ()), end (lazy_state_backlog.end ()); it != end && !stopped;)
|
||||
|
@ -1223,6 +1238,12 @@ void nano::bootstrap_attempt::lazy_backlog_cleanup ()
|
|||
lazy_add (it->first, it->second.retry_limit);
|
||||
++it;
|
||||
}
|
||||
// We don't want to open read transactions for too long
|
||||
++read_count;
|
||||
if (read_count % batch_read_size == 0)
|
||||
{
|
||||
transaction.refresh ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -164,6 +164,8 @@ public:
|
|||
std::mutex lazy_mutex;
|
||||
// Wallet lazy bootstrap
|
||||
std::deque<nano::account> wallet_accounts;
|
||||
/** The maximum number of records to be read in while iterating over long lazy containers */
|
||||
static uint64_t constexpr batch_read_size = 256;
|
||||
};
|
||||
class bootstrap_client final : public std::enable_shared_from_this<bootstrap_client>
|
||||
{
|
||||
|
|
|
@ -366,8 +366,7 @@ void nano::bulk_pull_account_client::receive_pending ()
|
|||
{
|
||||
if (!pending.is_zero ())
|
||||
{
|
||||
auto transaction (this_l->connection->node->store.tx_begin_read ());
|
||||
if (!this_l->connection->node->store.block_exists (transaction, pending))
|
||||
if (!this_l->connection->node->ledger.block_exists (pending))
|
||||
{
|
||||
this_l->connection->attempt->lazy_start (pending);
|
||||
}
|
||||
|
@ -552,8 +551,7 @@ std::shared_ptr<nano::block> nano::bulk_pull_server::get_next ()
|
|||
|
||||
if (send_current)
|
||||
{
|
||||
auto transaction (connection->node->store.tx_begin_read ());
|
||||
result = connection->node->store.block_get (transaction, current);
|
||||
result = connection->node->block (current);
|
||||
if (result != nullptr && set_current_to_end == false)
|
||||
{
|
||||
auto previous (result->previous ());
|
||||
|
|
|
@ -20,10 +20,9 @@ void nano::bulk_push_client::start ()
|
|||
auto this_l (shared_from_this ());
|
||||
connection->channel->send (
|
||||
message, [this_l](boost::system::error_code const & ec, size_t size_a) {
|
||||
auto transaction (this_l->connection->node->store.tx_begin_read ());
|
||||
if (!ec)
|
||||
{
|
||||
this_l->push (transaction);
|
||||
this_l->push ();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -36,7 +35,7 @@ void nano::bulk_push_client::start ()
|
|||
false); // is bootstrap traffic is_droppable false
|
||||
}
|
||||
|
||||
void nano::bulk_push_client::push (nano::transaction const & transaction_a)
|
||||
void nano::bulk_push_client::push ()
|
||||
{
|
||||
std::shared_ptr<nano::block> block;
|
||||
bool finished (false);
|
||||
|
@ -57,7 +56,7 @@ void nano::bulk_push_client::push (nano::transaction const & transaction_a)
|
|||
}
|
||||
if (!finished)
|
||||
{
|
||||
block = connection->node->store.block_get (transaction_a, current_target.first);
|
||||
block = connection->node->block (current_target.first);
|
||||
if (block == nullptr)
|
||||
{
|
||||
current_target.first = nano::block_hash (0);
|
||||
|
@ -108,8 +107,7 @@ void nano::bulk_push_client::push_block (nano::block const & block_a)
|
|||
connection->channel->send_buffer (nano::shared_const_buffer (std::move (buffer)), nano::stat::detail::all, [this_l](boost::system::error_code const & ec, size_t size_a) {
|
||||
if (!ec)
|
||||
{
|
||||
auto transaction (this_l->connection->node->store.tx_begin_read ());
|
||||
this_l->push (transaction);
|
||||
this_l->push ();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
namespace nano
|
||||
{
|
||||
class transaction;
|
||||
class bootstrap_client;
|
||||
class bulk_push_client final : public std::enable_shared_from_this<nano::bulk_push_client>
|
||||
{
|
||||
|
@ -14,7 +13,7 @@ public:
|
|||
explicit bulk_push_client (std::shared_ptr<nano::bootstrap_client> const &);
|
||||
~bulk_push_client ();
|
||||
void start ();
|
||||
void push (nano::transaction const &);
|
||||
void push ();
|
||||
void push_block (nano::block const &);
|
||||
void send_finished ();
|
||||
std::shared_ptr<nano::bootstrap_client> connection;
|
||||
|
|
|
@ -42,8 +42,7 @@ current (0),
|
|||
count (0),
|
||||
bulk_push_cost (0)
|
||||
{
|
||||
auto transaction (connection->node->store.tx_begin_read ());
|
||||
next (transaction);
|
||||
next ();
|
||||
}
|
||||
|
||||
nano::frontier_req_client::~frontier_req_client ()
|
||||
|
@ -123,14 +122,13 @@ void nano::frontier_req_client::received_frontier (boost::system::error_code con
|
|||
{
|
||||
connection->node->logger.always_log (boost::str (boost::format ("Received %1% frontiers from %2%") % std::to_string (count) % connection->channel->to_string ()));
|
||||
}
|
||||
auto transaction (connection->node->store.tx_begin_read ());
|
||||
if (!account.is_zero ())
|
||||
{
|
||||
while (!current.is_zero () && current < account)
|
||||
{
|
||||
// We know about an account they don't.
|
||||
unsynced (frontier, 0);
|
||||
next (transaction);
|
||||
next ();
|
||||
}
|
||||
if (!current.is_zero ())
|
||||
{
|
||||
|
@ -142,7 +140,7 @@ void nano::frontier_req_client::received_frontier (boost::system::error_code con
|
|||
}
|
||||
else
|
||||
{
|
||||
if (connection->node->store.block_exists (transaction, latest))
|
||||
if (connection->node->ledger.block_exists (latest))
|
||||
{
|
||||
// We know about a block they don't.
|
||||
unsynced (frontier, latest);
|
||||
|
@ -155,7 +153,7 @@ void nano::frontier_req_client::received_frontier (boost::system::error_code con
|
|||
bulk_push_cost += 5;
|
||||
}
|
||||
}
|
||||
next (transaction);
|
||||
next ();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -175,7 +173,7 @@ void nano::frontier_req_client::received_frontier (boost::system::error_code con
|
|||
{
|
||||
// We know about an account they don't.
|
||||
unsynced (frontier, 0);
|
||||
next (transaction);
|
||||
next ();
|
||||
}
|
||||
if (connection->node->config.logging.bulk_pull_logging ())
|
||||
{
|
||||
|
@ -202,13 +200,14 @@ void nano::frontier_req_client::received_frontier (boost::system::error_code con
|
|||
}
|
||||
}
|
||||
|
||||
void nano::frontier_req_client::next (nano::transaction const & transaction_a)
|
||||
void nano::frontier_req_client::next ()
|
||||
{
|
||||
// Filling accounts deque to prevent often read transactions
|
||||
if (accounts.empty ())
|
||||
{
|
||||
size_t max_size (128);
|
||||
for (auto i (connection->node->store.latest_begin (transaction_a, current.number () + 1)), n (connection->node->store.latest_end ()); i != n && accounts.size () != max_size; ++i)
|
||||
auto transaction (connection->node->store.tx_begin_read ());
|
||||
for (auto i (connection->node->store.latest_begin (transaction, current.number () + 1)), n (connection->node->store.latest_end ()); i != n && accounts.size () != max_size; ++i)
|
||||
{
|
||||
nano::account_info const & info (i->second);
|
||||
nano::account const & account (i->first);
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace nano
|
||||
{
|
||||
class transaction;
|
||||
class bootstrap_client;
|
||||
class frontier_req_client final : public std::enable_shared_from_this<nano::frontier_req_client>
|
||||
{
|
||||
|
@ -18,7 +17,7 @@ public:
|
|||
void receive_frontier ();
|
||||
void received_frontier (boost::system::error_code const &, size_t);
|
||||
void unsynced (nano::block_hash const &, nano::block_hash const &);
|
||||
void next (nano::transaction const &);
|
||||
void next ();
|
||||
std::shared_ptr<nano::bootstrap_client> connection;
|
||||
nano::account current;
|
||||
nano::block_hash frontier;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue