Skip to content

Commit

Permalink
Use chrono timestamps in ascending bootstrap code (#4687)
Browse files Browse the repository at this point in the history
* Use unique ptr

* Use chrono timestamps
  • Loading branch information
pwojcikdev authored and clemahieu committed Aug 6, 2024
1 parent bcb69fe commit ec15680
Show file tree
Hide file tree
Showing 11 changed files with 67 additions and 44 deletions.
6 changes: 3 additions & 3 deletions nano/core_test/bootstrap_ascending.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,9 @@ TEST (bootstrap_ascending, config_serialization)
config1.requests_limit = 0x101;
config1.database_requests_limit = 0x102;
config1.pull_count = 0x103;
config1.timeout = 0x104;
config1.request_timeout = 0x104ms;
config1.throttle_coefficient = 0x105;
config1.throttle_wait = 0x106;
config1.throttle_wait = 0x106ms;
config1.block_wait_count = 0x107;
nano::tomlconfig toml1;
ASSERT_FALSE (config1.serialize (toml1));
Expand All @@ -281,7 +281,7 @@ TEST (bootstrap_ascending, config_serialization)
ASSERT_EQ (config1.requests_limit, config2.requests_limit);
ASSERT_EQ (config1.database_requests_limit, config2.database_requests_limit);
ASSERT_EQ (config1.pull_count, config2.pull_count);
ASSERT_EQ (config1.timeout, config2.timeout);
ASSERT_EQ (config1.request_timeout, config2.request_timeout);
ASSERT_EQ (config1.throttle_coefficient, config2.throttle_coefficient);
ASSERT_EQ (config1.throttle_wait, config2.throttle_wait);
ASSERT_EQ (config1.block_wait_count, config2.block_wait_count);
Expand Down
10 changes: 10 additions & 0 deletions nano/lib/tomlconfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,16 @@ class tomlconfig : public nano::configbase
return *this;
}

/** Get chrono duration */
template <typename Duration>
tomlconfig & get_duration (std::string const & key, Duration & target)
{
uint64_t value;
get (key, value);
target = Duration{ value };
return *this;
}

/**
* Get value of optional key. Use default value of data type if missing.
*/
Expand Down
12 changes: 6 additions & 6 deletions nano/node/bootstrap/bootstrap_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ nano::error nano::account_sets_config::deserialize (nano::tomlconfig & toml)
toml.get ("consideration_count", consideration_count);
toml.get ("priorities_max", priorities_max);
toml.get ("blocking_max", blocking_max);
toml.get ("cooldown", cooldown);
toml.get_duration ("cooldown", cooldown);

return toml.get_error ();
}
Expand All @@ -19,7 +19,7 @@ nano::error nano::account_sets_config::serialize (nano::tomlconfig & toml) const
toml.put ("consideration_count", consideration_count, "Limit the number of account candidates to consider and also the number of iterations.\ntype:uint64");
toml.put ("priorities_max", priorities_max, "Cutoff size limit for the priority list.\ntype:uint64");
toml.put ("blocking_max", blocking_max, "Cutoff size limit for the blocked accounts from the priority list.\ntype:uint64");
toml.put ("cooldown", cooldown, "Waiting time for an account to become available.\ntype:milliseconds");
toml.put ("cooldown", cooldown.count (), "Waiting time for an account to become available.\ntype:milliseconds");

