Index: Use prune locks for blockfilterindex

Prior to this change blocks could be pruned up to the last block before the blockfilterindex current best block.
This commit is contained in:
Fabian Jahr 2021-04-18 23:06:18 +02:00
parent 2561823531
commit f08c9fb0c6
No known key found for this signature in database
GPG Key ID: F13D1E9D890798CD
7 changed files with 31 additions and 15 deletions

View File

@ -65,9 +65,9 @@ bool BaseIndex::Init()
LOCK(cs_main); LOCK(cs_main);
CChain& active_chain = m_chainstate->m_chain; CChain& active_chain = m_chainstate->m_chain;
if (locator.IsNull()) { if (locator.IsNull()) {
m_best_block_index = nullptr; SetBestBlockIndex(nullptr);
} else { } else {
m_best_block_index = m_chainstate->FindForkInGlobalIndex(locator); SetBestBlockIndex(m_chainstate->FindForkInGlobalIndex(locator));
} }
m_synced = m_best_block_index.load() == active_chain.Tip(); m_synced = m_best_block_index.load() == active_chain.Tip();
if (!m_synced) { if (!m_synced) {
@ -134,7 +134,7 @@ void BaseIndex::ThreadSync()
int64_t last_locator_write_time = 0; int64_t last_locator_write_time = 0;
while (true) { while (true) {
if (m_interrupt) { if (m_interrupt) {
m_best_block_index = pindex; SetBestBlockIndex(pindex);
// No need to handle errors in Commit. If it fails, the error will be already be // No need to handle errors in Commit. If it fails, the error will be already be
// logged. The best way to recover is to continue, as index cannot be corrupted by // logged. The best way to recover is to continue, as index cannot be corrupted by
// a missed commit to disk for an advanced index state. // a missed commit to disk for an advanced index state.
@ -146,7 +146,7 @@ void BaseIndex::ThreadSync()
LOCK(cs_main); LOCK(cs_main);
const CBlockIndex* pindex_next = NextSyncBlock(pindex, m_chainstate->m_chain); const CBlockIndex* pindex_next = NextSyncBlock(pindex, m_chainstate->m_chain);
if (!pindex_next) { if (!pindex_next) {
m_best_block_index = pindex; SetBestBlockIndex(pindex);
m_synced = true; m_synced = true;
// No need to handle errors in Commit. See rationale above. // No need to handle errors in Commit. See rationale above.
Commit(); Commit();
@ -168,7 +168,7 @@ void BaseIndex::ThreadSync()
} }
if (last_locator_write_time + SYNC_LOCATOR_WRITE_INTERVAL < current_time) { if (last_locator_write_time + SYNC_LOCATOR_WRITE_INTERVAL < current_time) {
m_best_block_index = pindex; SetBestBlockIndex(pindex);
last_locator_write_time = current_time; last_locator_write_time = current_time;
// No need to handle errors in Commit. See rationale above. // No need to handle errors in Commit. See rationale above.
Commit(); Commit();
@ -226,10 +226,10 @@ bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_ti
// out of sync may be possible but a users fault. // out of sync may be possible but a users fault.
// In case we reorg beyond the pruned depth, ReadBlockFromDisk would // In case we reorg beyond the pruned depth, ReadBlockFromDisk would
// throw and lead to a graceful shutdown // throw and lead to a graceful shutdown
m_best_block_index = new_tip; SetBestBlockIndex(new_tip);
if (!Commit()) { if (!Commit()) {
// If commit fails, revert the best block index to avoid corruption. // If commit fails, revert the best block index to avoid corruption.
m_best_block_index = current_tip; SetBestBlockIndex(current_tip);
return false; return false;
} }
@ -270,7 +270,7 @@ void BaseIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const
} }
if (WriteBlock(*block, pindex)) { if (WriteBlock(*block, pindex)) {
m_best_block_index = pindex; SetBestBlockIndex(pindex);
} else { } else {
FatalError("%s: Failed to write block %s to index", FatalError("%s: Failed to write block %s to index",
__func__, pindex->GetBlockHash().ToString()); __func__, pindex->GetBlockHash().ToString());
@ -377,3 +377,14 @@ IndexSummary BaseIndex::GetSummary() const
summary.best_block_height = m_best_block_index ? m_best_block_index.load()->nHeight : 0; summary.best_block_height = m_best_block_index ? m_best_block_index.load()->nHeight : 0;
return summary; return summary;
} }
void BaseIndex::SetBestBlockIndex(const CBlockIndex* block) {
assert(!node::fPruneMode || AllowPrune());
m_best_block_index = block;
if (AllowPrune() && block) {
node::PruneLockInfo prune_lock;
prune_lock.height_first = block->nHeight;
WITH_LOCK(::cs_main, m_chainstate->m_blockman.UpdatePruneLock(GetName(), prune_lock));
}
}

View File

@ -75,6 +75,9 @@ private:
/// to a chain reorganization), the index must halt until Commit succeeds or else it could end up /// to a chain reorganization), the index must halt until Commit succeeds or else it could end up
/// getting corrupted. /// getting corrupted.
bool Commit(); bool Commit();
virtual bool AllowPrune() const = 0;
protected: protected:
CChainState* m_chainstate{nullptr}; CChainState* m_chainstate{nullptr};
@ -103,6 +106,9 @@ protected:
/// Get the name of the index for display in logs. /// Get the name of the index for display in logs.
virtual const char* GetName() const = 0; virtual const char* GetName() const = 0;
/// Update the internal best block index as well as the prune lock.
void SetBestBlockIndex(const CBlockIndex* block);
public: public:
/// Destructor interrupts sync thread if running and blocks until it exits. /// Destructor interrupts sync thread if running and blocks until it exits.
virtual ~BaseIndex(); virtual ~BaseIndex();

View File

@ -38,6 +38,8 @@ private:
/** cache of block hash to filter header, to avoid disk access when responding to getcfcheckpt. */ /** cache of block hash to filter header, to avoid disk access when responding to getcfcheckpt. */
std::unordered_map<uint256, uint256, FilterHeaderHasher> m_headers_cache GUARDED_BY(m_cs_headers_cache); std::unordered_map<uint256, uint256, FilterHeaderHasher> m_headers_cache GUARDED_BY(m_cs_headers_cache);
bool AllowPrune() const override { return true; }
protected: protected:
bool Init() override; bool Init() override;

View File

@ -36,6 +36,8 @@ private:
bool ReverseBlock(const CBlock& block, const CBlockIndex* pindex); bool ReverseBlock(const CBlock& block, const CBlockIndex* pindex);
bool AllowPrune() const override { return true; }
protected: protected:
bool Init() override; bool Init() override;

View File

@ -20,6 +20,8 @@ protected:
private: private:
const std::unique_ptr<DB> m_db; const std::unique_ptr<DB> m_db;
bool AllowPrune() const override { return false; }
protected: protected:
bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) override; bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) override;

View File

@ -19,7 +19,6 @@
#include <deploymentstatus.h> #include <deploymentstatus.h>
#include <flatfile.h> #include <flatfile.h>
#include <hash.h> #include <hash.h>
#include <index/blockfilterindex.h>
#include <logging.h> #include <logging.h>
#include <logging/timer.h> #include <logging/timer.h>
#include <node/blockstorage.h> #include <node/blockstorage.h>
@ -2349,10 +2348,6 @@ bool CChainState::FlushStateToDisk(
int last_prune{m_chain.Height()}; // last height we can prune int last_prune{m_chain.Height()}; // last height we can prune
std::optional<std::string> limiting_lock; // prune lock that actually was the limiting factor, only used for logging std::optional<std::string> limiting_lock; // prune lock that actually was the limiting factor, only used for logging
ForEachBlockFilterIndex([&](BlockFilterIndex& index) {
last_prune = std::max(1, std::min(last_prune, index.GetSummary().best_block_height));
});
for (const auto& prune_lock : m_blockman.m_prune_locks) { for (const auto& prune_lock : m_blockman.m_prune_locks) {
if (prune_lock.second.height_first == std::numeric_limits<int>::max()) continue; if (prune_lock.second.height_first == std::numeric_limits<int>::max()) continue;
// Remove the buffer and one additional block here to get actual height that is outside of the buffer // Remove the buffer and one additional block here to get actual height that is outside of the buffer

View File

@ -15,8 +15,6 @@ import sys
EXPECTED_CIRCULAR_DEPENDENCIES = ( EXPECTED_CIRCULAR_DEPENDENCIES = (
"chainparamsbase -> util/system -> chainparamsbase", "chainparamsbase -> util/system -> chainparamsbase",
"node/blockstorage -> validation -> node/blockstorage", "node/blockstorage -> validation -> node/blockstorage",
"index/blockfilterindex -> node/blockstorage -> validation -> index/blockfilterindex",
"index/base -> validation -> index/blockfilterindex -> index/base",
"index/coinstatsindex -> node/coinstats -> index/coinstatsindex", "index/coinstatsindex -> node/coinstats -> index/coinstatsindex",
"policy/fees -> txmempool -> policy/fees", "policy/fees -> txmempool -> policy/fees",
"qt/addresstablemodel -> qt/walletmodel -> qt/addresstablemodel", "qt/addresstablemodel -> qt/walletmodel -> qt/addresstablemodel",