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;
|
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()
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue