Rewrite nano::store iterators to use variants instead of polymorphism.
This commit is contained in:
		
					parent
					
						
							
								db7405f580
							
						
					
				
			
			
				commit
				
					
						37f4f5c2d6
					
				
			
		
					 62 changed files with 978 additions and 742 deletions
				
			
		| 
						 | 
				
			
			@ -798,7 +798,7 @@ TEST (block_store, large_iteration)
 | 
			
		|||
	// Reverse iteration
 | 
			
		||||
	std::unordered_set<nano::account> accounts3;
 | 
			
		||||
	previous = std::numeric_limits<nano::uint256_t>::max ();
 | 
			
		||||
	for (auto i (store->account.rbegin (transaction)), n (store->account.end (transaction)); i != n; --i)
 | 
			
		||||
	for (auto i (store->account.rbegin (transaction)), n (store->account.rend (transaction)); i != n; ++i)
 | 
			
		||||
	{
 | 
			
		||||
		nano::account current (i->first);
 | 
			
		||||
		ASSERT_LT (current.number (), previous.number ());
 | 
			
		||||
| 
						 | 
				
			
			@ -1254,7 +1254,7 @@ TEST (block_store, online_weight)
 | 
			
		|||
		auto transaction (store->tx_begin_write ());
 | 
			
		||||
		ASSERT_EQ (0, store->online_weight.count (transaction));
 | 
			
		||||
		ASSERT_EQ (store->online_weight.end (transaction), store->online_weight.begin (transaction));
 | 
			
		||||
		ASSERT_EQ (store->online_weight.end (transaction), store->online_weight.rbegin (transaction));
 | 
			
		||||
		ASSERT_EQ (store->online_weight.rend (transaction), store->online_weight.rbegin (transaction));
 | 
			
		||||
		store->online_weight.put (transaction, 1, 2);
 | 
			
		||||
		store->online_weight.put (transaction, 3, 4);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1266,18 +1266,18 @@ TEST (block_store, online_weight)
 | 
			
		|||
		ASSERT_EQ (1, item->first);
 | 
			
		||||
		ASSERT_EQ (2, item->second.number ());
 | 
			
		||||
		auto item_last (store->online_weight.rbegin (transaction));
 | 
			
		||||
		ASSERT_NE (store->online_weight.end (transaction), item_last);
 | 
			
		||||
		ASSERT_NE (store->online_weight.rend (transaction), item_last);
 | 
			
		||||
		ASSERT_EQ (3, item_last->first);
 | 
			
		||||
		ASSERT_EQ (4, item_last->second.number ());
 | 
			
		||||
		store->online_weight.del (transaction, 1);
 | 
			
		||||
		ASSERT_EQ (1, store->online_weight.count (transaction));
 | 
			
		||||
		ASSERT_EQ (store->online_weight.begin (transaction), store->online_weight.rbegin (transaction));
 | 
			
		||||
		ASSERT_EQ (*store->online_weight.begin (transaction), *store->online_weight.rbegin (transaction));
 | 
			
		||||
		store->online_weight.del (transaction, 3);
 | 
			
		||||
	}
 | 
			
		||||
	auto transaction (store->tx_begin_read ());
 | 
			
		||||
	ASSERT_EQ (0, store->online_weight.count (transaction));
 | 
			
		||||
	ASSERT_EQ (store->online_weight.end (transaction), store->online_weight.begin (transaction));
 | 
			
		||||
	ASSERT_EQ (store->online_weight.end (transaction), store->online_weight.rbegin (transaction));
 | 
			
		||||
	ASSERT_EQ (store->online_weight.rend (transaction), store->online_weight.rbegin (transaction));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST (block_store, pruned_blocks)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -755,7 +755,7 @@ void nano::node::long_inactivity_cleanup ()
 | 
			
		|||
	if (store.online_weight.count (transaction) > 0)
 | 
			
		||||
	{
 | 
			
		||||
		auto sample (store.online_weight.rbegin (transaction));
 | 
			
		||||
		auto n (store.online_weight.end (transaction));
 | 
			
		||||
		auto n (store.online_weight.rend (transaction));
 | 
			
		||||
		debug_assert (sample != n);
 | 
			
		||||
		auto const one_week_ago = static_cast<std::size_t> ((std::chrono::system_clock::now () - std::chrono::hours (7 * 24)).time_since_epoch ().count ());
 | 
			
		||||
		perform_cleanup = sample->first < one_week_ago;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@
 | 
			
		|||
#include <nano/secure/ledger_set_any.hpp>
 | 
			
		||||
#include <nano/secure/ledger_set_confirmed.hpp>
 | 
			
		||||
#include <nano/store/lmdb/iterator.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator_templ.hpp>
 | 
			
		||||
 | 
			
		||||
#include <boost/format.hpp>
 | 
			
		||||
#include <boost/polymorphic_cast.hpp>
 | 
			
		||||
| 
						 | 
				
			
			@ -19,6 +20,8 @@
 | 
			
		|||
 | 
			
		||||
#include <argon2.h>
 | 
			
		||||
 | 
			
		||||
template class nano::store::typed_iterator<nano::account, nano::wallet_value>;
 | 
			
		||||
 | 
			
		||||
nano::uint256_union nano::wallet_store::check (store::transaction const & transaction_a)
 | 
			
		||||
{
 | 
			
		||||
	nano::wallet_value value (entry_get_raw (transaction_a, nano::wallet_store::check_special));
 | 
			
		||||
| 
						 | 
				
			
			@ -548,7 +551,8 @@ bool nano::wallet_store::exists (store::transaction const & transaction_a, nano:
 | 
			
		|||
void nano::wallet_store::serialize_json (store::transaction const & transaction_a, std::string & string_a)
 | 
			
		||||
{
 | 
			
		||||
	boost::property_tree::ptree tree;
 | 
			
		||||
	for (store::iterator<nano::uint256_union, nano::wallet_value> i (std::make_unique<nano::store::lmdb::iterator<nano::uint256_union, nano::wallet_value>> (transaction_a, env, handle)), n (nullptr); i != n; ++i)
 | 
			
		||||
	using iterator = store::typed_iterator<nano::uint256_union, nano::wallet_value>;
 | 
			
		||||
	for (iterator i{ store::iterator{ store::lmdb::iterator::begin (env.tx (transaction_a), handle) } }, n{ store::iterator{ store::lmdb::iterator::end (env.tx (transaction_a), handle) } }; i != n; ++i)
 | 
			
		||||
	{
 | 
			
		||||
		tree.put (i->first.to_string (), i->second.key.to_string ());
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1359,13 +1363,15 @@ nano::wallets::wallets (bool error_a, nano::node & node_a) :
 | 
			
		|||
		status |= mdb_dbi_open (env.tx (transaction), "send_action_ids", MDB_CREATE, &send_action_ids);
 | 
			
		||||
		release_assert (status == 0);
 | 
			
		||||
		std::string beginning (nano::uint256_union (0).to_string ());
 | 
			
		||||
		nano::store::lmdb::db_val beginning_val{ beginning.size (), const_cast<char *> (beginning.c_str ()) };
 | 
			
		||||
		std::string end ((nano::uint256_union (nano::uint256_t (0) - nano::uint256_t (1))).to_string ());
 | 
			
		||||
		store::iterator<std::array<char, 64>, nano::no_value> i (std::make_unique<nano::store::lmdb::iterator<std::array<char, 64>, nano::no_value>> (transaction, env, handle, nano::store::lmdb::db_val (beginning.size (), const_cast<char *> (beginning.c_str ()))));
 | 
			
		||||
		store::iterator<std::array<char, 64>, nano::no_value> n (std::make_unique<nano::store::lmdb::iterator<std::array<char, 64>, nano::no_value>> (transaction, env, handle, nano::store::lmdb::db_val (end.size (), const_cast<char *> (end.c_str ()))));
 | 
			
		||||
		nano::store::lmdb::db_val end_val{ end.size (), const_cast<char *> (end.c_str ()) };
 | 
			
		||||
		store::iterator i{ store::lmdb::iterator::lower_bound (env.tx (transaction), handle, beginning_val) };
 | 
			
		||||
		store::iterator n{ store::lmdb::iterator::lower_bound (env.tx (transaction), handle, end_val) };
 | 
			
		||||
		for (; i != n; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			nano::wallet_id id;
 | 
			
		||||
			std::string text (i->first.data (), i->first.size ());
 | 
			
		||||
			std::string text (reinterpret_cast<char const *> (i->first.data ()), i->first.size ());
 | 
			
		||||
			auto error (id.decode_hex (text));
 | 
			
		||||
			release_assert (!error);
 | 
			
		||||
			release_assert (items.find (id) == items.end ());
 | 
			
		||||
| 
						 | 
				
			
			@ -1488,13 +1494,15 @@ void nano::wallets::reload ()
 | 
			
		|||
	auto transaction (tx_begin_write ());
 | 
			
		||||
	std::unordered_set<nano::uint256_union> stored_items;
 | 
			
		||||
	std::string beginning (nano::uint256_union (0).to_string ());
 | 
			
		||||
	nano::store::lmdb::db_val beginning_val{ beginning.size (), const_cast<char *> (beginning.c_str ()) };
 | 
			
		||||
	std::string end ((nano::uint256_union (nano::uint256_t (0) - nano::uint256_t (1))).to_string ());
 | 
			
		||||
	store::iterator<std::array<char, 64>, nano::no_value> i (std::make_unique<nano::store::lmdb::iterator<std::array<char, 64>, nano::no_value>> (transaction, env, handle, nano::store::lmdb::db_val (beginning.size (), const_cast<char *> (beginning.c_str ()))));
 | 
			
		||||
	store::iterator<std::array<char, 64>, nano::no_value> n (std::make_unique<nano::store::lmdb::iterator<std::array<char, 64>, nano::no_value>> (transaction, env, handle, nano::store::lmdb::db_val (end.size (), const_cast<char *> (end.c_str ()))));
 | 
			
		||||
	nano::store::lmdb::db_val end_val{ end.size (), const_cast<char *> (end.c_str ()) };
 | 
			
		||||
	store::iterator i{ store::lmdb::iterator::lower_bound (env.tx (transaction), handle, beginning_val) };
 | 
			
		||||
	store::iterator n{ store::lmdb::iterator::lower_bound (env.tx (transaction), handle, end_val) };
 | 
			
		||||
	for (; i != n; ++i)
 | 
			
		||||
	{
 | 
			
		||||
		nano::wallet_id id;
 | 
			
		||||
		std::string text (i->first.data (), i->first.size ());
 | 
			
		||||
		std::string text (reinterpret_cast<char const *> (i->first.data ()), i->first.size ());
 | 
			
		||||
		auto error (id.decode_hex (text));
 | 
			
		||||
		debug_assert (!error);
 | 
			
		||||
		// New wallet
 | 
			
		||||
| 
						 | 
				
			
			@ -1755,20 +1763,22 @@ nano::uint128_t const nano::wallets::high_priority = std::numeric_limits<nano::u
 | 
			
		|||
 | 
			
		||||
auto nano::wallet_store::begin (store::transaction const & transaction_a) -> iterator
 | 
			
		||||
{
 | 
			
		||||
	iterator result (std::make_unique<nano::store::lmdb::iterator<nano::account, nano::wallet_value>> (transaction_a, env, handle, nano::store::lmdb::db_val (nano::account (special_count))));
 | 
			
		||||
	return result;
 | 
			
		||||
	nano::account account{ special_count };
 | 
			
		||||
	nano::store::lmdb::db_val val{ account };
 | 
			
		||||
	return iterator{ store::iterator{ store::lmdb::iterator::lower_bound (env.tx (transaction_a), handle, val) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::wallet_store::begin (store::transaction const & transaction_a, nano::account const & key) -> iterator
 | 
			
		||||
{
 | 
			
		||||
	iterator result (std::make_unique<nano::store::lmdb::iterator<nano::account, nano::wallet_value>> (transaction_a, env, handle, nano::store::lmdb::db_val (key)));
 | 
			
		||||
	return result;
 | 
			
		||||
	nano::account account (key);
 | 
			
		||||
	nano::store::lmdb::db_val val{ account };
 | 
			
		||||
	return iterator{ store::iterator{ store::lmdb::iterator::lower_bound (env.tx (transaction_a), handle, val) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::wallet_store::find (store::transaction const & transaction_a, nano::account const & key) -> iterator
 | 
			
		||||
{
 | 
			
		||||
	auto result (begin (transaction_a, key));
 | 
			
		||||
	iterator end{ nullptr };
 | 
			
		||||
	auto result = begin (transaction_a, key);
 | 
			
		||||
	auto end = this->end (transaction_a);
 | 
			
		||||
	if (result != end)
 | 
			
		||||
	{
 | 
			
		||||
		if (result->first == key)
 | 
			
		||||
| 
						 | 
				
			
			@ -1789,7 +1799,7 @@ auto nano::wallet_store::find (store::transaction const & transaction_a, nano::a
 | 
			
		|||
 | 
			
		||||
auto nano::wallet_store::end (store::transaction const & transaction_a) -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ store::lmdb::iterator::end (env.tx (transaction_a), handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nano::mdb_wallets_store::mdb_wallets_store (std::filesystem::path const & path_a, nano::lmdb_config const & lmdb_config_a) :
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@
 | 
			
		|||
#include <nano/store/component.hpp>
 | 
			
		||||
#include <nano/store/lmdb/lmdb.hpp>
 | 
			
		||||
#include <nano/store/lmdb/wallet_value.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator.hpp>
 | 
			
		||||
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
| 
						 | 
				
			
			@ -58,7 +59,7 @@ enum class key_type
 | 
			
		|||
class wallet_store final
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	using iterator = store::iterator<nano::account, nano::wallet_value>;
 | 
			
		||||
	using iterator = store::typed_iterator<nano::account, nano::wallet_value>;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	wallet_store (bool &, nano::kdf &, store::transaction &, store::lmdb::env &, nano::account, unsigned, std::string const &);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,6 @@ add_library(
 | 
			
		|||
  db_val.hpp
 | 
			
		||||
  db_val_impl.hpp
 | 
			
		||||
  iterator.hpp
 | 
			
		||||
  iterator_impl.hpp
 | 
			
		||||
  final_vote.hpp
 | 
			
		||||
  lmdb/account.hpp
 | 
			
		||||
  lmdb/block.hpp
 | 
			
		||||
| 
						 | 
				
			
			@ -33,6 +32,8 @@ add_library(
 | 
			
		|||
  pending.hpp
 | 
			
		||||
  pruned.hpp
 | 
			
		||||
  rep_weight.hpp
 | 
			
		||||
  reverse_iterator.hpp
 | 
			
		||||
  reverse_iterator_templ.hpp
 | 
			
		||||
  rocksdb/account.hpp
 | 
			
		||||
  rocksdb/block.hpp
 | 
			
		||||
  rocksdb/confirmation_height.hpp
 | 
			
		||||
| 
						 | 
				
			
			@ -51,6 +52,8 @@ add_library(
 | 
			
		|||
  rocksdb/version.hpp
 | 
			
		||||
  tables.hpp
 | 
			
		||||
  transaction.hpp
 | 
			
		||||
  typed_iterator.hpp
 | 
			
		||||
  typed_iterator_templ.hpp
 | 
			
		||||
  version.hpp
 | 
			
		||||
  versioning.hpp
 | 
			
		||||
  account.cpp
 | 
			
		||||
| 
						 | 
				
			
			@ -59,13 +62,13 @@ add_library(
 | 
			
		|||
  confirmation_height.cpp
 | 
			
		||||
  db_val.cpp
 | 
			
		||||
  iterator.cpp
 | 
			
		||||
  iterator_impl.cpp
 | 
			
		||||
  final_vote.cpp
 | 
			
		||||
  lmdb/account.cpp
 | 
			
		||||
  lmdb/block.cpp
 | 
			
		||||
  lmdb/confirmation_height.cpp
 | 
			
		||||
  lmdb/db_val.cpp
 | 
			
		||||
  lmdb/final_vote.cpp
 | 
			
		||||
  lmdb/iterator.cpp
 | 
			
		||||
  lmdb/lmdb.cpp
 | 
			
		||||
  lmdb/lmdb_env.cpp
 | 
			
		||||
  lmdb/transaction.cpp
 | 
			
		||||
| 
						 | 
				
			
			@ -80,11 +83,13 @@ add_library(
 | 
			
		|||
  peer.cpp
 | 
			
		||||
  pending.cpp
 | 
			
		||||
  pruned.cpp
 | 
			
		||||
  rep_weight.cpp
 | 
			
		||||
  rocksdb/account.cpp
 | 
			
		||||
  rocksdb/block.cpp
 | 
			
		||||
  rocksdb/confirmation_height.cpp
 | 
			
		||||
  rocksdb/db_val.cpp
 | 
			
		||||
  rocksdb/final_vote.cpp
 | 
			
		||||
  rocksdb/iterator.cpp
 | 
			
		||||
  rocksdb/online_weight.cpp
 | 
			
		||||
  rocksdb/peer.cpp
 | 
			
		||||
  rocksdb/pending.cpp
 | 
			
		||||
| 
						 | 
				
			
			@ -95,6 +100,7 @@ add_library(
 | 
			
		|||
  rocksdb/utility.cpp
 | 
			
		||||
  rocksdb/version.cpp
 | 
			
		||||
  transaction.cpp
 | 
			
		||||
  typed_iterator.cpp
 | 
			
		||||
  version.cpp
 | 
			
		||||
  versioning.cpp
 | 
			
		||||
  write_queue.hpp
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,9 @@
 | 
			
		|||
#include <nano/store/account.hpp>
 | 
			
		||||
#include <nano/store/reverse_iterator_templ.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator_templ.hpp>
 | 
			
		||||
 | 
			
		||||
template class nano::store::typed_iterator<nano::account, nano::account_info>;
 | 
			
		||||
template class nano::store::reverse_iterator<nano::store::typed_iterator<nano::account, nano::account_info>>;
 | 
			
		||||
 | 
			
		||||
std::optional<nano::account_info> nano::store::account::get (store::transaction const & transaction, nano::account const & account)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -13,3 +18,15 @@ std::optional<nano::account_info> nano::store::account::get (store::transaction
 | 
			
		|||
		return std::nullopt;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::account::rbegin (store::transaction const & tx) const -> reverse_iterator
 | 
			
		||||
{
 | 
			
		||||
	auto iter = end (tx);
 | 
			
		||||
	--iter;
 | 
			
		||||
	return reverse_iterator{ std::move (iter) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::account::rend (transaction const & tx) const -> reverse_iterator
 | 
			
		||||
{
 | 
			
		||||
	return reverse_iterator{ end (tx) };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,8 @@
 | 
			
		|||
#include <nano/lib/numbers.hpp>
 | 
			
		||||
#include <nano/store/component.hpp>
 | 
			
		||||
#include <nano/store/db_val_impl.hpp>
 | 
			
		||||
#include <nano/store/iterator.hpp>
 | 
			
		||||
#include <nano/store/reverse_iterator.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator.hpp>
 | 
			
		||||
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -20,19 +21,21 @@ namespace nano::store
 | 
			
		|||
class account
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	using iterator = store::iterator<nano::account, nano::account_info>;
 | 
			
		||||
	using iterator = typed_iterator<nano::account, nano::account_info>;
 | 
			
		||||
	using reverse_iterator = store::reverse_iterator<iterator>;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	virtual void put (store::write_transaction const &, nano::account const &, nano::account_info const &) = 0;
 | 
			
		||||
	virtual bool get (store::transaction const &, nano::account const &, nano::account_info &) = 0;
 | 
			
		||||
	std::optional<nano::account_info> get (store::transaction const &, nano::account const &);
 | 
			
		||||
	virtual void del (store::write_transaction const &, nano::account const &) = 0;
 | 
			
		||||
	virtual bool exists (store::transaction const &, nano::account const &) = 0;
 | 
			
		||||
	virtual size_t count (store::transaction const &) = 0;
 | 
			
		||||
	virtual iterator begin (store::transaction const &, nano::account const &) const = 0;
 | 
			
		||||
	virtual iterator begin (store::transaction const &) const = 0;
 | 
			
		||||
	virtual iterator rbegin (store::transaction const &) const = 0;
 | 
			
		||||
	virtual iterator end (store::transaction const & transaction_a) const = 0;
 | 
			
		||||
	virtual void for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const &) const = 0;
 | 
			
		||||
	virtual void put (write_transaction const & tx, nano::account const &, nano::account_info const &) = 0;
 | 
			
		||||
	virtual bool get (transaction const & tx, nano::account const &, nano::account_info &) = 0;
 | 
			
		||||
	std::optional<nano::account_info> get (transaction const & tx, nano::account const &);
 | 
			
		||||
	virtual void del (write_transaction const & tx, nano::account const &) = 0;
 | 
			
		||||
	virtual bool exists (transaction const & tx, nano::account const &) = 0;
 | 
			
		||||
	virtual size_t count (transaction const & tx) = 0;
 | 
			
		||||
	virtual iterator begin (transaction const & tx, nano::account const &) const = 0;
 | 
			
		||||
	virtual iterator begin (transaction const & tx) const = 0;
 | 
			
		||||
	reverse_iterator rbegin (transaction const & tx) const;
 | 
			
		||||
	reverse_iterator rend (transaction const & tx) const;
 | 
			
		||||
	virtual iterator end (transaction const & tx) const = 0;
 | 
			
		||||
	virtual void for_each_par (std::function<void (read_transaction const & tx, iterator, iterator)> const &) const = 0;
 | 
			
		||||
};
 | 
			
		||||
} // namespace nano::store
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1,4 @@
 | 
			
		|||
#include <nano/store/block.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator_templ.hpp>
 | 
			
		||||
 | 
			
		||||
template class nano::store::typed_iterator<nano::block_hash, nano::store::block_w_sideband>;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@
 | 
			
		|||
#include <nano/lib/numbers.hpp>
 | 
			
		||||
#include <nano/store/block_w_sideband.hpp>
 | 
			
		||||
#include <nano/store/component.hpp>
 | 
			
		||||
#include <nano/store/iterator.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator.hpp>
 | 
			
		||||
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <optional>
 | 
			
		||||
| 
						 | 
				
			
			@ -22,21 +22,21 @@ namespace nano::store
 | 
			
		|||
class block
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	using iterator = store::iterator<nano::block_hash, block_w_sideband>;
 | 
			
		||||
	using iterator = typed_iterator<nano::block_hash, block_w_sideband>;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	virtual void put (store::write_transaction const &, nano::block_hash const &, nano::block const &) = 0;
 | 
			
		||||
	virtual void raw_put (store::write_transaction const &, std::vector<uint8_t> const &, nano::block_hash const &) = 0;
 | 
			
		||||
	virtual std::optional<nano::block_hash> successor (store::transaction const &, nano::block_hash const &) const = 0;
 | 
			
		||||
	virtual void successor_clear (store::write_transaction const &, nano::block_hash const &) = 0;
 | 
			
		||||
	virtual std::shared_ptr<nano::block> get (store::transaction const &, nano::block_hash const &) const = 0;
 | 
			
		||||
	virtual std::shared_ptr<nano::block> random (store::transaction const &) = 0;
 | 
			
		||||
	virtual void del (store::write_transaction const &, nano::block_hash const &) = 0;
 | 
			
		||||
	virtual bool exists (store::transaction const &, nano::block_hash const &) = 0;
 | 
			
		||||
	virtual uint64_t count (store::transaction const &) = 0;
 | 
			
		||||
	virtual iterator begin (store::transaction const &, nano::block_hash const &) const = 0;
 | 
			
		||||
	virtual iterator begin (store::transaction const &) const = 0;
 | 
			
		||||
	virtual iterator end (store::transaction const &) const = 0;
 | 
			
		||||
	virtual void for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const & action_a) const = 0;
 | 
			
		||||
	virtual void put (write_transaction const & tx, nano::block_hash const &, nano::block const &) = 0;
 | 
			
		||||
	virtual void raw_put (write_transaction const & tx, std::vector<uint8_t> const &, nano::block_hash const &) = 0;
 | 
			
		||||
	virtual std::optional<nano::block_hash> successor (transaction const & tx, nano::block_hash const &) const = 0;
 | 
			
		||||
	virtual void successor_clear (write_transaction const & tx, nano::block_hash const &) = 0;
 | 
			
		||||
	virtual std::shared_ptr<nano::block> get (transaction const & tx, nano::block_hash const &) const = 0;
 | 
			
		||||
	virtual std::shared_ptr<nano::block> random (transaction const & tx) = 0;
 | 
			
		||||
	virtual void del (write_transaction const & tx, nano::block_hash const &) = 0;
 | 
			
		||||
	virtual bool exists (transaction const & tx, nano::block_hash const &) = 0;
 | 
			
		||||
	virtual uint64_t count (transaction const & tx) = 0;
 | 
			
		||||
	virtual iterator begin (transaction const & tx, nano::block_hash const &) const = 0;
 | 
			
		||||
	virtual iterator begin (transaction const & tx) const = 0;
 | 
			
		||||
	virtual iterator end (transaction const & tx) const = 0;
 | 
			
		||||
	virtual void for_each_par (std::function<void (read_transaction const & tx, iterator, iterator)> const & action_a) const = 0;
 | 
			
		||||
};
 | 
			
		||||
} // namespace nano::store
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,7 @@
 | 
			
		|||
#include <nano/store/confirmation_height.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator_templ.hpp>
 | 
			
		||||
 | 
			
		||||
template class nano::store::typed_iterator<nano::account, nano::confirmation_height_info>;
 | 
			
		||||
 | 
			
		||||
std::optional<nano::confirmation_height_info> nano::store::confirmation_height::get (store::transaction const & transaction, nano::account const & account)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
 | 
			
		||||
#include <nano/lib/numbers.hpp>
 | 
			
		||||
#include <nano/store/component.hpp>
 | 
			
		||||
#include <nano/store/iterator.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator.hpp>
 | 
			
		||||
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ namespace nano::store
 | 
			
		|||
class confirmation_height
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	using iterator = store::iterator<nano::account, nano::confirmation_height_info>;
 | 
			
		||||
	using iterator = typed_iterator<nano::account, nano::confirmation_height_info>;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	virtual void put (store::write_transaction const & transaction_a, nano::account const & account_a, nano::confirmation_height_info const & confirmation_height_info_a) = 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1,4 @@
 | 
			
		|||
#include <nano/store/final_vote.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator_templ.hpp>
 | 
			
		||||
 | 
			
		||||
template class nano::store::typed_iterator<nano::qualified_root, nano::block_hash>;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
 | 
			
		||||
#include <nano/lib/numbers.hpp>
 | 
			
		||||
#include <nano/store/component.hpp>
 | 
			
		||||
#include <nano/store/iterator.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator.hpp>
 | 
			
		||||
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ namespace nano::store
 | 
			
		|||
class final_vote
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	using iterator = store::iterator<nano::qualified_root, nano::block_hash>;
 | 
			
		||||
	using iterator = typed_iterator<nano::qualified_root, nano::block_hash>;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	virtual bool put (store::write_transaction const & transaction_a, nano::qualified_root const & root_a, nano::block_hash const & hash_a) = 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1,81 @@
 | 
			
		|||
#include <nano/lib/utility.hpp>
 | 
			
		||||
#include <nano/store/iterator.hpp>
 | 
			
		||||
 | 
			
		||||
namespace nano::store
 | 
			
		||||
{
 | 
			
		||||
void iterator::update ()
 | 
			
		||||
{
 | 
			
		||||
	std::visit ([&] (auto && arg) {
 | 
			
		||||
		if (!arg.is_end ())
 | 
			
		||||
		{
 | 
			
		||||
			this->current = arg.span ();
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			current = std::monostate{};
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	internals);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
iterator::iterator (std::variant<lmdb::iterator, rocksdb::iterator> && internals) noexcept :
 | 
			
		||||
	internals{ std::move (internals) }
 | 
			
		||||
{
 | 
			
		||||
	update ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
iterator::iterator (iterator && other) noexcept :
 | 
			
		||||
	internals{ std::move (other.internals) }
 | 
			
		||||
{
 | 
			
		||||
	current = std::move (other.current);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator= (iterator && other) noexcept -> iterator &
 | 
			
		||||
{
 | 
			
		||||
	internals = std::move (other.internals);
 | 
			
		||||
	current = std::move (other.current);
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator++ () -> iterator &
 | 
			
		||||
{
 | 
			
		||||
	std::visit ([] (auto && arg) {
 | 
			
		||||
		++arg;
 | 
			
		||||
	},
 | 
			
		||||
	internals);
 | 
			
		||||
	update ();
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator-- () -> iterator &
 | 
			
		||||
{
 | 
			
		||||
	std::visit ([] (auto && arg) {
 | 
			
		||||
		--arg;
 | 
			
		||||
	},
 | 
			
		||||
	internals);
 | 
			
		||||
	update ();
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator->() const -> const_pointer
 | 
			
		||||
{
 | 
			
		||||
	release_assert (!is_end ());
 | 
			
		||||
	return std::get_if<value_type> (¤t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator* () const -> const_reference
 | 
			
		||||
{
 | 
			
		||||
	release_assert (!is_end ());
 | 
			
		||||
	return std::get<value_type> (current);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator== (iterator const & other) const -> bool
 | 
			
		||||
{
 | 
			
		||||
	return internals == other.internals;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool iterator::is_end () const
 | 
			
		||||
{
 | 
			
		||||
	return std::holds_alternative<std::monostate> (current);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,69 +1,57 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <nano/store/iterator_impl.hpp>
 | 
			
		||||
#include <nano/store/lmdb/iterator.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/iterator.hpp>
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <span>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
namespace nano::store
 | 
			
		||||
{
 | 
			
		||||
/**
 | 
			
		||||
 * Iterates the key/value pairs of a transaction
 | 
			
		||||
 * @class iterator
 | 
			
		||||
 * @brief A generic database iterator for LMDB or RocksDB.
 | 
			
		||||
 *
 | 
			
		||||
 * This class represents an iterator for either LMDB or RocksDB (Persistent Key-Value Store) databases.
 | 
			
		||||
 * It is a circular iterator, meaning that the end() sentinel value is always in the iteration cycle.
 | 
			
		||||
 *
 | 
			
		||||
 * Key characteristics:
 | 
			
		||||
 * - Decrementing the end iterator points to the last key in the database.
 | 
			
		||||
 * - Incrementing the end iterator points to the first key in the database.
 | 
			
		||||
 * - Internally uses either an LMDB or RocksDB iterator, abstracted through a std::variant.
 | 
			
		||||
 */
 | 
			
		||||
template <typename T, typename U>
 | 
			
		||||
class iterator final
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	iterator (std::nullptr_t)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	iterator (std::unique_ptr<iterator_impl<T, U>> impl_a) :
 | 
			
		||||
		impl (std::move (impl_a))
 | 
			
		||||
	{
 | 
			
		||||
		impl->fill (current);
 | 
			
		||||
	}
 | 
			
		||||
	iterator (iterator<T, U> && other_a) :
 | 
			
		||||
		current (std::move (other_a.current)),
 | 
			
		||||
		impl (std::move (other_a.impl))
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	iterator<T, U> & operator++ ()
 | 
			
		||||
	{
 | 
			
		||||
		++*impl;
 | 
			
		||||
		impl->fill (current);
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
	iterator<T, U> & operator-- ()
 | 
			
		||||
	{
 | 
			
		||||
		--*impl;
 | 
			
		||||
		impl->fill (current);
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
	iterator<T, U> & operator= (iterator<T, U> && other_a) noexcept
 | 
			
		||||
	{
 | 
			
		||||
		impl = std::move (other_a.impl);
 | 
			
		||||
		current = std::move (other_a.current);
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
	iterator<T, U> & operator= (iterator<T, U> const &) = delete;
 | 
			
		||||
	std::pair<T, U> * operator->()
 | 
			
		||||
	{
 | 
			
		||||
		return ¤t;
 | 
			
		||||
	}
 | 
			
		||||
	std::pair<T, U> const & operator* () const
 | 
			
		||||
	{
 | 
			
		||||
		return current;
 | 
			
		||||
	}
 | 
			
		||||
	bool operator== (iterator<T, U> const & other_a) const
 | 
			
		||||
	{
 | 
			
		||||
		return (impl == nullptr && other_a.impl == nullptr) || (impl != nullptr && *impl == other_a.impl.get ()) || (other_a.impl != nullptr && *other_a.impl == impl.get ());
 | 
			
		||||
	}
 | 
			
		||||
	bool operator!= (iterator<T, U> const & other_a) const
 | 
			
		||||
	{
 | 
			
		||||
		return !(*this == other_a);
 | 
			
		||||
	}
 | 
			
		||||
	using iterator_category = std::bidirectional_iterator_tag;
 | 
			
		||||
	using value_type = std::pair<std::span<uint8_t const>, std::span<uint8_t const>>;
 | 
			
		||||
	using pointer = value_type *;
 | 
			
		||||
	using const_pointer = value_type const *;
 | 
			
		||||
	using reference = value_type &;
 | 
			
		||||
	using const_reference = value_type const &;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	std::pair<T, U> current;
 | 
			
		||||
	std::unique_ptr<iterator_impl<T, U>> impl;
 | 
			
		||||
	std::variant<lmdb::iterator, rocksdb::iterator> internals;
 | 
			
		||||
	std::variant<std::monostate, value_type> current;
 | 
			
		||||
	void update ();
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	iterator (std::variant<lmdb::iterator, rocksdb::iterator> && internals) noexcept;
 | 
			
		||||
 | 
			
		||||
	iterator (iterator const &) = delete;
 | 
			
		||||
	auto operator= (iterator const &) -> iterator & = delete;
 | 
			
		||||
 | 
			
		||||
	iterator (iterator && other) noexcept;
 | 
			
		||||
	auto operator= (iterator && other) noexcept -> iterator &;
 | 
			
		||||
 | 
			
		||||
	auto operator++ () -> iterator &;
 | 
			
		||||
	auto operator-- () -> iterator &;
 | 
			
		||||
	auto operator->() const -> const_pointer;
 | 
			
		||||
	auto operator* () const -> const_reference;
 | 
			
		||||
	auto operator== (iterator const & other) const -> bool;
 | 
			
		||||
	bool is_end () const;
 | 
			
		||||
};
 | 
			
		||||
} // namespace nano::store
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
#include <nano/store/iterator_impl.hpp>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,43 +0,0 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <nano/lib/utility.hpp>
 | 
			
		||||
#include <nano/store/transaction.hpp>
 | 
			
		||||
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
namespace nano::store
 | 
			
		||||
{
 | 
			
		||||
template <typename T, typename U>
 | 
			
		||||
class iterator_impl
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	explicit iterator_impl (transaction const & transaction_a) :
 | 
			
		||||
		txn{ transaction_a },
 | 
			
		||||
		transaction_epoch{ transaction_a.epoch () }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	virtual ~iterator_impl ()
 | 
			
		||||
	{
 | 
			
		||||
		debug_assert (transaction_epoch == txn.epoch (), "invalid iterator-transaction lifetime detected");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual iterator_impl<T, U> & operator++ () = 0;
 | 
			
		||||
	virtual iterator_impl<T, U> & operator-- () = 0;
 | 
			
		||||
	virtual bool operator== (iterator_impl<T, U> const & other_a) const = 0;
 | 
			
		||||
	virtual bool is_end_sentinal () const = 0;
 | 
			
		||||
	virtual void fill (std::pair<T, U> &) const = 0;
 | 
			
		||||
	iterator_impl<T, U> & operator= (iterator_impl<T, U> const &) = delete;
 | 
			
		||||
	bool operator== (iterator_impl<T, U> const * other_a) const
 | 
			
		||||
	{
 | 
			
		||||
		return (other_a != nullptr && *this == *other_a) || (other_a == nullptr && is_end_sentinal ());
 | 
			
		||||
	}
 | 
			
		||||
	bool operator!= (iterator_impl<T, U> const & other_a) const
 | 
			
		||||
	{
 | 
			
		||||
		return !(*this == other_a);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
	transaction const & txn;
 | 
			
		||||
	transaction::epoch_t const transaction_epoch;
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -45,22 +45,18 @@ size_t nano::store::lmdb::account::count (store::transaction const & transaction
 | 
			
		|||
 | 
			
		||||
auto nano::store::lmdb::account::begin (store::transaction const & transaction, nano::account const & account) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::account, nano::account_info> (transaction, tables::accounts, account);
 | 
			
		||||
	lmdb::db_val val{ account };
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::lower_bound (store.env.tx (transaction), accounts_handle, val) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::account::begin (store::transaction const & transaction) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::account, nano::account_info> (transaction, tables::accounts);
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::begin (store.env.tx (transaction), accounts_handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::account::rbegin (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
auto nano::store::lmdb::account::end (store::transaction const & tx) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::account, nano::account_info> (transaction_a, tables::accounts, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::account::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::end (store.env.tx (tx), accounts_handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::store::lmdb::account::for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const & action_a) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,6 @@ public:
 | 
			
		|||
	size_t count (store::transaction const & transaction_a) override;
 | 
			
		||||
	iterator begin (store::transaction const & transaction_a, nano::account const & account_a) const override;
 | 
			
		||||
	iterator begin (store::transaction const & transaction_a) const override;
 | 
			
		||||
	iterator rbegin (store::transaction const & transaction_a) const override;
 | 
			
		||||
	iterator end (store::transaction const & transaction_a) const override;
 | 
			
		||||
	void for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const & action_a) const override;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -137,17 +137,18 @@ uint64_t nano::store::lmdb::block::count (store::transaction const & transaction
 | 
			
		|||
 | 
			
		||||
auto nano::store::lmdb::block::begin (store::transaction const & transaction) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::block_hash, nano::store::block_w_sideband> (transaction, tables::blocks);
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::begin (store.env.tx (transaction), blocks_handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::block::begin (store::transaction const & transaction, nano::block_hash const & hash) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::block_hash, nano::store::block_w_sideband> (transaction, tables::blocks, hash);
 | 
			
		||||
	lmdb::db_val val{ hash };
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::lower_bound (store.env.tx (transaction), blocks_handle, val) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::block::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::end (store.env.tx (transaction_a), blocks_handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::store::lmdb::block::for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const & action_a) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,17 +61,18 @@ void nano::store::lmdb::confirmation_height::clear (store::write_transaction con
 | 
			
		|||
 | 
			
		||||
auto nano::store::lmdb::confirmation_height::begin (store::transaction const & transaction, nano::account const & account) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::account, nano::confirmation_height_info> (transaction, tables::confirmation_height, account);
 | 
			
		||||
	lmdb::db_val val{ account };
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::lower_bound (store.env.tx (transaction), confirmation_height_handle, val) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::confirmation_height::begin (store::transaction const & transaction) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::account, nano::confirmation_height_info> (transaction, tables::confirmation_height);
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::begin (store.env.tx (transaction), confirmation_height_handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::confirmation_height::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::end (store.env.tx (transaction_a), confirmation_height_handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::store::lmdb::confirmation_height::for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const & action_a) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,17 +66,18 @@ void nano::store::lmdb::final_vote::clear (store::write_transaction const & tran
 | 
			
		|||
 | 
			
		||||
auto nano::store::lmdb::final_vote::begin (store::transaction const & transaction, nano::qualified_root const & root) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::qualified_root, nano::block_hash> (transaction, tables::final_votes, root);
 | 
			
		||||
	lmdb::db_val val{ root };
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::lower_bound (store.env.tx (transaction), final_votes_handle, val) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::final_vote::begin (store::transaction const & transaction) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::qualified_root, nano::block_hash> (transaction, tables::final_votes);
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::begin (store.env.tx (transaction), final_votes_handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::final_vote::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::end (store.env.tx (transaction_a), final_votes_handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::store::lmdb::final_vote::for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const & action_a) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										133
									
								
								nano/store/lmdb/iterator.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								nano/store/lmdb/iterator.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,133 @@
 | 
			
		|||
#include <nano/lib/utility.hpp>
 | 
			
		||||
#include <nano/store/lmdb/iterator.hpp>
 | 
			
		||||
 | 
			
		||||
namespace nano::store::lmdb
 | 
			
		||||
{
 | 
			
		||||
auto iterator::span () const -> std::pair<std::span<uint8_t const>, std::span<uint8_t const>>
 | 
			
		||||
{
 | 
			
		||||
	auto & current = operator* ();
 | 
			
		||||
	std::span<uint8_t const> key{ reinterpret_cast<uint8_t const *> (current.first.mv_data), current.first.mv_size };
 | 
			
		||||
	std::span<uint8_t const> value{ reinterpret_cast<uint8_t const *> (current.second.mv_data), current.second.mv_size };
 | 
			
		||||
	return std::make_pair (key, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::is_end () const -> bool
 | 
			
		||||
{
 | 
			
		||||
	return std::holds_alternative<std::monostate> (current);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void iterator::update (int status)
 | 
			
		||||
{
 | 
			
		||||
	if (status == MDB_SUCCESS)
 | 
			
		||||
	{
 | 
			
		||||
		value_type init;
 | 
			
		||||
		auto status = mdb_cursor_get (cursor, &init.first, &init.second, MDB_GET_CURRENT);
 | 
			
		||||
		release_assert (status == MDB_SUCCESS);
 | 
			
		||||
		current = init;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		current = std::monostate{};
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
iterator::iterator (MDB_txn * tx, MDB_dbi dbi) noexcept
 | 
			
		||||
{
 | 
			
		||||
	auto open_status = mdb_cursor_open (tx, dbi, &cursor);
 | 
			
		||||
	release_assert (open_status == MDB_SUCCESS);
 | 
			
		||||
	this->current = std::monostate{};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::begin (MDB_txn * tx, MDB_dbi dbi) -> iterator
 | 
			
		||||
{
 | 
			
		||||
	iterator result{ tx, dbi };
 | 
			
		||||
	++result;
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::end (MDB_txn * tx, MDB_dbi dbi) -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ tx, dbi };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::lower_bound (MDB_txn * tx, MDB_dbi dbi, MDB_val const & lower_bound) -> iterator
 | 
			
		||||
{
 | 
			
		||||
	iterator result{ tx, dbi };
 | 
			
		||||
	auto status = mdb_cursor_get (result.cursor, const_cast<MDB_val *> (&lower_bound), nullptr, MDB_SET_RANGE);
 | 
			
		||||
	result.update (status);
 | 
			
		||||
	return std::move (result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
iterator::iterator (iterator && other) noexcept
 | 
			
		||||
{
 | 
			
		||||
	*this = std::move (other);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
iterator::~iterator ()
 | 
			
		||||
{
 | 
			
		||||
	if (cursor)
 | 
			
		||||
	{
 | 
			
		||||
		mdb_cursor_close (cursor);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator= (iterator && other) noexcept -> iterator &
 | 
			
		||||
{
 | 
			
		||||
	cursor = other.cursor;
 | 
			
		||||
	other.cursor = nullptr;
 | 
			
		||||
	current = other.current;
 | 
			
		||||
	other.current = std::monostate{};
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator++ () -> iterator &
 | 
			
		||||
{
 | 
			
		||||
	auto operation = is_end () ? MDB_FIRST : MDB_NEXT;
 | 
			
		||||
	auto status = mdb_cursor_get (cursor, nullptr, nullptr, operation);
 | 
			
		||||
	release_assert (status == MDB_SUCCESS || status == MDB_NOTFOUND);
 | 
			
		||||
	update (status);
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator-- () -> iterator &
 | 
			
		||||
{
 | 
			
		||||
	auto operation = is_end () ? MDB_LAST : MDB_PREV;
 | 
			
		||||
	auto status = mdb_cursor_get (cursor, nullptr, nullptr, operation);
 | 
			
		||||
	release_assert (status == MDB_SUCCESS || status == MDB_NOTFOUND);
 | 
			
		||||
	update (status);
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator->() const -> const_pointer
 | 
			
		||||
{
 | 
			
		||||
	release_assert (!is_end ());
 | 
			
		||||
	return std::get_if<value_type> (¤t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator* () const -> const_reference
 | 
			
		||||
{
 | 
			
		||||
	release_assert (!is_end ());
 | 
			
		||||
	return std::get<value_type> (current);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator== (iterator const & other) const -> bool
 | 
			
		||||
{
 | 
			
		||||
	if (is_end () != other.is_end ())
 | 
			
		||||
	{
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	if (is_end ())
 | 
			
		||||
	{
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	auto & lhs = std::get<value_type> (current);
 | 
			
		||||
	auto & rhs = std::get<value_type> (other.current);
 | 
			
		||||
	auto result = lhs.first.mv_data == rhs.first.mv_data;
 | 
			
		||||
	if (!result)
 | 
			
		||||
	{
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
	debug_assert (std::make_pair (lhs.first.mv_data, lhs.first.mv_size) == std::make_pair (rhs.first.mv_data, rhs.first.mv_size) && std::make_pair (lhs.second.mv_data, lhs.second.mv_size) == std::make_pair (rhs.second.mv_data, rhs.second.mv_size));
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
} // namespace nano::store::lmdb
 | 
			
		||||
| 
						 | 
				
			
			@ -1,310 +1,58 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <nano/store/component.hpp>
 | 
			
		||||
#include <nano/store/db_val.hpp>
 | 
			
		||||
#include <nano/store/iterator.hpp>
 | 
			
		||||
#include <nano/store/lmdb/lmdb_env.hpp>
 | 
			
		||||
#include <nano/store/transaction.hpp>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <span>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <variant>
 | 
			
		||||
 | 
			
		||||
#include <lmdb/libraries/liblmdb/lmdb.h>
 | 
			
		||||
 | 
			
		||||
namespace nano::store::lmdb
 | 
			
		||||
{
 | 
			
		||||
template <typename T, typename U>
 | 
			
		||||
class iterator : public iterator_impl<T, U>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	iterator (transaction const & transaction_a, env const & env_a, MDB_dbi db_a, MDB_val const & val_a = MDB_val{}, bool const direction_asc = true) :
 | 
			
		||||
		iterator_impl<T, U> (transaction_a)
 | 
			
		||||
	{
 | 
			
		||||
		auto status (mdb_cursor_open (env_a.tx (transaction_a), db_a, &cursor));
 | 
			
		||||
		release_assert (status == 0);
 | 
			
		||||
		auto operation (MDB_SET_RANGE);
 | 
			
		||||
		if (val_a.mv_size != 0)
 | 
			
		||||
		{
 | 
			
		||||
			current.first = val_a;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			operation = direction_asc ? MDB_FIRST : MDB_LAST;
 | 
			
		||||
		}
 | 
			
		||||
		auto status2 (mdb_cursor_get (cursor, ¤t.first.value, ¤t.second.value, operation));
 | 
			
		||||
		release_assert (status2 == 0 || status2 == MDB_NOTFOUND);
 | 
			
		||||
		if (status2 != MDB_NOTFOUND)
 | 
			
		||||
		{
 | 
			
		||||
			auto status3 (mdb_cursor_get (cursor, ¤t.first.value, ¤t.second.value, MDB_GET_CURRENT));
 | 
			
		||||
			release_assert (status3 == 0 || status3 == MDB_NOTFOUND);
 | 
			
		||||
			if (current.first.size () != sizeof (T))
 | 
			
		||||
			{
 | 
			
		||||
				clear ();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			clear ();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iterator () = default;
 | 
			
		||||
 | 
			
		||||
	iterator (iterator<T, U> && other_a)
 | 
			
		||||
	{
 | 
			
		||||
		cursor = other_a.cursor;
 | 
			
		||||
		other_a.cursor = nullptr;
 | 
			
		||||
		current = other_a.current;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iterator (iterator<T, U> const &) = delete;
 | 
			
		||||
 | 
			
		||||
	~iterator ()
 | 
			
		||||
	{
 | 
			
		||||
		if (cursor != nullptr)
 | 
			
		||||
		{
 | 
			
		||||
			mdb_cursor_close (cursor);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iterator_impl<T, U> & operator++ () override
 | 
			
		||||
	{
 | 
			
		||||
		debug_assert (cursor != nullptr);
 | 
			
		||||
		auto status (mdb_cursor_get (cursor, ¤t.first.value, ¤t.second.value, MDB_NEXT));
 | 
			
		||||
		release_assert (status == 0 || status == MDB_NOTFOUND);
 | 
			
		||||
		if (status == MDB_NOTFOUND)
 | 
			
		||||
		{
 | 
			
		||||
			clear ();
 | 
			
		||||
		}
 | 
			
		||||
		if (current.first.size () != sizeof (T))
 | 
			
		||||
		{
 | 
			
		||||
			clear ();
 | 
			
		||||
		}
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iterator_impl<T, U> & operator-- () override
 | 
			
		||||
	{
 | 
			
		||||
		debug_assert (cursor != nullptr);
 | 
			
		||||
		auto status (mdb_cursor_get (cursor, ¤t.first.value, ¤t.second.value, MDB_PREV));
 | 
			
		||||
		release_assert (status == 0 || status == MDB_NOTFOUND);
 | 
			
		||||
		if (status == MDB_NOTFOUND)
 | 
			
		||||
		{
 | 
			
		||||
			clear ();
 | 
			
		||||
		}
 | 
			
		||||
		if (current.first.size () != sizeof (T))
 | 
			
		||||
		{
 | 
			
		||||
			clear ();
 | 
			
		||||
		}
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::pair<store::db_val<MDB_val>, store::db_val<MDB_val>> * operator->()
 | 
			
		||||
	{
 | 
			
		||||
		return ¤t;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool operator== (iterator<T, U> const & base_a) const
 | 
			
		||||
	{
 | 
			
		||||
		auto const other_a (boost::polymorphic_downcast<iterator<T, U> const *> (&base_a));
 | 
			
		||||
		auto result (current.first.data () == other_a->current.first.data ());
 | 
			
		||||
		debug_assert (!result || (current.first.size () == other_a->current.first.size ()));
 | 
			
		||||
		debug_assert (!result || (current.second.data () == other_a->current.second.data ()));
 | 
			
		||||
		debug_assert (!result || (current.second.size () == other_a->current.second.size ()));
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool operator== (iterator_impl<T, U> const & base_a) const override
 | 
			
		||||
	{
 | 
			
		||||
		auto const other_a (boost::polymorphic_downcast<iterator<T, U> const *> (&base_a));
 | 
			
		||||
		auto result (current.first.data () == other_a->current.first.data ());
 | 
			
		||||
		debug_assert (!result || (current.first.size () == other_a->current.first.size ()));
 | 
			
		||||
		debug_assert (!result || (current.second.data () == other_a->current.second.data ()));
 | 
			
		||||
		debug_assert (!result || (current.second.size () == other_a->current.second.size ()));
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool is_end_sentinal () const override
 | 
			
		||||
	{
 | 
			
		||||
		return current.first.size () == 0;
 | 
			
		||||
	}
 | 
			
		||||
	void fill (std::pair<T, U> & value_a) const override
 | 
			
		||||
	{
 | 
			
		||||
		if (current.first.size () != 0)
 | 
			
		||||
		{
 | 
			
		||||
			value_a.first = static_cast<T> (current.first);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			value_a.first = T ();
 | 
			
		||||
		}
 | 
			
		||||
		if (current.second.size () != 0)
 | 
			
		||||
		{
 | 
			
		||||
			value_a.second = static_cast<U> (current.second);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			value_a.second = U ();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	void clear ()
 | 
			
		||||
	{
 | 
			
		||||
		current.first = store::db_val<MDB_val> ();
 | 
			
		||||
		current.second = store::db_val<MDB_val> ();
 | 
			
		||||
		debug_assert (is_end_sentinal ());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iterator<T, U> & operator= (iterator<T, U> && other_a)
 | 
			
		||||
	{
 | 
			
		||||
		if (cursor != nullptr)
 | 
			
		||||
		{
 | 
			
		||||
			mdb_cursor_close (cursor);
 | 
			
		||||
		}
 | 
			
		||||
		cursor = other_a.cursor;
 | 
			
		||||
		other_a.cursor = nullptr;
 | 
			
		||||
		current = other_a.current;
 | 
			
		||||
		other_a.clear ();
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iterator_impl<T, U> & operator= (iterator_impl<T, U> const &) = delete;
 | 
			
		||||
	MDB_cursor * cursor{ nullptr };
 | 
			
		||||
	std::pair<store::db_val<MDB_val>, store::db_val<MDB_val>> current;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Iterates the key/value pairs of two stores merged together
 | 
			
		||||
 * @class iterator
 | 
			
		||||
 * @brief An LMDB database iterator.
 | 
			
		||||
 *
 | 
			
		||||
 * This class represents an iterator for LMDB (Lightning Memory-Mapped Database) databases.
 | 
			
		||||
 * It is a circular iterator, meaning that the end() sentinel value is always in the iteration cycle.
 | 
			
		||||
 *
 | 
			
		||||
 * Key characteristics:
 | 
			
		||||
 * - Decrementing the end iterator points to the last key in the database.
 | 
			
		||||
 * - Incrementing the end iterator points to the first key in the database.
 | 
			
		||||
 */
 | 
			
		||||
template <typename T, typename U>
 | 
			
		||||
class merge_iterator : public iterator_impl<T, U>
 | 
			
		||||
class iterator
 | 
			
		||||
{
 | 
			
		||||
	MDB_cursor * cursor{ nullptr };
 | 
			
		||||
	std::variant<std::monostate, std::pair<MDB_val, MDB_val>> current;
 | 
			
		||||
	void update (int status);
 | 
			
		||||
	iterator (MDB_txn * tx, MDB_dbi dbi) noexcept;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	merge_iterator (transaction const & transaction_a, MDB_dbi db1_a, MDB_dbi db2_a) :
 | 
			
		||||
		impl1 (std::make_unique<iterator<T, U>> (transaction_a, db1_a)),
 | 
			
		||||
		impl2 (std::make_unique<iterator<T, U>> (transaction_a, db2_a))
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	using iterator_category = std::bidirectional_iterator_tag;
 | 
			
		||||
	using value_type = std::pair<MDB_val, MDB_val>;
 | 
			
		||||
	using pointer = value_type *;
 | 
			
		||||
	using const_pointer = value_type const *;
 | 
			
		||||
	using reference = value_type &;
 | 
			
		||||
	using const_reference = value_type const &;
 | 
			
		||||
 | 
			
		||||
	merge_iterator () :
 | 
			
		||||
		impl1 (std::make_unique<iterator<T, U>> ()),
 | 
			
		||||
		impl2 (std::make_unique<iterator<T, U>> ())
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	static auto begin (MDB_txn * tx, MDB_dbi dbi) -> iterator;
 | 
			
		||||
	static auto end (MDB_txn * tx, MDB_dbi dbi) -> iterator;
 | 
			
		||||
	static auto lower_bound (MDB_txn * tx, MDB_dbi dbi, MDB_val const & lower_bound) -> iterator;
 | 
			
		||||
 | 
			
		||||
	merge_iterator (transaction const & transaction_a, MDB_dbi db1_a, MDB_dbi db2_a, MDB_val const & val_a) :
 | 
			
		||||
		impl1 (std::make_unique<iterator<T, U>> (transaction_a, db1_a, val_a)),
 | 
			
		||||
		impl2 (std::make_unique<iterator<T, U>> (transaction_a, db2_a, val_a))
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	~iterator ();
 | 
			
		||||
 | 
			
		||||
	merge_iterator (merge_iterator<T, U> && other_a)
 | 
			
		||||
	{
 | 
			
		||||
		impl1 = std::move (other_a.impl1);
 | 
			
		||||
		impl2 = std::move (other_a.impl2);
 | 
			
		||||
	}
 | 
			
		||||
	iterator (iterator const &) = delete;
 | 
			
		||||
	auto operator= (iterator const &) -> iterator & = delete;
 | 
			
		||||
 | 
			
		||||
	merge_iterator (merge_iterator<T, U> const &) = delete;
 | 
			
		||||
	iterator (iterator && other_a) noexcept;
 | 
			
		||||
	auto operator= (iterator && other) noexcept -> iterator &;
 | 
			
		||||
 | 
			
		||||
	iterator_impl<T, U> & operator++ () override
 | 
			
		||||
	{
 | 
			
		||||
		++least_iterator ();
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iterator_impl<T, U> & operator-- () override
 | 
			
		||||
	{
 | 
			
		||||
		--least_iterator ();
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::pair<store::db_val<MDB_val>, store::db_val<MDB_val>> * operator->()
 | 
			
		||||
	{
 | 
			
		||||
		return least_iterator ().operator->();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool operator== (merge_iterator<T, U> const & other) const
 | 
			
		||||
	{
 | 
			
		||||
		return *impl1 == *other.impl1 && *impl2 == *other.impl2;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool operator!= (merge_iterator<T, U> const & base_a) const
 | 
			
		||||
	{
 | 
			
		||||
		return !(*this == base_a);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool operator== (iterator_impl<T, U> const & base_a) const override
 | 
			
		||||
	{
 | 
			
		||||
		debug_assert ((dynamic_cast<merge_iterator<T, U> const *> (&base_a) != nullptr) && "Incompatible iterator comparison");
 | 
			
		||||
		auto & other (static_cast<merge_iterator<T, U> const &> (base_a));
 | 
			
		||||
		return *this == other;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool is_end_sentinal () const override
 | 
			
		||||
	{
 | 
			
		||||
		return least_iterator ().is_end_sentinal ();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void fill (std::pair<T, U> & value_a) const override
 | 
			
		||||
	{
 | 
			
		||||
		auto & current (least_iterator ());
 | 
			
		||||
		if (current->first.size () != 0)
 | 
			
		||||
		{
 | 
			
		||||
			value_a.first = static_cast<T> (current->first);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			value_a.first = T ();
 | 
			
		||||
		}
 | 
			
		||||
		if (current->second.size () != 0)
 | 
			
		||||
		{
 | 
			
		||||
			value_a.second = static_cast<U> (current->second);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			value_a.second = U ();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	merge_iterator<T, U> & operator= (merge_iterator<T, U> &&) = default;
 | 
			
		||||
	merge_iterator<T, U> & operator= (merge_iterator<T, U> const &) = delete;
 | 
			
		||||
 | 
			
		||||
	mutable bool from_first_database{ false };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	iterator<T, U> & least_iterator () const
 | 
			
		||||
	{
 | 
			
		||||
		iterator<T, U> * result;
 | 
			
		||||
		if (impl1->is_end_sentinal ())
 | 
			
		||||
		{
 | 
			
		||||
			result = impl2.get ();
 | 
			
		||||
			from_first_database = false;
 | 
			
		||||
		}
 | 
			
		||||
		else if (impl2->is_end_sentinal ())
 | 
			
		||||
		{
 | 
			
		||||
			result = impl1.get ();
 | 
			
		||||
			from_first_database = true;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			auto key_cmp (mdb_cmp (mdb_cursor_txn (impl1->cursor), mdb_cursor_dbi (impl1->cursor), impl1->current.first, impl2->current.first));
 | 
			
		||||
 | 
			
		||||
			if (key_cmp < 0)
 | 
			
		||||
			{
 | 
			
		||||
				result = impl1.get ();
 | 
			
		||||
				from_first_database = true;
 | 
			
		||||
			}
 | 
			
		||||
			else if (key_cmp > 0)
 | 
			
		||||
			{
 | 
			
		||||
				result = impl2.get ();
 | 
			
		||||
				from_first_database = false;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				auto val_cmp (mdb_cmp (mdb_cursor_txn (impl1->cursor), mdb_cursor_dbi (impl1->cursor), impl1->current.second, impl2->current.second));
 | 
			
		||||
				result = val_cmp < 0 ? impl1.get () : impl2.get ();
 | 
			
		||||
				from_first_database = (result == impl1.get ());
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return *result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::unique_ptr<iterator<T, U>> impl1;
 | 
			
		||||
	std::unique_ptr<iterator<T, U>> impl2;
 | 
			
		||||
	auto operator++ () -> iterator &;
 | 
			
		||||
	auto operator-- () -> iterator &;
 | 
			
		||||
	auto operator->() const -> const_pointer;
 | 
			
		||||
	auto operator* () const -> const_reference;
 | 
			
		||||
	auto operator== (iterator const & other) const -> bool;
 | 
			
		||||
	auto span () const -> std::pair<std::span<uint8_t const>, std::span<uint8_t const>>;
 | 
			
		||||
	bool is_end () const;
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@
 | 
			
		|||
#include <nano/store/lmdb/iterator.hpp>
 | 
			
		||||
#include <nano/store/lmdb/lmdb.hpp>
 | 
			
		||||
#include <nano/store/lmdb/wallet_value.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator_templ.hpp>
 | 
			
		||||
#include <nano/store/version.hpp>
 | 
			
		||||
#include <nano/store/versioning.hpp>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +15,8 @@
 | 
			
		|||
 | 
			
		||||
#include <queue>
 | 
			
		||||
 | 
			
		||||
template class nano::store::typed_iterator<nano::account, nano::account_info_v22>;
 | 
			
		||||
 | 
			
		||||
nano::store::lmdb::component::component (nano::logger & logger_a, std::filesystem::path const & path_a, nano::ledger_constants & constants, nano::txn_tracking_config const & txn_tracking_config_a, std::chrono::milliseconds block_processor_batch_max_time_a, nano::lmdb_config const & lmdb_config_a, bool backup_before_upgrade_a) :
 | 
			
		||||
	// clang-format off
 | 
			
		||||
	nano::store::component{
 | 
			
		||||
| 
						 | 
				
			
			@ -264,8 +267,8 @@ void nano::store::lmdb::component::upgrade_v22_to_v23 (store::write_transaction
 | 
			
		|||
		auto transaction = tx_begin_read ();
 | 
			
		||||
 | 
			
		||||
		// Manually create v22 compatible iterator to read accounts
 | 
			
		||||
		auto it = make_iterator<nano::account, nano::account_info_v22> (transaction, tables::accounts);
 | 
			
		||||
		auto const end = store::iterator<nano::account, nano::account_info_v22> (nullptr);
 | 
			
		||||
		auto it = typed_iterator<nano::account, nano::account_info_v22>{ store::iterator{ iterator::begin (env.tx (transaction), account_store.accounts_handle) } };
 | 
			
		||||
		auto const end = typed_iterator<nano::account, nano::account_info_v22>{ store::iterator{ iterator::end (env.tx (transaction), account_store.accounts_handle) } };
 | 
			
		||||
 | 
			
		||||
		for (; it != end; ++it)
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -457,7 +460,7 @@ void nano::store::lmdb::component::rebuild_db (store::write_transaction const &
 | 
			
		|||
		MDB_dbi temp;
 | 
			
		||||
		mdb_dbi_open (env.tx (transaction_a), "temp_table", MDB_CREATE, &temp);
 | 
			
		||||
		// Copy all values to temporary table
 | 
			
		||||
		for (auto i (store::iterator<nano::uint256_union, nano::store::lmdb::db_val> (std::make_unique<nano::store::lmdb::iterator<nano::uint256_union, nano::store::lmdb::db_val>> (transaction_a, env, table))), n (store::iterator<nano::uint256_union, nano::store::lmdb::db_val> (nullptr)); i != n; ++i)
 | 
			
		||||
		for (typed_iterator<nano::uint256_union, nano::store::lmdb::db_val> i{ store::iterator{ iterator::begin (env.tx (transaction_a), table) } }, n{ store::iterator{ iterator::end (env.tx (transaction_a), table) } }; i != n; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			auto s = mdb_put (env.tx (transaction_a), temp, nano::store::lmdb::db_val (i->first), i->second, MDB_APPEND);
 | 
			
		||||
			release_assert_success (s);
 | 
			
		||||
| 
						 | 
				
			
			@ -466,7 +469,7 @@ void nano::store::lmdb::component::rebuild_db (store::write_transaction const &
 | 
			
		|||
		// Clear existing table
 | 
			
		||||
		mdb_drop (env.tx (transaction_a), table, 0);
 | 
			
		||||
		// Put values from copy
 | 
			
		||||
		for (auto i (store::iterator<nano::uint256_union, nano::store::lmdb::db_val> (std::make_unique<nano::store::lmdb::iterator<nano::uint256_union, nano::store::lmdb::db_val>> (transaction_a, env, temp))), n (store::iterator<nano::uint256_union, nano::store::lmdb::db_val> (nullptr)); i != n; ++i)
 | 
			
		||||
		for (typed_iterator<nano::uint256_union, nano::store::lmdb::db_val> i{ store::iterator{ iterator::begin (env.tx (transaction_a), temp) } }, n{ store::iterator{ iterator::end (env.tx (transaction_a), temp) } }; i != n; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			auto s = mdb_put (env.tx (transaction_a), table, nano::store::lmdb::db_val (i->first), i->second, MDB_APPEND);
 | 
			
		||||
			release_assert_success (s);
 | 
			
		||||
| 
						 | 
				
			
			@ -480,7 +483,7 @@ void nano::store::lmdb::component::rebuild_db (store::write_transaction const &
 | 
			
		|||
		MDB_dbi temp;
 | 
			
		||||
		mdb_dbi_open (env.tx (transaction_a), "temp_table", MDB_CREATE, &temp);
 | 
			
		||||
		// Copy all values to temporary table
 | 
			
		||||
		for (auto i (store::iterator<nano::pending_key, nano::pending_info> (std::make_unique<nano::store::lmdb::iterator<nano::pending_key, nano::pending_info>> (transaction_a, env, pending_store.pending_handle))), n (store::iterator<nano::pending_key, nano::pending_info> (nullptr)); i != n; ++i)
 | 
			
		||||
		for (typed_iterator<nano::pending_key, nano::pending_info> i{ store::iterator{ iterator::begin (env.tx (transaction_a), pending_store.pending_handle) } }, n{ store::iterator{ iterator::end (env.tx (transaction_a), pending_store.pending_handle) } }; i != n; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			auto s = mdb_put (env.tx (transaction_a), temp, nano::store::lmdb::db_val (i->first), nano::store::lmdb::db_val (i->second), MDB_APPEND);
 | 
			
		||||
			release_assert_success (s);
 | 
			
		||||
| 
						 | 
				
			
			@ -488,7 +491,7 @@ void nano::store::lmdb::component::rebuild_db (store::write_transaction const &
 | 
			
		|||
		release_assert (count (transaction_a, pending_store.pending_handle) == count (transaction_a, temp));
 | 
			
		||||
		mdb_drop (env.tx (transaction_a), pending_store.pending_handle, 0);
 | 
			
		||||
		// Put values from copy
 | 
			
		||||
		for (auto i (store::iterator<nano::pending_key, nano::pending_info> (std::make_unique<nano::store::lmdb::iterator<nano::pending_key, nano::pending_info>> (transaction_a, env, temp))), n (store::iterator<nano::pending_key, nano::pending_info> (nullptr)); i != n; ++i)
 | 
			
		||||
		for (typed_iterator<nano::pending_key, nano::pending_info> i{ store::iterator{ iterator::begin (env.tx (transaction_a), temp) } }, n{ store::iterator{ iterator::end (env.tx (transaction_a), temp) } }; i != n; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			auto s = mdb_put (env.tx (transaction_a), pending_store.pending_handle, nano::store::lmdb::db_val (i->first), nano::store::lmdb::db_val (i->second), MDB_APPEND);
 | 
			
		||||
			release_assert_success (s);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -93,18 +93,6 @@ public:
 | 
			
		|||
	bool copy_db (std::filesystem::path const & destination_file) override;
 | 
			
		||||
	void rebuild_db (store::write_transaction const & transaction_a) override;
 | 
			
		||||
 | 
			
		||||
	template <typename Key, typename Value>
 | 
			
		||||
	store::iterator<Key, Value> make_iterator (store::transaction const & transaction_a, tables table_a, bool const direction_asc = true) const
 | 
			
		||||
	{
 | 
			
		||||
		return store::iterator<Key, Value> (std::make_unique<nano::store::lmdb::iterator<Key, Value>> (transaction_a, env, table_to_dbi (table_a), nano::store::lmdb::db_val{}, direction_asc));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template <typename Key, typename Value>
 | 
			
		||||
	store::iterator<Key, Value> make_iterator (store::transaction const & transaction_a, tables table_a, nano::store::lmdb::db_val const & key) const
 | 
			
		||||
	{
 | 
			
		||||
		return store::iterator<Key, Value> (std::make_unique<nano::store::lmdb::iterator<Key, Value>> (transaction_a, env, table_to_dbi (table_a), key));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool init_error () const override;
 | 
			
		||||
 | 
			
		||||
	uint64_t count (store::transaction const &, MDB_dbi) const;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,17 +20,12 @@ void nano::store::lmdb::online_weight::del (store::write_transaction const & tra
 | 
			
		|||
 | 
			
		||||
auto nano::store::lmdb::online_weight::begin (store::transaction const & transaction) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<uint64_t, nano::amount> (transaction, tables::online_weight);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::online_weight::rbegin (store::transaction const & transaction) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<uint64_t, nano::amount> (transaction, tables::online_weight, false);
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::begin (store.env.tx (transaction), online_weight_handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::online_weight::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::end (store.env.tx (transaction_a), online_weight_handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t nano::store::lmdb::online_weight::count (store::transaction const & transaction) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,6 @@ public:
 | 
			
		|||
	void put (store::write_transaction const & transaction_a, uint64_t time_a, nano::amount const & amount_a) override;
 | 
			
		||||
	void del (store::write_transaction const & transaction_a, uint64_t time_a) override;
 | 
			
		||||
	iterator begin (store::transaction const & transaction_a) const override;
 | 
			
		||||
	iterator rbegin (store::transaction const & transaction_a) const override;
 | 
			
		||||
	iterator end (store::transaction const & transaction_a) const override;
 | 
			
		||||
	size_t count (store::transaction const & transaction_a) const override;
 | 
			
		||||
	void clear (store::write_transaction const & transaction_a) override;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,10 +47,10 @@ void nano::store::lmdb::peer::clear (store::write_transaction const & transactio
 | 
			
		|||
 | 
			
		||||
auto nano::store::lmdb::peer::begin (store::transaction const & transaction) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::endpoint_key, nano::millis_t> (transaction, tables::peers);
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::begin (store.env.tx (transaction), peers_handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::peer::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::end (store.env.tx (transaction_a), peers_handle) } };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,17 +47,18 @@ bool nano::store::lmdb::pending::any (store::transaction const & transaction_a,
 | 
			
		|||
 | 
			
		||||
auto nano::store::lmdb::pending::begin (store::transaction const & transaction_a, nano::pending_key const & key_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::pending_key, nano::pending_info> (transaction_a, tables::pending, key_a);
 | 
			
		||||
	lmdb::db_val val{ key_a };
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::lower_bound (store.env.tx (transaction_a), pending_handle, val) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::pending::begin (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::pending_key, nano::pending_info> (transaction_a, tables::pending);
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::begin (store.env.tx (transaction_a), pending_handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::pending::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::end (store.env.tx (transaction_a), pending_handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::store::lmdb::pending::for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const & action_a) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,17 +47,18 @@ void nano::store::lmdb::pruned::clear (store::write_transaction const & transact
 | 
			
		|||
 | 
			
		||||
auto nano::store::lmdb::pruned::begin (store::transaction const & transaction, nano::block_hash const & hash) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::block_hash, std::nullptr_t> (transaction, tables::pruned, hash);
 | 
			
		||||
	lmdb::db_val val{ hash };
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::lower_bound (store.env.tx (transaction), pruned_handle, val) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::pruned::begin (store::transaction const & transaction) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::block_hash, std::nullptr_t> (transaction, tables::pruned);
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::begin (store.env.tx (transaction), pruned_handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::pruned::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::end (store.env.tx (transaction_a), pruned_handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::store::lmdb::pruned::for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const & action_a) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,17 +45,18 @@ void nano::store::lmdb::rep_weight::del (store::write_transaction const & txn_a,
 | 
			
		|||
 | 
			
		||||
auto nano::store::lmdb::rep_weight::begin (store::transaction const & transaction_a, nano::account const & representative_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::account, nano::uint128_union> (transaction_a, tables::rep_weights, representative_a);
 | 
			
		||||
	lmdb::db_val val{ representative_a };
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::lower_bound (store.env.tx (transaction_a), rep_weights_handle, val) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::rep_weight::begin (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::account, nano::uint128_union> (transaction_a, tables::rep_weights);
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::begin (store.env.tx (transaction_a), rep_weights_handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::lmdb::rep_weight::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ lmdb::iterator::end (store.env.tx (transaction_a), rep_weights_handle) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::store::lmdb::rep_weight::for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const & action_a) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1,18 @@
 | 
			
		|||
#include <nano/store/online_weight.hpp>
 | 
			
		||||
#include <nano/store/reverse_iterator_templ.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator_templ.hpp>
 | 
			
		||||
 | 
			
		||||
template class nano::store::typed_iterator<uint64_t, nano::amount>;
 | 
			
		||||
template class nano::store::reverse_iterator<nano::store::typed_iterator<uint64_t, nano::amount>>;
 | 
			
		||||
 | 
			
		||||
auto nano::store::online_weight::rbegin (store::transaction const & tx) const -> reverse_iterator
 | 
			
		||||
{
 | 
			
		||||
	auto iter = end (tx);
 | 
			
		||||
	--iter;
 | 
			
		||||
	return reverse_iterator{ std::move (iter) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::online_weight::rend (transaction const & tx) const -> reverse_iterator
 | 
			
		||||
{
 | 
			
		||||
	return reverse_iterator{ end (tx) };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,8 @@
 | 
			
		|||
 | 
			
		||||
#include <nano/lib/numbers.hpp>
 | 
			
		||||
#include <nano/store/component.hpp>
 | 
			
		||||
#include <nano/store/iterator.hpp>
 | 
			
		||||
#include <nano/store/reverse_iterator.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator.hpp>
 | 
			
		||||
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -18,13 +19,15 @@ namespace nano::store
 | 
			
		|||
class online_weight
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	using iterator = store::iterator<uint64_t, nano::amount>;
 | 
			
		||||
	using iterator = typed_iterator<uint64_t, nano::amount>;
 | 
			
		||||
	using reverse_iterator = store::reverse_iterator<iterator>;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	virtual void put (store::write_transaction const &, uint64_t, nano::amount const &) = 0;
 | 
			
		||||
	virtual void del (store::write_transaction const &, uint64_t) = 0;
 | 
			
		||||
	virtual iterator begin (store::transaction const &) const = 0;
 | 
			
		||||
	virtual iterator rbegin (store::transaction const &) const = 0;
 | 
			
		||||
	reverse_iterator rbegin (store::transaction const &) const;
 | 
			
		||||
	reverse_iterator rend (store::transaction const &) const;
 | 
			
		||||
	virtual iterator end (store::transaction const & transaction_a) const = 0;
 | 
			
		||||
	virtual size_t count (store::transaction const &) const = 0;
 | 
			
		||||
	virtual void clear (store::write_transaction const &) = 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1,4 @@
 | 
			
		|||
#include <nano/store/peer.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator_templ.hpp>
 | 
			
		||||
 | 
			
		||||
template class nano::store::typed_iterator<nano::endpoint_key, nano::millis_t>;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
 | 
			
		||||
#include <nano/lib/numbers.hpp>
 | 
			
		||||
#include <nano/store/component.hpp>
 | 
			
		||||
#include <nano/store/iterator.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator.hpp>
 | 
			
		||||
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ namespace nano::store
 | 
			
		|||
class peer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	using iterator = store::iterator<nano::endpoint_key, nano::millis_t>;
 | 
			
		||||
	using iterator = typed_iterator<nano::endpoint_key, nano::millis_t>;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	/// Returns true if the peer was inserted, false if it was already in the container
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1,5 @@
 | 
			
		|||
#include <nano/secure/pending_info.hpp>
 | 
			
		||||
#include <nano/store/pending.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator_templ.hpp>
 | 
			
		||||
 | 
			
		||||
template class nano::store::typed_iterator<nano::pending_key, nano::pending_info>;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
 | 
			
		||||
#include <nano/lib/numbers.hpp>
 | 
			
		||||
#include <nano/store/component.hpp>
 | 
			
		||||
#include <nano/store/iterator.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator.hpp>
 | 
			
		||||
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <optional>
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ namespace nano::store
 | 
			
		|||
class pending
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	using iterator = store::iterator<nano::pending_key, nano::pending_info>;
 | 
			
		||||
	using iterator = typed_iterator<nano::pending_key, nano::pending_info>;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	virtual void put (store::write_transaction const &, nano::pending_key const &, nano::pending_info const &) = 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1,4 @@
 | 
			
		|||
#include <nano/store/pruned.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator_templ.hpp>
 | 
			
		||||
 | 
			
		||||
template class nano::store::typed_iterator<nano::block_hash, std::nullptr_t>;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
 | 
			
		||||
#include <nano/lib/numbers.hpp>
 | 
			
		||||
#include <nano/store/component.hpp>
 | 
			
		||||
#include <nano/store/iterator.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator.hpp>
 | 
			
		||||
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ namespace nano::store
 | 
			
		|||
class pruned
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	using iterator = store::iterator<nano::block_hash, std::nullptr_t>;
 | 
			
		||||
	using iterator = typed_iterator<nano::block_hash, std::nullptr_t>;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	virtual void put (store::write_transaction const & transaction_a, nano::block_hash const & hash_a) = 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										4
									
								
								nano/store/rep_weight.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								nano/store/rep_weight.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
#include <nano/store/rep_weight.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator_templ.hpp>
 | 
			
		||||
 | 
			
		||||
template class nano::store::typed_iterator<nano::account, nano::uint128_union>;
 | 
			
		||||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
 | 
			
		||||
#include <nano/lib/numbers.hpp>
 | 
			
		||||
#include <nano/store/component.hpp>
 | 
			
		||||
#include <nano/store/iterator.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator.hpp>
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <functional>
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ namespace nano::store
 | 
			
		|||
class rep_weight
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	using iterator = store::iterator<nano::account, nano::uint128_union>;
 | 
			
		||||
	using iterator = typed_iterator<nano::account, nano::uint128_union>;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	virtual ~rep_weight (){};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										48
									
								
								nano/store/reverse_iterator.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								nano/store/reverse_iterator.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,48 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
namespace nano::store
 | 
			
		||||
{
 | 
			
		||||
/**
 | 
			
		||||
 * @class reverse_iterator
 | 
			
		||||
 * @brief A reverse iterator adaptor for bidirectional iterators.
 | 
			
		||||
 *
 | 
			
		||||
 * This class template adapts any bidirectional iterator to reverse its direction of iteration.
 | 
			
		||||
 * It inverts the semantics of increment and decrement operations.
 | 
			
		||||
 *
 | 
			
		||||
 * Key characteristics:
 | 
			
		||||
 * - Incrementing (operator++) moves to the previous element in the sequence.
 | 
			
		||||
 * - Decrementing (operator--) moves to the next element in the sequence.
 | 
			
		||||
 * - Dereferencing refers to the same element as the adapted iterator.
 | 
			
		||||
 * - Compatible with any bidirectional iterator, not limited to specific container types.
 | 
			
		||||
 */
 | 
			
		||||
template <typename Iter>
 | 
			
		||||
class reverse_iterator
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	using iterator_category = std::bidirectional_iterator_tag;
 | 
			
		||||
	using value_type = Iter::value_type;
 | 
			
		||||
	using pointer = value_type *;
 | 
			
		||||
	using const_pointer = value_type const *;
 | 
			
		||||
	using reference = value_type &;
 | 
			
		||||
	using const_reference = value_type const &;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	Iter internal;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	reverse_iterator (Iter && other) noexcept;
 | 
			
		||||
 | 
			
		||||
	reverse_iterator (reverse_iterator const &) = delete;
 | 
			
		||||
	auto operator= (reverse_iterator const &) -> reverse_iterator & = delete;
 | 
			
		||||
 | 
			
		||||
	reverse_iterator (reverse_iterator && other) noexcept;
 | 
			
		||||
	auto operator= (reverse_iterator && other) noexcept -> reverse_iterator &;
 | 
			
		||||
 | 
			
		||||
	auto operator++ () -> reverse_iterator &;
 | 
			
		||||
	auto operator-- () -> reverse_iterator &;
 | 
			
		||||
	auto operator->() const -> const_pointer;
 | 
			
		||||
	auto operator* () const -> const_reference;
 | 
			
		||||
	auto operator== (reverse_iterator const & other) const -> bool;
 | 
			
		||||
	bool is_end () const;
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										63
									
								
								nano/store/reverse_iterator_templ.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								nano/store/reverse_iterator_templ.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
#include <nano/store/reverse_iterator.hpp>
 | 
			
		||||
 | 
			
		||||
namespace nano::store
 | 
			
		||||
{
 | 
			
		||||
template <typename Iter>
 | 
			
		||||
reverse_iterator<Iter>::reverse_iterator (Iter && other) noexcept :
 | 
			
		||||
	internal{ std::move (other) }
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Iter>
 | 
			
		||||
reverse_iterator<Iter>::reverse_iterator (reverse_iterator && other) noexcept :
 | 
			
		||||
	internal{ std::move (other.internal) }
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Iter>
 | 
			
		||||
auto reverse_iterator<Iter>::operator= (reverse_iterator && other) noexcept -> reverse_iterator &
 | 
			
		||||
{
 | 
			
		||||
	internal = std::move (other.internal);
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Iter>
 | 
			
		||||
auto reverse_iterator<Iter>::operator++ () -> reverse_iterator &
 | 
			
		||||
{
 | 
			
		||||
	--internal;
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Iter>
 | 
			
		||||
auto reverse_iterator<Iter>::operator-- () -> reverse_iterator &
 | 
			
		||||
{
 | 
			
		||||
	++internal;
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Iter>
 | 
			
		||||
auto reverse_iterator<Iter>::operator->() const -> const_pointer
 | 
			
		||||
{
 | 
			
		||||
	release_assert (!is_end ());
 | 
			
		||||
	return internal.operator->();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Iter>
 | 
			
		||||
auto reverse_iterator<Iter>::operator* () const -> const_reference
 | 
			
		||||
{
 | 
			
		||||
	release_assert (!is_end ());
 | 
			
		||||
	return internal.operator* ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Iter>
 | 
			
		||||
auto reverse_iterator<Iter>::operator== (reverse_iterator const & other) const -> bool
 | 
			
		||||
{
 | 
			
		||||
	return internal == other.internal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Iter>
 | 
			
		||||
bool reverse_iterator<Iter>::is_end () const
 | 
			
		||||
{
 | 
			
		||||
	return internal.is_end ();
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
#include <nano/secure/parallel_traversal.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/account.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/rocksdb.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/utility.hpp>
 | 
			
		||||
 | 
			
		||||
nano::store::rocksdb::account::account (nano::store::rocksdb::component & store_a) :
 | 
			
		||||
	store (store_a){};
 | 
			
		||||
| 
						 | 
				
			
			@ -44,22 +45,18 @@ size_t nano::store::rocksdb::account::count (store::transaction const & transact
 | 
			
		|||
 | 
			
		||||
auto nano::store::rocksdb::account::begin (store::transaction const & transaction, nano::account const & account) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::account, nano::account_info> (transaction, tables::accounts, account);
 | 
			
		||||
	rocksdb::db_val val{ account };
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::lower_bound (store.db.get (), rocksdb::tx (transaction), store.table_to_column_family (tables::accounts), val) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::account::begin (store::transaction const & transaction) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::account, nano::account_info> (transaction, tables::accounts);
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::begin (store.db.get (), rocksdb::tx (transaction), store.table_to_column_family (tables::accounts)) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::account::rbegin (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
auto nano::store::rocksdb::account::end (store::transaction const & transaction) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::account, nano::account_info> (transaction_a, tables::accounts, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::account::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::end (store.db.get (), rocksdb::tx (transaction), store.table_to_column_family (tables::accounts)) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::store::rocksdb::account::for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const & action_a) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,6 @@ public:
 | 
			
		|||
	size_t count (store::transaction const & transaction_a) override;
 | 
			
		||||
	iterator begin (store::transaction const & transaction_a, nano::account const & account_a) const override;
 | 
			
		||||
	iterator begin (store::transaction const & transaction_a) const override;
 | 
			
		||||
	iterator rbegin (store::transaction const & transaction_a) const override;
 | 
			
		||||
	iterator end (store::transaction const & transaction_a) const override;
 | 
			
		||||
	void for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const & action_a) const override;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
#include <nano/store/db_val_impl.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/block.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/rocksdb.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/utility.hpp>
 | 
			
		||||
 | 
			
		||||
namespace nano
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -136,17 +137,18 @@ uint64_t nano::store::rocksdb::block::count (store::transaction const & transact
 | 
			
		|||
 | 
			
		||||
auto nano::store::rocksdb::block::begin (store::transaction const & transaction) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::block_hash, nano::store::block_w_sideband> (transaction, tables::blocks);
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::begin (store.db.get (), rocksdb::tx (transaction), store.table_to_column_family (tables::blocks)) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::block::begin (store::transaction const & transaction, nano::block_hash const & hash) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::block_hash, nano::store::block_w_sideband> (transaction, tables::blocks, hash);
 | 
			
		||||
	rocksdb::db_val val{ hash };
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::lower_bound (store.db.get (), rocksdb::tx (transaction), store.table_to_column_family (tables::blocks), val) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::block::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::end (store.db.get (), rocksdb::tx (transaction_a), store.table_to_column_family (tables::blocks)) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::store::rocksdb::block::for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const & action_a) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
#include <nano/secure/parallel_traversal.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/confirmation_height.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/rocksdb.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/utility.hpp>
 | 
			
		||||
 | 
			
		||||
nano::store::rocksdb::confirmation_height::confirmation_height (nano::store::rocksdb::component & store) :
 | 
			
		||||
	store{ store }
 | 
			
		||||
| 
						 | 
				
			
			@ -61,17 +62,18 @@ void nano::store::rocksdb::confirmation_height::clear (store::write_transaction
 | 
			
		|||
 | 
			
		||||
auto nano::store::rocksdb::confirmation_height::begin (store::transaction const & transaction, nano::account const & account) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::account, nano::confirmation_height_info> (transaction, tables::confirmation_height, account);
 | 
			
		||||
	rocksdb::db_val val{ account };
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::lower_bound (store.db.get (), rocksdb::tx (transaction), store.table_to_column_family (tables::confirmation_height), val) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::confirmation_height::begin (store::transaction const & transaction) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::account, nano::confirmation_height_info> (transaction, tables::confirmation_height);
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::begin (store.db.get (), rocksdb::tx (transaction), store.table_to_column_family (tables::confirmation_height)) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::confirmation_height::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::end (store.db.get (), rocksdb::tx (transaction_a), store.table_to_column_family (tables::confirmation_height)) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::store::rocksdb::confirmation_height::for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const & action_a) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
#include <nano/secure/parallel_traversal.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/final_vote.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/rocksdb.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/utility.hpp>
 | 
			
		||||
 | 
			
		||||
nano::store::rocksdb::final_vote::final_vote (nano::store::rocksdb::component & store) :
 | 
			
		||||
	store{ store } {};
 | 
			
		||||
| 
						 | 
				
			
			@ -66,17 +67,18 @@ void nano::store::rocksdb::final_vote::clear (store::write_transaction const & t
 | 
			
		|||
 | 
			
		||||
auto nano::store::rocksdb::final_vote::begin (store::transaction const & transaction, nano::qualified_root const & root) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::qualified_root, nano::block_hash> (transaction, tables::final_votes, root);
 | 
			
		||||
	rocksdb::db_val val{ root };
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::lower_bound (store.db.get (), rocksdb::tx (transaction), store.table_to_column_family (tables::final_votes), val) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::final_vote::begin (store::transaction const & transaction) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::qualified_root, nano::block_hash> (transaction, tables::final_votes);
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::begin (store.db.get (), rocksdb::tx (transaction), store.table_to_column_family (tables::final_votes)) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::final_vote::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::end (store.db.get (), rocksdb::tx (transaction_a), store.table_to_column_family (tables::final_votes)) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::store::rocksdb::final_vote::for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const & action_a) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										146
									
								
								nano/store/rocksdb/iterator.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								nano/store/rocksdb/iterator.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,146 @@
 | 
			
		|||
#include <nano/lib/utility.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/iterator.hpp>
 | 
			
		||||
 | 
			
		||||
#include <rocksdb/iterator.h>
 | 
			
		||||
 | 
			
		||||
namespace nano::store::rocksdb
 | 
			
		||||
{
 | 
			
		||||
auto iterator::span () const -> std::pair<std::span<uint8_t const>, std::span<uint8_t const>>
 | 
			
		||||
{
 | 
			
		||||
	auto & current = operator* ();
 | 
			
		||||
	std::span<uint8_t const> key{ reinterpret_cast<uint8_t const *> (current.first.data ()), current.first.size () };
 | 
			
		||||
	std::span<uint8_t const> value{ reinterpret_cast<uint8_t const *> (current.second.data ()), current.second.size () };
 | 
			
		||||
	return std::make_pair (key, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::is_end () const -> bool
 | 
			
		||||
{
 | 
			
		||||
	return std::holds_alternative<std::monostate> (current);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void iterator::update ()
 | 
			
		||||
{
 | 
			
		||||
	if (iter->Valid ())
 | 
			
		||||
	{
 | 
			
		||||
		current = std::make_pair (iter->key (), iter->value ());
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		current = std::monostate{};
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
iterator::iterator (decltype (iter) && iter) :
 | 
			
		||||
	iter{ std::move (iter) }
 | 
			
		||||
{
 | 
			
		||||
	update ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::begin (::rocksdb::DB * db, std::variant<::rocksdb::Transaction *, ::rocksdb::ReadOptions *> snapshot, ::rocksdb::ColumnFamilyHandle * table) -> iterator
 | 
			
		||||
{
 | 
			
		||||
	auto result = iterator{ make_iterator (db, snapshot, table) };
 | 
			
		||||
	++result;
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::end (::rocksdb::DB * db, std::variant<::rocksdb::Transaction *, ::rocksdb::ReadOptions *> snapshot, ::rocksdb::ColumnFamilyHandle * table) -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ make_iterator (db, snapshot, table) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::lower_bound (::rocksdb::DB * db, std::variant<::rocksdb::Transaction *, ::rocksdb::ReadOptions *> snapshot, ::rocksdb::ColumnFamilyHandle * table, ::rocksdb::Slice const & lower_bound) -> iterator
 | 
			
		||||
{
 | 
			
		||||
	auto iter = make_iterator (db, snapshot, table);
 | 
			
		||||
	iter->Seek (lower_bound);
 | 
			
		||||
	return iterator{ std::move (iter) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::make_iterator (::rocksdb::DB * db, std::variant<::rocksdb::Transaction *, ::rocksdb::ReadOptions *> snapshot, ::rocksdb::ColumnFamilyHandle * table) -> std::unique_ptr<::rocksdb::Iterator>
 | 
			
		||||
{
 | 
			
		||||
	return std::unique_ptr<::rocksdb::Iterator>{ std::visit ([&] (auto && ptr) {
 | 
			
		||||
		using V = std::remove_cvref_t<decltype (ptr)>;
 | 
			
		||||
		if constexpr (std::is_same_v<V, ::rocksdb::Transaction *>)
 | 
			
		||||
		{
 | 
			
		||||
			::rocksdb::ReadOptions ropts;
 | 
			
		||||
			ropts.fill_cache = false;
 | 
			
		||||
			return ptr->GetIterator (ropts, table);
 | 
			
		||||
		}
 | 
			
		||||
		else if constexpr (std::is_same_v<V, ::rocksdb::ReadOptions *>)
 | 
			
		||||
		{
 | 
			
		||||
			ptr->fill_cache = false;
 | 
			
		||||
			return db->NewIterator (*ptr, table);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			static_assert (sizeof (V) == 0, "Missing variant handler for type V");
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	snapshot) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
iterator::iterator (iterator && other) noexcept
 | 
			
		||||
{
 | 
			
		||||
	*this = std::move (other);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator= (iterator && other) noexcept -> iterator &
 | 
			
		||||
{
 | 
			
		||||
	iter = std::move (other.iter);
 | 
			
		||||
	current = other.current;
 | 
			
		||||
	other.current = std::monostate{};
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator++ () -> iterator &
 | 
			
		||||
{
 | 
			
		||||
	if (!is_end ())
 | 
			
		||||
	{
 | 
			
		||||
		iter->Next ();
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		iter->SeekToFirst ();
 | 
			
		||||
	}
 | 
			
		||||
	update ();
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator-- () -> iterator &
 | 
			
		||||
{
 | 
			
		||||
	if (!is_end ())
 | 
			
		||||
	{
 | 
			
		||||
		iter->Prev ();
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		iter->SeekToLast ();
 | 
			
		||||
	}
 | 
			
		||||
	update ();
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator->() const -> const_pointer
 | 
			
		||||
{
 | 
			
		||||
	release_assert (!is_end ());
 | 
			
		||||
	return std::get_if<value_type> (¤t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator* () const -> const_reference
 | 
			
		||||
{
 | 
			
		||||
	release_assert (!is_end ());
 | 
			
		||||
	return std::get<value_type> (current);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto iterator::operator== (iterator const & other) const -> bool
 | 
			
		||||
{
 | 
			
		||||
	if (is_end () != other.is_end ())
 | 
			
		||||
	{
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	if (is_end ())
 | 
			
		||||
	{
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	return std::get<value_type> (current) == std::get<value_type> (other.current);
 | 
			
		||||
}
 | 
			
		||||
} // namespace nano::store::lmdb
 | 
			
		||||
| 
						 | 
				
			
			@ -1,196 +1,60 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <nano/store/component.hpp>
 | 
			
		||||
#include <nano/store/iterator.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/db_val.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/utility.hpp>
 | 
			
		||||
#include <nano/store/transaction.hpp>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <span>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <variant>
 | 
			
		||||
 | 
			
		||||
#include <rocksdb/db.h>
 | 
			
		||||
#include <rocksdb/filter_policy.h>
 | 
			
		||||
#include <rocksdb/options.h>
 | 
			
		||||
#include <rocksdb/slice.h>
 | 
			
		||||
#include <rocksdb/utilities/transaction.h>
 | 
			
		||||
 | 
			
		||||
namespace nano::store::rocksdb
 | 
			
		||||
{
 | 
			
		||||
template <typename T, typename U>
 | 
			
		||||
class iterator : public iterator_impl<T, U>
 | 
			
		||||
/**
 | 
			
		||||
 * @class iterator
 | 
			
		||||
 * @brief A RocksDB database iterator.
 | 
			
		||||
 *
 | 
			
		||||
 * This class represents an iterator for RocksDB (Persistent Key-Value Store) databases.
 | 
			
		||||
 * It is a circular iterator, meaning that the end() sentinel value is always in the iteration cycle.
 | 
			
		||||
 *
 | 
			
		||||
 * Key characteristics:
 | 
			
		||||
 * - Decrementing the end iterator points to the last key in the database.
 | 
			
		||||
 * - Incrementing the end iterator points to the first key in the database.
 | 
			
		||||
 */
 | 
			
		||||
class iterator
 | 
			
		||||
{
 | 
			
		||||
	std::unique_ptr<::rocksdb::Iterator> iter;
 | 
			
		||||
	std::variant<std::monostate, std::pair<::rocksdb::Slice, ::rocksdb::Slice>> current;
 | 
			
		||||
	void update ();
 | 
			
		||||
	iterator (decltype (iter) && iter);
 | 
			
		||||
	static auto make_iterator (::rocksdb::DB * db, std::variant<::rocksdb::Transaction *, ::rocksdb::ReadOptions *> snapshot, ::rocksdb::ColumnFamilyHandle * table) -> std::unique_ptr<::rocksdb::Iterator>;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	iterator () = default;
 | 
			
		||||
	using iterator_category = std::bidirectional_iterator_tag;
 | 
			
		||||
	using value_type = std::pair<::rocksdb::Slice, ::rocksdb::Slice>;
 | 
			
		||||
	using pointer = value_type *;
 | 
			
		||||
	using const_pointer = value_type const *;
 | 
			
		||||
	using reference = value_type &;
 | 
			
		||||
	using const_reference = value_type const &;
 | 
			
		||||
 | 
			
		||||
	iterator (::rocksdb::DB * db, transaction const & transaction_a, ::rocksdb::ColumnFamilyHandle * handle_a, db_val const * val_a, bool const direction_asc) :
 | 
			
		||||
		iterator_impl<T, U> (transaction_a)
 | 
			
		||||
	{
 | 
			
		||||
		auto internals = rocksdb::tx (transaction_a);
 | 
			
		||||
		auto iterator = std::visit ([&] (auto && ptr) {
 | 
			
		||||
			using V = std::remove_cvref_t<decltype (ptr)>;
 | 
			
		||||
			if constexpr (std::is_same_v<V, ::rocksdb::Transaction *>)
 | 
			
		||||
			{
 | 
			
		||||
				::rocksdb::ReadOptions ropts;
 | 
			
		||||
				ropts.fill_cache = false;
 | 
			
		||||
				return ptr->GetIterator (ropts, handle_a);
 | 
			
		||||
			}
 | 
			
		||||
			else if constexpr (std::is_same_v<V, ::rocksdb::ReadOptions *>)
 | 
			
		||||
			{
 | 
			
		||||
				ptr->fill_cache = false;
 | 
			
		||||
				return db->NewIterator (*ptr, handle_a);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				static_assert (sizeof (V) == 0, "Missing variant handler for type V");
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		internals);
 | 
			
		||||
		cursor.reset (iterator);
 | 
			
		||||
	static auto begin (::rocksdb::DB * db, std::variant<::rocksdb::Transaction *, ::rocksdb::ReadOptions *> snapshot, ::rocksdb::ColumnFamilyHandle * table) -> iterator;
 | 
			
		||||
	static auto end (::rocksdb::DB * db, std::variant<::rocksdb::Transaction *, ::rocksdb::ReadOptions *> snapshot, ::rocksdb::ColumnFamilyHandle * table) -> iterator;
 | 
			
		||||
	static auto lower_bound (::rocksdb::DB * db, std::variant<::rocksdb::Transaction *, ::rocksdb::ReadOptions *> snapshot, ::rocksdb::ColumnFamilyHandle * table, ::rocksdb::Slice const & lower_bound) -> iterator;
 | 
			
		||||
 | 
			
		||||
		if (val_a)
 | 
			
		||||
		{
 | 
			
		||||
			cursor->Seek (*val_a);
 | 
			
		||||
		}
 | 
			
		||||
		else if (direction_asc)
 | 
			
		||||
		{
 | 
			
		||||
			cursor->SeekToFirst ();
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			cursor->SeekToLast ();
 | 
			
		||||
		}
 | 
			
		||||
	iterator (iterator const &) = delete;
 | 
			
		||||
	auto operator= (iterator const &) -> iterator & = delete;
 | 
			
		||||
 | 
			
		||||
		if (cursor->Valid ())
 | 
			
		||||
		{
 | 
			
		||||
			current.first = cursor->key ();
 | 
			
		||||
			current.second = cursor->value ();
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			clear ();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	iterator (iterator && other_a) noexcept;
 | 
			
		||||
	auto operator= (iterator && other) noexcept -> iterator &;
 | 
			
		||||
 | 
			
		||||
	iterator (::rocksdb::DB * db, store::transaction const & transaction_a, ::rocksdb::ColumnFamilyHandle * handle_a) :
 | 
			
		||||
		iterator (db, transaction_a, handle_a, nullptr)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iterator (iterator<T, U> && other_a)
 | 
			
		||||
	{
 | 
			
		||||
		cursor = other_a.cursor;
 | 
			
		||||
		other_a.cursor = nullptr;
 | 
			
		||||
		current = other_a.current;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iterator (iterator<T, U> const &) = delete;
 | 
			
		||||
 | 
			
		||||
	iterator_impl<T, U> & operator++ () override
 | 
			
		||||
	{
 | 
			
		||||
		cursor->Next ();
 | 
			
		||||
		if (cursor->Valid ())
 | 
			
		||||
		{
 | 
			
		||||
			current.first = cursor->key ();
 | 
			
		||||
			current.second = cursor->value ();
 | 
			
		||||
 | 
			
		||||
			if (current.first.size () != sizeof (T))
 | 
			
		||||
			{
 | 
			
		||||
				clear ();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			clear ();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iterator_impl<T, U> & operator-- () override
 | 
			
		||||
	{
 | 
			
		||||
		cursor->Prev ();
 | 
			
		||||
		if (cursor->Valid ())
 | 
			
		||||
		{
 | 
			
		||||
			current.first = cursor->key ();
 | 
			
		||||
			current.second = cursor->value ();
 | 
			
		||||
 | 
			
		||||
			if (current.first.size () != sizeof (T))
 | 
			
		||||
			{
 | 
			
		||||
				clear ();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			clear ();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::pair<nano::store::rocksdb::db_val, nano::store::rocksdb::db_val> * operator->()
 | 
			
		||||
	{
 | 
			
		||||
		return ¤t;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool operator== (iterator_impl<T, U> const & base_a) const override
 | 
			
		||||
	{
 | 
			
		||||
		auto const other_a (boost::polymorphic_downcast<iterator<T, U> const *> (&base_a));
 | 
			
		||||
 | 
			
		||||
		if (!current.first.data () && !other_a->current.first.data ())
 | 
			
		||||
		{
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		else if (!current.first.data () || !other_a->current.first.data ())
 | 
			
		||||
		{
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		auto result (std::memcmp (current.first.data (), other_a->current.first.data (), current.first.size ()) == 0);
 | 
			
		||||
		debug_assert (!result || (current.first.size () == other_a->current.first.size ()));
 | 
			
		||||
		debug_assert (!result || std::memcmp (current.second.data (), other_a->current.second.data (), current.second.size ()) == 0);
 | 
			
		||||
		debug_assert (!result || (current.second.size () == other_a->current.second.size ()));
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool is_end_sentinal () const override
 | 
			
		||||
	{
 | 
			
		||||
		return current.first.size () == 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void fill (std::pair<T, U> & value_a) const override
 | 
			
		||||
	{
 | 
			
		||||
		{
 | 
			
		||||
			if (current.first.size () != 0)
 | 
			
		||||
			{
 | 
			
		||||
				value_a.first = static_cast<T> (current.first);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				value_a.first = T ();
 | 
			
		||||
			}
 | 
			
		||||
			if (current.second.size () != 0)
 | 
			
		||||
			{
 | 
			
		||||
				value_a.second = static_cast<U> (current.second);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				value_a.second = U ();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	void clear ()
 | 
			
		||||
	{
 | 
			
		||||
		current.first = nano::store::rocksdb::db_val{};
 | 
			
		||||
		current.second = nano::store::rocksdb::db_val{};
 | 
			
		||||
		debug_assert (is_end_sentinal ());
 | 
			
		||||
	}
 | 
			
		||||
	iterator<T, U> & operator= (iterator<T, U> && other_a)
 | 
			
		||||
	{
 | 
			
		||||
		cursor = std::move (other_a.cursor);
 | 
			
		||||
		current = other_a.current;
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
	iterator_impl<T, U> & operator= (iterator_impl<T, U> const &) = delete;
 | 
			
		||||
 | 
			
		||||
	std::unique_ptr<::rocksdb::Iterator> cursor;
 | 
			
		||||
	std::pair<nano::store::rocksdb::db_val, nano::store::rocksdb::db_val> current;
 | 
			
		||||
	auto operator++ () -> iterator &;
 | 
			
		||||
	auto operator-- () -> iterator &;
 | 
			
		||||
	auto operator->() const -> const_pointer;
 | 
			
		||||
	auto operator* () const -> const_reference;
 | 
			
		||||
	auto operator== (iterator const & other) const -> bool;
 | 
			
		||||
	auto span () const -> std::pair<std::span<uint8_t const>, std::span<uint8_t const>>;
 | 
			
		||||
	bool is_end () const;
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
#include <nano/store/rocksdb/online_weight.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/rocksdb.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/utility.hpp>
 | 
			
		||||
 | 
			
		||||
nano::store::rocksdb::online_weight::online_weight (nano::store::rocksdb::component & store_a) :
 | 
			
		||||
	store{ store_a }
 | 
			
		||||
| 
						 | 
				
			
			@ -20,17 +21,12 @@ void nano::store::rocksdb::online_weight::del (store::write_transaction const &
 | 
			
		|||
 | 
			
		||||
auto nano::store::rocksdb::online_weight::begin (store::transaction const & transaction) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<uint64_t, nano::amount> (transaction, tables::online_weight);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::online_weight::rbegin (store::transaction const & transaction) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<uint64_t, nano::amount> (transaction, tables::online_weight, false);
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::begin (store.db.get (), rocksdb::tx (transaction), store.table_to_column_family (tables::online_weight)) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::online_weight::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::end (store.db.get (), rocksdb::tx (transaction_a), store.table_to_column_family (tables::online_weight)) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t nano::store::rocksdb::online_weight::count (store::transaction const & transaction) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,6 @@ public:
 | 
			
		|||
	void put (store::write_transaction const & transaction_a, uint64_t time_a, nano::amount const & amount_a) override;
 | 
			
		||||
	void del (store::write_transaction const & transaction_a, uint64_t time_a) override;
 | 
			
		||||
	iterator begin (store::transaction const & transaction_a) const override;
 | 
			
		||||
	iterator rbegin (store::transaction const & transaction_a) const override;
 | 
			
		||||
	iterator end (store::transaction const & transaction_a) const override;
 | 
			
		||||
	size_t count (store::transaction const & transaction_a) const override;
 | 
			
		||||
	void clear (store::write_transaction const & transaction_a) override;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
#include <nano/store/rocksdb/peer.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/rocksdb.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/utility.hpp>
 | 
			
		||||
 | 
			
		||||
nano::store::rocksdb::peer::peer (nano::store::rocksdb::component & store) :
 | 
			
		||||
	store{ store } {};
 | 
			
		||||
| 
						 | 
				
			
			@ -47,10 +48,10 @@ void nano::store::rocksdb::peer::clear (store::write_transaction const & transac
 | 
			
		|||
 | 
			
		||||
auto nano::store::rocksdb::peer::begin (store::transaction const & transaction) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::endpoint_key, nano::millis_t> (transaction, tables::peers);
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::begin (store.db.get (), rocksdb::tx (transaction), store.table_to_column_family (tables::peers)) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::peer::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::end (store.db.get (), rocksdb::tx (transaction_a), store.table_to_column_family (tables::peers)) } };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
#include <nano/secure/parallel_traversal.hpp>
 | 
			
		||||
#include <nano/store/lmdb/pending.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/rocksdb.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/utility.hpp>
 | 
			
		||||
 | 
			
		||||
nano::store::rocksdb::pending::pending (nano::store::rocksdb::component & store) :
 | 
			
		||||
	store{ store } {};
 | 
			
		||||
| 
						 | 
				
			
			@ -47,17 +48,18 @@ bool nano::store::rocksdb::pending::any (store::transaction const & transaction_
 | 
			
		|||
 | 
			
		||||
auto nano::store::rocksdb::pending::begin (store::transaction const & transaction_a, nano::pending_key const & key_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.template make_iterator<nano::pending_key, nano::pending_info> (transaction_a, tables::pending, key_a);
 | 
			
		||||
	rocksdb::db_val val{ key_a };
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::lower_bound (store.db.get (), rocksdb::tx (transaction_a), store.table_to_column_family (tables::pending), val) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::pending::begin (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.template make_iterator<nano::pending_key, nano::pending_info> (transaction_a, tables::pending);
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::begin (store.db.get (), rocksdb::tx (transaction_a), store.table_to_column_family (tables::pending)) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::pending::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::end (store.db.get (), rocksdb::tx (transaction_a), store.table_to_column_family (tables::pending)) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::store::rocksdb::pending::for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const & action_a) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
#include <nano/secure/parallel_traversal.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/pruned.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/rocksdb.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/utility.hpp>
 | 
			
		||||
 | 
			
		||||
nano::store::rocksdb::pruned::pruned (nano::store::rocksdb::component & store_a) :
 | 
			
		||||
	store{ store_a } {};
 | 
			
		||||
| 
						 | 
				
			
			@ -47,17 +48,18 @@ void nano::store::rocksdb::pruned::clear (store::write_transaction const & trans
 | 
			
		|||
 | 
			
		||||
auto nano::store::rocksdb::pruned::begin (store::transaction const & transaction_a, nano::block_hash const & hash_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::block_hash, std::nullptr_t> (transaction_a, tables::pruned, hash_a);
 | 
			
		||||
	rocksdb::db_val val{ hash_a };
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::lower_bound (store.db.get (), rocksdb::tx (transaction_a), store.table_to_column_family (tables::pruned), val) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::pruned::begin (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::block_hash, std::nullptr_t> (transaction_a, tables::pruned);
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::begin (store.db.get (), rocksdb::tx (transaction_a), store.table_to_column_family (tables::pruned)) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::pruned::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::end (store.db.get (), rocksdb::tx (transaction_a), store.table_to_column_family (tables::pruned)) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::store::rocksdb::pruned::for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const & action_a) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
#include <nano/secure/parallel_traversal.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/rep_weight.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/rocksdb.hpp>
 | 
			
		||||
#include <nano/store/rocksdb/utility.hpp>
 | 
			
		||||
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -44,17 +45,18 @@ void nano::store::rocksdb::rep_weight::del (store::write_transaction const & txn
 | 
			
		|||
 | 
			
		||||
auto nano::store::rocksdb::rep_weight::begin (store::transaction const & txn_a, nano::account const & representative_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::account, nano::uint128_union> (txn_a, tables::rep_weights, representative_a);
 | 
			
		||||
	rocksdb::db_val val{ representative_a };
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::lower_bound (store.db.get (), rocksdb::tx (txn_a), store.table_to_column_family (tables::rep_weights), val) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::rep_weight::begin (store::transaction const & txn_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return store.make_iterator<nano::account, nano::uint128_union> (txn_a, tables::rep_weights);
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::begin (store.db.get (), rocksdb::tx (txn_a), store.table_to_column_family (tables::rep_weights)) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto nano::store::rocksdb::rep_weight::end (store::transaction const & transaction_a) const -> iterator
 | 
			
		||||
{
 | 
			
		||||
	return iterator{ nullptr };
 | 
			
		||||
	return iterator{ store::iterator{ rocksdb::iterator::end (store.db.get (), rocksdb::tx (transaction_a), store.table_to_column_family (tables::rep_weights)) } };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::store::rocksdb::rep_weight::for_each_par (std::function<void (store::read_transaction const &, iterator, iterator)> const & action_a) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -302,8 +302,8 @@ void nano::store::rocksdb::component::upgrade_v22_to_v23 (store::write_transacti
 | 
			
		|||
		auto transaction = tx_begin_read ();
 | 
			
		||||
 | 
			
		||||
		// Manually create v22 compatible iterator to read accounts
 | 
			
		||||
		auto it = make_iterator<nano::account, nano::account_info_v22> (transaction, tables::accounts);
 | 
			
		||||
		auto const end = store::iterator<nano::account, nano::account_info_v22> (nullptr);
 | 
			
		||||
		auto it = typed_iterator<nano::account, nano::account_info_v22> (store::iterator{ rocksdb::iterator::begin (db.get (), rocksdb::tx (transaction), table_to_column_family (tables::accounts)) });
 | 
			
		||||
		auto const end = typed_iterator<nano::account, nano::account_info_v22>{ store::iterator{ rocksdb::iterator::end (db.get (), rocksdb::tx (transaction), table_to_column_family (tables::accounts)) } };
 | 
			
		||||
 | 
			
		||||
		for (; it != end; ++it)
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -85,18 +85,6 @@ public:
 | 
			
		|||
 | 
			
		||||
	unsigned max_block_write_batch_num () const override;
 | 
			
		||||
 | 
			
		||||
	template <typename Key, typename Value>
 | 
			
		||||
	store::iterator<Key, Value> make_iterator (store::transaction const & transaction_a, tables table_a, bool const direction_asc = true) const
 | 
			
		||||
	{
 | 
			
		||||
		return store::iterator<Key, Value> (std::make_unique<nano::store::rocksdb::iterator<Key, Value>> (db.get (), transaction_a, table_to_column_family (table_a), nullptr, direction_asc));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template <typename Key, typename Value>
 | 
			
		||||
	store::iterator<Key, Value> make_iterator (store::transaction const & transaction_a, tables table_a, nano::store::rocksdb::db_val const & key) const
 | 
			
		||||
	{
 | 
			
		||||
		return store::iterator<Key, Value> (std::make_unique<nano::store::rocksdb::iterator<Key, Value>> (db.get (), transaction_a, table_to_column_family (table_a), &key, true));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool init_error () const override;
 | 
			
		||||
 | 
			
		||||
	std::string error_string (int status) const override;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								nano/store/typed_iterator.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								nano/store/typed_iterator.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
 | 
			
		||||
							
								
								
									
										63
									
								
								nano/store/typed_iterator.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								nano/store/typed_iterator.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <nano/store/iterator.hpp>
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <span>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
namespace nano::store
 | 
			
		||||
{
 | 
			
		||||
/**
 | 
			
		||||
 * @class typed_iterator
 | 
			
		||||
 * @brief A generic typed iterator for key-value stores.
 | 
			
		||||
 *
 | 
			
		||||
 * This class represents a typed iterator for key-value store databases, such as RocksDB.
 | 
			
		||||
 * It supports typing for both keys and values, providing type-safe access to the database contents.
 | 
			
		||||
 *
 | 
			
		||||
 * Key characteristics:
 | 
			
		||||
 * - Generic: Works with various key-value store implementations.
 | 
			
		||||
 * - Type-safe: Supports strongly typed keys and values.
 | 
			
		||||
 * - Circular: The end() sentinel value is always in the iteration cycle.
 | 
			
		||||
 * - Automatic deserialization: When pointing to a valid non-sentinel location, it loads and
 | 
			
		||||
 *   deserializes the database value into the appropriate type.
 | 
			
		||||
 *
 | 
			
		||||
 * Behavior:
 | 
			
		||||
 * - Decrementing the end iterator points to the last key-value pair in the database.
 | 
			
		||||
 * - Incrementing the end iterator points to the first key-value pair in the database.
 | 
			
		||||
 */
 | 
			
		||||
template <typename Key, typename Value>
 | 
			
		||||
class typed_iterator final
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	using iterator_category = std::bidirectional_iterator_tag;
 | 
			
		||||
	using value_type = std::pair<Key, Value>;
 | 
			
		||||
	using pointer = value_type *;
 | 
			
		||||
	using const_pointer = value_type const *;
 | 
			
		||||
	using reference = value_type &;
 | 
			
		||||
	using const_reference = value_type const &;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	iterator iter;
 | 
			
		||||
	std::variant<std::monostate, value_type> current;
 | 
			
		||||
	void update ();
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	typed_iterator (iterator && iter) noexcept;
 | 
			
		||||
 | 
			
		||||
	typed_iterator (typed_iterator const &) = delete;
 | 
			
		||||
	auto operator= (typed_iterator const &) -> typed_iterator & = delete;
 | 
			
		||||
 | 
			
		||||
	typed_iterator (typed_iterator && other) noexcept;
 | 
			
		||||
	auto operator= (typed_iterator && other) noexcept -> typed_iterator &;
 | 
			
		||||
 | 
			
		||||
	auto operator++ () -> typed_iterator &;
 | 
			
		||||
	auto operator-- () -> typed_iterator &;
 | 
			
		||||
	auto operator->() const -> const_pointer;
 | 
			
		||||
	auto operator* () const -> const_reference;
 | 
			
		||||
	auto operator== (typed_iterator const & other) const -> bool;
 | 
			
		||||
	auto is_end () const -> bool;
 | 
			
		||||
};
 | 
			
		||||
} // namespace nano::store
 | 
			
		||||
							
								
								
									
										88
									
								
								nano/store/typed_iterator_templ.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								nano/store/typed_iterator_templ.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,88 @@
 | 
			
		|||
#include <nano/lib/utility.hpp>
 | 
			
		||||
#include <nano/store/db_val_impl.hpp>
 | 
			
		||||
#include <nano/store/lmdb/db_val.hpp>
 | 
			
		||||
#include <nano/store/typed_iterator.hpp>
 | 
			
		||||
 | 
			
		||||
namespace nano::store
 | 
			
		||||
{
 | 
			
		||||
template <typename Key, typename Value>
 | 
			
		||||
void typed_iterator<Key, Value>::update ()
 | 
			
		||||
{
 | 
			
		||||
	if (!iter.is_end ())
 | 
			
		||||
	{
 | 
			
		||||
		// FIXME Don't convert via lmdb::db_val, this is just a placeholder
 | 
			
		||||
		auto const & data = *iter;
 | 
			
		||||
		lmdb::db_val key_val{ MDB_val{ data.first.size (), const_cast<void *> (reinterpret_cast<void const *> (data.first.data ())) } };
 | 
			
		||||
		lmdb::db_val value_val{ MDB_val{ data.second.size (), const_cast<void *> (reinterpret_cast<void const *> (data.second.data ())) } };
 | 
			
		||||
		current = std::make_pair (static_cast<Key> (key_val), static_cast<Value> (value_val));
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		current = std::monostate{};
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Key, typename Value>
 | 
			
		||||
typed_iterator<Key, Value>::typed_iterator (iterator && iter) noexcept :
 | 
			
		||||
	iter{ std::move (iter) }
 | 
			
		||||
{
 | 
			
		||||
	update ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Key, typename Value>
 | 
			
		||||
typed_iterator<Key, Value>::typed_iterator (typed_iterator && other) noexcept :
 | 
			
		||||
	iter{ std::move (other.iter) },
 | 
			
		||||
	current{ std::move (other.current) }
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Key, typename Value>
 | 
			
		||||
auto typed_iterator<Key, Value>::operator= (typed_iterator && other) noexcept -> typed_iterator &
 | 
			
		||||
{
 | 
			
		||||
	iter = std::move (other.iter);
 | 
			
		||||
	current = std::move (other.current);
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Key, typename Value>
 | 
			
		||||
auto typed_iterator<Key, Value>::operator++ () -> typed_iterator<Key, Value> &
 | 
			
		||||
{
 | 
			
		||||
	++iter;
 | 
			
		||||
	update ();
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Key, typename Value>
 | 
			
		||||
auto typed_iterator<Key, Value>::operator-- () -> typed_iterator<Key, Value> &
 | 
			
		||||
{
 | 
			
		||||
	--iter;
 | 
			
		||||
	update ();
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Key, typename Value>
 | 
			
		||||
auto typed_iterator<Key, Value>::operator->() const -> const_pointer
 | 
			
		||||
{
 | 
			
		||||
	release_assert (!is_end ());
 | 
			
		||||
	return std::get_if<value_type> (¤t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Key, typename Value>
 | 
			
		||||
auto typed_iterator<Key, Value>::operator* () const -> const_reference
 | 
			
		||||
{
 | 
			
		||||
	release_assert (!is_end ());
 | 
			
		||||
	return std::get<value_type> (current);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Key, typename Value>
 | 
			
		||||
auto typed_iterator<Key, Value>::operator== (typed_iterator<Key, Value> const & other) const -> bool
 | 
			
		||||
{
 | 
			
		||||
	return iter == other.iter;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Key, typename Value>
 | 
			
		||||
auto typed_iterator<Key, Value>::is_end () const -> bool
 | 
			
		||||
{
 | 
			
		||||
	return std::holds_alternative<std::monostate> (current);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue