Skip to content

Commit

Permalink
DomainPutQuery
Browse files Browse the repository at this point in the history
  • Loading branch information
battlmonstr committed Dec 24, 2024
1 parent 89996a6 commit 927719b
Show file tree
Hide file tree
Showing 19 changed files with 551 additions and 16 deletions.
29 changes: 29 additions & 0 deletions silkworm/db/datastore/kvdb/big_endian_codec.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
Copyright 2024 The Silkworm Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "big_endian_codec.hpp"

#include <silkworm/core/common/endian.hpp>

namespace silkworm::datastore::kvdb {

Slice BigEndianU64Encoder::encode() {
data.resize(sizeof(uint64_t), 0);
endian::store_big_u64(data.data(), value);
return to_slice(data);
}

} // namespace silkworm::datastore::kvdb
33 changes: 33 additions & 0 deletions silkworm/db/datastore/kvdb/big_endian_codec.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
Copyright 2024 The Silkworm Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#pragma once

#include "codec.hpp"

namespace silkworm::datastore::kvdb {

struct BigEndianU64Encoder : public Encoder {
uint64_t value{0};
Bytes data;

~BigEndianU64Encoder() override = default;
Slice encode() override;
};

static_assert(EncoderConcept<BigEndianU64Encoder>);

} // namespace silkworm::datastore::kvdb
43 changes: 43 additions & 0 deletions silkworm/db/datastore/kvdb/codec.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
Copyright 2024 The Silkworm Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#pragma once

#include "mdbx.hpp"

namespace silkworm::datastore::kvdb {

struct Encoder {
virtual ~Encoder() = default;
virtual Slice encode() = 0;
};

template <class TEncoder>
concept EncoderConcept =
std::derived_from<TEncoder, Encoder> &&
requires(TEncoder encoder) { encoder.value; };

struct Decoder {
virtual ~Decoder() = default;
virtual void decode(Slice data) = 0;
};

template <class TDecoder>
concept DecoderConcept =
std::derived_from<TDecoder, Decoder> &&
requires(TDecoder decoder) { decoder.value; };

} // namespace silkworm::datastore::kvdb
69 changes: 69 additions & 0 deletions silkworm/db/datastore/kvdb/domain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@

#include <optional>

#include "../common/step.hpp"
#include "big_endian_codec.hpp"
#include "codec.hpp"
#include "history.hpp"
#include "kvts_codec.hpp"
#include "mdbx.hpp"

namespace silkworm::datastore::kvdb {
Expand All @@ -29,4 +33,69 @@ struct Domain {
std::optional<History> history;
};

struct InvertedStepEncoder : public Encoder {
Step value{0};
BigEndianU64Encoder encoder;

~InvertedStepEncoder() override = default;

Slice encode() override {
encoder.value = ~value.value;
return encoder.encode();
}
};

static_assert(EncoderConcept<InvertedStepEncoder>);

template <EncoderConcept TEncoder>
using DomainKeyEncoder = KVTSKeyEncoder<TEncoder, InvertedStepEncoder>;

template <EncoderConcept TEncoder>
using DomainValueEncoder = KVTSValueEncoder<TEncoder, InvertedStepEncoder>;

template <EncoderConcept TKeyEncoder, EncoderConcept TValueEncoder>
struct DomainPutValueQuery {
RWTxn& tx;
Domain entity;

using TKey = decltype(TKeyEncoder::value);
using TValue = decltype(TValueEncoder::value);

void exec(const TKey& key, const TValue& value, Step step) {
DomainKeyEncoder<TKeyEncoder> key_encoder{entity.has_large_values};
key_encoder.value.key.value = key;
key_encoder.value.timestamp.value = step;

DomainValueEncoder<TValueEncoder> value_encoder{entity.has_large_values};
value_encoder.value.value.value = value;
value_encoder.value.timestamp.value = step;

tx.rw_cursor(entity.values_table)->upsert(key_encoder.encode(), value_encoder.encode());
}
};

template <EncoderConcept TKeyEncoder, EncoderConcept TValueEncoder>
struct DomainPutQuery {
RWTxn& tx;
Domain entity;

using TKey = decltype(TKeyEncoder::value);
using TValue = decltype(TValueEncoder::value);

void exec(
const TKey& key,
const TValue& value,
Timestamp timestamp,
const std::optional<TValue>& prev_value,
Step prev_step) {
DomainPutValueQuery<TKeyEncoder, TValueEncoder> value_query{tx, entity};
value_query.exec(key, value, prev_step);

if (entity.history && prev_value) {
HistoryPutQuery<TKeyEncoder, TValueEncoder> history_query{tx, *entity.history};
history_query.exec(key, *prev_value, timestamp);
}
}
};

} // namespace silkworm::datastore::kvdb
31 changes: 31 additions & 0 deletions silkworm/db/datastore/kvdb/history.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#pragma once

#include "inverted_index.hpp"
#include "kvts_codec.hpp"
#include "mdbx.hpp"

