From 430e7027a18870a296abb0bbd9332cbe40d8fdc0 Mon Sep 17 00:00:00 2001 From: furszy Date: Wed, 17 May 2023 00:55:09 -0300 Subject: [PATCH] refactor: index, decouple 'Init' from 'Start' So indexes can be initialized without spawning the sync thread. This makes asynchronous indexes startup possible in the following commits. --- src/index/base.cpp | 18 ++++++++++-------- src/index/base.h | 14 ++++++++------ src/init.cpp | 9 ++++++--- src/init.h | 2 +- src/test/blockfilter_index_tests.cpp | 3 ++- src/test/coinstatsindex_tests.cpp | 9 ++++++--- src/test/txindex_tests.cpp | 3 ++- 7 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/index/base.cpp b/src/index/base.cpp index cf07cae2864..0f25881804f 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -81,6 +81,13 @@ BaseIndex::~BaseIndex() bool BaseIndex::Init() { + // m_chainstate member gives indexing code access to node internals. It is + // removed in followup https://github.com/bitcoin/bitcoin/pull/24230 + m_chainstate = &m_chain->context()->chainman->ActiveChainstate(); + // Register to validation interface before setting the 'm_synced' flag, so that + // callbacks are not missed once m_synced is true. + RegisterValidationInterface(this); + CBlockLocator locator; if (!GetDB().ReadBestBlock(locator)) { locator.SetNull(); @@ -147,6 +154,7 @@ bool BaseIndex::Init() // datadir and an index enabled. If this is the case, indexation will happen solely // via `BlockConnected` signals until, possibly, the next restart. m_synced = synced; + m_init = true; return true; } @@ -401,15 +409,9 @@ void BaseIndex::Interrupt() m_interrupt(); } -bool BaseIndex::Start() +bool BaseIndex::StartBackgroundSync() { - // m_chainstate member gives indexing code access to node internals. It is - // removed in followup https://github.com/bitcoin/bitcoin/pull/24230 - m_chainstate = &m_chain->context()->chainman->ActiveChainstate(); - // Need to register this ValidationInterface before running Init(), so that - // callbacks are not missed if Init sets m_synced to true. - RegisterValidationInterface(this); - if (!Init()) return false; + if (!m_init) throw std::logic_error("Error: Cannot start a non-initialized index"); m_thread_sync = std::thread(&util::TraceThread, GetName(), [this] { ThreadSync(); }); return true; diff --git a/src/index/base.h b/src/index/base.h index 8affee90f86..8b986fe8c42 100644 --- a/src/index/base.h +++ b/src/index/base.h @@ -54,6 +54,8 @@ protected: }; private: + /// Whether the index has been initialized or not. + std::atomic m_init{false}; /// Whether the index is in sync with the main chain. The flag is flipped /// from false to true once, after which point this starts processing /// ValidationInterface notifications to stay in sync. @@ -69,9 +71,6 @@ private: std::thread m_thread_sync; CThreadInterrupt m_interrupt; - /// Read best block locator and check that data needed to sync has not been pruned. - bool Init(); - /// Sync the index with the block index starting from the current best block. /// Intended to be run in its own thread, m_thread_sync, and can be /// interrupted with m_interrupt. Once the index gets in sync, the m_synced @@ -142,9 +141,12 @@ public: void Interrupt(); - /// Start initializes the sync state and registers the instance as a - /// ValidationInterface so that it stays in sync with blockchain updates. - [[nodiscard]] bool Start(); + /// Initializes the sync state and registers the instance to the + /// validation interface so that it stays in sync with blockchain updates. + [[nodiscard]] bool Init(); + + /// Starts the initial sync process. + [[nodiscard]] bool StartBackgroundSync(); /// Stops the instance from staying in sync with blockchain updates. void Stop(); diff --git a/src/init.cpp b/src/init.cpp index 7d44ccc17f2..102e7932cd0 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1567,8 +1567,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) node.indexes.emplace_back(g_coin_stats_index.get()); } + // Init indexes + for (auto index : node.indexes) if (!index->Init()) return false; + // Now that all indexes are loaded, start them - StartIndexes(node); + if (!StartIndexBackgroundSync(node)) return false; // ********************************************************* Step 9: load wallet for (const auto& client : node.chain_clients) { @@ -1876,8 +1879,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) return true; } -bool StartIndexes(NodeContext& node) +bool StartIndexBackgroundSync(NodeContext& node) { - for (auto index : node.indexes) if (!index->Start()) return false; + for (auto index : node.indexes) if (!index->StartBackgroundSync()) return false; return true; } diff --git a/src/init.h b/src/init.h index a050a76b3cc..f27d6120ef3 100644 --- a/src/init.h +++ b/src/init.h @@ -74,6 +74,6 @@ bool AppInitMain(node::NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip void SetupServerArgs(ArgsManager& argsman); /** Validates requirements to run the indexes and spawns each index initial sync thread */ -bool StartIndexes(node::NodeContext& node); +bool StartIndexBackgroundSync(node::NodeContext& node); #endif // BITCOIN_INIT_H diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp index 24af51cce13..9bd5c7c2b6e 100644 --- a/src/test/blockfilter_index_tests.cpp +++ b/src/test/blockfilter_index_tests.cpp @@ -113,6 +113,7 @@ bool BuildChainTestingSetup::BuildChain(const CBlockIndex* pindex, BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup) { BlockFilterIndex filter_index(interfaces::MakeChain(m_node), BlockFilterType::BASIC, 1 << 20, true); + BOOST_REQUIRE(filter_index.Init()); uint256 last_header; @@ -139,7 +140,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup) // BlockUntilSyncedToCurrentChain should return false before index is started. BOOST_CHECK(!filter_index.BlockUntilSyncedToCurrentChain()); - BOOST_REQUIRE(filter_index.Start()); + BOOST_REQUIRE(filter_index.StartBackgroundSync()); // Allow filter index to catch up with the block index. IndexWaitSynced(filter_index); diff --git a/src/test/coinstatsindex_tests.cpp b/src/test/coinstatsindex_tests.cpp index 9dc88ea671d..74d6d7231a7 100644 --- a/src/test/coinstatsindex_tests.cpp +++ b/src/test/coinstatsindex_tests.cpp @@ -18,6 +18,7 @@ BOOST_AUTO_TEST_SUITE(coinstatsindex_tests) BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup) { CoinStatsIndex coin_stats_index{interfaces::MakeChain(m_node), 1 << 20, true}; + BOOST_REQUIRE(coin_stats_index.Init()); const CBlockIndex* block_index; { @@ -32,7 +33,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup) // is started. BOOST_CHECK(!coin_stats_index.BlockUntilSyncedToCurrentChain()); - BOOST_REQUIRE(coin_stats_index.Start()); + BOOST_REQUIRE(coin_stats_index.StartBackgroundSync()); IndexWaitSynced(coin_stats_index); @@ -83,7 +84,8 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup) const CChainParams& params = Params(); { CoinStatsIndex index{interfaces::MakeChain(m_node), 1 << 20}; - BOOST_REQUIRE(index.Start()); + BOOST_REQUIRE(index.Init()); + BOOST_REQUIRE(index.StartBackgroundSync()); IndexWaitSynced(index); std::shared_ptr new_block; CBlockIndex* new_block_index = nullptr; @@ -109,8 +111,9 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup) { CoinStatsIndex index{interfaces::MakeChain(m_node), 1 << 20}; + BOOST_REQUIRE(index.Init()); // Make sure the index can be loaded. - BOOST_REQUIRE(index.Start()); + BOOST_REQUIRE(index.StartBackgroundSync()); index.Stop(); } } diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp index 2677502ef03..cb80dbed69c 100644 --- a/src/test/txindex_tests.cpp +++ b/src/test/txindex_tests.cpp @@ -17,6 +17,7 @@ BOOST_AUTO_TEST_SUITE(txindex_tests) BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup) { TxIndex txindex(interfaces::MakeChain(m_node), 1 << 20, true); + BOOST_REQUIRE(txindex.Init()); CTransactionRef tx_disk; uint256 block_hash; @@ -29,7 +30,7 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup) // BlockUntilSyncedToCurrentChain should return false before txindex is started. BOOST_CHECK(!txindex.BlockUntilSyncedToCurrentChain()); - BOOST_REQUIRE(txindex.Start()); + BOOST_REQUIRE(txindex.StartBackgroundSync()); // Allow tx index to catch up with the block index. IndexWaitSynced(txindex);