return toml.get_error ();
}
Expand All @@ -32,9 +32,9 @@ nano::error nano::bootstrap_ascending_config::deserialize (nano::tomlconfig & to
toml.get ("requests_limit", requests_limit);
toml.get ("database_requests_limit", database_requests_limit);
toml.get ("pull_count", pull_count);
toml.get ("timeout", timeout);
toml.get_duration ("timeout", request_timeout);
toml.get ("throttle_coefficient", throttle_coefficient);
toml.get ("throttle_wait", throttle_wait);
toml.get_duration ("throttle_wait", throttle_wait);
toml.get ("block_wait_count", block_wait_count);

if (toml.has_key ("account_sets"))
Expand All @@ -51,9 +51,9 @@ nano::error nano::bootstrap_ascending_config::serialize (nano::tomlconfig & toml
toml.put ("requests_limit", requests_limit, "Request limit to ascending bootstrap after which requests will be dropped.\nNote: changing to unlimited (0) is not recommended.\ntype:uint64");
toml.put ("database_requests_limit", database_requests_limit, "Request limit for accounts from database after which requests will be dropped.\nNote: changing to unlimited (0) is not recommended as this operation competes for resources on querying the database.\ntype:uint64");
toml.put ("pull_count", pull_count, "Number of requested blocks for ascending bootstrap request.\ntype:uint64");
toml.put ("timeout", timeout, "Timeout in milliseconds for incoming ascending bootstrap messages to be processed.\ntype:milliseconds");
toml.put ("timeout", request_timeout.count (), "Timeout in milliseconds for incoming ascending bootstrap messages to be processed.\ntype:milliseconds");
toml.put ("throttle_coefficient", throttle_coefficient, "Scales the number of samples to track for bootstrap throttling.\ntype:uint64");
toml.put ("throttle_wait", throttle_wait, "Length of time to wait between requests when throttled.\ntype:milliseconds");
toml.put ("throttle_wait", throttle_wait.count (), "Length of time to wait between requests when throttled.\ntype:milliseconds");
toml.put ("block_wait_count", block_wait_count, "Asending bootstrap will wait while block processor has more than this many blocks queued.\ntype:uint64");

nano::tomlconfig account_sets_l;
Expand Down
6 changes: 3 additions & 3 deletions nano/node/bootstrap/bootstrap_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class account_sets_config final
std::size_t consideration_count{ 4 };
std::size_t priorities_max{ 256 * 1024 };
std::size_t blocking_max{ 256 * 1024 };
nano::millis_t cooldown{ 1000 * 3 };
std::chrono::milliseconds cooldown{ 1000 * 3 };
};

class bootstrap_ascending_config final
Expand All @@ -30,9 +30,9 @@ class bootstrap_ascending_config final
std::size_t requests_limit{ 64 };
std::size_t database_requests_limit{ 1024 };
std::size_t pull_count{ nano::bootstrap_server::max_blocks };
nano::millis_t timeout{ 1000 * 3 };
std::chrono::milliseconds request_timeout{ 1000 * 5 };
std::size_t throttle_coefficient{ 16 };
nano::millis_t throttle_wait{ 100 };
std::chrono::milliseconds throttle_wait{ 100 };
std::size_t block_wait_count{ 1000 };

nano::account_sets_config account_sets;
Expand Down
34 changes: 17 additions & 17 deletions nano/node/bootstrap_ascending/account_sets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,25 +114,36 @@ void nano::bootstrap_ascending::account_sets::unblock (nano::account const & acc
}
}

void nano::bootstrap_ascending::account_sets::timestamp (const nano::account & account, bool reset)
void nano::bootstrap_ascending::account_sets::timestamp_set (const nano::account & account)
{
const nano::millis_t tstamp = reset ? 0 : nano::milliseconds_since_epoch ();
auto iter = priorities.get<tag_account> ().find (account);
if (iter != priorities.get<tag_account> ().end ())
{
priorities.get<tag_account> ().modify (iter, [] (auto & entry) {
entry.timestamp = std::chrono::steady_clock::now ();
});
}
}

void nano::bootstrap_ascending::account_sets::timestamp_reset (const nano::account & account)
{
auto iter = priorities.get<tag_account> ().find (account);
if (iter != priorities.get<tag_account> ().end ())
{
priorities.get<tag_account> ().modify (iter, [tstamp] (auto & entry) {
entry.timestamp = tstamp;
priorities.get<tag_account> ().modify (iter, [] (auto & entry) {
entry.timestamp = {};
});
}
}

// Returns false if the account is busy
bool nano::bootstrap_ascending::account_sets::check_timestamp (const nano::account & account) const
{
auto iter = priorities.get<tag_account> ().find (account);
if (iter != priorities.get<tag_account> ().end ())
{
if (nano::milliseconds_since_epoch () - iter->timestamp < config.cooldown)
auto const cutoff = std::chrono::steady_clock::now () - config.cooldown;
if (iter->timestamp > cutoff)
{
return false;
}
Expand Down Expand Up @@ -240,15 +251,4 @@ std::unique_ptr<nano::container_info_component> nano::bootstrap_ascending::accou
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "priorities", priorities.size (), sizeof (decltype (priorities)::value_type) }));
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "blocking", blocking.size (), sizeof (decltype (blocking)::value_type) }));
return composite;
}

