Skip to content

Commit aeb2302

Browse files
authored
datastore: query caches refactoring (#2880)
1 parent 41185c3 commit aeb2302

36 files changed

+469
-260
lines changed

silkworm/capi/init.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ SILKWORM_EXPORT int silkworm_init(SilkwormHandle* handle, const struct SilkwormS
8383
.state_repository_latest = std::move(state_repository_latest),
8484
.state_repository_historical = std::move(state_repository_historical),
8585
.chaindata = {},
86+
.query_caches = snapshots::QueryCaches{db::state::make_query_caches_schema(), snapshots_dir_path, settings->state_repo_index_salt},
8687
};
8788

8889
// NOLINTNEXTLINE(bugprone-unhandled-exception-at-new)

silkworm/capi/silkworm.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ SILKWORM_EXPORT int silkworm_execute_txn(SilkwormHandle handle, MDBX_txn* mdbx_t
500500
db_ref,
501501
handle->db->blocks_repository,
502502
handle->db->state_repository_latest,
503+
handle->db->query_caches,
503504
};
504505
if (!handle->chain_config) {
505506
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
646647
db_ref,
647648
handle->db->blocks_repository,
648649
handle->db->state_repository_latest,
650+
handle->db->query_caches,
649651
};
650652

651653
const auto log_index = handle->executions_in_block[index].log_index;

silkworm/db/blocks/schema_config.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ snapshots::SnapshotRepository make_blocks_repository(
5757
schema,
5858
index_salt,
5959
make_blocks_index_builders_factory(),
60-
std::nullopt, // no domain caches
61-
std::nullopt, // no inverted index caches
6260
};
6361
}
6462

silkworm/db/capi/component.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <silkworm/core/common/assert.hpp>
99
#include <silkworm/db/access_layer.hpp>
1010
#include <silkworm/db/datastore/kvdb/database.hpp>
11+
#include <silkworm/db/datastore/snapshots/query_caches.hpp>
1112
#include <silkworm/db/datastore/snapshots/snapshot_repository.hpp>
1213

1314
namespace silkworm::db::capi {
@@ -17,6 +18,7 @@ struct Component {
1718
silkworm::snapshots::SnapshotRepository state_repository_latest;
1819
silkworm::snapshots::SnapshotRepository state_repository_historical;
1920
std::unique_ptr<silkworm::datastore::kvdb::DatabaseUnmanaged> chaindata;
21+
silkworm::snapshots::QueryCaches query_caches;
2022

2123
DataStoreRef data_store() {
2224
SILKWORM_ASSERT(chaindata);
@@ -25,6 +27,7 @@ struct Component {
2527
blocks_repository,
2628
state_repository_latest,
2729
state_repository_historical,
30+
query_caches,
2831
};
2932
}
3033

silkworm/db/data_store.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ datastore::Schema DataStore::make_schema() {
1313
snapshots.repository(blocks::kBlocksRepositoryName) = blocks::make_blocks_repository_schema();
1414
snapshots.repository(state::kStateRepositoryNameLatest) = state::make_state_repository_schema_latest();
1515
snapshots.repository(state::kStateRepositoryNameHistorical) = state::make_state_repository_schema_historical();
16+
snapshots.query_caches_schema() = state::make_query_caches_schema();
1617

1718
return {
1819
std::move(kvdb),

silkworm/db/data_store.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ struct DataStoreRef {
1717
snapshots::SnapshotRepository& blocks_repository;
1818
snapshots::SnapshotRepository& state_repository_latest;
1919
snapshots::SnapshotRepository& state_repository_historical;
20+
const snapshots::QueryCaches& query_caches;
2021
};
2122

2223
class DataStore {
@@ -32,6 +33,7 @@ class DataStore {
3233
std::move(blocks_repository),
3334
std::move(state_repository_latest),
3435
std::move(state_repository_historical)),
36+
blocks_repository.path(),
3537
} {}
3638

3739
public:
@@ -61,6 +63,7 @@ class DataStore {
6163
blocks_repository(),
6264
state_repository_latest(),
6365
state_repository_historical(),
66+
store_.query_caches(),
6467
};
6568
}
6669

@@ -75,6 +78,7 @@ class DataStore {
7578
snapshots::SnapshotRepository& state_repository_historical() const {
7679
return store_.repository(state::kStateRepositoryNameHistorical);
7780
}
81+
const snapshots::QueryCaches& query_caches() const { return store_.query_caches(); }
7882

7983
static datastore::kvdb::Schema::DatabaseDef make_chaindata_database_schema();
8084
static datastore::kvdb::Database make_chaindata_database(mdbx::env_managed chaindata_env);

silkworm/db/datastore/data_store.hpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "common/entity_name.hpp"
99
#include "kvdb/database.hpp"
1010
#include "schema.hpp"
11+
#include "snapshots/query_caches.hpp"
1112
#include "snapshots/snapshot_repository.hpp"
1213

1314
namespace silkworm::datastore {
@@ -17,21 +18,25 @@ class DataStore {
1718
DataStore(
1819
Schema schema,
1920
EntityMap<std::unique_ptr<kvdb::Database>> databases,
20-
EntityMap<std::unique_ptr<snapshots::SnapshotRepository>> repositories)
21+
EntityMap<std::unique_ptr<snapshots::SnapshotRepository>> repositories,
22+
const std::filesystem::path& snapshots_path)
2123
: schema_{std::move(schema)},
2224
databases_{std::move(databases)},
23-
repositories_{std::move(repositories)} {}
25+
repositories_{std::move(repositories)},
26+
query_caches_{schema_.snapshots.query_caches_schema(), snapshots_path} {}
2427

2528
const Schema& schema() const { return schema_; }
2629

2730
kvdb::Database& default_database() const { return database(kvdb::Schema::kDefaultEntityName); }
2831
kvdb::Database& database(const EntityName& name) const { return *databases_.at(name); }
2932
snapshots::SnapshotRepository& repository(const EntityName& name) const { return *repositories_.at(name); }
33+
const snapshots::QueryCaches& query_caches() const { return query_caches_; }
3034

3135
private:
3236
Schema schema_;
3337
EntityMap<std::unique_ptr<kvdb::Database>> databases_;
3438
EntityMap<std::unique_ptr<snapshots::SnapshotRepository>> repositories_;
39+
snapshots::QueryCaches query_caches_;
3540
};
3641

3742
} // namespace silkworm::datastore

silkworm/db/datastore/domain_get_as_of_query.hpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,19 @@ struct DomainGetAsOfQuery {
1717
kvdb::Domain kvdb_entity,
1818
kvdb::ROTxn& tx,
1919
const snapshots::SnapshotRepositoryROAccess& repository_latest,
20-
const snapshots::SnapshotRepositoryROAccess& repository_historical)
21-
: query1_{*kvdb_entity.history, tx, repository_historical},
22-
query2_{history_segment_names.front(), kvdb_entity, tx, repository_latest} {}
20+
const snapshots::SnapshotRepositoryROAccess& repository_historical,
21+
const snapshots::QueryCaches& query_caches)
22+
: query1_{*kvdb_entity.history, tx, repository_historical, query_caches},
23+
query2_{history_segment_names.front(), kvdb_entity, tx, repository_latest, query_caches} {}
2324

2425
DomainGetAsOfQuery(
2526
const kvdb::DatabaseRef& database,
2627
kvdb::ROTxn& tx,
2728
const snapshots::SnapshotRepositoryROAccess& repository_latest,
28-
const snapshots::SnapshotRepositoryROAccess& repository_historical)
29-
: query1_{database, tx, repository_historical},
30-
query2_{history_segment_names.front(), database, tx, repository_latest} {}
29+
const snapshots::SnapshotRepositoryROAccess& repository_historical,
30+
const snapshots::QueryCaches& query_caches)
31+
: query1_{database, tx, repository_historical, query_caches},
32+
query2_{history_segment_names.front(), database, tx, repository_latest, query_caches} {}
3133

3234
using Key = decltype(TKeyEncoder1::value);
3335
using Value = decltype(TValueDecoder1::value);

silkworm/db/datastore/domain_get_latest_query.hpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,23 @@ struct DomainGetLatestQuery {
1717
datastore::EntityName entity_name,
1818
kvdb::Domain kvdb_entity,
1919
kvdb::ROTxn& tx,
20-
const snapshots::SnapshotRepositoryROAccess& repository)
20+
const snapshots::SnapshotRepositoryROAccess& repository,
21+
const snapshots::QueryCaches& query_caches)
2122
: query1_{tx, kvdb_entity},
22-
query2_{repository, entity_name} {}
23+
query2_{repository, query_caches, entity_name} {}
2324

