Adds an expiration time for orphan tx.

This prevents higher order orphans and other junk from
 holding positions in the orphan map.  Parents delayed
 twenty minutes are more are unlikely to ever arrive.

The freed space will improve the orphan matching success rate for
 other transactions.
This commit is contained in:
Gregory Maxwell 2016-06-11 00:26:16 +00:00
parent db0ffe80a0
commit 11cc143895
2 changed files with 26 additions and 1 deletions

View file

@ -100,6 +100,7 @@ struct IteratorComparator
struct COrphanTx { struct COrphanTx {
CTransaction tx; CTransaction tx;
NodeId fromPeer; NodeId fromPeer;
int64_t nTimeExpire;
}; };
map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main); map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main);
map<COutPoint, set<map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY(cs_main); map<COutPoint, set<map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY(cs_main);
@ -641,7 +642,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c
return false; return false;
} }
auto ret = mapOrphanTransactions.emplace(hash, COrphanTx{tx, peer}); auto ret = mapOrphanTransactions.emplace(hash, COrphanTx{tx, peer, GetTime() + ORPHAN_TX_EXPIRE_TIME});
assert(ret.second); assert(ret.second);
BOOST_FOREACH(const CTxIn& txin, tx.vin) { BOOST_FOREACH(const CTxIn& txin, tx.vin) {
mapOrphanTransactionsByPrev[txin.prevout].insert(ret.first); mapOrphanTransactionsByPrev[txin.prevout].insert(ret.first);
@ -689,6 +690,26 @@ void EraseOrphansFor(NodeId peer)
unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRED(cs_main) unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{ {
unsigned int nEvicted = 0; unsigned int nEvicted = 0;
static int64_t nNextSweep;
int64_t nNow = GetTime();
if (nNextSweep <= nNow) {
// Sweep out expired orphan pool entries:
int nErased = 0;
int64_t nMinExpTime = nNow + ORPHAN_TX_EXPIRE_TIME - ORPHAN_TX_EXPIRE_INTERVAL;
map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin();
while (iter != mapOrphanTransactions.end())
{
map<uint256, COrphanTx>::iterator maybeErase = iter++;
if (maybeErase->second.nTimeExpire <= nNow) {
nErased += EraseOrphanTx(maybeErase->second.tx.GetHash());
} else {
nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime);
}
}
// Sweep again 5 minutes after the next entry that expires in order to batch the linear scan.
nNextSweep = nMinExpTime + ORPHAN_TX_EXPIRE_INTERVAL;
if (nErased > 0) LogPrint("mempool", "Erased %d orphan tx due to expiration\n", nErased);
}
while (mapOrphanTransactions.size() > nMaxOrphans) while (mapOrphanTransactions.size() > nMaxOrphans)
{ {
// Evict a random orphan: // Evict a random orphan:

View file

@ -56,6 +56,10 @@ static const CAmount HIGH_TX_FEE_PER_KB = 0.01 * COIN;
static const CAmount HIGH_MAX_TX_FEE = 100 * HIGH_TX_FEE_PER_KB; static const CAmount HIGH_MAX_TX_FEE = 100 * HIGH_TX_FEE_PER_KB;
/** Default for -maxorphantx, maximum number of orphan transactions kept in memory */ /** Default for -maxorphantx, maximum number of orphan transactions kept in memory */
static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100;
/** Expiration time for orphan transactions in seconds */
static const int64_t ORPHAN_TX_EXPIRE_TIME = 20 * 60;
/** Minimum time between orphan transactions expire time checks in seconds */
static const int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60;
/** Default for -limitancestorcount, max number of in-mempool ancestors */ /** Default for -limitancestorcount, max number of in-mempool ancestors */
static const unsigned int DEFAULT_ANCESTOR_LIMIT = 25; static const unsigned int DEFAULT_ANCESTOR_LIMIT = 25;
/** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors */ /** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors */