dncurrency/nano/node/peer_history.cpp
2024-12-22 21:32:28 +01:00

166 lines
4 KiB
C++

#include <nano/lib/thread_roles.hpp>
#include <nano/node/network.hpp>
#include <nano/node/peer_history.hpp>
#include <nano/node/transport/channel.hpp>
#include <nano/store/component.hpp>
#include <nano/store/peer.hpp>
nano::peer_history::peer_history (nano::peer_history_config const & config_a, nano::store::component & store_a, nano::network & network_a, nano::logger & logger_a, nano::stats & stats_a) :
config{ config_a },
store{ store_a },
network{ network_a },
logger{ logger_a },
stats{ stats_a }
{
}
nano::peer_history::~peer_history ()
{
debug_assert (!thread.joinable ());
}
void nano::peer_history::start ()
{
debug_assert (!thread.joinable ());
thread = std::thread ([this] {
nano::thread_role::set (nano::thread_role::name::peer_history);
run ();
});
}
void nano::peer_history::stop ()
{
{
nano::lock_guard<nano::mutex> guard{ mutex };
stopped = true;
}
condition.notify_all ();
if (thread.joinable ())
{
thread.join ();
}
}
bool nano::peer_history::exists (nano::endpoint const & endpoint) const
{
auto transaction = store.tx_begin_read ();
return store.peer.exists (transaction, endpoint);
}
size_t nano::peer_history::size () const
{
auto transaction = store.tx_begin_read ();
return store.peer.count (transaction);
}
void nano::peer_history::trigger ()
{
condition.notify_all ();
}
void nano::peer_history::run ()
{
nano::unique_lock<nano::mutex> lock{ mutex };
while (!stopped)
{
condition.wait_for (lock, config.check_interval, [this] { return stopped.load (); });
if (!stopped)
{
stats.inc (nano::stat::type::peer_history, nano::stat::detail::loop);
lock.unlock ();
run_one ();
lock.lock ();
}
}
}
void nano::peer_history::run_one ()
{
auto live_peers = network.list ();
auto transaction = store.tx_begin_write ();
// Add or update live peers
for (auto const & peer : live_peers)
{
auto const endpoint = peer->get_peering_endpoint ();
bool const exists = store.peer.exists (transaction, endpoint);
store.peer.put (transaction, endpoint, nano::milliseconds_since_epoch ());
if (!exists)
{
stats.inc (nano::stat::type::peer_history, nano::stat::detail::inserted);
logger.debug (nano::log::type::peer_history, "Saved new peer: {}", fmt::streamed (endpoint));
}
else
{
stats.inc (nano::stat::type::peer_history, nano::stat::detail::updated);
}
}
// Erase old peers
auto const now = std::chrono::system_clock::now ();
auto const cutoff = now - config.erase_cutoff;
std::deque<nano::store::peer::iterator::value_type> to_remove;
for (auto it = store.peer.begin (transaction); it != store.peer.end (transaction); ++it)
{
auto const [endpoint, timestamp_millis] = *it;
auto timestamp = nano::from_milliseconds_since_epoch (timestamp_millis);
if (timestamp > now || timestamp < cutoff)
{
to_remove.push_back (*it);
stats.inc (nano::stat::type::peer_history, nano::stat::detail::erased);
logger.debug (nano::log::type::peer_history, "Erased peer: {} (not seen for {}s)",
fmt::streamed (endpoint.endpoint ()),
nano::log::seconds_delta (timestamp));
}
}
// Remove entries after iterating to avoid iterator invalidation
for (auto const & entry : to_remove)
{
store.peer.del (transaction, entry.first);
}
}
std::vector<nano::endpoint> nano::peer_history::peers () const
{
auto transaction = store.tx_begin_read ();
std::vector<nano::endpoint> peers;
for (auto it = store.peer.begin (transaction); it != store.peer.end (transaction); ++it)
{
auto const [endpoint, timestamp_millis] = *it;
peers.push_back (endpoint.endpoint ());
}
return peers;
}
/*
* peer_history_config
*/
nano::peer_history_config::peer_history_config (nano::network_constants const & network)
{
if (network.is_dev_network ())
{
check_interval = 1s;
erase_cutoff = 10s;
}
}
nano::error nano::peer_history_config::serialize (nano::tomlconfig & toml) const
{
// TODO: Serialization / deserialization
return toml.get_error ();
}
nano::error nano::peer_history_config::deserialize (nano::tomlconfig & toml)
{
// TODO: Serialization / deserialization
return toml.get_error ();
}