diff --git a/nano/core_test/rpc.cpp b/nano/core_test/rpc.cpp index 7a90ac5322..0d6ca54d26 100644 --- a/nano/core_test/rpc.cpp +++ b/nano/core_test/rpc.cpp @@ -44,7 +44,7 @@ class test_response boost::property_tree::read_json (body, json); status = 200; } - catch (std::exception & e) + catch (std::exception &) { status = 500; } @@ -4243,7 +4243,7 @@ TEST (rpc, wallet_history) system.deadline_set (5s); while (response.status == 0) { - system.poll (); + ASSERT_NO_ERROR (system.poll ()); } ASSERT_EQ (200, response.status); std::vector> history_l; @@ -4345,3 +4345,31 @@ TEST (rpc, sign_block) ASSERT_NE (block->block_signature (), send.block_signature ()); ASSERT_EQ (block->hash (), send.hash ()); } + +TEST (rpc, memory_stats) +{ + nano::system system (24000, 1); + auto node = system.nodes.front (); + nano::rpc rpc (system.io_ctx, *node, nano::rpc_config (true)); + + // Preliminary test adding to the vote uniquer and checking json output is correct + nano::keypair key; + auto block (std::make_shared (0, 0, 0, 0, 0, key.prv, key.pub, 0)); + std::vector hashes; + hashes.push_back (block->hash ()); + auto vote (std::make_shared (key.pub, key.prv, 0, hashes)); + node->vote_uniquer.unique (vote); + rpc.start (); + boost::property_tree::ptree request; + request.put ("action", "stats"); + request.put ("type", "objects"); + test_response response (request, rpc, system.io_ctx); + system.deadline_set (5s); + while (response.status == 0) + { + ASSERT_NO_ERROR (system.poll ()); + } + ASSERT_EQ (200, response.status); + + ASSERT_EQ (response.json.get_child ("node").get_child ("vote_uniquer").get_child ("votes").get ("count"), "1"); +} diff --git a/nano/lib/blocks.cpp b/nano/lib/blocks.cpp index 2095f62f8d..468b0685d1 100644 --- a/nano/lib/blocks.cpp +++ b/nano/lib/blocks.cpp @@ -1607,3 +1607,15 @@ size_t nano::block_uniquer::size () std::lock_guard lock (mutex); return blocks.size (); } + +namespace nano +{ +std::unique_ptr collect_seq_con_info (block_uniquer & block_uniquer, const std::string & name) +{ + auto count = block_uniquer.size (); + auto sizeof_element = sizeof (block_uniquer::value_type); + auto composite = std::make_unique (name); + composite->add_component (std::make_unique (seq_con_info{ "blocks", count, sizeof_element })); + return composite; +} +} diff --git a/nano/lib/blocks.hpp b/nano/lib/blocks.hpp index 03e9073484..94b4c7389c 100644 --- a/nano/lib/blocks.hpp +++ b/nano/lib/blocks.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -322,14 +323,19 @@ class block_visitor class block_uniquer { public: + using value_type = std::pair>; + std::shared_ptr unique (std::shared_ptr); size_t size (); private: std::mutex mutex; - std::unordered_map> blocks; + std::unordered_map, value_type::second_type> blocks; static unsigned constexpr cleanup_count = 2; }; + +std::unique_ptr collect_seq_con_info (block_uniquer & block_uniquer, const std::string & name); + std::shared_ptr deserialize_block (nano::stream &, nano::block_uniquer * = nullptr); std::shared_ptr deserialize_block (nano::stream &, nano::block_type, nano::block_uniquer * = nullptr); std::shared_ptr deserialize_block_json (boost::property_tree::ptree const &, nano::block_uniquer * = nullptr); diff --git a/nano/lib/utility.cpp b/nano/lib/utility.cpp index 69c5d63046..0b1b036fd3 100644 --- a/nano/lib/utility.cpp +++ b/nano/lib/utility.cpp @@ -3,6 +3,44 @@ namespace nano { +seq_con_info_composite::seq_con_info_composite (const std::string & name) : +name (name) +{ +} + +bool seq_con_info_composite::is_composite () const +{ + return true; +} + +void seq_con_info_composite::add_component (std::unique_ptr child) +{ + children.push_back (std::move (child)); +} + +const std::vector> & seq_con_info_composite::get_children () const +{ + return children; +} + +const std::string & seq_con_info_composite::get_name () const +{ + return name; +} + +seq_con_info_leaf::seq_con_info_leaf (const seq_con_info & info) : +info (info) +{ +} +bool seq_con_info_leaf::is_composite () const +{ + return false; +} +const seq_con_info & seq_con_info_leaf::get_info () const +{ + return info; +} + namespace thread_role { /* diff --git a/nano/lib/utility.hpp b/nano/lib/utility.hpp index f3ade70e8f..4e57486164 100644 --- a/nano/lib/utility.hpp +++ b/nano/lib/utility.hpp @@ -11,6 +11,49 @@ namespace nano { +/* These containers are used to collect information about sequence containers. + * It makes use of the composite design pattern to collect information + * from sequence containers and sequence containers inside member variables. + */ +struct seq_con_info +{ + std::string name; + size_t count; + size_t sizeof_element; +}; + +class seq_con_info_component +{ +public: + virtual ~seq_con_info_component () = default; + virtual bool is_composite () const = 0; +}; + +class seq_con_info_composite : public seq_con_info_component +{ +public: + seq_con_info_composite (const std::string & name); + bool is_composite () const override; + void add_component (std::unique_ptr child); + const std::vector> & get_children () const; + const std::string & get_name () const; + +private: + std::string name; + std::vector> children; +}; + +class seq_con_info_leaf : public seq_con_info_component +{ +public: + seq_con_info_leaf (const seq_con_info & info); + bool is_composite () const override; + const seq_con_info & get_info () const; + +private: + seq_con_info info; +}; + // Lower priority of calling work generating thread void work_thread_reprioritize (); @@ -86,6 +129,21 @@ class observer_set std::mutex mutex; std::vector> observers; }; + +template +inline std::unique_ptr collect_seq_con_info (observer_set & observer_set, const std::string & name) +{ + size_t count = 0; + { + std::lock_guard lock (observer_set.mutex); + count = observer_set.observers.size (); + } + + auto sizeof_element = sizeof (typename decltype (observer_set.observers)::value_type); + auto composite = std::make_unique (name); + composite->add_component (std::make_unique (seq_con_info{ "observers", count, sizeof_element })); + return composite; +} } void release_assert_internal (bool check, const char * check_expr, const char * file, unsigned int line); diff --git a/nano/lib/work.cpp b/nano/lib/work.cpp index 54aafe6280..b310498001 100644 --- a/nano/lib/work.cpp +++ b/nano/lib/work.cpp @@ -193,3 +193,21 @@ uint64_t nano::work_pool::generate (nano::uint256_union const & hash_a, uint64_t auto result (work.get_future ().get ()); return result.value (); } + +namespace nano +{ +std::unique_ptr collect_seq_con_info (work_pool & work_pool, const std::string & name) +{ + auto composite = std::make_unique (name); + + size_t count = 0; + { + std::lock_guard (work_pool.mutex); + count = work_pool.pending.size (); + } + auto sizeof_element = sizeof (decltype (work_pool.pending)::value_type); + composite->add_component (std::make_unique (seq_con_info{ "pending", count, sizeof_element })); + composite->add_component (collect_seq_con_info (work_pool.work_observers, "work_observers")); + return composite; +} +} diff --git a/nano/lib/work.hpp b/nano/lib/work.hpp index f6155ebc24..90f28b2486 100644 --- a/nano/lib/work.hpp +++ b/nano/lib/work.hpp @@ -48,4 +48,6 @@ class work_pool static uint64_t const publish_full_threshold = 0xffffffc000000000; static uint64_t const publish_threshold = nano::nano_network == nano::nano_networks::nano_test_network ? publish_test_threshold : publish_full_threshold; }; + +std::unique_ptr collect_seq_con_info (work_pool & work_pool, const std::string & name); } diff --git a/nano/node/bootstrap.cpp b/nano/node/bootstrap.cpp index d572329489..a1ad300918 100644 --- a/nano/node/bootstrap.cpp +++ b/nano/node/bootstrap.cpp @@ -1903,6 +1903,23 @@ void nano::bootstrap_initiator::notify_listeners (bool in_progress_a) } } +namespace nano +{ +std::unique_ptr collect_seq_con_info (bootstrap_initiator & bootstrap_initiator, const std::string & name) +{ + size_t count = 0; + { + std::lock_guard guard (bootstrap_initiator.mutex); + count = bootstrap_initiator.observers.size (); + } + + auto sizeof_element = sizeof (decltype (bootstrap_initiator.observers)::value_type); + auto composite = std::make_unique (name); + composite->add_component (std::make_unique (seq_con_info{ "observers", count, sizeof_element })); + return composite; +} +} + nano::bootstrap_listener::bootstrap_listener (boost::asio::io_context & io_ctx_a, uint16_t port_a, nano::node & node_a) : acceptor (io_ctx_a), defer_acceptor (io_ctx_a), @@ -2005,6 +2022,23 @@ boost::asio::ip::tcp::endpoint nano::bootstrap_listener::endpoint () return boost::asio::ip::tcp::endpoint (boost::asio::ip::address_v6::loopback (), local.port ()); } +namespace nano +{ +std::unique_ptr collect_seq_con_info (bootstrap_listener & bootstrap_listener, const std::string & name) +{ + size_t count = 0; + { + std::lock_guard guard (bootstrap_listener.mutex); + count = bootstrap_listener.connections.size (); + } + + auto sizeof_element = sizeof (decltype (bootstrap_listener.connections)::value_type); + auto composite = std::make_unique (name); + composite->add_component (std::make_unique (seq_con_info{ "connections", count, sizeof_element })); + return composite; +} +} + nano::bootstrap_server::~bootstrap_server () { if (node->config.logging.bulk_pull_logging ()) diff --git a/nano/node/bootstrap.hpp b/nano/node/bootstrap.hpp index 1051e44430..927fda4740 100644 --- a/nano/node/bootstrap.hpp +++ b/nano/node/bootstrap.hpp @@ -243,7 +243,12 @@ class bootstrap_initiator std::condition_variable condition; std::vector> observers; boost::thread thread; + + friend std::unique_ptr collect_seq_con_info (bootstrap_initiator & bootstrap_initiator, const std::string & name); }; + +std::unique_ptr collect_seq_con_info (bootstrap_initiator & bootstrap_initiator, const std::string & name); + class bootstrap_server; class bootstrap_listener { @@ -265,6 +270,9 @@ class bootstrap_listener private: boost::asio::steady_timer defer_acceptor; }; + +std::unique_ptr collect_seq_con_info (bootstrap_listener & bootstrap_listener, const std::string & name); + class message; class bootstrap_server : public std::enable_shared_from_this { diff --git a/nano/node/node.cpp b/nano/node/node.cpp index a24f2d3e4f..fe600ec912 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -1279,6 +1279,44 @@ void nano::vote_processor::calculate_weights () } } +namespace nano +{ +std::unique_ptr collect_seq_con_info (node_observers & node_observers, const std::string & name) +{ + auto composite = std::make_unique (name); + composite->add_component (collect_seq_con_info (node_observers.blocks, "blocks")); + composite->add_component (collect_seq_con_info (node_observers.wallet, "wallet")); + composite->add_component (collect_seq_con_info (node_observers.vote, "vote")); + composite->add_component (collect_seq_con_info (node_observers.account_balance, "account_balance")); + composite->add_component (collect_seq_con_info (node_observers.endpoint, "endpoint")); + composite->add_component (collect_seq_con_info (node_observers.disconnect, "disconnect")); + return composite; +} + +std::unique_ptr collect_seq_con_info (vote_processor & vote_processor, const std::string & name) +{ + size_t votes_count = 0; + size_t representatives_1_count = 0; + size_t representatives_2_count = 0; + size_t representatives_3_count = 0; + + { + std::lock_guard (vote_processor.mutex); + votes_count = vote_processor.votes.size (); + representatives_1_count = vote_processor.representatives_1.size (); + representatives_2_count = vote_processor.representatives_2.size (); + representatives_3_count = vote_processor.representatives_3.size (); + } + + auto composite = std::make_unique (name); + composite->add_component (std::make_unique (seq_con_info{ "votes", votes_count, sizeof (decltype (vote_processor.votes)::value_type) })); + composite->add_component (std::make_unique (seq_con_info{ "representatives_1", representatives_1_count, sizeof (decltype (vote_processor.representatives_1)::value_type) })); + composite->add_component (std::make_unique (seq_con_info{ "representatives_2", representatives_2_count, sizeof (decltype (vote_processor.representatives_2)::value_type) })); + composite->add_component (std::make_unique (seq_con_info{ "representatives_3", representatives_3_count, sizeof (decltype (vote_processor.representatives_3)::value_type) })); + return composite; +} +} + void nano::rep_crawler::add (nano::block_hash const & hash_a) { std::lock_guard lock (mutex); @@ -1297,6 +1335,22 @@ bool nano::rep_crawler::exists (nano::block_hash const & hash_a) return active.count (hash_a) != 0; } +namespace nano +{ +std::unique_ptr collect_seq_con_info (rep_crawler & rep_crawler, const std::string & name) +{ + size_t count = 0; + { + std::lock_guard guard (rep_crawler.mutex); + count = rep_crawler.active.size (); + } + + auto sizeof_element = sizeof (decltype (rep_crawler.active)::value_type); + auto composite = std::make_unique (name); + composite->add_component (std::make_unique (seq_con_info{ "active", count, sizeof_element })); + return composite; +} +} nano::signature_checker::signature_checker (unsigned num_threads) : thread_pool (num_threads), single_threaded (num_threads == 0), @@ -1952,6 +2006,36 @@ void nano::block_processor::queue_unchecked (nano::transaction const & transacti node.gap_cache.blocks.get<1> ().erase (hash_a); } +namespace nano +{ +std::unique_ptr collect_seq_con_info (block_processor & block_processor, const std::string & name) +{ + size_t state_blocks_count = 0; + size_t blocks_count = 0; + size_t blocks_hashes_count = 0; + size_t forced_count = 0; + size_t rolled_back_count = 0; + + { + std::lock_guard guard (block_processor.mutex); + state_blocks_count = block_processor.state_blocks.size (); + blocks_count = block_processor.blocks.size (); + blocks_hashes_count = block_processor.blocks_hashes.size (); + forced_count = block_processor.forced.size (); + rolled_back_count = block_processor.rolled_back.size (); + } + + auto composite = std::make_unique (name); + composite->add_component (std::make_unique (seq_con_info{ "state_blocks", state_blocks_count, sizeof (decltype (block_processor.state_blocks)::value_type) })); + composite->add_component (std::make_unique (seq_con_info{ "blocks", blocks_count, sizeof (decltype (block_processor.blocks)::value_type) })); + composite->add_component (std::make_unique (seq_con_info{ "blocks_hashes", blocks_hashes_count, sizeof (decltype (block_processor.blocks_hashes)::value_type) })); + composite->add_component (std::make_unique (seq_con_info{ "forced", forced_count, sizeof (decltype (block_processor.forced)::value_type) })); + composite->add_component (std::make_unique (seq_con_info{ "rolled_back", rolled_back_count, sizeof (decltype (block_processor.rolled_back)::value_type) })); + composite->add_component (collect_seq_con_info (block_processor.generator, "generator")); + return composite; +} +} + nano::node::node (nano::node_init & init_a, boost::asio::io_context & io_ctx_a, uint16_t peering_port_a, boost::filesystem::path const & application_path_a, nano::alarm & alarm_a, nano::logging const & logging_a, nano::work_pool & work_a) : node (init_a, io_ctx_a, application_path_a, alarm_a, nano::node_config (peering_port_a, logging_a), work_a) { @@ -2277,6 +2361,32 @@ void nano::node::process_fork (nano::transaction const & transaction_a, std::sha } } +namespace nano +{ +std::unique_ptr collect_seq_con_info (node & node, const std::string & name) +{ + auto composite = std::make_unique (name); + composite->add_component (collect_seq_con_info (node.work, "work")); + composite->add_component (collect_seq_con_info (node.gap_cache, "gap_cache")); + composite->add_component (collect_seq_con_info (node.ledger, "ledger")); + composite->add_component (collect_seq_con_info (node.active, "active")); + composite->add_component (collect_seq_con_info (node.bootstrap_initiator, "bootstrap_initiator")); + composite->add_component (collect_seq_con_info (node.bootstrap, "bootstrap")); + composite->add_component (collect_seq_con_info (node.peers, "peers")); + composite->add_component (collect_seq_con_info (node.observers, "observers")); + composite->add_component (collect_seq_con_info (node.wallets, "wallets")); + composite->add_component (collect_seq_con_info (node.vote_processor, "vote_processor")); + composite->add_component (collect_seq_con_info (node.rep_crawler, "rep_crawler")); + composite->add_component (collect_seq_con_info (node.block_processor, "block_processor")); + composite->add_component (collect_seq_con_info (node.block_arrival, "block_arrival")); + composite->add_component (collect_seq_con_info (node.online_reps, "online_reps")); + composite->add_component (collect_seq_con_info (node.votes_cache, "votes_cache")); + composite->add_component (collect_seq_con_info (node.block_uniquer, "block_uniquer")); + composite->add_component (collect_seq_con_info (node.vote_uniquer, "vote_uniquer")); + return composite; +} +} + nano::gap_cache::gap_cache (nano::node & node_a) : node (node_a) { @@ -2366,6 +2476,23 @@ nano::uint128_t nano::gap_cache::bootstrap_threshold (nano::transaction const & return result; } +namespace nano +{ +std::unique_ptr collect_seq_con_info (gap_cache & gap_cache, const std::string & name) +{ + size_t count = 0; + { + std::lock_guard (gap_cache.mutex); + count = gap_cache.blocks.size (); + } + + auto sizeof_element = sizeof (decltype (gap_cache.blocks)::value_type); + auto composite = std::make_unique (name); + composite->add_component (std::make_unique (seq_con_info{ "blocks", count, sizeof_element })); + return composite; +} +} + void nano::network::confirm_send (nano::confirm_ack const & confirm_a, std::shared_ptr> bytes_a, nano::endpoint const & endpoint_a) { if (node.config.logging.network_publish_logging ()) @@ -3215,6 +3342,23 @@ bool nano::block_arrival::recent (nano::block_hash const & hash_a) return arrival.get<1> ().find (hash_a) != arrival.get<1> ().end (); } +namespace nano +{ +std::unique_ptr collect_seq_con_info (block_arrival & block_arrival, const std::string & name) +{ + size_t count = 0; + { + std::lock_guard guard (block_arrival.mutex); + count = block_arrival.arrival.size (); + } + + auto sizeof_element = sizeof (decltype (block_arrival.arrival)::value_type); + auto composite = std::make_unique (name); + composite->add_component (std::make_unique (seq_con_info{ "arrival", count, sizeof_element })); + return composite; +} +} + nano::online_reps::online_reps (nano::node & node) : node (node) { @@ -3293,6 +3437,23 @@ std::vector nano::online_reps::list () return result; } +namespace nano +{ +std::unique_ptr collect_seq_con_info (online_reps & online_reps, const std::string & name) +{ + size_t count = 0; + { + std::lock_guard guard (online_reps.mutex); + count = online_reps.reps.size (); + } + + auto sizeof_element = sizeof (decltype (online_reps.reps)::value_type); + auto composite = std::make_unique (name); + composite->add_component (std::make_unique (seq_con_info{ "arrival", count, sizeof_element })); + return composite; +} +} + namespace { boost::asio::ip::address_v6 mapped_from_v4_bytes (unsigned long address_a) @@ -4128,6 +4289,28 @@ bool nano::active_transactions::publish (std::shared_ptr block_a) return result; } +namespace nano +{ +std::unique_ptr collect_seq_con_info (active_transactions & active_transactions, const std::string & name) +{ + size_t roots_count = 0; + size_t blocks_count = 0; + size_t confirmed_count = 0; + + { + std::lock_guard guard (active_transactions.mutex); + roots_count = active_transactions.roots.size (); + blocks_count = active_transactions.blocks.size (); + confirmed_count = active_transactions.confirmed.size (); + } + + auto composite = std::make_unique (name); + composite->add_component (std::make_unique (seq_con_info{ "roots", roots_count, sizeof (decltype (active_transactions.roots)::value_type) })); + composite->add_component (std::make_unique (seq_con_info{ "blocks", blocks_count, sizeof (decltype (active_transactions.blocks)::value_type) })); + composite->add_component (std::make_unique (seq_con_info{ "confirmed", confirmed_count, sizeof (decltype (active_transactions.confirmed)::value_type) })); + return composite; +} +} int nano::node::store_version () { auto transaction (store.tx_begin_read ()); diff --git a/nano/node/node.hpp b/nano/node/node.hpp index 34229940b3..a8b60be2c1 100644 --- a/nano/node/node.hpp +++ b/nano/node/node.hpp @@ -148,6 +148,9 @@ class active_transactions bool stopped; boost::thread thread; }; + +std::unique_ptr collect_seq_con_info (active_transactions & active_transactions, const std::string & name); + class operation { public: @@ -192,6 +195,9 @@ class gap_cache std::mutex mutex; nano::node & node; }; + +std::unique_ptr collect_seq_con_info (gap_cache & gap_cache, const std::string & name); + class work_pool; class send_info { @@ -225,6 +231,9 @@ class block_arrival static size_t constexpr arrival_size_min = 8 * 1024; static std::chrono::seconds constexpr arrival_time_min = std::chrono::seconds (300); }; + +std::unique_ptr collect_seq_con_info (block_arrival & block_arrival, const std::string & name); + class rep_last_heard_info { public: @@ -240,6 +249,8 @@ class online_reps nano::uint128_t online_stake (); nano::uint128_t online_stake_total; std::vector list (); + +private: boost::multi_index_container< nano::rep_last_heard_info, boost::multi_index::indexed_by< @@ -247,10 +258,14 @@ class online_reps boost::multi_index::hashed_unique>>> reps; -private: std::mutex mutex; nano::node & node; + + friend std::unique_ptr collect_seq_con_info (online_reps & online_reps, const std::string & name); }; + +std::unique_ptr collect_seq_con_info (online_reps & online_reps, const std::string & name); + class udp_data { public: @@ -359,6 +374,9 @@ class node_observers nano::observer_set endpoint; nano::observer_set<> disconnect; }; + +std::unique_ptr collect_seq_con_info (node_observers & node_observers, const std::string & name); + class vote_processor { public: @@ -385,7 +403,12 @@ class vote_processor bool stopped; bool active; boost::thread thread; + + friend std::unique_ptr collect_seq_con_info (vote_processor & vote_processor, const std::string & name); }; + +std::unique_ptr collect_seq_con_info (vote_processor & vote_processor, const std::string & name); + // The network is crawled for representatives by occasionally sending a unicast confirm_req for a specific block and watching to see if it's acknowledged with a vote. class rep_crawler { @@ -396,6 +419,9 @@ class rep_crawler std::mutex mutex; std::unordered_set active; }; + +std::unique_ptr collect_seq_con_info (rep_crawler & rep_crawler, const std::string & name); + class block_processor; class signature_check_set final { @@ -496,7 +522,12 @@ class block_processor std::condition_variable condition; nano::node & node; std::mutex mutex; + + friend std::unique_ptr collect_seq_con_info (block_processor & block_processor, const std::string & name); }; + +std::unique_ptr collect_seq_con_info (block_processor & block_processor, const std::string & name); + class node : public std::enable_shared_from_this { public: @@ -593,6 +624,9 @@ class node : public std::enable_shared_from_this static std::chrono::hours constexpr unchecked_cleaning_interval = std::chrono::hours (2); std::chrono::seconds unchecked_cutoff = std::chrono::seconds (7 * 24 * 60 * 60); // Week }; + +std::unique_ptr collect_seq_con_info (node & node, const std::string & name); + class thread_runner { public: diff --git a/nano/node/peers.cpp b/nano/node/peers.cpp index 7df34fdf53..bd09858800 100644 --- a/nano/node/peers.cpp +++ b/nano/node/peers.cpp @@ -474,3 +474,33 @@ bool nano::peer_container::insert (nano::endpoint const & endpoint_a, unsigned v } return result; } + +namespace nano +{ +std::unique_ptr collect_seq_con_info (peer_container & peer_container, const std::string & name) +{ + size_t peers_count = 0; + size_t attemps_count = 0; + { + std::lock_guard guard (peer_container.mutex); + peers_count = peer_container.peers.size (); + attemps_count = peer_container.attempts.size (); + } + + auto composite = std::make_unique (name); + composite->add_component (std::make_unique (seq_con_info{ "peers", peers_count, sizeof (decltype (peer_container.peers)::value_type) })); + composite->add_component (std::make_unique (seq_con_info{ "attempts", attemps_count, sizeof (decltype (peer_container.attempts)::value_type) })); + + size_t syn_cookies_count = 0; + size_t syn_cookies_per_ip_count = 0; + { + std::lock_guard guard (peer_container.syn_cookie_mutex); + syn_cookies_count = peer_container.syn_cookies.size (); + syn_cookies_per_ip_count = peer_container.syn_cookies_per_ip.size (); + } + + composite->add_component (std::make_unique (seq_con_info{ "syn_cookies", syn_cookies_count, sizeof (decltype (peer_container.syn_cookies)::value_type) })); + composite->add_component (std::make_unique (seq_con_info{ "syn_cookies_per_ip", syn_cookies_per_ip_count, sizeof (decltype (peer_container.syn_cookies_per_ip)::value_type) })); + return composite; +} +} diff --git a/nano/node/peers.hpp b/nano/node/peers.hpp index d9e762684e..24968da60a 100644 --- a/nano/node/peers.hpp +++ b/nano/node/peers.hpp @@ -137,4 +137,6 @@ class peer_container // Maximum number of peers per IP static size_t constexpr max_peers_per_ip = 10; }; + +std::unique_ptr collect_seq_con_info (peer_container & peer_container, const std::string & name); } diff --git a/nano/node/rpc.cpp b/nano/node/rpc.cpp index de1c1d0d73..3b13d9de77 100644 --- a/nano/node/rpc.cpp +++ b/nano/node/rpc.cpp @@ -9,6 +9,11 @@ #include +namespace +{ +void construct_json (nano::seq_con_info_component * component, boost::property_tree::ptree & parent); +} + nano::rpc_secure_config::rpc_secure_config () : enable (false), verbose_logging (false) @@ -3086,19 +3091,30 @@ void nano::rpc_handler::stats () { auto sink = node.stats.log_sink_json (); std::string type (request.get ("type", "")); + bool use_sink = false; if (type == "counters") { node.stats.log_counters (*sink); + use_sink = true; + } + else if (type == "objects") + { + rpc_control_impl (); + if (!ec) + { + construct_json (collect_seq_con_info (node, "node").get (), response_l); + } } else if (type == "samples") { node.stats.log_samples (*sink); + use_sink = true; } else { ec = nano::error_rpc::invalid_missing_type; } - if (!ec) + if (!ec && use_sink) { auto stat_tree_l (*static_cast (sink->to_object ())); stat_tree_l.put ("stat_duration_seconds", node.stats.last_reset ().count ()); @@ -4632,7 +4648,7 @@ void nano::rpc_handler::process_request () } } } - catch (std::runtime_error const & err) + catch (std::runtime_error const &) { error_response (response, "Unable to parse JSON"); } @@ -4727,3 +4743,30 @@ std::unique_ptr nano::get_rpc (boost::asio::io_context & io_ctx_a, na return impl; } + +namespace +{ +void construct_json (nano::seq_con_info_component * component, boost::property_tree::ptree & parent) +{ + // We are a leaf node, print name and exit + if (!component->is_composite ()) + { + auto & leaf_info = static_cast (component)->get_info (); + boost::property_tree::ptree child; + child.put ("count", leaf_info.count); + child.put ("size", leaf_info.count * leaf_info.sizeof_element); + parent.add_child (leaf_info.name, child); + return; + } + + auto composite = static_cast (component); + + boost::property_tree::ptree current; + for (auto & child : composite->get_children ()) + { + construct_json (child.get (), current); + } + + parent.add_child (composite->get_name (), current); +} +} diff --git a/nano/node/voting.cpp b/nano/node/voting.cpp index e842b2e7cb..e199fb2b5e 100644 --- a/nano/node/voting.cpp +++ b/nano/node/voting.cpp @@ -140,3 +140,35 @@ std::vector> nano::votes_cache::find (nano::block_ha } return result; } + +namespace nano +{ +std::unique_ptr collect_seq_con_info (vote_generator & vote_generator, const std::string & name) +{ + size_t hashes_count = 0; + + { + std::lock_guard guard (vote_generator.mutex); + hashes_count = vote_generator.hashes.size (); + } + auto sizeof_element = sizeof (decltype (vote_generator.hashes)::value_type); + auto composite = std::make_unique (name); + composite->add_component (std::make_unique (seq_con_info{ "state_blocks", hashes_count, sizeof_element })); + return composite; +} + +std::unique_ptr collect_seq_con_info (votes_cache & votes_cache, const std::string & name) +{ + size_t cache_count = 0; + + { + std::lock_guard guard (votes_cache.cache_mutex); + cache_count = votes_cache.cache.size (); + } + auto sizeof_element = sizeof (decltype (votes_cache.cache)::value_type); + auto composite = std::make_unique (name); + /* This does not currently loop over each element inside the cache to get the sizes of the votes inside cached_votes */ + composite->add_component (std::make_unique (seq_con_info{ "cache", cache_count, sizeof_element })); + return composite; +} +} diff --git a/nano/node/voting.hpp b/nano/node/voting.hpp index fc7497c1fa..167ecbc97e 100644 --- a/nano/node/voting.hpp +++ b/nano/node/voting.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -35,7 +36,11 @@ class vote_generator bool stopped; bool started; boost::thread thread; + + friend std::unique_ptr collect_seq_con_info (vote_generator & vote_generator, const std::string & name); }; + +std::unique_ptr collect_seq_con_info (vote_generator & vote_generator, const std::string & name); class cached_votes { public: @@ -58,5 +63,9 @@ class votes_cache boost::multi_index::hashed_unique>>> cache; static size_t constexpr max_cache = (nano::nano_network == nano::nano_networks::nano_test_network) ? 2 : 1000; + + friend std::unique_ptr collect_seq_con_info (votes_cache & votes_cache, const std::string & name); }; + +std::unique_ptr collect_seq_con_info (votes_cache & votes_cache, const std::string & name); } diff --git a/nano/node/wallet.cpp b/nano/node/wallet.cpp index 00cce8d398..2a59ce1ab5 100644 --- a/nano/node/wallet.cpp +++ b/nano/node/wallet.cpp @@ -1680,3 +1680,24 @@ MDB_txn * nano::wallet_store::tx (nano::transaction const & transaction_a) const auto result (boost::polymorphic_downcast (transaction_a.impl.get ())); return *result; } + +namespace nano +{ +std::unique_ptr collect_seq_con_info (wallets & wallets, const std::string & name) +{ + size_t items_count = 0; + size_t actions_count = 0; + { + std::lock_guard guard (wallets.mutex); + items_count = wallets.items.size (); + actions_count = wallets.actions.size (); + } + + auto composite = std::make_unique (name); + auto sizeof_item_element = sizeof (decltype (wallets.items)::value_type); + auto sizeof_actions_element = sizeof (decltype (wallets.actions)::value_type); + composite->add_component (std::make_unique (seq_con_info{ "items", items_count, sizeof_item_element })); + composite->add_component (std::make_unique (seq_con_info{ "actions_count", actions_count, sizeof_actions_element })); + return composite; +} +} diff --git a/nano/node/wallet.hpp b/nano/node/wallet.hpp index 8c3061f035..30a3a85964 100644 --- a/nano/node/wallet.hpp +++ b/nano/node/wallet.hpp @@ -209,6 +209,9 @@ class wallets */ nano::transaction tx_begin (bool write = false); }; + +std::unique_ptr collect_seq_con_info (wallets & wallets, const std::string & name); + class wallets_store { public: diff --git a/nano/secure/common.cpp b/nano/secure/common.cpp index 5c15d51a42..e8e6771829 100644 --- a/nano/secure/common.cpp +++ b/nano/secure/common.cpp @@ -774,6 +774,18 @@ size_t nano::vote_uniquer::size () return votes.size (); } +namespace nano +{ +std::unique_ptr collect_seq_con_info (vote_uniquer & vote_uniquer, const std::string & name) +{ + auto count = vote_uniquer.size (); + auto sizeof_element = sizeof (vote_uniquer::value_type); + auto composite = std::make_unique (name); + composite->add_component (std::make_unique (seq_con_info{ "votes", count, sizeof_element })); + return composite; +} +} + nano::genesis::genesis () { boost::property_tree::ptree tree; diff --git a/nano/secure/common.hpp b/nano/secure/common.hpp index cfa4d7fb05..7b2d07feda 100644 --- a/nano/secure/common.hpp +++ b/nano/secure/common.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -254,6 +255,8 @@ class vote class vote_uniquer { public: + using value_type = std::pair>; + vote_uniquer (nano::block_uniquer &); std::shared_ptr unique (std::shared_ptr); size_t size (); @@ -261,9 +264,12 @@ class vote_uniquer private: nano::block_uniquer & uniquer; std::mutex mutex; - std::unordered_map> votes; + std::unordered_map, value_type::second_type> votes; static unsigned constexpr cleanup_count = 2; }; + +std::unique_ptr collect_seq_con_info (vote_uniquer & vote_uniquer, const std::string & name); + enum class vote_code { invalid, // Vote is not signed correctly diff --git a/nano/secure/ledger.cpp b/nano/secure/ledger.cpp index e71d73da72..72c30b8195 100644 --- a/nano/secure/ledger.cpp +++ b/nano/secure/ledger.cpp @@ -1021,3 +1021,15 @@ std::shared_ptr nano::ledger::forked_block (nano::transaction const } return result; } + +namespace nano +{ +std::unique_ptr collect_seq_con_info (ledger & ledger, const std::string & name) +{ + auto composite = std::make_unique (name); + auto count = ledger.bootstrap_weights.size (); + auto sizeof_element = sizeof (decltype (ledger.bootstrap_weights)::value_type); + composite->add_component (std::make_unique (seq_con_info{ "bootstrap_weights", count, sizeof_element })); + return composite; +} +} diff --git a/nano/secure/ledger.hpp b/nano/secure/ledger.hpp index ef1d7cd269..e47da23920 100644 --- a/nano/secure/ledger.hpp +++ b/nano/secure/ledger.hpp @@ -52,4 +52,6 @@ class ledger nano::uint256_union epoch_link; nano::account epoch_signer; }; -}; + +std::unique_ptr collect_seq_con_info (ledger & ledger, const std::string & name); +}