This repository has been archived by the owner on Aug 2, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Add support for block log splitting #9184
Merged
Merged
Changes from 10 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
e9cfda6
Add support for block log splitting
huangminghuang 3ac568f
Merge branch 'develop' into block-log-split
huangminghuang efec3c7
bug fixes and PR comments
huangminghuang 34c81d3
rename blocks-split-factor to blocks-log-stride
huangminghuang f9937b6
allows log file version upgrade after spliting
huangminghuang dce3cc3
more stride rename
huangminghuang 0745026
add support to recover from incomplete block head automatically
huangminghuang dd10241
fix bug and modify restart chain test with block num with 3 digits.
huangminghuang 68ec5ae
Merge branch 'develop' into block-log-split
huangminghuang ebf48b0
add test to split from v1 log
huangminghuang 00eb6c9
use RAII to set blocklog version in unittests
huangminghuang d15e3b5
remove unneeded code
huangminghuang d2f8e5b
add comment to address PR concern
huangminghuang 0ebb3fd
added tests for different max_retained_block_files configuration
huangminghuang 5fb2af4
handle retained block log with overlapping ranges
huangminghuang b069f54
add assertion to protect against bad memory access
huangminghuang 3063759
Address more PR comments
huangminghuang e2dd458
extend block-log-auto-fix to recovery from corrupted index file
huangminghuang a674825
change command line option description
huangminghuang ee3a733
more command line description change
huangminghuang c158c7b
Some more PR comments fix
huangminghuang 3207d7d
rename allow_block_log_auto_fix to fix_irreversible_blocks
huangminghuang File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -150,7 +150,6 @@ class chain_plugin_impl { | |
|
||
|
||
fc::optional<fork_database> fork_db; | ||
fc::optional<block_log> block_logger; | ||
fc::optional<controller::config> chain_config; | ||
fc::optional<controller> chain; | ||
fc::optional<genesis_state> genesis; | ||
|
@@ -228,6 +227,14 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip | |
cfg.add_options() | ||
("blocks-dir", bpo::value<bfs::path>()->default_value("blocks"), | ||
"the location of the blocks directory (absolute path or relative to application data dir)") | ||
("blocks-log-stride", bpo::value<uint32_t>()->default_value(config::default_blocks_log_stride), | ||
"split the block log file when the head block number is the multiple of the split factor") | ||
("max-retained-block-files", bpo::value<uint16_t>()->default_value(config::default_max_retained_block_files), | ||
"the maximum number of blocks files to retain so that the blocks in those files can be queried.\n" | ||
"When the number is reached, the oldest block file would be move to archive dir or deleted if the archive dir is empty." ) | ||
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. Make this match the documentation in the PR. |
||
("blocks-archive-dir", bpo::value<bfs::path>()->default_value(config::default_blocks_archive_dir_name), | ||
"the location of the blocks archive directory (absolute path or relative to blocks dir).\n" | ||
"If the value is empty, blocks files beyond the retained limit will be deleted.") | ||
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. Make this match the documentation in the PR. |
||
("protocol-features-dir", bpo::value<bfs::path>()->default_value("protocol_features"), | ||
"the location of the protocol_features directory (absolute path or relative to application config dir)") | ||
("checkpoint", bpo::value<vector<string>>()->composing(), "Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints.") | ||
|
@@ -742,6 +749,9 @@ void chain_plugin::plugin_initialize(const variables_map& options) { | |
my->chain_config->blocks_dir = my->blocks_dir; | ||
my->chain_config->state_dir = app().data_dir() / config::default_state_dir_name; | ||
my->chain_config->read_only = my->readonly; | ||
my->chain_config->blocks_archive_dir = options.at("blocks-archive-dir").as<bfs::path>(); | ||
my->chain_config->blocks_log_stride = options.at("blocks-log-stride").as<uint32_t>(); | ||
my->chain_config->max_retained_block_files = options.at("max-retained-block-files").as<uint16_t>(); | ||
|
||
if (auto resmon_plugin = app().find_plugin<resource_monitor_plugin>()) { | ||
resmon_plugin->monitor_directory(my->chain_config->blocks_dir); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ | |
#include <contracts.hpp> | ||
#include <snapshots.hpp> | ||
#include <boost/iostreams/device/mapped_file.hpp> | ||
#include <fc/io/cfile.hpp> | ||
#include "test_cfd_transaction.hpp" | ||
|
||
using namespace eosio; | ||
|
@@ -235,8 +236,162 @@ BOOST_FIXTURE_TEST_CASE(test_light_validation_restart_from_block_log_with_pruned | |
BOOST_REQUIRE_NO_THROW(block_log::repair_log(blocks_dir)); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE(test_split_log) { | ||
namespace bfs = boost::filesystem; | ||
fc::temp_directory temp_dir; | ||
|
||
tester chain( | ||
temp_dir, | ||
[](controller::config& config) { | ||
config.blocks_log_stride = 20; | ||
config.max_retained_block_files = 5; | ||
}, | ||
true); | ||
chain.produce_blocks(150); | ||
|
||
auto blocks_dir = chain.get_config().blocks_dir; | ||
auto blocks_archive_dir = chain.get_config().blocks_dir / chain.get_config().blocks_archive_dir; | ||
|
||
BOOST_CHECK(bfs::exists( blocks_archive_dir / "blocks-1-20.log" )); | ||
BOOST_CHECK(bfs::exists( blocks_archive_dir / "blocks-1-20.index" )); | ||
BOOST_CHECK(bfs::exists( blocks_archive_dir / "blocks-21-40.log" )); | ||
BOOST_CHECK(bfs::exists( blocks_archive_dir / "blocks-21-40.index" )); | ||
|
||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-41-60.log" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-41-60.index" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-61-80.log" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-61-80.index" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-81-100.log" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-81-100.index" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-101-120.log" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-101-120.index" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-121-140.log" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-121-140.index" )); | ||
|
||
BOOST_CHECK( ! chain.control->fetch_block_by_number(40) ); | ||
|
||
BOOST_CHECK( chain.control->fetch_block_by_number(81)->block_num() == 81 ); | ||
BOOST_CHECK( chain.control->fetch_block_by_number(90)->block_num() == 90 ); | ||
BOOST_CHECK( chain.control->fetch_block_by_number(100)->block_num() == 100 ); | ||
|
||
BOOST_CHECK( chain.control->fetch_block_by_number(41)->block_num() == 41 ); | ||
BOOST_CHECK( chain.control->fetch_block_by_number(50)->block_num() == 50 ); | ||
BOOST_CHECK( chain.control->fetch_block_by_number(60)->block_num() == 60 ); | ||
|
||
BOOST_CHECK( chain.control->fetch_block_by_number(121)->block_num() == 121 ); | ||
BOOST_CHECK( chain.control->fetch_block_by_number(130)->block_num() == 130 ); | ||
BOOST_CHECK( chain.control->fetch_block_by_number(140)->block_num() == 140 ); | ||
|
||
BOOST_CHECK( chain.control->fetch_block_by_number(145)->block_num() == 145); | ||
|
||
BOOST_CHECK( ! chain.control->fetch_block_by_number(160)); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE(test_split_log_no_archive) { | ||
|
||
namespace bfs = boost::filesystem; | ||
fc::temp_directory temp_dir; | ||
|
||
tester chain( | ||
temp_dir, | ||
[](controller::config& config) { | ||
config.blocks_archive_dir = ""; | ||
config.blocks_log_stride = 10; | ||
config.max_retained_block_files = 5; | ||
}, | ||
true); | ||
chain.produce_blocks(75); | ||
|
||
auto blocks_dir = chain.get_config().blocks_dir; | ||
auto blocks_archive_dir = chain.get_config().blocks_dir / chain.get_config().blocks_archive_dir; | ||
|
||
BOOST_CHECK(!bfs::exists( blocks_archive_dir / "blocks-1-10.log" )); | ||
BOOST_CHECK(!bfs::exists( blocks_archive_dir / "blocks-1-10.index" )); | ||
BOOST_CHECK(!bfs::exists( blocks_archive_dir / "blocks-11-20.log" )); | ||
BOOST_CHECK(!bfs::exists( blocks_archive_dir / "blocks-11-20.index" )); | ||
BOOST_CHECK(!bfs::exists( blocks_dir / "blocks-1-10.log" )); | ||
BOOST_CHECK(!bfs::exists( blocks_dir / "blocks-1-10.index" )); | ||
BOOST_CHECK(!bfs::exists( blocks_dir / "blocks-11-20.log" )); | ||
BOOST_CHECK(!bfs::exists( blocks_dir / "blocks-11-20.index" )); | ||
|
||
b1bart marked this conversation as resolved.
Show resolved
Hide resolved
|
||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-21-30.log" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-21-30.index" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-31-40.log" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-31-40.index" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-41-50.log" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-41-50.index" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-51-60.log" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-51-60.index" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-61-70.log" )); | ||
BOOST_CHECK(bfs::exists( blocks_dir / "blocks-61-70.index" )); | ||
|
||
BOOST_CHECK( ! chain.control->fetch_block_by_number(10)); | ||
BOOST_CHECK( chain.control->fetch_block_by_number(70)); | ||
BOOST_CHECK( ! chain.control->fetch_block_by_number(80)); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE(test_split_log_replay) { | ||
|
||
namespace bfs = boost::filesystem; | ||
fc::temp_directory temp_dir; | ||
|
||
tester chain( | ||
temp_dir, | ||
[](controller::config& config) { | ||
config.blocks_log_stride = 20; | ||
config.max_retained_block_files = 10; | ||
}, | ||
true); | ||
chain.produce_blocks(150); | ||
|
||
controller::config copied_config = chain.get_config(); | ||
auto genesis = chain::block_log::extract_genesis_state(chain.get_config().blocks_dir); | ||
BOOST_REQUIRE(genesis); | ||
|
||
chain.close(); | ||
|
||
void trim_blocklog_front() { | ||
// remove the state files to make sure we are starting from block log | ||
remove_existing_states(copied_config); | ||
tester from_block_log_chain(copied_config, *genesis); | ||
BOOST_CHECK( from_block_log_chain.control->fetch_block_by_number(1)->block_num() == 1); | ||
BOOST_CHECK( from_block_log_chain.control->fetch_block_by_number(75)->block_num() == 75); | ||
BOOST_CHECK( from_block_log_chain.control->fetch_block_by_number(100)->block_num() == 100); | ||
BOOST_CHECK( from_block_log_chain.control->fetch_block_by_number(150)->block_num() == 150); | ||
} | ||
|
||
BOOST_FIXTURE_TEST_CASE(restart_from_block_log_with_incomplete_head,restart_from_block_log_test_fixture) { | ||
auto& config = chain.get_config(); | ||
auto blocks_path = config.blocks_dir; | ||
// write a few random bytes to block log indicating the last block entry is incomplete | ||
fc::cfile logfile; | ||
logfile.set_file_path(config.blocks_dir / "blocks.log"); | ||
logfile.open("ab"); | ||
const char random_data[] = "12345678901231876983271649837"; | ||
logfile.write(random_data, sizeof(random_data)); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE(test_split_from_v1_log) { | ||
namespace bfs = boost::filesystem; | ||
fc::temp_directory temp_dir; | ||
block_log::set_version(1); | ||
tester chain( | ||
temp_dir, | ||
[](controller::config& config) { | ||
config.blocks_log_stride = 20; | ||
config.max_retained_block_files = 5; | ||
}, | ||
true); | ||
chain.produce_blocks(75); | ||
|
||
BOOST_CHECK( chain.control->fetch_block_by_number(1)->block_num() == 1 ); | ||
BOOST_CHECK( chain.control->fetch_block_by_number(21)->block_num() == 21 ); | ||
BOOST_CHECK( chain.control->fetch_block_by_number(41)->block_num() == 41 ); | ||
BOOST_CHECK( chain.control->fetch_block_by_number(75)->block_num() == 75 ); | ||
block_log::set_version(block_log::max_supported_version); | ||
} | ||
|
||
void trim_blocklog_front(uint32_t version) { | ||
block_log::set_version(version); | ||
tester chain; | ||
chain.produce_blocks(10); | ||
chain.produce_blocks(20); | ||
|
@@ -256,28 +411,31 @@ void trim_blocklog_front() { | |
|
||
block_log old_log(blocks_dir); | ||
block_log new_log(temp1.path); | ||
// double check if the version has been set to the desired version | ||
BOOST_CHECK(old_log.version() == version); | ||
BOOST_CHECK(new_log.first_block_num() == 10); | ||
BOOST_CHECK(new_log.head()->block_num() == old_log.head()->block_num()); | ||
|
||
int num_blocks_trimmed = 10 - 1; | ||
BOOST_CHECK(fc::file_size(temp1.path / "blocks.index") == old_index_size - sizeof(uint64_t) * num_blocks_trimmed); | ||
block_log::set_version(block_log::max_supported_version); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE(test_trim_blocklog_front) { trim_blocklog_front(); } | ||
BOOST_AUTO_TEST_CASE(test_trim_blocklog_front) { | ||
trim_blocklog_front(block_log::max_supported_version); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE(test_trim_blocklog_front_v1) { | ||
block_log::set_version(1); | ||
trim_blocklog_front(); | ||
block_log::set_version(1); | ||
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. Don't need this anymore. |
||
trim_blocklog_front(1); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE(test_trim_blocklog_front_v2) { | ||
block_log::set_version(2); | ||
trim_blocklog_front(); | ||
trim_blocklog_front(2); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE(test_trim_blocklog_front_v3) { | ||
block_log::set_version(3); | ||
trim_blocklog_front(); | ||
trim_blocklog_front(3); | ||
} | ||
|
||
BOOST_AUTO_TEST_SUITE_END() |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
I think we should add here (and also in PR API documentation) something like "When the stride is breached, the current blog log and index will be renamed 'blocks--.log/index' and a new current block log and index will be created with the most recent block. All files following this format will be used to construct an extended block log."