Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
Merge pull request #7401 from EOSIO/feature/state_database_versioning
Browse files Browse the repository at this point in the history
state database versioning
  • Loading branch information
b1bart authored May 28, 2019
2 parents 7de4582 + 3898c22 commit 0ca3ad4
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 1 deletion.
47 changes: 46 additions & 1 deletion libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <eosio/chain/reversible_block_object.hpp>
#include <eosio/chain/genesis_intrinsics.hpp>
#include <eosio/chain/whitelisted_intrinsics.hpp>
#include <eosio/chain/database_header_object.hpp>

#include <eosio/chain/protocol_feature_manager.hpp>
#include <eosio/chain/authorization_manager.hpp>
Expand Down Expand Up @@ -45,7 +46,8 @@ using controller_index_set = index_set<
transaction_multi_index,
generated_transaction_multi_index,
table_id_multi_index,
code_index
code_index,
database_header_multi_index
>;

using contract_database_index_set = index_set<
Expand Down Expand Up @@ -578,6 +580,31 @@ struct controller_impl {
head = fork_db.head();
}
}

// check database version
const auto& header_idx = db.get_index<database_header_multi_index>().indices().get<by_id>();

if (database_header_object::minimum_version != 0) {
EOS_ASSERT(header_idx.begin() != header_idx.end(), bad_database_version_exception,
"state database version pre-dates versioning, please restore from a compatible snapshot or replay!");
} else if ( header_idx.empty() ) {
// temporary code to upgrade from existing un-versioned state database
static_assert(database_header_object::minimum_version == 0, "remove this path once the minimum version moves");
db.create<database_header_object>([](const auto& header){
// nothing to do here
});
}

const auto& header_itr = header_idx.begin();
header_itr->validate();

// upgrade to the latest compatible version
if (header_itr->version != database_header_object::current_version) {
db.modify(*header_itr, [](auto& header) {
header.version = database_header_object::current_version;
});
}

// At this point head != nullptr && fork_db.head() != nullptr && fork_db.root() != nullptr.
// Furthermore, fork_db.root()->block_num <= lib_num.
// Also, even though blog.head() may still be nullptr, blog.first_block_num() is guaranteed to be lib_num + 1.
Expand Down Expand Up @@ -788,6 +815,11 @@ struct controller_impl {
return;
}

// skip the database_header as it is only relevant to in-memory database
if (std::is_same<value_t, database_header_object>::value) {
return;
}

snapshot->write_section<value_t>([this]( auto& section ){
decltype(utils)::walk(db, [this, &section]( const auto &row ) {
section.add_row(row, db);
Expand Down Expand Up @@ -835,6 +867,11 @@ struct controller_impl {
return;
}

// skip the database_header as it is only relevant to in-memory database
if (std::is_same<value_t, database_header_object>::value) {
return;
}

snapshot->read_section<value_t>([this]( auto& section ) {
bool more = !section.empty();
while(more) {
Expand All @@ -851,6 +888,9 @@ struct controller_impl {
resource_limits.read_from_snapshot(snapshot);

db.set_revision( head->block_num );
db.create<database_header_object>([](const auto& header){
// nothing to do
});
}

sha256 calculate_integrity_hash() const {
Expand Down Expand Up @@ -893,6 +933,11 @@ struct controller_impl {
}

void initialize_database() {
// create the database header sigil
db.create<database_header_object>([&]( auto& header ){
// nothing to do for now
});

// Initialize block summary index
for (int i = 0; i < 0x10000; i++)
db.create<block_summary_object>([&](block_summary_object&) {});
Expand Down
56 changes: 56 additions & 0 deletions libraries/chain/include/eosio/chain/database_header_object.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* @file
* @copyright defined in eos/LICENSE
*/
#pragma once
#include <eosio/chain/types.hpp>

#include "multi_index_includes.hpp"

namespace eosio { namespace chain {
/**
* @brief tracks the version of the application data stored in the database
* @ingroup object
*
* the in-memory database expects that binay structures of data do not shift between executions. Some
* upgrades will bump this version to indicate that the expectations of the binary application data
* have changed. When it is safe to directly use an older version that will be allowed though cases
* where this is possible may be rare.
*/
class database_header_object : public chainbase::object<database_header_object_type, database_header_object>
{
OBJECT_CTOR(database_header_object)

/**
* VERSION HISTORY
* - 0 : implied version when this header is absent
* - 1 : initial version, prior to this no `database_header_object` existed in the shared memory file but
* no changes to its format were made so it can be safely added to existing databases
*/

static constexpr uint32_t current_version = 1;
static constexpr uint32_t minimum_version = 0;

id_type id;
uint32_t version = current_version;

void validate() const {
EOS_ASSERT(std::clamp(version, minimum_version, current_version) == version, bad_database_version_exception,
"state database version is incompatible, please restore from a compatible snapshot or replay!",
("version", version)("minimum_version", minimum_version)("maximum_version", current_version));
}
};

struct by_block_id;
using database_header_multi_index = chainbase::shared_multi_index_container<
database_header_object,
indexed_by<
ordered_unique<tag<by_id>, BOOST_MULTI_INDEX_MEMBER(database_header_object, database_header_object::id_type, id)>
>
>;

} }

CHAINBASE_SET_INDEX_TYPE(eosio::chain::database_header_object, eosio::chain::database_header_multi_index)

FC_REFLECT( eosio::chain::database_header_object, (version) )
2 changes: 2 additions & 0 deletions libraries/chain/include/eosio/chain/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ namespace eosio { namespace chain {
3060003, "Contract Table Query Exception" )
FC_DECLARE_DERIVED_EXCEPTION( contract_query_exception, database_exception,
3060004, "Contract Query Exception" )
FC_DECLARE_DERIVED_EXCEPTION( bad_database_version_exception, database_exception,
3060005, "Database is an unknown or unsupported version" )

FC_DECLARE_DERIVED_EXCEPTION( guard_exception, database_exception,
3060100, "Guard Exception" )
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/include/eosio/chain/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ namespace eosio { namespace chain {
protocol_state_object_type,
account_ram_correction_object_type,
code_object_type,
database_header_object_type,
OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types
};

Expand Down

0 comments on commit 0ca3ad4

Please sign in to comment.