Skip to content
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

block log pruning: optionally reduce disk usage of block log file during operation by periodically trimming blocks #342

Merged
merged 24 commits into from
Jun 15, 2022
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6b573f0
optional automatic trimming of block log file
spoonincode Jun 2, 2022
66e6075
use new common cfile hole punching
spoonincode Jun 5, 2022
56c89be
refactor blocklog::index_writer to mmap the index file
spoonincode Jun 5, 2022
87e5ebe
make blocklog::reverse_iterator aware of trimmed logs
spoonincode Jun 6, 2022
aae0c50
adjust a few off-by-ones
spoonincode Jun 6, 2022
939b860
"vacuum" support for converting a trimmed blog back to a flat one
spoonincode Jun 6, 2022
2fac08e
eosio-blocklog awareness of trimmed logs & --prune option
spoonincode Jun 6, 2022
8712bad
reword new log trimming to log pruning
spoonincode Jun 6, 2022
32d174d
fix some "trim" -> "prune" rewording; enforce prune block config >0
spoonincode Jun 6, 2022
d52b82e
get rid of unused blk_size in block log
spoonincode Jun 7, 2022
a7cf0a7
make vacuum status messages be time driven not byte driven
spoonincode Jun 7, 2022
bc65c63
vacuum() does not need to be exposed public for blocklog
spoonincode Jun 7, 2022
c79c0b7
bump fc submod to main
spoonincode Jun 7, 2022
f94e721
flush the block log files after potential trailer count
spoonincode Jun 7, 2022
3823198
tweaks from unit test discoveries
spoonincode Jun 8, 2022
6fe0c84
unit tests for pruned block log
spoonincode Jun 8, 2022
262aac0
grab bag of changes to block log prunning
spoonincode Jun 13, 2022
5dd2d28
convert blog prune configurations over to a well defined struct
spoonincode Jun 13, 2022
db7cf65
fix prune_threshold mask setup in blog prune config
spoonincode Jun 13, 2022
1336572
reorder skips/seeks when finding head of blog for better clarity
spoonincode Jun 13, 2022
2c5fe57
update eosio-blocklog for latest pruning changes
spoonincode Jun 13, 2022
3cd203a
Merge remote-tracking branch 'origin/main' into blog_trimming
spoonincode Jun 13, 2022
a15e1a0
Merge remote-tracking branch 'origin/main' into blog_trimming
spoonincode Jun 14, 2022
679bb0b
rename block log pruning option to block-log-retain-blocks
spoonincode Jun 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
425 changes: 317 additions & 108 deletions libraries/chain/block_log.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ struct controller_impl {
db( cfg.state_dir,
cfg.read_only ? database::read_only : database::read_write,
cfg.state_size, false, cfg.db_map_mode ),
blog( cfg.blocks_dir ),
blog( cfg.blocks_dir, cfg.block_prune_count ),
fork_db( cfg.blocks_dir / config::reversible_blocks_dir_name ),
wasmif( cfg.wasm_runtime, cfg.eosvmoc_tierup, db, cfg.state_dir, cfg.eosvmoc_config, !cfg.profile_accounts.empty() ),
resource_limits( db, [&s]() { return s.get_deep_mind_logger(); }),
Expand Down
12 changes: 10 additions & 2 deletions libraries/chain/include/eosio/chain/block_log.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,25 @@ namespace eosio { namespace chain {
*
* The main file is the only file that needs to persist. The index file can be reconstructed during a
* linear scan of the main file.
*
* An optional "pruned" mode can be activated which stores a 4 byte trailer on the log file indicating
* how many blocks at the end of the log are valid. Any earlier blocks in the log are assumed destroyed
* and unreadable due to reclamation for purposes of saving space.
*/

class block_log {
public:
block_log(const fc::path& data_dir);
block_log(const fc::path& data_dir, std::optional<uint32_t> prune_blocks);
block_log(block_log&& other);
~block_log();

uint64_t append(const signed_block_ptr& b);
void append(const signed_block_ptr& b);
void flush();
void reset( const genesis_state& gs, const signed_block_ptr& genesis_block );
void reset( const chain_id_type& chain_id, uint32_t first_block_num );

void vacuum();

signed_block_ptr read_block(uint64_t file_pos)const;
void read_block_header(block_header& bh, uint64_t file_pos)const;
signed_block_ptr read_block_by_num(uint32_t block_num)const;
Expand Down Expand Up @@ -79,6 +85,8 @@ namespace eosio { namespace chain {

static bool is_supported_version(uint32_t version);

static bool is_pruned_log(const fc::path& data_dir);

static bool trim_blocklog_front(const fc::path& block_dir, const fc::path& temp_dir, uint32_t truncate_at_block);

private:
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ namespace eosio { namespace chain {
flat_set< pair<account_name, action_name> > action_blacklist;
flat_set<public_key_type> key_blacklist;
path blocks_dir = chain::config::default_blocks_dir_name;
std::optional<uint32_t> block_prune_count;
path state_dir = chain::config::default_state_dir_name;
uint64_t state_size = chain::config::default_state_size;
uint64_t state_guard_size = chain::config::default_state_guard_size;
Expand Down
2 changes: 1 addition & 1 deletion libraries/fc
12 changes: 10 additions & 2 deletions plugins/chain_plugin/chain_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,11 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip
("transaction-finality-status-success-duration-sec", bpo::value<uint64_t>()->default_value(config::default_max_transaction_finality_status_success_duration_sec),
"Duration (in seconds) a successful transaction's Finality Status will remain available from being first identified.")
("transaction-finality-status-failure-duration-sec", bpo::value<uint64_t>()->default_value(config::default_max_transaction_finality_status_failure_duration_sec),
"Duration (in seconds) a failed transaction's Finality Status will remain available from being first identified.")
;
"Duration (in seconds) a failed transaction's Finality Status will remain available from being first identified.");

if(cfile::supports_hole_punching())
cfg.add_options()("block-log-prune-blocks", bpo::value<uint32_t>(), "if set, periodically prune the block log to store only configured number of most recent blocks");


// TODO: rate limiting
/*("per-authorized-account-transaction-msg-rate-limit-time-frame-sec", bpo::value<uint32_t>()->default_value(default_per_auth_account_time_frame_seconds),
Expand Down Expand Up @@ -863,6 +866,11 @@ void chain_plugin::plugin_initialize(const variables_map& options) {
// move fork_db to new location
upgrade_from_reversible_to_fork_db( my.get() );

if(options.count( "block-log-prune-blocks" )) {
my->chain_config->block_prune_count = options.at( "block-log-prune-blocks" ).as<uint32_t>();
EOS_ASSERT(*my->chain_config->block_prune_count, plugin_config_exception, "block-log-prune-blocks cannot be 0");
}

if( options.at( "delete-all-blocks" ).as<bool>()) {
ilog( "Deleting state database and blocks" );
if( options.at( "truncate-at-block" ).as<uint32_t>() > 0 )
Expand Down
24 changes: 23 additions & 1 deletion programs/eosio-blocklog/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ struct blocklog {
void read_log();
void set_program_options(options_description& cli);
void initialize(const variables_map& options);
void do_vacuum();

bfs::path blocks_dir;
bfs::path output_file;
Expand All @@ -47,7 +48,10 @@ struct blocklog {
bool make_index = false;
bool trim_log = false;
bool smoke_test = false;
bool vacuum = false;
bool help = false;

std::optional<uint32_t> keep_pruned;
};

struct report_time {
Expand All @@ -65,9 +69,15 @@ struct report_time {
const std::string _desc;
};

void blocklog::do_vacuum() {
EOS_ASSERT( keep_pruned, block_log_exception, "blocks.log is not a pruned log; nothing to vacuum" );
block_log blocks(blocks_dir, std::optional<uint32_t>());
ilog("Successfully vacuumed block log");
}

void blocklog::read_log() {
report_time rt("reading log");
block_log block_logger(blocks_dir);
block_log block_logger(blocks_dir, keep_pruned);
const auto end = block_logger.read_head();
EOS_ASSERT( end, block_log_exception, "No blocks found in block log" );
EOS_ASSERT( end->block_num() > 1, block_log_exception, "Only one block found in block log" );
Expand Down Expand Up @@ -186,6 +196,8 @@ void blocklog::set_program_options(options_description& cli)
"Trim blocks.log and blocks.index. Must give 'blocks-dir' and 'first and/or 'last'.")
("smoke-test", bpo::bool_switch(&smoke_test)->default_value(false),
"Quick test that blocks.log and blocks.index are well formed and agree with each other.")
("vacuum", bpo::bool_switch(&vacuum)->default_value(false),
"Vacuum a pruned blocks.log in to an un-pruned blocks.log")
("help,h", bpo::bool_switch(&help)->default_value(false), "Print this help message and exit.")
;
}
Expand All @@ -205,6 +217,11 @@ void blocklog::initialize(const variables_map& options) {
else
output_file = bld;
}

//if the log is pruned, keep it that way by passing the ctor a large trim value. otherwise the ctor
// will perform a prune even if the user hadn't asked for one here
if(block_log::is_pruned_log(blocks_dir))
keep_pruned = UINT32_MAX;
} FC_LOG_AND_RETHROW()

}
Expand Down Expand Up @@ -302,6 +319,11 @@ int main(int argc, char** argv) {
}
return 0;
}
if (blog.vacuum) {
blog.initialize(vmap);
blog.do_vacuum();
return 0;
}
if (blog.make_index) {
const bfs::path blocks_dir = vmap.at("blocks-dir").as<bfs::path>();
bfs::path out_file = blocks_dir / "blocks.index";
Expand Down