diff --git a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/code_cache.hpp b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/code_cache.hpp index fe7ff49788..d753a9dcaa 100644 --- a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/code_cache.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/code_cache.hpp @@ -15,7 +15,6 @@ #include -#include namespace std { template<> struct hash { @@ -39,7 +38,7 @@ struct config; class code_cache_base { public: - code_cache_base(const std::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, const chainbase::database& db); + code_cache_base(const std::filesystem::path& data_dir, const eosvmoc::config& eosvmoc_config, const chainbase::database& db); ~code_cache_base(); const int& fd() const { return _cache_fd; } @@ -78,9 +77,20 @@ class code_cache_base { local::datagram_protocol::socket _compile_monitor_write_socket{_ctx}; local::datagram_protocol::socket _compile_monitor_read_socket{_ctx}; - //these are really only useful to the async code cache, but keep them here so - //free_code can be shared - std::unordered_set _queued_compiles; + //these are really only useful to the async code cache, but keep them here so free_code can be shared + using queued_compilies_t = boost::multi_index_container< + code_tuple, + indexed_by< + sequenced<>, + hashed_unique, + composite_key< code_tuple, + member, + member + > + > + > + >; + queued_compilies_t _queued_compiles; std::unordered_map _outstanding_compiles_and_poison; size_t _free_bytes_eviction_threshold; @@ -95,13 +105,13 @@ class code_cache_base { class code_cache_async : public code_cache_base { public: - code_cache_async(const std::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, const chainbase::database& db); + code_cache_async(const std::filesystem::path& data_dir, const eosvmoc::config& eosvmoc_config, const chainbase::database& db); ~code_cache_async(); //If code is in cache: returns pointer & bumps to front of MRU list //If code is not in cache, and not blacklisted, and not currently compiling: return nullptr and kick off compile //otherwise: return nullptr - const code_descriptor* const get_descriptor_for_code(const digest_type& code_id, const uint8_t& vm_version, bool is_write_window, get_cd_failure& failure); + const code_descriptor* const get_descriptor_for_code(bool high_priority, const digest_type& code_id, const uint8_t& vm_version, bool is_write_window, get_cd_failure& failure); private: std::thread _monitor_reply_thread; diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index 33bb863dbc..668fdb81a4 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -94,7 +94,8 @@ namespace eosio { namespace chain { const chain::eosvmoc::code_descriptor* cd = nullptr; chain::eosvmoc::code_cache_base::get_cd_failure failure = chain::eosvmoc::code_cache_base::get_cd_failure::temporary; try { - cd = my->eosvmoc->cc.get_descriptor_for_code(code_hash, vm_version, context.control.is_write_window(), failure); + const bool high_priority = context.get_receiver().prefix() == chain::config::system_account_name; + cd = my->eosvmoc->cc.get_descriptor_for_code(high_priority, code_hash, vm_version, context.control.is_write_window(), failure); } catch(...) { //swallow errors here, if EOS VM OC has gone in to the weeds we shouldn't bail: continue to try and run baseline 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 2576b46f96..37eca74914 100644 --- a/libraries/chain/webassembly/runtimes/eos-vm-oc/code_cache.cpp +++ b/libraries/chain/webassembly/runtimes/eos-vm-oc/code_cache.cpp @@ -38,7 +38,7 @@ static constexpr size_t descriptor_ptr_from_file_start = header_offset + offseto static_assert(sizeof(code_cache_header) <= header_size, "code_cache_header too big"); -code_cache_async::code_cache_async(const std::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, const chainbase::database& db) : +code_cache_async::code_cache_async(const std::filesystem::path& data_dir, const eosvmoc::config& eosvmoc_config, const chainbase::database& db) : code_cache_base(data_dir, eosvmoc_config, db), _result_queue(eosvmoc_config.threads * 2), _threads(eosvmoc_config.threads) @@ -106,7 +106,7 @@ std::tuple code_cache_async::consume_compile_thread_queue() { } -const code_descriptor* const code_cache_async::get_descriptor_for_code(const digest_type& code_id, const uint8_t& vm_version, bool is_write_window, get_cd_failure& failure) { +const code_descriptor* const code_cache_async::get_descriptor_for_code(bool high_priority, const digest_type& code_id, const uint8_t& vm_version, bool is_write_window, get_cd_failure& failure) { //if there are any outstanding compiles, process the result queue now //When app is in write window, all tasks are running sequentially and read-only threads //are not running. Safe to update cache entries. @@ -156,13 +156,16 @@ const code_descriptor* const code_cache_async::get_descriptor_for_code(const dig it->second = false; return nullptr; } - if(_queued_compiles.find(ct) != _queued_compiles.end()) { + if(auto it = _queued_compiles.get().find(boost::make_tuple(std::ref(code_id), vm_version)); it != _queued_compiles.get().end()) { failure = get_cd_failure::temporary; // Compile might not be done yet return nullptr; } if(_outstanding_compiles_and_poison.size() >= _threads) { - _queued_compiles.emplace(ct); + if (high_priority) + _queued_compiles.push_front(ct); + else + _queued_compiles.push_back(ct); failure = get_cd_failure::temporary; // Compile might not be done yet return nullptr; } @@ -221,7 +224,7 @@ const code_descriptor* const code_cache_sync::get_descriptor_for_code_sync(const return &*_cache_index.push_front(std::move(std::get(result.result))).first; } -code_cache_base::code_cache_base(const std::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, const chainbase::database& db) : +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") { @@ -377,7 +380,8 @@ void code_cache_base::free_code(const digest_type& code_id, const uint8_t& vm_ve } //if it's in the queued list, erase it - _queued_compiles.erase({code_id, vm_version}); + if(auto i = _queued_compiles.get().find(boost::make_tuple(std::ref(code_id), vm_version)); i != _queued_compiles.get().end()) + _queued_compiles.get().erase(i); //however, if it's currently being compiled there is no way to cancel the compile, //so instead set a poison boolean that indicates not to insert the code in to the cache