aboutsummaryrefslogtreecommitdiff
path: root/src/txmempool.h
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@protonmail.com>2021-02-24 09:07:10 +0100
committerWladimir J. van der Laan <laanwj@protonmail.com>2021-02-24 09:57:21 +0100
commitb59f2787e53318caad6d3292de2cc6e17995d277 (patch)
treebb9418e42c437df99130c8ad220d53336120836c /src/txmempool.h
parent587c986ccf88daef5e979eaa91163349e36a544d (diff)
parentfd6580e405699ccb051fd2a34525e48d3253673d (diff)
downloadbitcoin-b59f2787e53318caad6d3292de2cc6e17995d277.tar.xz
Merge #18017: txmempool: split epoch logic into class
fd6580e405699ccb051fd2a34525e48d3253673d [refactor] txmempool: split epoch logic into class (Anthony Towns) Pull request description: Splits the epoch logic introduced in #17925 into a separate class. Uses clang's thread safety annotations and encapsulates the data more strongly to reduce chances of bugs from API misuse. ACKs for top commit: jonatack: ACK fd6580e405699ccb051fd2a34525e48d3253673d using clang thread safety annotations looks like a very good idea, and the encapsulation this change adds should improve robustness (and possible unit test-ability) of the code. Verified that changing some of the locking duly provoked build-time warnings with Clang 9 on Debian and that small changes in the new `Epoch` class were covered by failing functional test assertions in `mempool_updatefromblock.py`, `mempool_resurrect.py`, and `mempool_reorg.py` hebasto: re-ACK fd6580e405699ccb051fd2a34525e48d3253673d, since my [previous](https://github.com/bitcoin/bitcoin/pull/18017#pullrequestreview-569619362) review: Tree-SHA512: 7004623faa02b56639aa05ab7a078320a6d8d54ec62d8022876221e33f350f47df51ddff056c0de5be798f8eb39b5c03c2d3f035698555d70abc218e950f2f8c
Diffstat (limited to 'src/txmempool.h')
-rw-r--r--src/txmempool.h55
1 files changed, 13 insertions, 42 deletions
diff --git a/src/txmempool.h b/src/txmempool.h
index b8de326737..143048b205 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -21,6 +21,7 @@
#include <primitives/transaction.h>
#include <random.h>
#include <sync.h>
+#include <util/epochguard.h>
#include <util/hasher.h>
#include <boost/multi_index_container.hpp>
@@ -64,6 +65,7 @@ struct CompareIteratorByHash {
return a->GetTx().GetHash() < b->GetTx().GetHash();
}
};
+
/** \class CTxMemPoolEntry
*
* CTxMemPoolEntry stores data about the corresponding transaction, as well
@@ -156,7 +158,7 @@ public:
Children& GetMemPoolChildren() const { return m_children; }
mutable size_t vTxHashesIdx; //!< Index in mempool's vTxHashes
- mutable uint64_t m_epoch; //!< epoch when last touched, useful for graph algorithms
+ mutable Epoch::Marker m_epoch_marker; //!< epoch when last touched, useful for graph algorithms
};
// Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index.
@@ -486,8 +488,7 @@ private:
mutable int64_t lastRollingFeeUpdate;
mutable bool blockSinceLastRollingFeeBump;
mutable double rollingMinimumFeeRate; //!< minimum fee to get into the pool, decreases exponentially
- mutable uint64_t m_epoch{0};
- mutable bool m_has_epoch_guard{false};
+ mutable Epoch m_epoch GUARDED_BY(cs);
// In-memory counter for external mempool tracking purposes.
// This number is incremented once every time a transaction
@@ -666,7 +667,7 @@ public:
* for). Note: vHashesToUpdate should be the set of transactions from the
* disconnected block that have been accepted back into the mempool.
*/
- void UpdateTransactionsFromBlock(const std::vector<uint256>& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
+ void UpdateTransactionsFromBlock(const std::vector<uint256>& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main) LOCKS_EXCLUDED(m_epoch);
/** Try to calculate all in-mempool ancestors of entry.
* (these are all calculated including the tx itself)
@@ -827,52 +828,22 @@ private:
*/
void removeUnchecked(txiter entry, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs);
public:
- /** EpochGuard: RAII-style guard for using epoch-based graph traversal algorithms.
- * When walking ancestors or descendants, we generally want to avoid
- * visiting the same transactions twice. Some traversal algorithms use
- * std::set (or setEntries) to deduplicate the transaction we visit.
- * However, use of std::set is algorithmically undesirable because it both
- * adds an asymptotic factor of O(log n) to traverals cost and triggers O(n)
- * more dynamic memory allocations.
- * In many algorithms we can replace std::set with an internal mempool
- * counter to track the time (or, "epoch") that we began a traversal, and
- * check + update a per-transaction epoch for each transaction we look at to
- * determine if that transaction has not yet been visited during the current
- * traversal's epoch.
- * Algorithms using std::set can be replaced on a one by one basis.
- * Both techniques are not fundamentally incompatible across the codebase.
- * Generally speaking, however, the remaining use of std::set for mempool
- * traversal should be viewed as a TODO for replacement with an epoch based
- * traversal, rather than a preference for std::set over epochs in that
- * algorithm.
- */
- class EpochGuard {
- const CTxMemPool& pool;
- public:
- explicit EpochGuard(const CTxMemPool& in);
- ~EpochGuard();
- };
- // N.B. GetFreshEpoch modifies mutable state via the EpochGuard construction
- // (and later destruction)
- EpochGuard GetFreshEpoch() const EXCLUSIVE_LOCKS_REQUIRED(cs);
-
/** visited marks a CTxMemPoolEntry as having been traversed
- * during the lifetime of the most recently created EpochGuard
+ * during the lifetime of the most recently created Epoch::Guard
* and returns false if we are the first visitor, true otherwise.
*
- * An EpochGuard must be held when visited is called or an assert will be
+ * An Epoch::Guard must be held when visited is called or an assert will be
* triggered.
*
*/
- bool visited(txiter it) const EXCLUSIVE_LOCKS_REQUIRED(cs) {
- assert(m_has_epoch_guard);
- bool ret = it->m_epoch >= m_epoch;
- it->m_epoch = std::max(it->m_epoch, m_epoch);
- return ret;
+ bool visited(const txiter it) const EXCLUSIVE_LOCKS_REQUIRED(cs, m_epoch)
+ {
+ return m_epoch.visited(it->m_epoch_marker);
}
- bool visited(Optional<txiter> it) const EXCLUSIVE_LOCKS_REQUIRED(cs) {
- assert(m_has_epoch_guard);
+ bool visited(Optional<txiter> it) const EXCLUSIVE_LOCKS_REQUIRED(cs, m_epoch)
+ {
+ assert(m_epoch.guarded()); // verify guard even when it==nullopt
return !it || visited(*it);
}
};