mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-04 18:22:57 +02:00
Merge bitcoin/bitcoin#30611: validation: write chainstate to disk every hour
e976bd3045validation: add randomness to periodic write interval (Andrew Toth)2e2f410681refactor: replace m_last_write with m_next_write (Andrew Toth)b557fa7a17refactor: rename fDoFullFlush to should_write (Andrew Toth)d73bd9fbe4validation: write chainstate to disk every hour (Andrew Toth)0ad7d7abdbtest: chainstate write test for periodic chainstate flush (Andrew Toth) Pull request description: Since #28233, periodically writing the chainstate to disk every 24 hours does not clear the dbcache. Since #28280, periodically writing the chainstate to disk is proportional only to the amount of dirty entries in the cache. Due to these changes, it is no longer beneficial to only write the chainstate to disk every 24 hours. The periodic flush interval was necessary because every write of the chainstate would clear the dbcache. Now, we can get rid of the periodic flush interval and simply write the chainstate along with blocks and block index at least every hour. Three benefits of doing this: 1. For IBD or reindex-chainstate with a combination of large dbcache setting, slow CPU, slow internet speed/unreliable peers, it could be up to 24 hours until the chainstate is persisted to disk. A power outage or crash could potentially lose up to 24 hours of progress. If there is a very large amount of dirty cache entries, writing to disk when a flush finally does occur will take a very long time. Crashing during this window of writing can cause https://github.com/bitcoin/bitcoin/issues/11600. By syncing every hour in unison with the block index we avoid this problem. Only a maximum of one hour of progress can be lost, and the window for crashing during writing is much smaller. For IBD with lower dbcache settings, faster CPU, or better internet speed/reliable peers, chainstate writes are already triggered more often than every hour so this change will have no effect on IBD. 2. Based on discussion in #28280, writing only once every 24 hours during long running operation of a node causes IO spikes. Writing smaller chainstate changes every hour like we do with blocks and block index will reduce IO spikes. 3. Faster shutdown speeds. All dirty chainstate entries must be persisted to disk on shutdown. If we have a lot of dirty entries, such as when close to 24 hours or if we sync with a large dbcache, it can take a long time to shutdown. By keeping the chainstate clean we avoid this problem. Inspired by [this comment](https://github.com/bitcoin/bitcoin/pull/28280#issuecomment-2121088705). Resolves https://github.com/bitcoin/bitcoin/issues/11600 ACKs for top commit: achow101: ACKe976bd3045davidgumberg: utACKe976bd3045sipa: utACKe976bd3045l0rinc: ACKe976bd3045Tree-SHA512: 5bccd8f1dea47f9820a3fd32fe3bb6841c0167b3d6870cc8f3f7e2368f124af1a914bca6acb06889cd7183638a8dbdbace54d3237c3683f2b567eb7355e015ee
This commit is contained in:
@@ -25,6 +25,7 @@ add_executable(test_bitcoin
|
||||
blockmanager_tests.cpp
|
||||
bloom_tests.cpp
|
||||
bswap_tests.cpp
|
||||
chainstate_write_tests.cpp
|
||||
checkqueue_tests.cpp
|
||||
cluster_linearize_tests.cpp
|
||||
coins_tests.cpp
|
||||
|
||||
45
src/test/chainstate_write_tests.cpp
Normal file
45
src/test/chainstate_write_tests.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <test/util/setup_common.h>
|
||||
#include <validation.h>
|
||||
#include <validationinterface.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(chainstate_write_tests)
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(chainstate_write_interval, TestingSetup)
|
||||
{
|
||||
struct TestSubscriber final : CValidationInterface {
|
||||
bool m_did_flush{false};
|
||||
void ChainStateFlushed(ChainstateRole, const CBlockLocator&) override
|
||||
{
|
||||
m_did_flush = true;
|
||||
}
|
||||
};
|
||||
|
||||
const auto sub{std::make_shared<TestSubscriber>()};
|
||||
m_node.validation_signals->RegisterSharedValidationInterface(sub);
|
||||
auto& chainstate{Assert(m_node.chainman)->ActiveChainstate()};
|
||||
BlockValidationState state_dummy{};
|
||||
|
||||
// The first periodic flush sets m_next_write and does not flush
|
||||
chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC);
|
||||
m_node.validation_signals->SyncWithValidationInterfaceQueue();
|
||||
BOOST_CHECK(!sub->m_did_flush);
|
||||
|
||||
// The periodic flush interval is between 50 and 70 minutes (inclusive)
|
||||
SetMockTime(GetTime<std::chrono::minutes>() + 49min);
|
||||
chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC);
|
||||
m_node.validation_signals->SyncWithValidationInterfaceQueue();
|
||||
BOOST_CHECK(!sub->m_did_flush);
|
||||
|
||||
SetMockTime(GetTime<std::chrono::minutes>() + 70min);
|
||||
chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC);
|
||||
m_node.validation_signals->SyncWithValidationInterfaceQueue();
|
||||
BOOST_CHECK(sub->m_did_flush);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
Reference in New Issue
Block a user