From d9c7a2ac08d9d0108f34837fb7fb33f53fc08741 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 20 May 2025 20:08:24 +0300 Subject: [PATCH 1/4] get_coinbase_hash_cached refactored --- src/currency_core/blockchain_storage.cpp | 9 +++- src/currency_core/blockchain_storage_basic.h | 55 +++++++++++++++++--- 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 63bee8a0..ad7b4ea4 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -3838,7 +3838,14 @@ bool blockchain_storage::find_blockchain_supplement(const std::list mis; get_transactions_direct(m_db_blocks[i]->bl.tx_hashes, blocks.back().second, mis); CHECK_AND_ASSERT_MES(!mis.size(), false, "internal error, block " << get_block_hash(m_db_blocks[i]->bl) << " [" << i << "] contains missing transactions: " << mis); - blocks.back().third = m_db_transactions.find(get_coinbase_hash_cached(*m_db_blocks[i])); + //blocks.back().third = m_db_transactions.find(get_coinbase_hash_cached(*m_db_blocks[i])); + + crypto::hash coinbase_hash = get_coinbase_hash_cached(*m_db_blocks[i]); + blocks.back().third = m_db_transactions.find(coinbase_hash); + if (!blocks.back().third) + { + LOG_PRINT_YELLOW("m_db_transactions.find failed for coinbase hash: " << coinbase_hash << ", height: " << i, LOG_LEVEL_0); + } } return true; } diff --git a/src/currency_core/blockchain_storage_basic.h b/src/currency_core/blockchain_storage_basic.h index efeb2759..891c314d 100644 --- a/src/currency_core/blockchain_storage_basic.h +++ b/src/currency_core/blockchain_storage_basic.h @@ -77,6 +77,28 @@ namespace currency // This is an optional data fields, It is not included in serialization and therefore is never stored in the database. // It might be calculated "on the fly" to speed up access operations. mutable std::shared_ptr m_cache_coinbase_id; + mutable std::atomic m_cache_coinbase_state{0}; + + block_extended_info& operator=(const block_extended_info& rhs) + { + this->bl = rhs.bl; + this->height = rhs.height; + this->block_cumulative_size = rhs.block_cumulative_size; + this->cumulative_diff_adjusted = rhs.cumulative_diff_adjusted; + this->cumulative_diff_precise = rhs.cumulative_diff_precise; + this->cumulative_diff_precise_adjusted = rhs.cumulative_diff_precise_adjusted; + this->difficulty = rhs.difficulty; + this->already_generated_coins = rhs.already_generated_coins; + this->stake_hash = rhs.stake_hash; + this->version = rhs.version; + this->this_block_tx_fee_median = rhs.this_block_tx_fee_median; + this->effective_tx_fee_median = rhs.effective_tx_fee_median; + this->m_cache_coinbase_id.reset(); + this->m_cache_coinbase_state = 0; + return *this; + } + block_extended_info(const block_extended_info& rhs) { *this = rhs; } + block_extended_info() = default; }; struct gindex_increment @@ -194,14 +216,31 @@ namespace currency inline crypto::hash get_coinbase_hash_cached(const block_extended_info& bei) - { - std::shared_ptr local_coinbase_id = bei.m_cache_coinbase_id; - if (!local_coinbase_id) - { - bei.m_cache_coinbase_id = std::make_shared(get_transaction_hash(bei.bl.miner_tx)); - local_coinbase_id = bei.m_cache_coinbase_id; - } - return *local_coinbase_id; + { + // bei.m_cache_coinbase_state : 0 -- m_cache_coinbase_id is empty + // 1 -- m_cache_coinbase_id is calculating and writing + // 2 -- m_cache_coinbase_id is ready to read + if (bei.m_cache_coinbase_state == 2) + { + // state is 2, cache must be ready, access the cache + std::shared_ptr local_coinbase_id = bei.m_cache_coinbase_id; + CHECK_AND_ASSERT_THROW_MES(local_coinbase_id, "internal error: m_cache_coinbase_id is empty"); + return *local_coinbase_id; + } + + uint8_t state = 0; + if (bei.m_cache_coinbase_state.compare_exchange_strong(state, 1)) + { + // state has just been 0, now 1, we're calculating + std::shared_ptr ptr_h = std::make_shared(get_transaction_hash(bei.bl.miner_tx)); + bei.m_cache_coinbase_id = ptr_h; + bei.m_cache_coinbase_state = 2; + return *ptr_h; + } + + // state is 1, another thread is calculating, so we calculate locally and don't touch the cache + crypto::hash h = get_transaction_hash(bei.bl.miner_tx); + return h; } } // namespace currency From 4be5761a90f4671a25380e562ea8a7c935baa8d0 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 21 May 2025 04:32:16 +0300 Subject: [PATCH 2/4] epee::misc_utils::void_copy introduced --- contrib/epee/include/misc_language.h | 12 ++++++++++ src/currency_core/blockchain_storage_basic.h | 25 ++------------------ 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/contrib/epee/include/misc_language.h b/contrib/epee/include/misc_language.h index dd599cf8..04cb9750 100644 --- a/contrib/epee/include/misc_language.h +++ b/contrib/epee/include/misc_language.h @@ -627,6 +627,18 @@ namespace misc_utils }; + // helper class mainly intended for using with std::atomic to repair copy-construction in classes where std::atomic is aggregated + template + struct void_copy : public parent_t + { + void_copy() = default; + void_copy(void_copy&&) noexcept = default; + void_copy& operator=(void_copy&&) noexcept = default; + + void_copy(const void_copy&) : parent_t{} {} + void_copy& operator=(const void_copy&) { return *this; } + }; + } // namespace misc_utils } // namespace epee diff --git a/src/currency_core/blockchain_storage_basic.h b/src/currency_core/blockchain_storage_basic.h index 891c314d..9593a2d5 100644 --- a/src/currency_core/blockchain_storage_basic.h +++ b/src/currency_core/blockchain_storage_basic.h @@ -77,28 +77,7 @@ namespace currency // This is an optional data fields, It is not included in serialization and therefore is never stored in the database. // It might be calculated "on the fly" to speed up access operations. mutable std::shared_ptr m_cache_coinbase_id; - mutable std::atomic m_cache_coinbase_state{0}; - - block_extended_info& operator=(const block_extended_info& rhs) - { - this->bl = rhs.bl; - this->height = rhs.height; - this->block_cumulative_size = rhs.block_cumulative_size; - this->cumulative_diff_adjusted = rhs.cumulative_diff_adjusted; - this->cumulative_diff_precise = rhs.cumulative_diff_precise; - this->cumulative_diff_precise_adjusted = rhs.cumulative_diff_precise_adjusted; - this->difficulty = rhs.difficulty; - this->already_generated_coins = rhs.already_generated_coins; - this->stake_hash = rhs.stake_hash; - this->version = rhs.version; - this->this_block_tx_fee_median = rhs.this_block_tx_fee_median; - this->effective_tx_fee_median = rhs.effective_tx_fee_median; - this->m_cache_coinbase_id.reset(); - this->m_cache_coinbase_state = 0; - return *this; - } - block_extended_info(const block_extended_info& rhs) { *this = rhs; } - block_extended_info() = default; + mutable epee::misc_utils::void_copy> m_cache_coinbase_state; }; struct gindex_increment @@ -235,7 +214,7 @@ namespace currency // state has just been 0, now 1, we're calculating std::shared_ptr ptr_h = std::make_shared(get_transaction_hash(bei.bl.miner_tx)); bei.m_cache_coinbase_id = ptr_h; - bei.m_cache_coinbase_state = 2; + bei.m_cache_coinbase_state.store(2); return *ptr_h; } From cc9e39825c853ff80014d20013142e8926a99f5f Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 21 May 2025 04:33:24 +0300 Subject: [PATCH 3/4] cache_helper/cache_base fixed and improved --- contrib/epee/include/cache_helper.h | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/contrib/epee/include/cache_helper.h b/contrib/epee/include/cache_helper.h index 416b58bd..7d42fe73 100644 --- a/contrib/epee/include/cache_helper.h +++ b/contrib/epee/include/cache_helper.h @@ -98,7 +98,11 @@ namespace epee if (it == data.end()) return false; - most_recet_acessed.splice(most_recet_acessed.begin(), most_recet_acessed, it->second.second); + //most_recet_acessed.splice(most_recet_acessed.begin(), most_recet_acessed, it->second.second); + most_recet_acessed.erase(it->second.second); + most_recet_acessed.push_front(k); + it->second.second = most_recet_acessed.begin(); + v = it->second.first; return true; } @@ -106,8 +110,18 @@ namespace epee bool set(const t_key& k, const t_value& v) { CRITICAL_REGION_LOCAL(m_lock); - most_recet_acessed.push_front(k); - data[k] = std::pair::iterator>(v, most_recet_acessed.begin()); + auto it = data.find(k); + if (it == data.end()) + { + most_recet_acessed.push_front(k); + data.insert(std::make_pair(k, std::make_pair(v, most_recet_acessed.begin()))); + } + else + { + most_recet_acessed.erase(it->second.second); + most_recet_acessed.push_front(k); + it->second.second = most_recet_acessed.begin(); + } trim(); return true; @@ -248,7 +262,10 @@ namespace epee bool erase(const t_key& k) { - return m_isolation.isolated_write_access([&](){return base_class::erase(k); }); + return m_isolation.isolated_write_access([&]() + { + return base_class::erase(k); + }); } }; From d9116735440a8efc7b91e67760c044d9f812a662 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 21 May 2025 04:47:39 +0300 Subject: [PATCH 4/4] cache_base: typo fixed --- contrib/epee/include/cache_helper.h | 33 +++++++++++++++-------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/contrib/epee/include/cache_helper.h b/contrib/epee/include/cache_helper.h index 7d42fe73..6a5c475a 100644 --- a/contrib/epee/include/cache_helper.h +++ b/contrib/epee/include/cache_helper.h @@ -61,7 +61,7 @@ namespace epee class cache_base { uint64_t max_allowed_elements; - std::list most_recet_acessed; + std::list most_recent_accessed; typename container_selector::iterator> >::container data; protected: critical_section m_lock; @@ -78,7 +78,7 @@ namespace epee size_t most_recent_accessed_container_size() const { - return most_recet_acessed.size(); + return most_recent_accessed.size(); } uint64_t get_max_elements() const @@ -98,10 +98,10 @@ namespace epee if (it == data.end()) return false; - //most_recet_acessed.splice(most_recet_acessed.begin(), most_recet_acessed, it->second.second); - most_recet_acessed.erase(it->second.second); - most_recet_acessed.push_front(k); - it->second.second = most_recet_acessed.begin(); + //most_recent_accessed.splice(most_recent_accessed.begin(), most_recent_accessed, it->second.second); + most_recent_accessed.erase(it->second.second); + most_recent_accessed.push_front(k); + it->second.second = most_recent_accessed.begin(); v = it->second.first; return true; @@ -113,14 +113,14 @@ namespace epee auto it = data.find(k); if (it == data.end()) { - most_recet_acessed.push_front(k); - data.insert(std::make_pair(k, std::make_pair(v, most_recet_acessed.begin()))); + most_recent_accessed.push_front(k); + data.insert(std::make_pair(k, std::make_pair(v, most_recent_accessed.begin()))); } else { - most_recet_acessed.erase(it->second.second); - most_recet_acessed.push_front(k); - it->second.second = most_recet_acessed.begin(); + most_recent_accessed.erase(it->second.second); + most_recent_accessed.push_front(k); + it->second.second = most_recent_accessed.begin(); } trim(); @@ -131,7 +131,7 @@ namespace epee { CRITICAL_REGION_LOCAL(m_lock); data.clear(); - most_recet_acessed.clear(); + most_recent_accessed.clear(); } bool erase(const t_key& k) @@ -141,20 +141,21 @@ namespace epee if (data_it == data.end()) return false; - most_recet_acessed.erase(data_it->second.second); + most_recent_accessed.erase(data_it->second.second); data.erase(data_it); return true; } + protected: void trim() { CRITICAL_REGION_LOCAL(m_lock); - while (most_recet_acessed.size() > max_allowed_elements) + while (most_recent_accessed.size() > max_allowed_elements) { - auto data_it = data.find(most_recet_acessed.back()); + auto data_it = data.find(most_recent_accessed.back()); if (data_it != data.end()) data.erase(data_it); - most_recet_acessed.erase(--most_recet_acessed.end()); + most_recent_accessed.erase(--most_recent_accessed.end()); } } };