Statistics support (#759)

This commit is contained in:
cryptocode 2018-04-29 18:36:21 +02:00 committed by Lee Bousfield
commit 751d092c43
17 changed files with 1170 additions and 147 deletions

View file

@ -312,6 +312,8 @@ add_library (node
rai/node/testing.cpp
rai/node/wallet.hpp
rai/node/wallet.cpp
rai/node/stats.hpp
rai/node/stats.cpp
rai/node/working.hpp
rai/node/xorshift.hpp)

View file

@ -643,7 +643,8 @@ TEST (block_store, upgrade_v2_v3)
rai::genesis genesis;
auto hash (genesis.hash ());
genesis.initialize (transaction, store);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::change_block change (hash, key1.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0);
change_hash = change.hash ();
ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, change).code);
@ -664,7 +665,8 @@ TEST (block_store, upgrade_v2_v3)
}
bool init (false);
rai::block_store store (init, path);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::transaction transaction (store.environment, nullptr, true);
ASSERT_TRUE (!init);
ASSERT_LT (2, store.version_get (transaction));
@ -693,7 +695,8 @@ TEST (block_store, upgrade_v3_v4)
}
bool init (false);
rai::block_store store (init, path);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::transaction transaction (store.environment, nullptr, true);
ASSERT_FALSE (init);
ASSERT_LT (3, store.version_get (transaction));
@ -717,7 +720,8 @@ TEST (block_store, upgrade_v4_v5)
rai::transaction transaction (store.environment, nullptr, true);
rai::genesis genesis;
genesis.initialize (transaction, store);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
store.version_put (transaction, 4);
rai::account_info info;
store.account_get (transaction, rai::test_genesis_key.pub, info);
@ -931,7 +935,8 @@ TEST (block_store, upgrade_v9_v10)
rai::transaction transaction (store.environment, nullptr, true);
rai::genesis genesis;
genesis.initialize (transaction, store);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
store.version_put (transaction, 9);
rai::account_info info;
store.account_get (transaction, rai::test_genesis_key.pub, info);

View file

@ -1,6 +1,7 @@
#include <cryptopp/filters.h>
#include <cryptopp/randpool.h>
#include <gtest/gtest.h>
#include <rai/node/stats.hpp>
#include <rai/node/testing.hpp>
// Init returns an error if it can't open files at the path
@ -9,7 +10,8 @@ TEST (ledger, store_error)
bool init (false);
rai::block_store store (init, boost::filesystem::path ("///"));
ASSERT_FALSE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
}
// Ledger can be initialized and returns a basic query for an empty account
@ -18,7 +20,8 @@ TEST (ledger, empty)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::account account;
rai::transaction transaction (store.environment, nullptr, false);
auto balance (ledger.account_balance (transaction, account));
@ -31,7 +34,8 @@ TEST (ledger, genesis_balance)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -62,14 +66,15 @@ TEST (ledger, checksum_persistence)
max.qwords[2] = ~max.qwords[2];
max.qwords[3] = 0;
max.qwords[3] = ~max.qwords[3];
rai::stat stats;
rai::transaction transaction (store.environment, nullptr, true);
{
rai::ledger ledger (store);
rai::ledger ledger (store, stats);
rai::genesis genesis;
genesis.initialize (transaction, store);
checksum1 = ledger.checksum (transaction, 0, max);
}
rai::ledger ledger (store);
rai::ledger ledger (store, stats);
ASSERT_EQ (checksum1, ledger.checksum (transaction, 0, max));
}
@ -90,7 +95,8 @@ TEST (ledger, process_send)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::transaction transaction (store.environment, nullptr, true);
rai::genesis genesis;
genesis.initialize (transaction, store);
@ -182,7 +188,8 @@ TEST (ledger, process_receive)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -238,7 +245,8 @@ TEST (ledger, rollback_receiver)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -275,7 +283,8 @@ TEST (ledger, rollback_representation)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -327,7 +336,8 @@ TEST (ledger, receive_rollback)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -343,7 +353,8 @@ TEST (ledger, process_duplicate)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -364,7 +375,8 @@ TEST (ledger, representative_genesis)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -378,7 +390,8 @@ TEST (ledger, weight)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -390,7 +403,8 @@ TEST (ledger, representative_change)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::keypair key2;
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
@ -427,7 +441,8 @@ TEST (ledger, send_fork)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::keypair key2;
rai::keypair key3;
rai::genesis genesis;
@ -446,7 +461,8 @@ TEST (ledger, receive_fork)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::keypair key2;
rai::keypair key3;
rai::genesis genesis;
@ -471,7 +487,8 @@ TEST (ledger, open_fork)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::keypair key2;
rai::keypair key3;
rai::genesis genesis;
@ -495,7 +512,8 @@ TEST (ledger, checksum_single)
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
store.checksum_put (transaction, 0, 0, genesis.hash ());
ASSERT_EQ (genesis.hash (), ledger.checksum (transaction, 0, std::numeric_limits<rai::uint256_t>::max ()));
rai::change_block block1 (ledger.latest (transaction, rai::test_genesis_key.pub), rai::account (1), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0);
@ -514,7 +532,8 @@ TEST (ledger, checksum_two)
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
store.checksum_put (transaction, 0, 0, genesis.hash ());
rai::keypair key2;
rai::send_block block1 (ledger.latest (transaction, rai::test_genesis_key.pub), key2.pub, 100, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0);
@ -531,7 +550,8 @@ TEST (ledger, DISABLED_checksum_range)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::transaction transaction (store.environment, nullptr, false);
rai::checksum check1 (ledger.checksum (transaction, 0, std::numeric_limits<rai::uint256_t>::max ()));
ASSERT_TRUE (check1.is_zero ());
@ -628,7 +648,8 @@ TEST (ledger, representation)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -700,7 +721,8 @@ TEST (ledger, double_open)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -718,7 +740,8 @@ TEST (ledegr, double_receive)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -993,7 +1016,8 @@ TEST (ledger, fail_change_old)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1010,7 +1034,8 @@ TEST (ledger, fail_change_gap_previous)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1025,7 +1050,8 @@ TEST (ledger, fail_change_bad_signature)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1040,7 +1066,8 @@ TEST (ledger, fail_change_fork)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1059,7 +1086,8 @@ TEST (ledger, fail_send_old)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1076,7 +1104,8 @@ TEST (ledger, fail_send_gap_previous)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1091,7 +1120,8 @@ TEST (ledger, fail_send_bad_signature)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1106,7 +1136,8 @@ TEST (ledger, fail_send_negative_spend)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1123,7 +1154,8 @@ TEST (ledger, fail_send_fork)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1140,7 +1172,8 @@ TEST (ledger, fail_open_old)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1157,7 +1190,8 @@ TEST (ledger, fail_open_gap_source)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1172,7 +1206,8 @@ TEST (ledger, fail_open_bad_signature)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1189,7 +1224,8 @@ TEST (ledger, fail_open_fork_previous)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1209,7 +1245,8 @@ TEST (ledger, fail_open_account_mismatch)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1226,7 +1263,8 @@ TEST (ledger, fail_receive_old)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1247,7 +1285,8 @@ TEST (ledger, fail_receive_gap_source)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1271,7 +1310,8 @@ TEST (ledger, fail_receive_overreceive)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1292,7 +1332,8 @@ TEST (ledger, fail_receive_bad_signature)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1316,7 +1357,8 @@ TEST (ledger, fail_receive_gap_previous_opened)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1340,7 +1382,8 @@ TEST (ledger, fail_receive_gap_previous_unopened)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1361,7 +1404,8 @@ TEST (ledger, fail_receive_fork_previous)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1389,7 +1433,8 @@ TEST (ledger, fail_receive_received_source)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1423,7 +1468,8 @@ TEST (ledger, latest_empty)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::keypair key;
rai::transaction transaction (store.environment, nullptr, false);
auto latest (ledger.latest (transaction, key.pub));
@ -1435,7 +1481,8 @@ TEST (ledger, latest_root)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -1452,7 +1499,8 @@ TEST (ledger, supply_cache)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store, 40);
rai::stat stats;
rai::ledger ledger (store, stats, 40);
{
rai::transaction transaction (store.environment, nullptr, true);
rai::genesis genesis;
@ -1475,7 +1523,8 @@ TEST (ledger, inactive_supply)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store, 40);
rai::stat stats;
rai::ledger ledger (store, stats, 40);
{
rai::transaction transaction (store.environment, nullptr, true);
rai::genesis genesis;
@ -1498,7 +1547,8 @@ TEST (ledger, change_representative_move_representation)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::keypair key1;
rai::transaction transaction (store.environment, nullptr, true);
rai::genesis genesis;
@ -1522,7 +1572,8 @@ TEST (ledger, send_open_receive_rollback)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store, 0);
rai::stat stats;
rai::ledger ledger (store, stats, 0);
rai::transaction transaction (store.environment, nullptr, true);
rai::genesis genesis;
genesis.initialize (transaction, store);
@ -1579,7 +1630,8 @@ TEST (ledger, bootstrap_rep_weight)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store, 40);
rai::stat stats;
rai::ledger ledger (store, stats, 40);
rai::account_info info1;
rai::keypair key2;
rai::genesis genesis;
@ -1613,7 +1665,8 @@ TEST (ledger, block_destination_source)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -1658,7 +1711,8 @@ TEST (ledger, state_account)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -1673,7 +1727,8 @@ TEST (ledger, state_send_receive)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -1705,7 +1760,8 @@ TEST (ledger, state_receive)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -1735,7 +1791,8 @@ TEST (ledger, state_rep_change)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -1758,7 +1815,8 @@ TEST (ledger, state_open)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -1792,7 +1850,8 @@ TEST (ledger, send_after_state_fail)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -1809,7 +1868,8 @@ TEST (ledger, receive_after_state_fail)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -1826,7 +1886,8 @@ TEST (ledger, change_after_state_fail)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -1843,7 +1904,8 @@ TEST (ledger, state_unreceivable_fail)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -1866,7 +1928,8 @@ TEST (ledger, state_receive_bad_amount_fail)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -1889,7 +1952,8 @@ TEST (ledger, state_no_link_amount_fail)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -1906,7 +1970,8 @@ TEST (ledger, state_receive_wrong_account_fail)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -1930,7 +1995,8 @@ TEST (ledger, state_open_state_fork)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -1950,7 +2016,8 @@ TEST (ledger, state_state_open_fork)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -1970,7 +2037,8 @@ TEST (ledger, state_open_previous_fail)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -1987,7 +2055,8 @@ TEST (ledger, state_open_source_fail)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -2004,7 +2073,8 @@ TEST (ledger, state_send_change)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -2027,7 +2097,8 @@ TEST (ledger, state_receive_change)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -2059,7 +2130,8 @@ TEST (ledger, state_open_old)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -2079,7 +2151,8 @@ TEST (ledger, state_receive_old)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -2103,7 +2176,8 @@ TEST (ledger, state_rollback_send)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -2133,7 +2207,8 @@ TEST (ledger, state_rollback_receive)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -2158,7 +2233,8 @@ TEST (ledger, state_rollback_received_send)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -2184,7 +2260,8 @@ TEST (ledger, state_rep_change_rollback)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -2204,7 +2281,8 @@ TEST (ledger, state_open_rollback)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -2229,7 +2307,8 @@ TEST (ledger, state_send_change_rollback)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -2249,7 +2328,8 @@ TEST (ledger, state_receive_change_rollback)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
ledger.state_block_parse_canary = genesis.hash ();
rai::transaction transaction (store.environment, nullptr, true);
@ -2274,7 +2354,8 @@ TEST (ledger, state_canary_blocks)
rai::genesis genesis;
rai::send_block parse_canary (genesis.hash (), rai::test_genesis_key.pub, rai::genesis_amount, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0);
rai::send_block generate_canary (parse_canary.hash (), rai::test_genesis_key.pub, rai::genesis_amount, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0);
rai::ledger ledger (store, 0, parse_canary.hash (), generate_canary.hash ());
rai::stat stats;
rai::ledger ledger (store, stats, 0, parse_canary.hash (), generate_canary.hash ());
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
rai::state_block state (rai::test_genesis_key.pub, genesis.hash (), rai::test_genesis_key.pub, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0);

