Perform wallet representative action without holding any mutex (#2759)
* Perform wallet representative action without holding any mutex This relaxes restrictions on the action and avoids potential deadlocks through lock-order-inversion * Relax debug_assert when adding to votes_cache as the representative counts can change even during a foreach_representative action * Windows requires explicitly unlocking the mutex once locked
This commit is contained in:
parent
6b89f7090d
commit
f30b3e87dd
3 changed files with 57 additions and 28 deletions
|
|
@ -1556,3 +1556,22 @@ TEST (wallet, epoch_2_receive_unopened)
|
||||||
}
|
}
|
||||||
ASSERT_LT (tries, max_tries);
|
ASSERT_LT (tries, max_tries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST (wallet, foreach_representative_deadlock)
|
||||||
|
{
|
||||||
|
nano::system system (1);
|
||||||
|
auto & node (*system.nodes[0]);
|
||||||
|
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
|
||||||
|
node.wallets.compute_reps ();
|
||||||
|
ASSERT_EQ (1, node.wallets.rep_counts ().voting);
|
||||||
|
node.wallets.foreach_representative ([&node](nano::public_key const & pub, nano::raw_key const & prv) {
|
||||||
|
if (node.wallets.mutex.try_lock ())
|
||||||
|
{
|
||||||
|
node.wallets.mutex.unlock ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT_FALSE (true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,9 +137,12 @@ wallets (wallets_a)
|
||||||
|
|
||||||
void nano::votes_cache::add (std::shared_ptr<nano::vote> const & vote_a)
|
void nano::votes_cache::add (std::shared_ptr<nano::vote> const & vote_a)
|
||||||
{
|
{
|
||||||
nano::lock_guard<std::mutex> lock (cache_mutex);
|
|
||||||
auto voting (wallets.rep_counts ().voting);
|
auto voting (wallets.rep_counts ().voting);
|
||||||
debug_assert (voting > 0);
|
if (voting == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nano::lock_guard<std::mutex> lock (cache_mutex);
|
||||||
auto const max_cache_size (network_params.voting.max_cache / std::max (voting, static_cast<decltype (voting)> (1)));
|
auto const max_cache_size (network_params.voting.max_cache / std::max (voting, static_cast<decltype (voting)> (1)));
|
||||||
for (auto & block : vote_a->blocks)
|
for (auto & block : vote_a->blocks)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1750,8 +1750,10 @@ void nano::wallets::foreach_representative (std::function<void(nano::public_key
|
||||||
{
|
{
|
||||||
if (node.config.enable_voting)
|
if (node.config.enable_voting)
|
||||||
{
|
{
|
||||||
nano::lock_guard<std::mutex> lock (mutex);
|
std::vector<std::pair<nano::public_key const, nano::raw_key const>> action_accounts_l;
|
||||||
|
{
|
||||||
auto transaction_l (tx_begin_read ());
|
auto transaction_l (tx_begin_read ());
|
||||||
|
nano::lock_guard<std::mutex> lock (mutex);
|
||||||
for (auto i (items.begin ()), n (items.end ()); i != n; ++i)
|
for (auto i (items.begin ()), n (items.end ()); i != n; ++i)
|
||||||
{
|
{
|
||||||
auto & wallet (*i->second);
|
auto & wallet (*i->second);
|
||||||
|
|
@ -1773,7 +1775,7 @@ void nano::wallets::foreach_representative (std::function<void(nano::public_key
|
||||||
auto error (wallet.store.fetch (transaction_l, account, prv));
|
auto error (wallet.store.fetch (transaction_l, account, prv));
|
||||||
(void)error;
|
(void)error;
|
||||||
debug_assert (!error);
|
debug_assert (!error);
|
||||||
action_a (account, prv);
|
action_accounts_l.emplace_back (account, prv);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -1789,6 +1791,11 @@ void nano::wallets::foreach_representative (std::function<void(nano::public_key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (auto const & representative : action_accounts_l)
|
||||||
|
{
|
||||||
|
action_a (representative.first, representative.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nano::wallets::exists (nano::transaction const & transaction_a, nano::account const & account_a)
|
bool nano::wallets::exists (nano::transaction const & transaction_a, nano::account const & account_a)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue