diff --git a/contrib/tracing/README.md b/contrib/tracing/README.md index 252053e7b87..f5095d6ba80 100644 --- a/contrib/tracing/README.md +++ b/contrib/tracing/README.md @@ -246,10 +246,10 @@ $ python3 contrib/tracing/log_utxocache_flush.py $(pidof bitcoind) ``` Logging utxocache flushes. Ctrl-C to end... -Duration (µs) Mode Coins Count Memory Usage Prune -730451 IF_NEEDED 22990 3323.54 kB True -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 +2005788 FORCE_FLUSH 2238117 310189.68 kB False +2685 FORCE_FLUSH 0 262.24 kB False ``` ### log_utxos.bt diff --git a/contrib/tracing/log_utxocache_flush.py b/contrib/tracing/log_utxocache_flush.py index 230b38e975b..bcbc79dfb30 100755 --- a/contrib/tracing/log_utxocache_flush.py +++ b/contrib/tracing/log_utxocache_flush.py @@ -10,7 +10,7 @@ from bcc import BPF, USDT """Example logging Bitcoin Core utxo set cache flushes utilizing the utxocache:flush tracepoint.""" -# USAGE: ./contrib/tracing/log_utxocache_flush.py path/to/bitcoind +# USAGE: ./contrib/tracing/log_utxocache_flush.py # BCC: The C program to be compiled to an eBPF program (by BCC) and loaded into # a sandboxed Linux kernel VM. @@ -45,7 +45,7 @@ FLUSH_MODES = [ 'NONE', 'IF_NEEDED', 'PERIODIC', - 'ALWAYS' + 'FORCE_FLUSH', ] @@ -61,7 +61,7 @@ class Data(ctypes.Structure): def print_event(event): - print("%-15d %-10s %-15d %-15s %-8s" % ( + print("%-15d %-12s %-15d %-15s %-8s" % ( event.duration, FLUSH_MODES[event.mode], event.coins_count, @@ -88,7 +88,7 @@ def main(pid): b["flush"].open_perf_buffer(handle_flush) 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", "Flush for Prune")) diff --git a/doc/tracing.md b/doc/tracing.md index 927fd34b553..e0e96b044eb 100644 --- a/doc/tracing.md +++ b/doc/tracing.md @@ -185,8 +185,8 @@ Is called *after* the in-memory UTXO cache is flushed. Arguments passed: 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` - (`NONE`), `1` (`IF_NEEDED`), `2` (`PERIODIC`), `3` (`ALWAYS`) +2. Flush state mode as `uint32`. It's an enumerator class with values + `0` (`NONE`), `1` (`IF_NEEDED`), `2` (`PERIODIC`), `3` (`FORCE_FLUSH`), 3. Cache size (number of coins) before the flush as `uint64` 4. Cache memory usage in bytes as `uint64` 5. If pruning caused the flush as `bool` diff --git a/src/test/chainstate_write_tests.cpp b/src/test/chainstate_write_tests.cpp index 5c459227763..4a79cd8a463 100644 --- a/src/test/chainstate_write_tests.cpp +++ b/src/test/chainstate_write_tests.cpp @@ -82,7 +82,7 @@ BOOST_FIXTURE_TEST_CASE(write_during_multiblock_activation, TestChain100Setup) BOOST_CHECK_EQUAL(second_from_tip->pprev, chainstate.m_chain.Tip()); // 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(); // The periodic flush interval is between 50 and 70 minutes (inclusive) // The next call to a PERIODIC write will flush diff --git a/src/validation.cpp b/src/validation.cpp index b6da6d2d8d6..c8d326e5802 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2795,8 +2795,9 @@ bool Chainstate::FlushStateToDisk( 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. 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. - 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. if (should_write) { 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!")); } // 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(); full_flush_completed = true; TRACEPOINT(utxocache, flush, @@ -2874,7 +2874,7 @@ bool Chainstate::FlushStateToDisk( void Chainstate::ForceFlushStateToDisk() { BlockValidationState state; - if (!this->FlushStateToDisk(state, FlushStateMode::ALWAYS)) { + if (!this->FlushStateToDisk(state, FlushStateMode::FORCE_FLUSH)) { 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); } else { // 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; } @@ -5992,7 +5992,7 @@ util::Result ChainstateManager::PopulateAndValidateSnapshot( // returns in `ActivateSnapshot()`, when `MaybeRebalanceCaches()` is // called, since we've added a snapshot chainstate and therefore will // have to downsize the IBD chainstate, which will result in a call to - // `FlushStateToDisk(ALWAYS)`. + // `FlushStateToDisk(FORCE_FLUSH)`. } assert(index); diff --git a/src/validation.h b/src/validation.h index e4b1e555bdd..fb96de4e2eb 100644 --- a/src/validation.h +++ b/src/validation.h @@ -457,12 +457,12 @@ enum DisconnectResult class ConnectTrace; /** @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 { NONE, IF_NEEDED, PERIODIC, - ALWAYS + FORCE_FLUSH, }; /** @@ -735,7 +735,7 @@ public: FlushStateMode mode, int nManualPruneHeight = 0); - //! Unconditionally flush all changes to disk. + //! Flush all changes to disk. void ForceFlushStateToDisk(); //! Prune blockfiles from the disk if necessary and then flush chainstate changes diff --git a/test/functional/interface_usdt_utxocache.py b/test/functional/interface_usdt_utxocache.py index fe7f7e3adb6..bbdb8b9a6b6 100755 --- a/test/functional/interface_usdt_utxocache.py +++ b/test/functional/interface_usdt_utxocache.py @@ -109,7 +109,7 @@ FLUSHMODE_NAME = { 0: "NONE", 1: "IF_NEEDED", 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 # UTXOs and one that flushes 0 UTXOs. Normally the 0-UTXO-flush is the # 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": "ALWAYS", "for_prune": False, "size": 0}) + expected_flushes.append({"mode": "FORCE_FLUSH", "for_prune": False, "size": UTXOS_IN_CACHE}) + expected_flushes.append({"mode": "FORCE_FLUSH", "for_prune": False, "size": 0}) self.stop_node(0) bpf.perf_buffer_poll(timeout=200)