Skip to content

Commit 4368384

Browse files
committed
index: Allow atomic commits of index state to be extended.
1 parent e439aeb commit 4368384

File tree

2 files changed

+41
-15
lines changed

2 files changed

+41
-15
lines changed

src/index/base.cpp

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ bool BaseIndex::DB::ReadBestBlock(CBlockLocator& locator) const
4141
return success;
4242
}
4343

44-
bool BaseIndex::DB::WriteBestBlock(const CBlockLocator& locator)
44+
void BaseIndex::DB::WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator)
4545
{
46-
return Write(DB_BEST_BLOCK, locator);
46+
batch.Write(DB_BEST_BLOCK, locator);
4747
}
4848

4949
BaseIndex::~BaseIndex()
@@ -95,17 +95,22 @@ void BaseIndex::ThreadSync()
9595
int64_t last_locator_write_time = 0;
9696
while (true) {
9797
if (m_interrupt) {
98-
WriteBestBlock(pindex);
98+
m_best_block_index = pindex;
99+
// No need to handle errors in Commit. If it fails, the error will be already be
100+
// logged. The best way to recover is to continue, as index cannot be corrupted by
101+
// a missed commit to disk for an advanced index state.
102+
Commit();
99103
return;
100104
}
101105

102106
{
103107
LOCK(cs_main);
104108
const CBlockIndex* pindex_next = NextSyncBlock(pindex);
105109
if (!pindex_next) {
106-
WriteBestBlock(pindex);
107110
m_best_block_index = pindex;
108111
m_synced = true;
112+
// No need to handle errors in Commit. See rationale above.
113+
Commit();
109114
break;
110115
}
111116
pindex = pindex_next;
@@ -119,8 +124,10 @@ void BaseIndex::ThreadSync()
119124
}
120125

121126
if (last_locator_write_time + SYNC_LOCATOR_WRITE_INTERVAL < current_time) {
122-
WriteBestBlock(pindex);
127+
m_best_block_index = pindex;
123128
last_locator_write_time = current_time;
129+
// No need to handle errors in Commit. See rationale above.
130+
Commit();
124131
}
125132

126133
CBlock block;
@@ -144,15 +151,22 @@ void BaseIndex::ThreadSync()
144151
}
145152
}
146153

147-
bool BaseIndex::WriteBestBlock(const CBlockIndex* block_index)
154+
bool BaseIndex::Commit()
148155
{
149-
LOCK(cs_main);
150-
if (!GetDB().WriteBestBlock(chainActive.GetLocator(block_index))) {
151-
return error("%s: Failed to write locator to disk", __func__);
156+
CDBBatch batch(GetDB());
157+
if (!CommitInternal(batch) || !GetDB().WriteBatch(batch)) {
158+
return error("%s: Failed to commit latest %s state", __func__, GetName());
152159
}
153160
return true;
154161
}
155162

163+
bool BaseIndex::CommitInternal(CDBBatch& batch)
164+
{
165+
LOCK(cs_main);
166+
GetDB().WriteBestBlock(batch, chainActive.GetLocator(m_best_block_index));
167+
return true;
168+
}
169+
156170
void BaseIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex,
157171
const std::vector<CTransactionRef>& txn_conflicted)
158172
{
@@ -224,9 +238,10 @@ void BaseIndex::ChainStateFlushed(const CBlockLocator& locator)
224238
return;
225239
}
226240

227-
if (!GetDB().WriteBestBlock(locator)) {
228-
error("%s: Failed to write locator to disk", __func__);
229-
}
241+
// No need to handle errors in Commit. If it fails, the error will be already be logged. The
242+
// best way to recover is to continue, as index cannot be corrupted by a missed commit to disk
243+
// for an advanced index state.
244+
Commit();
230245
}
231246

232247
bool BaseIndex::BlockUntilSyncedToCurrentChain()

src/index/base.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class BaseIndex : public CValidationInterface
3232
bool ReadBestBlock(CBlockLocator& locator) const;
3333

3434
/// Write block locator of the chain that the txindex is in sync with.
35-
bool WriteBestBlock(const CBlockLocator& locator);
35+
void WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator);
3636
};
3737

3838
private:
@@ -54,8 +54,15 @@ class BaseIndex : public CValidationInterface
5454
/// over and the sync thread exits.
5555
void ThreadSync();
5656

57-
/// Write the current chain block locator to the DB.
58-
bool WriteBestBlock(const CBlockIndex* block_index);
57+
/// Write the current index state (eg. chain block locator and subclass-specific items) to disk.
58+
///
59+
/// Recommendations for error handling:
60+
/// If called on a successor of the previous committed best block in the index, the index can
61+
/// continue processing without risk of corruption, though the index state will need to catch up
62+
/// from further behind on reboot. If the new state is not a successor of the previous state (due
63+
/// to a chain reorganization), the index must halt until Commit succeeds or else it could end up
64+
/// getting corrupted.
65+
bool Commit();
5966

6067
protected:
6168
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex,
@@ -69,6 +76,10 @@ class BaseIndex : public CValidationInterface
6976
/// Write update index entries for a newly connected block.
7077
virtual bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) { return true; }
7178

79+
/// Virtual method called internally by Commit that can be overridden to atomically
80+
/// commit more index state.
81+
virtual bool CommitInternal(CDBBatch& batch);
82+
7283
virtual DB& GetDB() const = 0;
7384

7485
/// Get the name of the index for display in logs.

0 commit comments

Comments
 (0)