-
Notifications
You must be signed in to change notification settings - Fork 73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IF: Support load of fork database after instant-finality is enabled #2113
Changes from all commits
a0a3528
4f634cd
7ec302e
a0a5573
5cae9d9
1207522
23bee43
7a4b5d5
d31be4f
175af8f
e07d937
9310754
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,33 +11,35 @@ namespace eosio::chain { | |
struct fork_database_impl; | ||
|
||
/** | ||
* @class fork_database | ||
* @class fork_database_t | ||
* @brief manages light-weight state for all potential unconfirmed forks | ||
* | ||
* As new blocks are received, they are pushed into the fork database. The fork | ||
* database tracks the longest chain and the last irreversible block number. All | ||
* blocks older than the last irreversible block are freed after emitting the | ||
* irreversible signal. | ||
* | ||
* An internal mutex is used to provide thread-safety. | ||
* Not thread safe, thread safety provided by fork_database below. | ||
* fork_database should be used instead of fork_database_t directly as it manages | ||
* the different supported types. | ||
*/ | ||
template<class bsp> // either block_state_legacy_ptr or block_state_ptr | ||
class fork_database { | ||
class fork_database_t { | ||
public: | ||
static constexpr uint32_t legacy_magic_number = 0x30510FDB; | ||
static constexpr uint32_t magic_number = 0x4242FDB; | ||
linh2931 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
using bs = bsp::element_type; | ||
using bhsp = bs::bhsp_t; | ||
using bhs = bhsp::element_type; | ||
using bsp_t = bsp; | ||
using branch_type = deque<bsp>; | ||
using branch_type_pair = pair<branch_type, branch_type>; | ||
|
||
explicit fork_database( const std::filesystem::path& data_dir ); | ||
~fork_database(); | ||
|
||
std::filesystem::path get_data_dir() const; | ||
explicit fork_database_t(uint32_t magic_number = legacy_magic_number); | ||
|
||
void open( validator_t& validator ); | ||
void close(); | ||
void open( const std::filesystem::path& fork_db_file, validator_t& validator ); | ||
void close( const std::filesystem::path& fork_db_file ); | ||
|
||
bhsp get_block_header( const block_id_type& id ) const; | ||
bsp get_block( const block_id_type& id ) const; | ||
|
@@ -70,6 +72,9 @@ namespace eosio::chain { | |
bsp head() const; | ||
bsp pending_head() const; | ||
|
||
// only accessed by main thread, no mutex protection | ||
bsp chain_head; | ||
|
||
/** | ||
* Returns the sequence of block states resulting from trimming the branch from the | ||
* root block (exclusive) to the block with an id of `h` (inclusive) by removing any | ||
|
@@ -95,15 +100,98 @@ namespace eosio::chain { | |
|
||
void mark_valid( const bsp& h ); | ||
|
||
static const uint32_t magic_number; | ||
|
||
static const uint32_t min_supported_version; | ||
static const uint32_t max_supported_version; | ||
|
||
private: | ||
unique_ptr<fork_database_impl<bsp>> my; | ||
}; | ||
|
||
using fork_database_legacy = fork_database<block_state_legacy_ptr>; | ||
|
||
using fork_database_legacy_t = fork_database_t<block_state_legacy_ptr>; | ||
using fork_database_if_t = fork_database_t<block_state_ptr>; | ||
|
||
/** | ||
* Provides thread safety on fork_database_t and provide mechanism for opening the correct type | ||
* as well as switching from legacy (old dpos) to instant-finality. | ||
* | ||
* All methods assert until open() is closed. | ||
*/ | ||
class fork_database { | ||
mutable std::recursive_mutex m; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not a fan of recursive mutexes. However, currently controller uses nested calls of |
||
const std::filesystem::path data_dir; | ||
std::variant<fork_database_t<block_state_legacy_ptr>, fork_database_t<block_state_ptr>> vforkdb; | ||
public: | ||
explicit fork_database(const std::filesystem::path& data_dir); | ||
~fork_database(); // close on destruction | ||
|
||
void open( validator_t& validator ); | ||
void close(); | ||
|
||
void switch_from_legacy(); | ||
|
||
// see fork_database_t::fetch_branch(forkdb->head()->id()) | ||
std::vector<signed_block_ptr> fetch_branch_from_head(); | ||
|
||
template <class R, class F> | ||
R apply(const F& f) { | ||
std::lock_guard g(m); | ||
if constexpr (std::is_same_v<void, R>) | ||
std::visit([&](auto& forkdb) { f(forkdb); }, vforkdb); | ||
else | ||
return std::visit([&](auto& forkdb) -> R { return f(forkdb); }, vforkdb); | ||
} | ||
|
||
template <class R, class F> | ||
R apply(const F& f) const { | ||
std::lock_guard g(m); | ||
if constexpr (std::is_same_v<void, R>) | ||
std::visit([&](const auto& forkdb) { f(forkdb); }, vforkdb); | ||
else | ||
return std::visit([&](const auto& forkdb) -> R { return f(forkdb); }, vforkdb); | ||
} | ||
|
||
/// Apply for when only need lambda executed when in instant-finality mode | ||
template <class R, class F> | ||
R apply_if(const F& f) { | ||
std::lock_guard g(m); | ||
if constexpr (std::is_same_v<void, R>) | ||
std::visit(overloaded{[&](fork_database_legacy_t&) {}, | ||
[&](fork_database_if_t& forkdb) { f(forkdb); }}, | ||
vforkdb); | ||
else | ||
return std::visit(overloaded{[&](fork_database_legacy_t&) -> R { return {}; }, | ||
[&](fork_database_if_t& forkdb) -> R { return f(forkdb); }}, | ||
vforkdb); | ||
} | ||
|
||
/// Apply for when only need lambda executed when in legacy mode | ||
template <class R, class F> | ||
R apply_legacy(const F& f) { | ||
std::lock_guard g(m); | ||
if constexpr (std::is_same_v<void, R>) | ||
std::visit(overloaded{[&](fork_database_legacy_t& forkdb) { f(forkdb); }, | ||
[&](fork_database_if_t&) {}}, | ||
vforkdb); | ||
else | ||
return std::visit(overloaded{[&](fork_database_legacy_t& forkdb) -> R { return f(forkdb); }, | ||
[&](fork_database_if_t&) -> R { return {}; }}, | ||
vforkdb); | ||
} | ||
|
||
/// @param legacy_f the lambda to execute if in legacy mode | ||
/// @param if_f the lambda to execute if in instant-finality mode | ||
template <class R, class LegacyF, class IfF> | ||
R apply(const LegacyF& legacy_f, const IfF& if_f) { | ||
std::lock_guard g(m); | ||
if constexpr (std::is_same_v<void, R>) | ||
std::visit(overloaded{[&](fork_database_legacy_t& forkdb) { legacy_f(forkdb); }, | ||
[&](fork_database_if_t& forkdb) { if_f(forkdb); }}, | ||
vforkdb); | ||
else | ||
return std::visit(overloaded{[&](fork_database_legacy_t& forkdb) -> R { return legacy_f(forkdb); }, | ||
[&](fork_database_if_t& forkdb) -> R { return if_f(forkdb); }}, | ||
vforkdb); | ||
} | ||
|
||
// if we ever support more than one version then need to save min/max in fork_database_t | ||
static constexpr uint32_t min_supported_version = 1; | ||
static constexpr uint32_t max_supported_version = 1; | ||
}; | ||
} /// eosio::chain |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now it occurs to me, if we already have an issue, we don't need a warning, because the issue will remind us.