refactor: rename FlushStateMode::ALWAYS to FORCE_FLUSH

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 <pieter@wuille.net>
Co-authored-by: optout <13562139+optout21@users.noreply.github.com>
This commit is contained in:
committed 2026-01-03 12:43:57 +01:00
1 parent ab233255d4
commit 7099e93d0a
7 files changed
+22 -22

No files matched your search

+4 -4
View File
@@ -246,10 +246,10 @@ $ python3 contrib/tracing/log_utxocache_flush.py $(pidof bitcoind)
``` ```
Logging utxocache flushes. Ctrl-C to end... Logging utxocache flushes. Ctrl-C to end...
Duration (µs) Mode Coins Count Memory Usage Prune Duration (µs) Mode Coins Count Memory Usage Flush for Prune
730451 IF_NEEDED 22990 3323.54 kB True 2556340 IF_NEEDED 2899141 394844.34 kB False
637657 ALWAYS 122320 17124.80 kB False 2005788 FORCE_FLUSH 2238117 310189.68 kB False
81349 ALWAYS 0 1383.49 kB False 2685 FORCE_FLUSH 0 262.24 kB False
``` ```
### log_utxos.bt ### log_utxos.bt
+4 -4
View File
@@ -10,7 +10,7 @@ from bcc import BPF, USDT
"""Example logging Bitcoin Core utxo set cache flushes utilizing """Example logging Bitcoin Core utxo set cache flushes utilizing
the utxocache:flush tracepoint.""" the utxocache:flush tracepoint."""
# USAGE: ./contrib/tracing/log_utxocache_flush.py path/to/bitcoind # USAGE: ./contrib/tracing/log_utxocache_flush.py <pid of bitcoind>
# BCC: The C program to be compiled to an eBPF program (by BCC) and loaded into # BCC: The C program to be compiled to an eBPF program (by BCC) and loaded into
# a sandboxed Linux kernel VM. # a sandboxed Linux kernel VM.
@@ -45,7 +45,7 @@ FLUSH_MODES = [
'NONE', 'NONE',
'IF_NEEDED', 'IF_NEEDED',
'PERIODIC', 'PERIODIC',
'ALWAYS' 'FORCE_FLUSH',
] ]
@@ -61,7 +61,7 @@ class Data(ctypes.Structure):
def print_event(event): def print_event(event):
print("%-15d %-10s %-15d %-15s %-8s" % ( print("%-15d %-12s %-15d %-15s %-8s" % (
event.duration, event.duration,
FLUSH_MODES[event.mode], FLUSH_MODES[event.mode],
event.coins_count, event.coins_count,
@@ -88,7 +88,7 @@ def main(pid):
b["flush"].open_perf_buffer(handle_flush) b["flush"].open_perf_buffer(handle_flush)
print("Logging utxocache flushes. Ctrl-C to end...") print("Logging utxocache flushes. Ctrl-C to end...")
print("%-15s %-10s %-15s %-15s %-8s" % ("Duration (µs)", "Mode", print("%-15s %-12s %-15s %-15s %-8s" % ("Duration (µs)", "Mode",
"Coins Count", "Memory Usage", "Coins Count", "Memory Usage",
"Flush for Prune")) "Flush for Prune"))
+2 -2
View File
@@ -185,8 +185,8 @@ Is called *after* the in-memory UTXO cache is flushed.
Arguments passed: Arguments passed:
1. Time it took to flush the cache microseconds as `int64` 1. Time it took to flush the cache microseconds as `int64`
2. Flush state mode as `uint32`. It's an enumerator class with values `0` 2. Flush state mode as `uint32`. It's an enumerator class with values
(`NONE`), `1` (`IF_NEEDED`), `2` (`PERIODIC`), `3` (`ALWAYS`) `0` (`NONE`), `1` (`IF_NEEDED`), `2` (`PERIODIC`), `3` (`FORCE_FLUSH`),
3. Cache size (number of coins) before the flush as `uint64` 3. Cache size (number of coins) before the flush as `uint64`
4. Cache memory usage in bytes as `uint64` 4. Cache memory usage in bytes as `uint64`
5. If pruning caused the flush as `bool` 5. If pruning caused the flush as `bool`
+1 -1
View File
@@ -82,7 +82,7 @@ BOOST_FIXTURE_TEST_CASE(write_during_multiblock_activation, TestChain100Setup)
BOOST_CHECK_EQUAL(second_from_tip->pprev, chainstate.m_chain.Tip()); BOOST_CHECK_EQUAL(second_from_tip->pprev, chainstate.m_chain.Tip());
// Set m_next_write to current time // Set m_next_write to current time
chainstate.FlushStateToDisk(state_dummy, FlushStateMode::ALWAYS); chainstate.FlushStateToDisk(state_dummy, FlushStateMode::FORCE_FLUSH);
m_node.validation_signals->SyncWithValidationInterfaceQueue(); m_node.validation_signals->SyncWithValidationInterfaceQueue();
// The periodic flush interval is between 50 and 70 minutes (inclusive) // The periodic flush interval is between 50 and 70 minutes (inclusive)
// The next call to a PERIODIC write will flush // The next call to a PERIODIC write will flush
+5 -5
View File
@@ -2795,8 +2795,9 @@ bool Chainstate::FlushStateToDisk(
bool fCacheCritical = mode == FlushStateMode::IF_NEEDED && cache_state >= CoinsCacheSizeState::CRITICAL; bool fCacheCritical = mode == FlushStateMode::IF_NEEDED && cache_state >= CoinsCacheSizeState::CRITICAL;
// It's been a while since we wrote the block index and chain state to disk. Do this frequently, so we don't need to redownload or reindex after a crash. // It's been a while since we wrote the block index and chain state to disk. Do this frequently, so we don't need to redownload or reindex after a crash.
bool fPeriodicWrite = mode == FlushStateMode::PERIODIC && nNow >= m_next_write; bool fPeriodicWrite = mode == FlushStateMode::PERIODIC && nNow >= m_next_write;
const auto empty_cache{(mode == FlushStateMode::FORCE_FLUSH) || fCacheLarge || fCacheCritical};
// Combine all conditions that result in a write to disk. // Combine all conditions that result in a write to disk.
bool should_write = (mode == FlushStateMode::ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicWrite || fFlushForPrune; bool should_write = empty_cache || fPeriodicWrite || fFlushForPrune;
// Write blocks, block index and best chain related state to disk. // Write blocks, block index and best chain related state to disk.
if (should_write) { if (should_write) {
LogDebug(BCLog::COINDB, "Writing chainstate to disk: flush mode=%s, prune=%d, large=%d, critical=%d, periodic=%d", LogDebug(BCLog::COINDB, "Writing chainstate to disk: flush mode=%s, prune=%d, large=%d, critical=%d, periodic=%d",
@@ -2844,7 +2845,6 @@ bool Chainstate::FlushStateToDisk(
return FatalError(m_chainman.GetNotifications(), state, _("Disk space is too low!")); return FatalError(m_chainman.GetNotifications(), state, _("Disk space is too low!"));
} }
// Flush the chainstate (which may refer to block index entries). // Flush the chainstate (which may refer to block index entries).
const auto empty_cache{(mode == FlushStateMode::ALWAYS) || fCacheLarge || fCacheCritical};
empty_cache ? CoinsTip().Flush() : CoinsTip().Sync(); empty_cache ? CoinsTip().Flush() : CoinsTip().Sync();
full_flush_completed = true; full_flush_completed = true;
TRACEPOINT(utxocache, flush, TRACEPOINT(utxocache, flush,
@@ -2874,7 +2874,7 @@ bool Chainstate::FlushStateToDisk(
void Chainstate::ForceFlushStateToDisk() void Chainstate::ForceFlushStateToDisk()
{ {
BlockValidationState state; BlockValidationState state;
if (!this->FlushStateToDisk(state, FlushStateMode::ALWAYS)) { if (!this->FlushStateToDisk(state, FlushStateMode::FORCE_FLUSH)) {
LogWarning("Failed to force flush state (%s)", state.ToString()); LogWarning("Failed to force flush state (%s)", state.ToString());
} }
} }
@@ -5546,7 +5546,7 @@ bool Chainstate::ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size)
ret = FlushStateToDisk(state, FlushStateMode::IF_NEEDED); ret = FlushStateToDisk(state, FlushStateMode::IF_NEEDED);
} else { } else {
// Otherwise, flush state to disk and deallocate the in-memory coins map. // Otherwise, flush state to disk and deallocate the in-memory coins map.
ret = FlushStateToDisk(state, FlushStateMode::ALWAYS); ret = FlushStateToDisk(state, FlushStateMode::FORCE_FLUSH);
} }
return ret; return ret;
} }
@@ -5992,7 +5992,7 @@ util::Result<void> ChainstateManager::PopulateAndValidateSnapshot(
// returns in `ActivateSnapshot()`, when `MaybeRebalanceCaches()` is // returns in `ActivateSnapshot()`, when `MaybeRebalanceCaches()` is
// called, since we've added a snapshot chainstate and therefore will // called, since we've added a snapshot chainstate and therefore will
// have to downsize the IBD chainstate, which will result in a call to // have to downsize the IBD chainstate, which will result in a call to
// `FlushStateToDisk(ALWAYS)`. // `FlushStateToDisk(FORCE_FLUSH)`.
} }
assert(index); assert(index);
+3 -3
View File
@@ -457,12 +457,12 @@ enum DisconnectResult
class ConnectTrace; class ConnectTrace;
/** @see Chainstate::FlushStateToDisk */ /** @see Chainstate::FlushStateToDisk */
inline constexpr std::array FlushStateModeNames{"NONE", "IF_NEEDED", "PERIODIC", "ALWAYS"}; inline constexpr std::array FlushStateModeNames{"NONE", "IF_NEEDED", "PERIODIC", "FORCE_FLUSH"};
enum class FlushStateMode: uint8_t { enum class FlushStateMode: uint8_t {
NONE, NONE,
IF_NEEDED, IF_NEEDED,
PERIODIC, PERIODIC,
ALWAYS FORCE_FLUSH,
}; };
/** /**
@@ -735,7 +735,7 @@ public:
FlushStateMode mode, FlushStateMode mode,
int nManualPruneHeight = 0); int nManualPruneHeight = 0);
//! Unconditionally flush all changes to disk. //! Flush all changes to disk.
void ForceFlushStateToDisk(); void ForceFlushStateToDisk();
//! Prune blockfiles from the disk if necessary and then flush chainstate changes //! Prune blockfiles from the disk if necessary and then flush chainstate changes
+3 -3
View File
@@ -109,7 +109,7 @@ FLUSHMODE_NAME = {
0: "NONE", 0: "NONE",
1: "IF_NEEDED", 1: "IF_NEEDED",
2: "PERIODIC", 2: "PERIODIC",
3: "ALWAYS", 3: "FORCE_FLUSH",
} }
@@ -389,8 +389,8 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
# A node shutdown causes two flushes. One that flushes UTXOS_IN_CACHE # A node shutdown causes two flushes. One that flushes UTXOS_IN_CACHE
# UTXOs and one that flushes 0 UTXOs. Normally the 0-UTXO-flush is the # UTXOs and one that flushes 0 UTXOs. Normally the 0-UTXO-flush is the
# second flush, however it can happen that the order changes. # second flush, however it can happen that the order changes.
expected_flushes.append({"mode": "ALWAYS", "for_prune": False, "size": UTXOS_IN_CACHE}) expected_flushes.append({"mode": "FORCE_FLUSH", "for_prune": False, "size": UTXOS_IN_CACHE})
expected_flushes.append({"mode": "ALWAYS", "for_prune": False, "size": 0}) expected_flushes.append({"mode": "FORCE_FLUSH", "for_prune": False, "size": 0})
self.stop_node(0) self.stop_node(0)
bpf.perf_buffer_poll(timeout=200) bpf.perf_buffer_poll(timeout=200)