Skip to content

Conversation

@l0rinc
Copy link
Contributor

@l0rinc l0rinc commented Oct 22, 2025

Revival of #30610 (comment) with the remaining comments applied on top

Since #28280, the cost of a non-wiping sync of the UTXO cache is only proportional to the number of dirty entries, rather than proportional to the size of the entire cache. Because of that, there is no reason to perform a wiping flush in case the contents of the cache is still useful.

Split the FlushStateMode::ALWAYS mode into a FORCE_SYNC (non-wiping) and a FORCE_FLUSH (wiping), and then use the former in scantxoutset, gettxoutsetinfo, snapshot creation.

(slightly updated after #30214)

@DrahtBot
Copy link
Contributor

DrahtBot commented Oct 22, 2025

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Code Coverage & Benchmarks

For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/33680.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK cedwies, optout21

If your review is incorrectly listed, please copy-paste <!--meta-tag:bot-skip--> into the comment that the bot should ignore.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #34125 (validation: reuse should_empty check for chainstate flush by l0rinc)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

Copy link

@cedwies cedwies left a comment

Choose a reason for hiding this comment

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

Approach ACK

Do ForceFlushToDisk(...)/FlushToDisk(...) require cs_main to be held?
Most call sites hold it during shutdown flushes, but the function itself doesn’t assert or document that (no AssertLockHeld(cs_main)). If this is correct, I think a short comment can help that a Lock is not strictly needed.

@@ -57,7 +57,7 @@ void sanity_check_snapshot()
// Connect the chain to the tmp chainman and sanity check the chainparams snapshot values.
LOCK(cs_main);
auto& cs{node.chainman->ActiveChainstate()};
cs.ForceFlushStateToDisk();
cs.ForceFlushStateToDisk(/*wipe_cache=*/true);
Copy link

Choose a reason for hiding this comment

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

Why are we wiping the cache here? We only compute stats from CoinsDB(), not the in-memory cache, so a non-wiping flush (wipe_cache=false) should be enough for consistency (?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, changed to false, added you as coauthor, thanks.

@optout21
Copy link
Contributor

optout21 commented Nov 1, 2025

I suggest splitting into two commits:

  • Preparatory rename & new parameter(s) but without behavior change, to minimize diff in 2nd commit (rename ALWAYS to FORCE_FLUSH I suppose)
  • Change in behavior in the respective places (scantxoutset, gettxoutsetinfo, etc.)

@l0rinc l0rinc force-pushed the l0rinc/force-sync branch 2 times, most recently from adfb4eb to a59aace Compare November 1, 2025 21:24
@l0rinc
Copy link
Contributor Author

l0rinc commented Nov 1, 2025

Thanks @optout21 & @cedwies, split the change to 2 commits, one just renames the old value and adjusts the docs and scripts, the second introduces the new value.
I'm not sure about the locking, let's investigate that as a follow-up.

637657 ALWAYS 122320 17124.80 kB False
81349 ALWAYS 0 1383.49 kB False
Duration (µs) Mode Coins Count Memory Usage Flush for Prune
2556340 IF_NEEDED 2899141 394844.34 kB False
Copy link
Contributor

Choose a reason for hiding this comment

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

The 'Flush for Prune' has changed here to False, and now all lines have False value here. Can the False line be preserved, or is it OK in this sample output?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the actual output of running the script, looks like it wasn't updated in a while

Copy link
Contributor

Choose a reason for hiding this comment

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

I was wondering how tracing is affected by this change. The trace includes the mode, and it should display it fine, so the trace should be OK.

It would be nice to check how the trace looks for a FORCE_SYNC case as well; I guess that can be triggered by an RPC call to the running node.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've never used tracing before, my understanding is that @0xB10C uses these for monitoring mostly.

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 the actual output of running the script, looks like it wasn't updated in a while

I think that the scripts only enables the trace and listens to it, but it does not trigger a particular use case.
If trace outputs are displayed with these changes, that should be sufficient check (i.e., tracing a FORCE_SYNC is not crucial).

Copy link
Contributor

Choose a reason for hiding this comment

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

I plan have a closer look.

I don't use the utxocache tracepoints at the moment.

Copy link
Contributor

@0xB10C 0xB10C Nov 19, 2025

Choose a reason for hiding this comment

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

This is the actual output of running the script, looks like it wasn't updated in a while

Since the script logs UTXO cache events, running it against a different node will produce different output. Not sure if worth changing the example output of the script here. The example output is just as valid just as it was before.

If you retouch, feel free to revert, but I don't think it matters much.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for checking!
The headers have changed and the column widths, so I had to regenerate the example to be accurate:

-Duration (µs)   Mode       Coins Count     Memory Usage    Prune
+Duration (µs)   Mode         Coins Count     Memory Usage    Flush for Prune

@optout21
Copy link
Contributor

optout21 commented Nov 3, 2025

reACK c6ca2b8
Re-reviewed after two rebases.

(prev:
reACK 14abac10f2ebd93367c91dde7586a35456ef9d45
re utACK d4425982ca4aff9b856a26f1d83d1419252f10a2
utACK a59aacefd1a0cdb448c8f847665a5809f9897605)

@l0rinc
Copy link
Contributor Author

l0rinc commented Nov 4, 2025

rebased after #30595

@cedwies
Copy link

cedwies commented Nov 17, 2025

utACK d442598

@0xB10C
Copy link
Contributor

0xB10C commented Nov 19, 2025

Looked at the flush tracing changes a bit (d4425982ca4aff9b856a26f1d83d1419252f10a2). They seem fine to me. I can't really comment on the other changes, as I'm not too familiar with the utxo cache in general.

from #33680 (comment):

I was wondering how tracing is affected by this change. The trace includes the mode, and it should display it fine, so the trace should be OK.
It would be nice to check how the trace looks for a FORCE_SYNC case as well; I guess that can be triggered by an RPC call to the running node.

Tested this against a signet node. gettxoutsetinfo produces FORCE_SYNC (and the cache remains filled) and shutting down produces FORCE_FLUSH. As I would have expected.

$ python3 contrib/tracing/log_utxocache_flush.py 1234
Hooking into bitcoind with pid 1234
Logging utxocache flushes. Ctrl-C to end...
Duration (µs)   Mode         Coins Count     Memory Usage    Flush for Prune
3911            FORCE_SYNC   3               262.34 kB       False
12439           FORCE_SYNC   3               262.34 kB       False
4652            FORCE_SYNC   3               262.34 kB       False
1331            FORCE_FLUSH  16              262.46 kB       False
939             FORCE_FLUSH  0               262.24 kB       False

@l0rinc
Copy link
Contributor Author

l0rinc commented Dec 2, 2025

Rebased with trivial conflicts, ready for re-review.

Copy link

@cedwies cedwies left a comment

Choose a reason for hiding this comment

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

reACK 14abac1

@l0rinc
Copy link
Contributor Author

l0rinc commented Dec 16, 2025

Non-trivial rebase after #30214

Changes:

  • The new chainstate_write_tests.cpp also needed renaming in the first commit;
  • ForceFlushStateToDisk(bool wipe_cache = true) is default-true now to minimize the diff.

@cedwies
Copy link

cedwies commented Dec 25, 2025

checked the changes, ACK 11fe88a

l0rinc and others added 2 commits January 3, 2026 12:43
This prepares the addition of `FORCE_SYNC`.

`empty_cache` in `FlushStateToDisk` was moved up to be reusable and `FlushStateMode::FORCE_FLUSH` was used as a placeholder before we properly split the two new states.
`log_utxocache_flush.py` was regenerated and the alignment adjusted for the wider `FlushStateMode` values.

Co-authored-by: Pieter Wuille <[email protected]>
Co-authored-by: optout <[email protected]>
Since bitcoin#28280, the cost of a non-wiping sync of the UTXO cache is only proportional to the number of dirty entries, rather than proportional to the size of the entire cache. Because of that, there is no reason to perform a wiping flush in case the contents of the cache is still useful.

Split the FlushStateMode::ALWAYS mode into a FORCE_SYNC (non-wiping) and a FORCE_FLUSH (wiping), and then use the former in scantxoutset, gettxoutsetinfo, snapshot creation.

Co-authored-by: l0rinc <[email protected]>
Co-authored-by: cedwies <[email protected]>
@l0rinc l0rinc force-pushed the l0rinc/force-sync branch from 11fe88a to c6ca2b8 Compare January 3, 2026 11:44
@l0rinc
Copy link
Contributor Author

l0rinc commented Jan 3, 2026

Trivial rebase after #33866, you can check it with git range-diff -w -U0 master 11fe88a c6ca2b8.
Ready for review again!

@cedwies
Copy link

cedwies commented Jan 3, 2026

reACK c6ca2b8 (trivial)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants