Skip to content

Conversation

sipa
Copy link
Member

@sipa sipa commented Aug 27, 2016

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.

@jonasschnelli
Copy link
Contributor

This is indeed a nice idea.
utACK.

@instagibbs
Copy link
Member

At the risk of it being blatantly obvious, this would especially allow nodes with default settings during IBD to sync faster, yes?

concept ACK

@sipa
Copy link
Member Author

sipa commented Aug 29, 2016

At the risk of it being blatantly obvious, this would especially allow nodes with default settings during IBD to sync faster, yes?

Indeed!

@gmaxwell
Copy link
Contributor

gmaxwell commented Sep 3, 2016

utACK.

@rebroad
Copy link
Contributor

rebroad commented Sep 15, 2016

At the risk of appearing stupid, how does this help nodes with default settings sync faster during IBD?

...coincache helps to validate blocks..?

@sipa
Copy link
Member Author

sipa commented Sep 15, 2016 via email

@paveljanik
Copy link
Contributor

utACK 8b85ede

@morcos
Copy link
Contributor

morcos commented Sep 15, 2016

@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.

@sipa
Copy link
Member Author

sipa commented Sep 19, 2016

@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));
Copy link
Contributor

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)"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

luke-jr pushed a commit to bitcoinknots/bitcoin that referenced this pull request Oct 20, 2016
@fanquake
Copy link
Member

fanquake commented Nov 7, 2016

Seeing a roughly 30% decrease in time to reindex to 270'000 with this change.

Master -reindex-chainstate

08:04:43 Cache configuration:
08:04:43 * Using 2.0MiB for block index database
08:04:43 * Using 8.0MiB for chain state database
08:04:43 * Using 290.0MiB for in-memory UTXO set

08:04:45 UpdateTip: height=0 cache=0.0MiB(0tx)
08:08:09 UpdateTip: height=200000 cache=172.9MiB(553629tx)
08:12:52 UpdateTip: height=230000 cache=274.9MiB(668943tx)
08:19:08 UpdateTip: height=260488 cache=239.4MiB(318281tx)
08:19:08 UpdateTip: height=260489 cache=239.4MiB(318525tx)
08:22:11 UpdateTip: height=270000 cache=31.7MiB(8943tx)

1046s

#8610 -reindex-chainstate

07:50:16 Cache configuration:
07:50:16 * Using 2.0MiB for block index database
07:50:16 * Using 8.0MiB for chain state database
07:50:16 * Using 290.0MiB for UTXO set (plus up to 286.1MiB of unused mempool space)
...
07:50:18 UpdateTip: height=0 cache=0.0MiB(0tx)
07:53:33 UpdateTip: height=200000 cache=356.1MiB(1336689tx)
07:56:58 UpdateTip: height=230000 cache=575.5MiB(1900937tx)
08:01:02 UpdateTip: height=260488 cache=576.1MiB(1324684tx)
08:01:11 UpdateTip: height=260489 cache=16.0MiB(0tx)
08:02:32 UpdateTip: height=270000 cache=486.6MiB(972452tx)

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();
Copy link
Contributor

@morcos morcos Nov 25, 2016

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.

@morcos
Copy link
Contributor

morcos commented Nov 25, 2016

utACK modulo suggestion about calling LimitMempoolSize in FSTD.
However if we decide there are downsides to that suggestion, I'm fine with leaving it out.

EDIT: maybe 0dedace? Though I'm not sure it's worth it..

@sipa
Copy link
Member Author

sipa commented Nov 26, 2016

@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;
Copy link
Contributor

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).

@sdaftuar
Copy link
Member

sdaftuar commented Nov 26, 2016

@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 FlushStateToDisk anywhere the mempool might be in an inconsistent state. I don't think it's safe to call LimitMempoolSize() when the mempool is in an inconsistent state, because CTxMemPool::TrimToSize() and CTxMemPool::Expire rely on CTxMemPool::CalculateDescendants() to do the right thing, and that function assumes that setMemPoolChildren is correct for all entries. If CalculateDescendants() doesn't catch everything it should, then we could wind up with orphans in the mempool.

So in particular, during a reorg, we call AcceptToMemoryPool() for all the transactions in a disconnected block. If someone were to add a FlushStateToDisk() call inside ATMP (which I think seems harmless on the face of it), then that would introduce a bug that could cause orphans in the mempool after a reorg.

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...

@sipa
Copy link
Member Author

sipa commented Nov 26, 2016

I removed the commit again.

@laanwj
Copy link
Member

laanwj commented Nov 28, 2016

Concept ACK

@sipa
Copy link
Member Author

sipa commented Nov 28, 2016

Going to address @morcos's issue soon.

@sipa
Copy link
Member Author

sipa commented Dec 22, 2016

