diff --git a/silkworm/db/chain/local_chain_storage.cpp b/silkworm/db/chain/local_chain_storage.cpp index e0395f532d..7e176972f5 100644 --- a/silkworm/db/chain/local_chain_storage.cpp +++ b/silkworm/db/chain/local_chain_storage.cpp @@ -23,8 +23,18 @@ namespace silkworm::db::chain { +LocalChainStorage::LocalChainStorage( + db::DataModel data_model, + std::shared_ptr cache) + : data_model_{data_model}, + cache_{cache} { + std::call_once(cache_->chain_config_once_flag, [this] { + cache_->chain_config = data_model_.read_chain_config(); + }); +} + Task LocalChainStorage::read_chain_config() const { - const auto chain_config{data_model_.read_chain_config()}; + const auto chain_config = cache_->chain_config; if (!chain_config) { throw std::runtime_error{"empty chain config data in storage"}; } diff --git a/silkworm/db/chain/local_chain_storage.hpp b/silkworm/db/chain/local_chain_storage.hpp index 91ac1f4cc0..f951d94e32 100644 --- a/silkworm/db/chain/local_chain_storage.hpp +++ b/silkworm/db/chain/local_chain_storage.hpp @@ -16,6 +16,8 @@ #pragma once +#include + #include #include "chain_storage.hpp" @@ -26,8 +28,14 @@ namespace silkworm::db::chain { //! in local database (accessed via MDBX API) or local snapshot files (accessed via custom snapshot API) class LocalChainStorage : public ChainStorage { public: - explicit LocalChainStorage(db::DataModel data_model) - : data_model_{data_model} {} + struct Cache { + std::optional chain_config; + std::once_flag chain_config_once_flag; + }; + + LocalChainStorage( + db::DataModel data_model, + std::shared_ptr cache); ~LocalChainStorage() override = default; Task read_chain_config() const override; @@ -74,6 +82,7 @@ class LocalChainStorage : public ChainStorage { private: db::DataModel data_model_; + std::shared_ptr cache_; }; } // namespace silkworm::db::chain diff --git a/silkworm/db/kv/api/direct_service.cpp b/silkworm/db/kv/api/direct_service.cpp index 65cf1714aa..4221a5fafe 100644 --- a/silkworm/db/kv/api/direct_service.cpp +++ b/silkworm/db/kv/api/direct_service.cpp @@ -26,7 +26,7 @@ namespace silkworm::db::kv::api { DirectService::DirectService(ServiceRouter router, DataStoreRef data_store, StateCache* state_cache) : router_{router}, data_store_{std::move(data_store)}, - state_cache_{state_cache} {} + shared_transaction_cache_{std::make_shared(state_cache)} {} // rpc Version(google.protobuf.Empty) returns (types.VersionReply); Task DirectService::version() { @@ -35,7 +35,7 @@ Task DirectService::version() { // rpc Tx(stream Cursor) returns (stream Pair); Task> DirectService::begin_transaction() { - co_return std::make_unique(data_store_, state_cache_); + co_return std::make_unique(data_store_, shared_transaction_cache_); } // rpc StateChanges(StateChangeRequest) returns (stream StateChangeBatch); diff --git a/silkworm/db/kv/api/direct_service.hpp b/silkworm/db/kv/api/direct_service.hpp index 11ad9edd4a..66f8fc9ae9 100644 --- a/silkworm/db/kv/api/direct_service.hpp +++ b/silkworm/db/kv/api/direct_service.hpp @@ -18,6 +18,7 @@ #include +#include "local_transaction.hpp" #include "service.hpp" #include "service_router.hpp" @@ -52,8 +53,7 @@ class DirectService : public Service { //! The data store DataStoreRef data_store_; - //! The local state cache built upon incoming state changes - StateCache* state_cache_; + std::shared_ptr shared_transaction_cache_; }; } // namespace silkworm::db::kv::api diff --git a/silkworm/db/kv/api/local_transaction.cpp b/silkworm/db/kv/api/local_transaction.cpp index 9b10220e0e..dcd9fba8ed 100644 --- a/silkworm/db/kv/api/local_transaction.cpp +++ b/silkworm/db/kv/api/local_transaction.cpp @@ -138,7 +138,9 @@ Task> LocalTransaction::get_cursor(const std::str std::shared_ptr LocalTransaction::create_storage() { // The calling thread *must* be the *same* which created this LocalTransaction instance - return std::make_shared(DataModel{tx_, data_store_.blocks_repository}); + return std::make_shared( + DataModel{tx_, data_store_.blocks_repository}, + cache_->chain_storage_cache()); } Task LocalTransaction::first_txn_num_in_block(BlockNum block_num) { diff --git a/silkworm/db/kv/api/local_transaction.hpp b/silkworm/db/kv/api/local_transaction.hpp index 7e0d4f2ac2..39b60daf5b 100644 --- a/silkworm/db/kv/api/local_transaction.hpp +++ b/silkworm/db/kv/api/local_transaction.hpp @@ -24,6 +24,7 @@ #include +#include #include #include "base_transaction.hpp" @@ -34,9 +35,27 @@ namespace silkworm::db::kv::api { class LocalTransaction : public BaseTransaction { public: - LocalTransaction(DataStoreRef data_store, StateCache* state_cache) - : BaseTransaction(state_cache), + class Cache { + public: + using ChainStorageCache = db::chain::LocalChainStorage::Cache; + explicit Cache(StateCache* state_cache) + : state_cache_{state_cache}, + chain_storage_cache_{std::make_shared()} {} + StateCache* state_cache() const { return state_cache_; } + std::shared_ptr chain_storage_cache() const { return chain_storage_cache_; } + + private: + //! The local state cache built upon incoming state changes + StateCache* state_cache_; + std::shared_ptr chain_storage_cache_; + }; + + LocalTransaction( + DataStoreRef data_store, + std::shared_ptr cache) + : BaseTransaction{cache->state_cache()}, data_store_{std::move(data_store)}, + cache_{std::move(cache)}, tx_{data_store_.chaindata.access_ro().start_ro_tx()} {} ~LocalTransaction() override = default; @@ -105,6 +124,7 @@ class LocalTransaction : public BaseTransaction { std::map> dup_cursors_; DataStoreRef data_store_; + std::shared_ptr cache_; uint32_t last_cursor_id_{0}; datastore::kvdb::ROTxnManaged tx_; uint64_t tx_id_{++next_tx_id_};