0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-03 09:56:38 -05:00

Merge bitcoin/bitcoin#28233: validation: don't clear cache on periodic flush: >2x block connection speed

4a6d1d1e3b validation: don't clear cache on periodic flush (Andrew Toth)

Pull request description:

  Since https://github.com/bitcoin/bitcoin/pull/17487 we no longer need to clear the coins cache when syncing to disk. A warm coins cache significantly speeds up block connection, and only needs to be fully flushed when nearing the `dbcache` limit.

  Periodic flushes occur every 24 hours, which empties the cache and causes block connection to slow down. By keeping the cache through periodic flushes a node can run for several days with an increasingly hotter cache and connect blocks much more quickly. Now not only can setting a higher `dbcache` value be beneficial for IBD, it can also be beneficial for connecting blocks faster.

  To benchmark in real world usage, I spun up 6 identical `t2.small` AWS EC2 instances, all running in the same region in the same VPC. I configured 2 instances to run master, 2 instances to run the change in this PR, and 2 instances to run the change in this PR but with `dbcache=1000`. All instances had `prune=5000` and a 20 GB `gp2` `EBS` volume. A 7th EC2 instance in the same VPC ran master and connected only to some trusted nodes in the outside network. Each of the 6 nodes under test only connected directly to this 7th instance. I manually pruned as much as possible and uploaded the same `blocks`, `chainstate` and `mempool.dat` to all instances. I started all 6 peers simultaneously at block height `835245` and ran them for over a week until block `836534`.

  The results were much faster block connection times for this branch compared to master, and much faster for this branch with `dbcache=1000` compared to default `dbcache`.

  |  branch |speed |
  |-----------:|----------:|
  | master 1 | 1995.49ms/blk |
  | master 2 | 2129.78ms/blk |
  | branch default dbcache 1 | 1189.65ms/blk |
  | branch default dbcache 2 | 1037.74ms/blk |
  | branch dbcache=1000 1 | 393.69ms/blk |
  | branch dbcache=1000 2 | 427.77ms/blk |

  The log files of all 6 instances are [here](https://gist.github.com/andrewtoth/03c95033e7581d5dbc5be028639a1a91).
  There is a lot of noise with the exact times of blocks being connected, so I plotted the rolling 20 block connect time averages. The large dots are the times where the cache is emptied. For the red master nodes, this happens every 24 hours. The blue branch nodes with default `dbcache` only filled up and emptied the caches once, which is seen in the middle. The green branch nodes with 1000 `dbcache` never emptied the cache. It is very clear from the chart that whenever the cache is emptied, connect block speed degrades significantly.

  ![plot](https://github.com/bitcoin/bitcoin/assets/237213/802cb28d-1ad4-47c3-a886-c5366b423eca)

  Also note that this still clears the cache for pruning flushes. Having frequent pruning flushes with a large cache that doesn't clear is less performant than the status quo https://github.com/bitcoin/bitcoin/pull/15265#issuecomment-458657451. See https://github.com/bitcoin/bitcoin/pull/28280.

ACKs for top commit:
  sipa:
    utACK 4a6d1d1e3b
  achow101:
    ACK 4a6d1d1e3b
  brunoerg:
    crACK 4a6d1d1e3b

Tree-SHA512: 05dbc677bc309bbcf89c52a6c5e853e2816b0ef0b5ee3719b30696df315a0427e244bb82da9ad828ec0e7ea8764552f8affe14c0184b52adf1909f5d8c1b4f9e
This commit is contained in:
Ava Chow 2024-05-13 16:31:19 -04:00
commit d6069cb8d6
No known key found for this signature in database
GPG key ID: 17565732E08E5E41

View file

@ -2748,8 +2748,10 @@ 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).
if (!CoinsTip().Flush()) const auto empty_cache{(mode == FlushStateMode::ALWAYS) || fCacheLarge || fCacheCritical || fFlushForPrune};
if (empty_cache ? !CoinsTip().Flush() : !CoinsTip().Sync()) {
return FatalError(m_chainman.GetNotifications(), state, _("Failed to write to coin database.")); return FatalError(m_chainman.GetNotifications(), state, _("Failed to write to coin database."));
}
m_last_flush = nNow; m_last_flush = nNow;
full_flush_completed = true; full_flush_completed = true;
TRACE5(utxocache, flush, TRACE5(utxocache, flush,