Skip to content

Commit

Permalink
db: BodySnapshotFreezer use sequential txn_id without gaps (#2215)
Browse files Browse the repository at this point in the history
  • Loading branch information
battlmonstr authored Aug 10, 2024
1 parent 2d57336 commit 112ced3
Show file tree
Hide file tree
Showing 12 changed files with 82 additions and 26 deletions.
11 changes: 8 additions & 3 deletions silkworm/db/access_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1320,16 +1320,21 @@ std::optional<BlockHeader> DataModel::read_header_from_snapshot(const Hash& hash
return block_header;
}

bool DataModel::read_body_from_snapshot(BlockNum height, BlockBody& body) {
std::optional<BlockBodyForStorage> DataModel::read_body_for_storage_from_snapshot(BlockNum height) {
if (!repository_) {
return false;
return std::nullopt;
}

// We know the body snapshot in advance: find it based on target block number
const auto snapshot_and_index = repository_->find_segment(SnapshotType::bodies, height);
if (!snapshot_and_index) return false;
if (!snapshot_and_index) return std::nullopt;

auto stored_body = BodyFindByBlockNumQuery{*snapshot_and_index}.exec(height);
return stored_body;
}

bool DataModel::read_body_from_snapshot(BlockNum height, BlockBody& body) {
auto stored_body = read_body_for_storage_from_snapshot(height);
if (!stored_body) return false;

// Skip first and last *system transactions* in block body
Expand Down
3 changes: 3 additions & 0 deletions silkworm/db/access_layer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,9 @@ class DataModel {
[[nodiscard]] bool read_body(const Hash& hash, BlockNum height, BlockBody& body) const;
[[nodiscard]] bool read_body(const Hash& hash, BlockBody& body) const;

//! Read block body for storage from the snapshot repository
[[nodiscard]] static std::optional<BlockBodyForStorage> read_body_for_storage_from_snapshot(BlockNum height);

//! Read the canonical block header at specified height
[[nodiscard]] std::optional<Hash> read_canonical_hash(BlockNum height) const;

Expand Down
11 changes: 9 additions & 2 deletions silkworm/db/bodies/body_snapshot_freezer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,20 @@

namespace silkworm::db {

void BodySnapshotFreezer::copy(ROTxn& txn, BlockNumRange range, snapshots::SnapshotFileWriter& file_writer) const {
void BodySnapshotFreezer::copy(ROTxn& txn, const FreezerCommand& command, snapshots::SnapshotFileWriter& file_writer) const {
BlockNumRange range = command.range;
uint64_t base_txn_id = command.base_txn_id;

snapshots::BodySnapshotWriter writer{file_writer};
auto out = writer.out();
for (BlockNum i = range.first; i < range.second; i++) {
auto value_opt = read_canonical_body_for_storage(txn, i);
if (!value_opt) throw std::runtime_error{"BodySnapshotFreezer::copy missing body for block " + std::to_string(i)};
*out++ = *value_opt;
BlockBodyForStorage& value = *value_opt;
// remap to sequential values without gaps (see txnum.go)
value.base_txn_id = base_txn_id;
base_txn_id += value.txn_count;
*out++ = value;
}
}

Expand Down
2 changes: 1 addition & 1 deletion silkworm/db/bodies/body_snapshot_freezer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ namespace silkworm::db {
class BodySnapshotFreezer : public SnapshotFreezer {
public:
~BodySnapshotFreezer() override = default;
void copy(ROTxn& txn, BlockNumRange range, snapshots::SnapshotFileWriter& file_writer) const override;
void copy(ROTxn& txn, const FreezerCommand& command, snapshots::SnapshotFileWriter& file_writer) const override;
void cleanup(RWTxn& txn, BlockNumRange range) const override;
};

Expand Down
8 changes: 3 additions & 5 deletions silkworm/db/data_migration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,9 @@

#include <memory>

namespace silkworm::db {
#include "data_migration_command.hpp"

struct DataMigrationCommand {
virtual ~DataMigrationCommand() = default;
};
namespace silkworm::db {

struct DataMigrationResult {
virtual ~DataMigrationResult() = default;
Expand All @@ -34,7 +32,7 @@ struct DataMigration {
void run();

protected:
virtual std::unique_ptr<DataMigrationCommand> next_command();
virtual std::unique_ptr<DataMigrationCommand> next_command() = 0;
virtual std::shared_ptr<DataMigrationResult> migrate(std::unique_ptr<DataMigrationCommand> command) = 0;
virtual void index(std::shared_ptr<DataMigrationResult> result) = 0;
virtual void commit(std::shared_ptr<DataMigrationResult> result) = 0;
Expand Down
25 changes: 25 additions & 0 deletions silkworm/db/data_migration_command.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
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

namespace silkworm::db {

struct DataMigrationCommand {
virtual ~DataMigrationCommand() = default;
};

} // namespace silkworm::db
25 changes: 15 additions & 10 deletions silkworm/db/freezer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,6 @@ namespace silkworm::db {

using namespace silkworm::snapshots;

struct FreezerCommand : public DataMigrationCommand {
BlockNumRange range;

explicit FreezerCommand(BlockNumRange range1)
: range(std::move(range1)) {}
~FreezerCommand() override = default;
};

struct FreezerResult : public DataMigrationResult {
SnapshotBundle bundle;

Expand All @@ -63,6 +55,12 @@ static BlockNum get_first_stored_header_num(ROTxn& txn) {
return num_opt.value_or(0);
}

static std::optional<uint64_t> get_next_base_txn_id(BlockNum number) {
auto body = DataModel::read_body_for_storage_from_snapshot(number);
if (!body) return std::nullopt;
return body->base_txn_id + body->txn_count;
}

std::unique_ptr<DataMigrationCommand> Freezer::next_command() {
BlockNum last_frozen = snapshots_.max_block_available();
BlockNum start = (last_frozen > 0) ? last_frozen + 1 : 0;
Expand All @@ -73,8 +71,15 @@ std::unique_ptr<DataMigrationCommand> Freezer::next_command() {
return get_tip_num(db_tx);
}();

uint64_t base_txn_id = [last_frozen]() -> uint64_t {
if (last_frozen == 0) return 0;
auto id = get_next_base_txn_id(last_frozen);
assert(id.has_value());
return *id;
}();

if (end + kFullImmutabilityThreshold <= tip) {
return std::make_unique<FreezerCommand>(FreezerCommand{{start, end}});
return std::make_unique<FreezerCommand>(FreezerCommand{{start, end}, base_txn_id});
}
return {};
}
Expand Down Expand Up @@ -108,7 +113,7 @@ std::shared_ptr<DataMigrationResult> Freezer::migrate(std::unique_ptr<DataMigrat
{
auto db_tx = db_access_.start_ro_tx();
auto& freezer = get_snapshot_freezer(path.type());
freezer.copy(db_tx, range, file_writer);
freezer.copy(db_tx, freezer_command, file_writer);
}
SnapshotFileWriter::flush(std::move(file_writer));
}
Expand Down
3 changes: 2 additions & 1 deletion silkworm/db/headers/header_snapshot_freezer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@

namespace silkworm::db {

void HeaderSnapshotFreezer::copy(ROTxn& txn, BlockNumRange range, snapshots::SnapshotFileWriter& file_writer) const {
void HeaderSnapshotFreezer::copy(ROTxn& txn, const FreezerCommand& command, snapshots::SnapshotFileWriter& file_writer) const {
BlockNumRange range = command.range;
snapshots::HeaderSnapshotWriter writer{file_writer};
auto out = writer.out();
for (BlockNum i = range.first; i < range.second; i++) {
Expand Down
2 changes: 1 addition & 1 deletion silkworm/db/headers/header_snapshot_freezer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ namespace silkworm::db {
class HeaderSnapshotFreezer : public SnapshotFreezer {
public:
~HeaderSnapshotFreezer() override = default;
void copy(ROTxn& txn, BlockNumRange range, snapshots::SnapshotFileWriter& file_writer) const override;
void copy(ROTxn& txn, const FreezerCommand& command, snapshots::SnapshotFileWriter& file_writer) const override;
void cleanup(RWTxn& txn, BlockNumRange range) const override;
};

Expand Down
13 changes: 12 additions & 1 deletion silkworm/db/snapshot_freezer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,27 @@

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

#include "data_migration_command.hpp"
#include "mdbx/mdbx.hpp"
#include "snapshots/snapshot_writer.hpp"

namespace silkworm::db {

struct FreezerCommand : public DataMigrationCommand {
BlockNumRange range;
uint64_t base_txn_id;

FreezerCommand(BlockNumRange range1, uint64_t base_txn_id1)
: range(std::move(range1)),
base_txn_id(base_txn_id1) {}
~FreezerCommand() override = default;
};

struct SnapshotFreezer {
virtual ~SnapshotFreezer() = default;

//! Copies data for a block range from db to the snapshot file.
virtual void copy(ROTxn& txn, BlockNumRange range, snapshots::SnapshotFileWriter& file_writer) const = 0;
virtual void copy(ROTxn& txn, const FreezerCommand& command, snapshots::SnapshotFileWriter& file_writer) const = 0;

//! Cleans up data for a block range from db after it was copied to the snapshot file.
virtual void cleanup(RWTxn& txn, BlockNumRange range) const = 0;
Expand Down
3 changes: 2 additions & 1 deletion silkworm/db/transactions/txn_snapshot_freezer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@

namespace silkworm::db {

void TransactionSnapshotFreezer::copy(ROTxn& txn, BlockNumRange range, snapshots::SnapshotFileWriter& file_writer) const {
void TransactionSnapshotFreezer::copy(ROTxn& txn, const FreezerCommand& command, snapshots::SnapshotFileWriter& file_writer) const {
BlockNumRange range = command.range;
snapshots::TransactionSnapshotWriter writer{file_writer};
auto out = writer.out();
auto system_tx = snapshots::empty_system_tx();
Expand Down
2 changes: 1 addition & 1 deletion silkworm/db/transactions/txn_snapshot_freezer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ namespace silkworm::db {
class TransactionSnapshotFreezer : public SnapshotFreezer {
public:
~TransactionSnapshotFreezer() override = default;
void copy(ROTxn& txn, BlockNumRange range, snapshots::SnapshotFileWriter& file_writer) const override;
void copy(ROTxn& txn, const FreezerCommand& command, snapshots::SnapshotFileWriter& file_writer) const override;
void cleanup(RWTxn& txn, BlockNumRange range) const override;
};

Expand Down

0 comments on commit 112ced3

Please sign in to comment.