Merge pull request #4759 from clemahieu/store_iterator_cleanup

Convert store iterators to variants rather than using polymorphism.
This commit is contained in:
clemahieu 2024-10-27 08:34:10 +00:00 committed by GitHub
commit 09b635f217
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
64 changed files with 1046 additions and 784 deletions

View file

@ -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)

View file

@ -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;

View file

@ -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) :

View file

@ -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 &);

View file

@ -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

View file

@ -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) };
}

View file

@ -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

View file

@ -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>;

View file

@ -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

View file

@ -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)
{

View file

@ -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;

View file

@ -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>;

View file

@ -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;

View file

@ -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> (&current);
}
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);
}
}

View file

@ -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 &current;
}
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

View file

@ -1 +0,0 @@
#include <nano/store/iterator_impl.hpp>

View file

@ -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;
};
}

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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

View 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> (&current);
}
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

View file

@ -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, &current.first.value, &current.second.value, operation));
release_assert (status2 == 0 || status2 == MDB_NOTFOUND);
if (status2 != MDB_NOTFOUND)
{
auto status3 (mdb_cursor_get (cursor, &current.first.value, &current.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, &current.first.value, &current.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, &current.first.value, &current.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 &current;
}
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;
};
}

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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) } };
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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) };
}

View file

@ -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;

View file

@ -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>;

View file

@ -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

View file

@ -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>;

View file

@ -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;

View file

@ -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>;

View file

@ -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;

View 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>;

View file

@ -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 (){};

View 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;
};
}

View 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 ();
}
}

View file

@ -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

View file

@ -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;
};

View file

@ -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

View file

@ -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

View file

@ -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

View 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> (&current);
}
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

View file

@ -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 &current;
}
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;
};
}

View file

@ -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

View file

@ -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;

View file

@ -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)) } };
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View 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 ());
}

View 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 *>;
}

View file

@ -0,0 +1 @@

View 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

View 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> (&current);
}
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);
}
}