From 097e7454b3301fd48f6ed8c89a20ecef407ba767 Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Mon, 22 Apr 2019 11:54:27 -0400 Subject: [PATCH] evict wasm_cache entries once the last block they are used in becomes irreversible the wasm_cache needs to be periodically pruned of old entries. controller will now note to wasm_interface when the reference count of some code_hash goes to 0 and wasm_interface will then evict those entries once that block becomes irreversible. Unfortunately there are still many corner cases that can cause items in the cache to never be evicted or evicted too soon, but some reasonably accurate eviction is direly needed for long replays so this is considered good enough for now --- libraries/chain/controller.cpp | 4 ++++ libraries/chain/eosio_contract.cpp | 1 + .../chain/include/eosio/chain/wasm_interface.hpp | 6 ++++++ .../include/eosio/chain/wasm_interface_private.hpp | 13 +++++++++++++ libraries/chain/wasm_interface.cpp | 8 ++++++++ 5 files changed, 32 insertions(+) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index bafe7933e9d..1b1f914db2d 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -313,6 +313,10 @@ struct controller_impl { set_activation_handler(); set_activation_handler(); + self.irreversible_block.connect([this](const block_state_ptr& bsp) { + wasmif.current_lib(bsp->block_num); + }); + #define SET_APP_HANDLER( receiver, contract, action) \ set_apply_handler( #receiver, #contract, #action, &BOOST_PP_CAT(apply_, BOOST_PP_CAT(contract, BOOST_PP_CAT(_,action) ) ) ) diff --git a/libraries/chain/eosio_contract.cpp b/libraries/chain/eosio_contract.cpp index 1fe849abb48..4a18406ee02 100644 --- a/libraries/chain/eosio_contract.cpp +++ b/libraries/chain/eosio_contract.cpp @@ -160,6 +160,7 @@ void apply_eosio_setcode(apply_context& context) { old_size = (int64_t)old_code_entry.code.size() * config::setcode_ram_bytes_multiplier; if( old_code_entry.code_ref_count == 1 ) { db.remove(old_code_entry); + context.control.get_wasm_interface().code_block_num_last_used(account.code_hash, account.vm_type, account.vm_version, context.control.head_block_num() + 1); } else { db.modify(old_code_entry, [](code_object& o) { --o.code_ref_count; diff --git a/libraries/chain/include/eosio/chain/wasm_interface.hpp b/libraries/chain/include/eosio/chain/wasm_interface.hpp index 5ddea081d48..b5749179a9b 100644 --- a/libraries/chain/include/eosio/chain/wasm_interface.hpp +++ b/libraries/chain/include/eosio/chain/wasm_interface.hpp @@ -82,6 +82,12 @@ namespace eosio { namespace chain { //validates code -- does a WASM validation pass and checks the wasm against EOSIO specific constraints static void validate(const controller& control, const bytes& code); + //indicate that a particular code probably won't be used after given block_num + void code_block_num_last_used(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version, const uint32_t& block_num); + + //indicate the current LIB. evicts old cache entries + void current_lib(const uint32_t lib); + //Calls apply or error on a given code void apply(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version, apply_context& context); diff --git a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp index 362a29e19f0..2f59bccf69f 100644 --- a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp +++ b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp @@ -64,6 +64,19 @@ namespace eosio { namespace chain { return mem_image; } + void code_block_num_last_used(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version, const uint32_t& block_num) { + wasm_cache_index::iterator it = wasm_instantiation_cache.find(boost::make_tuple(code_hash, vm_type, vm_version)); + if(it != wasm_instantiation_cache.end()) + wasm_instantiation_cache.modify(it, [block_num](wasm_cache_entry& e) { + e.last_block_num_used = block_num; + }); + } + + void current_lib(uint32_t lib) { + //anything last used before or on the LIB can be evicted + wasm_instantiation_cache.get().erase(wasm_instantiation_cache.get().begin(), wasm_instantiation_cache.get().upper_bound(lib)); + } + const std::unique_ptr& get_instantiated_module( const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version, transaction_context& trx_context ) { diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index 9fd144a3cb1..75682ff4b80 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -57,6 +57,14 @@ namespace eosio { namespace chain { //Hard: Kick off instantiation in a separate thread at this location } + void wasm_interface::code_block_num_last_used(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version, const uint32_t& block_num) { + my->code_block_num_last_used(code_hash, vm_type, vm_version, block_num); + } + + void wasm_interface::current_lib(const uint32_t lib) { + my->current_lib(lib); + } + void wasm_interface::apply( const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version, apply_context& context ) { my->get_instantiated_module(code_hash, vm_type, vm_version, context.trx_context)->apply(context); }