diff --git a/docs/01_nodeos/03_plugins/producer_plugin/10_block-producing-explained.md b/docs/01_nodeos/03_plugins/producer_plugin/10_block-producing-explained.md index 1c3d56ef14..454a2fb613 100644 --- a/docs/01_nodeos/03_plugins/producer_plugin/10_block-producing-explained.md +++ b/docs/01_nodeos/03_plugins/producer_plugin/10_block-producing-explained.md @@ -4,87 +4,84 @@ content_title: Block Production Explained For simplicity of the explanation let's consider the following notations: -m = max_block_cpu_usage +* `r` = `producer_repetitions = 12` (hard-coded value) +* `m` = `max_block_cpu_usage` (on-chain consensus value) +* `u` = `max_block_net_usage` (on-chain consensus value) +* `t` = `block-time` +* `e` = `produce-block-offset-ms` (nodeos configuration) +* `w` = `block-time-interval = 500ms` (hard-coded value) +* `a` = `produce-block-early-amount = w - (w - (e / r)) = e / r ms` (how much to release each block of round early by) +* `l` = `produce-block-time = t - a` +* `p` = `produce block time window = w - a` (amount of wall clock time to produce a block) +* `c` = `billed_cpu_in_block = minimum(m, w - a)` +* `n` = `network tcp/ip latency` +* `h` = `block header validation time ms` + +Peer validation for similar hardware/version/config will be <= `m` + +**Let's consider the example of the following two BPs and their network topology as depicted in the below diagram** -t = block-time - -e = last-block-cpu-effort-percent - -w = block_time_interval = 500ms - -a = produce-block-early-amount = (w - w*e/100) ms - -p = produce-block-time; p = t - a - -c = billed_cpu_in_block = minimum(m, w - a) - -n = network tcp/ip latency - -peer validation for similar hardware/eosio-version/config will be <= m - -**Let's consider for exemplification the following four BPs and their network topology as depicted in below diagram** - - -```dot-svg -#p2p_local_chain_prunning.dot - local chain prunning -# -#notes: * to see image copy/paste to https://dreampuf.github.io/GraphvizOnline -# * image will be rendered by gatsby-remark-graphviz plugin in eosio docs. - -digraph { - newrank=true #allows ranks inside subgraphs (important!) - compound=true #allows edges connecting nodes with subgraphs - graph [rankdir=LR] - node [style=filled, fillcolor=lightgray, shape=square, fixedsize=true, width=.55, fontsize=10] - edge [dir=both, arrowsize=.6, weight=100] - splines=false - - subgraph cluster_chain { - label="Block Producers Peers"; labelloc="b" - graph [color=invis] - b0 [label="...", color=invis, style=""] - b1 [label="BP-A"]; b2 [label="BP-A\nPeer"]; b3 [label="BP-B\nPeer"]; b4 [label="BP-B"] - b5 [label="...", color=invis, style=""] - b0 -> b1 -> b2 -> b3 -> b4 -> b5 - } //cluster_chain - -} //digraph +``` + +------+ +------+ +------+ +------+ + -->| BP-A |---->| BP-A |------>| BP-B |---->| BP-B | + +------+ | Peer | | Peer | +------+ + +------+ +------+ ``` -`BP-A` will send block at `p` and, - -`BP-B` needs block at time `t` or otherwise will drop it. +`BP-A` will send block at `l` and, `BP-B` needs block at time `t` or otherwise will drop it. If `BP-A`is producing 12 blocks as follows `b(lock) at t(ime) 1`, `bt 1.5`, `bt 2`, `bt 2.5`, `bt 3`, `bt 3.5`, `bt 4`, `bt 4.5`, `bt 5`, `bt 5.5`, `bt 6`, `bt 6.5` then `BP-B` needs `bt 6.5` by time `6.5` so it has `.5` to produce `bt 7`. Please notice that the time of `bt 7` minus `.5` equals the time of `bt 6.5` therefore time `t` is the last block time of `BP-A` and when `BP-B` needs to start its first block. -## Example 1 -`BP-A` has 50% e, m = 200ms, c = 200ms, n = 0ms, a = 250ms: -`BP-A` sends at (t-250ms) <-> `BP-A-Peer` processes for 200ms and sends at (t - 50ms) <-> `BP-B-Peer` processes for 200ms and sends at (t + 150ms) <-> arrive at `BP-B` 150ms too late. - -## Example 2 -`BP-A` has 40% e and m = 200ms, c = 200ms, n = 0ms, a = 300ms: -(t-300ms) <-> (+200ms) <-> (+200ms) <-> arrive at `BP-B` 100ms too late. - -## Example 3 -`BP-A` has 30% e and m = 200ms, c = 150ms, n = 0ms, a = 350ms: -(t-350ms) <-> (+150ms) <-> (+150ms) <-> arrive at `BP-B` with 50ms to spare. - -## Example 4 -`BP-A` has 25% e and m = 200ms, c = 125ms, n = 0ms, a = 375ms: -(t-375ms) <-> (+125ms) <-> (+125ms) <-> arrive at `BP-B` with 125ms to spare. - -## Example 5 -`BP-A` has 10% e and m = 200ms, c = 50ms, n = 0ms, a = 450ms: -(t-450ms) <-> (+50ms) <-> (+50ms) <-> arrive at `BP-B` with 350ms to spare. - -## Example 6 -`BP-A` has 10% e and m = 200ms, c = 50ms, n = 15ms, a = 450ms: -(t-450ms) <- +15ms -> (+50ms) <- +15ms -> (+50ms) <- +15ms -> `BP-B` <-> arrive with 305ms to spare. +A block is produced and sent when either it reaches `m` or `u` or `p`. + +Starting in Leap 4.0, blocks are propagated after block header validation. This means instead of `BP-A Peer` & `BP-B Peer` taking `m` time to validate and forward a block it only takes a small number of milliseconds to verify the block header and then forward the block. + +Starting in Leap 5.0, blocks in a round are started immediately after the completion of the previous block. Before 5.0, blocks were always started on `w` intervals and a node would "sleep" between blocks if needed. In 5.0, the "sleeps" are all moved to the end of the block production round. + +## Example 1: block arrives 110ms early +* Assuming zero network latency between all nodes. +* Assuming blocks do not reach `m` and therefore take `w - a` time to produce. +* Assume block completion including signing takes zero time. +* `BP-A` has e = 120, n = 0ms, h = 5ms, a = 10ms +* `BP-A` sends b1 at `t1-10ms` => `BP-A-Peer` processes `h=5ms`, sends at `t-5ms` => `BP-B-Peer` processes `h=5ms`, sends at `t-0ms` => arrives at `BP-B` at `t`. +* `BP-A` starts b2 at `t1-10ms`, sends b2 at `t2-20ms` => `BP-A-Peer` processes `h=5ms`, sends at `t2-15ms` => `BP-B-Peer` processes `h=5ms`, sends at `t2-10ms` => arrives at `BP-B` at `t2-10ms`. +* `BP-A` starts b3 at `t2-20ms`, ... +* `BP-A` starts b12 at `t11-110ms`, sends b12 at `t12-120ms` => `BP-A-Peer` processes `h=5ms`, sends at `t12-115ms` => `BP-B-Peer` processes `h=5ms`, sends at `t12-110ms` => arrives at `BP-B` at `t12-110ms` + +## Example 2: block arrives 80ms early +* Assuming zero network latency between `BP-A` & `BP-A Peer` and between `BP-B Peer` & `BP-B`. +* Assuming 150ms network latency between `BP-A Peer` & `BP-B Peer`. +* Assuming blocks do not reach `m` and therefore take `w - a` time to produce. +* Assume block completion including signing takes zero time. +* `BP-A` has e = 240, n = 0ms/150ms, h = 5ms, a = 20ms +* `BP-A` sends b1 at `t1-20ms` => `BP-A-Peer` processes `h=5ms`, sends at `t-15ms` =(150ms)> `BP-B-Peer` processes `h=5ms`, sends at `t+140ms` => arrives at `BP-B` at `t+140ms`. +* `BP-A` starts b2 at `t1-20ms`, sends b2 at `t2-40ms` => `BP-A-Peer` processes `h=5ms`, sends at `t2-35ms` =(150ms)> `BP-B-Peer` processes `h=5ms`, sends at `t2+120ms` => arrives at `BP-B` at `t2+120ms`. +* `BP-A` starts b3 at `t2-40ms`, ... +* `BP-A` starts b12 at `t11-220ms`, sends b12 at `t12-240ms` => `BP-A-Peer` processes `h=5ms`, sends at `t12-235ms` =(150ms)> `BP-B-Peer` processes `h=5ms`, sends at `t12-80ms` => arrives at `BP-B` at `t12-80ms` + +## Example 3: block arrives 16ms late and is dropped +* Assuming zero network latency between `BP-A` & `BP-A Peer` and between `BP-B Peer` & `BP-B`. +* Assuming 200ms network latency between `BP-A Peer` & `BP-B Peer`. +* Assuming blocks do not reach `m` and therefore take `w - a` time to produce. +* Assume block completion including signing takes zero time. +* `BP-A` has e = 204, n = 0ms/200ms, h = 10ms, a = 17ms +* `BP-A` sends b1 at `t1-17ms` => `BP-A-Peer` processes `h=10ms`, sends at `t-7ms` =(200ms)> `BP-B-Peer` processes `h=10ms`, sends at `t+203ms` => arrives at `BP-B` at `t+203ms`. +* `BP-A` starts b2 at `t1-17ms`, sends b2 at `t2-34ms` => `BP-A-Peer` processes `h=10ms`, sends at `t2-24ms` =(200ms)> `BP-B-Peer` processes `h=10ms`, sends at `t2+186ms` => arrives at `BP-B` at `t2+186ms`. +* `BP-A` starts b3 at `t2-34ms`, ... +* `BP-A` starts b12 at `t11-187ms`, sends b12 at `t12-204ms` => `BP-A-Peer` processes `h=10ms`, sends at `t12-194ms` =(200ms)> `BP-B-Peer` processes `h=10ms`, sends at `t12+16ms` => arrives at `BP-B` at `t12+16ms` + +## Example 4: full blocks are produced early +* Assuming zero network latency between `BP-A` & `BP-A Peer` and between `BP-B Peer` & `BP-B`. +* Assuming 200ms network latency between `BP-A Peer` & `BP-B Peer`. +* Assume all blocks are full as there are enough queued up unapplied transactions ready to fill all blocks. +* Assume a block can be produced with 200ms worth of transactions in 225ms worth of time. There is overhead for producing the block. +* `BP-A` has e = 120, m = 200ms, n = 0ms/200ms, h = 10ms, a = 10ms +* `BP-A` sends b1 at `t1-275s` => `BP-A-Peer` processes `h=10ms`, sends at `t-265ms` =(200ms)> `BP-B-Peer` processes `h=10ms`, sends at `t-55ms` => arrives at `BP-B` at `t-55ms`. +* `BP-A` starts b2 at `t1-275ms`, sends b2 at `t2-550ms (t1-50ms)` => `BP-A-Peer` processes `h=10ms`, sends at `t2-540ms` =(200ms)> `BP-B-Peer` processes `h=10ms`, sends at `t2-330ms` => arrives at `BP-B` at `t2-330ms`. +* `BP-A` starts b3 at `t2-550ms`, ... +* `BP-A` starts b12 at `t11-3025ms`, sends b12 at `t12-3300ms` => `BP-A-Peer` processes `h=10ms`, sends at `t12-3290ms` =(200ms)> `BP-B-Peer` processes `h=10ms`, sends at `t12-3080ms` => arrives at `BP-B` at `t12-3080ms` -## Example 7 -Example world-wide network:`BP-A`has 10% e and m = 200ms, c = 50ms, n = 15ms/250ms, a = 450ms: -(t-450ms) <- +15ms -> (+50ms) <- +250ms -> (+50ms) <- +15ms -> `BP-B` <-> arrive with 70ms to spare. Running wasm-runtime=eos-vm-jit eos-vm-oc-enable on relay node will reduce the validation time. diff --git a/docs/01_nodeos/03_plugins/producer_plugin/index.md b/docs/01_nodeos/03_plugins/producer_plugin/index.md index 533aaf5427..3d36b24f04 100644 --- a/docs/01_nodeos/03_plugins/producer_plugin/index.md +++ b/docs/01_nodeos/03_plugins/producer_plugin/index.md @@ -72,20 +72,9 @@ Config Options for eosio::producer_plugin: can extend during low usage (only enforced subjectively; use 1000 to not enforce any limit) - --produce-time-offset-us arg (=0) Offset of non last block producing time - in microseconds. Valid range 0 .. - -block_time_interval. - --last-block-time-offset-us arg (=-200000) - Offset of last block producing time in - microseconds. Valid range 0 .. - -block_time_interval. - --cpu-effort-percent arg (=80) Percentage of cpu block production time - used to produce block. Whole number - percentages, e.g. 80 for 80% - --last-block-cpu-effort-percent arg (=80) - Percentage of cpu block production time - used to produce last block. Whole - number percentages, e.g. 80 for 80% + --produce-block-offset-ms arg (=450) The minimum time to reserve at the end + of a production round for blocks to + propagate to the next block producer. --max-block-cpu-usage-threshold-us arg (=5000) Threshold of CPU block production to consider block full; when within diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 06edfe06ea..c21c62db63 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -77,7 +77,7 @@ const static uint32_t default_max_inline_action_size = 512 * 102 const static uint16_t default_max_inline_action_depth = 4; const static uint16_t default_max_auth_depth = 6; const static uint32_t default_sig_cpu_bill_pct = 50 * percent_1; // billable percentage of signature recovery -const static uint32_t default_block_cpu_effort_pct = 90 * percent_1; // percentage of block time used for producing block +const static uint32_t default_produce_block_offset_ms = 450; const static uint16_t default_controller_thread_pool_size = 2; const static uint32_t default_max_variable_signature_length = 16384u; const static uint32_t default_max_action_return_value_size = 256; diff --git a/libraries/chain/webassembly/runtimes/eos-vm-oc/code_cache.cpp b/libraries/chain/webassembly/runtimes/eos-vm-oc/code_cache.cpp index 6100c3384d..7c48b5b079 100644 --- a/libraries/chain/webassembly/runtimes/eos-vm-oc/code_cache.cpp +++ b/libraries/chain/webassembly/runtimes/eos-vm-oc/code_cache.cpp @@ -226,13 +226,13 @@ const code_descriptor* const code_cache_sync::get_descriptor_for_code_sync(const code_cache_base::code_cache_base(const std::filesystem::path& data_dir, const eosvmoc::config& eosvmoc_config, const chainbase::database& db) : _db(db), - _cache_file_path(data_dir/"code_cache.bin") -{ + _cache_file_path(data_dir/"code_cache.bin") { static_assert(sizeof(allocator_t) <= header_offset, "header offset intersects with allocator"); std::filesystem::create_directories(data_dir); - if(!std::filesystem::exists(_cache_file_path)) { + bool created_file = false; + auto create_code_cache_file = [&] { EOS_ASSERT(eosvmoc_config.cache_size >= allocator_t::get_min_size(total_header_size), database_exception, "configured code cache size is too small"); std::ofstream ofs(_cache_file_path.generic_string(), std::ofstream::trunc); EOS_ASSERT(ofs.good(), database_exception, "unable to create EOS VM Optimized Compiler code cache"); @@ -241,19 +241,35 @@ code_cache_base::code_cache_base(const std::filesystem::path& data_dir, const eo bip::mapped_region creation_region(creation_mapping, bip::read_write); new (creation_region.get_address()) allocator_t(eosvmoc_config.cache_size, total_header_size); new ((char*)creation_region.get_address() + header_offset) code_cache_header; - } + created_file = true; + }; code_cache_header cache_header; - { + auto check_code_cache = [&] { char header_buff[total_header_size]; std::ifstream hs(_cache_file_path.generic_string(), std::ifstream::binary); hs.read(header_buff, sizeof(header_buff)); EOS_ASSERT(!hs.fail(), bad_database_version_exception, "failed to read code cache header"); memcpy((char*)&cache_header, header_buff + header_offset, sizeof(cache_header)); + + EOS_ASSERT(cache_header.id == header_id, bad_database_version_exception, "existing EOS VM OC code cache not compatible with this version"); + EOS_ASSERT(!cache_header.dirty, database_exception, "code cache is dirty"); + }; + + if (!std::filesystem::exists(_cache_file_path)) { + create_code_cache_file(); } - EOS_ASSERT(cache_header.id == header_id, bad_database_version_exception, "existing EOS VM OC code cache not compatible with this version"); - EOS_ASSERT(!cache_header.dirty, database_exception, "code cache is dirty"); + try { + check_code_cache(); + } catch (const fc::exception&) { + if (created_file) + throw; + + ilog("EOS VM optimized Compiler code cache corrupt, recreating"); + create_code_cache_file(); + check_code_cache(); + } set_on_disk_region_dirty(true); diff --git a/libraries/chainbase b/libraries/chainbase index 3bfb0d00b6..13c9c35e39 160000 --- a/libraries/chainbase +++ b/libraries/chainbase @@ -1 +1 @@ -Subproject commit 3bfb0d00b61087bff804c622ffa5929fec2fa4ed +Subproject commit 13c9c35e393f1739c053ff7a03edb4d9df30990d diff --git a/libraries/state_history/include/eosio/state_history/log.hpp b/libraries/state_history/include/eosio/state_history/log.hpp index 567294c2a2..0c574476e9 100644 --- a/libraries/state_history/include/eosio/state_history/log.hpp +++ b/libraries/state_history/include/eosio/state_history/log.hpp @@ -73,9 +73,10 @@ struct state_history_log_header { chain::block_id_type block_id = {}; uint64_t payload_size = 0; }; -static const int state_history_log_header_serial_size = sizeof(state_history_log_header::magic) + - sizeof(state_history_log_header::block_id) + - sizeof(state_history_log_header::payload_size); +static constexpr int state_history_log_header_serial_size = sizeof(state_history_log_header::magic) + + sizeof(state_history_log_header::block_id) + + sizeof(state_history_log_header::payload_size); +static_assert(sizeof(state_history_log_header) == state_history_log_header_serial_size); namespace state_history { struct prune_config { @@ -323,7 +324,7 @@ class state_history_log { catalog.open(log_dir, conf.retained_dir, conf.archive_dir, name); catalog.max_retained_files = conf.max_retained_files; if (_end_block == 0) { - _begin_block = _end_block = catalog.last_block_num() +1; + _index_begin_block = _begin_block = _end_block = catalog.last_block_num() +1; } } }, _config); @@ -539,6 +540,7 @@ class state_history_log { "wrote payload with incorrect size to ${name}.log", ("name", name)); fc::raw::pack(log, pos); + index.seek_end(0); fc::raw::pack(index, pos); if (_begin_block == _end_block) _index_begin_block = _begin_block = block_num; @@ -576,10 +578,14 @@ class state_history_log { if (block_num >= _begin_block && block_num < _end_block) { state_history_log_header header; get_entry(block_num, header); + EOS_ASSERT(chain::block_header::num_from_id(header.block_id) == block_num, chain::plugin_exception, + "header id does not match requested ${a} != ${b}", ("a", chain::block_header::num_from_id(header.block_id))("b", block_num)); return header.block_id; } return {}; } + EOS_ASSERT(chain::block_header::num_from_id(*result) == block_num, chain::plugin_exception, + "catalog id does not match requested ${a} != ${b}", ("a", chain::block_header::num_from_id(*result))("b", block_num)); return result; } @@ -894,47 +900,16 @@ class state_history_log { } void split_log() { - - std::filesystem::path log_file_path = log.get_file_path(); - std::filesystem::path index_file_path = index.get_file_path(); - - fc::datastream new_log_file; - fc::datastream new_index_file; - - std::filesystem::path tmp_log_file_path = log_file_path; - tmp_log_file_path.replace_extension("log.tmp"); - std::filesystem::path tmp_index_file_path = index_file_path; - tmp_index_file_path.replace_extension("index.tmp"); - - new_log_file.set_file_path(tmp_log_file_path); - new_index_file.set_file_path(tmp_index_file_path); - - try { - new_log_file.open(fc::cfile::truncate_rw_mode); - new_index_file.open(fc::cfile::truncate_rw_mode); - - } catch (...) { - wlog("Unable to open new state history log or index file for writing during log spliting, " - "continue writing to existing block log file\n"); - return; - } - index.close(); log.close(); catalog.add(_begin_block, _end_block - 1, log.get_file_path().parent_path(), name); - _begin_block = _end_block; + _index_begin_block = _begin_block = _end_block; - using std::swap; - swap(new_log_file, log); - swap(new_index_file, index); - - std::filesystem::rename(tmp_log_file_path, log_file_path); - std::filesystem::rename(tmp_index_file_path, index_file_path); - - log.set_file_path(log_file_path); - index.set_file_path(index_file_path); + log.open(fc::cfile::truncate_rw_mode); + log.seek_end(0); + index.open(fc::cfile::truncate_rw_mode); } }; // state_history_log diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index a98a826e07..aed684572e 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -463,14 +463,6 @@ void clear_directory_contents( const std::filesystem::path& p ) { } } -void clear_chainbase_files( const std::filesystem::path& p ) { - if( !std::filesystem::is_directory( p ) ) - return; - - std::filesystem::remove( p / "shared_memory.bin" ); - std::filesystem::remove( p / "shared_memory.meta" ); -} - namespace { // This can be removed when versions of eosio that support reversible chainbase state file no longer supported. void upgrade_from_reversible_to_fork_db(chain_plugin_impl* my) { @@ -762,7 +754,7 @@ void chain_plugin_impl::plugin_initialize(const variables_map& options) { ilog( "Replay requested: deleting state database" ); if( options.at( "truncate-at-block" ).as() > 0 ) wlog( "The --truncate-at-block option does not work for a regular replay of the blockchain." ); - clear_chainbase_files( chain_config->state_dir ); + clear_directory_contents( chain_config->state_dir ); } else if( options.at( "truncate-at-block" ).as() > 0 ) { wlog( "The --truncate-at-block option can only be used with --hard-replay-blockchain." ); } diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 0c7f72f735..8008025f73 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -1747,10 +1747,6 @@ namespace eosio { peer_dlog( this, "enqueue sync block ${num}", ("num", peer_requested->last + 1) ); } uint32_t num = peer_requested->last + 1; - if(num == peer_requested->end_block) { - peer_requested.reset(); - peer_dlog( this, "completing enqueue_sync_block ${num}", ("num", num) ); - } controller& cc = my_impl->chain_plug->chain(); signed_block_ptr sb; @@ -1771,6 +1767,10 @@ namespace eosio { block_sync_throttling = false; block_sync_bytes_sent += enqueue_block( sb, true ); ++peer_requested->last; + if(num == peer_requested->end_block) { + peer_requested.reset(); + peer_dlog( this, "completing enqueue_sync_block ${num}", ("num", num) ); + } } else { peer_ilog( this, "enqueue sync, unable to fetch block ${num}, sending benign_other go away", ("num", num) ); peer_requested.reset(); // unable to provide requested blocks diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/block_timing_util.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/block_timing_util.hpp index b4e3741874..27ba83ff6c 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/block_timing_util.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/block_timing_util.hpp @@ -42,28 +42,28 @@ namespace block_timing_util { // In the past, a producer would always start a block `config::block_interval_us` ahead of its block time. However, // it causes the last block in a block production round being released too late for the next producer to have // received it and start producing on schedule. To mitigate the problem, we leave no time gap in block producing. For - // example, given block_interval=500 ms and cpu effort=400 ms, assuming the our round start at time point 0; in the + // example, given block_interval=500 ms and cpu effort=400 ms, assuming our round starts at time point 0; in the // past, the block start time points would be at time point -500, 0, 500, 1000, 1500, 2000 .... With this new // approach, the block time points would become -500, -100, 300, 700, 1100 ... - inline fc::time_point production_round_block_start_time(uint32_t cpu_effort_us, chain::block_timestamp_type block_time) { + inline fc::time_point production_round_block_start_time(fc::microseconds cpu_effort, chain::block_timestamp_type block_time) { uint32_t block_slot = block_time.slot; uint32_t production_round_start_block_slot = (block_slot / chain::config::producer_repetitions) * chain::config::producer_repetitions; uint32_t production_round_index = block_slot % chain::config::producer_repetitions; return chain::block_timestamp_type(production_round_start_block_slot - 1).to_time_point() + - fc::microseconds(cpu_effort_us * production_round_index); + fc::microseconds(cpu_effort.count() * production_round_index); } - inline fc::time_point calculate_producing_block_deadline(uint32_t cpu_effort_us, chain::block_timestamp_type block_time) { - auto estimated_deadline = production_round_block_start_time(cpu_effort_us, block_time) + fc::microseconds(cpu_effort_us); + inline fc::time_point calculate_producing_block_deadline(fc::microseconds cpu_effort, chain::block_timestamp_type block_time) { + auto estimated_deadline = production_round_block_start_time(cpu_effort, block_time) + cpu_effort; auto now = fc::time_point::now(); if (estimated_deadline > now) { return estimated_deadline; } else { // This could only happen when the producer stop producing and then comes back alive in the middle of its own // production round. In this case, we just use the hard deadline. - const auto hard_deadline = block_time.to_time_point() - fc::microseconds(chain::config::block_interval_us - cpu_effort_us); - return std::min(hard_deadline, now + fc::microseconds(cpu_effort_us)); + const auto hard_deadline = block_time.to_time_point() - fc::microseconds(chain::config::block_interval_us - cpu_effort.count()); + return std::min(hard_deadline, now + cpu_effort); } } @@ -118,7 +118,7 @@ namespace block_timing_util { // Return the *next* block start time according to its block time slot. // Returns empty optional if no producers are in the active_schedule. // block_num is only used for watermark minimum offset. - inline std::optional calculate_producer_wake_up_time(uint32_t cpu_effort_us, uint32_t block_num, + inline std::optional calculate_producer_wake_up_time(fc::microseconds cpu_effort, uint32_t block_num, const chain::block_timestamp_type& ref_block_time, const std::set& producers, const std::vector& active_schedule, @@ -141,7 +141,7 @@ namespace block_timing_util { return {}; } - return production_round_block_start_time(cpu_effort_us, chain::block_timestamp_type(wake_up_slot)); + return production_round_block_start_time(cpu_effort, chain::block_timestamp_type(wake_up_slot)); } } // namespace block_timing_util diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp index f2c7e914f1..495d1b91a6 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp @@ -17,7 +17,8 @@ class producer_plugin : public appbase::plugin { struct runtime_options { std::optional max_transaction_time; std::optional max_irreversible_block_age; - std::optional cpu_effort_us; + // minimum time to reserve at the end of a production round for blocks to propagate to the next block producer. + std::optional produce_block_offset_ms; std::optional subjective_cpu_leeway_us; std::optional greylist_limit; }; @@ -196,7 +197,7 @@ class producer_plugin : public appbase::plugin { } //eosio -FC_REFLECT(eosio::producer_plugin::runtime_options, (max_transaction_time)(max_irreversible_block_age)(cpu_effort_us)(subjective_cpu_leeway_us)(greylist_limit)); +FC_REFLECT(eosio::producer_plugin::runtime_options, (max_transaction_time)(max_irreversible_block_age)(produce_block_offset_ms)(subjective_cpu_leeway_us)(greylist_limit)); FC_REFLECT(eosio::producer_plugin::greylist_params, (accounts)); FC_REFLECT(eosio::producer_plugin::whitelist_blacklist, (actor_whitelist)(actor_blacklist)(contract_whitelist)(contract_blacklist)(action_blacklist)(key_blacklist) ) FC_REFLECT(eosio::producer_plugin::integrity_hash_information, (head_block_id)(integrity_hash)) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 75df5a5224..c8411f07f1 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -371,7 +371,6 @@ class producer_plugin_impl : public std::enable_shared_from_thischain().get_subjective_cpu_leeway() ? chain_plug->chain().get_subjective_cpu_leeway()->count() : std::optional(), chain_plug->chain().get_greylist_limit()}; @@ -502,14 +501,14 @@ class producer_plugin_impl : public std::enable_shared_from_this _max_transaction_time_ms; // modified by app thread, read by net_plugin thread pool std::atomic _received_block{0}; // modified by net_plugin thread pool fc::microseconds _max_irreversible_block_age_us; - int32_t _cpu_effort_us = 0; + // produce-block-offset is in terms of the complete round, internally use calculated value for each block of round + fc::microseconds _produce_block_cpu_effort; fc::time_point _pending_block_deadline; uint32_t _max_block_cpu_usage_threshold_us = 0; uint32_t _max_block_net_usage_threshold_bytes = 0; bool _disable_subjective_p2p_billing = true; bool _disable_subjective_api_billing = true; fc::time_point _irreversible_block_time; - fc::time_point _idle_trx_time{fc::time_point::now()}; std::vector _protocol_features_to_activate; bool _protocol_features_signaled = false; // to mark whether it has been signaled in start_block @@ -614,6 +613,17 @@ class producer_plugin_impl : public std::enable_shared_from_this next); + void set_produce_block_offset(uint32_t produce_block_offset_ms) { + EOS_ASSERT(produce_block_offset_ms < (config::producer_repetitions * config::block_interval_ms), plugin_config_exception, + "produce-block-offset-ms ${p} must be [0 - ${max})", ("p", produce_block_offset_ms)("max", config::producer_repetitions * config::block_interval_ms)); + _produce_block_cpu_effort = fc::microseconds(config::block_interval_us - (produce_block_offset_ms*1000 / config::producer_repetitions) ); + } + + fc::microseconds get_produce_block_offset() const { + return fc::milliseconds( (config::block_interval_ms * config::producer_repetitions) - + ((_produce_block_cpu_effort.count() / 1000) * config::producer_repetitions) ); + } + void on_block(const block_state_ptr& bsp) { auto& chain = chain_plug->chain(); auto before = _unapplied_transactions.size(); @@ -1035,8 +1045,8 @@ void producer_plugin::set_program_options( "account that can not access to extended CPU/NET virtual resources") ("greylist-limit", boost::program_options::value()->default_value(1000), "Limit (between 1 and 1000) on the multiple that CPU/NET virtual resources can extend during low usage (only enforced subjectively; use 1000 to not enforce any limit)") - ("cpu-effort-percent", bpo::value()->default_value(config::default_block_cpu_effort_pct / config::percent_1), - "Percentage of cpu block production time used to produce block. Whole number percentages, e.g. 80 for 80%") + ("produce-block-offset-ms", bpo::value()->default_value(config::default_produce_block_offset_ms), + "The minimum time to reserve at the end of a production round for blocks to propagate to the next block producer.") ("max-block-cpu-usage-threshold-us", bpo::value()->default_value( 5000 ), "Threshold of CPU block production to consider block full; when within threshold of max-block-cpu-usage block can be produced immediately") ("max-block-net-usage-threshold-bytes", bpo::value()->default_value( 1024 ), @@ -1136,12 +1146,7 @@ void producer_plugin_impl::plugin_initialize(const boost::program_options::varia _account_fails.set_max_failures_per_account(options.at("subjective-account-max-failures").as(), subjective_account_max_failures_window_size); - uint32_t cpu_effort_pct = options.at("cpu-effort-percent").as(); - EOS_ASSERT(cpu_effort_pct >= 0 && cpu_effort_pct <= 100, plugin_config_exception, - "cpu-effort-percent ${pct} must be 0 - 100", ("pct", cpu_effort_pct)); - cpu_effort_pct *= config::percent_1; - - _cpu_effort_us = EOS_PERCENT(config::block_interval_us, cpu_effort_pct); + set_produce_block_offset(options.at("produce-block-offset-ms").as()); _max_block_cpu_usage_threshold_us = options.at("max-block-cpu-usage-threshold-us").as(); EOS_ASSERT(_max_block_cpu_usage_threshold_us < config::block_interval_us, @@ -1454,8 +1459,8 @@ void producer_plugin_impl::update_runtime_options(const producer_plugin::runtime check_speculating = true; } - if (options.cpu_effort_us) { - _cpu_effort_us = *options.cpu_effort_us; + if (options.produce_block_offset_ms) { + set_produce_block_offset(*options.produce_block_offset_ms); } if (check_speculating && in_speculating_mode()) { @@ -1851,10 +1856,10 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { } } - _pending_block_deadline = block_timing_util::calculate_producing_block_deadline(_cpu_effort_us, block_time); + _pending_block_deadline = block_timing_util::calculate_producing_block_deadline(_produce_block_cpu_effort, block_time); } else if (!_producers.empty()) { // cpu effort percent doesn't matter for the first block of the round, use max (block_interval_us) for cpu effort - auto wake_time = block_timing_util::calculate_producer_wake_up_time(config::block_interval_us, chain.head_block_num(), chain.head_block_time(), + auto wake_time = block_timing_util::calculate_producer_wake_up_time(fc::microseconds(config::block_interval_us), chain.head_block_num(), chain.head_block_time(), _producers, chain.head_block_state()->active_schedule.producers, _producer_watermarks); if (wake_time) @@ -2017,8 +2022,8 @@ bool producer_plugin_impl::remove_expired_trxs(const fc::time_point& deadline) { }); if (exhausted && in_producing_mode()) { - fc_wlog(_log, "Unable to process all expired transactions of the ${n} transactions in the unapplied queue before deadline, " - "Expired ${expired}", ("n", orig_count)("expired", num_expired)); + fc_wlog(_log, "Unable to process all expired transactions of the ${n} transactions in the unapplied queue before deadline ${d}, " + "Expired ${expired}", ("n", orig_count)("d", deadline)("expired", num_expired)); } else { fc_dlog(_log, "Processed ${ex} expired transactions of the ${n} transactions in the unapplied queue.", ("n", orig_count)("ex", num_expired)); } @@ -2486,7 +2491,7 @@ void producer_plugin_impl::schedule_production_loop() { if (!_producers.empty() && !production_disabled_by_policy()) { chain::controller& chain = chain_plug->chain(); fc_dlog(_log, "Waiting till another block is received and scheduling Speculative/Production Change"); - auto wake_time = block_timing_util::calculate_producer_wake_up_time(_cpu_effort_us, chain.head_block_num(), calculate_pending_block_time(), + auto wake_time = block_timing_util::calculate_producer_wake_up_time(_produce_block_cpu_effort, chain.head_block_num(), calculate_pending_block_time(), _producers, chain.head_block_state()->active_schedule.producers, _producer_watermarks); schedule_delayed_production_loop(weak_from_this(), wake_time); @@ -2505,7 +2510,7 @@ void producer_plugin_impl::schedule_production_loop() { chain::controller& chain = chain_plug->chain(); fc_dlog(_log, "Speculative Block Created; Scheduling Speculative/Production Change"); EOS_ASSERT(chain.is_building_block(), missing_pending_block_state, "speculating without pending_block_state"); - auto wake_time = block_timing_util::calculate_producer_wake_up_time(_cpu_effort_us, chain.pending_block_num(), chain.pending_block_timestamp(), + auto wake_time = block_timing_util::calculate_producer_wake_up_time(_produce_block_cpu_effort, chain.pending_block_num(), chain.pending_block_timestamp(), _producers, chain.head_block_state()->active_schedule.producers, _producer_watermarks); schedule_delayed_production_loop(weak_from_this(), wake_time); @@ -2522,7 +2527,7 @@ void producer_plugin_impl::schedule_maybe_produce_block(bool exhausted) { assert(in_producing_mode()); // we succeeded but block may be exhausted static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); - auto deadline = block_timing_util::calculate_producing_block_deadline(_cpu_effort_us, chain.pending_block_time()); + auto deadline = block_timing_util::calculate_producing_block_deadline(_produce_block_cpu_effort, chain.pending_block_time()); if (!exhausted && deadline > fc::time_point::now()) { // ship this block off no later than its deadline diff --git a/plugins/producer_plugin/test/test_block_timing_util.cpp b/plugins/producer_plugin/test/test_block_timing_util.cpp index efb045b477..a3a43452e8 100644 --- a/plugins/producer_plugin/test/test_block_timing_util.cpp +++ b/plugins/producer_plugin/test/test_block_timing_util.cpp @@ -25,7 +25,7 @@ BOOST_AUTO_TEST_CASE(test_production_round_block_start_time) { for (int i = 0; i < eosio::chain::config::producer_repetitions; ++i, expected_start_time = expected_start_time + cpu_effort) { auto block_time = eosio::chain::block_timestamp_type(production_round_1st_block_slot + i); - BOOST_CHECK_EQUAL(eosio::block_timing_util::production_round_block_start_time(cpu_effort_us, block_time), expected_start_time); + BOOST_CHECK_EQUAL(eosio::block_timing_util::production_round_block_start_time(cpu_effort, block_time), expected_start_time); } } @@ -43,7 +43,7 @@ BOOST_AUTO_TEST_CASE(test_calculate_block_deadline) { for (int i = 0; i < eosio::chain::config::producer_repetitions; ++i) { auto block_time = eosio::chain::block_timestamp_type(production_round_1st_block_slot + i); auto expected_deadline = block_time.to_time_point() - fc::milliseconds((i + 1) * 100); - BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort_us, block_time), + BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort, block_time), expected_deadline); fc::mock_time_traits::set_now(expected_deadline); } @@ -56,18 +56,18 @@ BOOST_AUTO_TEST_CASE(test_calculate_block_deadline) { auto second_block_time = eosio::chain::block_timestamp_type(production_round_1st_block_slot + 1); fc::mock_time_traits::set_now(second_block_time.to_time_point() - fc::milliseconds(200)); auto second_block_hard_deadline = second_block_time.to_time_point() - fc::milliseconds(100); - BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort_us, second_block_time), + BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort, second_block_time), second_block_hard_deadline); // use previous deadline as now fc::mock_time_traits::set_now(second_block_hard_deadline); auto third_block_time = eosio::chain::block_timestamp_type(production_round_1st_block_slot + 2); - BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort_us, third_block_time), + BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort, third_block_time), third_block_time.to_time_point() - fc::milliseconds(300)); // use previous deadline as now fc::mock_time_traits::set_now(third_block_time.to_time_point() - fc::milliseconds(300)); auto forth_block_time = eosio::chain::block_timestamp_type(production_round_1st_block_slot + 3); - BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort_us, forth_block_time), + BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort, forth_block_time), forth_block_time.to_time_point() - fc::milliseconds(400)); /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -75,21 +75,21 @@ BOOST_AUTO_TEST_CASE(test_calculate_block_deadline) { auto seventh_block_time = eosio::chain::block_timestamp_type(production_round_1st_block_slot + 6); fc::mock_time_traits::set_now(seventh_block_time.to_time_point() - fc::milliseconds(500)); - BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort_us, seventh_block_time), + BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort, seventh_block_time), seventh_block_time.to_time_point() - fc::milliseconds(100)); // use previous deadline as now fc::mock_time_traits::set_now(seventh_block_time.to_time_point() - fc::milliseconds(100)); auto eighth_block_time = eosio::chain::block_timestamp_type(production_round_1st_block_slot + 7); - BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort_us, eighth_block_time), + BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort, eighth_block_time), eighth_block_time.to_time_point() - fc::milliseconds(200)); // use previous deadline as now fc::mock_time_traits::set_now(eighth_block_time.to_time_point() - fc::milliseconds(200)); auto ninth_block_time = eosio::chain::block_timestamp_type(production_round_1st_block_slot + 8); - BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort_us, ninth_block_time), + BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort, ninth_block_time), ninth_block_time.to_time_point() - fc::milliseconds(300)); } } @@ -102,7 +102,7 @@ BOOST_AUTO_TEST_CASE(test_calculate_producer_wake_up_time) { producer_watermarks empty_watermarks; // use full cpu effort for most of these tests since calculate_producing_block_deadline is tested above - constexpr uint32_t full_cpu_effort = eosio::chain::config::block_interval_us; + constexpr fc::microseconds full_cpu_effort = fc::microseconds{eosio::chain::config::block_interval_us}; { // no producers BOOST_CHECK_EQUAL(calculate_producer_wake_up_time(full_cpu_effort, 2, chain::block_timestamp_type{}, {}, {}, empty_watermarks), std::optional{}); @@ -206,7 +206,7 @@ BOOST_AUTO_TEST_CASE(test_calculate_producer_wake_up_time) { BOOST_CHECK_EQUAL(calculate_producer_wake_up_time(full_cpu_effort, 2, block_timestamp, producers, active_schedule, empty_watermarks), expected_block_time); // cpu_effort at 50%, initc - constexpr uint32_t half_cpu_effort = eosio::chain::config::block_interval_us / 2u; + constexpr fc::microseconds half_cpu_effort = fc::microseconds{eosio::chain::config::block_interval_us / 2u}; producers = std::set{ "initc"_n }; block_timestamp = block_timestamp_type(prod_round_1st_block_slot); expected_block_time = block_timestamp_type(prod_round_1st_block_slot + 2*config::producer_repetitions).to_time_point(); @@ -221,7 +221,7 @@ BOOST_AUTO_TEST_CASE(test_calculate_producer_wake_up_time) { block_timestamp = block_timestamp_type(prod_round_1st_block_slot + 2*config::producer_repetitions + 2); // second in round is 50% sooner expected_block_time = block_timestamp.to_time_point(); - expected_block_time -= fc::microseconds(2*half_cpu_effort); + expected_block_time -= fc::microseconds(2*half_cpu_effort.count()); BOOST_CHECK_EQUAL(calculate_producer_wake_up_time(half_cpu_effort, 2, block_timestamp, producers, active_schedule, empty_watermarks), expected_block_time); } { // test watermark diff --git a/plugins/resource_monitor_plugin/include/eosio/resource_monitor_plugin/file_space_handler.hpp b/plugins/resource_monitor_plugin/include/eosio/resource_monitor_plugin/file_space_handler.hpp index 230edf62fb..a4c04b02d1 100644 --- a/plugins/resource_monitor_plugin/include/eosio/resource_monitor_plugin/file_space_handler.hpp +++ b/plugins/resource_monitor_plugin/include/eosio/resource_monitor_plugin/file_space_handler.hpp @@ -4,18 +4,47 @@ #include #include - +#include namespace eosio::resource_monitor { template class file_space_handler { public: - file_space_handler(SpaceProvider&& space_provider, boost::asio::io_context& ctx) - :space_provider(std::move(space_provider)), - timer{ctx} + file_space_handler(SpaceProvider&& space_provider) + :space_provider(std::move(space_provider)) { } + void start(const std::vector& directories) { + for ( auto& dir: directories ) { + add_file_system( dir ); + + // A directory like "data" contains subdirectories like + // "block". Those subdirectories can mount on different + // file systems. Make sure they are taken care of. + for (std::filesystem::directory_iterator itr(dir); itr != std::filesystem::directory_iterator(); ++itr) { + if (std::filesystem::is_directory(itr->path())) { + add_file_system( itr->path() ); + } + } + } + + thread_pool.start(thread_pool_size, + []( const fc::exception& e ) { + elog("Exception in resource monitor plugin thread pool, exiting: ${e}", ("e", e.to_detail_string()) ); + appbase::app().quit(); }, + [&]() { space_monitor_loop(); } + ); + } + + // called on main thread from plugin shutdown() + void stop() { + // After thread pool stops, timer is not accessible within it. + // In addition, timer's destructor will call cancel. + // Therefore, no need to call cancel explicitly. + thread_pool.stop(); + } + void set_sleep_time(uint32_t sleep_time) { sleep_time_in_secs = sleep_time; } @@ -128,6 +157,7 @@ namespace eosio::resource_monitor { ("path_name", path_name.string())("shutdown_available", to_gib(shutdown_available)) ("capacity", to_gib(info.capacity))("threshold_desc", threshold_desc()) ); } + // on resmon thread void space_monitor_loop() { if ( is_threshold_exceeded() && shutdown_on_exceeded ) { elog("Gracefully shutting down, exceeded file system configured threshold."); @@ -137,9 +167,12 @@ namespace eosio::resource_monitor { update_warning_interval_counter(); timer.expires_from_now( boost::posix_time::seconds( sleep_time_in_secs )); - timer.async_wait([this](const auto& ec) { if ( ec ) { + // No need to check if ec is operation_aborted (cancelled), + // as cancel callback will never be make it here after thread_pool + // is stopped, even though cancel is called in the timer's + // destructor. wlog("Exit due to error: ${ec}, message: ${message}", ("ec", ec.value()) ("message", ec.message())); @@ -154,7 +187,10 @@ namespace eosio::resource_monitor { private: SpaceProvider space_provider; - boost::asio::deadline_timer timer; + static constexpr size_t thread_pool_size = 1; + eosio::chain::named_thread_pool thread_pool; + + boost::asio::deadline_timer timer {thread_pool.get_executor()}; uint32_t sleep_time_in_secs {2}; uint32_t shutdown_threshold {90}; diff --git a/plugins/resource_monitor_plugin/resource_monitor_plugin.cpp b/plugins/resource_monitor_plugin/resource_monitor_plugin.cpp index 15cf0dcbdc..f0088987d2 100644 --- a/plugins/resource_monitor_plugin/resource_monitor_plugin.cpp +++ b/plugins/resource_monitor_plugin/resource_monitor_plugin.cpp @@ -37,7 +37,7 @@ namespace eosio { class resource_monitor_plugin_impl { public: resource_monitor_plugin_impl() - :space_handler(system_file_space_provider(), ctx) + :space_handler(system_file_space_provider()) { } @@ -109,42 +109,14 @@ class resource_monitor_plugin_impl { // Start main thread void plugin_startup() { - ilog("Creating and starting monitor thread"); - - // By now all plugins are initialized. - // Find out filesystems containing the directories requested - // so far. - for ( auto& dir: directories_registered ) { - space_handler.add_file_system( dir ); - - // A directory like "data" contains subdirectories like - // "block". Those subdirectories can mount on different - // file systems. Make sure they are taken care of. - for (std::filesystem::directory_iterator itr(dir); itr != std::filesystem::directory_iterator(); ++itr) { - if (std::filesystem::is_directory(itr->path())) { - space_handler.add_file_system( itr->path() ); - } - } - } - - monitor_thread = std::thread( [this] { - fc::set_thread_name( "resmon" ); // console_appender uses 9 chars for thread name reporting. - space_handler.space_monitor_loop(); - - ctx.run(); - } ); + space_handler.start(directories_registered); } // System is shutting down. void plugin_shutdown() { - ilog("shutdown..."); - - ctx.stop(); - - // Wait for the thread to end - monitor_thread.join(); - - ilog("exit shutdown"); + ilog("entered shutdown..."); + space_handler.stop(); + ilog("exiting shutdown"); } void monitor_directory(const std::filesystem::path& path) { @@ -169,8 +141,6 @@ class resource_monitor_plugin_impl { static constexpr uint32_t warning_interval_min = 1; static constexpr uint32_t warning_interval_max = 450; // e.g. if the monitor interval is 2 sec, the warning interval is at most 15 minutes - boost::asio::io_context ctx; - using file_space_handler_t = file_space_handler; file_space_handler_t space_handler; }; diff --git a/plugins/resource_monitor_plugin/test/CMakeLists.txt b/plugins/resource_monitor_plugin/test/CMakeLists.txt index a564c515dc..e9f0bf03ba 100644 --- a/plugins/resource_monitor_plugin/test/CMakeLists.txt +++ b/plugins/resource_monitor_plugin/test/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable( test_resmon_plugin test_resmon_plugin.cpp test_add_file_system.cpp test_monitor_loop.cpp test_threshold.cpp ) +add_executable( test_resmon_plugin test_resmon_plugin.cpp test_add_file_system.cpp test_threshold.cpp ) target_link_libraries( test_resmon_plugin resource_monitor_plugin ) target_include_directories( test_resmon_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) add_test(NAME test_resmon_plugin COMMAND plugins/resource_monitor_plugin/test/test_resmon_plugin WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/plugins/resource_monitor_plugin/test/test_add_file_system.cpp b/plugins/resource_monitor_plugin/test/test_add_file_system.cpp index 201fa96555..baae648c12 100644 --- a/plugins/resource_monitor_plugin/test/test_add_file_system.cpp +++ b/plugins/resource_monitor_plugin/test/test_add_file_system.cpp @@ -23,11 +23,9 @@ struct add_file_system_fixture { add_file_system_fixture& fixture; }; - boost::asio::io_context ctx; - using file_space_handler_t = file_space_handler; add_file_system_fixture() - : space_handler(mock_space_provider(*this), ctx) + : space_handler(mock_space_provider(*this)) { } diff --git a/plugins/resource_monitor_plugin/test/test_monitor_loop.cpp b/plugins/resource_monitor_plugin/test/test_monitor_loop.cpp deleted file mode 100644 index c48488f8fb..0000000000 --- a/plugins/resource_monitor_plugin/test/test_monitor_loop.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include - -#include - -using namespace eosio; -using namespace eosio::resource_monitor; -using namespace boost::system; - -struct space_handler_fixture { - struct mock_space_provider { - explicit mock_space_provider(space_handler_fixture& fixture) - :fixture(fixture) - {} - - int get_stat(const char *path, struct stat *buf) const { - return fixture.mock_get_stat(path, buf); - } - - std::filesystem::space_info get_space(const std::filesystem::path& p, std::error_code& ec) const { - return fixture.mock_get_space(p, ec); - } - - space_handler_fixture& fixture; - }; - - boost::asio::io_context ctx; - - using file_space_handler_t = file_space_handler; - space_handler_fixture() - : space_handler(mock_space_provider( *this ), ctx) - { - } - - void add_file_system(const std::filesystem::path& path_name) { - space_handler.add_file_system( path_name ); - } - - void set_threshold(uint32_t threshold, uint32_t warning_threshold) { - space_handler.set_threshold( threshold, warning_threshold ); - } - - void set_sleep_time(uint32_t sleep_time) { - space_handler.set_sleep_time( sleep_time ); - } - - void set_shutdown_on_exceeded(bool shutdown_on_exceeded) { - space_handler.set_shutdown_on_exceeded(shutdown_on_exceeded); - } - - bool is_threshold_exceeded() { - return space_handler.is_threshold_exceeded(); - } - - void space_monitor_loop() { - return space_handler.space_monitor_loop(); - } - - bool test_loop_common(int num_loops, int interval) - { - mock_get_space = [ i = 0, num_loops ]( const std::filesystem::path& p, std::error_code& ec) mutable -> std::filesystem::space_info { - ec = boost::system::errc::make_error_code(errc::success); - - std::filesystem::space_info rc{}; - rc.capacity = 1000000; - - if ( i < num_loops + 1 ) { // "+ 1" for the get_space in add_file_system - rc.available = 300000; - } else { - rc.available = 100000; - } - - i++; - - return rc; - }; - - mock_get_stat = []( const char *path, struct stat *buf ) -> int { - buf->st_dev = 0; - return 0; - }; - - set_threshold(80, 75); - set_shutdown_on_exceeded(true); - set_sleep_time(interval); - add_file_system("/test"); - - auto start = std::chrono::system_clock::now(); - - auto monitor_thread = std::thread( [this] { - space_monitor_loop(); - ctx.run(); - }); - - monitor_thread.join(); - - auto end = std::chrono::system_clock::now(); - std::chrono::duration test_duration = end - start; - - // For tests to be repeatable on any platforms under any loads, - // particularly for longer runs, - // we just make sure the test duration is longer than a margin - // of theroretical duration. - bool finished_in_time = (test_duration >= std::chrono::duration((num_loops - 1) * interval)); - - return finished_in_time; - } - - // fixture data and methods - std::function mock_get_space; - std::function mock_get_stat; - - file_space_handler_t space_handler; -}; - -BOOST_AUTO_TEST_SUITE(monitor_loop_tests) - BOOST_FIXTURE_TEST_CASE(zero_loop, space_handler_fixture) - { - BOOST_TEST( test_loop_common(0, 1) ); - } - - BOOST_FIXTURE_TEST_CASE(one_loop_1_secs_interval, space_handler_fixture) - { - BOOST_TEST( test_loop_common(1, 1) ); - } - - BOOST_FIXTURE_TEST_CASE(two_loops_1_sec_interval, space_handler_fixture) - { - BOOST_TEST( test_loop_common(2, 1) ); - } - - BOOST_FIXTURE_TEST_CASE(ten_loops_1_sec_interval, space_handler_fixture) - { - BOOST_TEST( test_loop_common(10, 1) ); - } - - BOOST_FIXTURE_TEST_CASE(one_loop_5_secs_interval, space_handler_fixture) - { - BOOST_TEST( test_loop_common(1, 5) ); - } - - BOOST_FIXTURE_TEST_CASE(two_loops_5_sec_interval, space_handler_fixture) - { - BOOST_TEST( test_loop_common(2, 5) ); - } - - BOOST_FIXTURE_TEST_CASE(five_loops_5_sec_interval, space_handler_fixture) - { - BOOST_TEST( test_loop_common(5, 5) ); - } - -BOOST_AUTO_TEST_SUITE_END() diff --git a/plugins/resource_monitor_plugin/test/test_threshold.cpp b/plugins/resource_monitor_plugin/test/test_threshold.cpp index b84261c50b..1a420d9976 100644 --- a/plugins/resource_monitor_plugin/test/test_threshold.cpp +++ b/plugins/resource_monitor_plugin/test/test_threshold.cpp @@ -23,11 +23,9 @@ struct threshold_fixture { threshold_fixture& fixture; }; - boost::asio::io_context ctx; - using file_space_handler_t = file_space_handler; threshold_fixture() - : space_handler(std::make_unique(mock_space_provider(*this), ctx)) + : space_handler(std::make_unique(mock_space_provider(*this))) { } @@ -49,7 +47,7 @@ struct threshold_fixture { bool test_threshold_common(std::map& available, std::map& dev, uint32_t warning_threshold=75) { bool first = test_threshold_common_(available, dev, warning_threshold); - space_handler = std::make_unique(mock_space_provider(*this), ctx); + space_handler = std::make_unique(mock_space_provider(*this)); test_absolute = true; bool second = test_threshold_common_(available, dev, warning_threshold); diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/session.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/session.hpp index 3d3c920af1..26af991d58 100644 --- a/plugins/state_history_plugin/include/eosio/state_history_plugin/session.hpp +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/session.hpp @@ -57,11 +57,15 @@ class session_manager { private: using entry_ptr = std::unique_ptr; + boost::asio::io_context& ship_io_context; std::set> session_set; bool sending = false; std::deque, entry_ptr>> send_queue; public: + explicit session_manager(boost::asio::io_context& ship_io_context) + : ship_io_context(ship_io_context) {} + void insert(std::shared_ptr s) { session_set.insert(std::move(s)); } @@ -103,8 +107,12 @@ class session_manager { void pop_entry(bool call_send = true) { send_queue.erase(send_queue.begin()); sending = false; - if (call_send || !send_queue.empty()) - send(); + if (call_send || !send_queue.empty()) { + // avoid blowing the stack + boost::asio::post(ship_io_context, [this]() { + send(); + }); + } } void send_updates() { diff --git a/plugins/state_history_plugin/state_history_plugin.cpp b/plugins/state_history_plugin/state_history_plugin.cpp index f117996f14..a779a50be0 100644 --- a/plugins/state_history_plugin/state_history_plugin.cpp +++ b/plugins/state_history_plugin/state_history_plugin.cpp @@ -62,7 +62,6 @@ struct state_history_plugin_impl : std::enable_shared_from_this thread_pool; + session_manager session_mgr{thread_pool.get_executor()}; + bool plugin_started = false; public: diff --git a/plugins/state_history_plugin/tests/session_test.cpp b/plugins/state_history_plugin/tests/session_test.cpp index c7b7be1ecc..63b260040c 100644 --- a/plugins/state_history_plugin/tests/session_test.cpp +++ b/plugins/state_history_plugin/tests/session_test.cpp @@ -101,20 +101,22 @@ struct mock_state_history_plugin { eosio::state_history::block_position block_head; fc::temp_directory log_dir; - std::optional log; + std::optional trace_log; + std::optional state_log; std::atomic stopping = false; - eosio::session_manager session_mgr; + eosio::session_manager session_mgr{ship_ioc}; constexpr static uint32_t default_frame_size = 1024; - std::optional& get_trace_log() { return log; } - std::optional& get_chain_state_log() { return log; } + std::optional& get_trace_log() { return trace_log; } + std::optional& get_chain_state_log() { return state_log; } fc::sha256 get_chain_id() const { return {}; } boost::asio::io_context& get_ship_executor() { return ship_ioc; } void setup_state_history_log(eosio::state_history_log_config conf = {}) { - log.emplace("ship", log_dir.path(), conf); + trace_log.emplace("ship_trace", log_dir.path(), conf); + state_log.emplace("ship_state", log_dir.path(), conf); } fc::logger logger = fc::logger::get(DEFAULT_LOGGER); @@ -130,7 +132,20 @@ struct mock_state_history_plugin { return fc::time_point{}; } - std::optional get_block_id(uint32_t block_num) { return block_id_for(block_num); } + std::optional get_block_id(uint32_t block_num) { + std::optional id; + if( trace_log ) { + id = trace_log->get_block_id( block_num ); + if( id ) + return id; + } + if( state_log ) { + id = state_log->get_block_id( block_num ); + if( id ) + return id; + } + return block_id_for(block_num); + } eosio::state_history::block_position get_block_head() { return block_head; } eosio::state_history::block_position get_last_irreversible() { return block_head; } @@ -284,13 +299,24 @@ struct state_history_test_fixture { header.payload_size += sizeof(uint64_t); } - server.log->write_entry(header, block_id_for(index - 1), [&](auto& f) { + std::unique_lock gt(server.trace_log->_mx); + server.trace_log->write_entry(header, block_id_for(index - 1), [&](auto& f) { f.write((const char*)&type, sizeof(type)); if (type == 1) { f.write((const char*)&decompressed_byte_count, sizeof(decompressed_byte_count)); } f.write(compressed.data(), compressed.size()); }); + gt.unlock(); + std::unique_lock gs(server.state_log->_mx); + server.state_log->write_entry(header, block_id_for(index - 1), [&](auto& f) { + f.write((const char*)&type, sizeof(type)); + if (type == 1) { + f.write((const char*)&decompressed_byte_count, sizeof(decompressed_byte_count)); + } + f.write(compressed.data(), compressed.size()); + }); + gs.unlock(); if (written_data.size() < index) written_data.resize(index); @@ -428,6 +454,62 @@ BOOST_FIXTURE_TEST_CASE(test_session_no_prune, state_history_test_fixture) { FC_LOG_AND_RETHROW() } +BOOST_FIXTURE_TEST_CASE(test_split_log, state_history_test_fixture) { + try { + // setup block head for the server + constexpr uint32_t head = 1023; + eosio::state_history::partition_config conf; + conf.stride = 25; + server.setup_state_history_log(conf); + uint32_t head_block_num = head; + server.block_head = {head_block_num, block_id_for(head_block_num)}; + + // generate the log data used for traces and deltas + uint32_t n = mock_state_history_plugin::default_frame_size; + add_to_log(1, n * sizeof(uint32_t), generate_data(n)); // original data format + add_to_log(2, 0, generate_data(n)); // format to accommodate the compressed size greater than 4GB + add_to_log(3, 1, generate_data(n)); // format to encode decompressed size to avoid decompress entire data upfront. + for (size_t i = 4; i <= head; ++i) { + add_to_log(i, 1, generate_data(n)); + } + + send_request(eosio::state_history::get_blocks_request_v0{.start_block_num = 1, + .end_block_num = UINT32_MAX, + .max_messages_in_flight = UINT32_MAX, + .have_positions = {}, + .irreversible_only = false, + .fetch_block = true, + .fetch_traces = true, + .fetch_deltas = true}); + + eosio::state_history::state_result result; + // we should get 1023 consecutive block result + eosio::chain::block_id_type prev_id; + for (int i = 0; i < head; ++i) { + receive_result(result); + BOOST_REQUIRE(std::holds_alternative(result)); + auto r = std::get(result); + BOOST_REQUIRE_EQUAL(r.head.block_num, server.block_head.block_num); + if (i > 0) { + BOOST_TEST(prev_id.str() == r.prev_block->block_id.str()); + } + prev_id = r.this_block->block_id; + BOOST_REQUIRE(r.traces.has_value()); + BOOST_REQUIRE(r.deltas.has_value()); + auto traces = r.traces.value(); + auto deltas = r.deltas.value(); + auto& data = written_data[i]; + auto data_size = data.size() * sizeof(int32_t); + BOOST_REQUIRE_EQUAL(traces.size(), data_size); + BOOST_REQUIRE_EQUAL(deltas.size(), data_size); + + BOOST_REQUIRE(std::equal(traces.begin(), traces.end(), (const char*)data.data())); + BOOST_REQUIRE(std::equal(deltas.begin(), deltas.end(), (const char*)data.data())); + } + } + FC_LOG_AND_RETHROW() +} + BOOST_FIXTURE_TEST_CASE(test_session_with_prune, state_history_test_fixture) { try { // setup block head for the server diff --git a/tests/PerformanceHarness/README.md b/tests/PerformanceHarness/README.md index 15c2fadc00..42ff944ef0 100644 --- a/tests/PerformanceHarness/README.md +++ b/tests/PerformanceHarness/README.md @@ -504,7 +504,7 @@ usage: PerformanceHarnessScenarioRunner.py findMax testBpOpMode overrideBasicTes [--cluster-log-lvl {all,debug,info,warn,error,off}] [--net-threads NET_THREADS] [--disable-subjective-billing DISABLE_SUBJECTIVE_BILLING] - [--cpu-effort-percent CPU_EFFORT_PERCENT] + [--produce-block-offset-ms PRODUCE_BLOCK_OFFSET_MS] [--producer-threads PRODUCER_THREADS] [--read-only-write-window-time-us READ_ONLY_WRITE_WINDOW_TIME_US] [--read-only-read-window-time-us READ_ONLY_READ_WINDOW_TIME_US] @@ -579,8 +579,9 @@ Performance Test Basic Base: Number of worker threads in net_plugin thread pool --disable-subjective-billing DISABLE_SUBJECTIVE_BILLING Disable subjective CPU billing for API/P2P transactions - --cpu-effort-percent CPU_EFFORT_PERCENT - Percentage of cpu block production time used to produce block. Whole number percentages, e.g. 80 for 80% + --produce-block-offset-ms PRODUCE_BLOCK_OFFSET_MS + The number of milliseconds early the last block of a production round should + be produced. --producer-threads PRODUCER_THREADS Number of worker threads in producer thread pool --read-only-write-window-time-us READ_ONLY_WRITE_WINDOW_TIME_US @@ -663,7 +664,7 @@ The following classes and scripts are typically used by the Performance Harness [--cluster-log-lvl {all,debug,info,warn,error,off}] [--net-threads NET_THREADS] [--disable-subjective-billing DISABLE_SUBJECTIVE_BILLING] - [--cpu-effort-percent CPU_EFFORT_PERCENT] + [--produce-block-offset-ms PRODUCE_BLOCK_OFFSET_MS] [--producer-threads PRODUCER_THREADS] [--http-max-in-flight-requests HTTP_MAX_IN_FLIGHT_REQUESTS] [--http-max-response-time-ms HTTP_MAX_RESPONSE_TIME_MS] @@ -742,8 +743,9 @@ Performance Test Basic Base: Number of worker threads in net_plugin thread pool (default: 4) --disable-subjective-billing DISABLE_SUBJECTIVE_BILLING Disable subjective CPU billing for API/P2P transactions (default: True) - --cpu-effort-percent CPU_EFFORT_PERCENT - Percentage of cpu block production time used to produce block. Whole number percentages, e.g. 80 for 80% (default: 100) + --produce-block-offset-ms PRODUCE_BLOCK_OFFSET_MS + The number of milliseconds early the last block of a production round should + be produced. --producer-threads PRODUCER_THREADS Number of worker threads in producer thread pool (default: 2) --http-max-in-flight-requests HTTP_MAX_IN_FLIGHT_REQUESTS @@ -1586,9 +1588,9 @@ Finally, the full detail test report for each of the determined max TPS throughp "greylistLimit": null, "_greylistLimitNodeosDefault": 1000, "_greylistLimitNodeosArg": "--greylist-limit", - "cpuEffortPercent": 100, - "_cpuEffortPercentNodeosDefault": 90, - "_cpuEffortPercentNodeosArg": "--cpu-effort-percent", + "produceBlockOffsetMs": 0, + "_produceBlockOffsetMsDefault": 450, + "_produceBlockOffsetMsArg": "--produce-block-offset-ms", "maxBlockCpuUsageThresholdUs": null, "_maxBlockCpuUsageThresholdUsNodeosDefault": 5000, "_maxBlockCpuUsageThresholdUsNodeosArg": "--max-block-cpu-usage-threshold-us", @@ -2246,9 +2248,9 @@ The Performance Test Basic generates, by default, a report that details results "greylistLimit": null, "_greylistLimitNodeosDefault": 1000, "_greylistLimitNodeosArg": "--greylist-limit", - "cpuEffortPercent": 100, - "_cpuEffortPercentNodeosDefault": 90, - "_cpuEffortPercentNodeosArg": "--cpu-effort-percent", + "produceBlockOffsetMs": 0, + "_produceBlockOffsetMsDefault": 450, + "_produceBlockOffsetMsArg": "--produce-block-offset-ms", "maxBlockCpuUsageThresholdUs": null, "_maxBlockCpuUsageThresholdUsNodeosDefault": 5000, "_maxBlockCpuUsageThresholdUsNodeosArg": "--max-block-cpu-usage-threshold-us", diff --git a/tests/PerformanceHarness/performance_test_basic.py b/tests/PerformanceHarness/performance_test_basic.py index 5fc66778b9..0d56329985 100755 --- a/tests/PerformanceHarness/performance_test_basic.py +++ b/tests/PerformanceHarness/performance_test_basic.py @@ -663,7 +663,7 @@ def setupClusterConfig(args) -> ClusterConfig: producerPluginArgs = ProducerPluginArgs(disableSubjectiveApiBilling=args.disable_subjective_billing, disableSubjectiveP2pBilling=args.disable_subjective_billing, - cpuEffortPercent=args.cpu_effort_percent, + produceBlockOffsetMs=args.produce_block_offset_ms, producerThreads=args.producer_threads, maxTransactionTime=-1, readOnlyWriteWindowTimeUs=args.read_only_write_window_time_us, readOnlyReadWindowTimeUs=args.read_only_read_window_time_us) @@ -720,7 +720,7 @@ def _createBaseArgumentParser(defEndpointApiDef: str, defProdNodeCnt: int, defVa choices=["all", "debug", "info", "warn", "error", "off"], default="info") ptbBaseParserGroup.add_argument("--net-threads", type=int, help=argparse.SUPPRESS if suppressHelp else "Number of worker threads in net_plugin thread pool", default=4) ptbBaseParserGroup.add_argument("--disable-subjective-billing", type=bool, help=argparse.SUPPRESS if suppressHelp else "Disable subjective CPU billing for API/P2P transactions", default=True) - ptbBaseParserGroup.add_argument("--cpu-effort-percent", type=int, help=argparse.SUPPRESS if suppressHelp else "Percentage of cpu block production time used to produce block. Whole number percentages, e.g. 80 for 80%%", default=100) + ptbBaseParserGroup.add_argument("--produce-block-offset-ms", type=int, help=argparse.SUPPRESS if suppressHelp else "The minimum time to reserve at the end of a production round for blocks to propagate to the next block producer.", default=0) ptbBaseParserGroup.add_argument("--producer-threads", type=int, help=argparse.SUPPRESS if suppressHelp else "Number of worker threads in producer thread pool", default=2) ptbBaseParserGroup.add_argument("--read-only-write-window-time-us", type=int, help=argparse.SUPPRESS if suppressHelp else "Time in microseconds the write window lasts.", default=200000) ptbBaseParserGroup.add_argument("--read-only-read-window-time-us", type=int, help=argparse.SUPPRESS if suppressHelp else "Time in microseconds the read window lasts.", default=60000) diff --git a/tests/p2p_high_latency_test.py b/tests/p2p_high_latency_test.py index 861fade6a0..2b8028209c 100644 --- a/tests/p2p_high_latency_test.py +++ b/tests/p2p_high_latency_test.py @@ -68,8 +68,7 @@ def exec(cmd): try: TestHelper.printSystemInfo("BEGIN") - traceNodeosArgs=" --plugin eosio::producer_plugin --produce-time-offset-us 0 --last-block-time-offset-us 0 --cpu-effort-percent 100 \ - --last-block-cpu-effort-percent 100 --producer-threads 1 --plugin eosio::net_plugin --net-threads 1" + traceNodeosArgs=" --plugin eosio::producer_plugin --produce-block-offset-ms 0 --producer-threads 1 --plugin eosio::net_plugin --net-threads 1" if cluster.launch(pnodes=1, totalNodes=totalNodes, totalProducers=1, specificExtraNodeosArgs=specificExtraNodeosArgs, extraNodeosArgs=traceNodeosArgs) is False: Utils.cmdError("launcher") Utils.errorExit("Failed to stand up eos cluster.") diff --git a/tests/resource_monitor_plugin_test.py b/tests/resource_monitor_plugin_test.py index 5b53793620..4370d529dc 100755 --- a/tests/resource_monitor_plugin_test.py +++ b/tests/resource_monitor_plugin_test.py @@ -23,6 +23,7 @@ stderrFile=dataDir + "/stderr.txt" testNum=0 +max_start_time_secs=10 # time nodeos takes to start # We need debug level to get more information about nodeos process logging="""{ @@ -105,7 +106,7 @@ def testCommon(title, extraNodeosArgs, expectedMsgs): prepareDirectories() - timeout=120 # Leave sufficient time such nodeos can start up fully in any platforms + timeout=max_start_time_secs # Leave sufficient time such nodeos can start up fully in any platforms runNodeos(extraNodeosArgs, timeout) for msg in expectedMsgs: @@ -156,7 +157,7 @@ def testInterval(title, extraNodeosArgs, interval, expectedMsgs, warningThreshol prepareDirectories() fillFS(dataDir, warningThreshold) - timeout = 120 + interval * 2 # Leave sufficient time so nodeos can start up fully in any platforms, and at least two warnings can be output + timeout = max_start_time_secs + interval * 2 # Leave sufficient time so nodeos can start up fully in any platforms, and at least two warnings can be output if timeout > testIntervalMaxTimeout: errorExit ("Max timeout for testInterval is %d sec" % (testIntervalMaxTimeout)) runNodeos(extraNodeosArgs, timeout) @@ -169,15 +170,15 @@ def testInterval(title, extraNodeosArgs, interval, expectedMsgs, warningThreshol errorExit ("Log containing \"%s\" should be output every %d seconds" % (msg, interval)) def testAll(): - testCommon("Resmon enabled: all arguments", "--plugin eosio::resource_monitor_plugin --resource-monitor-space-threshold=85 --resource-monitor-interval-seconds=5 --resource-monitor-not-shutdown-on-threshold-exceeded", ["threshold set to 85", "interval set to 5", "Shutdown flag when threshold exceeded set to false", "Creating and starting monitor thread"]) + testCommon("Resmon enabled: all arguments", "--plugin eosio::resource_monitor_plugin --resource-monitor-space-threshold=85 --resource-monitor-interval-seconds=5 --resource-monitor-not-shutdown-on-threshold-exceeded", ["threshold set to 85", "interval set to 5", "Shutdown flag when threshold exceeded set to false"]) # default arguments and default directories to be monitored - testCommon("Resmon not enabled: no arguments", "", ["interval set to 2", "threshold set to 90", "Shutdown flag when threshold exceeded set to true", "Creating and starting monitor thread", "snapshots's file system to be monitored", "blocks's file system to be monitored", "state's file system to be monitored"]) + testCommon("Resmon not enabled: no arguments", "", ["interval set to 2", "threshold set to 90", "Shutdown flag when threshold exceeded set to true", "snapshots's file system to be monitored", "blocks's file system to be monitored", "state's file system to be monitored"]) # default arguments with registered directories - testCommon("Resmon not enabled: Producer, Chain, State History and Trace Api", "--plugin eosio::state_history_plugin --state-history-dir=/tmp/state-history --plugin eosio::trace_api_plugin --trace-dir=/tmp/trace --trace-no-abis", ["interval set to 2", "threshold set to 90", "Shutdown flag when threshold exceeded set to true", "snapshots's file system to be monitored", "blocks's file system to be monitored", "state's file system to be monitored", "state-history's file system to be monitored", "trace's file system to be monitored", "Creating and starting monitor thread"]) + testCommon("Resmon not enabled: Producer, Chain, State History and Trace Api", "--plugin eosio::state_history_plugin --state-history-dir=/tmp/state-history --disable-replay-opts --plugin eosio::trace_api_plugin --trace-dir=/tmp/trace --trace-no-abis", ["interval set to 2", "threshold set to 90", "Shutdown flag when threshold exceeded set to true", "snapshots's file system to be monitored", "blocks's file system to be monitored", "state's file system to be monitored", "state-history's file system to be monitored", "trace's file system to be monitored"]) - testCommon("Resmon enabled: Producer, Chain, State History and Trace Api", "--plugin eosio::resource_monitor_plugin --plugin eosio::state_history_plugin --state-history-dir=/tmp/state-history --plugin eosio::trace_api_plugin --trace-dir=/tmp/trace --trace-no-abis --resource-monitor-space-threshold=80 --resource-monitor-interval-seconds=3", ["snapshots's file system to be monitored", "blocks's file system to be monitored", "state's file system to be monitored", "state-history's file system to be monitored", "trace's file system to be monitored", "Creating and starting monitor thread", "threshold set to 80", "interval set to 3", "Shutdown flag when threshold exceeded set to true"]) + testCommon("Resmon enabled: Producer, Chain, State History and Trace Api", "--plugin eosio::resource_monitor_plugin --plugin eosio::state_history_plugin --state-history-dir=/tmp/state-history --disable-replay-opts --plugin eosio::trace_api_plugin --trace-dir=/tmp/trace --trace-no-abis --resource-monitor-space-threshold=80 --resource-monitor-interval-seconds=3", ["snapshots's file system to be monitored", "blocks's file system to be monitored", "state's file system to be monitored", "state-history's file system to be monitored", "trace's file system to be monitored", "threshold set to 80", "interval set to 3", "Shutdown flag when threshold exceeded set to true"]) # Only test minimum warning threshold (i.e. 6) to trigger warning as much as possible testInterval("Resmon enabled: set warning interval", diff --git a/tests/ship_streamer_test.py b/tests/ship_streamer_test.py index e5710c5e36..710ab90db4 100755 --- a/tests/ship_streamer_test.py +++ b/tests/ship_streamer_test.py @@ -70,7 +70,7 @@ def getLatestSnapshot(nodeId): shipNodeNum = 1 specificExtraNodeosArgs={} - specificExtraNodeosArgs[shipNodeNum]="--plugin eosio::state_history_plugin --trace-history --chain-state-history --plugin eosio::net_api_plugin --plugin eosio::producer_api_plugin " + specificExtraNodeosArgs[shipNodeNum]="--plugin eosio::state_history_plugin --trace-history --chain-state-history --state-history-stride 200 --plugin eosio::net_api_plugin --plugin eosio::producer_api_plugin " # producer nodes will be mapped to 0 through totalProducerNodes-1, so the number totalProducerNodes will be the non-producing node specificExtraNodeosArgs[totalProducerNodes]="--plugin eosio::test_control_api_plugin " @@ -206,7 +206,7 @@ def getLatestSnapshot(nodeId): prodNode0.waitForProducer(forkAtProducer) prodNode1.waitForProducer(prodNode1Prod) if nonProdNode.verifyAlive(): - Utils.errorExit("Bridge did not shutdown"); + Utils.errorExit("Bridge did not shutdown") Print("Fork started") forkProgress="defproducer" + chr(ord(forkAtProducer[-1])+3) @@ -215,7 +215,7 @@ def getLatestSnapshot(nodeId): Print("Restore fork") Print("Relaunching the non-producing bridge node to connect the producing nodes again") if nonProdNode.verifyAlive(): - Utils.errorExit("Bridge is already running"); + Utils.errorExit("Bridge is already running") if not nonProdNode.relaunch(): Utils.errorExit(f"Failure - (non-production) node {nonProdNode.nodeNum} should have restarted") diff --git a/tests/test_read_only_trx.cpp b/tests/test_read_only_trx.cpp index 636c7228c7..27a6c6be1e 100644 --- a/tests/test_read_only_trx.cpp +++ b/tests/test_read_only_trx.cpp @@ -204,6 +204,9 @@ BOOST_AUTO_TEST_CASE(with_3_read_only_threads) { BOOST_AUTO_TEST_CASE(with_3_read_only_threads_no_tierup) { std::vector specific_args = { "-p", "eosio", "-e", "--read-only-threads=3", +#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED + "--eos-vm-oc-enable=none", +#endif "--max-transaction-time=10", "--abi-serializer-max-time-ms=999", "--read-only-write-window-time-us=100000", @@ -215,7 +218,6 @@ BOOST_AUTO_TEST_CASE(with_3_read_only_threads_no_tierup) { BOOST_AUTO_TEST_CASE(with_8_read_only_threads) { std::vector specific_args = { "-p", "eosio", "-e", "--read-only-threads=8", - "--eos-vm-oc-enable=none", "--max-transaction-time=10", "--abi-serializer-max-time-ms=999", "--read-only-write-window-time-us=10000", @@ -227,7 +229,9 @@ BOOST_AUTO_TEST_CASE(with_8_read_only_threads) { BOOST_AUTO_TEST_CASE(with_8_read_only_threads_no_tierup) { std::vector specific_args = { "-p", "eosio", "-e", "--read-only-threads=8", +#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED "--eos-vm-oc-enable=none", +#endif "--max-transaction-time=10", "--abi-serializer-max-time-ms=999", "--read-only-write-window-time-us=10000",