Reload wallets list from disk each 5 minutes (#1619)

* Add mutexes for all wallets functions

* Reload wallets list from disk each 5 minutes

* Test wallets.reload
This commit is contained in:
Sergey Kroshnin 2019-01-26 19:09:12 +03:00 committed by Zach Hyatt
commit 88afc90f81
4 changed files with 76 additions and 1 deletions

View file

@ -1,6 +1,7 @@
#include <gtest/gtest.h>
#include <nano/core_test/testutil.hpp>
#include <nano/node/node.hpp>
#include <nano/node/testing.hpp>
using namespace std::chrono_literals;
@ -95,3 +96,23 @@ TEST (wallets, DISABLED_wallet_create_max)
auto existing = wallets.items.find (key.pub);
ASSERT_TRUE (existing == wallets.items.end ());
}
TEST (wallets, reload)
{
nano::system system (24000, 1);
nano::uint256_union one (1);
bool error (false);
ASSERT_FALSE (error);
ASSERT_EQ (1, system.nodes[0]->wallets.items.size ());
{
nano::inactive_node node (system.nodes[0]->application_path, 24001);
auto wallet (node.node->wallets.create (one));
ASSERT_NE (wallet, nullptr);
}
system.deadline_set (5s);
while (system.nodes[0]->wallets.open (one) == nullptr)
{
system.poll ();
}
ASSERT_EQ (2, system.nodes[0]->wallets.items.size ());
}

View file

@ -2276,6 +2276,9 @@ void nano::node::backup_wallet ()
void nano::node::search_pending ()
{
// Reload wallets from disk
wallets.reload ();
// Search pending
wallets.search_pending_all ();
auto this_l (shared ());
alarm.add (std::chrono::steady_clock::now () + search_pending_interval, [this_l]() {

View file

@ -1299,6 +1299,7 @@ thread ([this]() {
do_wallet_actions ();
})
{
std::lock_guard<std::mutex> lock (mutex);
if (!error_a)
{
auto transaction (tx_begin_write ());
@ -1340,6 +1341,7 @@ nano::wallets::~wallets ()
std::shared_ptr<nano::wallet> nano::wallets::open (nano::uint256_union const & id_a)
{
std::lock_guard<std::mutex> lock (mutex);
std::shared_ptr<nano::wallet> result;
auto existing (items.find (id_a));
if (existing != items.end ())
@ -1351,6 +1353,7 @@ std::shared_ptr<nano::wallet> nano::wallets::open (nano::uint256_union const & i
std::shared_ptr<nano::wallet> nano::wallets::create (nano::uint256_union const & id_a)
{
std::lock_guard<std::mutex> lock (mutex);
assert (items.find (id_a) == items.end ());
std::shared_ptr<nano::wallet> result;
bool error;
@ -1368,6 +1371,7 @@ std::shared_ptr<nano::wallet> nano::wallets::create (nano::uint256_union const &
bool nano::wallets::search_pending (nano::uint256_union const & wallet_a)
{
std::lock_guard<std::mutex> lock (mutex);
auto result (false);
auto existing (items.find (wallet_a));
result = existing == items.end ();
@ -1381,6 +1385,7 @@ bool nano::wallets::search_pending (nano::uint256_union const & wallet_a)
void nano::wallets::search_pending_all ()
{
std::lock_guard<std::mutex> lock (mutex);
for (auto i : items)
{
i.second->search_pending ();
@ -1398,6 +1403,49 @@ void nano::wallets::destroy (nano::uint256_union const & id_a)
wallet->store.destroy (transaction);
}
void nano::wallets::reload ()
{
std::lock_guard<std::mutex> lock (mutex);
auto transaction (tx_begin_write ());
std::unordered_set<nano::uint256_union> stored_items;
std::string beginning (nano::uint256_union (0).to_string ());
std::string end ((nano::uint256_union (nano::uint256_t (0) - nano::uint256_t (1))).to_string ());
nano::store_iterator<std::array<char, 64>, nano::mdb_val::no_value> i (std::make_unique<nano::mdb_iterator<std::array<char, 64>, nano::mdb_val::no_value>> (transaction, handle, nano::mdb_val (beginning.size (), const_cast<char *> (beginning.c_str ()))));
nano::store_iterator<std::array<char, 64>, nano::mdb_val::no_value> n (std::make_unique<nano::mdb_iterator<std::array<char, 64>, nano::mdb_val::no_value>> (transaction, handle, nano::mdb_val (end.size (), const_cast<char *> (end.c_str ()))));
for (; i != n; ++i)
{
nano::uint256_union id;
std::string text (i->first.data (), i->first.size ());
auto error (id.decode_hex (text));
assert (!error);
// New wallet
if (items.find (id) == items.end ())
{
auto wallet (std::make_shared<nano::wallet> (error, transaction, *this, text));
if (!error)
{
items[id] = wallet;
}
}
// List of wallets on disk
stored_items.insert (id);
}
// Delete non existing wallets from memory
std::vector<nano::uint256_union> deleted_items;
for (auto i : items)
{
if (stored_items.find (i.first) == stored_items.end ())
{
deleted_items.push_back (i.first);
}
}
for (auto & i : deleted_items)
{
assert (items.find (i) == items.end ());
items.erase (i);
}
}
void nano::wallets::do_wallet_actions ()
{
std::unique_lock<std::mutex> lock (mutex);
@ -1436,11 +1484,12 @@ void nano::wallets::queue_wallet_action (nano::uint128_t const & amount_a, std::
void nano::wallets::foreach_representative (nano::transaction const & transaction_a, std::function<void(nano::public_key const & pub_a, nano::raw_key const & prv_a)> const & action_a)
{
std::lock_guard<std::mutex> lock (mutex);
auto transaction_l (node.wallets.tx_begin_read ());
for (auto i (items.begin ()), n (items.end ()); i != n; ++i)
{
auto & wallet (*i->second);
std::lock_guard<std::recursive_mutex> lock (wallet.store.mutex);
std::lock_guard<std::recursive_mutex> store_lock (wallet.store.mutex);
for (auto j (wallet.store.begin (transaction_l)), m (wallet.store.end ()); j != m; ++j)
{
nano::account account (j->first);
@ -1469,6 +1518,7 @@ void nano::wallets::foreach_representative (nano::transaction const & transactio
bool nano::wallets::exists (nano::transaction const & transaction_a, nano::public_key const & account_a)
{
std::lock_guard<std::mutex> lock (mutex);
auto result (false);
for (auto i (items.begin ()), n (items.end ()); !result && i != n; ++i)
{

View file

@ -171,6 +171,7 @@ public:
bool search_pending (nano::uint256_union const &);
void search_pending_all ();
void destroy (nano::uint256_union const &);
void reload ();
void do_wallet_actions ();
void queue_wallet_action (nano::uint128_t const &, std::shared_ptr<nano::wallet>, std::function<void(nano::wallet &)> const &);
void foreach_representative (nano::transaction const &, std::function<void(nano::public_key const &, nano::raw_key const &)> const &);