namespace silkworm::datastore::kvdb {
Expand All @@ -27,4 +28,34 @@ struct History {
InvertedIndex inverted_index;
};

template <EncoderConcept TEncoder>
using HistoryKeyEncoder = KVTSKeyEncoder<TEncoder, TimestampEncoder>;

template <EncoderConcept TEncoder>
using HistoryValueEncoder = KVTSValueEncoder<TEncoder, TimestampEncoder>;

template <EncoderConcept TKeyEncoder, EncoderConcept TValueEncoder>
struct HistoryPutQuery {
RWTxn& tx;
History entity;

using TKey = decltype(TKeyEncoder::value);
using TValue = decltype(TValueEncoder::value);

void exec(const TKey& key, const TValue& value, Timestamp timestamp) {
HistoryKeyEncoder<TKeyEncoder> key_encoder{entity.has_large_values};
key_encoder.value.key.value = key;
key_encoder.value.timestamp.value = timestamp;

HistoryValueEncoder<TValueEncoder> value_encoder{entity.has_large_values};
value_encoder.value.value.value = value;
value_encoder.value.timestamp.value = timestamp;

tx.rw_cursor(entity.values_table)->upsert(key_encoder.encode(), value_encoder.encode());

InvertedIndexPutQuery<TKeyEncoder> inverted_index_query{tx, entity.inverted_index};
inverted_index_query.exec(key, timestamp, false);
}
};

} // namespace silkworm::datastore::kvdb
33 changes: 33 additions & 0 deletions silkworm/db/datastore/kvdb/inverted_index.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

#pragma once

#include "../common/timestamp.hpp"
#include "big_endian_codec.hpp"
#include "codec.hpp"
#include "mdbx.hpp"

namespace silkworm::datastore::kvdb {
Expand All @@ -25,4 +28,34 @@ struct InvertedIndex {
const MapConfig& index_table;
};

using TimestampEncoder = BigEndianU64Encoder;

template <EncoderConcept TKeyEncoder>
struct InvertedIndexPutQuery {
RWTxn& tx;
InvertedIndex entity;

using TKey = decltype(TKeyEncoder::value);

void exec(const TKey& key, const Timestamp timestamp, bool with_index_update) {
return exec<TimestampEncoder>(key, timestamp, with_index_update);
}

template <EncoderConcept TTimestampEncoder, typename TTimestamp = decltype(TTimestampEncoder::value)>
void exec(const TKey& key, const TTimestamp& timestamp, bool with_index_update) {
TKeyEncoder key_encoder;
key_encoder.value = key;
Slice key_slice = key_encoder.encode();

TTimestampEncoder ts_encoder;
ts_encoder.value = timestamp;
Slice ts_slice = ts_encoder.encode();

tx.rw_cursor(entity.keys_table)->upsert(ts_slice, key_slice);
if (with_index_update) {
tx.rw_cursor(entity.index_table)->upsert(key_slice, ts_slice);
}
}
};

} // namespace silkworm::datastore::kvdb
85 changes: 85 additions & 0 deletions silkworm/db/datastore/kvdb/kvts_codec.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
Copyright 2024 The Silkworm Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#pragma once

#include "codec.hpp"
#include "raw_codec.hpp"

namespace silkworm::datastore::kvdb {

template <EncoderConcept TEncoder, EncoderConcept TTimestampEncoder>
class KVTSKeyEncoder : public Encoder {
public:
struct {
TEncoder key;
TTimestampEncoder timestamp;
} value;

explicit KVTSKeyEncoder(bool has_large_values)
: has_large_values_{has_large_values} {}
~KVTSKeyEncoder() override = default;

Slice encode() override {
data_.clear();
if (has_large_values_) {
// encode as key + timestamp
data_.append(from_slice(value.key.encode()));
data_.append(from_slice(value.timestamp.encode()));
return to_slice(data_);
} else {
return value.key.encode();
}
}

private:
bool has_large_values_;
Bytes data_;
};

template <EncoderConcept TEncoder, EncoderConcept TTimestampEncoder>
class KVTSValueEncoder : public Encoder {
public:
struct {
TEncoder value;
TTimestampEncoder timestamp;
} value;

explicit KVTSValueEncoder(bool has_large_values)
: has_large_values_{has_large_values} {}
~KVTSValueEncoder() override = default;

Slice encode() override {
data_.clear();
if (has_large_values_) {
return value.value.encode();
} else {
// encode as timestamp + value
data_.append(from_slice(value.timestamp.encode()));
data_.append(from_slice(value.value.encode()));
return to_slice(data_);
}
}

private:
bool has_large_values_;
Bytes data_;
};

static_assert(EncoderConcept<KVTSKeyEncoder<RawEncoder<Bytes>, RawEncoder<Bytes>>>);
static_assert(EncoderConcept<KVTSValueEncoder<RawEncoder<Bytes>, RawEncoder<Bytes>>>);

} // namespace silkworm::datastore::kvdb
Loading

0 comments on commit 927719b

Please sign in to comment.