2425
DomainGetLatestQuery(
2526
datastore::EntityName entity_name,
2627
const kvdb::DatabaseRef& database,
2728
kvdb::ROTxn& tx,
28-
const snapshots::SnapshotRepositoryROAccess& repository)
29+
const snapshots::SnapshotRepositoryROAccess& repository,
30+
const snapshots::QueryCaches& query_caches)
2931
: DomainGetLatestQuery{
3032
entity_name,
3133
database.domain(entity_name),
3234
tx,
3335
repository,
36+
query_caches,
3437
} {}
3538

3639
using Key1 = decltype(TKeyEncoder1::value);

silkworm/db/datastore/history_get_query.hpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,21 @@ struct HistoryGetQuery {
1717
HistoryGetQuery(
1818
kvdb::History kvdb_entity,
1919
kvdb::ROTxn& tx,
20-
const snapshots::SnapshotRepositoryROAccess& repository)
20+
const snapshots::SnapshotRepositoryROAccess& repository,
21+
const snapshots::QueryCaches& query_caches)
2122
: query1_{tx, kvdb_entity},
22-
query2_{repository} {}
23+
query2_{repository, query_caches} {}
2324

2425
HistoryGetQuery(
2526
const kvdb::DatabaseRef& database,
2627
kvdb::ROTxn& tx,
27-
const snapshots::SnapshotRepositoryROAccess& repository)
28+
const snapshots::SnapshotRepositoryROAccess& repository,
29+
const snapshots::QueryCaches& query_caches)
2830
: HistoryGetQuery{
2931
database.domain(segment_names.front()).history.value(),
3032
tx,
3133
repository,
34+
query_caches,
3235
} {}
3336

3437
using Key1 = decltype(TKeyEncoder1::value);

silkworm/db/datastore/snapshots/domain_cache.hpp

Lines changed: 0 additions & 25 deletions
This file was deleted.

silkworm/db/datastore/snapshots/domain_get_latest_query.hpp

Lines changed: 71 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
#include "common/codec.hpp"
88
#include "common/raw_codec.hpp"
99
#include "domain.hpp"
10-
#include "domain_cache.hpp"
10+
#include "query_cache.hpp"
11+
#include "query_caches.hpp"
1112
#include "segment/kv_segment_reader.hpp"
1213
#include "snapshot_bundle.hpp"
1314
#include "snapshot_repository_ro_access.hpp"
@@ -54,11 +55,70 @@ struct DomainGetLatestSegmentQuery {
5455
Domain entity_;
5556
};
5657

