* Move container info classes to separate file * Introduce better `container_info` class * Rename legacy to `container_info_entry` * Conversion * Test * Fixes
186 lines
4.8 KiB
C++
186 lines
4.8 KiB
C++
#include <nano/lib/blocks.hpp>
|
|
#include <nano/lib/locks.hpp>
|
|
#include <nano/lib/stats.hpp>
|
|
#include <nano/lib/stats_enums.hpp>
|
|
#include <nano/lib/thread_roles.hpp>
|
|
#include <nano/lib/timer.hpp>
|
|
#include <nano/node/unchecked_map.hpp>
|
|
|
|
nano::unchecked_map::unchecked_map (unsigned const max_unchecked_blocks, nano::stats & stats, bool const & disable_delete) :
|
|
max_unchecked_blocks{ max_unchecked_blocks },
|
|
stats{ stats },
|
|
disable_delete{ disable_delete }
|
|
{
|
|
}
|
|
|
|
nano::unchecked_map::~unchecked_map ()
|
|
{
|
|
debug_assert (!thread.joinable ());
|
|
}
|
|
|
|
void nano::unchecked_map::start ()
|
|
{
|
|
debug_assert (!thread.joinable ());
|
|
|
|
thread = std::thread ([this] () {
|
|
nano::thread_role::set (nano::thread_role::name::unchecked);
|
|
run ();
|
|
});
|
|
}
|
|
|
|
void nano::unchecked_map::stop ()
|
|
{
|
|
{
|
|
nano::lock_guard<nano::mutex> lock{ mutex };
|
|
stopped = true;
|
|
}
|
|
condition.notify_all ();
|
|
|
|
if (thread.joinable ())
|
|
{
|
|
thread.join ();
|
|
}
|
|
}
|
|
|
|
void nano::unchecked_map::put (nano::hash_or_account const & dependency, nano::unchecked_info const & info)
|
|
{
|
|
nano::lock_guard<std::recursive_mutex> lock{ entries_mutex };
|
|
nano::unchecked_key key{ dependency, info.block->hash () };
|
|
entries.get<tag_root> ().insert ({ key, info });
|
|
|
|
if (entries.size () > max_unchecked_blocks)
|
|
{
|
|
entries.get<tag_sequenced> ().pop_front ();
|
|
}
|
|
|
|
stats.inc (nano::stat::type::unchecked, nano::stat::detail::put);
|
|
}
|
|
|
|
void nano::unchecked_map::for_each (std::function<void (nano::unchecked_key const &, nano::unchecked_info const &)> action, std::function<bool ()> predicate)
|
|
{
|
|
nano::lock_guard<std::recursive_mutex> lock{ entries_mutex };
|
|
for (auto i = entries.begin (), n = entries.end (); predicate () && i != n; ++i)
|
|
{
|
|
action (i->key, i->info);
|
|
}
|
|
}
|
|
|
|
void nano::unchecked_map::for_each (nano::hash_or_account const & dependency, std::function<void (nano::unchecked_key const &, nano::unchecked_info const &)> action, std::function<bool ()> predicate)
|
|
{
|
|
nano::lock_guard<std::recursive_mutex> lock{ entries_mutex };
|
|
for (auto i = entries.template get<tag_root> ().lower_bound (nano::unchecked_key{ dependency, 0 }), n = entries.template get<tag_root> ().end (); predicate () && i != n && i->key.key () == dependency.as_block_hash (); ++i)
|
|
{
|
|
action (i->key, i->info);
|
|
}
|
|
}
|
|
|
|
std::vector<nano::unchecked_info> nano::unchecked_map::get (nano::block_hash const & hash)
|
|
{
|
|
std::vector<nano::unchecked_info> result;
|
|
for_each (hash, [&result] (nano::unchecked_key const & key, nano::unchecked_info const & info) {
|
|
result.push_back (info);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
bool nano::unchecked_map::exists (nano::unchecked_key const & key) const
|
|
{
|
|
nano::lock_guard<std::recursive_mutex> lock{ entries_mutex };
|
|
return entries.get<tag_root> ().count (key) != 0;
|
|
}
|
|
|
|
void nano::unchecked_map::del (nano::unchecked_key const & key)
|
|
{
|
|
nano::lock_guard<std::recursive_mutex> lock{ entries_mutex };
|
|
auto erased = entries.get<tag_root> ().erase (key);
|
|
debug_assert (erased);
|
|
}
|
|
|
|
void nano::unchecked_map::clear ()
|
|
{
|
|
nano::lock_guard<std::recursive_mutex> lock{ entries_mutex };
|
|
entries.clear ();
|
|
}
|
|
|
|
size_t nano::unchecked_map::entries_size () const
|
|
{
|
|
nano::lock_guard<std::recursive_mutex> lock{ entries_mutex };
|
|
return entries.size ();
|
|
}
|
|
|
|
size_t nano::unchecked_map::queries_size () const
|
|
{
|
|
nano::lock_guard<nano::mutex> lock{ mutex };
|
|
return buffer.size ();
|
|
}
|
|
|
|
size_t nano::unchecked_map::count () const
|
|
{
|
|
return entries_size ();
|
|
}
|
|
|
|
void nano::unchecked_map::trigger (nano::hash_or_account const & dependency)
|
|
{
|
|
nano::unique_lock<nano::mutex> lock{ mutex };
|
|
buffer.emplace_back (dependency);
|
|
lock.unlock ();
|
|
stats.inc (nano::stat::type::unchecked, nano::stat::detail::trigger);
|
|
condition.notify_all (); // Notify run ()
|
|
}
|
|
|
|
void nano::unchecked_map::process_queries (decltype (buffer) const & back_buffer)
|
|
{
|
|
for (auto const & item : back_buffer)
|
|
{
|
|
query_impl (item.hash);
|
|
}
|
|
}
|
|
|
|
void nano::unchecked_map::run ()
|
|
{
|
|
nano::unique_lock<nano::mutex> lock{ mutex };
|
|
while (!stopped)
|
|
{
|
|
if (!buffer.empty ())
|
|
{
|
|
back_buffer.swap (buffer);
|
|
writing_back_buffer = true;
|
|
lock.unlock ();
|
|
process_queries (back_buffer);
|
|
lock.lock ();
|
|
writing_back_buffer = false;
|
|
back_buffer.clear ();
|
|
}
|
|
else
|
|
{
|
|
condition.wait (lock, [this] () {
|
|
return stopped || !buffer.empty ();
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
void nano::unchecked_map::query_impl (nano::block_hash const & hash)
|
|
{
|
|
std::deque<nano::unchecked_key> delete_queue;
|
|
for_each (hash, [this, &delete_queue] (nano::unchecked_key const & key, nano::unchecked_info const & info) {
|
|
delete_queue.push_back (key);
|
|
stats.inc (nano::stat::type::unchecked, nano::stat::detail::satisfied);
|
|
satisfied.notify (info);
|
|
});
|
|
if (!disable_delete)
|
|
{
|
|
for (auto const & key : delete_queue)
|
|
{
|
|
del (key);
|
|
}
|
|
}
|
|
}
|
|
|
|
nano::container_info nano::unchecked_map::container_info () const
|
|
{
|
|
nano::container_info info;
|
|
info.put ("entries", entries_size ());
|
|
info.put ("queries", queries_size ());
|
|
return info;
|
|
}
|