Skip to content

Commit

Permalink
Add unchecked_map stats (#4148)
Browse files Browse the repository at this point in the history
* Add stats counting to unchecked_map.

* Moving several tests related to unchecked_map to the unchecked_map.cpp file.
  • Loading branch information
clemahieu authored Feb 22, 2023
1 parent 430346c commit f9e5bbf
Show file tree
Hide file tree
Showing 7 changed files with 240 additions and 218 deletions.
214 changes: 4 additions & 210 deletions nano/core_test/block_store.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,214 +412,6 @@ TEST (block_store, genesis)
ASSERT_EQ (nano::dev::genesis->account (), nano::dev::genesis_key.pub);
}

// This test checks for basic operations in the unchecked table such as putting a new block, retrieving it, and
// deleting it from the database
TEST (unchecked, simple)
{
nano::test::system system{};
nano::logger_mt logger{};
auto store = nano::make_store (logger, nano::unique_path (), nano::dev::constants);
nano::unchecked_map unchecked{ *store, false };
ASSERT_TRUE (!store->init_error ());
nano::block_builder builder;
auto block = builder
.send ()
.previous (0)
.destination (1)
.balance (2)
.sign (nano::keypair ().prv, 4)
.work (5)
.build_shared ();
// Asserts the block wasn't added yet to the unchecked table
auto block_listing1 = unchecked.get (store->tx_begin_read (), block->previous ());
ASSERT_TRUE (block_listing1.empty ());
// Enqueues a block to be saved on the unchecked table
unchecked.put (block->previous (), nano::unchecked_info (block));
// Waits for the block to get written in the database
auto check_block_is_listed = [&] (nano::transaction const & transaction_a, nano::block_hash const & block_hash_a) {
return unchecked.get (transaction_a, block_hash_a).size () > 0;
};
ASSERT_TIMELY (5s, check_block_is_listed (store->tx_begin_read (), block->previous ()));
auto transaction = store->tx_begin_write ();
// Retrieves the block from the database
auto block_listing2 = unchecked.get (transaction, block->previous ());
ASSERT_FALSE (block_listing2.empty ());
// Asserts the added block is equal to the retrieved one
ASSERT_EQ (*block, *(block_listing2[0].block));
// Deletes the block from the database
unchecked.del (transaction, nano::unchecked_key (block->previous (), block->hash ()));
// Asserts the block is deleted
auto block_listing3 = unchecked.get (transaction, block->previous ());
ASSERT_TRUE (block_listing3.empty ());
}

// This test ensures the unchecked table is able to receive more than one block
TEST (unchecked, multiple)
{
nano::test::system system{};
if (nano::rocksdb_config::using_rocksdb_in_tests ())
{
// Don't test this in rocksdb mode
return;
}
nano::logger_mt logger{};
auto store = nano::make_store (logger, nano::unique_path (), nano::dev::constants);
nano::unchecked_map unchecked{ *store, false };
ASSERT_TRUE (!store->init_error ());
nano::block_builder builder;
auto block = builder
.send ()
.previous (4)
.destination (1)
.balance (2)
.sign (nano::keypair ().prv, 4)
.work (5)
.build_shared ();
// Asserts the block wasn't added yet to the unchecked table
auto block_listing1 = unchecked.get (store->tx_begin_read (), block->previous ());
ASSERT_TRUE (block_listing1.empty ());
// Enqueues the first block
unchecked.put (block->previous (), nano::unchecked_info (block));
// Enqueues a second block
unchecked.put (block->source (), nano::unchecked_info (block));
auto check_block_is_listed = [&] (nano::transaction const & transaction_a, nano::block_hash const & block_hash_a) {
return unchecked.get (transaction_a, block_hash_a).size () > 0;
};
// Waits for and asserts the first block gets saved in the database
ASSERT_TIMELY (5s, check_block_is_listed (store->tx_begin_read (), block->previous ()));
// Waits for and asserts the second block gets saved in the database
ASSERT_TIMELY (5s, check_block_is_listed (store->tx_begin_read (), block->source ()));
}

