The UTXO set has grown significantly since 2017, and flushing it from memory to LevelDB often takes over 20 minutes after a successful IBD with large dbcache values. The final UTXO set is written to disk in batches, which LevelDB sorts into SST files. By increasing the default batch size, we can reduce overhead from repeated compaction cycles, minimize constant overhead per batch, and achieve more sequential writes.
Experiments with different batch sizes (loaded via assumeutxo at block 840k, then measuring final flush time) show that 64 MiB batches significantly reduce flush time without notably increasing memory usage.
dbbatchsize | flush_sum (ms) |
---|---|
8 « 20 | 236993.73 |
8 « 20 | 239557.79 |
8 « 20 | 244149.25 |
8 « 20 | 246116.93 |
8 « 20 | 243496.98 |
16 « 20 | 209673.01 |
16 « 20 | 225029.97 |
16 « 20 | 230826.61 |
16 « 20 | 230312.84 |
16 « 20 | 235912.83 |
32 « 20 | 201898.77 |
32 « 20 | 196676.18 |
32 « 20 | 198958.81 |
32 « 20 | 196230.08 |
32 « 20 | 199105.84 |
64 « 20 | 150691.51 |
64 « 20 | 151072.18 |
64 « 20 | 151465.16 |
64 « 20 | 150403.59 |
64 « 20 | 150342.34 |
128 « 20 | 155917.81 |
128 « 20 | 156121.83 |
128 « 20 | 156514.6 |
128 « 20 | 155616.36 |
128 « 20 | 156398.24 |
256 « 20 | 166843.39 |
256 « 20 | 166226.37 |
256 « 20 | 166351.75 |
256 « 20 | 166197.15 |
256 « 20 | 166755.22 |
512 « 20 | 186020.24 |
512 « 20 | 186689.18 |
512 « 20 | 186895.21 |
512 « 20 | 185427.1 |
512 « 20 | 186105.48 |
1 « 30 | 185488.98 |
1 « 30 | 185963.51 |
1 « 30 | 185754.25 |
1 « 30 | 186993.17 |
1 « 30 | 186145.73 |
Checking the impact of a -reindex-chainstate
with -stopatheight=878000
and -dbcache=30000
gives:
On SSD:
16 « 20
02025-01-12T07:31:05Z [warning] Flushing large (26 GiB) UTXO set to disk, it may take several minutes
12025-01-12T07:53:51Z Shutdown: done
Flush time before: 22 minutes and 46 seconds
64 « 20
02025-01-12T18:30:00Z [warning] Flushing large (26 GiB) UTXO set to disk, it may take several minutes
12025-01-12T18:44:43Z Shutdown: done
Flush time after: 14 minutes and 43 seconds
On HDD:
16 « 20
02025-01-12T04:31:40Z [warning] Flushing large (26 GiB) UTXO set to disk, it may take several minutes
12025-01-12T05:02:39Z Shutdown: done
Flush time before: 30 minutes and 59 seconds
64 « 20
02025-01-12T20:22:24Z [warning] Flushing large (26 GiB) UTXO set to disk, it may take several minutes
12025-01-12T20:42:57Z Shutdown: done
Flush time after: 20 minutes and 33 seconds
Reproducer:
You can either do a full IBD or a reindex(-chainstate) and check the final logs flush the 840k blocks or load the UTXO set from the assumeUTXO torrent and use that to measure:
0# Build Bitcoin Core
1cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build -j$(nproc)
2
3# Set up a clean demo environment
4mkdir -p demo && rm -rfd demo/chainstate demo/chainstate_snapshot demo/debug.log
5
6# Download the UTXO set until 840k
7See: [#28553](/bitcoin-bitcoin/28553/)
8
9# Start bitcoind with minimal settings without mempool and internet connection
10build/src/bitcoind -datadir=demo -stopatheight=1
11build/src/bitcoind -datadir=demo -daemon -blocksonly=1 -connect=0
12
13# Load the AssumeUTXO snapshot, making sure the path is correct
14# Expected output includes `"coins_loaded": 176948713`
15build/src/bitcoin-cli -datadir=demo loadtxoutset ~/utxo-840000.dat
16
17# Stop the daemon and verify snapshot flushes in the logs
18build/src/bitcoin-cli -datadir=demo stop
19grep "FlushSnapshotToDisk: completed" demo/debug.log