diff --git a/silkworm/capi/init.cpp b/silkworm/capi/init.cpp index 5ba3838bbe..d8b690129f 100644 --- a/silkworm/capi/init.cpp +++ b/silkworm/capi/init.cpp @@ -83,6 +83,7 @@ SILKWORM_EXPORT int silkworm_init(SilkwormHandle* handle, const struct SilkwormS .state_repository_latest = std::move(state_repository_latest), .state_repository_historical = std::move(state_repository_historical), .chaindata = {}, + .query_caches = snapshots::QueryCaches{db::state::make_query_caches_schema(), snapshots_dir_path, settings->state_repo_index_salt}, }; // NOLINTNEXTLINE(bugprone-unhandled-exception-at-new) diff --git a/silkworm/capi/silkworm.cpp b/silkworm/capi/silkworm.cpp index 324cce2576..b6390abcfc 100644 --- a/silkworm/capi/silkworm.cpp +++ b/silkworm/capi/silkworm.cpp @@ -500,6 +500,7 @@ SILKWORM_EXPORT int silkworm_execute_txn(SilkwormHandle handle, MDBX_txn* mdbx_t db_ref, handle->db->blocks_repository, handle->db->state_repository_latest, + handle->db->query_caches, }; if (!handle->chain_config) { handle->chain_config = db::read_chain_config(unmanaged_tx); @@ -646,6 +647,7 @@ SILKWORM_EXPORT int silkworm_block_exec_end(SilkwormHandle handle, MDBX_txn* mdb db_ref, handle->db->blocks_repository, handle->db->state_repository_latest, + handle->db->query_caches, }; const auto log_index = handle->executions_in_block[index].log_index; diff --git a/silkworm/db/blocks/schema_config.cpp b/silkworm/db/blocks/schema_config.cpp index 5470263703..dfa22f2fd2 100644 --- a/silkworm/db/blocks/schema_config.cpp +++ b/silkworm/db/blocks/schema_config.cpp @@ -57,8 +57,6 @@ snapshots::SnapshotRepository make_blocks_repository( schema, index_salt, make_blocks_index_builders_factory(), - std::nullopt, // no domain caches - std::nullopt, // no inverted index caches }; } diff --git a/silkworm/db/capi/component.hpp b/silkworm/db/capi/component.hpp index 78f95cf67f..7c586c3eb8 100644 --- a/silkworm/db/capi/component.hpp +++ b/silkworm/db/capi/component.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace silkworm::db::capi { @@ -17,6 +18,7 @@ struct Component { silkworm::snapshots::SnapshotRepository state_repository_latest; silkworm::snapshots::SnapshotRepository state_repository_historical; std::unique_ptr chaindata; + silkworm::snapshots::QueryCaches query_caches; DataStoreRef data_store() { SILKWORM_ASSERT(chaindata); @@ -25,6 +27,7 @@ struct Component { blocks_repository, state_repository_latest, state_repository_historical, + query_caches, }; } diff --git a/silkworm/db/data_store.cpp b/silkworm/db/data_store.cpp index e61b922c35..a643ae8810 100644 --- a/silkworm/db/data_store.cpp +++ b/silkworm/db/data_store.cpp @@ -13,6 +13,7 @@ datastore::Schema DataStore::make_schema() { snapshots.repository(blocks::kBlocksRepositoryName) = blocks::make_blocks_repository_schema(); snapshots.repository(state::kStateRepositoryNameLatest) = state::make_state_repository_schema_latest(); snapshots.repository(state::kStateRepositoryNameHistorical) = state::make_state_repository_schema_historical(); + snapshots.query_caches_schema() = state::make_query_caches_schema(); return { std::move(kvdb), diff --git a/silkworm/db/data_store.hpp b/silkworm/db/data_store.hpp index 5709b2716e..286a18de30 100644 --- a/silkworm/db/data_store.hpp +++ b/silkworm/db/data_store.hpp @@ -17,6 +17,7 @@ struct DataStoreRef { snapshots::SnapshotRepository& blocks_repository; snapshots::SnapshotRepository& state_repository_latest; snapshots::SnapshotRepository& state_repository_historical; + const snapshots::QueryCaches& query_caches; }; class DataStore { @@ -32,6 +33,7 @@ class DataStore { std::move(blocks_repository), std::move(state_repository_latest), std::move(state_repository_historical)), + blocks_repository.path(), } {} public: @@ -61,6 +63,7 @@ class DataStore { blocks_repository(), state_repository_latest(), state_repository_historical(), + store_.query_caches(), }; } @@ -75,6 +78,7 @@ class DataStore { snapshots::SnapshotRepository& state_repository_historical() const { return store_.repository(state::kStateRepositoryNameHistorical); } + const snapshots::QueryCaches& query_caches() const { return store_.query_caches(); } static datastore::kvdb::Schema::DatabaseDef make_chaindata_database_schema(); static datastore::kvdb::Database make_chaindata_database(mdbx::env_managed chaindata_env); diff --git a/silkworm/db/datastore/data_store.hpp b/silkworm/db/datastore/data_store.hpp index 6dab6a3237..9f37e32704 100644 --- a/silkworm/db/datastore/data_store.hpp +++ b/silkworm/db/datastore/data_store.hpp @@ -8,6 +8,7 @@ #include "common/entity_name.hpp" #include "kvdb/database.hpp" #include "schema.hpp" +#include "snapshots/query_caches.hpp" #include "snapshots/snapshot_repository.hpp" namespace silkworm::datastore { @@ -17,21 +18,25 @@ class DataStore { DataStore( Schema schema, EntityMap> databases, - EntityMap> repositories) + EntityMap> repositories, + const std::filesystem::path& snapshots_path) : schema_{std::move(schema)}, databases_{std::move(databases)}, - repositories_{std::move(repositories)} {} + repositories_{std::move(repositories)}, + query_caches_{schema_.snapshots.query_caches_schema(), snapshots_path} {} const Schema& schema() const { return schema_; } kvdb::Database& default_database() const { return database(kvdb::Schema::kDefaultEntityName); } kvdb::Database& database(const EntityName& name) const { return *databases_.at(name); } snapshots::SnapshotRepository& repository(const EntityName& name) const { return *repositories_.at(name); } + const snapshots::QueryCaches& query_caches() const { return query_caches_; } private: Schema schema_; EntityMap> databases_; EntityMap> repositories_; + snapshots::QueryCaches query_caches_; }; } // namespace silkworm::datastore diff --git a/silkworm/db/datastore/domain_get_as_of_query.hpp b/silkworm/db/datastore/domain_get_as_of_query.hpp index 7a143f556c..bef022fbbd 100644 --- a/silkworm/db/datastore/domain_get_as_of_query.hpp +++ b/silkworm/db/datastore/domain_get_as_of_query.hpp @@ -17,17 +17,19 @@ struct DomainGetAsOfQuery { kvdb::Domain kvdb_entity, kvdb::ROTxn& tx, const snapshots::SnapshotRepositoryROAccess& repository_latest, - const snapshots::SnapshotRepositoryROAccess& repository_historical) - : query1_{*kvdb_entity.history, tx, repository_historical}, - query2_{history_segment_names.front(), kvdb_entity, tx, repository_latest} {} + const snapshots::SnapshotRepositoryROAccess& repository_historical, + const snapshots::QueryCaches& query_caches) + : query1_{*kvdb_entity.history, tx, repository_historical, query_caches}, + query2_{history_segment_names.front(), kvdb_entity, tx, repository_latest, query_caches} {} DomainGetAsOfQuery( const kvdb::DatabaseRef& database, kvdb::ROTxn& tx, const snapshots::SnapshotRepositoryROAccess& repository_latest, - const snapshots::SnapshotRepositoryROAccess& repository_historical) - : query1_{database, tx, repository_historical}, - query2_{history_segment_names.front(), database, tx, repository_latest} {} + const snapshots::SnapshotRepositoryROAccess& repository_historical, + const snapshots::QueryCaches& query_caches) + : query1_{database, tx, repository_historical, query_caches}, + query2_{history_segment_names.front(), database, tx, repository_latest, query_caches} {} using Key = decltype(TKeyEncoder1::value); using Value = decltype(TValueDecoder1::value); diff --git a/silkworm/db/datastore/domain_get_latest_query.hpp b/silkworm/db/datastore/domain_get_latest_query.hpp index 17cce5e740..7408ce894c 100644 --- a/silkworm/db/datastore/domain_get_latest_query.hpp +++ b/silkworm/db/datastore/domain_get_latest_query.hpp @@ -17,20 +17,23 @@ struct DomainGetLatestQuery { datastore::EntityName entity_name, kvdb::Domain kvdb_entity, kvdb::ROTxn& tx, - const snapshots::SnapshotRepositoryROAccess& repository) + const snapshots::SnapshotRepositoryROAccess& repository, + const snapshots::QueryCaches& query_caches) : query1_{tx, kvdb_entity}, - query2_{repository, entity_name} {} + query2_{repository, query_caches, entity_name} {} DomainGetLatestQuery( datastore::EntityName entity_name, const kvdb::DatabaseRef& database, kvdb::ROTxn& tx, - const snapshots::SnapshotRepositoryROAccess& repository) + const snapshots::SnapshotRepositoryROAccess& repository, + const snapshots::QueryCaches& query_caches) : DomainGetLatestQuery{ entity_name, database.domain(entity_name), tx, repository, + query_caches, } {} using Key1 = decltype(TKeyEncoder1::value); diff --git a/silkworm/db/datastore/history_get_query.hpp b/silkworm/db/datastore/history_get_query.hpp index cb196c825f..6b2ee5dad3 100644 --- a/silkworm/db/datastore/history_get_query.hpp +++ b/silkworm/db/datastore/history_get_query.hpp @@ -17,18 +17,21 @@ struct HistoryGetQuery { HistoryGetQuery( kvdb::History kvdb_entity, kvdb::ROTxn& tx, - const snapshots::SnapshotRepositoryROAccess& repository) + const snapshots::SnapshotRepositoryROAccess& repository, + const snapshots::QueryCaches& query_caches) : query1_{tx, kvdb_entity}, - query2_{repository} {} + query2_{repository, query_caches} {} HistoryGetQuery( const kvdb::DatabaseRef& database, kvdb::ROTxn& tx, - const snapshots::SnapshotRepositoryROAccess& repository) + const snapshots::SnapshotRepositoryROAccess& repository, + const snapshots::QueryCaches& query_caches) : HistoryGetQuery{ database.domain(segment_names.front()).history.value(), tx, repository, + query_caches, } {} using Key1 = decltype(TKeyEncoder1::value); diff --git a/silkworm/db/datastore/snapshots/domain_cache.hpp b/silkworm/db/datastore/snapshots/domain_cache.hpp deleted file mode 100644 index 7a4aed93ee..0000000000 --- a/silkworm/db/datastore/snapshots/domain_cache.hpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2025 The Silkworm Authors -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include -#include -#include - -#include - -#include "../common/entity_name.hpp" -#include "../common/step.hpp" -#include "common/cache.hpp" - -namespace silkworm::snapshots { - -struct DomainGetLatestCacheData { - BytesOrByteView value; - std::optional range_end{0}; -}; -using DomainGetLatestCache = Cache; -using DomainGetLatestCaches = std::map>; - -} // namespace silkworm::snapshots diff --git a/silkworm/db/datastore/snapshots/domain_get_latest_query.hpp b/silkworm/db/datastore/snapshots/domain_get_latest_query.hpp index 2fdce3cb3d..84c77cd234 100644 --- a/silkworm/db/datastore/snapshots/domain_get_latest_query.hpp +++ b/silkworm/db/datastore/snapshots/domain_get_latest_query.hpp @@ -7,7 +7,8 @@ #include "common/codec.hpp" #include "common/raw_codec.hpp" #include "domain.hpp" -#include "domain_cache.hpp" +#include "query_cache.hpp" +#include "query_caches.hpp" #include "segment/kv_segment_reader.hpp" #include "snapshot_bundle.hpp" #include "snapshot_repository_ro_access.hpp" @@ -54,11 +55,70 @@ struct DomainGetLatestSegmentQuery { Domain entity_; }; -template -struct DomainGetLatestQuery { +struct DomainGetLatestQueryRawNoCache { const SnapshotRepositoryROAccess& repository; datastore::EntityName entity_name; + struct Result { + Decoder::Word value; + datastore::Step step{0}; + }; + + std::optional exec(ByteView key_data) { + for (auto& bundle_ptr : repository.view_bundles_reverse()) { + const SnapshotBundle& bundle = *bundle_ptr; + DomainGetLatestSegmentQuery, RawDecoder> query{bundle, entity_name}; + std::optional value_data = query.exec_raw(key_data); + if (value_data) { + return Result{std::move(*value_data), bundle.step_range().end}; + } + } + return std::nullopt; + } +}; + +struct DomainGetLatestQueryRawWithCache { + using Result = DomainGetLatestQueryRawNoCache::Result; + using CacheType = QueryCache>; + static inline const datastore::EntityName kName{"DomainGetLatestQueryRawWithCache"}; + + DomainGetLatestQueryRawWithCache( + const SnapshotRepositoryROAccess& repository, + const QueryCaches& query_caches, + datastore::EntityName entity_name) + : query_{repository, entity_name}, + cache_{query_caches.cache(kName, entity_name).get()} {} + + std::optional exec(ByteView key_data) { + if (!cache_) { + return query_.exec(key_data); + } + + std::optional> cached_result; + uint64_t cache_key{0}; + std::tie(cached_result, cache_key) = cache_->get(key_data); + if (cached_result) { + return std::move(*cached_result); + } + + std::optional result = query_.exec(key_data); + cache_->put(cache_key, result); + return result; + } + + private: + DomainGetLatestQueryRawNoCache query_; + CacheType* cache_; +}; + +template +struct DomainGetLatestQuery { + DomainGetLatestQuery( + const SnapshotRepositoryROAccess& repository, + const QueryCaches& query_caches, + datastore::EntityName entity_name) + : query_{repository, query_caches, entity_name} {} + using Key = decltype(TKeyEncoder::value); using Value = decltype(TValueDecoder::value); @@ -68,43 +128,20 @@ struct DomainGetLatestQuery { }; std::optional exec(const Key& key) { - DomainGetLatestCache* cache = repository.domain_get_latest_cache(entity_name); - TKeyEncoder key_encoder; key_encoder.value = key; ByteView key_data = key_encoder.encode_word(); - uint64_t key_hash_hi{0}; - if (cache) { - std::optional cached_data; - if (std::tie(cached_data, key_hash_hi) = cache->get(key_data); cached_data) { - if (!cached_data->range_end) { // hit in cache but value not found - return std::nullopt; - } - TValueDecoder value_decoder; - value_decoder.decode_word(cached_data->value); - return Result{std::move(value_decoder.value), *cached_data->range_end}; - } - } + auto value_data = query_.exec(key_data); + if (!value_data) return std::nullopt; - for (auto& bundle_ptr : repository.view_bundles_reverse()) { - const SnapshotBundle& bundle = *bundle_ptr; - DomainGetLatestSegmentQuery query{bundle, entity_name}; - std::optional value_data = query.exec_raw(key_data); - if (value_data) { - if (cache) { - cache->put(key_hash_hi, {*value_data, bundle.step_range().end}); - } - TValueDecoder value_decoder; - value_decoder.decode_word(*value_data); - return Result{std::move(value_decoder.value), bundle.step_range().end}; - } - } - if (cache) { - cache->put(key_hash_hi, {}); - } - return std::nullopt; + TValueDecoder value_decoder; + value_decoder.decode_word(value_data->value); + return Result{std::move(value_decoder.value), value_data->step}; } + + private: + DomainGetLatestQueryRawWithCache query_; }; } // namespace silkworm::snapshots diff --git a/silkworm/db/datastore/snapshots/history_get_query.hpp b/silkworm/db/datastore/snapshots/history_get_query.hpp index be0c871816..9ff9a142b5 100644 --- a/silkworm/db/datastore/snapshots/history_get_query.hpp +++ b/silkworm/db/datastore/snapshots/history_get_query.hpp @@ -8,6 +8,7 @@ #include "common/codec.hpp" #include "common/raw_codec.hpp" #include "inverted_index_seek_query.hpp" +#include "query_caches.hpp" #include "snapshot_repository_ro_access.hpp" namespace silkworm::snapshots { @@ -17,11 +18,13 @@ template < DecoderConcept TValueDecoder, const SegmentAndAccessorIndexNames& segment_names> struct HistoryGetQuery { - explicit HistoryGetQuery(const SnapshotRepositoryROAccess& repository) + HistoryGetQuery( + const SnapshotRepositoryROAccess& repository, + const QueryCaches& query_caches) : timestamp_query_{ repository, [](const SnapshotBundle& bundle) { return bundle.history(segment_names.front()).inverted_index; }, - [&]() { return repository.inverted_index_seek_cache(segment_names.front()); }, + query_caches.cache(InvertedIndexSeekQueryRawWithCache::kName, segment_names.front()).get(), }, value_query_{repository} {} diff --git a/silkworm/db/datastore/snapshots/inverted_index_cache.hpp b/silkworm/db/datastore/snapshots/inverted_index_cache.hpp deleted file mode 100644 index 78e24c3f8f..0000000000 --- a/silkworm/db/datastore/snapshots/inverted_index_cache.hpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2025 The Silkworm Authors -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include -#include -#include - -#include - -#include "../common/entity_name.hpp" -#include "common/cache.hpp" - -namespace silkworm::snapshots { - -struct InvertedIndexSeekCacheData { - datastore::Timestamp requested; - datastore::Timestamp found; -}; -using InvertedIndexSeekCache = Cache; -using InvertedIndexSeekCaches = std::map>; - -} // namespace silkworm::snapshots diff --git a/silkworm/db/datastore/snapshots/inverted_index_seek_query.hpp b/silkworm/db/datastore/snapshots/inverted_index_seek_query.hpp index e4ef080fe0..9b5d2d30f8 100644 --- a/silkworm/db/datastore/snapshots/inverted_index_seek_query.hpp +++ b/silkworm/db/datastore/snapshots/inverted_index_seek_query.hpp @@ -37,73 +37,100 @@ struct InvertedIndexSeekSegmentQuery { InvertedIndexTimestampList& list = *list_opt; const auto seek_result = list.seek(timestamp); - if (!seek_result) { - return std::nullopt; + if (seek_result) { + return seek_result->second; } - const auto [_, higher_or_equal_timestamp] = *seek_result; - return higher_or_equal_timestamp; + return std::nullopt; } private: InvertedIndexFindByKeySegmentQuery query_; }; +struct InvertedIndexSeekQueryRawNoCache { + const SnapshotRepositoryROAccess& repository_; + std::function entity_provider_; + + std::optional exec(ByteView key_data, datastore::Timestamp timestamp) { + datastore::TimestampRange ts_range{timestamp, repository_.max_timestamp_available() + 1}; + for (auto& bundle_ptr : repository_.bundles_intersecting_range(ts_range, /*ascending=*/true)) { + const SnapshotBundle& bundle = *bundle_ptr; + InvertedIndexSeekSegmentQuery> query{entity_provider_(bundle)}; + std::optional result = query.exec_raw(key_data, timestamp); + if (result) { + return result; + } + } + return std::nullopt; + } +}; + +struct InvertedIndexSeekQueryRawWithCache { + struct InvertedIndexSeekCacheData { + datastore::Timestamp requested; + std::optional found; + }; + + using CacheType = QueryCache; + static inline const datastore::EntityName kName{"InvertedIndexSeekQueryRawWithCache"}; + + InvertedIndexSeekQueryRawWithCache( + const SnapshotRepositoryROAccess& repository, + std::function entity_provider, + CacheType* cache) + : query_{repository, std::move(entity_provider)}, + cache_{cache} {} + + std::optional exec(ByteView key_data, datastore::Timestamp timestamp) { + if (!cache_) { + return query_.exec(key_data, timestamp); + } + + std::optional cached_data; + uint64_t cache_key{0}; + std::tie(cached_data, cache_key) = cache_->get(key_data); + if (cached_data && (cached_data->requested <= timestamp)) { + if (!cached_data->found) { // hit in cache but value not found + return std::nullopt; + } + if (timestamp <= *cached_data->found) { + return cached_data->found; + } + } + + std::optional result = query_.exec(key_data, timestamp); + bool found_equal = result && (*result == timestamp); + if (!found_equal) { + cache_->put(cache_key, {.requested = timestamp, .found = result}); + } + return result; + } + + private: + InvertedIndexSeekQueryRawNoCache query_; + CacheType* cache_; +}; + template struct InvertedIndexSeekQuery { - explicit InvertedIndexSeekQuery( + InvertedIndexSeekQuery( const SnapshotRepositoryROAccess& repository, std::function entity_provider, - std::function cache_provider) - : repository_{repository}, - entity_provider_{std::move(entity_provider)}, - cache_provider_{std::move(cache_provider)} {} + InvertedIndexSeekQueryRawWithCache::CacheType* cache) + : query_{repository, std::move(entity_provider), cache} {} using Key = decltype(TKeyEncoder::value); std::optional exec(Key key, datastore::Timestamp timestamp) { - InvertedIndexSeekCache* cache = cache_provider_(); - TKeyEncoder key_encoder; key_encoder.value = std::move(key); ByteView key_data = key_encoder.encode_word(); - uint64_t key_hash_hi{0}; - if (cache) { - std::optional cached_data; - if (std::tie(cached_data, key_hash_hi) = cache->get(key_data); cached_data) { - if (cached_data->requested <= timestamp) { - if (timestamp <= cached_data->found) { - return cached_data->found; - } - if (cached_data->found == 0) { // hit in cache but value not found - return std::nullopt; - } - } - } - } - - datastore::TimestampRange ts_range{timestamp, repository_.max_timestamp_available() + 1}; - for (auto& bundle_ptr : repository_.bundles_intersecting_range(ts_range, /*ascending=*/true)) { - const SnapshotBundle& bundle = *bundle_ptr; - InvertedIndexSeekSegmentQuery query{entity_provider_(bundle)}; - std::optional higher_or_equal = query.exec_raw(key_data, timestamp); - if (higher_or_equal) { - if (cache && *higher_or_equal > timestamp) { - cache->put(key_hash_hi, {.requested = timestamp, .found = *higher_or_equal}); - } - return higher_or_equal; - } - } - if (cache) { - cache->put(key_hash_hi, {.requested = timestamp, .found = 0}); // 0 means value not found - } - return std::nullopt; + return query_.exec(key_data, timestamp); } private: - const SnapshotRepositoryROAccess& repository_; - std::function entity_provider_; - std::function cache_provider_; + InvertedIndexSeekQueryRawWithCache query_; }; } // namespace silkworm::snapshots diff --git a/silkworm/db/datastore/snapshots/common/cache.hpp b/silkworm/db/datastore/snapshots/query_cache.hpp similarity index 51% rename from silkworm/db/datastore/snapshots/common/cache.hpp rename to silkworm/db/datastore/snapshots/query_cache.hpp index b6f1029991..812ebb8789 100644 --- a/silkworm/db/datastore/snapshots/common/cache.hpp +++ b/silkworm/db/datastore/snapshots/query_cache.hpp @@ -8,26 +8,28 @@ #include -#include "key_hasher.hpp" +#include "common/key_hasher.hpp" namespace silkworm::snapshots { template -class Cache { +class QueryCache { public: - Cache(size_t size, uint32_t salt) : cache_{size, /*thread_safe=*/true}, key_hasher_{salt} {} + QueryCache(size_t size, KeyHasher key_hasher) + : cache_{size, /* thread_safe = */ true}, + key_hasher_{std::move(key_hasher)} {} - void put(uint64_t key_hash_high, const Value& value) { - cache_.put(key_hash_high, value); + void put(uint64_t cache_key, const Value& value) { + cache_.put(cache_key, value); } - std::optional get(uint64_t key_hash_high) { - return cache_.get_as_copy(key_hash_high); + std::optional get(uint64_t cache_key) { + return cache_.get_as_copy(cache_key); } std::pair, uint64_t> get(ByteView key) { - const uint64_t hash_high = key_hasher_.hash(key); - return {get(hash_high), hash_high}; + const uint64_t cache_key = key_hasher_.hash(key); + return {get(cache_key), cache_key}; } void clear() noexcept { diff --git a/silkworm/db/datastore/snapshots/query_caches.cpp b/silkworm/db/datastore/snapshots/query_caches.cpp new file mode 100644 index 0000000000..33519573ff --- /dev/null +++ b/silkworm/db/datastore/snapshots/query_caches.cpp @@ -0,0 +1,38 @@ +// Copyright 2025 The Silkworm Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "query_caches.hpp" + +#include + +#include "domain_get_latest_query.hpp" +#include "index_salt_file.hpp" +#include "inverted_index_seek_query.hpp" + +namespace silkworm::snapshots { + +void QueryCaches::register_caches(const QueryCachesSchema& schema) { + uint32_t salt = index_salt_.value_or(RandomNumber{}.generate_one()); + KeyHasher key_hasher{salt}; + + register_caches( + schema, + DomainGetLatestQueryRawWithCache::kName, + std::function{[key_hasher](size_t cache_size) { + return std::make_shared(cache_size, key_hasher); + }}); + + register_caches( + schema, + InvertedIndexSeekQueryRawWithCache::kName, + std::function{[key_hasher](size_t cache_size) { + return std::make_shared(cache_size, key_hasher); + }}); +} + +std::optional QueryCaches::load_index_salt(const std::filesystem::path& snapshots_path) const { + IndexSaltFile file{snapshots_path / schema_.index_salt_file_name()}; + return file.exists() ? file.load() : std::optional{}; +} + +} // namespace silkworm::snapshots diff --git a/silkworm/db/datastore/snapshots/query_caches.hpp b/silkworm/db/datastore/snapshots/query_caches.hpp new file mode 100644 index 0000000000..95dc0b2700 --- /dev/null +++ b/silkworm/db/datastore/snapshots/query_caches.hpp @@ -0,0 +1,63 @@ +// Copyright 2025 The Silkworm Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include +#include +#include +#include + +#include "../common/entity_name.hpp" +#include "query_caches_schema.hpp" + +namespace silkworm::snapshots { + +class QueryCaches { + public: + explicit QueryCaches( + QueryCachesSchema schema, + const std::filesystem::path& snapshots_path, + std::optional index_salt = std::nullopt) + : schema_{std::move(schema)} { + index_salt_ = index_salt ? index_salt : load_index_salt(snapshots_path); + register_caches(schema_); + } + + template + std::shared_ptr cache(datastore::EntityName query_name, datastore::EntityName entity_name) const { + if (caches_.contains(query_name)) { + auto& caches = caches_.at(query_name); + if (caches.contains(entity_name)) { + std::shared_ptr cache = caches.at(entity_name); + return std::static_pointer_cast(std::move(cache)); + } + } + return {}; + } + + private: + template + void add_cache(datastore::EntityName query_name, datastore::EntityName entity_name, std::shared_ptr cache) { + caches_.try_emplace(query_name, decltype(caches_)::mapped_type{}); + caches_.at(query_name).emplace(entity_name, std::shared_ptr{cache}); + } + + template + void register_caches(const QueryCachesSchema& schema, datastore::EntityName query_name, std::function(size_t)> cache_factory) { + size_t cache_size = schema.cache_size(query_name); + for (auto& [entity_name, _] : schema.entities()) { + add_cache(query_name, entity_name, cache_factory(cache_size)); + } + } + + void register_caches(const QueryCachesSchema& schema); + + std::optional load_index_salt(const std::filesystem::path& snapshots_path) const; + + QueryCachesSchema schema_; + std::optional index_salt_; + datastore::EntityMap>> caches_; +}; + +} // namespace silkworm::snapshots diff --git a/silkworm/db/datastore/snapshots/query_caches_schema.hpp b/silkworm/db/datastore/snapshots/query_caches_schema.hpp new file mode 100644 index 0000000000..0167f0beff --- /dev/null +++ b/silkworm/db/datastore/snapshots/query_caches_schema.hpp @@ -0,0 +1,42 @@ +// Copyright 2025 The Silkworm Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include +#include +#include + +#include "../common/entity_name.hpp" + +namespace silkworm::snapshots { + +class QueryCachesSchema { + public: + QueryCachesSchema& enable(datastore::EntityName entity_name) { + entities_[entity_name] = true; + return *this; + } + + QueryCachesSchema& cache_size(datastore::EntityName query_name, size_t size) { + cache_sizes_[query_name] = size; + return *this; + } + + QueryCachesSchema& index_salt_file_name(std::string_view value) { + index_salt_file_name_ = value; + return *this; + } + + const datastore::EntityMap& entities() const { return entities_; } + bool is_enabled(datastore::EntityName entity_name) const { return entities_.contains(entity_name); } + size_t cache_size(datastore::EntityName query_name) const { return cache_sizes_.at(query_name); } + const std::string& index_salt_file_name() const { return index_salt_file_name_.value(); } + + private: + datastore::EntityMap entities_; + datastore::EntityMap cache_sizes_; + std::optional index_salt_file_name_; +}; + +} // namespace silkworm::snapshots diff --git a/silkworm/db/datastore/snapshots/schema.hpp b/silkworm/db/datastore/snapshots/schema.hpp index ad8ce12e01..dcb95a97ec 100644 --- a/silkworm/db/datastore/snapshots/schema.hpp +++ b/silkworm/db/datastore/snapshots/schema.hpp @@ -9,6 +9,7 @@ #include "../common/entity_name.hpp" #include "../common/step_timestamp_converter.hpp" #include "common/snapshot_path.hpp" +#include "query_caches_schema.hpp" #include "segment/seg/compression_kind.hpp" namespace silkworm::snapshots { @@ -219,6 +220,10 @@ class Schema { return repository_defs_[name]; } + QueryCachesSchema& query_caches_schema() { + return query_caches_schema_; + } + static inline const datastore::EntityName kDefaultEntityName{"_"}; static inline const datastore::EntityName kDomainKVSegmentName{"DomainKVSegment"}; @@ -250,6 +255,7 @@ class Schema { private: datastore::EntityMap repository_defs_; + QueryCachesSchema query_caches_schema_; }; } // namespace silkworm::snapshots diff --git a/silkworm/db/datastore/snapshots/snapshot_repository.cpp b/silkworm/db/datastore/snapshots/snapshot_repository.cpp index 8866c6c5d3..eec9dad8bf 100644 --- a/silkworm/db/datastore/snapshots/snapshot_repository.cpp +++ b/silkworm/db/datastore/snapshots/snapshot_repository.cpp @@ -26,9 +26,7 @@ SnapshotRepository::SnapshotRepository( bool open, Schema::RepositoryDef schema, std::optional index_salt, - std::unique_ptr index_builders_factory, - std::optional domain_caches, - std::optional inverted_index_caches) + std::unique_ptr index_builders_factory) : name_(std::move(name)), dir_path_(std::move(dir_path)), schema_(std::move(schema)), @@ -36,9 +34,7 @@ SnapshotRepository::SnapshotRepository( index_salt_(index_salt), index_builders_factory_(std::move(index_builders_factory)), bundles_(std::make_shared()), - bundles_mutex_(std::make_unique()), - domain_caches_{std::move(domain_caches)}, - inverted_index_caches_{std::move(inverted_index_caches)} { + bundles_mutex_(std::make_unique()) { if (open) reopen_folder(); } @@ -62,18 +58,6 @@ void SnapshotRepository::replace_snapshot_bundles(SnapshotBundle bundle) { bundles_ = bundles; } -DomainGetLatestCache* SnapshotRepository::domain_get_latest_cache(const datastore::EntityName& name) const { - if (!domain_caches_) return nullptr; - if (!domain_caches_->contains(name)) return nullptr; - return domain_caches_->at(name).get(); -} - -InvertedIndexSeekCache* SnapshotRepository::inverted_index_seek_cache(const datastore::EntityName& name) const { - if (!inverted_index_caches_) return nullptr; - if (!inverted_index_caches_->contains(name)) return nullptr; - return inverted_index_caches_->at(name).get(); -} - size_t SnapshotRepository::bundles_count() const { std::scoped_lock lock(*bundles_mutex_); return bundles_->size(); diff --git a/silkworm/db/datastore/snapshots/snapshot_repository.hpp b/silkworm/db/datastore/snapshots/snapshot_repository.hpp index 3053c1793d..1a9b19e42e 100644 --- a/silkworm/db/datastore/snapshots/snapshot_repository.hpp +++ b/silkworm/db/datastore/snapshots/snapshot_repository.hpp @@ -44,9 +44,7 @@ class SnapshotRepository : public SnapshotRepositoryROAccess { bool open, Schema::RepositoryDef schema, std::optional index_salt, - std::unique_ptr index_builders_factory, - std::optional domain_caches, - std::optional inverted_index_caches); + std::unique_ptr index_builders_factory); SnapshotRepository(SnapshotRepository&&) = default; SnapshotRepository& operator=(SnapshotRepository&&) noexcept = delete; @@ -67,9 +65,6 @@ class SnapshotRepository : public SnapshotRepositoryROAccess { //! Replace bundles whose ranges are contained within the given bundle void replace_snapshot_bundles(SnapshotBundle bundle); - DomainGetLatestCache* domain_get_latest_cache(const datastore::EntityName& name) const override; - InvertedIndexSeekCache* inverted_index_seek_cache(const datastore::EntityName& name) const override; - size_t bundles_count() const override; Timestamp max_timestamp_available() const override; @@ -134,10 +129,6 @@ class SnapshotRepository : public SnapshotRepositoryROAccess { //! Full snapshot bundles ordered by block_from std::shared_ptr bundles_; std::unique_ptr bundles_mutex_; - - //! Cache for D/II values across all bundles - std::optional domain_caches_; - std::optional inverted_index_caches_; }; } // namespace silkworm::snapshots diff --git a/silkworm/db/datastore/snapshots/snapshot_repository_ro_access.hpp b/silkworm/db/datastore/snapshots/snapshot_repository_ro_access.hpp index 9ee4d4ee7f..0eff90ae34 100644 --- a/silkworm/db/datastore/snapshots/snapshot_repository_ro_access.hpp +++ b/silkworm/db/datastore/snapshots/snapshot_repository_ro_access.hpp @@ -15,8 +15,6 @@ #include "../common/step.hpp" #include "../common/timestamp.hpp" #include "common/util/iterator/map_values_view.hpp" -#include "domain_cache.hpp" -#include "inverted_index_cache.hpp" #include "segment_and_accessor_index.hpp" namespace silkworm::snapshots { @@ -49,9 +47,6 @@ struct SnapshotRepositoryROAccess { virtual ~SnapshotRepositoryROAccess() = default; - virtual DomainGetLatestCache* domain_get_latest_cache(const datastore::EntityName& name) const = 0; - virtual InvertedIndexSeekCache* inverted_index_seek_cache(const datastore::EntityName& name) const = 0; - virtual size_t bundles_count() const = 0; //! All types of .seg and .idx files are available up to this timestamp diff --git a/silkworm/db/kv/api/local_transaction.cpp b/silkworm/db/kv/api/local_transaction.cpp index dd41d67980..dbf12f5d13 100644 --- a/silkworm/db/kv/api/local_transaction.cpp +++ b/silkworm/db/kv/api/local_transaction.cpp @@ -153,11 +153,13 @@ Task LocalTransaction::get_latest(GetLatestRequest request) { } const EntityName domain_name = kTable2EntityNames.at(request.table); - RawDomainGetLatestQuery query( + RawDomainGetLatestQuery query{ domain_name, data_store_.chaindata.domain(domain_name), tx_, - data_store_.state_repository_latest); + data_store_.state_repository_latest, + data_store_.query_caches, + }; auto result = query.exec(request.key); if (!result) { co_return GetLatestResult{}; diff --git a/silkworm/db/kv/api/local_transaction.hpp b/silkworm/db/kv/api/local_transaction.hpp index 52f78560b6..bb18afc611 100644 --- a/silkworm/db/kv/api/local_transaction.hpp +++ b/silkworm/db/kv/api/local_transaction.hpp @@ -69,20 +69,24 @@ class LocalTransaction : public BaseTransaction { private: template auto query_domain_as_of(const datastore::EntityName domain_name, ByteView key, Timestamp ts) { - DomainGetAsOfQuery query( + DomainGetAsOfQuery query{ data_store_.chaindata.domain(domain_name), tx_, data_store_.state_repository_latest, - data_store_.state_repository_historical); + data_store_.state_repository_historical, + data_store_.query_caches, + }; return query.exec(key, ts); } template auto query_history_get(datastore::kvdb::History kvdb_entity, ByteView key, datastore::Timestamp ts) { - HistoryGetQuery query( + HistoryGetQuery query{ kvdb_entity, tx_, - data_store_.state_repository_historical); + data_store_.state_repository_historical, + data_store_.query_caches, + }; return query.exec(key, ts); } diff --git a/silkworm/db/state/accounts_domain.hpp b/silkworm/db/state/accounts_domain.hpp index f02b5ab476..371f6055f2 100644 --- a/silkworm/db/state/accounts_domain.hpp +++ b/silkworm/db/state/accounts_domain.hpp @@ -23,14 +23,17 @@ struct AccountsDomainGetLatestQuery : public datastore::DomainGetLatestQuery< AccountsDomainGetLatestQuery( const datastore::kvdb::DatabaseRef& database, datastore::kvdb::ROTxn& tx, - const snapshots::SnapshotRepositoryROAccess& repository) + const snapshots::SnapshotRepositoryROAccess& repository, + const snapshots::QueryCaches& query_caches) : datastore::DomainGetLatestQuery< AddressKVDBEncoder, AddressSnapshotsEncoder, - AccountKVDBCodec, AccountSnapshotsCodec>( + AccountKVDBCodec, AccountSnapshotsCodec>{ db::state::kDomainNameAccounts, database.domain(db::state::kDomainNameAccounts), tx, - repository) {} + repository, + query_caches, + } {} }; struct AccountsDomainPutQuery : public datastore::kvdb::DomainPutQuery { diff --git a/silkworm/db/state/code_domain.hpp b/silkworm/db/state/code_domain.hpp index 9175d2a1b8..fd03d4484d 100644 --- a/silkworm/db/state/code_domain.hpp +++ b/silkworm/db/state/code_domain.hpp @@ -23,14 +23,17 @@ struct CodeDomainGetLatestQuery : public datastore::DomainGetLatestQuery< CodeDomainGetLatestQuery( const datastore::kvdb::DatabaseRef& database, datastore::kvdb::ROTxn& tx, - const snapshots::SnapshotRepositoryROAccess& repository) + const snapshots::SnapshotRepositoryROAccess& repository, + const snapshots::QueryCaches& query_caches) : datastore::DomainGetLatestQuery< AddressKVDBEncoder, AddressSnapshotsEncoder, - datastore::kvdb::RawDecoder, snapshots::RawDecoder>( + datastore::kvdb::RawDecoder, snapshots::RawDecoder>{ db::state::kDomainNameCode, database.domain(db::state::kDomainNameCode), tx, - repository) {} + repository, + query_caches, + } {} }; struct CodeDomainPutQuery : public datastore::kvdb::DomainPutQuery> { diff --git a/silkworm/db/state/commitment_domain.hpp b/silkworm/db/state/commitment_domain.hpp index 62e3791b99..6ac6eb6652 100644 --- a/silkworm/db/state/commitment_domain.hpp +++ b/silkworm/db/state/commitment_domain.hpp @@ -22,14 +22,17 @@ struct CommitmentDomainGetLatestQuery : public datastore::DomainGetLatestQuery< CommitmentDomainGetLatestQuery( const datastore::kvdb::DatabaseRef& database, datastore::kvdb::ROTxn& tx, - const snapshots::SnapshotRepositoryROAccess& repository) + const snapshots::SnapshotRepositoryROAccess& repository, + const snapshots::QueryCaches& query_caches) : datastore::DomainGetLatestQuery< datastore::kvdb::RawEncoder, snapshots::RawEncoder, - datastore::kvdb::RawDecoder, snapshots::RawDecoder>( + datastore::kvdb::RawDecoder, snapshots::RawDecoder>{ db::state::kDomainNameCommitment, database.domain(db::state::kDomainNameCommitment), tx, - repository) {} + repository, + query_caches, + } {} }; struct CommitmentDomainPutQuery : public datastore::kvdb::DomainPutQuery, datastore::kvdb::RawEncoder> { diff --git a/silkworm/db/state/receipts_domain.hpp b/silkworm/db/state/receipts_domain.hpp index 28cfd89b4e..b5ef80be54 100644 --- a/silkworm/db/state/receipts_domain.hpp +++ b/silkworm/db/state/receipts_domain.hpp @@ -69,14 +69,17 @@ struct ReceiptsDomainGetLatestQuery : public datastore::DomainGetLatestQuery< ReceiptsDomainGetLatestQuery( const datastore::kvdb::DatabaseRef& database, datastore::kvdb::ROTxn& tx, - const snapshots::SnapshotRepositoryROAccess& repository) + const snapshots::SnapshotRepositoryROAccess& repository, + const snapshots::QueryCaches& query_caches) : datastore::DomainGetLatestQuery< datastore::kvdb::RawEncoder, snapshots::RawEncoder, - datastore::kvdb::RawDecoder, snapshots::RawDecoder>( + datastore::kvdb::RawDecoder, snapshots::RawDecoder>{ db::state::kDomainNameReceipts, database.domain(db::state::kDomainNameReceipts), tx, - repository) {} + repository, + query_caches, + } {} }; struct ReceiptsDomainPutQuery : public datastore::kvdb::DomainPutQuery, datastore::kvdb::RawEncoder> { diff --git a/silkworm/db/state/schema_config.cpp b/silkworm/db/state/schema_config.cpp index 33554e92b1..00d4e5af4f 100644 --- a/silkworm/db/state/schema_config.cpp +++ b/silkworm/db/state/schema_config.cpp @@ -7,6 +7,8 @@ #include +#include "../datastore/snapshots/domain_get_latest_query.hpp" +#include "../datastore/snapshots/inverted_index_seek_query.hpp" #include "state_index_builders_factory.hpp" #include "step_txn_id_converter.hpp" @@ -73,41 +75,21 @@ datastore::kvdb::Schema::DatabaseDef make_state_database_schema() { return schema; } -static constexpr size_t kDefaultDomainCacheSize = 10'000; -static constexpr size_t kDefaultInvertedIndexCacheSize = 4'096; - -// 1. std::array instead of const char* because MSVC is stricter on non-type template parameters passed by reference -// 2. explicit std::array template arguments to avoid incorrect CTAD as std::array -static constexpr std::array kDomainCacheEnvVar{"D_LRU_CACHE_SIZE"}; -static constexpr std::array kInvertedIndexCacheEnvVar{"II_LRU_CACHE_SIZE"}; - -template -static size_t cache_size() { - const auto cache_size_var = Environment::get(env_var_name.data()); - return cache_size_var.empty() ? default_size : std::stoul(cache_size_var); -} - -template -static std::unique_ptr make_cache(std::optional salt) { - const size_t size = cache_size(); - return size > 0 ? std::make_unique(size, salt.value_or(0)) : nullptr; -} +snapshots::QueryCachesSchema make_query_caches_schema() { + snapshots::QueryCachesSchema schema; + schema.index_salt_file_name("salt-state.txt"); -template -static auto make_caches(std::optional salt) { - std::map> caches; - for (const auto& entity_name : {kDomainNameAccounts, kDomainNameStorage, kDomainNameCode, kDomainNameReceipts}) { - caches.emplace(entity_name, make_cache(salt)); - } - return caches; -} + schema.enable(kDomainNameAccounts); + schema.enable(kDomainNameStorage); + schema.enable(kDomainNameCode); + schema.enable(kDomainNameReceipts); -static snapshots::DomainGetLatestCaches make_domain_caches(std::optional salt) { - return make_caches(salt); -} + static constexpr size_t kDefaultDomainCacheSize = 10'000; + static constexpr size_t kDefaultInvertedIndexCacheSize = 4'096; + schema.cache_size(snapshots::DomainGetLatestQueryRawWithCache::kName, kDefaultDomainCacheSize); + schema.cache_size(snapshots::InvertedIndexSeekQueryRawWithCache::kName, kDefaultInvertedIndexCacheSize); -static snapshots::InvertedIndexSeekCaches make_inverted_index_caches(std::optional salt) { - return make_caches(salt); + return schema; } static snapshots::SnapshotRepository make_state_repository( @@ -123,8 +105,6 @@ static snapshots::SnapshotRepository make_state_repository( schema, index_salt, std::make_unique(schema), - make_domain_caches(index_salt), - make_inverted_index_caches(index_salt), }; } diff --git a/silkworm/db/state/schema_config.hpp b/silkworm/db/state/schema_config.hpp index 2ee85d8f25..7d5af5c866 100644 --- a/silkworm/db/state/schema_config.hpp +++ b/silkworm/db/state/schema_config.hpp @@ -11,6 +11,7 @@ #include "../datastore/snapshots/domain.hpp" #include "../datastore/snapshots/index_builders_factory.hpp" #include "../datastore/snapshots/inverted_index.hpp" +#include "../datastore/snapshots/query_caches_schema.hpp" #include "../datastore/snapshots/schema.hpp" #include "../datastore/snapshots/snapshot_repository.hpp" @@ -22,6 +23,7 @@ inline const datastore::EntityName kStateRepositoryNameHistorical{"StateHistoric snapshots::Schema::RepositoryDef make_state_repository_schema_latest(); snapshots::Schema::RepositoryDef make_state_repository_schema_historical(); datastore::kvdb::Schema::DatabaseDef make_state_database_schema(); +snapshots::QueryCachesSchema make_query_caches_schema(); snapshots::SnapshotRepository make_state_repository_latest( std::filesystem::path dir_path, diff --git a/silkworm/db/state/storage_domain.hpp b/silkworm/db/state/storage_domain.hpp index 47692fd589..ef3ee0938e 100644 --- a/silkworm/db/state/storage_domain.hpp +++ b/silkworm/db/state/storage_domain.hpp @@ -22,14 +22,17 @@ struct StorageDomainGetLatestQuery : public datastore::DomainGetLatestQuery< StorageDomainGetLatestQuery( const datastore::kvdb::DatabaseRef& database, datastore::kvdb::ROTxn& tx, - const snapshots::SnapshotRepositoryROAccess& repository) + const snapshots::SnapshotRepositoryROAccess& repository, + const snapshots::QueryCaches& query_caches) : datastore::DomainGetLatestQuery< StorageAddressAndLocationKVDBEncoder, StorageAddressAndLocationSnapshotsCodec, - PackedBytes32KVDBCodec, PackedBytes32SnapshotsCodec>( + PackedBytes32KVDBCodec, PackedBytes32SnapshotsCodec>{ db::state::kDomainNameStorage, database.domain(db::state::kDomainNameStorage), tx, - repository) {} + repository, + query_caches, + } {} }; struct StorageDomainPutQuery : public datastore::kvdb::DomainPutQuery { diff --git a/silkworm/execution/domain_state.cpp b/silkworm/execution/domain_state.cpp index 71adb12322..2f9f4044db 100644 --- a/silkworm/execution/domain_state.cpp +++ b/silkworm/execution/domain_state.cpp @@ -29,7 +29,7 @@ using namespace datastore; // - add base_txn_id to block and get_txn_by_id method std::optional DomainState::read_account(const evmc::address& address) const noexcept { - AccountsDomainGetLatestQuery query{database_, tx_, latest_state_repository_}; + AccountsDomainGetLatestQuery query{database_, tx_, latest_state_repository_, query_caches_}; auto result = query.exec(address); if (result) { return std::move(result->value); @@ -42,7 +42,7 @@ ByteView DomainState::read_code(const evmc::address& address, const evmc::bytes3 return code_[address]; // NOLINT(runtime/arrays) } - CodeDomainGetLatestQuery query{database_, tx_, latest_state_repository_}; + CodeDomainGetLatestQuery query{database_, tx_, latest_state_repository_, query_caches_}; auto result = query.exec(address); if (result) { auto [it, _] = code_.emplace(address, std::move(result->value)); @@ -55,7 +55,7 @@ evmc::bytes32 DomainState::read_storage( const evmc::address& address, uint64_t /*incarnation*/, const evmc::bytes32& location) const noexcept { - StorageDomainGetLatestQuery query{database_, tx_, latest_state_repository_}; + StorageDomainGetLatestQuery query{database_, tx_, latest_state_repository_, query_caches_}; auto result = query.exec({address, location}); if (result) { return std::move(result->value); @@ -150,7 +150,7 @@ void DomainState::update_account( std::optional initial, std::optional current) { if (!initial) { - AccountsDomainGetLatestQuery query_prev{database_, tx_, latest_state_repository_}; + AccountsDomainGetLatestQuery query_prev{database_, tx_, latest_state_repository_, query_caches_}; auto result_prev = query_prev.exec(address); if (result_prev) { initial = std::move(result_prev->value); @@ -173,7 +173,7 @@ void DomainState::update_account_code( uint64_t /*incarnation*/, const evmc::bytes32& /*code_hash*/, ByteView code) { - CodeDomainGetLatestQuery query_prev{database_, tx_, latest_state_repository_}; + CodeDomainGetLatestQuery query_prev{database_, tx_, latest_state_repository_, query_caches_}; auto result_prev = query_prev.exec(address); std::optional original_code = std::nullopt; @@ -195,7 +195,7 @@ void DomainState::update_storage( evmc::bytes32 original_value{}; if (initial == evmc::bytes32{}) { - StorageDomainGetLatestQuery query_prev{database_, tx_, latest_state_repository_}; + StorageDomainGetLatestQuery query_prev{database_, tx_, latest_state_repository_, query_caches_}; auto result_prev = query_prev.exec({address, location}); if (result_prev) { original_value = std::move(result_prev->value); diff --git a/silkworm/execution/domain_state.hpp b/silkworm/execution/domain_state.hpp index 88d60b58e4..ae7b9dddd4 100644 --- a/silkworm/execution/domain_state.hpp +++ b/silkworm/execution/domain_state.hpp @@ -26,12 +26,14 @@ class DomainState : public State { TxnId txn_id, datastore::kvdb::RWTxn& tx, datastore::kvdb::DatabaseRef& database, - snapshots::SnapshotRepositoryROAccess& blocks_repository, - snapshots::SnapshotRepositoryROAccess& latest_state_repository) + const snapshots::SnapshotRepositoryROAccess& blocks_repository, + snapshots::SnapshotRepositoryROAccess& latest_state_repository, + const snapshots::QueryCaches& query_caches) : txn_id_{txn_id}, tx_{tx}, database_{database}, latest_state_repository_{latest_state_repository}, + query_caches_{query_caches}, data_model_{db::DataModel{tx_, blocks_repository}} {} explicit DomainState( @@ -39,13 +41,14 @@ class DomainState : public State { datastore::kvdb::RWTxn& tx, datastore::kvdb::DatabaseRef& database, snapshots::SnapshotRepositoryROAccess& state_repository, - db::DataModel& data_model) - + snapshots::QueryCaches& query_caches, + db::DataModel data_model) : txn_id_{txn_id}, tx_{tx}, database_{database}, latest_state_repository_{state_repository}, - data_model_{data_model} {} + query_caches_{query_caches}, + data_model_{std::move(data_model)} {} std::optional read_account(const evmc::address& address) const noexcept override; @@ -107,6 +110,7 @@ class DomainState : public State { datastore::kvdb::RWTxn& tx_; datastore::kvdb::DatabaseRef& database_; snapshots::SnapshotRepositoryROAccess& latest_state_repository_; + const snapshots::QueryCaches& query_caches_; db::DataModel data_model_; mutable std::unordered_map code_; }; diff --git a/silkworm/execution/domain_state_test.cpp b/silkworm/execution/domain_state_test.cpp index 9f5be8ad1b..631415a8b0 100644 --- a/silkworm/execution/domain_state_test.cpp +++ b/silkworm/execution/domain_state_test.cpp @@ -29,7 +29,14 @@ TEST_CASE("DomainState data access", "[execution][domain][state]") { auto rw_tx = ds_context.chaindata_rw().start_rw_tx(); auto db_ref = ds_context->chaindata().ref(); - auto sut = DomainState{1, rw_tx, db_ref, ds_context->blocks_repository(), ds_context->state_repository_latest()}; + DomainState sut{ + 1, + rw_tx, + db_ref, + ds_context->blocks_repository(), + ds_context->state_repository_latest(), + ds_context->query_caches(), + }; auto header0_hash = sut.canonical_hash(0); auto header0 = sut.read_header(0, header0_hash.value()); @@ -148,7 +155,14 @@ TEST_CASE("DomainState data access", "[execution][domain][state]") { CHECK(account_66_read->balance == account_66_v2.balance); auto next_step_txn_id = db::state::kStepSizeForTemporalSnapshots + 1; - auto sut2 = DomainState{next_step_txn_id, rw_tx, db_ref, ds_context->blocks_repository(), ds_context->state_repository_latest()}; + DomainState sut2{ + next_step_txn_id, + rw_tx, + db_ref, + ds_context->blocks_repository(), + ds_context->state_repository_latest(), + ds_context->query_caches(), + }; Account account_66_v3{ .nonce = 10, .balance = 262, @@ -207,7 +221,14 @@ TEST_CASE("DomainState data access", "[execution][domain][state]") { CHECK(code_66_read == code_66); auto next_step_txn_id = db::state::kStepSizeForTemporalSnapshots + 1; - auto sut2 = DomainState{next_step_txn_id, rw_tx, db_ref, ds_context->blocks_repository(), ds_context->state_repository_latest()}; + DomainState sut2{ + next_step_txn_id, + rw_tx, + db_ref, + ds_context->blocks_repository(), + ds_context->state_repository_latest(), + ds_context->query_caches(), + }; code_66 = *from_hex("0x6044"); code_hash_66 = std::bit_cast(keccak256(code_66)); sut2.update_account_code( @@ -264,7 +285,14 @@ TEST_CASE("DomainState data access", "[execution][domain][state]") { CHECK(storage_66_01 == 0x0124_bytes32); auto next_step_txn_id = db::state::kStepSizeForTemporalSnapshots + 1; - auto sut2 = DomainState{next_step_txn_id, rw_tx, db_ref, ds_context->blocks_repository(), ds_context->state_repository_latest()}; + DomainState sut2{ + next_step_txn_id, + rw_tx, + db_ref, + ds_context->blocks_repository(), + ds_context->state_repository_latest(), + ds_context->query_caches(), + }; sut2.update_storage( 0x668bdf435d810c91414ec09147daa6db62406379_address, kDefaultIncarnation, @@ -286,7 +314,14 @@ TEST_CASE("DomainState empty overridden methods do nothing", "[execution][domain auto rw_tx = ds_context.chaindata_rw().start_rw_tx(); auto db_ref = ds_context->chaindata().ref(); - auto sut = DomainState{1, rw_tx, db_ref, ds_context->blocks_repository(), ds_context->state_repository_latest()}; + DomainState sut{ + 1, + rw_tx, + db_ref, + ds_context->blocks_repository(), + ds_context->state_repository_latest(), + ds_context->query_caches(), + }; CHECK_NOTHROW(sut.insert_block(Block{}, evmc::bytes32{})); CHECK_NOTHROW(sut.canonize_block(0, evmc::bytes32{})); diff --git a/silkworm/execution/local_state.hpp b/silkworm/execution/local_state.hpp index 1c288d1a27..61ea7646b5 100644 --- a/silkworm/execution/local_state.hpp +++ b/silkworm/execution/local_state.hpp @@ -86,7 +86,13 @@ class LocalState : public State { template auto query_as_of() const { - return DomainQuery{data_store_.chaindata, tx_, data_store_.state_repository_latest, data_store_.state_repository_historical}; + return DomainQuery{ + data_store_.chaindata, + tx_, + data_store_.state_repository_latest, + data_store_.state_repository_historical, + data_store_.query_caches, + }; } std::optional txn_id_;