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 all 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
436 changes: 323 additions & 113 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.prune_config ),
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
16 changes: 14 additions & 2 deletions libraries/chain/include/eosio/chain/block_log.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +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.
*/

struct block_log_prune_config {
uint32_t prune_blocks; //number of blocks to prune to when doing a prune
size_t prune_threshold = 4*1024*1024; //(approximately) how many bytes need to be added before a prune is performed
std::optional<size_t> vacuum_on_close; //when set, a vacuum is performed on dtor if log contains less than this many live bytes
};

class block_log {
public:
block_log(const fc::path& data_dir);
block_log(const fc::path& data_dir, std::optional<block_log_prune_config> prune_config);
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 );
Expand Down Expand Up @@ -79,6 +89,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
2 changes: 2 additions & 0 deletions libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once
#include <eosio/chain/block_state.hpp>
#include <eosio/chain/block_log.hpp>
#include <eosio/chain/trace.hpp>
#include <eosio/chain/genesis_state.hpp>
#include <chainbase/pinnable_mapped_file.hpp>
Expand Down Expand Up @@ -69,6 +70,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<block_log_prune_config> prune_config;
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
13 changes: 11 additions & 2 deletions plugins/chain_plugin/chain_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,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-retain-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 @@ -860,6 +863,12 @@ 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-retain-blocks" )) {
my->chain_config->prune_config.emplace();
my->chain_config->prune_config->prune_blocks = options.at( "block-log-retain-blocks" ).as<uint32_t>();
EOS_ASSERT(my->chain_config->prune_config->prune_blocks, plugin_config_exception, "block-log-retain-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
26 changes: 25 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<block_log_prune_config> blog_keep_prune_conf;
};

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

void blocklog::do_vacuum() {
EOS_ASSERT( blog_keep_prune_conf, block_log_exception, "blocks.log is not a pruned log; nothing to vacuum" );
block_log blocks(blocks_dir, std::optional<block_log_prune_config>()); //passing an unset block_log_prune_config turns off pruning this performs a vacuum
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, blog_keep_prune_conf);
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,13 @@ void blocklog::initialize(const variables_map& options) {
else
output_file = bld;
}

//if the log is pruned, keep it that way by passing in a config with a large block pruning value. There is otherwise no
// way to tell block_log "keep the current non/pruneness of the log"
if(block_log::is_pruned_log(blocks_dir)) {
blog_keep_prune_conf.emplace();
blog_keep_prune_conf->prune_blocks = UINT32_MAX;
}
} FC_LOG_AND_RETHROW()

}
Expand Down Expand Up @@ -302,6 +321,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
Loading