// This test ensures that a block can't occur twice in the unchecked table.
TEST (unchecked, double_put)
{
nano::test::system system{};
nano::logger_mt logger{};
auto store = nano::make_store (logger, nano::unique_path (), nano::dev::constants);
nano::unchecked_map unchecked{ *store, false };
ASSERT_TRUE (!store->init_error ());
nano::block_builder builder;
auto block = builder
.send ()
.previous (4)
.destination (1)
.balance (2)
.sign (nano::keypair ().prv, 4)
.work (5)
.build_shared ();
// Asserts the block wasn't added yet to the unchecked table
auto block_listing1 = unchecked.get (store->tx_begin_read (), block->previous ());
ASSERT_TRUE (block_listing1.empty ());
// Enqueues the block to be saved in the unchecked table
unchecked.put (block->previous (), nano::unchecked_info (block));
// Enqueues the block again in an attempt to have it there twice
unchecked.put (block->previous (), nano::unchecked_info (block));
auto check_block_is_listed = [&] (nano::transaction const & transaction_a, nano::block_hash const & block_hash_a) {
return unchecked.get (transaction_a, block_hash_a).size () > 0;
};
// Waits for and asserts the block was added at least once
ASSERT_TIMELY (5s, check_block_is_listed (store->tx_begin_read (), block->previous ()));
// Asserts the block was added at most once -- this is objective of this test.
auto block_listing2 = unchecked.get (store->tx_begin_read (), block->previous ());
ASSERT_EQ (block_listing2.size (), 1);
}

// Tests that recurrent get calls return the correct values
TEST (unchecked, multiple_get)
{
nano::test::system system{};
nano::logger_mt logger{};
auto store = nano::make_store (logger, nano::unique_path (), nano::dev::constants);
nano::unchecked_map unchecked{ *store, false };
ASSERT_TRUE (!store->init_error ());
// Instantiates three blocks
nano::block_builder builder;
auto block1 = builder
.send ()
.previous (4)
.destination (1)
.balance (2)
.sign (nano::keypair ().prv, 4)
.work (5)
.build_shared ();
auto block2 = builder
.send ()
.previous (3)
.destination (1)
.balance (2)
.sign (nano::keypair ().prv, 4)
.work (5)
.build_shared ();
auto block3 = builder
.send ()
.previous (5)
.destination (1)
.balance (2)
.sign (nano::keypair ().prv, 4)
.work (5)
.build_shared ();
// Add the blocks' info to the unchecked table
unchecked.put (block1->previous (), nano::unchecked_info (block1)); // unchecked1
unchecked.put (block1->hash (), nano::unchecked_info (block1)); // unchecked2
unchecked.put (block2->previous (), nano::unchecked_info (block2)); // unchecked3
unchecked.put (block1->previous (), nano::unchecked_info (block2)); // unchecked1
unchecked.put (block1->hash (), nano::unchecked_info (block2)); // unchecked2
unchecked.put (block3->previous (), nano::unchecked_info (block3));
unchecked.put (block3->hash (), nano::unchecked_info (block3)); // unchecked4
unchecked.put (block1->previous (), nano::unchecked_info (block3)); // unchecked1

// count the number of blocks in the unchecked table by counting them one by one
// we cannot trust the count() method if the backend is rocksdb
auto count_unchecked_blocks_one_by_one = [&store, &unchecked] () {
size_t count = 0;
auto transaction = store->tx_begin_read ();
unchecked.for_each (transaction, [&count] (nano::unchecked_key const & key, nano::unchecked_info const & info) {
++count;
});
return count;
};

// Waits for the blocks to get saved in the database
ASSERT_TIMELY (5s, 8 == count_unchecked_blocks_one_by_one ());

std::vector<nano::block_hash> unchecked1;
// Asserts the entries will be found for the provided key
auto transaction = store->tx_begin_read ();
auto unchecked1_blocks = unchecked.get (transaction, block1->previous ());
ASSERT_EQ (unchecked1_blocks.size (), 3);
for (auto & i : unchecked1_blocks)
{
unchecked1.push_back (i.block->hash ());
}
// Asserts the payloads where correclty saved
ASSERT_TRUE (std::find (unchecked1.begin (), unchecked1.end (), block1->hash ()) != unchecked1.end ());
ASSERT_TRUE (std::find (unchecked1.begin (), unchecked1.end (), block2->hash ()) != unchecked1.end ());
ASSERT_TRUE (std::find (unchecked1.begin (), unchecked1.end (), block3->hash ()) != unchecked1.end ());
std::vector<nano::block_hash> unchecked2;
// Asserts the entries will be found for the provided key
auto unchecked2_blocks = unchecked.get (transaction, block1->hash ());
ASSERT_EQ (unchecked2_blocks.size (), 2);
for (auto & i : unchecked2_blocks)
{
unchecked2.push_back (i.block->hash ());
}
// Asserts the payloads where correctly saved
ASSERT_TRUE (std::find (unchecked2.begin (), unchecked2.end (), block1->hash ()) != unchecked2.end ());
ASSERT_TRUE (std::find (unchecked2.begin (), unchecked2.end (), block2->hash ()) != unchecked2.end ());
// Asserts the entry is found by the key and the payload is saved
auto unchecked3 = unchecked.get (transaction, block2->previous ());
ASSERT_EQ (unchecked3.size (), 1);
ASSERT_EQ (unchecked3[0].block->hash (), block2->hash ());
// Asserts the entry is found by the key and the payload is saved
auto unchecked4 = unchecked.get (transaction, block3->hash ());
ASSERT_EQ (unchecked4.size (), 1);
ASSERT_EQ (unchecked4[0].block->hash (), block3->hash ());
// Asserts no entry is found for a block that wasn't added
auto unchecked5 = unchecked.get (transaction, block2->hash ());
ASSERT_EQ (unchecked5.size (), 0);
}

