index: Allow atomic commits of index state to be extended.
This commit is contained in:
parent
e439aeb30c
commit
4368384f1d
2 changed files with 41 additions and 15 deletions
|
@ -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,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);
|
||||
if (!GetDB().WriteBestBlock(chainActive.GetLocator(block_index))) {
|
||||
return error("%s: Failed to write locator to disk", __func__);
|
||||
}
|
||||
GetDB().WriteBestBlock(batch, chainActive.GetLocator(m_best_block_index));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -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…
Reference in a new issue