Changeset View
Changeset View
Standalone View
Standalone View
src/txmempool.cpp
Show First 20 Lines • Show All 1,315 Lines • ▼ Show 20 Lines | while (DynamicMemoryUsage() > MAX_DISCONNECTED_TX_POOL_SIZE) { | ||||
// Drop the earliest entry, and remove its children from the | // Drop the earliest entry, and remove its children from the | ||||
// mempool. | // mempool. | ||||
auto it = queuedTx.get<insertion_order>().begin(); | auto it = queuedTx.get<insertion_order>().begin(); | ||||
g_mempool.removeRecursive(**it, MemPoolRemovalReason::REORG); | g_mempool.removeRecursive(**it, MemPoolRemovalReason::REORG); | ||||
removeEntry(it); | removeEntry(it); | ||||
} | } | ||||
} | } | ||||
void DisconnectedBlockTransactions::importMempool() { | |||||
// addForBlock's algorithm sorts a vector of transactions back into | |||||
// topological order. We use it in a separate object to create a valid | |||||
// ordering of all mempool transactions, which we then splice in front of | |||||
// the current queuedTx. This results in a valid sequence of transactions to | |||||
// be reprocessed in updateMempoolForReorg | |||||
DisconnectedBlockTransactions ordered_mempool; | |||||
std::vector<CTransactionRef> vtx; | |||||
vtx.reserve(g_mempool.mapTx.size()); | |||||
for (const CTxMemPoolEntry &e : g_mempool.mapTx) { | |||||
vtx.push_back(e.GetSharedTx()); | |||||
} | |||||
ordered_mempool.addForBlock(vtx); | |||||
cachedInnerUsage += ordered_mempool.cachedInnerUsage; | |||||
queuedTx.get<insertion_order>().splice( | |||||
queuedTx.get<insertion_order>().begin(), | |||||
ordered_mempool.queuedTx.get<insertion_order>()); | |||||
// We limit memory usage because we can't know if this block is the last one | |||||
// being disconnected. Right now, the dynamic memory usage of these mempool | |||||
// transactions is being double accounted for, both here and in g_mempool. | |||||
// Once the caller clears g_mempool, this estimate becomes coherent again | |||||
while (DynamicMemoryUsage() > MAX_DISCONNECTED_TX_POOL_SIZE) { | |||||
// Drop the earliest entry which, by definition, has no children | |||||
auto it = queuedTx.get<insertion_order>().begin(); | |||||
removeEntry(it); | |||||
} | |||||
} | |||||
deadalnix: It looks like a good algorithm. However, this doesn't lock the mempool and adds one more… | |||||
void DisconnectedBlockTransactions::updateMempoolForReorg(const Config &config, | void DisconnectedBlockTransactions::updateMempoolForReorg(const Config &config, | ||||
bool fAddToMempool) { | bool fAddToMempool) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
std::vector<TxId> txidsUpdate; | std::vector<TxId> txidsUpdate; | ||||
// disconnectpool's insertion_order index sorts the entries from oldest to | // disconnectpool's insertion_order index sorts the entries from oldest to | ||||
// newest, but the oldest entry will be the last tx from the latest mined | // newest, but the oldest entry will be the last tx from the latest mined | ||||
// block that was disconnected. | // block that was disconnected. | ||||
Show All 37 Lines |
It looks like a good algorithm. However, this doesn't lock the mempool and adds one more dependency on a global variable. It would be beneficial to pass the mempool as an argument, and make sure the locking is appropriate.
This also doesn't seems to clear the mempool.
I think this should probably be its own patch and come with a test.