Separate inactive votes cache from gap cache (#2542)

* Separate inactive votes cache from gap cache
* Move functional changes to new PR
This commit is contained in:
Sergey Kroshnin 2020-02-13 13:34:53 +03:00 committed by GitHub
commit 298a3c8915
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 96 additions and 24 deletions

View file

@ -995,11 +995,12 @@ void nano::active_transactions::add_inactive_votes_cache (nano::block_hash const
// Check principal representative status
if (node.ledger.weight (representative_a) > node.minimum_principal_weight ())
{
auto existing (inactive_votes_cache.get<nano::gap_cache::tag_hash> ().find (hash_a));
if (existing != inactive_votes_cache.get<nano::gap_cache::tag_hash> ().end () && !existing->confirmed)
auto & inactive_by_hash (inactive_votes_cache.get<tag_hash> ());
auto existing (inactive_by_hash.find (hash_a));
if (existing != inactive_by_hash.end () && !existing->confirmed)
{
auto is_new (false);
inactive_votes_cache.get<nano::gap_cache::tag_hash> ().modify (existing, [representative_a, &is_new](nano::gap_information & info) {
inactive_by_hash.modify (existing, [representative_a, &is_new](nano::inactive_cache_information & info) {
auto it = std::find (info.voters.begin (), info.voters.end (), representative_a);
is_new = (it == info.voters.end ());
if (is_new)
@ -1011,9 +1012,9 @@ void nano::active_transactions::add_inactive_votes_cache (nano::block_hash const
if (is_new)
{
if (node.gap_cache.bootstrap_check (existing->voters, hash_a))
if (inactive_votes_bootstrap_check (existing->voters, hash_a))
{
inactive_votes_cache.get<nano::gap_cache::tag_hash> ().modify (existing, [](nano::gap_information & info) {
inactive_by_hash.modify (existing, [](nano::inactive_cache_information & info) {
info.confirmed = true;
});
}
@ -1021,37 +1022,86 @@ void nano::active_transactions::add_inactive_votes_cache (nano::block_hash const
}
else
{
inactive_votes_cache.get<nano::gap_cache::tag_arrival> ().emplace (nano::gap_information{ std::chrono::steady_clock::now (), hash_a, std::vector<nano::account> (1, representative_a) });
std::vector<nano::account> representative_vector (1, representative_a);
auto & inactive_by_arrival (inactive_votes_cache.get<tag_arrival> ());
inactive_by_arrival.emplace (nano::inactive_cache_information{ std::chrono::steady_clock::now (), hash_a, representative_vector });
if (inactive_votes_cache.size () > inactive_votes_cache_max)
{
inactive_votes_cache.get<nano::gap_cache::tag_arrival> ().erase (inactive_votes_cache.get<nano::gap_cache::tag_arrival> ().begin ());
inactive_by_arrival.erase (inactive_by_arrival.begin ());
}
}
}
}
nano::gap_information nano::active_transactions::find_inactive_votes_cache (nano::block_hash const & hash_a)
nano::inactive_cache_information nano::active_transactions::find_inactive_votes_cache (nano::block_hash const & hash_a)
{
auto existing (inactive_votes_cache.get<nano::gap_cache::tag_hash> ().find (hash_a));
if (existing != inactive_votes_cache.get<nano::gap_cache::tag_hash> ().end ())
auto & inactive_by_hash (inactive_votes_cache.get<tag_hash> ());
auto existing (inactive_by_hash.find (hash_a));
if (existing != inactive_by_hash.end ())
{
return *existing;
}
else
{
return nano::gap_information{ std::chrono::steady_clock::time_point{}, 0, std::vector<nano::account>{} };
return nano::inactive_cache_information{ std::chrono::steady_clock::time_point{}, 0, std::vector<nano::account>{} };
}
}
void nano::active_transactions::erase_inactive_votes_cache (nano::block_hash const & hash_a)
{
auto existing (inactive_votes_cache.get<nano::gap_cache::tag_hash> ().find (hash_a));
if (existing != inactive_votes_cache.get<nano::gap_cache::tag_hash> ().end ())
auto & inactive_by_hash (inactive_votes_cache.get<tag_hash> ());
auto existing (inactive_by_hash.find (hash_a));
if (existing != inactive_by_hash.end ())
{
inactive_votes_cache.get<nano::gap_cache::tag_hash> ().erase (existing);
inactive_by_hash.erase (existing);
}
}
bool nano::active_transactions::inactive_votes_bootstrap_check (std::vector<nano::account> const & voters_a, nano::block_hash const & hash_a)
{
uint128_t tally;
for (auto const & voter : voters_a)
{
tally += node.ledger.weight (voter);
}
bool start_bootstrap (false);
if (!node.flags.disable_lazy_bootstrap)
{
if (tally >= node.config.online_weight_minimum.number ())
{
start_bootstrap = true;
}
}
else if (!node.flags.disable_legacy_bootstrap && tally > node.gap_cache.bootstrap_threshold ())
{
start_bootstrap = true;
}
if (start_bootstrap)
{
auto node_l (node.shared ());
auto now (std::chrono::steady_clock::now ());
node.alarm.add (node_l->network_params.network.is_test_network () ? now + std::chrono::milliseconds (5) : now + std::chrono::seconds (5), [node_l, hash_a]() {
auto transaction (node_l->store.tx_begin_read ());
if (!node_l->store.block_exists (transaction, hash_a))
{
if (!node_l->bootstrap_initiator.in_progress ())
{
node_l->logger.try_log (boost::str (boost::format ("Missing block %1% which has enough votes to warrant lazy bootstrapping it") % hash_a.to_string ()));
}
if (!node_l->flags.disable_lazy_bootstrap)
{
node_l->bootstrap_initiator.bootstrap_lazy (hash_a);
}
else if (!node_l->flags.disable_legacy_bootstrap)
{
node_l->bootstrap_initiator.bootstrap ();
}
}
});
}
return start_bootstrap;
}
size_t nano::active_transactions::dropped_elections_cache_size ()
{
nano::lock_guard<std::mutex> guard (mutex);

View file

@ -60,6 +60,15 @@ public:
nano::qualified_root root;
};
class inactive_cache_information final
{
public:
std::chrono::steady_clock::time_point arrival;
nano::block_hash hash;
std::vector<nano::account> voters;
bool confirmed{ false };
};
// Core class for determining consensus
// Holds all active blocks i.e. recently added blocks that need confirmation
class active_transactions final
@ -70,6 +79,8 @@ class active_transactions final
class tag_root {};
class tag_sequence {};
class tag_uncemented {};
class tag_arrival {};
class tag_hash {};
// clang-format on
public:
@ -114,7 +125,7 @@ public:
std::deque<nano::election_status> confirmed;
void add_confirmed (nano::election_status const &, nano::qualified_root const &);
void add_inactive_votes_cache (nano::block_hash const &, nano::account const &);
nano::gap_information find_inactive_votes_cache (nano::block_hash const &);
nano::inactive_cache_information find_inactive_votes_cache (nano::block_hash const &);
void erase_inactive_votes_cache (nano::block_hash const &);
nano::confirmation_height_processor & confirmation_height_processor;
nano::node & node;
@ -184,8 +195,17 @@ private:
void prioritize_account_for_confirmation (prioritize_num_uncemented &, size_t &, nano::account const &, nano::account_info const &, uint64_t);
static size_t constexpr max_priority_cementable_frontiers{ 100000 };
static size_t constexpr confirmed_frontiers_max_pending_cut_off{ 1000 };
nano::gap_cache::ordered_gaps inactive_votes_cache;
// clang-format off
using ordered_cache = boost::multi_index_container<nano::inactive_cache_information,
mi::indexed_by<
mi::ordered_non_unique<mi::tag<tag_arrival>,
mi::member<nano::inactive_cache_information, std::chrono::steady_clock::time_point, &nano::inactive_cache_information::arrival>>,
mi::hashed_unique<mi::tag<tag_hash>,
mi::member<nano::inactive_cache_information, nano::block_hash, &nano::inactive_cache_information::hash>>>>;
ordered_cache inactive_votes_cache;
// clang-format on
static size_t constexpr inactive_votes_cache_max{ 16 * 1024 };
bool inactive_votes_bootstrap_check (std::vector<nano::account> const &, nano::block_hash const &);
// clang-format off
boost::multi_index_container<nano::election_timepoint,
mi::indexed_by<

View file

@ -754,8 +754,9 @@ bool nano::bootstrap_attempt::confirm_frontiers (nano::unique_lock<std::mutex> &
}
else
{
nano::lock_guard<std::mutex> active_lock (node->active.mutex);
nano::unique_lock<std::mutex> active_lock (node->active.mutex);
auto existing (node->active.find_inactive_votes_cache (*ii));
active_lock.unlock ();
nano::uint128_t tally;
for (auto & voter : existing.voters)
{

View file

@ -40,11 +40,12 @@ void nano::gap_cache::vote (std::shared_ptr<nano::vote> vote_a)
nano::lock_guard<std::mutex> lock (mutex);
for (auto hash : *vote_a)
{
auto existing (blocks.get<tag_hash> ().find (hash));
if (existing != blocks.get<tag_hash> ().end () && !existing->confirmed)
auto & gap_blocks_by_hash (blocks.get<tag_hash> ());
auto existing (gap_blocks_by_hash.find (hash));
if (existing != gap_blocks_by_hash.end () && !existing->bootstrap_started)
{
auto is_new (false);
blocks.get<tag_hash> ().modify (existing, [&is_new, &vote_a](nano::gap_information & info) {
gap_blocks_by_hash.modify (existing, [&is_new, &vote_a](nano::gap_information & info) {
auto it = std::find (info.voters.begin (), info.voters.end (), vote_a->account);
is_new = (it == info.voters.end ());
if (is_new)
@ -57,8 +58,8 @@ void nano::gap_cache::vote (std::shared_ptr<nano::vote> vote_a)
{
if (bootstrap_check (existing->voters, hash))
{
blocks.get<tag_hash> ().modify (existing, [](nano::gap_information & info) {
info.confirmed = true;
gap_blocks_by_hash.modify (existing, [](nano::gap_information & info) {
info.bootstrap_started = true;
});
}
}
@ -69,7 +70,7 @@ void nano::gap_cache::vote (std::shared_ptr<nano::vote> vote_a)
bool nano::gap_cache::bootstrap_check (std::vector<nano::account> const & voters_a, nano::block_hash const & hash_a)
{
uint128_t tally;
for (auto & voter : voters_a)
for (auto const & voter : voters_a)
{
tally += node.ledger.weight (voter);
}

View file

@ -27,7 +27,7 @@ public:
std::chrono::steady_clock::time_point arrival;
nano::block_hash hash;
std::vector<nano::account> voters;
bool confirmed{ false };
bool bootstrap_started{ false };
};
/** Maintains voting and arrival information for gaps (missing source or previous blocks in account chains) */