Merge pull request #4759 from clemahieu/store_iterator_cleanup
Convert store iterators to variants rather than using polymorphism.
This commit is contained in:
commit
09b635f217
64 changed files with 1046 additions and 784 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
|
||||
|
@ -47,9 +48,12 @@ add_library(
|
|||
rocksdb/rocksdb.hpp
|
||||
rocksdb/iterator.hpp
|
||||
rocksdb/transaction_impl.hpp
|
||||
rocksdb/utility.hpp
|
||||
rocksdb/version.hpp
|
||||
tables.hpp
|
||||
transaction.hpp
|
||||
typed_iterator.hpp
|
||||
typed_iterator_templ.hpp
|
||||
version.hpp
|
||||
versioning.hpp
|
||||
account.cpp
|
||||
|
@ -58,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
|
||||
|
@ -79,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
|
||||
|
@ -91,8 +97,10 @@ add_library(
|
|||
rocksdb/rep_weight.cpp
|
||||
rocksdb/rocksdb.cpp
|
||||
rocksdb/transaction.cpp
|
||||
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,207 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/store/component.hpp>
|
||||
#include <nano/store/iterator.hpp>
|
||||
#include <nano/store/rocksdb/db_val.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
|
||||
{
|
||||
inline bool is_read (nano::store::transaction const & transaction_a)
|
||||
{
|
||||
return (dynamic_cast<nano::store::read_transaction const *> (&transaction_a) != nullptr);
|
||||
}
|
||||
|
||||
inline rocksdb::ReadOptions & snapshot_options (nano::store::transaction const & transaction_a)
|
||||
{
|
||||
debug_assert (is_read (transaction_a));
|
||||
return *static_cast<rocksdb::ReadOptions *> (transaction_a.get_handle ());
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// Don't fill the block cache for any blocks read as a result of an iterator
|
||||
if (is_read (transaction_a))
|
||||
{
|
||||
auto read_options = snapshot_options (transaction_a);
|
||||
read_options.fill_cache = false;
|
||||
cursor.reset (db->NewIterator (read_options, handle_a));
|
||||
}
|
||||
else
|
||||
{
|
||||
::rocksdb::ReadOptions ropts;
|
||||
ropts.fill_cache = false;
|
||||
cursor.reset (tx (transaction_a)->GetIterator (ropts, handle_a));
|
||||
}
|
||||
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;
|
||||
|
||||
private:
|
||||
::rocksdb::Transaction * tx (store::transaction const & transaction_a) const
|
||||
{
|
||||
return static_cast<::rocksdb::Transaction *> (transaction_a.get_handle ());
|
||||
}
|
||||
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
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <nano/store/rocksdb/iterator.hpp>
|
||||
#include <nano/store/rocksdb/rocksdb.hpp>
|
||||
#include <nano/store/rocksdb/transaction_impl.hpp>
|
||||
#include <nano/store/rocksdb/utility.hpp>
|
||||
#include <nano/store/version.hpp>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
@ -301,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)
|
||||
{
|
||||
|
@ -499,19 +500,27 @@ rocksdb::ColumnFamilyHandle * nano::store::rocksdb::component::table_to_column_f
|
|||
bool nano::store::rocksdb::component::exists (store::transaction const & transaction_a, tables table_a, nano::store::rocksdb::db_val const & key_a) const
|
||||
{
|
||||
::rocksdb::PinnableSlice slice;
|
||||
::rocksdb::Status status;
|
||||
if (is_read (transaction_a))
|
||||
{
|
||||
status = db->Get (snapshot_options (transaction_a), table_to_column_family (table_a), key_a, &slice);
|
||||
}
|
||||
else
|
||||
{
|
||||
::rocksdb::ReadOptions options;
|
||||
options.fill_cache = false;
|
||||
status = tx (transaction_a)->Get (options, table_to_column_family (table_a), key_a, &slice);
|
||||
}
|
||||
auto internals = rocksdb::tx (transaction_a);
|
||||
auto status = std::visit ([&] (auto && ptr) {
|
||||
using V = std::remove_cvref_t<decltype (ptr)>;
|
||||
if constexpr (std::is_same_v<V, ::rocksdb::Transaction *>)
|
||||
{
|
||||
::rocksdb::ReadOptions options;
|
||||
options.fill_cache = false;
|
||||
return ptr->Get (options, table_to_column_family (table_a), key_a, &slice);
|
||||
}
|
||||
else if constexpr (std::is_same_v<V, ::rocksdb::ReadOptions *>)
|
||||
{
|
||||
return db->Get (*ptr, table_to_column_family (table_a), key_a, &slice);
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert (sizeof (V) == 0, "Missing variant handler for type V");
|
||||
}
|
||||
},
|
||||
internals);
|
||||
|
||||
return (status.ok ());
|
||||
return status.ok ();
|
||||
}
|
||||
|
||||
int nano::store::rocksdb::component::del (store::write_transaction const & transaction_a, tables table_a, nano::store::rocksdb::db_val const & key_a)
|
||||
|
@ -520,7 +529,7 @@ int nano::store::rocksdb::component::del (store::write_transaction const & trans
|
|||
// RocksDB does not report not_found status, it is a pre-condition that the key exists
|
||||
debug_assert (exists (transaction_a, table_a, key_a));
|
||||
flush_tombstones_check (table_a);
|
||||
return tx (transaction_a)->Delete (table_to_column_family (table_a), key_a).code ();
|
||||
return std::get<::rocksdb::Transaction *> (rocksdb::tx (transaction_a))->Delete (table_to_column_family (table_a), key_a).code ();
|
||||
}
|
||||
|
||||
void nano::store::rocksdb::component::flush_tombstones_check (tables table_a)
|
||||
|
@ -543,26 +552,28 @@ void nano::store::rocksdb::component::flush_table (nano::tables table_a)
|
|||
db->Flush (::rocksdb::FlushOptions{}, table_to_column_family (table_a));
|
||||
}
|
||||
|
||||
rocksdb::Transaction * nano::store::rocksdb::component::tx (store::transaction const & transaction_a) const
|
||||
{
|
||||
debug_assert (!is_read (transaction_a));
|
||||
return static_cast<::rocksdb::Transaction *> (transaction_a.get_handle ());
|
||||
}
|
||||
|
||||
int nano::store::rocksdb::component::get (store::transaction const & transaction_a, tables table_a, nano::store::rocksdb::db_val const & key_a, nano::store::rocksdb::db_val & value_a) const
|
||||
{
|
||||
::rocksdb::ReadOptions options;
|
||||
::rocksdb::PinnableSlice slice;
|
||||
auto handle = table_to_column_family (table_a);
|
||||
::rocksdb::Status status;
|
||||
if (is_read (transaction_a))
|
||||
{
|
||||
status = db->Get (snapshot_options (transaction_a), handle, key_a, &slice);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = tx (transaction_a)->Get (options, handle, key_a, &slice);
|
||||
}
|
||||
auto internals = rocksdb::tx (transaction_a);
|
||||
auto status = std::visit ([&] (auto && ptr) {
|
||||
using V = std::remove_cvref_t<decltype (ptr)>;
|
||||
if constexpr (std::is_same_v<V, ::rocksdb::Transaction *>)
|
||||
{
|
||||
return ptr->Get (options, handle, key_a, &slice);
|
||||
}
|
||||
else if constexpr (std::is_same_v<V, ::rocksdb::ReadOptions *>)
|
||||
{
|
||||
return db->Get (*ptr, handle, key_a, &slice);
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert (sizeof (V) == 0, "Missing variant handler for type V");
|
||||
}
|
||||
},
|
||||
internals);
|
||||
|
||||
if (status.ok ())
|
||||
{
|
||||
|
@ -576,8 +587,7 @@ int nano::store::rocksdb::component::get (store::transaction const & transaction
|
|||
int nano::store::rocksdb::component::put (store::write_transaction const & transaction_a, tables table_a, nano::store::rocksdb::db_val const & key_a, nano::store::rocksdb::db_val const & value_a)
|
||||
{
|
||||
debug_assert (transaction_a.contains (table_a));
|
||||
auto txn = tx (transaction_a);
|
||||
return txn->Put (table_to_column_family (table_a), key_a, value_a).code ();
|
||||
return std::get<::rocksdb::Transaction *> (rocksdb::tx (transaction_a))->Put (table_to_column_family (table_a), key_a, value_a).code ();
|
||||
}
|
||||
|
||||
bool nano::store::rocksdb::component::not_found (int status) const
|
||||
|
|
|
@ -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;
|
||||
|
@ -122,7 +110,6 @@ private:
|
|||
std::unordered_map<nano::tables, tombstone_info> tombstone_map;
|
||||
std::unordered_map<char const *, nano::tables> cf_name_table_map;
|
||||
|
||||
::rocksdb::Transaction * tx (store::transaction const & transaction_a) const;
|
||||
std::vector<nano::tables> all_tables () const;
|
||||
|
||||
bool not_found (int status) const override;
|
||||
|
|
11
nano/store/rocksdb/utility.cpp
Normal file
11
nano/store/rocksdb/utility.cpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <nano/store/rocksdb/transaction_impl.hpp>
|
||||
#include <nano/store/rocksdb/utility.hpp>
|
||||
|
||||
auto nano::store::rocksdb::tx (store::transaction const & transaction_a) -> std::variant<::rocksdb::Transaction *, ::rocksdb::ReadOptions *>
|
||||
{
|
||||
if (dynamic_cast<nano::store::read_transaction const *> (&transaction_a) != nullptr)
|
||||
{
|
||||
return static_cast<::rocksdb::ReadOptions *> (transaction_a.get_handle ());
|
||||
}
|
||||
return static_cast<::rocksdb::Transaction *> (transaction_a.get_handle ());
|
||||
}
|
15
nano/store/rocksdb/utility.hpp
Normal file
15
nano/store/rocksdb/utility.hpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <variant>
|
||||
|
||||
#include <rocksdb/utilities/transaction_db.h>
|
||||
|
||||
namespace nano::store
|
||||
{
|
||||
class transaction;
|
||||
}
|
||||
|
||||
namespace nano::store::rocksdb
|
||||
{
|
||||
auto tx (store::transaction const & transaction_a) -> std::variant<::rocksdb::Transaction *, ::rocksdb::ReadOptions *>;
|
||||
}
|
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