View file

@ -53,9 +53,9 @@ TEST (network, self_discard)
{
rai::system system (24000, 1);
system.nodes[0]->network.remote = system.nodes[0]->network.endpoint ();
ASSERT_EQ (0, system.nodes[0]->network.bad_sender_count);
ASSERT_EQ (0, system.nodes[0]->stats.count (rai::stat::type::error, rai::stat::detail::bad_sender));
system.nodes[0]->network.receive_action (boost::system::error_code{}, 0);
ASSERT_EQ (1, system.nodes[0]->network.bad_sender_count);
ASSERT_EQ (1, system.nodes[0]->stats.count (rai::stat::type::error, rai::stat::detail::bad_sender));
}
TEST (network, send_keepalive)
@ -67,11 +67,11 @@ TEST (network, send_keepalive)
auto node1 (std::make_shared<rai::node> (init1, system.service, 24001, rai::unique_path (), system.alarm, system.logging, system.work));
node1->start ();
system.nodes[0]->network.send_keepalive (node1->network.endpoint ());
auto initial (system.nodes[0]->network.incoming.keepalive.load ());
auto initial (system.nodes[0]->stats.count (rai::stat::type::message, rai::stat::detail::keepalive, rai::stat::dir::in));
ASSERT_EQ (0, system.nodes[0]->peers.list ().size ());
ASSERT_EQ (0, node1->peers.list ().size ());
auto iterations (0);
while (system.nodes[0]->network.incoming.keepalive == initial)
while (system.nodes[0]->stats.count (rai::stat::type::message, rai::stat::detail::keepalive, rai::stat::dir::in) == initial)
{
system.poll ();
++iterations;
@ -95,9 +95,9 @@ TEST (network, keepalive_ipv4)
auto node1 (std::make_shared<rai::node> (init1, system.service, 24001, rai::unique_path (), system.alarm, system.logging, system.work));
node1->start ();
node1->send_keepalive (rai::endpoint (boost::asio::ip::address_v4::loopback (), 24000));
auto initial (system.nodes[0]->network.incoming.keepalive.load ());
auto initial (system.nodes[0]->stats.count (rai::stat::type::message, rai::stat::detail::keepalive, rai::stat::dir::in));
auto iterations (0);
while (system.nodes[0]->network.incoming.keepalive == initial)
while (system.nodes[0]->stats.count (rai::stat::type::message, rai::stat::detail::keepalive, rai::stat::dir::in) == initial)
{
system.poll ();
++iterations;
@ -154,7 +154,7 @@ TEST (network, send_discarded_publish)
ASSERT_EQ (genesis.hash (), system.nodes[1]->latest (rai::test_genesis_key.pub));
}
auto iterations (0);
while (system.nodes[1]->network.incoming.publish == 0)
while (system.nodes[1]->stats.count (rai::stat::type::message, rai::stat::detail::publish, rai::stat::dir::in) == 0)
{
system.poll ();
++iterations;
@ -177,7 +177,7 @@ TEST (network, send_invalid_publish)
ASSERT_EQ (genesis.hash (), system.nodes[1]->latest (rai::test_genesis_key.pub));
}
auto iterations (0);
while (system.nodes[1]->network.incoming.publish == 0)
while (system.nodes[1]->stats.count (rai::stat::type::message, rai::stat::detail::publish, rai::stat::dir::in) == 0)
{
system.poll ();
++iterations;
@ -222,7 +222,7 @@ TEST (network, send_valid_publish)
rai::block_hash latest2 (system.nodes[1]->latest (rai::test_genesis_key.pub));
system.nodes[1]->process_active (std::unique_ptr<rai::block> (new rai::send_block (block2)));
auto iterations (0);
while (system.nodes[0]->network.incoming.publish == 0)
while (system.nodes[0]->stats.count (rai::stat::type::message, rai::stat::detail::publish, rai::stat::dir::in) == 0)
{
system.poll ();
++iterations;
@ -246,15 +246,15 @@ TEST (network, send_insufficient_work)
}
auto node1 (system.nodes[1]->shared ());
system.nodes[0]->network.send_buffer (bytes->data (), bytes->size (), system.nodes[1]->network.endpoint (), [bytes, node1](boost::system::error_code const & ec, size_t size) {});
ASSERT_EQ (0, system.nodes[0]->network.insufficient_work_count);
ASSERT_EQ (0, system.nodes[0]->stats.count (rai::stat::type::error, rai::stat::detail::insufficient_work));
auto iterations (0);
while (system.nodes[1]->network.insufficient_work_count == 0)
while (system.nodes[1]->stats.count (rai::stat::type::error, rai::stat::detail::insufficient_work) == 0)
{
system.poll ();
++iterations;
ASSERT_LT (iterations, 200);
}
ASSERT_EQ (1, system.nodes[1]->network.insufficient_work_count);
ASSERT_EQ (1, system.nodes[1]->stats.count (rai::stat::type::error, rai::stat::detail::insufficient_work));
}
TEST (receivable_processor, confirm_insufficient_pos)

View file

@ -400,7 +400,7 @@ TEST (node, connect_after_junk)
uint64_t junk (0);
node1->network.socket.async_send_to (boost::asio::buffer (&junk, sizeof (junk)), system.nodes[0]->network.endpoint (), [](boost::system::error_code const &, size_t) {});
auto iterations1 (0);
while (system.nodes[0]->network.error_count == 0)
while (system.nodes[0]->stats.count (rai::stat::type::error) == 0)
{
system.poll ();
++iterations1;
@ -1060,7 +1060,7 @@ TEST (node, fork_no_vote_quorum)
confirm.serialize (stream);
}
node2.network.confirm_send (confirm, bytes, node3.network.endpoint ());
while (node3.network.incoming.confirm_ack < 3)
while (node3.stats.count (rai::stat::type::message, rai::stat::detail::confirm_ack, rai::stat::dir::in) < 3)
{
system.poll ();
}
@ -1333,7 +1333,7 @@ TEST (node, no_voting)
++iterations;
ASSERT_GT (200, iterations);
}
ASSERT_EQ (0, node1.network.incoming.confirm_ack);
ASSERT_EQ (0, node1.stats.count (rai::stat::type::message, rai::stat::detail::confirm_ack, rai::stat::dir::in));
}
TEST (node, start_observer)
@ -1461,6 +1461,22 @@ TEST (node, bootstrap_connection_scaling)
ASSERT_EQ (1, attempt->target_connections (50000));
}
// Test stat counting at both type and detail levels
TEST (node, stat_counting)
{
rai::system system (24000, 1);
auto & node1 (*system.nodes[0]);
node1.stats.add (rai::stat::type::ledger, rai::stat::dir::in, 1);
node1.stats.add (rai::stat::type::ledger, rai::stat::dir::in, 5);
node1.stats.inc (rai::stat::type::ledger, rai::stat::dir::in);
node1.stats.inc (rai::stat::type::ledger, rai::stat::detail::send, rai::stat::dir::in);
node1.stats.inc (rai::stat::type::ledger, rai::stat::detail::send, rai::stat::dir::in);
node1.stats.inc (rai::stat::type::ledger, rai::stat::detail::receive, rai::stat::dir::in);
ASSERT_EQ (10, node1.stats.count (rai::stat::type::ledger, rai::stat::dir::in));
ASSERT_EQ (2, node1.stats.count (rai::stat::type::ledger, rai::stat::detail::send, rai::stat::dir::in));
ASSERT_EQ (1, node1.stats.count (rai::stat::type::ledger, rai::stat::detail::receive, rai::stat::dir::in));
}
TEST (node, online_reps)
{
rai::system system (24000, 2);

View file

@ -11,7 +11,8 @@ TEST (processor_service, bad_send_signature)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
@ -29,7 +30,8 @@ TEST (processor_service, bad_receive_signature)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);

