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

pull/14121/head
Jim Posen 6 years ago
parent e439aeb30c
commit 4368384f1d

@ -41,9 +41,9 @@ bool BaseIndex::DB::ReadBestBlock(CBlockLocator& locator) const
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()
@ -95,7 +95,11 @@ void BaseIndex::ThreadSync()
int64_t last_locator_write_time = 0;
while (true) {
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;
}
@ -103,9 +107,10 @@ void BaseIndex::ThreadSync()
LOCK(cs_main);
const CBlockIndex* pindex_next = NextSyncBlock(pindex);
if (!pindex_next) {
WriteBestBlock(pindex);
m_best_block_index = pindex;
m_synced = true;
// No need to handle errors in Commit. See rationale above.
Commit();
break;
}
pindex = pindex_next;
@ -119,8 +124,10 @@ void BaseIndex::ThreadSync()
}
if (last_locator_write_time + SYNC_LOCATOR_WRITE_INTERVAL < current_time) {
WriteBestBlock(pindex);
m_best_block_index = pindex;
last_locator_write_time = current_time;
// No need to handle errors in Commit. See rationale above.
Commit();
}
CBlock block;
@ -144,15 +151,22 @@ void BaseIndex::ThreadSync()
}
}
bool BaseIndex::WriteBestBlock(const CBlockIndex* block_index)
bool BaseIndex::Commit()
{
LOCK(cs_main);
if (!GetDB().WriteBestBlock(chainActive.GetLocator(block_index))) {
return error("%s: Failed to write locator to disk", __func__);
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);
GetDB().WriteBestBlock(batch, chainActive.GetLocator(m_best_block_index));
return true;
}
void BaseIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex,
const std::vector<CTransactionRef>& txn_conflicted)
{
@ -224,9 +238,10 @@ void BaseIndex::ChainStateFlushed(const CBlockLocator& locator)
return;
}
if (!GetDB().WriteBestBlock(locator)) {
error("%s: Failed to write locator to disk", __func__);
}
// 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();
}
bool BaseIndex::BlockUntilSyncedToCurrentChain()

@ -32,7 +32,7 @@ protected:
bool ReadBestBlock(CBlockLocator& locator) const;
/// 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:
@ -54,8 +54,15 @@ private:
/// over and the sync thread exits.
void ThreadSync();
/// Write the current chain block locator to the DB.
bool WriteBestBlock(const CBlockIndex* block_index);
/// Write the current index state (eg. chain block locator and subclass-specific items) to disk.
///
/// 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:
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.
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;
/// Get the name of the index for display in logs.

Loading…
Cancel
Save