-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Share unused mempool memory with coincache #8610
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This is indeed a nice idea. |
At the risk of it being blatantly obvious, this would especially allow nodes with default settings during IBD to sync faster, yes? concept ACK |
Indeed! |
utACK. |
At the risk of appearing stupid, how does this help nodes with default settings sync faster during IBD? ...coincache helps to validate blocks..? |
Because during IBD, the mempool is nearly empty. With this patch, all that
unused mempool space (300 Mbyte by default currently) will be used for the
chainstate cache, which is the bottleneck for block validation during IBD.
|
utACK 8b85ede |
@sipa do you have any concern that this gives outside peers some control over when your coinsviewcache is flushed? That seems not ideal to me, at least until we are smarter about flushing it. I had previously imagined doing this by setting the mempool limit low initially and then increasing it to the desired setting after IBD was finished. But I'm not sure I succeeded in having the code architected to make that possible. |
@morcos I think that's already a concern, but I'm not sure this patch worsens it significantly. External peers can cause an increase in memory usage of the cache or the mempool, but the latter is already harder anyway. |
LogPrintf("Cache configuration:\n"); | ||
LogPrintf("* Using %.1fMiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024)); | ||
LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024)); | ||
LogPrintf("* Using %.1fMiB for in-memory UTXO set\n", nCoinCacheUsage * (1.0 / 1024 / 1024)); | ||
LogPrintf("* Using %.1fMiB for UTXO set (shared with mempool)\n", nCoinCachePlusMempoolUsage * (1.0 / 1024 / 1024)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is confusing to me - maybe "Using $cache_only_size for UTXO set (+ up to $mempool_size from mempool)"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Github-Pull: bitcoin#8610 Rebased-From: 27562ef
Seeing a roughly 30% decrease in time to reindex to 270'000 with this change. Master -reindex-chainstate08:04:43 Cache configuration: 08:04:45 UpdateTip: height=0 cache=0.0MiB(0tx) 1046s#8610 -reindex-chainstate07:50:16 Cache configuration: 734s |
@@ -2553,6 +2553,7 @@ enum FlushStateMode { | |||
* or always and in all cases if we're in prune mode and are deleting files. | |||
*/ | |||
bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { | |||
size_t cacheSize = mempool.DynamicMemoryUsage(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it would be better to call LimitMempoolSize
right before this? During a reorg the mempool size isn't limited until the end, so theoretically FlushStateToDisk
could get called and have its effective cache size reduced below the expected minimum. @sdaftuar Is there any harm in calling an extra LimitMempoolSize
in the middle of a reorg other than possible inefficiencies of what you're evicting?
EDIT: Shoot this isn't exactly what I was imagining. I was thinking it would only limit the mempool if it was going to flush anyway, but this suggestion will limit the mempool every time FSTD is called which defeats the whole point of not limiting inside a reorg.
utACK modulo suggestion about calling LimitMempoolSize in FSTD. EDIT: maybe 0dedace? Though I'm not sure it's worth it.. |
@morcos Looks good, I've included it. |
// The cache is large and close to the limit, but we have time now (not in the middle of a block processing). | ||
bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize * (10.0/9) > nCoinCacheUsage; | ||
bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize * (10.0/9) > nCoinCachePlusMempoolUsage; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sipa sorry, one more issue. this line would be pretty broken if someone sets a large maxmempool. i was thinking maybe we should change it to 20.0/19 so it doesn't make the base case behavior a smaller effective cache size, but then realized if someone sets say a 2GB mempool and doesn't make a larger dbcache, then they could be flushing all the time.
Perhaps this problem and the other one could be avoided by just calculating any extra available space max(0,(maxmempool - usage)) and comparing only the pcoinstip usage to (dbcache limit + any extra available space).
@morcos Not sure I'm a fan of 0dedace. I believe this code will work correctly for now, but only because we don't seem to call So in particular, during a reorg, we call So at the very least, we would need to document that FlushStateToDisk() has a new requirement, that the mempool is in a consistent state when invoked. But as this condition is difficult to assert for and test, I think my preference would be to not impose this requirement, just to reduce the chance we introduce a bug in the future. But also, note that #9208 should solve the problem of the mempool growing beyond its configured limit during a reorg... |
I removed the commit again. |
Concept ACK |
Going to address @morcos's issue soon. |
Rebased, and rewritten to take #8610 (comment) into account. |
Concept ACK. |
Looks good @sipa , thanks Seems like an actual lock inversion, I think you fixed it previously by moving the I guess you lost the advantage of the extra space in VerifyDB, but that seems no big loss to me. |
If the mempool is not completely full, treat the difference between the maximum size and the actual usage as available for the coin cache. This also changes the early flush trigger from (usage > 0.9 * space) to (usage > 0.9 * space && usage > space - 100MB). This means we're not permanently leaving 10% of the space unused when the space is large.
If the mempool is not completely full, treat the difference between the maximum size and the actual usage as available for the coin cache. This also changes the early flush trigger from (usage > 0.9 * space) to (usage > 0.9 * space && usage > space - 100MB). This means we're not permanently leaving 10% of the space unused when the space is large. Github-Pull: bitcoin#8610 Rebased-From: ba3cecf
#8610 on top of master (2a524b8) with -reindex-chainstate -dbcache=2048:
807s (to 280'000)Master (2a524b8) -reindex-chainstate -dbcache=2048:
801s (to 280'000)Master (2a524b8) -reindex-chainstate -dbcache=300:
1082s (to 270'000)#8610 on top of master (2a524b8) -reindex-chainstate -dbcache=300
720s (to 270'000) |
utACK ba3cecf (for the avoidance of doubt) |
utACK ba3cecf |
ba3cecf Share unused mempool memory with coincache (Pieter Wuille)
utACK - will merge and test |
Nodes running in -blocksonly mode do not send and receive transactions outside blocks. They do not have a mempool, so -maxmempool should be set to 0. Unused mempool memory can be used for the UTXO coincache (PR bitcoin#8610) so not setting -maxmempool to 0 can cause to coincache to grow larger than expected. If -blocksonly is set and -maxmempool is set to anything other than 0, error and exit. If -blocksonly is set and -maxmempool is not set, implicitly set -maxmempool to 0.
ba3cecf Share unused mempool memory with coincache (Pieter Wuille)
A suggestion from IRC: allow the chainstate cache to use unused mempool memory.
If the mempool is not completely full, treat the difference between the maximum size and the actual usage as available for the coin cache.
This also changes the early flush trigger from (usage > 0.9 * space) to (usage > 0.9 * space && usage > space - 100MB). This means we're not permanently leaving 10% of the space unused when the space is large.