View file

@ -1,6 +1,7 @@
#include <rai/blockstore.hpp>
#include <rai/ledger.hpp>
#include <rai/node/common.hpp>
#include <rai/node/stats.hpp>
namespace
{
@ -39,6 +40,7 @@ public:
{
ledger.store.block_info_del (transaction, hash);
}
ledger.stats.inc (rai::stat::type::rollback, rai::stat::detail::send);
}
void receive_block (rai::receive_block const & block_a) override
{
@ -61,6 +63,7 @@ public:
{
ledger.store.block_info_del (transaction, hash);
}
ledger.stats.inc (rai::stat::type::rollback, rai::stat::detail::receive);
}
void open_block (rai::open_block const & block_a) override
{
@ -73,6 +76,7 @@ public:
ledger.store.block_del (transaction, hash);
ledger.store.pending_put (transaction, rai::pending_key (destination_account, block_a.hashables.source), { source_account, amount });
ledger.store.frontier_del (transaction, hash);
ledger.stats.inc (rai::stat::type::rollback, rai::stat::detail::open);
}
void change_block (rai::change_block const & block_a) override
{
@ -94,6 +98,7 @@ public:
{
ledger.store.block_info_del (transaction, hash);
}
ledger.stats.inc (rai::stat::type::rollback, rai::stat::detail::change);
}
void state_block (rai::state_block const & block_a) override
{
@ -121,11 +126,13 @@ public:
ledger.rollback (transaction, ledger.latest (transaction, block_a.hashables.link));
}
ledger.store.pending_del (transaction, key);
ledger.stats.inc (rai::stat::type::rollback, rai::stat::detail::send);
}
else if (!block_a.hashables.link.is_zero ())
{
rai::pending_info info (ledger.account (transaction, block_a.hashables.link), block_a.hashables.balance.number () - balance);
ledger.store.pending_put (transaction, rai::pending_key (block_a.hashables.account, block_a.hashables.link), info);
ledger.stats.inc (rai::stat::type::rollback, rai::stat::detail::receive);
}
rai::account_info info;
@ -151,6 +158,10 @@ public:
break;
}
}
else
{
ledger.stats.inc (rai::stat::type::rollback, rai::stat::detail::open);
}
ledger.store.block_del (transaction, hash);
}
MDB_txn * transaction;
@ -220,6 +231,7 @@ void ledger_processor::state_block_impl (rai::state_block const & block_a)
result.code = block_a.previous ().is_zero () ? rai::process_result::progress : rai::process_result::gap_previous; // Does the first block in an account yield 0 for previous() ? (Unambigious)
if (result.code == rai::process_result::progress)
{
ledger.stats.inc (rai::stat::type::ledger, rai::stat::detail::open);
result.code = !block_a.hashables.link.is_zero () ? rai::process_result::progress : rai::process_result::gap_source; // Is the first block receiving from a send ? (Unambigious)
}
}
@ -250,6 +262,7 @@ void ledger_processor::state_block_impl (rai::state_block const & block_a)
}
if (result.code == rai::process_result::progress)
{
ledger.stats.inc (rai::stat::type::ledger, rai::stat::detail::state_block);
result.state_is_send = is_send;
ledger.store.block_put (transaction, hash, block_a);
@ -266,10 +279,12 @@ void ledger_processor::state_block_impl (rai::state_block const & block_a)
rai::pending_key key (block_a.hashables.link, hash);
rai::pending_info info (block_a.hashables.account, result.amount.number ());
ledger.store.pending_put (transaction, key, info);
ledger.stats.inc (rai::stat::type::ledger, rai::stat::detail::send);
}
else if (!block_a.hashables.link.is_zero ())
{
ledger.store.pending_del (transaction, rai::pending_key (block_a.hashables.account, block_a.hashables.link));
ledger.stats.inc (rai::stat::type::ledger, rai::stat::detail::receive);
}
ledger.change_latest (transaction, block_a.hashables.account, hash, hash, block_a.hashables.balance, info.block_count + 1, true);
@ -319,6 +334,7 @@ void ledger_processor::change_block (rai::change_block const & block_a)
ledger.store.frontier_put (transaction, hash, account);
result.account = account;
result.amount = 0;
ledger.stats.inc (rai::stat::type::ledger, rai::stat::detail::change);
}
}
}
@ -364,6 +380,7 @@ void ledger_processor::send_block (rai::send_block const & block_a)
result.account = account;
result.amount = amount;
result.pending_account = block_a.hashables.destination;
ledger.stats.inc (rai::stat::type::ledger, rai::stat::detail::send);
}
}
}
@ -418,6 +435,7 @@ void ledger_processor::receive_block (rai::receive_block const & block_a)
ledger.store.frontier_put (transaction, hash, account);
result.account = account;
result.amount = pending.amount;
ledger.stats.inc (rai::stat::type::ledger, rai::stat::detail::receive);
}
}
}
@ -468,6 +486,7 @@ void ledger_processor::open_block (rai::open_block const & block_a)
ledger.store.frontier_put (transaction, hash, block_a.hashables.account);
result.account = block_a.hashables.account;
result.amount = pending.amount;
ledger.stats.inc (rai::stat::type::ledger, rai::stat::detail::open);
}
}
}
@ -535,8 +554,9 @@ void rai::supply::update_cache ()
}
}
rai::ledger::ledger (rai::block_store & store_a, rai::uint128_t const & inactive_supply_a, rai::block_hash const & state_block_parse_canary_a, rai::block_hash const & state_block_generate_canary_a) :
rai::ledger::ledger (rai::block_store & store_a, rai::stat & stat_a, rai::uint128_t const & inactive_supply_a, rai::block_hash const & state_block_parse_canary_a, rai::block_hash const & state_block_generate_canary_a) :
store (store_a),
stats (stat_a),
check_bootstrap_weights (true),
state_block_parse_canary (state_block_parse_canary_a),
state_block_generate_canary (state_block_generate_canary_a),

View file

