src: update internal data structure to boost::bimap.

startup speed up 2-5x because this PR changing
O(n^2) operation to O(nlogn).
This commit is contained in:
0xFFFC0000 2024-06-21 07:22:19 +00:00
parent cc73fe7116
commit 445319d3f1
No known key found for this signature in database
GPG Key ID: 650F7C2B7BDA3819
2 changed files with 40 additions and 26 deletions

View File

@ -29,6 +29,7 @@
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <algorithm> #include <algorithm>
#include <boost/bimap/support/iterator_type_by.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
@ -42,6 +43,7 @@
#include "blockchain_db/blockchain_db.h" #include "blockchain_db/blockchain_db.h"
#include "int-util.h" #include "int-util.h"
#include "misc_language.h" #include "misc_language.h"
#include "misc_log_ex.h"
#include "warnings.h" #include "warnings.h"
#include "common/perf_timer.h" #include "common/perf_timer.h"
#include "crypto/hash.h" #include "crypto/hash.h"
@ -464,7 +466,7 @@ namespace cryptonote
break; break;
try try
{ {
const crypto::hash &txid = it->second; const crypto::hash &txid = it->get_right();
txpool_tx_meta_t meta; txpool_tx_meta_t meta;
if (!m_blockchain.get_txpool_tx_meta(txid, meta)) if (!m_blockchain.get_txpool_tx_meta(txid, meta))
{ {
@ -491,11 +493,11 @@ namespace cryptonote
return; return;
} }
// remove first, in case this throws, so key images aren't removed // remove first, in case this throws, so key images aren't removed
MINFO("Pruning tx " << txid << " from txpool: weight: " << meta.weight << ", fee/byte: " << it->first.first); MINFO("Pruning tx " << txid << " from txpool: weight: " << meta.weight << ", fee/byte: " << it->get_left().first);
m_blockchain.remove_txpool_tx(txid); m_blockchain.remove_txpool_tx(txid);
reduce_txpool_weight(meta.weight); reduce_txpool_weight(meta.weight);
remove_transaction_keyimages(tx, txid); remove_transaction_keyimages(tx, txid);
MINFO("Pruned tx " << txid << " from txpool: weight: " << meta.weight << ", fee/byte: " << it->first.first); MINFO("Pruned tx " << txid << " from txpool: weight: " << meta.weight << ", fee/byte: " << it->get_left().first);
auto it_prev = it; auto it_prev = it;
--it_prev; --it_prev;
@ -751,13 +753,9 @@ namespace cryptonote
m_remove_stuck_tx_interval.do_call([this](){return remove_stuck_transactions();}); m_remove_stuck_tx_interval.do_call([this](){return remove_stuck_transactions();});
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
sorted_tx_container::iterator tx_memory_pool::find_tx_in_sorted_container(const crypto::hash& id) const sorted_tx_container::iterator tx_memory_pool::find_tx_in_sorted_container(const crypto::hash& id)
{ {
return std::find_if( m_txs_by_fee_and_receive_time.begin(), m_txs_by_fee_and_receive_time.end() return m_txs_by_fee_and_receive_time.project_up(m_txs_by_fee_and_receive_time.right.find(id));
, [&](const sorted_tx_container::value_type& a){
return a.second == id;
}
);
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
//TODO: investigate whether boolean return is appropriate //TODO: investigate whether boolean return is appropriate
@ -1644,15 +1642,15 @@ namespace cryptonote
for (; sorted_it != m_txs_by_fee_and_receive_time.end(); ++sorted_it) for (; sorted_it != m_txs_by_fee_and_receive_time.end(); ++sorted_it)
{ {
txpool_tx_meta_t meta; txpool_tx_meta_t meta;
if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta)) if (!m_blockchain.get_txpool_tx_meta(sorted_it->get_right(), meta))
{ {
static bool warned = false; static bool warned = false;
if (!warned) if (!warned)
MERROR(" failed to find tx meta: " << sorted_it->second << " (will only print once)"); MERROR(" failed to find tx meta: " << sorted_it->get_right() << " (will only print once)");
warned = true; warned = true;
continue; continue;
} }
LOG_PRINT_L2("Considering " << sorted_it->second << ", weight " << meta.weight << ", current block weight " << total_weight << "/" << max_total_weight << ", current coinbase " << print_money(best_coinbase) << ", relay method " << (unsigned)meta.get_relay_method()); LOG_PRINT_L2("Considering " << sorted_it->get_right() << ", weight " << meta.weight << ", current block weight " << total_weight << "/" << max_total_weight << ", current coinbase " << print_money(best_coinbase) << ", relay method " << (unsigned)meta.get_relay_method());
if (!meta.matches(relay_category::legacy) && !(m_mine_stem_txes && meta.get_relay_method() == relay_method::stem)) if (!meta.matches(relay_category::legacy) && !(m_mine_stem_txes && meta.get_relay_method() == relay_method::stem))
{ {
@ -1702,7 +1700,7 @@ namespace cryptonote
} }
// "local" and "stem" txes are filtered above // "local" and "stem" txes are filtered above
cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(sorted_it->second, relay_category::all); cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(sorted_it->get_right(), relay_category::all);
cryptonote::transaction tx; cryptonote::transaction tx;
@ -1713,7 +1711,7 @@ namespace cryptonote
bool ready = false; bool ready = false;
try try
{ {
ready = is_transaction_ready_to_go(meta, sorted_it->second, txblob, tx); ready = is_transaction_ready_to_go(meta, sorted_it->get_right(), txblob, tx);
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
@ -1724,7 +1722,7 @@ namespace cryptonote
{ {
try try
{ {
m_blockchain.update_txpool_tx(sorted_it->second, meta); m_blockchain.update_txpool_tx(sorted_it->get_right(), meta);
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
@ -1743,7 +1741,7 @@ namespace cryptonote
continue; continue;
} }
bl.tx_hashes.push_back(sorted_it->second); bl.tx_hashes.push_back(sorted_it->get_right());
total_weight += meta.weight; total_weight += meta.weight;
fee += meta.fee; fee += meta.fee;
best_coinbase = coinbase; best_coinbase = coinbase;
@ -1854,7 +1852,11 @@ namespace cryptonote
m_txs_by_fee_and_receive_time.erase(sorted_it); m_txs_by_fee_and_receive_time.erase(sorted_it);
} }
} }
m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>(fee, receive_time), txid); auto insert_result = m_txs_by_fee_and_receive_time.insert(sorted_tx_container::value_type(std::pair<double, time_t>(fee, receive_time), txid));
if (!insert_result.second) {
MERROR("Failed to add txid " << txid << " to the m_txs_by_fee_and_receive_time");
}
// Don't check for "resurrected" txs in case of reorgs i.e. don't check in 'm_removed_txs_by_time' // Don't check for "resurrected" txs in case of reorgs i.e. don't check in 'm_removed_txs_by_time'
// whether we have that txid there and if yes remove it; this results in possible duplicates // whether we have that txid there and if yes remove it; this results in possible duplicates

View File

@ -39,6 +39,9 @@
#include <queue> #include <queue>
#include <boost/serialization/version.hpp> #include <boost/serialization/version.hpp>
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/bimap.hpp>
#include <boost/bimap/set_of.hpp>
#include <boost/bimap/multiset_of.hpp>
#include "span.h" #include "span.h"
#include "string_tools.h" #include "string_tools.h"
@ -62,24 +65,33 @@ namespace cryptonote
//! pair of <transaction fee, transaction hash> for organization //! pair of <transaction fee, transaction hash> for organization
typedef std::pair<std::pair<double, std::time_t>, crypto::hash> tx_by_fee_and_receive_time_entry; typedef std::pair<std::pair<double, std::time_t>, crypto::hash> tx_by_fee_and_receive_time_entry;
class txCompare class txFeeCompare
{ {
public: public:
bool operator()(const tx_by_fee_and_receive_time_entry& a, const tx_by_fee_and_receive_time_entry& b) const bool operator()(const std::pair<double, std::time_t>& a, const std::pair<double, std::time_t>& b) const
{ {
// sort by greatest first, not least // sort by greatest first, not least
if (a.first.first > b.first.first) return true; if (a.first > b.first) return true;
if (a.first.first < b.first.first) return false; if (a.first < b.first) return false;
if (a.first.second < b.first.second) return true; if (a.second < b.second) return true;
if (a.first.second > b.first.second) return false; return false;
}
};
return memcmp(a.second.data, b.second.data, sizeof(crypto::hash)) < 0; class hashCompare
{
public:
bool operator()(const crypto::hash& a, const crypto::hash& b) const
{
return memcmp(a.data, b.data, sizeof(crypto::hash)) < 0;
} }
}; };
//! container for sorting transactions by fee per unit size //! container for sorting transactions by fee per unit size
typedef std::set<tx_by_fee_and_receive_time_entry, txCompare> sorted_tx_container; typedef boost::bimap<boost::bimaps::multiset_of<std::pair<double, std::time_t>, txFeeCompare>,
boost::bimaps::set_of<crypto::hash, hashCompare>> sorted_tx_container;
/** /**
* @brief Transaction pool, handles transactions which are not part of a block * @brief Transaction pool, handles transactions which are not part of a block
@ -653,7 +665,7 @@ private:
* *
* @return an iterator, possibly to the end of the container if not found * @return an iterator, possibly to the end of the container if not found
*/ */
sorted_tx_container::iterator find_tx_in_sorted_container(const crypto::hash& id) const; sorted_tx_container::iterator find_tx_in_sorted_container(const crypto::hash& id);
//! cache/call Blockchain::check_tx_inputs results //! cache/call Blockchain::check_tx_inputs results
bool check_tx_inputs(const std::function<cryptonote::transaction&(void)> &get_tx, const crypto::hash &txid, uint64_t &max_used_block_height, crypto::hash &max_used_block_id, tx_verification_context &tvc, bool kept_by_block = false) const; bool check_tx_inputs(const std::function<cryptonote::transaction&(void)> &get_tx, const crypto::hash &txid, uint64_t &max_used_block_height, crypto::hash &max_used_block_id, tx_verification_context &tvc, bool kept_by_block = false) const;