mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-06-29 10:19:26 +02:00
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.
This commit is contained in:
@ -81,6 +81,13 @@ BaseIndex::~BaseIndex()
|
|||||||
|
|
||||||
bool BaseIndex::Init()
|
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;
|
CBlockLocator locator;
|
||||||
if (!GetDB().ReadBestBlock(locator)) {
|
if (!GetDB().ReadBestBlock(locator)) {
|
||||||
locator.SetNull();
|
locator.SetNull();
|
||||||
@ -147,6 +154,7 @@ bool BaseIndex::Init()
|
|||||||
// datadir and an index enabled. If this is the case, indexation will happen solely
|
// datadir and an index enabled. If this is the case, indexation will happen solely
|
||||||
// via `BlockConnected` signals until, possibly, the next restart.
|
// via `BlockConnected` signals until, possibly, the next restart.
|
||||||
m_synced = synced;
|
m_synced = synced;
|
||||||
|
m_init = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,15 +409,9 @@ void BaseIndex::Interrupt()
|
|||||||
m_interrupt();
|
m_interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseIndex::Start()
|
bool BaseIndex::StartBackgroundSync()
|
||||||
{
|
{
|
||||||
// m_chainstate member gives indexing code access to node internals. It is
|
if (!m_init) throw std::logic_error("Error: Cannot start a non-initialized index");
|
||||||
// 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;
|
|
||||||
|
|
||||||
m_thread_sync = std::thread(&util::TraceThread, GetName(), [this] { ThreadSync(); });
|
m_thread_sync = std::thread(&util::TraceThread, GetName(), [this] { ThreadSync(); });
|
||||||
return true;
|
return true;
|
||||||
|
@ -54,6 +54,8 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// Whether the index has been initialized or not.
|
||||||
|
std::atomic<bool> m_init{false};
|
||||||
/// Whether the index is in sync with the main chain. The flag is flipped
|
/// 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
|
/// from false to true once, after which point this starts processing
|
||||||
/// ValidationInterface notifications to stay in sync.
|
/// ValidationInterface notifications to stay in sync.
|
||||||
@ -69,9 +71,6 @@ private:
|
|||||||
std::thread m_thread_sync;
|
std::thread m_thread_sync;
|
||||||
CThreadInterrupt m_interrupt;
|
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.
|
/// 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
|
/// 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
|
/// interrupted with m_interrupt. Once the index gets in sync, the m_synced
|
||||||
@ -142,9 +141,12 @@ public:
|
|||||||
|
|
||||||
void Interrupt();
|
void Interrupt();
|
||||||
|
|
||||||
/// Start initializes the sync state and registers the instance as a
|
/// Initializes the sync state and registers the instance to the
|
||||||
/// ValidationInterface so that it stays in sync with blockchain updates.
|
/// validation interface so that it stays in sync with blockchain updates.
|
||||||
[[nodiscard]] bool Start();
|
[[nodiscard]] bool Init();
|
||||||
|
|
||||||
|
/// Starts the initial sync process.
|
||||||
|
[[nodiscard]] bool StartBackgroundSync();
|
||||||
|
|
||||||
/// Stops the instance from staying in sync with blockchain updates.
|
/// Stops the instance from staying in sync with blockchain updates.
|
||||||
void Stop();
|
void Stop();
|
||||||
|
@ -1567,8 +1567,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
|||||||
node.indexes.emplace_back(g_coin_stats_index.get());
|
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
|
// Now that all indexes are loaded, start them
|
||||||
StartIndexes(node);
|
if (!StartIndexBackgroundSync(node)) return false;
|
||||||
|
|
||||||
// ********************************************************* Step 9: load wallet
|
// ********************************************************* Step 9: load wallet
|
||||||
for (const auto& client : node.chain_clients) {
|
for (const auto& client : node.chain_clients) {
|
||||||
@ -1876,8 +1879,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
|||||||
return true;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,6 @@ bool AppInitMain(node::NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip
|
|||||||
void SetupServerArgs(ArgsManager& argsman);
|
void SetupServerArgs(ArgsManager& argsman);
|
||||||
|
|
||||||
/** Validates requirements to run the indexes and spawns each index initial sync thread */
|
/** 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
|
#endif // BITCOIN_INIT_H
|
||||||
|
@ -113,6 +113,7 @@ bool BuildChainTestingSetup::BuildChain(const CBlockIndex* pindex,
|
|||||||
BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
|
BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
|
||||||
{
|
{
|
||||||
BlockFilterIndex filter_index(interfaces::MakeChain(m_node), BlockFilterType::BASIC, 1 << 20, true);
|
BlockFilterIndex filter_index(interfaces::MakeChain(m_node), BlockFilterType::BASIC, 1 << 20, true);
|
||||||
|
BOOST_REQUIRE(filter_index.Init());
|
||||||
|
|
||||||
uint256 last_header;
|
uint256 last_header;
|
||||||
|
|
||||||
@ -139,7 +140,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
|
|||||||
// BlockUntilSyncedToCurrentChain should return false before index is started.
|
// BlockUntilSyncedToCurrentChain should return false before index is started.
|
||||||
BOOST_CHECK(!filter_index.BlockUntilSyncedToCurrentChain());
|
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.
|
// Allow filter index to catch up with the block index.
|
||||||
IndexWaitSynced(filter_index);
|
IndexWaitSynced(filter_index);
|
||||||
|
@ -18,6 +18,7 @@ BOOST_AUTO_TEST_SUITE(coinstatsindex_tests)
|
|||||||
BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
|
BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
|
||||||
{
|
{
|
||||||
CoinStatsIndex coin_stats_index{interfaces::MakeChain(m_node), 1 << 20, true};
|
CoinStatsIndex coin_stats_index{interfaces::MakeChain(m_node), 1 << 20, true};
|
||||||
|
BOOST_REQUIRE(coin_stats_index.Init());
|
||||||
|
|
||||||
const CBlockIndex* block_index;
|
const CBlockIndex* block_index;
|
||||||
{
|
{
|
||||||
@ -32,7 +33,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
|
|||||||
// is started.
|
// is started.
|
||||||
BOOST_CHECK(!coin_stats_index.BlockUntilSyncedToCurrentChain());
|
BOOST_CHECK(!coin_stats_index.BlockUntilSyncedToCurrentChain());
|
||||||
|
|
||||||
BOOST_REQUIRE(coin_stats_index.Start());
|
BOOST_REQUIRE(coin_stats_index.StartBackgroundSync());
|
||||||
|
|
||||||
IndexWaitSynced(coin_stats_index);
|
IndexWaitSynced(coin_stats_index);
|
||||||
|
|
||||||
@ -83,7 +84,8 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup)
|
|||||||
const CChainParams& params = Params();
|
const CChainParams& params = Params();
|
||||||
{
|
{
|
||||||
CoinStatsIndex index{interfaces::MakeChain(m_node), 1 << 20};
|
CoinStatsIndex index{interfaces::MakeChain(m_node), 1 << 20};
|
||||||
BOOST_REQUIRE(index.Start());
|
BOOST_REQUIRE(index.Init());
|
||||||
|
BOOST_REQUIRE(index.StartBackgroundSync());
|
||||||
IndexWaitSynced(index);
|
IndexWaitSynced(index);
|
||||||
std::shared_ptr<const CBlock> new_block;
|
std::shared_ptr<const CBlock> new_block;
|
||||||
CBlockIndex* new_block_index = nullptr;
|
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};
|
CoinStatsIndex index{interfaces::MakeChain(m_node), 1 << 20};
|
||||||
|
BOOST_REQUIRE(index.Init());
|
||||||
// Make sure the index can be loaded.
|
// Make sure the index can be loaded.
|
||||||
BOOST_REQUIRE(index.Start());
|
BOOST_REQUIRE(index.StartBackgroundSync());
|
||||||
index.Stop();
|
index.Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ BOOST_AUTO_TEST_SUITE(txindex_tests)
|
|||||||
BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
|
BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
|
||||||
{
|
{
|
||||||
TxIndex txindex(interfaces::MakeChain(m_node), 1 << 20, true);
|
TxIndex txindex(interfaces::MakeChain(m_node), 1 << 20, true);
|
||||||
|
BOOST_REQUIRE(txindex.Init());
|
||||||
|
|
||||||
CTransactionRef tx_disk;
|
CTransactionRef tx_disk;
|
||||||
uint256 block_hash;
|
uint256 block_hash;
|
||||||
@ -29,7 +30,7 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
|
|||||||
// BlockUntilSyncedToCurrentChain should return false before txindex is started.
|
// BlockUntilSyncedToCurrentChain should return false before txindex is started.
|
||||||
BOOST_CHECK(!txindex.BlockUntilSyncedToCurrentChain());
|
BOOST_CHECK(!txindex.BlockUntilSyncedToCurrentChain());
|
||||||
|
|
||||||
BOOST_REQUIRE(txindex.Start());
|
BOOST_REQUIRE(txindex.StartBackgroundSync());
|
||||||
|
|
||||||
// Allow tx index to catch up with the block index.
|
// Allow tx index to catch up with the block index.
|
||||||
IndexWaitSynced(txindex);
|
IndexWaitSynced(txindex);
|
||||||
|
Reference in New Issue
Block a user