Rebased, and rewritten to take #8610 (comment) into account.

@jtimon
Copy link
Contributor

jtimon commented Dec 22, 2016

Concept ACK.

@morcos
Copy link
Contributor

morcos commented Dec 22, 2016

Looks good @sipa , thanks

Seems like an actual lock inversion, I think you fixed it previously by moving the mempool.DynamicMemoryUsage() to the top of FlustStateToDisk, which makes sense to me.
However I don't understand why CWallet::ReacceptWalletTransactions is locking mempool.cs anyway, so maybe that should also be removed.

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.
luke-jr pushed a commit to bitcoinknots/bitcoin that referenced this pull request Dec 23, 2016
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
@fanquake
Copy link
Member

fanquake commented Jan 4, 2017

#8610 on top of master (2a524b8) with -reindex-chainstate -dbcache=2048:

2017-01-03 22:39:59 Cache configuration:
2017-01-03 22:39:59 * Using 2.0MiB for block index database
2017-01-03 22:39:59 * Using 8.0MiB for chain state database
2017-01-03 22:39:59 * Using 2038.0MiB for in-memory UTXO set (plus up to 286.1MiB of unused mempool space)
2017-01-03 22:43:04 height=200000 cache=356.1MiB(1336689tx)
2017-01-03 22:46:20 height=230000 cache=575.5MiB(1900937tx)
2017-01-03 22:51:26 height=270000 cache=915.5MiB(2499199tx)
2017-01-03 22:53:26 height=280000 cache=1050.5MiB(2816546tx)

807s (to 280'000)

Master (2a524b8) -reindex-chainstate -dbcache=2048:

2017-01-03 23:01:24 Cache configuration:
2017-01-03 23:01:24 * Using 2.0MiB for block index database
2017-01-03 23:01:24 * Using 8.0MiB for chain state database
2017-01-03 23:01:24 * Using 2038.0MiB for in-memory UTXO set
2017-01-03 23:04:29 height=200000 cache=356.1MiB(1336689tx)
2017-01-03 23:07:46 height=230000 cache=575.5MiB(1900937tx)
2017-01-03 23:12:48 height=270000 cache=915.5MiB(2499199tx)
2017-01-03 23:14:45 height=280000 cache=1050.5MiB(2816546tx)

801s (to 280'000)

Master (2a524b8) -reindex-chainstate -dbcache=300:

2017-01-03 23:24:34 Cache configuration:
2017-01-03 23:24:34 * Using 2.0MiB for block index database
2017-01-03 23:24:34 * Using 8.0MiB for chain state database
2017-01-03 23:24:34 * Using 290.0MiB for in-memory UTXO set
2017-01-03 23:27:55 height=200000 cache=172.9MiB(553629tx)
2017-01-03 23:32:32 height=230000 cache=274.9MiB(668943tx)
2017-01-03 23:36:41 height=250000 cache=128.6MiB(113010tx)
2017-01-03 23:42:36 height=270000 cache=31.7MiB(8943tx)

1082s (to 270'000)

#8610 on top of master (2a524b8) -reindex-chainstate -dbcache=300

2017-01-03 23:47:30 Cache configuration:
2017-01-03 23:47:30 * Using 2.0MiB for block index database
2017-01-03 23:47:30 * Using 8.0MiB for chain state database
2017-01-03 23:47:30 * Using 290.0MiB for in-memory UTXO set (plus up to 286.1MiB of unused mempool space)
2017-01-03 23:50:37 height=200000 cache=356.1MiB(1336689tx)
2017-01-03 23:53:58 height=230000 cache=575.5MiB(1900937tx)
2017-01-03 23:56:50 height=250000 cache=504.4MiB(1124858tx)
2017-01-03 23:59:30 height=270000 cache=486.6MiB(972452tx)
2017-01-04 00:02:10 height=280000 cache=75.2MiB(48075tx)

720s (to 270'000)

@morcos
Copy link
Contributor

morcos commented Jan 5, 2017

utACK ba3cecf (for the avoidance of doubt)

@TheBlueMatt
Copy link
Contributor

utACK ba3cecf

@sipa sipa merged commit ba3cecf into bitcoin:master Jan 5, 2017
sipa added a commit that referenced this pull request Jan 5, 2017
ba3cecf Share unused mempool memory with coincache (Pieter Wuille)
@rebroad
Copy link
Contributor

rebroad commented Jan 6, 2017

utACK - will merge and test

@sipa sipa mentioned this pull request Jan 10, 2017
18 tasks
jnewbery added a commit to jnewbery/bitcoin that referenced this pull request Jan 17, 2017
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.
codablock pushed a commit to codablock/dash that referenced this pull request Oct 23, 2017
ba3cecf Share unused mempool memory with coincache (Pieter Wuille)
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Sep 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.