TEST (block_store, empty_accounts)
{
nano::logger_mt logger;
Expand Down Expand Up @@ -653,9 +445,10 @@ TEST (block_store, one_block)

TEST (block_store, empty_bootstrap)
{
nano::test::system system{};
nano::logger_mt logger;
auto store = nano::make_store (logger, nano::unique_path (), nano::dev::constants);
nano::unchecked_map unchecked{ *store, false };
nano::unchecked_map unchecked{ *store, system.stats, false };
ASSERT_TRUE (!store->init_error ());
auto transaction (store->tx_begin_read ());
size_t count = 0;
Expand Down Expand Up @@ -1176,10 +969,11 @@ namespace lmdb
// Databases need to be dropped in order to convert to dupsort compatible
TEST (block_store, DISABLED_change_dupsort) // Unchecked is no longer dupsort table
{
nano::test::system system{};
auto path (nano::unique_path ());
nano::logger_mt logger{};
nano::lmdb::store store{ logger, path, nano::dev::constants };
nano::unchecked_map unchecked{ store, false };
nano::unchecked_map unchecked{ store, system.stats, false };
auto transaction (store.tx_begin_write ());
ASSERT_EQ (0, mdb_drop (store.env.tx (transaction), store.unchecked_store.unchecked_handle, 1));
ASSERT_EQ (0, mdb_dbi_open (store.env.tx (transaction), "unchecked", MDB_CREATE, &store.unchecked_store.unchecked_handle));
Expand Down
5 changes: 3 additions & 2 deletions nano/core_test/ledger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5535,12 +5535,13 @@ TEST (ledger, hash_root_random)

TEST (ledger, migrate_lmdb_to_rocksdb)
{
nano::test::system system{};
auto path = nano::unique_path ();
nano::logger_mt logger{};
boost::asio::ip::address_v6 address (boost::asio::ip::make_address_v6 ("::ffff:127.0.0.1"));
uint16_t port = 100;
nano::lmdb::store store{ logger, path / "data.ldb", nano::dev::constants };
nano::unchecked_map unchecked{ store, false };
nano::unchecked_map unchecked{ store, system.stats, false };
nano::stats stats{};
nano::ledger ledger{ store, stats, nano::dev::constants };
nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits<unsigned>::max () };
Expand Down Expand Up @@ -5582,7 +5583,7 @@ TEST (ledger, migrate_lmdb_to_rocksdb)
ASSERT_FALSE (error);

nano::rocksdb::store rocksdb_store{ logger, path / "rocksdb", nano::dev::constants };
nano::unchecked_map rocksdb_unchecked{ rocksdb_store, false };
nano::unchecked_map rocksdb_unchecked{ rocksdb_store, system.stats, false };
auto rocksdb_transaction (rocksdb_store.tx_begin_read ());

nano::pending_info pending_info{};
Expand Down
Loading

0 comments on commit f9e5bbf

Please sign in to comment.