diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 112460107a..c018e2e93f 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1359,8 +1359,6 @@ struct controller_impl { // When in IRREVERSIBLE mode fork_db blocks are applied and marked valid when they become irreversible template controller::apply_blocks_result apply_irreversible_block(ForkDB& fork_db, const BSP& bsp) { - if (read_mode != db_read_mode::IRREVERSIBLE) - return controller::apply_blocks_result::complete; // ignore if constexpr (std::is_same_v>) { // before transition to savanna return apply_block(bsp, controller::block_status::complete, trx_meta_cache_lookup{}); @@ -1544,6 +1542,8 @@ struct controller_impl { if( new_lib_num <= lib_num ) return; + const fc::time_point start = fc::time_point::now(); + auto mark_branch_irreversible = [&, this](auto& fork_db) { assert(!irreversible_mode() || fork_db.head()); const auto& head_id = irreversible_mode() ? fork_db.head()->id() : chain_head.id(); @@ -1563,27 +1563,39 @@ struct controller_impl { // irreversible. Instead, this moves irreversible as much as possible and allows the next maybe_switch_forks call to apply these // non-validated blocks. After the maybe_switch_forks call (before next produced block or on next received block), irreversible // can then move forward on the then validated blocks. - return read_mode == db_read_mode::IRREVERSIBLE || bsp->is_valid(); + // In irreversible mode, break every ~500ms to allow other tasks (e.g. get_info, SHiP) opportunity to run. There is a post + // for every incoming blocks; enough posted tasks to apply all blocks queued to the fork db. + if (irreversible_mode()) { + if (!replaying && fc::time_point::now() - start > fc::milliseconds(500)) + return false; + return true; + } + return bsp->is_valid(); }; - std::vector>> v; - v.reserve( branch.size() ); - for( auto bitr = branch.rbegin(); bitr != branch.rend() && should_process(*bitr); ++bitr ) { - - v.emplace_back( post_async_task( thread_pool.get_executor(), [b=(*bitr)->block]() { return fc::raw::pack(*b); } ) ); + using packed_block_future = std::future>; + std::vector v; + if (!irreversible_mode()) { + v.reserve( branch.size() ); + for( auto bitr = branch.rbegin(); bitr != branch.rend() && should_process(*bitr); ++bitr ) { + v.emplace_back( post_async_task( thread_pool.get_executor(), [b=(*bitr)->block]() { return fc::raw::pack(*b); } ) ); + } } auto it = v.begin(); for( auto bitr = branch.rbegin(); bitr != branch.rend() && should_process(*bitr); ++bitr ) { - if (apply_irreversible_block(fork_db, *bitr) != controller::apply_blocks_result::complete) - break; + packed_block_future f; + if (irreversible_mode()) { + f = post_async_task( thread_pool.get_executor(), [b=(*bitr)->block]() { return fc::raw::pack(*b); } ); + if (apply_irreversible_block(fork_db, *bitr) != controller::apply_blocks_result::complete) + break; + } emit( irreversible_block, std::tie((*bitr)->block, (*bitr)->id()), __FILE__, __LINE__ ); // blog.append could fail due to failures like running out of space. // Do it before commit so that in case it throws, DB can be rolled back. - blog.append( (*bitr)->block, (*bitr)->id(), it->get() ); - ++it; + blog.append( (*bitr)->block, (*bitr)->id(), irreversible_mode() ? f.get() : it++->get() ); db.commit( (*bitr)->block_num() ); root_id = (*bitr)->id(); @@ -1595,13 +1607,14 @@ struct controller_impl { } } catch( const std::exception& e ) { try { + elog("Caught exception while logging irreversible: ${e}", ("e", e.what())); if (root_id != fork_db.root()->id()) { fork_db.advance_root(root_id); } } catch( const fc::exception& e2 ) { - wlog("Caught exception ${e2}, while processing exception ${e}", ("e2", e2.to_detail_string())("e", e.what())); + elog("Caught exception ${e2}, while processing exception ${e}", ("e2", e2.to_detail_string())("e", e.what())); } catch( const std::exception& e2 ) { - wlog("Caught exception ${e2}, while processing exception ${e}", ("e2", e2.what())("e", e.what())); + elog("Caught exception ${e2}, while processing exception ${e}", ("e2", e2.what())("e", e.what())); } throw; } @@ -4948,7 +4961,7 @@ struct controller_impl { } bool should_terminate() const { - return should_terminate(chain_head.block_num()); + return should_terminate(chain_head.block_num()) || check_shutdown(); } bool should_pause() const { diff --git a/tests/interrupt_trx_test.py b/tests/interrupt_trx_test.py index 7350631849..72b5e270b0 100755 --- a/tests/interrupt_trx_test.py +++ b/tests/interrupt_trx_test.py @@ -109,6 +109,7 @@ trans=prodNode.pushMessage(contract, action, data, opts) assert trans and trans[0], "Failed to push doitslow action" + assert prodNode.waitForHeadToAdvance(blocksToAdvance=3), "prodNode not advancing head after doitforever action" assert prodNode.waitForLibToAdvance(), "prodNode did not advance lib after doitforever action" assert prodNode2.waitForLibToAdvance(), "prodNode2 did not advance lib after doitforever action"