index: Allow atomic commits of index state to be extended.

This commit is contained in:
Jim Posen 2019-03-02 18:35:55 -08:00
parent e439aeb30c
commit 4368384f1d
2 changed files with 41 additions and 15 deletions

View file

@ -41,9 +41,9 @@ bool BaseIndex::DB::ReadBestBlock(CBlockLocator& locator) const
return success; return success;
} }
bool BaseIndex::DB::WriteBestBlock(const CBlockLocator& locator) void BaseIndex::DB::WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator)
{ {
return Write(DB_BEST_BLOCK, locator); batch.Write(DB_BEST_BLOCK, locator);
} }
BaseIndex::~BaseIndex() BaseIndex::~BaseIndex()
@ -95,7 +95,11 @@ 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) {
WriteBestBlock(pindex); m_best_block_index = pindex;
// 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
// a missed commit to disk for an advanced index state.
Commit();
return; return;
} }
@ -103,9 +107,10 @@ void BaseIndex::ThreadSync()
LOCK(cs_main); LOCK(cs_main);
const CBlockIndex* pindex_next = NextSyncBlock(pindex); const CBlockIndex* pindex_next = NextSyncBlock(pindex);
if (!pindex_next) { if (!pindex_next) {
WriteBestBlock(pindex);
m_best_block_index = pindex; m_best_block_index = pindex;
m_synced = true; m_synced = true;
// No need to handle errors in Commit. See rationale above.
Commit();
break; break;
} }
pindex = pindex_next; pindex = pindex_next;
@ -119,8 +124,10 @@ 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) {
WriteBestBlock(pindex); m_best_block_index = pindex;
last_locator_write_time = current_time; last_locator_write_time = current_time;
// No need to handle errors in Commit. See rationale above.
Commit();
} }
CBlock block; CBlock block;
@ -144,12 +151,19 @@ void BaseIndex::ThreadSync()
} }
} }
bool BaseIndex::WriteBestBlock(const CBlockIndex* block_index) bool BaseIndex::Commit()
{
CDBBatch batch(GetDB());
if (!CommitInternal(batch) || !GetDB().WriteBatch(batch)) {
return error("%s: Failed to commit latest %s state", __func__, GetName());
}
return true;
}
bool BaseIndex::CommitInternal(CDBBatch& batch)
{ {
LOCK(cs_main); LOCK(cs_main);
if (!GetDB().WriteBestBlock(chainActive.GetLocator(block_index))) { GetDB().WriteBestBlock(batch, chainActive.GetLocator(m_best_block_index));
return error("%s: Failed to write locator to disk", __func__);
}
return true; return true;
} }
@ -224,9 +238,10 @@ void BaseIndex::ChainStateFlushed(const CBlockLocator& locator)
return; return;
} }
if (!GetDB().WriteBestBlock(locator)) { // No need to handle errors in Commit. If it fails, the error will be already be logged. The
error("%s: Failed to write locator to disk", __func__); // best way to recover is to continue, as index cannot be corrupted by a missed commit to disk
} // for an advanced index state.
Commit();
} }
bool BaseIndex::BlockUntilSyncedToCurrentChain() bool BaseIndex::BlockUntilSyncedToCurrentChain()

View file

@ -32,7 +32,7 @@ protected:
bool ReadBestBlock(CBlockLocator& locator) const; bool ReadBestBlock(CBlockLocator& locator) const;
/// Write block locator of the chain that the txindex is in sync with. /// Write block locator of the chain that the txindex is in sync with.
bool WriteBestBlock(const CBlockLocator& locator); void WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator);
}; };
private: private:
@ -54,8 +54,15 @@ private:
/// over and the sync thread exits. /// over and the sync thread exits.
void ThreadSync(); void ThreadSync();
/// Write the current chain block locator to the DB. /// Write the current index state (eg. chain block locator and subclass-specific items) to disk.
bool WriteBestBlock(const CBlockIndex* block_index); ///
/// Recommendations for error handling:
/// If called on a successor of the previous committed best block in the index, the index can
/// continue processing without risk of corruption, though the index state will need to catch up
/// from further behind on reboot. If the new state is not a successor of the previous state (due
/// to a chain reorganization), the index must halt until Commit succeeds or else it could end up
/// getting corrupted.
bool Commit();
protected: protected:
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex, void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex,
@ -69,6 +76,10 @@ protected:
/// Write update index entries for a newly connected block. /// Write update index entries for a newly connected block.
virtual bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) { return true; } virtual bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) { return true; }
/// Virtual method called internally by Commit that can be overridden to atomically
/// commit more index state.
virtual bool CommitInternal(CDBBatch& batch);
virtual DB& GetDB() const = 0; virtual DB& GetDB() const = 0;
/// Get the name of the index for display in logs. /// Get the name of the index for display in logs.