/*
* priority_entry
*/

nano::bootstrap_ascending::account_sets::priority_entry::priority_entry (nano::account account_a, float priority_a) :
account{ account_a },
priority{ priority_a }
{
id = nano::bootstrap_ascending::generate_id ();
}
}
12 changes: 6 additions & 6 deletions nano/node/bootstrap_ascending/account_sets.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ namespace bootstrap_ascending
void priority_down (nano::account const & account);
void block (nano::account const & account, nano::block_hash const & dependency);
void unblock (nano::account const & account, std::optional<nano::block_hash> const & hash = std::nullopt);
void timestamp (nano::account const & account, bool reset = false);
void timestamp_set (nano::account const & account);
void timestamp_reset (nano::account const & account);

nano::account next ();

Expand All @@ -68,12 +69,11 @@ namespace bootstrap_ascending
private:
struct priority_entry
{
nano::account account{ 0 };
float priority{ 0 };
nano::millis_t timestamp{ 0 };
nano::bootstrap_ascending::id_t id{ 0 }; // Uniformly distributed, used for random querying
nano::account account;
float priority;

priority_entry (nano::account account, float priority);
id_t id{ generate_id () }; // Uniformly distributed, used for random querying
std::chrono::steady_clock::time_point timestamp{};
};

struct blocking_entry
Expand Down
15 changes: 10 additions & 5 deletions nano/node/bootstrap_ascending/service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ void nano::bootstrap_ascending::service::inspect (secure::transaction const & tx
// If we've inserted any block in to an account, unmark it as blocked
accounts.unblock (account);
accounts.priority_up (account);
accounts.timestamp (account, /* reset timestamp */ true);
accounts.timestamp_reset (account);

if (block.is_send ())
{
Expand Down Expand Up @@ -230,7 +230,7 @@ nano::account nano::bootstrap_ascending::service::wait_available_account ()
auto account = available_account ();
if (!account.is_zero ())
{
accounts.timestamp (account);
accounts.timestamp_set (account);
return account;
}
else
Expand All @@ -246,7 +246,6 @@ bool nano::bootstrap_ascending::service::request (nano::account & account, std::
async_tag tag{};
tag.id = nano::bootstrap_ascending::generate_id ();
tag.account = account;
tag.time = nano::milliseconds_since_epoch ();

// Check if the account picked has blocks, if it does, start the pull from the highest block
auto info = ledger.store.account.get (ledger.store.tx_begin_read (), account);
Expand Down Expand Up @@ -323,8 +322,14 @@ void nano::bootstrap_ascending::service::run_timeouts ()
scoring.sync (network.list ());
scoring.timeout ();
throttle.resize (compute_throttle_size ());

auto const cutoff = std::chrono::steady_clock::now () - config.bootstrap_ascending.request_timeout;
auto should_timeout = [cutoff] (async_tag const & tag) {
return tag.timestamp < cutoff;
};

auto & tags_by_order = tags.get<tag_sequenced> ();
while (!tags_by_order.empty () && nano::time_difference (tags_by_order.front ().time, nano::milliseconds_since_epoch ()) > config.bootstrap_ascending.timeout)
while (!tags_by_order.empty () && should_timeout (tags_by_order.front ()))
{
auto tag = tags_by_order.front ();
tags_by_order.pop_front ();
Expand All @@ -350,7 +355,7 @@ void nano::bootstrap_ascending::service::process (nano::asc_pull_ack const & mes
tags_by_id.erase (iterator);

// Track bootstrap request response time
stats.sample (nano::stat::sample::bootstrap_tag_duration, nano::milliseconds_since_epoch () - tag.time, { 0, config.bootstrap_ascending.timeout });
stats.sample (nano::stat::sample::bootstrap_tag_duration, nano::log::milliseconds_delta (tag.timestamp), { 0, config.bootstrap_ascending.request_timeout.count () });

scoring.received_message (channel);

Expand Down
3 changes: 2 additions & 1 deletion nano/node/bootstrap_ascending/service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,9 @@ namespace bootstrap_ascending
query_type type{ query_type::invalid };
nano::bootstrap_ascending::id_t id{ 0 };
nano::hash_or_account start{ 0 };
nano::millis_t time{ 0 };
nano::account account{ 0 };

std::chrono::steady_clock::time_point timestamp{ std::chrono::steady_clock::now () };
};

public: // Events
Expand Down
1 change: 1 addition & 0 deletions nano/node/message_processor.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <nano/lib/thread_roles.hpp>
#include <nano/node/bootstrap_ascending/service.hpp>
#include <nano/node/message_processor.hpp>
#include <nano/node/node.hpp>

Expand Down
4 changes: 3 additions & 1 deletion nano/node/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <nano/lib/tomlconfig.hpp>
#include <nano/lib/utility.hpp>
#include <nano/node/active_elections.hpp>
#include <nano/node/bootstrap_ascending/service.hpp>
#include <nano/node/common.hpp>
#include <nano/node/confirming_set.hpp>
#include <nano/node/daemonconfig.hpp>
Expand Down Expand Up @@ -216,7 +217,8 @@ nano::node::node (std::shared_ptr<boost::asio::io_context> io_ctx_a, std::filesy
aggregator{ *aggregator_impl },
wallets (wallets_store.init_error (), *this),
backlog{ nano::backlog_population_config (config), scheduler, ledger, stats },
ascendboot{ config, block_processor, ledger, network, stats },
ascendboot_impl{ std::make_unique<nano::bootstrap_ascending::service> (config, block_processor, ledger, network, stats) },
ascendboot{ *ascendboot_impl },
websocket{ config.websocket_config, observers, wallets, ledger, io_ctx, logger },
epoch_upgrader{ *this, ledger, store, network_params, logger },
local_block_broadcaster_impl{ std::make_unique<nano::local_block_broadcaster> (config.local_block_broadcaster, *this, block_processor, network, confirming_set, stats, logger, !flags.disable_block_processor_republishing) },
Expand Down
8 changes: 6 additions & 2 deletions nano/node/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#include <nano/node/bootstrap/bootstrap.hpp>
#include <nano/node/bootstrap/bootstrap_attempt.hpp>
#include <nano/node/bootstrap/bootstrap_server.hpp>
#include <nano/node/bootstrap_ascending/service.hpp>
#include <nano/node/distributed_work_factory.hpp>
#include <nano/node/epoch_upgrader.hpp>
#include <nano/node/fwd.hpp>
Expand Down Expand Up @@ -62,6 +61,10 @@ namespace transport
{
class tcp_listener;
}
namespace bootstrap_ascending
{
class service;
}
namespace rocksdb
{
} // Declare a namespace rocksdb inside nano so all references to the rocksdb library need to be globally scoped e.g. ::rocksdb::Slice
Expand Down Expand Up @@ -209,7 +212,8 @@ class node final : public std::enable_shared_from_this<node>
nano::request_aggregator & aggregator;
nano::wallets wallets;
nano::backlog_population backlog;
nano::bootstrap_ascending::service ascendboot;
std::unique_ptr<nano::bootstrap_ascending::service> ascendboot_impl;
nano::bootstrap_ascending::service & ascendboot;
nano::websocket_server websocket;
nano::epoch_upgrader epoch_upgrader;
std::unique_ptr<nano::local_block_broadcaster> local_block_broadcaster_impl;
Expand Down

0 comments on commit ec15680

Please sign in to comment.