57-
template <EncoderConcept TKeyEncoder, DecoderConcept TValueDecoder>
58-
struct DomainGetLatestQuery {
58+
struct DomainGetLatestQueryRawNoCache {
5959
const SnapshotRepositoryROAccess& repository;
6060
datastore::EntityName entity_name;
6161

62+
struct Result {
63+
Decoder::Word value;
64+
datastore::Step step{0};
65+
};
66+
67+
std::optional<Result> exec(ByteView key_data) {
68+
for (auto& bundle_ptr : repository.view_bundles_reverse()) {
69+
const SnapshotBundle& bundle = *bundle_ptr;
70+
DomainGetLatestSegmentQuery<RawEncoder<ByteView>, RawDecoder<Decoder::Word>> query{bundle, entity_name};
71+
std::optional<Decoder::Word> value_data = query.exec_raw(key_data);
72+
if (value_data) {
73+
return Result{std::move(*value_data), bundle.step_range().end};
74+
}
75+
}
76+
return std::nullopt;
77+
}
78+
};
79+
80+
struct DomainGetLatestQueryRawWithCache {
81+
using Result = DomainGetLatestQueryRawNoCache::Result;
82+
using CacheType = QueryCache<std::optional<Result>>;
83+
static inline const datastore::EntityName kName{"DomainGetLatestQueryRawWithCache"};
84+
85+
DomainGetLatestQueryRawWithCache(
86+
const SnapshotRepositoryROAccess& repository,
87+
const QueryCaches& query_caches,
88+
datastore::EntityName entity_name)
89+
: query_{repository, entity_name},
90+
cache_{query_caches.cache<CacheType>(kName, entity_name).get()} {}
91+
92+
std::optional<Result> exec(ByteView key_data) {
93+
if (!cache_) {
94+
return query_.exec(key_data);
95+
}
96+
97+
std::optional<std::optional<Result>> cached_result;
98+
uint64_t cache_key{0};
99+
std::tie(cached_result, cache_key) = cache_->get(key_data);
100+
if (cached_result) {
101+
return std::move(*cached_result);
102+
}
103+
104+
std::optional<Result> result = query_.exec(key_data);
105+
cache_->put(cache_key, result);
106+
return result;
107+
}
108+
109+
private:
110+
DomainGetLatestQueryRawNoCache query_;
111+
CacheType* cache_;
112+
};
113+
114+
template <EncoderConcept TKeyEncoder, DecoderConcept TValueDecoder>
115+
struct DomainGetLatestQuery {
116+
DomainGetLatestQuery(
117+
const SnapshotRepositoryROAccess& repository,
118+
const QueryCaches& query_caches,
119+
datastore::EntityName entity_name)
120+
: query_{repository, query_caches, entity_name} {}
121+
62122
using Key = decltype(TKeyEncoder::value);
63123
using Value = decltype(TValueDecoder::value);
64124

@@ -68,43 +128,20 @@ struct DomainGetLatestQuery {
68128
};
69129

70130
std::optional<Result> exec(const Key& key) {
71-
DomainGetLatestCache* cache = repository.domain_get_latest_cache(entity_name);
72-
73131
TKeyEncoder key_encoder;
74132
key_encoder.value = key;
75133
ByteView key_data = key_encoder.encode_word();
76134

77-
uint64_t key_hash_hi{0};
78-
if (cache) {
79-
std::optional<DomainGetLatestCacheData> cached_data;
80-
if (std::tie(cached_data, key_hash_hi) = cache->get(key_data); cached_data) {
81-
if (!cached_data->range_end) { // hit in cache but value not found
82-
return std::nullopt;
83-
}
84-
TValueDecoder value_decoder;
85-
value_decoder.decode_word(cached_data->value);
86-
return Result{std::move(value_decoder.value), *cached_data->range_end};
87-
}
88-
}
135+
auto value_data = query_.exec(key_data);
136+
if (!value_data) return std::nullopt;
89137

90-
for (auto& bundle_ptr : repository.view_bundles_reverse()) {
91-
const SnapshotBundle& bundle = *bundle_ptr;
92-
DomainGetLatestSegmentQuery<TKeyEncoder, TValueDecoder> query{bundle, entity_name};
93-
std::optional<Decoder::Word> value_data = query.exec_raw(key_data);
94-
if (value_data) {
95-
if (cache) {
96-
cache->put(key_hash_hi, {*value_data, bundle.step_range().end});
97-
}
98-
TValueDecoder value_decoder;
99-
value_decoder.decode_word(*value_data);
100-
return Result{std::move(value_decoder.value), bundle.step_range().end};
101-
}
102-
}
103-
if (cache) {
104-
cache->put(key_hash_hi, {});
105-
}
106-
return std::nullopt;
138+
TValueDecoder value_decoder;
139+
value_decoder.decode_word(value_data->value);
140+
return Result{std::move(value_decoder.value), value_data->step};
107141
}
142+
143+
private:
144+
DomainGetLatestQueryRawWithCache query_;
108145
};
109146

110147
} // namespace silkworm::snapshots

silkworm/db/datastore/snapshots/history_get_query.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "common/codec.hpp"
99
#include "common/raw_codec.hpp"
1010
#include "inverted_index_seek_query.hpp"
11+
#include "query_caches.hpp"
1112
#include "snapshot_repository_ro_access.hpp"
1213

1314
namespace silkworm::snapshots {
@@ -17,11 +18,13 @@ template <
1718
DecoderConcept TValueDecoder,
1819
const SegmentAndAccessorIndexNames& segment_names>
1920
struct HistoryGetQuery {
20-
explicit HistoryGetQuery(const SnapshotRepositoryROAccess& repository)
21+
HistoryGetQuery(
22+
const SnapshotRepositoryROAccess& repository,
23+
const QueryCaches& query_caches)
2124
: timestamp_query_{
2225
repository,
2326
[](const SnapshotBundle& bundle) { return bundle.history(segment_names.front()).inverted_index; },
24-
[&]() { return repository.inverted_index_seek_cache(segment_names.front()); },
27+
query_caches.cache<InvertedIndexSeekQueryRawWithCache::CacheType>(InvertedIndexSeekQueryRawWithCache::kName, segment_names.front()).get(),
2528
},
2629
value_query_{repository} {}
2730

0 commit comments

Comments
 (0)