diff --git a/cmd/common/db_checklist.cpp b/cmd/common/db_checklist.cpp index e0ed930102..9163789bf9 100644 --- a/cmd/common/db_checklist.cpp +++ b/cmd/common/db_checklist.cpp @@ -40,7 +40,7 @@ void run_db_checklist(NodeSettings& node_settings, bool init_if_empty) { // Open chaindata environment and check tables are consistent log::Message("Opening database", {"path", node_settings.data_directory->chaindata().path().string()}); auto chaindata_env{db::open_env(node_settings.chaindata_env_config)}; - db::RWTxn tx(chaindata_env); + db::RWTxnManaged tx(chaindata_env); // Ensures all tables are present db::table::check_or_create_chaindata_tables(tx); diff --git a/cmd/dev/backend_kv_server.cpp b/cmd/dev/backend_kv_server.cpp index 2cfdc994da..51bb89011c 100644 --- a/cmd/dev/backend_kv_server.cpp +++ b/cmd/dev/backend_kv_server.cpp @@ -188,7 +188,7 @@ int main(int argc, char* argv[]) { SILK_INFO << "BackEndKvServer MDBX max readers: " << database_env.max_readers(); // Read chain config from database (this allows for custom config) - db::ROTxn ro_txn{database_env}; + db::ROTxnManaged ro_txn{database_env}; node_settings.chain_config = db::read_chain_config(ro_txn); if (!node_settings.chain_config.has_value()) { throw std::runtime_error("invalid chain config in database"); diff --git a/cmd/dev/check_changes.cpp b/cmd/dev/check_changes.cpp index 6a55fb9653..8b20c01b7d 100644 --- a/cmd/dev/check_changes.cpp +++ b/cmd/dev/check_changes.cpp @@ -75,7 +75,7 @@ int main(int argc, char* argv[]) { data_dir.deploy(); db::EnvConfig db_config{data_dir.chaindata().path().string()}; auto env{db::open_env(db_config)}; - db::RWTxn txn{env}; + db::RWTxnManaged txn{env}; auto chain_config{db::read_chain_config(txn)}; if (!chain_config) { throw std::runtime_error("Unable to retrieve chain config"); diff --git a/cmd/dev/check_pow.cpp b/cmd/dev/check_pow.cpp index a452c2423f..81814ac4f6 100644 --- a/cmd/dev/check_pow.cpp +++ b/cmd/dev/check_pow.cpp @@ -80,7 +80,7 @@ int main(int argc, char* argv[]) { // Set database parameters db::EnvConfig db_config{options.datadir}; auto env{db::open_env(db_config)}; - db::ROTxn txn{env}; + db::ROTxnManaged txn{env}; auto config{db::read_chain_config(txn)}; if (!config.has_value()) { diff --git a/cmd/dev/check_senders.cpp b/cmd/dev/check_senders.cpp index 3973aca7eb..a6c784d16e 100644 --- a/cmd/dev/check_senders.cpp +++ b/cmd/dev/check_senders.cpp @@ -67,7 +67,7 @@ int main(int argc, char* argv[]) { etl::Collector collector(data_dir.etl().path().string().c_str(), /* flush size */ 512 * kMebi); auto env{db::open_env(db_config)}; - db::ROTxn txn{env}; + db::ROTxnManaged txn{env}; auto canonical_hashes_cursor = txn.ro_cursor(db::table::kCanonicalHashes); auto bodies_cursor = txn.ro_cursor(db::table::kBlockBodies); diff --git a/cmd/dev/scan_txs.cpp b/cmd/dev/scan_txs.cpp index a0f5536fc3..5fb868a10d 100644 --- a/cmd/dev/scan_txs.cpp +++ b/cmd/dev/scan_txs.cpp @@ -64,7 +64,7 @@ int main(int argc, char* argv[]) { data_dir.deploy(); db::EnvConfig db_config{data_dir.chaindata().path().string()}; auto env{db::open_env(db_config)}; - db::RWTxn txn{env}; + db::RWTxnManaged txn{env}; auto chain_config{db::read_chain_config(txn)}; if (!chain_config) { throw std::runtime_error("Unable to retrieve chain config"); diff --git a/cmd/dev/toolbox.cpp b/cmd/dev/toolbox.cpp index 0ce6b6972b..31518f5993 100644 --- a/cmd/dev/toolbox.cpp +++ b/cmd/dev/toolbox.cpp @@ -457,7 +457,7 @@ void do_stage_set(db::EnvConfig& config, std::string&& stage_name, uint32_t new_ } auto env{silkworm::db::open_env(config)}; - db::RWTxn txn{env}; + db::RWTxnManaged txn{env}; if (!db::stages::is_known_stage(stage_name.c_str())) { throw std::runtime_error("Stage name " + stage_name + " is not known"); } @@ -551,7 +551,7 @@ void do_freelist(db::EnvConfig& config, bool detail) { void do_schema(db::EnvConfig& config) { auto env{silkworm::db::open_env(config)}; - db::ROTxn txn{env}; + db::ROTxnManaged txn{env}; auto schema_version{db::read_schema_version(txn)}; if (!schema_version.has_value()) { @@ -845,7 +845,7 @@ void do_init_genesis(DataDirectory& data_dir, const std::string&& json_file, uin // Prime database db::EnvConfig config{data_dir.chaindata().path().string(), /*create*/ true}; auto env{db::open_env(config)}; - db::RWTxn txn{env}; + db::RWTxnManaged txn{env}; db::table::check_or_create_chaindata_tables(txn); db::initialize_genesis(txn, genesis_json, /*allow_exceptions=*/true); @@ -863,7 +863,7 @@ void do_init_genesis(DataDirectory& data_dir, const std::string&& json_file, uin void do_chainconfig(db::EnvConfig& config) { auto env{silkworm::db::open_env(config)}; - db::ROTxn txn{env}; + db::ROTxnManaged txn{env}; auto chain_config{db::read_chain_config(txn)}; if (!chain_config.has_value()) { throw std::runtime_error("Not an initialized Silkworm db or unknown/custom chain "); @@ -882,7 +882,7 @@ void do_first_byte_analysis(db::EnvConfig& config) { } auto env{silkworm::db::open_env(config)}; - db::ROTxn txn{env}; + db::ROTxnManaged txn{env}; std::cout << "\n" << (boost::format(fmt_hdr) % "Table name" % "%") << "\n" @@ -945,7 +945,7 @@ void do_extract_headers(db::EnvConfig& config, const std::string& file_name, uin } auto env{silkworm::db::open_env(config)}; - db::ROTxn txn{env}; + db::ROTxnManaged txn{env}; // We can store all header hashes into a single byte array given all // hashes are same in length. By consequence we only need to assert @@ -1401,7 +1401,7 @@ void do_trie_reset(db::EnvConfig& config, bool always_yes) { } auto env{silkworm::db::open_env(config)}; - db::RWTxn txn{env}; + db::RWTxnManaged txn{env}; log::Info("Clearing ...", {"table", db::table::kTrieOfAccounts.name}); txn->clear_map(db::table::kTrieOfAccounts.name); log::Info("Clearing ...", {"table", db::table::kTrieOfStorage.name}); @@ -1420,7 +1420,7 @@ void do_trie_root(db::EnvConfig& config) { } auto env{silkworm::db::open_env(config)}; - db::ROTxn txn{env}; + db::ROTxnManaged txn{env}; db::PooledCursor trie_accounts(txn, db::table::kTrieOfAccounts); std::string source{db::table::kTrieOfAccounts.name}; @@ -1473,7 +1473,7 @@ void do_reset_to_download(db::EnvConfig& config, bool keep_senders) { log::Info() << "Ok boss ... you say it. Please be patient..."; auto env{silkworm::db::open_env(config)}; - db::RWTxn txn(env); + db::RWTxnManaged txn(env); StopWatch sw(/*auto_start=*/true); // Void finish stage diff --git a/silkworm/node/backend/remote/grpc/kv_calls.cpp b/silkworm/node/backend/remote/grpc/kv_calls.cpp index fc5e16bcae..9aba836dcc 100644 --- a/silkworm/node/backend/remote/grpc/kv_calls.cpp +++ b/silkworm/node/backend/remote/grpc/kv_calls.cpp @@ -83,7 +83,7 @@ awaitable TxCall::operator()(const EthereumBackEnd& backend) { grpc::Status status{grpc::Status::OK}; try { // Create a new read-only transaction. - read_only_txn_ = db::ROTxn{*chaindata_env}; + read_only_txn_ = db::ROTxnManaged{*chaindata_env}; SILK_DEBUG << "TxCall peer: " << peer() << " started tx: " << read_only_txn_->id(); // Send an unsolicited message containing the transaction ID. @@ -336,7 +336,7 @@ void TxCall::handle_max_ttl_timer_expired(const EthereumBackEnd& backend) { // Close and reopen to avoid long-lived transactions (resource-consuming for MDBX) read_only_txn_.abort(); - read_only_txn_ = db::ROTxn{*chaindata_env}; + read_only_txn_ = db::ROTxnManaged{*chaindata_env}; // Restore the whole state of the transaction (i.e. all cursor positions) const bool restore_success = restore_cursors(positions); diff --git a/silkworm/node/backend/remote/grpc/kv_calls.hpp b/silkworm/node/backend/remote/grpc/kv_calls.hpp index 42bd68bcaf..151e922eab 100644 --- a/silkworm/node/backend/remote/grpc/kv_calls.hpp +++ b/silkworm/node/backend/remote/grpc/kv_calls.hpp @@ -146,7 +146,7 @@ class TxCall : public server::BidiStreamingCall { static std::chrono::milliseconds max_ttl_duration_; - db::ROTxn read_only_txn_; + db::ROTxnManaged read_only_txn_; std::map cursors_; uint32_t last_cursor_id_{0}; }; diff --git a/silkworm/node/db/db_utils_test.cpp b/silkworm/node/db/db_utils_test.cpp index 623c352358..2ee890fe20 100644 --- a/silkworm/node/db/db_utils_test.cpp +++ b/silkworm/node/db/db_utils_test.cpp @@ -35,7 +35,7 @@ namespace db { auto db = db::open_env(db_config); db::RWAccess rw_access(db); - db::RWTxn tx = rw_access.start_rw_tx(); + db::RWTxnManaged tx = rw_access.start_rw_tx(); db::table::check_or_create_chaindata_tables(tx); diff --git a/silkworm/node/db/mdbx.cpp b/silkworm/node/db/mdbx.cpp index 600d037eba..9513666d46 100644 --- a/silkworm/node/db/mdbx.cpp +++ b/silkworm/node/db/mdbx.cpp @@ -225,31 +225,31 @@ size_t max_value_size_for_leaf_page(const mdbx::txn& txn, const size_t key_size) return max_value_size_for_leaf_page(page_size, key_size); } -std::unique_ptr ROTxn::ro_cursor(const MapConfig& config) { +std::unique_ptr ROTxnManaged::ro_cursor(const MapConfig& config) { return std::make_unique(*this, config); } -std::unique_ptr ROTxn::ro_cursor_dup_sort(const MapConfig& config) { +std::unique_ptr ROTxnManaged::ro_cursor_dup_sort(const MapConfig& config) { return std::make_unique(*this, config); } -std::unique_ptr RWTxn::rw_cursor(const MapConfig& config) { +std::unique_ptr RWTxnManaged::rw_cursor(const MapConfig& config) { return std::make_unique(*this, config); } -std::unique_ptr RWTxn::rw_cursor_dup_sort(const MapConfig& config) { +std::unique_ptr RWTxnManaged::rw_cursor_dup_sort(const MapConfig& config) { return std::make_unique(*this, config); } -void RWTxn::commit_and_renew() { +void RWTxnManaged::commit_and_renew() { if (!commit_disabled_) { - mdbx::env env = db(); + mdbx::env env = ROTxnManaged::db(); managed_txn_.commit(); managed_txn_ = env.start_write(); // renew transaction } } -void RWTxn::commit_and_stop() { +void RWTxnManaged::commit_and_stop() { if (!commit_disabled_) { managed_txn_.commit(); } diff --git a/silkworm/node/db/mdbx.hpp b/silkworm/node/db/mdbx.hpp index 722f97d516..6c49fbb4e0 100644 --- a/silkworm/node/db/mdbx.hpp +++ b/silkworm/node/db/mdbx.hpp @@ -191,42 +191,63 @@ struct MapConfig { const ::mdbx::value_mode value_mode{::mdbx::value_mode::single}; // Data Storage Mode }; -//! \brief This class wraps a read-only transaction. +//! \brief ROTxn represents a read-only transaction. //! It is used in function signatures to clarify that read-only access is sufficient, read-write access is not required. class ROTxn { public: - explicit ROTxn() = default; - explicit ROTxn(mdbx::env& env) : managed_txn_{env.start_read()} {} - explicit ROTxn(mdbx::env&& env) : managed_txn_{env.start_read()} {} virtual ~ROTxn() = default; + // Access to the underling raw mdbx transaction + virtual mdbx::txn& operator*() = 0; + virtual mdbx::txn* operator->() = 0; + virtual operator mdbx::txn&() = 0; // NOLINT(google-explicit-constructor) + + [[nodiscard]] virtual uint64_t id() const = 0; + [[nodiscard]] virtual bool is_open() const = 0; + [[nodiscard]] virtual mdbx::env db() const = 0; + + virtual std::unique_ptr ro_cursor(const MapConfig& config) = 0; + virtual std::unique_ptr ro_cursor_dup_sort(const MapConfig& config) = 0; + + virtual void abort() = 0; +}; + +//! \brief ROTxnManaged wraps a *managed* read-only transaction, which means the underlying transaction lifecycle +//! is entirely managed by this class. +class ROTxnManaged : public virtual ROTxn { + public: + explicit ROTxnManaged() = default; + explicit ROTxnManaged(mdbx::env& env) : managed_txn_{env.start_read()} {} + explicit ROTxnManaged(mdbx::env&& env) : managed_txn_{env.start_read()} {} + ~ROTxnManaged() override = default; + // Not copyable - ROTxn(const ROTxn&) = delete; - ROTxn& operator=(const ROTxn&) = delete; + ROTxnManaged(const ROTxnManaged&) = delete; + ROTxnManaged& operator=(const ROTxnManaged&) = delete; // Only movable - ROTxn(ROTxn&& source) noexcept : managed_txn_(std::move(source.managed_txn_)) {} - ROTxn& operator=(ROTxn&& other) noexcept { + ROTxnManaged(ROTxnManaged&& source) noexcept : managed_txn_(std::move(source.managed_txn_)) {} + ROTxnManaged& operator=(ROTxnManaged&& other) noexcept { managed_txn_ = std::move(other.managed_txn_); return *this; } // Access to the underling raw mdbx transaction - mdbx::txn& operator*() { return managed_txn_; } - mdbx::txn* operator->() { return &managed_txn_; } - operator mdbx::txn&() { return managed_txn_; } // NOLINT(google-explicit-constructor) + mdbx::txn& operator*() override { return managed_txn_; } + mdbx::txn* operator->() override { return &managed_txn_; } + operator mdbx::txn&() override { return managed_txn_; } // NOLINT(google-explicit-constructor) - [[nodiscard]] uint64_t id() const { return managed_txn_.id(); } - [[nodiscard]] bool is_open() const { return managed_txn_.txn::operator bool(); } - [[nodiscard]] mdbx::env db() const { return managed_txn_.env(); } + [[nodiscard]] uint64_t id() const override { return managed_txn_.id(); } + [[nodiscard]] bool is_open() const override { return managed_txn_.txn::operator bool(); } + [[nodiscard]] mdbx::env db() const override { return managed_txn_.env(); } - virtual std::unique_ptr ro_cursor(const MapConfig& config); - virtual std::unique_ptr ro_cursor_dup_sort(const MapConfig& config); + std::unique_ptr ro_cursor(const MapConfig& config) override; + std::unique_ptr ro_cursor_dup_sort(const MapConfig& config) override; - void abort() { managed_txn_.abort(); } + void abort() override { managed_txn_.abort(); } protected: - explicit ROTxn(mdbx::txn_managed&& source) : managed_txn_{std::move(source)} {} + explicit ROTxnManaged(mdbx::txn_managed&& source) : managed_txn_{std::move(source)} {} mdbx::txn_managed managed_txn_; }; @@ -235,38 +256,55 @@ class ROTxn { //! It is used in function signatures to clarify that read-write access is required. //! It supports explicit disable/enable of commit capabilities. //! Disabling commit is useful for running several stages on a handful of blocks atomically. -class RWTxn : public ROTxn { +class RWTxn : public virtual ROTxn { public: - explicit RWTxn() = default; - // This variant creates new mdbx transactions as need be. - explicit RWTxn(mdbx::env& env) : ROTxn{env.start_write()} {} ~RWTxn() override = default; + virtual void disable_commit() = 0; + virtual void enable_commit() = 0; + + virtual std::unique_ptr rw_cursor(const MapConfig& config) = 0; + virtual std::unique_ptr rw_cursor_dup_sort(const MapConfig& config) = 0; + + virtual void commit_and_renew() = 0; + virtual void commit_and_stop() = 0; +}; + +//! \brief RWTxnManaged wraps a *managed* read-write transaction, which means the underlying transaction lifecycle +//! is entirely managed by this class. +class RWTxnManaged : public RWTxn, public ROTxnManaged { + public: + explicit RWTxnManaged() = default; + // This variant creates new mdbx transactions as need be. + explicit RWTxnManaged(mdbx::env& env) : ROTxnManaged{env.start_write()} {} + ~RWTxnManaged() override = default; + // Not copyable - RWTxn(const RWTxn&) = delete; - RWTxn& operator=(const RWTxn&) = delete; + RWTxnManaged(const RWTxnManaged&) = delete; + RWTxnManaged& operator=(const RWTxnManaged&) = delete; // Only movable - RWTxn(RWTxn&& source) noexcept : ROTxn(std::move(source)), commit_disabled_{source.commit_disabled_} {} - RWTxn& operator=(RWTxn&& other) noexcept { + RWTxnManaged(RWTxnManaged&& source) noexcept + : ROTxnManaged(std::move(source)), commit_disabled_{source.commit_disabled_} {} + RWTxnManaged& operator=(RWTxnManaged&& other) noexcept { commit_disabled_ = other.commit_disabled_; - ROTxn::operator=(std::move(other)); + ROTxnManaged::operator=(std::move(other)); return *this; } - void disable_commit() { commit_disabled_ = true; } - void enable_commit() { commit_disabled_ = false; } + void disable_commit() override { commit_disabled_ = true; } + void enable_commit() override { commit_disabled_ = false; } - virtual std::unique_ptr rw_cursor(const MapConfig& config); - virtual std::unique_ptr rw_cursor_dup_sort(const MapConfig& config); + std::unique_ptr rw_cursor(const MapConfig& config) override; + std::unique_ptr rw_cursor_dup_sort(const MapConfig& config) override; - void commit_and_renew(); - void commit_and_stop(); + void commit_and_renew() override; + void commit_and_stop() override; void reopen(mdbx::env& env) { managed_txn_ = env.start_write(); } protected: - explicit RWTxn(mdbx::txn_managed&& source) : ROTxn{std::move(source)} {} + explicit RWTxnManaged(mdbx::txn_managed&& source) : ROTxnManaged{std::move(source)} {} bool commit_disabled_{false}; }; @@ -277,7 +315,7 @@ class ROAccess { explicit ROAccess(mdbx::env& env) : env_{env} {} ROAccess(const ROAccess& copy) = default; - ROTxn start_ro_tx() { return ROTxn(env_); } + ROTxnManaged start_ro_tx() { return ROTxnManaged(env_); } mdbx::env& operator*() { return env_; } @@ -291,7 +329,7 @@ class RWAccess : public ROAccess { explicit RWAccess(mdbx::env& env) : ROAccess{env} {} RWAccess(const RWAccess& copy) = default; - RWTxn start_rw_tx() { return RWTxn(env_); } + RWTxnManaged start_rw_tx() { return RWTxnManaged(env_); } }; //! \brief Reference to a processing function invoked by cursor_for_each & cursor_for_count on each record @@ -344,13 +382,12 @@ size_t max_value_size_for_leaf_page(const ::mdbx::txn& txn, size_t key_size); //! \brief Managed cursor class to access cursor API //! \remarks Unlike ::mdbx::cursor_managed this class withdraws and deposits allocated MDBX_cursor handles in a -//! thread_local pool for reuse. This helps avoiding multiple mallocs on cursor creation. +//! thread-local pool for reuse. This helps avoiding multiple malloc on cursor creation. class PooledCursor : public RWCursorDupSort, protected ::mdbx::cursor { public: explicit PooledCursor(); explicit PooledCursor(RWTxn& txn, ::mdbx::map_handle map); explicit PooledCursor(::mdbx::txn& txn, const MapConfig& config); - explicit PooledCursor(RWTxn& txn, const MapConfig& config) : PooledCursor(*txn, config) {} ~PooledCursor() override; PooledCursor(PooledCursor&& other) noexcept; diff --git a/silkworm/node/db/mdbx_test.cpp b/silkworm/node/db/mdbx_test.cpp index d6c75622a6..1dcdd7e981 100644 --- a/silkworm/node/db/mdbx_test.cpp +++ b/silkworm/node/db/mdbx_test.cpp @@ -218,7 +218,7 @@ TEST_CASE("RWTxn") { SECTION("Managed") { { - auto tx{db::RWTxn(env)}; + auto tx{db::RWTxnManaged(env)}; db::PooledCursor table_cursor(*tx, {table_name}); // populate table @@ -235,19 +235,19 @@ TEST_CASE("RWTxn") { } SECTION("External") { - RWTxn tx{env}; + RWTxnManaged tx{env}; tx.disable_commit(); { (void)tx->create_map(table_name, mdbx::key_mode::usual, mdbx::value_mode::single); tx.commit_and_renew(); // Does not have any effect } tx.abort(); - RWTxn tx2{env}; + RWTxnManaged tx2{env}; REQUIRE(db::has_map(tx2, table_name) == false); } SECTION("Cursor from RWTxn") { - auto tx{db::RWTxn(env)}; + auto tx{db::RWTxnManaged(env)}; db::PooledCursor table_cursor(tx, {table_name}); REQUIRE(table_cursor.empty()); REQUIRE_NOTHROW(table_cursor.bind(tx, {table_name})); diff --git a/silkworm/node/db/memory_mutation.cpp b/silkworm/node/db/memory_mutation.cpp index 26bf9b1c12..82344633e9 100644 --- a/silkworm/node/db/memory_mutation.cpp +++ b/silkworm/node/db/memory_mutation.cpp @@ -39,7 +39,7 @@ MemoryDatabase::MemoryDatabase(const std::filesystem::path& tmp_dir) { memory_env_ = db::open_env(memory_config); // Create predefined tables for chaindata schema - RWTxn txn{memory_env_}; + RWTxnManaged txn{memory_env_}; table::check_or_create_chaindata_tables(txn); txn.commit_and_stop(); } @@ -69,7 +69,7 @@ ::mdbx::txn_managed MemoryOverlay::start_rw_txn() { } MemoryMutation::MemoryMutation(MemoryOverlay& overlay) - : RWTxn{overlay.start_rw_txn()}, overlay_(overlay) { + : RWTxnManaged{overlay.start_rw_txn()}, overlay_(overlay) { // Initialize sequences db::PooledCursor cursor{*overlay_.external_txn(), db::table::kSequence}; db::PooledCursor memory_cursor{managed_txn_, db::table::kSequence}; diff --git a/silkworm/node/db/memory_mutation.hpp b/silkworm/node/db/memory_mutation.hpp index edb1921c58..fc9b3ed93c 100644 --- a/silkworm/node/db/memory_mutation.hpp +++ b/silkworm/node/db/memory_mutation.hpp @@ -56,7 +56,7 @@ class MemoryOverlay { class MemoryMutationCursor; -class MemoryMutation : public RWTxn { +class MemoryMutation : public RWTxnManaged { public: explicit MemoryMutation(MemoryOverlay& overlay); MemoryMutation(MemoryMutation&& other) noexcept = default; diff --git a/silkworm/node/db/memory_mutation_cursor_test.cpp b/silkworm/node/db/memory_mutation_cursor_test.cpp index 764458fb6e..9e6ce6c366 100644 --- a/silkworm/node/db/memory_mutation_cursor_test.cpp +++ b/silkworm/node/db/memory_mutation_cursor_test.cpp @@ -25,7 +25,7 @@ namespace silkworm::db { static mdbx::env_managed create_main_env(const db::EnvConfig& main_db_config) { auto main_env = db::open_env(main_db_config); - RWTxn main_txn{main_env}; + RWTxnManaged main_txn{main_env}; table::check_or_create_chaindata_tables(main_txn); open_map(main_txn, db::table::kCode); open_map(main_txn, db::table::kAccountChangeSet); @@ -85,7 +85,7 @@ struct MemoryMutationCursorTest { .in_memory = true, }; mdbx::env_managed main_env{create_main_env(main_db_config)}; - RWTxn main_txn{main_env}; + RWTxnManaged main_txn{main_env}; MemoryOverlay overlay{tmp_dir.path(), &main_txn}; MemoryMutation mutation{overlay}; test_util::SetLogVerbosityGuard log_guard_{log::Level::kNone}; diff --git a/silkworm/node/db/memory_mutation_test.cpp b/silkworm/node/db/memory_mutation_test.cpp index 634e9c767d..16a8bd102c 100644 --- a/silkworm/node/db/memory_mutation_test.cpp +++ b/silkworm/node/db/memory_mutation_test.cpp @@ -60,7 +60,7 @@ TEST_CASE("MemoryMutation", "[silkworm][node][db][memory_mutation]") { .in_memory = true, }; auto main_env{db::open_env(main_db_config)}; - RWTxn main_rw_txn{main_env}; + RWTxnManaged main_rw_txn{main_env}; MemoryOverlay overlay{tmp_dir.path(), &main_rw_txn}; SECTION("Create one memory mutation") { diff --git a/silkworm/node/node.cpp b/silkworm/node/node.cpp index daf0d885e1..1aee82f63a 100644 --- a/silkworm/node/node.cpp +++ b/silkworm/node/node.cpp @@ -99,7 +99,7 @@ void NodeImpl::setup_snapshots() { throw std::runtime_error{"Cannot increase max file descriptor up to " + std::to_string(kMaxFileDescriptors)}; } - db::RWTxn rw_txn{chaindata_db_}; + db::RWTxnManaged rw_txn{chaindata_db_}; // Snapshot sync - download chain from peers using snapshot files snapshot::SnapshotSync snapshot_sync{&snapshot_repository_, settings_.chain_config.value()}; diff --git a/silkworm/node/stagedsync/forks/extending_fork.cpp b/silkworm/node/stagedsync/forks/extending_fork.cpp index 7983a5f6e0..627ebc9166 100644 --- a/silkworm/node/stagedsync/forks/extending_fork.cpp +++ b/silkworm/node/stagedsync/forks/extending_fork.cpp @@ -62,7 +62,7 @@ void ExtendingFork::start_with(BlockId new_head, std::list(forking_point_, - db::ROTxn(main_chain_.tx().db()), + db::ROTxnManaged(main_chain_.tx().db()), main_chain_.node_settings()); // create the real fork fork_->extend_with(blocks_); // extend it with the blocks ensure(fork_->current_head() == new_head, "fork head mismatch"); diff --git a/silkworm/node/stagedsync/forks/fork.cpp b/silkworm/node/stagedsync/forks/fork.cpp index f7c07ae1b9..96f0e48323 100644 --- a/silkworm/node/stagedsync/forks/fork.cpp +++ b/silkworm/node/stagedsync/forks/fork.cpp @@ -28,7 +28,7 @@ namespace silkworm::stagedsync { -Fork::Fork(BlockId forking_point, db::ROTxn&& main_chain_tx, NodeSettings& ns) +Fork::Fork(BlockId forking_point, db::ROTxnManaged&& main_chain_tx, NodeSettings& ns) : main_tx_{std::move(main_chain_tx)}, memory_db_{TemporaryDirectory::get_unique_temporary_path(ns.data_directory->forks().path()), &main_tx_}, memory_tx_{memory_db_}, diff --git a/silkworm/node/stagedsync/forks/fork.hpp b/silkworm/node/stagedsync/forks/fork.hpp index 98c9f0de26..addb4404ee 100644 --- a/silkworm/node/stagedsync/forks/fork.hpp +++ b/silkworm/node/stagedsync/forks/fork.hpp @@ -35,7 +35,7 @@ class MainChain; class Fork { public: - explicit Fork(BlockId forking_point, db::ROTxn&& main_chain_tx, NodeSettings&); + explicit Fork(BlockId forking_point, db::ROTxnManaged&& main_chain_tx, NodeSettings&); Fork(const Fork&) = delete; void close(); @@ -71,7 +71,7 @@ class Fork { std::set collect_bad_headers(InvalidChain& invalid_chain); - db::ROTxn main_tx_; + db::ROTxnManaged main_tx_; db::MemoryOverlay memory_db_; mutable db::MemoryMutation memory_tx_; db::DataModel data_model_; diff --git a/silkworm/node/stagedsync/forks/fork_test.cpp b/silkworm/node/stagedsync/forks/fork_test.cpp index b27cfb82c4..362556a37a 100644 --- a/silkworm/node/stagedsync/forks/fork_test.cpp +++ b/silkworm/node/stagedsync/forks/fork_test.cpp @@ -133,7 +133,7 @@ TEST_CASE("Fork") { BlockId forking_point = main_chain.last_chosen_head(); Fork_ForTest fork{forking_point, - db::ROTxn(main_chain.tx().db()), // this need to be on a different thread than main_chain + db::ROTxnManaged(main_chain.tx().db()), // this need to be on a different thread than main_chain context.node_settings()}; CHECK(db::stages::read_stage_progress(fork.memory_tx_, db::stages::kHeadersKey) == 3); diff --git a/silkworm/node/stagedsync/forks/main_chain.hpp b/silkworm/node/stagedsync/forks/main_chain.hpp index 14e2336da0..e0ef2764d1 100644 --- a/silkworm/node/stagedsync/forks/main_chain.hpp +++ b/silkworm/node/stagedsync/forks/main_chain.hpp @@ -100,7 +100,7 @@ class MainChain { asio::io_context& io_context_; NodeSettings& node_settings_; db::RWAccess db_access_; - mutable db::RWTxn tx_; + mutable db::RWTxnManaged tx_; db::DataModel data_model_; bool is_first_sync_{true}; diff --git a/silkworm/node/stagedsync/stages/_test.cpp b/silkworm/node/stagedsync/stages/_test.cpp index 69ea414bfa..4d36dc8c4c 100644 --- a/silkworm/node/stagedsync/stages/_test.cpp +++ b/silkworm/node/stagedsync/stages/_test.cpp @@ -54,7 +54,7 @@ TEST_CASE("Sync Stages") { test_util::SetLogVerbosityGuard log_guard{log::Level::kNone}; auto chaindata_env{db::open_env(node_settings.chaindata_env_config)}; - db::RWTxn txn(chaindata_env); + db::RWTxnManaged txn(chaindata_env); db::table::check_or_create_chaindata_tables(txn); txn.commit_and_renew(); diff --git a/silkworm/node/stagedsync/stages/stage_bodies_test.cpp b/silkworm/node/stagedsync/stages/stage_bodies_test.cpp index c4a436734b..7088b9b8da 100644 --- a/silkworm/node/stagedsync/stages/stage_bodies_test.cpp +++ b/silkworm/node/stagedsync/stages/stage_bodies_test.cpp @@ -47,7 +47,7 @@ TEST_CASE("BodiesStage - data model") { * h0 <----- h1 */ SECTION("one invalid body after the genesis") { - db::RWTxn tx(context.env()); + db::RWTxnManaged tx(context.env()); auto header0_hash = db::read_canonical_hash(tx, 0); REQUIRE(header0_hash.has_value()); @@ -82,7 +82,7 @@ TEST_CASE("BodiesStage - data model") { } SECTION("one valid body after the genesis") { - db::RWTxn tx(context.env()); + db::RWTxnManaged tx(context.env()); auto header0_hash = db::read_canonical_hash(tx, 0); REQUIRE(header0_hash.has_value()); diff --git a/silkworm/node/stagedsync/stages/stage_headers_test.cpp b/silkworm/node/stagedsync/stages/stage_headers_test.cpp index b4df034f7d..24abf5ff29 100644 --- a/silkworm/node/stagedsync/stages/stage_headers_test.cpp +++ b/silkworm/node/stagedsync/stages/stage_headers_test.cpp @@ -42,7 +42,7 @@ TEST_CASE("HeadersStage - data model") { * h0 <----- h1 */ SECTION("one header after the genesis") { - db::RWTxn tx(context.env()); + db::RWTxnManaged tx(context.env()); auto header0_hash = db::read_canonical_hash(tx, 0); REQUIRE(header0_hash.has_value()); @@ -85,7 +85,7 @@ TEST_CASE("HeadersStage - data model") { * |-- h1' */ SECTION("some header after the genesis") { - db::RWTxn tx(context.env()); + db::RWTxnManaged tx(context.env()); // starting from an initial status auto header0 = db::read_canonical_header(tx, 0); diff --git a/silkworm/node/test/context.cpp b/silkworm/node/test/context.cpp index e1918e6c00..6f1008b778 100644 --- a/silkworm/node/test/context.cpp +++ b/silkworm/node/test/context.cpp @@ -34,7 +34,7 @@ Context::Context(bool with_create_tables, bool in_memory) { .in_memory = in_memory}; node_settings_.prune_mode = std::make_unique(); env_ = db::open_env(node_settings_.chaindata_env_config); - txn_ = std::make_unique(env_); + txn_ = std::make_unique(env_); if (with_create_tables) { db::table::check_or_create_chaindata_tables(*txn_); } diff --git a/silkworm/silkrpc/core/local_state.cpp b/silkworm/silkrpc/core/local_state.cpp index 5b6c967c36..a1fe8239f2 100644 --- a/silkworm/silkrpc/core/local_state.cpp +++ b/silkworm/silkrpc/core/local_state.cpp @@ -26,11 +26,11 @@ namespace silkworm::rpc::state { std::optional LocalState::read_account(const evmc::address& address) const noexcept { - return silkworm::db::read_account(rotxn_, address, block_number_ + 1); + return silkworm::db::read_account(txn_, address, block_number_ + 1); } silkworm::ByteView LocalState::read_code(const evmc::bytes32& code_hash) const noexcept { - auto code_optional = silkworm::db::read_code(rotxn_, code_hash); + auto code_optional = silkworm::db::read_code(txn_, code_hash); if (!code_optional) { return silkworm::ByteView{}; } @@ -38,7 +38,7 @@ silkworm::ByteView LocalState::read_code(const evmc::bytes32& code_hash) const n } evmc::bytes32 LocalState::read_storage(const evmc::address& address, uint64_t incarnation, const evmc::bytes32& location) const noexcept { - return silkworm::db::read_storage(rotxn_, address, incarnation, location, block_number_ + 1); + return silkworm::db::read_storage(txn_, address, incarnation, location, block_number_ + 1); } uint64_t LocalState::previous_incarnation(const evmc::address& /*address*/) const noexcept { @@ -46,15 +46,15 @@ uint64_t LocalState::previous_incarnation(const evmc::address& /*address*/) cons } std::optional LocalState::read_header(uint64_t block_number, const evmc::bytes32& block_hash) const noexcept { - return silkworm::db::read_header(rotxn_, block_number, block_hash); + return silkworm::db::read_header(txn_, block_number, block_hash); } bool LocalState::read_body(uint64_t block_number, const evmc::bytes32& block_hash, silkworm::BlockBody& filled_body) const noexcept { - return silkworm::db::read_body(rotxn_, block_hash, block_number, filled_body); + return silkworm::db::read_body(txn_, block_hash, block_number, filled_body); } std::optional LocalState::total_difficulty(uint64_t block_number, const evmc::bytes32& block_hash) const noexcept { - return silkworm::db::read_total_difficulty(rotxn_, block_number, block_hash); + return silkworm::db::read_total_difficulty(txn_, block_number, block_hash); } evmc::bytes32 LocalState::state_root_hash() const { @@ -68,7 +68,7 @@ uint64_t LocalState::current_canonical_block() const { std::optional LocalState::canonical_hash(uint64_t block_number) const { // This method should not be called by EVM::execute - return silkworm::db::read_canonical_hash(rotxn_, block_number); + return silkworm::db::read_canonical_hash(txn_, block_number); } } // namespace silkworm::rpc::state diff --git a/silkworm/silkrpc/core/local_state.hpp b/silkworm/silkrpc/core/local_state.hpp index fe7d8463a1..0c08cf877e 100644 --- a/silkworm/silkrpc/core/local_state.hpp +++ b/silkworm/silkrpc/core/local_state.hpp @@ -36,7 +36,7 @@ namespace silkworm::rpc::state { class LocalState : public silkworm::State { public: explicit LocalState(uint64_t block_number, std::shared_ptr chaindata_env) - : block_number_{block_number}, chaindata_env_{chaindata_env}, rotxn_{*chaindata_env} {} + : block_number_{block_number}, chaindata_env_{chaindata_env}, txn_{*chaindata_env} {} std::optional read_account(const evmc::address& address) const noexcept override; @@ -88,12 +88,10 @@ class LocalState : public silkworm::State { void unwind_state_changes(uint64_t /*block_number*/) override {} - void reset(); - private: uint64_t block_number_; std::shared_ptr chaindata_env_; - mutable db::ROTxn rotxn_; + mutable db::ROTxnManaged txn_; }; } // namespace silkworm::rpc::state diff --git a/silkworm/silkrpc/ethdb/file/local_transaction.hpp b/silkworm/silkrpc/ethdb/file/local_transaction.hpp index 4c1f67ec8c..42f16f9333 100644 --- a/silkworm/silkrpc/ethdb/file/local_transaction.hpp +++ b/silkworm/silkrpc/ethdb/file/local_transaction.hpp @@ -63,7 +63,7 @@ class LocalTransaction : public Transaction { std::shared_ptr chaindata_env_; uint32_t last_cursor_id_; - db::ROTxn txn_; + db::ROTxnManaged txn_; }; } // namespace silkworm::rpc::ethdb::file diff --git a/silkworm/sync/internals/body_retrieval.hpp b/silkworm/sync/internals/body_retrieval.hpp index 8bd2340a78..2fe18e3442 100644 --- a/silkworm/sync/internals/body_retrieval.hpp +++ b/silkworm/sync/internals/body_retrieval.hpp @@ -32,7 +32,7 @@ class BodyRetrieval { std::vector recover(std::vector); protected: - db::ROTxn db_tx_; + db::ROTxnManaged db_tx_; }; } // namespace silkworm diff --git a/silkworm/sync/internals/body_sequence_test.cpp b/silkworm/sync/internals/body_sequence_test.cpp index 169d3ae5ce..ccc8731abf 100644 --- a/silkworm/sync/internals/body_sequence_test.cpp +++ b/silkworm/sync/internals/body_sequence_test.cpp @@ -447,7 +447,7 @@ TEST_CASE("body downloading", "[silkworm][sync][BodySequence]") { BlockHeader header2; header2.number = 2; header2.parent_hash = header1_hash; - db::RWTxn txn2{context.env()}; + db::RWTxnManaged txn2{context.env()}; db::write_canonical_header_hash(txn2, header2.hash().bytes, 1); db::write_canonical_header(txn2, header2); db::write_header(txn2, header2, true); diff --git a/silkworm/sync/internals/header_retrieval.hpp b/silkworm/sync/internals/header_retrieval.hpp index d46bf0fbe9..3742311e69 100644 --- a/silkworm/sync/internals/header_retrieval.hpp +++ b/silkworm/sync/internals/header_retrieval.hpp @@ -43,7 +43,7 @@ class HeaderRetrieval { uint64_t& max_non_canonical); protected: - db::ROTxn db_tx_; + db::ROTxnManaged db_tx_; db::DataModel data_model_; };