@ -5,6 +5,7 @@
namespace rai
{
class block_store;
class stat;
class shared_ptr_block_hash
{
@ -38,7 +39,7 @@ private:
class ledger
{
public:
ledger (rai::block_store &, rai::uint128_t const & = 0, rai::block_hash const & = 0, rai::block_hash const & = 0);
ledger (rai::block_store &, rai::stat &, rai::uint128_t const & = 0, rai::block_hash const & = 0, rai::block_hash const & = 0);
std::pair<rai::uint128_t, std::shared_ptr<rai::block>> winner (MDB_txn *, rai::votes const & votes_a);
// Map of weight -> associated block, ordered greatest to least
std::map<rai::uint128_t, std::shared_ptr<rai::block>, std::greater<rai::uint128_t>> tally (MDB_txn *, rai::votes const &);
@ -70,6 +71,7 @@ public:
bool state_block_generation_enabled (MDB_txn *);
static rai::uint128_t const unit;
rai::block_store & store;
rai::stat & stats;
std::unordered_map<rai::account, rai::uint128_t> bootstrap_weights;
uint64_t bootstrap_weight_max_blocks;
std::atomic<bool> check_bootstrap_weights;

View file

@ -1301,6 +1301,7 @@ void rai::bootstrap_initiator::bootstrap ()
std::unique_lock<std::mutex> lock (mutex);
if (!stopped && attempt == nullptr)
{
node.stats.inc (rai::stat::type::bootstrap, rai::stat::detail::initiate, rai::stat::dir::out);
attempt = std::make_shared<rai::bootstrap_attempt> (node.shared ());
condition.notify_all ();
}
@ -1317,6 +1318,7 @@ void rai::bootstrap_initiator::bootstrap (rai::endpoint const & endpoint_a)
attempt->stop ();
condition.wait (lock);
}
node.stats.inc (rai::stat::type::bootstrap, rai::stat::detail::initiate, rai::stat::dir::out);
attempt = std::make_shared<rai::bootstrap_attempt> (node.shared ());
attempt->add_connection (endpoint_a);
condition.notify_all ();
@ -1507,6 +1509,7 @@ void rai::bootstrap_server::receive_header_action (boost::system::error_code con
{
case rai::message_type::bulk_pull:
{
node->stats.inc (rai::stat::type::bootstrap, rai::stat::detail::bulk_pull, rai::stat::dir::in);
auto this_l (shared_from_this ());
boost::asio::async_read (*socket, boost::asio::buffer (receive_buffer.data () + 8, sizeof (rai::uint256_union) + sizeof (rai::uint256_union)), [this_l](boost::system::error_code const & ec, size_t size_a) {
this_l->receive_bulk_pull_action (ec, size_a);
@ -1515,6 +1518,7 @@ void rai::bootstrap_server::receive_header_action (boost::system::error_code con
}
case rai::message_type::bulk_pull_blocks:
{
node->stats.inc (rai::stat::type::bootstrap, rai::stat::detail::bulk_pull_blocks, rai::stat::dir::in);
auto this_l (shared_from_this ());
boost::asio::async_read (*socket, boost::asio::buffer (receive_buffer.data () + rai::bootstrap_message_header_size, sizeof (rai::uint256_union) + sizeof (rai::uint256_union) + sizeof (bulk_pull_blocks_mode) + sizeof (uint32_t)), [this_l](boost::system::error_code const & ec, size_t size_a) {
this_l->receive_bulk_pull_blocks_action (ec, size_a);
@ -1523,6 +1527,7 @@ void rai::bootstrap_server::receive_header_action (boost::system::error_code con
}
case rai::message_type::frontier_req:
{
node->stats.inc (rai::stat::type::bootstrap, rai::stat::detail::frontier_req, rai::stat::dir::in);
auto this_l (shared_from_this ());
boost::asio::async_read (*socket, boost::asio::buffer (receive_buffer.data () + 8, sizeof (rai::uint256_union) + sizeof (uint32_t) + sizeof (uint32_t)), [this_l](boost::system::error_code const & ec, size_t size_a) {
this_l->receive_frontier_req_action (ec, size_a);
@ -1531,6 +1536,7 @@ void rai::bootstrap_server::receive_header_action (boost::system::error_code con
}
case rai::message_type::bulk_push:
{
node->stats.inc (rai::stat::type::bootstrap, rai::stat::detail::bulk_push, rai::stat::dir::in);
add_request (std::unique_ptr<rai::message> (new rai::bulk_push));
break;
}
@ -2069,6 +2075,7 @@ void rai::bulk_push_server::received_type ()
{
case rai::block_type::send:
{
connection->node->stats.inc (rai::stat::type::bootstrap, rai::stat::detail::send, rai::stat::dir::in);
boost::asio::async_read (*connection->socket, boost::asio::buffer (receive_buffer.data () + 1, rai::send_block::size), [this_l](boost::system::error_code const & ec, size_t size_a) {
this_l->received_block (ec, size_a);
});
@ -2076,6 +2083,7 @@ void rai::bulk_push_server::received_type ()
}
case rai::block_type::receive:
{
connection->node->stats.inc (rai::stat::type::bootstrap, rai::stat::detail::receive, rai::stat::dir::in);
boost::asio::async_read (*connection->socket, boost::asio::buffer (receive_buffer.data () + 1, rai::receive_block::size), [this_l](boost::system::error_code const & ec, size_t size_a) {
this_l->received_block (ec, size_a);
});
@ -2083,6 +2091,7 @@ void rai::bulk_push_server::received_type ()
}
case rai::block_type::open:
{
connection->node->stats.inc (rai::stat::type::bootstrap, rai::stat::detail::open, rai::stat::dir::in);
boost::asio::async_read (*connection->socket, boost::asio::buffer (receive_buffer.data () + 1, rai::open_block::size), [this_l](boost::system::error_code const & ec, size_t size_a) {
this_l->received_block (ec, size_a);
});
@ -2090,6 +2099,7 @@ void rai::bulk_push_server::received_type ()
}
case rai::block_type::change:
{
connection->node->stats.inc (rai::stat::type::bootstrap, rai::stat::detail::change, rai::stat::dir::in);
boost::asio::async_read (*connection->socket, boost::asio::buffer (receive_buffer.data () + 1, rai::change_block::size), [this_l](boost::system::error_code const & ec, size_t size_a) {
this_l->received_block (ec, size_a);
});
@ -2097,6 +2107,7 @@ void rai::bulk_push_server::received_type ()
}
case rai::block_type::state:
{
connection->node->stats.inc (rai::stat::type::bootstrap, rai::stat::detail::state_block, rai::stat::dir::in);
boost::asio::async_read (*connection->socket, boost::asio::buffer (receive_buffer.data () + 1, rai::state_block::size), [this_l](boost::system::error_code const & ec, size_t size_a) {
this_l->received_block (ec, size_a);
});

View file

@ -32,22 +32,11 @@ int constexpr rai::port_mapping::mapping_timeout;
int constexpr rai::port_mapping::check_timeout;
unsigned constexpr rai::active_transactions::announce_interval_ms;
rai::message_statistics::message_statistics () :
keepalive (0),
publish (0),
confirm_req (0),
confirm_ack (0)
{
}
rai::network::network (rai::node & node_a, uint16_t port) :
socket (node_a.service, rai::endpoint (boost::asio::ip::address_v6::any (), port)),
resolver (node_a.service),
node (node_a),
bad_sender_count (0),
on (true),
insufficient_work_count (0),
error_count (0)
on (true)
{
}
@ -84,7 +73,6 @@ void rai::network::send_keepalive (rai::endpoint const & endpoint_a)
{
BOOST_LOG (node.log) << boost::str (boost::format ("Keepalive req sent to %1%") % endpoint_a);
}
++outgoing.keepalive;
std::weak_ptr<rai::node> node_w (node.shared ());
send_buffer (bytes->data (), bytes->size (), endpoint_a, [bytes, node_w, endpoint_a](boost::system::error_code const & ec, size_t) {
if (auto node_l = node_w.lock ())
@ -93,6 +81,10 @@ void rai::network::send_keepalive (rai::endpoint const & endpoint_a)
{
BOOST_LOG (node_l->log) << boost::str (boost::format ("Error sending keepalive to %1%: %2%") % endpoint_a % ec.message ());
}
else
{
node_l->stats.inc (rai::stat::type::message, rai::stat::detail::keepalive, rai::stat::dir::out);
}
}
});
}
@ -122,7 +114,6 @@ void rai::node::keepalive (std::string const & address_a, uint16_t port_a)
void rai::network::republish (rai::block_hash const & hash_a, std::shared_ptr<std::vector<uint8_t>> buffer_a, rai::endpoint endpoint_a)
{
++outgoing.publish;
if (node.config.logging.network_publish_logging ())
{
BOOST_LOG (node.log) << boost::str (boost::format ("Publishing %1% to %2%") % hash_a.to_string () % endpoint_a);
@ -135,6 +126,10 @@ void rai::network::republish (rai::block_hash const & hash_a, std::shared_ptr<st
{
BOOST_LOG (node_l->log) << boost::str (boost::format ("Error sending publish to %1%: %2%") % endpoint_a % ec.message ());
}
else
{
node_l->stats.inc (rai::stat::type::message, rai::stat::detail::publish, rai::stat::dir::out);
}
}
});
}
@ -270,7 +265,7 @@ void rai::network::send_confirm_req (rai::endpoint const & endpoint_a, std::shar
BOOST_LOG (node.log) << boost::str (boost::format ("Sending confirm req to %1%") % endpoint_a);
}
std::weak_ptr<rai::node> node_w (node.shared ());
++outgoing.confirm_req;
node.stats.inc (rai::stat::type::message, rai::stat::detail::confirm_req, rai::stat::dir::out);
send_buffer (bytes->data (), bytes->size (), endpoint_a, [bytes, node_w](boost::system::error_code const & ec, size_t size) {
if (auto node_l = node_w.lock ())
{
@ -328,7 +323,7 @@ public:
{
BOOST_LOG (node.log) << boost::str (boost::format ("Received keepalive message from %1%") % sender);
}
++node.network.incoming.keepalive;
node.stats.inc (rai::stat::type::message, rai::stat::detail::keepalive, rai::stat::dir::in);
node.peers.contacted (sender, message_a.version_using);
node.network.merge_peers (message_a.peers);
}
@ -338,7 +333,7 @@ public:
{
BOOST_LOG (node.log) << boost::str (boost::format ("Publish message from %1% for %2%") % sender % message_a.block->hash ().to_string ());
}
++node.network.incoming.publish;
node.stats.inc (rai::stat::type::message, rai::stat::detail::publish, rai::stat::dir::in);
node.peers.contacted (sender, message_a.version_using);
node.peers.insert (sender, message_a.version_using);
node.process_active (message_a.block);
@ -349,7 +344,7 @@ public:
{
BOOST_LOG (node.log) << boost::str (boost::format ("Confirm_req message from %1% for %2%") % sender % message_a.block->hash ().to_string ());
}
++node.network.incoming.confirm_req;
node.stats.inc (rai::stat::type::message, rai::stat::detail::confirm_req, rai::stat::dir::in);
node.peers.contacted (sender, message_a.version_using);
node.peers.insert (sender, message_a.version_using);
node.process_active (message_a.block);
@ -366,7 +361,7 @@ public:
{
BOOST_LOG (node.log) << boost::str (boost::format ("Received confirm_ack message from %1% for %2% sequence %3%") % sender % message_a.vote->block->hash ().to_string () % std::to_string (message_a.vote->sequence));
}
++node.network.incoming.confirm_ack;
node.stats.inc (rai::stat::type::message, rai::stat::detail::confirm_ack, rai::stat::dir::in);
node.peers.contacted (sender, message_a.version_using);
node.peers.insert (sender, message_a.version_using);
node.process_active (message_a.vote->block);
@ -420,7 +415,7 @@ void rai::network::receive_action (boost::system::error_code const & error, size
parser.deserialize_buffer (buffer.data (), size_a);
if (parser.status != rai::message_parser::parse_status::success)
{
++error_count;
node.stats.inc (rai::stat::type::error);
if (parser.status == rai::message_parser::parse_status::insufficient_work)
{
@ -429,7 +424,8 @@ void rai::network::receive_action (boost::system::error_code const & error, size
BOOST_LOG (node.log) << "Insufficient work in message";
}
++insufficient_work_count;
// We've already increment error count, update detail only
node.stats.inc_detail_only (rai::stat::type::error, rai::stat::detail::insufficient_work);
}
else if (parser.status == rai::message_parser::parse_status::invalid_message_type)
{
@ -478,6 +474,10 @@ void rai::network::receive_action (boost::system::error_code const & error, size
BOOST_LOG (node.log) << "Could not deserialize buffer";
}
}
else
{
node.stats.add (rai::stat::type::traffic, rai::stat::dir::in, size_a);
}
}
else
{
@ -485,7 +485,8 @@ void rai::network::receive_action (boost::system::error_code const & error, size
{
BOOST_LOG (node.log) << boost::str (boost::format ("Reserved sender %1%") % remote.address ().to_string ());
}
++bad_sender_count;
node.stats.inc_detail_only (rai::stat::type::error, rai::stat::detail::bad_sender);
}
receive ();
}
@ -1023,6 +1024,11 @@ bool rai::node_config::deserialize_json (bool & upgraded_a, boost::property_tree
{
result = true;
}
auto stat_config_l (tree_a.get_child_optional ("statistics"));
if (stat_config_l)
{
result |= stat_config.deserialize_json (stat_config_l.get ());
}
auto inactive_supply_l (tree_a.get<std::string> ("inactive_supply"));
auto password_fanout_l (tree_a.get<std::string> ("password_fanout"));
auto io_threads_l (tree_a.get<std::string> ("io_threads"));
@ -1109,12 +1115,15 @@ rai::vote_result rai::vote_processor::vote (std::shared_ptr<rai::vote> vote_a, r
{
case rai::vote_code::invalid:
status = "Invalid";
node.stats.inc (rai::stat::type::vote, rai::stat::detail::vote_invalid);
break;
case rai::vote_code::replay:
status = "Replay";
node.stats.inc (rai::stat::type::vote, rai::stat::detail::vote_replay);
break;
case rai::vote_code::vote:
status = "Vote";
node.stats.inc (rai::stat::type::vote, rai::stat::detail::vote_valid);
break;
}
BOOST_LOG (node.log) << boost::str (boost::format ("Vote from: %1% sequence: %2% block: %3% status: %4%") % vote_a->account.to_account () % std::to_string (vote_a->sequence) % vote_a->block->hash ().to_string () % status);
@ -1443,7 +1452,7 @@ alarm (alarm_a),
work (work_a),
store (init_a.block_store_init, application_path_a / "data.ldb", config_a.lmdb_max_dbs),
gap_cache (*this),
ledger (store, config_a.inactive_supply.number (), config.state_block_parse_canary, config.state_block_generate_canary),
ledger (store, stats, config_a.inactive_supply.number (), config.state_block_parse_canary, config.state_block_generate_canary),
active (*this),
network (*this, config.peering_port),
bootstrap_initiator (*this),
@ -1456,7 +1465,8 @@ vote_processor (*this),
warmed_up (0),
block_processor (*this),
block_processor_thread ([this]() { this->block_processor.process_blocks (); }),
online_reps (*this)
online_reps (*this),
stats (config.stat_config)
{
wallets.observer = [this](bool active) {
observers.wallet (active);
@ -1772,7 +1782,6 @@ void rai::network::confirm_send (rai::confirm_ack const & confirm_a, std::shared
BOOST_LOG (node.log) << boost::str (boost::format ("Sending confirm_ack for block %1% to %2% sequence %3%") % confirm_a.vote->block->hash ().to_string () % endpoint_a % std::to_string (confirm_a.vote->sequence));
}
std::weak_ptr<rai::node> node_w (node.shared ());
++outgoing.confirm_ack;
node.network.send_buffer (bytes_a->data (), bytes_a->size (), endpoint_a, [bytes_a, node_w, endpoint_a](boost::system::error_code const & ec, size_t size_a) {
if (auto node_l = node_w.lock ())
{
@ -1780,6 +1789,10 @@ void rai::network::confirm_send (rai::confirm_ack const & confirm_a, std::shared
{
BOOST_LOG (node_l->log) << boost::str (boost::format ("Error broadcasting confirm_ack to %1%: %2%") % endpoint_a % ec.message ());
}
else
{
node_l->stats.inc (rai::stat::type::message, rai::stat::detail::confirm_ack, rai::stat::dir::out);
}
}
});
}
@ -2953,6 +2966,7 @@ void rai::network::send_buffer (uint8_t const * data_a, size_t size_a, rai::endp
}
socket.async_send_to (boost::asio::buffer (data_a, size_a), endpoint_a, [this, callback_a](boost::system::error_code const & ec, size_t size_a) {
callback_a (ec, size_a);
this->node.stats.add (rai::stat::type::traffic, rai::stat::dir::out, size_a);
if (this->node.config.logging.network_packet_logging ())
{
BOOST_LOG (this->node.log) << "Packet send complete";

View file

@ -3,6 +3,7 @@
#include <rai/ledger.hpp>
#include <rai/lib/work.hpp>
#include <rai/node/bootstrap.hpp>
#include <rai/node/stats.hpp>
#include <rai/node/wallet.hpp>
#include <condition_variable>
@ -13,7 +14,6 @@
#include <unordered_set>
#include <boost/asio.hpp>
#include <boost/circular_buffer.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/log/trivial.hpp>
#include <boost/multi_index/hashed_index.hpp>
@ -281,15 +281,6 @@ public:
uint64_t check_count;
bool on;
};
class message_statistics
{
public:
message_statistics ();
std::atomic<uint64_t> keepalive;
std::atomic<uint64_t> publish;
std::atomic<uint64_t> confirm_req;
std::atomic<uint64_t> confirm_ack;
};
class block_arrival_info
{
public:
@ -363,12 +354,7 @@ public:
std::mutex socket_mutex;
boost::asio::ip::udp::resolver resolver;
rai::node & node;
uint64_t bad_sender_count;
bool on;
uint64_t insufficient_work_count;
uint64_t error_count;
rai::message_statistics incoming;
rai::message_statistics outgoing;
static uint16_t const node_port = rai::rai_network == rai::rai_networks::rai_live_network ? 7075 : 54000;
};
class logging
@ -449,6 +435,7 @@ public:
uint16_t callback_port;
std::string callback_target;
int lmdb_max_dbs;
rai::stat_config stat_config;
rai::block_hash state_block_parse_canary;
rai::block_hash state_block_generate_canary;
static std::chrono::seconds constexpr keepalive_period = std::chrono::seconds (60);
@ -575,6 +562,7 @@ public:
std::thread block_processor_thread;
rai::block_arrival block_arrival;
rai::online_reps online_reps;
rai::stat stats;
static double constexpr price_max = 16.0;
static double constexpr free_cutoff = 1024.0;
static std::chrono::seconds constexpr period = std::chrono::seconds (60);

View file

@ -3207,6 +3207,31 @@ void rai::rpc_handler::send ()
}
}
void rai::rpc_handler::stats ()
{
bool error = false;
auto sink = node.stats.log_sink_json ();
std::string type (request.get<std::string> ("type", ""));
if (type == "counters")
{
node.stats.log_counters (*sink);
}
else if (type == "samples")
{
node.stats.log_samples (*sink);
}
else
{
error = true;
error_response (response, "Invalid or missing type argument");
}
if (!error)
{
response (*static_cast<boost::property_tree::ptree *> (sink->to_object ()));
}
}
void rai::rpc_handler::stop ()
{
if (rpc.config.enable_control)
@ -4825,6 +4850,10 @@ void rai::rpc_handler::process_request ()
{
send ();
}
else if (action == "stats")
{
stats ();
}
else if (action == "stop")
{
stop ();

View file

@ -180,6 +180,7 @@ public:
void search_pending ();
void search_pending_all ();
void send ();
void stats ();
void stop ();
void successors ();
void unchecked ();

438
rai/node/stats.cpp Normal file
View file

@ -0,0 +1,438 @@
#include <boost/asio.hpp>
#include <boost/format.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <ctime>
#include <fstream>
#include <iostream>
#include <rai/node/stats.hpp>
#include <sstream>
#include <tuple>
bool rai::stat_config::deserialize_json (boost::property_tree::ptree & tree_a)
{
bool error = false;
auto sampling_l (tree_a.get_child_optional ("sampling"));
if (sampling_l)
{
sampling_enabled = sampling_l->get<bool> ("enabled", sampling_enabled);
capacity = sampling_l->get<size_t> ("capacity", capacity);
interval = sampling_l->get<size_t> ("interval", interval);
}
auto log_l (tree_a.get_child_optional ("log"));
if (log_l)
{
log_headers = log_l->get<bool> ("headers", log_headers);
log_interval_counters = log_l->get<size_t> ("interval_counters", log_interval_counters);
log_interval_samples = log_l->get<size_t> ("interval_samples", log_interval_samples);
log_rotation_count = log_l->get<size_t> ("rotation_count", log_rotation_count);
log_counters_filename = log_l->get<std::string> ("filename_counters", log_counters_filename);
log_samples_filename = log_l->get<std::string> ("filename_samples", log_samples_filename);
// Don't allow specifying the same file name for counter and samples logs
error = (log_counters_filename == log_samples_filename);
}
return error;
}
std::string rai::stat_log_sink::tm_to_string (tm & tm)
{
return (boost::format ("%04d.%02d.%02d %02d:%02d:%02d") % (1900 + tm.tm_year) % (tm.tm_mon + 1) % tm.tm_mday % tm.tm_hour % tm.tm_min % tm.tm_sec).str ();
}
/** JSON sink. The resulting JSON object is provided as both a property_tree::ptree (to_object) and a string (to_string) */
class json_writer : public rai::stat_log_sink
{
boost::property_tree::ptree tree;
boost::property_tree::ptree entries;
public:
std::ostream & out () override
{
return sstr;
}
void begin () override
{
tree.clear ();
}
void write_header (std::string header, std::chrono::system_clock::time_point & walltime) override
{
std::time_t now = std::chrono::system_clock::to_time_t (walltime);
tm tm = *localtime (&now);
tree.put ("type", header);
tree.put ("created", tm_to_string (tm));
}
void write_entry (tm & tm, std::string type, std::string detail, std::string dir, uint64_t value) override
{
boost::property_tree::ptree entry;
entry.put ("time", boost::format ("%02d:%02d:%02d") % tm.tm_hour % tm.tm_min % tm.tm_sec);
entry.put ("type", type);
entry.put ("detail", detail);
entry.put ("dir", dir);
entry.put ("value", value);
entries.push_back (std::make_pair ("", entry));
}
void finalize () override
{
tree.add_child ("entries", entries);
}
void * to_object () override
{
return &tree;
}
std::string to_string () override
{
boost::property_tree::write_json (sstr, tree);
return sstr.str ();
}
private:
std::ostringstream sstr;
};
/** File sink with rotation support */
class file_writer : public rai::stat_log_sink
{
public:
std::ofstream log;
std::string filename;
file_writer (std::string filename) :
filename (filename)
{
log.open (filename.c_str (), std::ofstream::out);
}
virtual ~file_writer ()
{
log.close ();
}
std::ostream & out () override
{
return log;
}
void write_header (std::string header, std::chrono::system_clock::time_point & walltime) override
{
std::time_t now = std::chrono::system_clock::to_time_t (walltime);
tm tm = *localtime (&now);
log << header << "," << boost::format ("%04d.%02d.%02d %02d:%02d:%02d") % (1900 + tm.tm_year) % (tm.tm_mon + 1) % tm.tm_mday % tm.tm_hour % tm.tm_min % tm.tm_sec << std::endl;
}
void write_entry (tm & tm, std::string type, std::string detail, std::string dir, uint64_t value) override
{
log << boost::format ("%02d:%02d:%02d") % tm.tm_hour % tm.tm_min % tm.tm_sec << "," << type << "," << detail << "," << dir << "," << value << std::endl;
}
void rotate () override
{
log.close ();
log.open (filename.c_str (), std::ofstream::out);
log_entries = 0;
}
};
rai::stat::stat (rai::stat_config config) :
config (config)
{
}
std::shared_ptr<rai::stat_entry> rai::stat::get_entry (uint32_t key)
{
return get_entry (key, config.interval, config.capacity);
}
std::shared_ptr<rai::stat_entry> rai::stat::get_entry (uint32_t key, size_t interval, size_t capacity)
{
std::unique_lock<std::mutex> lock (stat_mutex);
return get_entry_impl (key, interval, capacity);
}
std::shared_ptr<rai::stat_entry> rai::stat::get_entry_impl (uint32_t key, size_t interval, size_t capacity)
{
std::shared_ptr<rai::stat_entry> res;
auto entry = entries.find (key);
if (entry == entries.end ())
{
res = entries.insert (std::make_pair (key, std::make_shared<rai::stat_entry> (capacity, interval))).first->second;
}
else
{
res = entry->second;
}
return res;
}
std::unique_ptr<rai::stat_log_sink> rai::stat::log_sink_json ()
{
return std::make_unique<json_writer> ();
}
std::unique_ptr<rai::stat_log_sink> log_sink_file (std::string filename)
{
return std::make_unique<file_writer> (filename);
}
void rai::stat::log_counters (stat_log_sink & sink)
{
std::unique_lock<std::mutex> lock (stat_mutex);
log_counters_impl (sink);
}
void rai::stat::log_counters_impl (stat_log_sink & sink)
{
sink.begin ();
if (sink.entries () >= config.log_rotation_count)
{
sink.rotate ();
}
if (config.log_headers)
{
auto walltime (std::chrono::system_clock::now ());
sink.write_header ("counters", walltime);
}
for (auto & it : entries)
{
std::time_t time = std::chrono::system_clock::to_time_t (it.second->counter.timestamp);
tm local_tm = *localtime (&time);
auto key = it.first;
std::string type = type_to_string (key);
std::string detail = detail_to_string (key);
std::string dir = dir_to_string (key);
sink.write_entry (local_tm, type, detail, dir, it.second->counter.value);
}
sink.entries ()++;
sink.finalize ();
}
void rai::stat::log_samples (stat_log_sink & sink)
{
std::unique_lock<std::mutex> lock (stat_mutex);
log_samples_impl (sink);
}
void rai::stat::log_samples_impl (stat_log_sink & sink)
{
sink.begin ();
if (sink.entries () >= config.log_rotation_count)
{
sink.rotate ();
}
if (config.log_headers)
{
auto walltime (std::chrono::system_clock::now ());
sink.write_header ("samples", walltime);
}
for (auto & it : entries)
{
auto key = it.first;
std::string type = type_to_string (key);
std::string detail = detail_to_string (key);
std::string dir = dir_to_string (key);
for (auto & datapoint : it.second->samples)
{
std::time_t time = std::chrono::system_clock::to_time_t (datapoint.timestamp);
tm local_tm = *localtime (&time);
sink.write_entry (local_tm, type, detail, dir, datapoint.value);
}
}
sink.entries ()++;
sink.finalize ();
}
void rai::stat::update (uint32_t key_a, uint64_t value)
{
static file_writer log_count (config.log_counters_filename);
static file_writer log_sample (config.log_samples_filename);
auto now (std::chrono::steady_clock::now ());
std::unique_lock<std::mutex> lock (stat_mutex);
auto entry (get_entry_impl (key_a, config.interval, config.capacity));
// Counters
auto old (entry->counter.value);
entry->counter.add (value);
entry->count_observers (old, entry->counter.value);
std::chrono::duration<double, std::milli> duration = now - log_last_count_writeout;
if (config.log_interval_counters > 0 && duration.count () > config.log_interval_counters)
{
log_counters_impl (log_count);
log_last_count_writeout = now;
}
// Samples
if (config.sampling_enabled && entry->sample_interval > 0)
{
entry->sample_current.add (value, false);
std::chrono::duration<double, std::milli> duration = now - entry->sample_start_time;
if (duration.count () > entry->sample_interval)
{
entry->sample_start_time = now;
// Make a snapshot of samples for thread safety and to get a stable container
entry->sample_current.timestamp = std::chrono::system_clock::now ();
entry->samples.push_back (entry->sample_current);
entry->sample_current.value = 0;
if (entry->sample_observers.observers.size () > 0)
{
auto snapshot (entry->samples);
entry->sample_observers (snapshot);
}
// Log sink
duration = now - log_last_sample_writeout;
if (config.log_interval_samples > 0 && duration.count () > config.log_interval_samples)
{
log_samples_impl (log_sample);
log_last_sample_writeout = now;
}
}
}
}
std::string rai::stat::type_to_string (uint32_t key)
{
auto type = static_cast<stat::type> (key >> 16 & 0x000000ff);
std::string res;
switch (type)
{
case rai::stat::type::block:
res = "block";
break;
case rai::stat::type::bootstrap:
res = "bootstrap";
break;
case rai::stat::type::error:
res = "error";
break;
case rai::stat::type::ledger:
res = "ledger";
break;
case rai::stat::type::peering:
res = "peering";
break;
case rai::stat::type::rollback:
res = "rollback";
break;
case rai::stat::type::traffic:
res = "traffic";
break;
case rai::stat::type::vote:
res = "vote";
break;
case rai::stat::type::message:
res = "message";
break;
}
return res;
}
std::string rai::stat::detail_to_string (uint32_t key)
{
auto detail = static_cast<stat::detail> (key >> 8 & 0x000000ff);
std::string res;
switch (detail)
{
case rai::stat::detail::all:
res = "all";
break;
case rai::stat::detail::bad_sender:
res = "bad_sender";
break;
case rai::stat::detail::bulk_pull:
res = "bulk_pull";
break;
case rai::stat::detail::bulk_pull_blocks:
res = "bulk_pull_blocks";
break;
case rai::stat::detail::bulk_push:
res = "bulk_push";
break;
case rai::stat::detail::change:
res = "change";
break;
case rai::stat::detail::confirm_ack:
res = "confirm_ack";
break;
case rai::stat::detail::confirm_req:
res = "confirm_req";
break;
case rai::stat::detail::frontier_req:
res = "frontier_req";
break;
case rai::stat::detail::handshake:
res = "handshake";
break;
case rai::stat::detail::initiate:
res = "initiate";
break;
case rai::stat::detail::insufficient_work:
res = "insufficient_work";
break;
case rai::stat::detail::keepalive:
res = "keepalive";
break;
case rai::stat::detail::open:
res = "open";
break;
case rai::stat::detail::publish:
res = "publish";
break;
case rai::stat::detail::receive:
res = "receive";
break;
case rai::stat::detail::republish_vote:
res = "republish_vote";
break;
case rai::stat::detail::send:
res = "send";
break;
case rai::stat::detail::state_block:
res = "state_block";
break;
case rai::stat::detail::vote_valid:
res = "vote_valid";
break;
case rai::stat::detail::vote_replay:
res = "vote_replay";
break;
case rai::stat::detail::vote_invalid:
res = "vote_invalid";
break;
}
return res;
}
std::string rai::stat::dir_to_string (uint32_t key)
{
auto dir = static_cast<stat::dir> (key & 0x000000ff);
std::string res;
switch (dir)
{
case rai::stat::dir::in:
res = "in";
break;
case rai::stat::dir::out:
res = "out";
break;
}
return res;
}

413
rai/node/stats.hpp Normal file
View file

@ -0,0 +1,413 @@
#pragma once
#include <atomic>
#include <boost/circular_buffer.hpp>
#include <boost/property_tree/ptree.hpp>
#include <chrono>
#include <map>
#include <memory>
#include <mutex>
#include <rai/lib/utility.hpp>
#include <string>
#include <unordered_map>
namespace rai
{
class node;
/**
* Serialize and deserialize the 'statistics' node from config.json
* All configuration values have defaults. In particular, file logging of statistics
* is disabled by default.
*/
class stat_config
{
public:
/** Reads the JSON statistics node */
bool deserialize_json (boost::property_tree::ptree & tree_a);
/** If true, sampling of counters is enabled */
bool sampling_enabled{ false };
/** How many sample intervals to keep in the ring buffer */
size_t capacity{ 0 };
/** Sample interval in milliseconds */
size_t interval{ 0 };
/** How often to log sample array, in milliseconds. Default is 0 (no logging) */
size_t log_interval_samples{ 0 };
/** How often to log counters, in milliseconds. Default is 0 (no logging) */
size_t log_interval_counters{ 0 };
/** Maximum number of log outputs before rotating the file */
size_t log_rotation_count{ 100 };
/** If true, write headers on each counter or samples writeout. The header contains log type and the current wall time. */
bool log_headers{ true };
/** Filename for the counter log */
std::string log_counters_filename{ "counters.stat" };
/** Filename for the sampling log */
std::string log_samples_filename{ "samples.stat" };
};
/** Value and wall time of measurement */
class stat_datapoint
{
public:
/** Value of the sample interval */
uint64_t value{ 0 };
/** When the sample was added. This is wall time (system_clock), suitable for display purposes. */
std::chrono::system_clock::time_point timestamp{ std::chrono::system_clock::now () };
/** Add \addend to the current value and optionally update the timestamp */
inline void add (uint64_t addend, bool update_timestamp = true)
{
value += addend;
if (update_timestamp)
{
timestamp = std::chrono::system_clock::now ();
}
}
};
/** Bookkeeping of statistics for a specific type/detail/direction combination */
class stat_entry
{
public:
stat_entry (size_t capacity, size_t interval) :
samples (capacity), sample_interval (interval)
{
}
/** Optional samples. Note that this doesn't allocate any memory unless sampling is configured, which sets the capacity. */
boost::circular_buffer<stat_datapoint> samples;
/** Start time of current sample interval. This is a steady clock for measuring interval; the datapoint contains the wall time. */
std::chrono::steady_clock::time_point sample_start_time{ std::chrono::steady_clock::now () };
/** Sample interval in milliseconds. If 0, sampling is disabled. */
size_t sample_interval;
/** Value within the current sample interval */
stat_datapoint sample_current;
/** Counting value for this entry, including the time of last update. This is never reset and only increases. */
stat_datapoint counter;
/** Zero or more observers for samples. Called at the end of the sample interval. */
rai::observer_set<boost::circular_buffer<stat_datapoint> &> sample_observers;
/** Observers for count. Called on each update. */
rai::observer_set<uint64_t, uint64_t> count_observers;
};
/** Log sink interface */
class stat_log_sink
{
public:
virtual ~stat_log_sink () = default;
/** Returns a reference to the log output stream */
virtual std::ostream & out () = 0;
/** Called before logging starts */
virtual void begin ()
{
}
/** Called after logging is completed */
virtual void finalize ()
{
}
/** Write a header enrty to the log */
virtual void write_header (std::string header, std::chrono::system_clock::time_point & walltime)
{
}
/** Write a counter or sampling entry to the log */
virtual void write_entry (tm & tm, std::string type, std::string detail, std::string dir, uint64_t value)
{
}
/** Rotates the log (e.g. empty file). This is a no-op for sinks where rotation is not supported. */
virtual void rotate ()
{
}
/** Returns a reference to the log entry counter */
inline size_t & entries ()
{
return log_entries;
}
/** Returns the string representation of the log. If not supported, an empty string is returned. */
virtual std::string to_string ()
{
return "";
}
/**
* Returns the object representation of the log result. The type depends on the sink used.
* @returns Object, or nullptr if no object result is available.
*/
virtual void * to_object ()
{
return nullptr;
}
protected:
std::string tm_to_string (tm & tm);
size_t log_entries{ 0 };
};
/**
* Collects counts and samples for inbound and outbound traffic, blocks, errors, and so on.
* Stats can be queried and observed on a type level (such as message and ledger) as well as a more
* specific detail level (such as send blocks)
*/
class stat
{
public:
/** Primary statistics type */
enum class type : uint8_t
{
traffic,
error,
message,
block,
ledger,
rollback,
bootstrap,
vote,
peering
};
/** Optional detail type */
enum class detail : uint8_t
{
all = 0,
// error specific
bad_sender,
insufficient_work,
// ledger, block, bootstrap
send,
receive,
open,
change,
state_block,
// message specific
keepalive,
publish,
republish_vote,
confirm_req,
confirm_ack,
// bootstrap specific
initiate,
bulk_pull,
bulk_push,
bulk_pull_blocks,
frontier_req,
// vote specific
vote_valid,
vote_replay,
vote_invalid,
// peering
handshake,
};
/** Direction of the stat. If the direction is irrelevant, use in */
enum class dir : uint8_t
{
in,
out
};
/** Constructor using the default config values */
stat ()
{
}
/**
* Initialize stats with a config.
* @param config Configuration object; deserialized from config.json
*/
stat (rai::stat_config config);
/**
* Call this to override the default sample interval and capacity, for a specific stat entry.
* This must be called before any stat entries are added, as part of the node initialiation.
*/
inline void configure (stat::type type, stat::detail detail, stat::dir dir, size_t interval, size_t capacity)
{
get_entry (key_of (type, detail, dir), interval, capacity);
}
/**
* Disables sampling for a given type/detail/dir combination
*/
inline void disable_sampling (stat::type type, stat::detail detail, stat::dir dir)
{
auto entry = get_entry (key_of (type, detail, dir));
entry->sample_interval = 0;
}
/** Increments the given counter */
inline void inc (stat::type type, stat::dir dir = stat::dir::in)
{
add (type, dir, 1);
}
/** Increments the counter for \detail, but doesn't update at the type level */
inline void inc_detail_only (stat::type type, stat::detail detail, stat::dir dir = stat::dir::in)
{
add (type, detail, dir, 1);
}
/** Increments the given counter */
inline void inc (stat::type type, stat::detail detail, stat::dir dir = stat::dir::in)
{
add (type, detail, dir, 1);
}
/** Adds \p value to the given counter */
inline void add (stat::type type, stat::dir dir, uint64_t value)
{
add (type, detail::all, dir, value);
}
/**
* Add \p value to stat. If sampling is configured, this will update the current sample and
* call any sample observers if the interval is over.
*
* @param type Main statistics type
* @param detail Detail type, or detail::none to register on type-level only
* @param dir Direction
* @param value The amount to add
* @param detail_only If true, only update the detail-level counter
*/
inline void add (stat::type type, stat::detail detail, stat::dir dir, uint64_t value, bool detail_only = false)
{
constexpr uint32_t no_detail_mask = 0xffff00ff;
uint32_t key = key_of (type, detail, dir);
update (key, value);
// Optionally update at type-level as well
if (!detail_only && (key & no_detail_mask) != key)
{
update (key & no_detail_mask, value);
}
}
/**
* Add a sampling observer for a given counter.
* The observer receives a snapshot of the current sampling. Accessing the sample buffer is thus thread safe.
* To avoid recursion, the observer callback must only use the received data point snapshop, not query the stat object.
* @param observer The observer receives a snapshot of the current samples.
*/
inline void observe_sample (stat::type type, stat::detail detail, stat::dir dir, std::function<void(boost::circular_buffer<stat_datapoint> &)> observer)
{
get_entry (key_of (type, detail, dir))->sample_observers.add (observer);
}
inline void observe_sample (stat::type type, stat::dir dir, std::function<void(boost::circular_buffer<stat_datapoint> &)> observer)
{
observe_sample (type, stat::detail::all, dir, observer);
}
/**
* Add count observer for a given type, detail and direction combination. The observer receives old and new value.
* To avoid recursion, the observer callback must only use the received counts, not query the stat object.
* @param observer The observer receives the old and the new count.
*/
inline void observe_count (stat::type type, stat::detail detail, stat::dir dir, std::function<void(uint64_t, uint64_t)> observer)
{
get_entry (key_of (type, detail, dir))->count_observers.add (observer);
}
/** Returns a potentially empty list of the last N samples, where N is determined by the 'capacity' configuration */
inline boost::circular_buffer<stat_datapoint> * samples (stat::type type, stat::detail detail, stat::dir dir)
{
return &get_entry (key_of (type, detail, dir))->samples;
}
/** Returns current value for the given counter at the type level */
inline uint64_t count (stat::type type, stat::dir dir = stat::dir::in)
{
return count (type, stat::detail::all, dir);
}
/** Returns current value for the given counter at the detail level */
inline uint64_t count (stat::type type, stat::detail detail, stat::dir dir = stat::dir::in)
{
return get_entry (key_of (type, detail, dir))->counter.value;
}
/** Log counters to the given log link */
void log_counters (stat_log_sink & sink);
/** Log samples to the given log sink */
void log_samples (stat_log_sink & sink);
/** Returns a new JSON log sink */
std::unique_ptr<stat_log_sink> log_sink_json ();
/** Returns a new file log sink */
std::unique_ptr<stat_log_sink> log_sink_file (std::string filename);
private:
static std::string type_to_string (uint32_t key);
static std::string detail_to_string (uint32_t key);
static std::string dir_to_string (uint32_t key);
/** Constructs a key given type, detail and direction. This is used as input to update(...) and get_entry(...) */
inline uint32_t key_of (stat::type type, stat::detail detail, stat::dir dir) const
{
return static_cast<uint8_t> (type) << 16 | static_cast<uint8_t> (detail) << 8 | static_cast<uint8_t> (dir);
}
/** Get entry for key, creating a new entry if necessary, using interval and sample count from config */
std::shared_ptr<rai::stat_entry> get_entry (uint32_t key);
/** Get entry for key, creating a new entry if necessary */
std::shared_ptr<rai::stat_entry> get_entry (uint32_t key, size_t sample_interval, size_t max_samples);
/** Unlocked implementation of get_entry() */
std::shared_ptr<rai::stat_entry> get_entry_impl (uint32_t key, size_t sample_interval, size_t max_samples);
/**
* Update count and sample and call any observers on the key
* @param key a key constructor from stat::type, stat::detail and stat::direction
* @value Amount to add to the counter
*/
void update (uint32_t key, uint64_t value);
/** Unlocked implementation of log_counters() to avoid using recursive locking */
void log_counters_impl (stat_log_sink & sink);
/** Unlocked implementation of log_samples() to avoid using recursive locking */
void log_samples_impl (stat_log_sink & sink);
/** Configuration deserialized from config.json */
rai::stat_config config;
/** Stat entries are sorted by key to simplify processing of log output */
std::map<uint32_t, std::shared_ptr<rai::stat_entry>> entries;
std::chrono::steady_clock::time_point log_last_count_writeout{ std::chrono::steady_clock::now () };
std::chrono::steady_clock::time_point log_last_sample_writeout{ std::chrono::steady_clock::now () };
/** All access to stat is thread safe, including calls from observers on the same thread */
std::mutex stat_mutex;
};
}

View file

@ -471,7 +471,7 @@ TEST (history, short_text)
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::genesis genesis;
rai::ledger ledger (store);
rai::ledger ledger (store, system.nodes[0]->stats);
{
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);

View file

@ -109,7 +109,8 @@ TEST (ledger, deep_account_compute)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_FALSE (init);
rai::ledger ledger (store);
rai::stat stats;
rai::ledger ledger (store, stats);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);