Skip to content

Commit fadafab

Browse files
author
MarcoFalke
committed
move-only: Move functions to blockstorage
1 parent fa7e64d commit fadafab

File tree

5 files changed

+267
-264
lines changed

5 files changed

+267
-264
lines changed

src/index/txindex.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include <index/disktxpos.h>
66
#include <index/txindex.h>
7+
#include <node/blockstorage.h>
78
#include <node/ui_interface.h>
89
#include <shutdown.h>
910
#include <util/system.h>

src/node/blockstorage.cpp

Lines changed: 246 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@
66

77
#include <chain.h>
88
#include <chainparams.h>
9+
#include <clientversion.h>
10+
#include <consensus/validation.h>
911
#include <flatfile.h>
1012
#include <fs.h>
13+
#include <hash.h>
1114
#include <pow.h>
1215
#include <shutdown.h>
1316
#include <signet.h>
1417
#include <streams.h>
18+
#include <undo.h>
1519
#include <util/system.h>
1620
#include <validation.h>
1721

@@ -38,6 +42,10 @@ std::set<CBlockIndex*> setDirtyBlockIndex;
3842
std::set<int> setDirtyFileInfo;
3943
// } // namespace
4044

45+
static FILE* OpenUndoFile(const FlatFilePos &pos, bool fReadOnly = false);
46+
static FlatFileSeq BlockFileSeq();
47+
static FlatFileSeq UndoFileSeq();
48+
4149
bool IsBlockPruned(const CBlockIndex* pblockindex)
4250
{
4351
return (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0);
@@ -84,8 +92,217 @@ void CleanupBlockRevFiles()
8492
}
8593
}
8694

87-
// From validation. TODO move here
88-
bool FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigned int nHeight, CChain& active_chain, uint64_t nTime, bool fKnown = false);
95+
std::string CBlockFileInfo::ToString() const
96+
{
97+
return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, FormatISO8601Date(nTimeFirst), FormatISO8601Date(nTimeLast));
98+
}
99+
100+
CBlockFileInfo* GetBlockFileInfo(size_t n)
101+
{
102+
LOCK(cs_LastBlockFile);
103+
104+
return &vinfoBlockFile.at(n);
105+
}
106+
107+
static bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)
108+
{
109+
// Open history file to append
110+
CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
111+
if (fileout.IsNull())
112+
return error("%s: OpenUndoFile failed", __func__);
113+
114+
// Write index header
115+
unsigned int nSize = GetSerializeSize(blockundo, fileout.GetVersion());
116+
fileout << messageStart << nSize;
117+
118+
// Write undo data
119+
long fileOutPos = ftell(fileout.Get());
120+
if (fileOutPos < 0)
121+
return error("%s: ftell failed", __func__);
122+
pos.nPos = (unsigned int)fileOutPos;
123+
fileout << blockundo;
124+
125+
// calculate & write checksum
126+
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
127+
hasher << hashBlock;
128+
hasher << blockundo;
129+
fileout << hasher.GetHash();
130+
131+
return true;
132+
}
133+
134+
bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex)
135+
{
136+
FlatFilePos pos = pindex->GetUndoPos();
137+
if (pos.IsNull()) {
138+
return error("%s: no undo data available", __func__);
139+
}
140+
141+
// Open history file to read
142+
CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
143+
if (filein.IsNull())
144+
return error("%s: OpenUndoFile failed", __func__);
145+
146+
// Read block
147+
uint256 hashChecksum;
148+
CHashVerifier<CAutoFile> verifier(&filein); // We need a CHashVerifier as reserializing may lose data
149+
try {
150+
verifier << pindex->pprev->GetBlockHash();
151+
verifier >> blockundo;
152+
filein >> hashChecksum;
153+
}
154+
catch (const std::exception& e) {
155+
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
156+
}
157+
158+
// Verify checksum
159+
if (hashChecksum != verifier.GetHash())
160+
return error("%s: Checksum mismatch", __func__);
161+
162+
return true;
163+
}
164+
165+
static void FlushUndoFile(int block_file, bool finalize = false)
166+
{
167+
FlatFilePos undo_pos_old(block_file, vinfoBlockFile[block_file].nUndoSize);
168+
if (!UndoFileSeq().Flush(undo_pos_old, finalize)) {
169+
AbortNode("Flushing undo file to disk failed. This is likely the result of an I/O error.");
170+
}
171+
}
172+
173+
void FlushBlockFile(bool fFinalize = false, bool finalize_undo = false)
174+
{
175+
LOCK(cs_LastBlockFile);
176+
FlatFilePos block_pos_old(nLastBlockFile, vinfoBlockFile[nLastBlockFile].nSize);
177+
if (!BlockFileSeq().Flush(block_pos_old, fFinalize)) {
178+
AbortNode("Flushing block file to disk failed. This is likely the result of an I/O error.");
179+
}
180+
// we do not always flush the undo file, as the chain tip may be lagging behind the incoming blocks,
181+
// e.g. during IBD or a sync after a node going offline
182+
if (!fFinalize || finalize_undo) FlushUndoFile(nLastBlockFile, finalize_undo);
183+
}
184+
185+
uint64_t CalculateCurrentUsage()
186+
{
187+
LOCK(cs_LastBlockFile);
188+
189+
uint64_t retval = 0;
190+
for (const CBlockFileInfo &file : vinfoBlockFile) {
191+
retval += file.nSize + file.nUndoSize;
192+
}
193+
return retval;
194+
}
195+
196+
void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune)
197+
{
198+
for (std::set<int>::iterator it = setFilesToPrune.begin(); it != setFilesToPrune.end(); ++it) {
199+
FlatFilePos pos(*it, 0);
200+
fs::remove(BlockFileSeq().FileName(pos));
201+
fs::remove(UndoFileSeq().FileName(pos));
202+
LogPrintf("Prune: %s deleted blk/rev (%05u)\n", __func__, *it);
203+
}
204+
}
205+
206+
static FlatFileSeq BlockFileSeq()
207+
{
208+
return FlatFileSeq(gArgs.GetBlocksDirPath(), "blk", gArgs.GetBoolArg("-fastprune", false) ? 0x4000 /* 16kb */ : BLOCKFILE_CHUNK_SIZE);
209+
}
210+
211+
static FlatFileSeq UndoFileSeq()
212+
{
213+
return FlatFileSeq(gArgs.GetBlocksDirPath(), "rev", UNDOFILE_CHUNK_SIZE);
214+
}
215+
216+
FILE* OpenBlockFile(const FlatFilePos &pos, bool fReadOnly) {
217+
return BlockFileSeq().Open(pos, fReadOnly);
218+
}
219+
220+
/** Open an undo file (rev?????.dat) */
221+
static FILE* OpenUndoFile(const FlatFilePos &pos, bool fReadOnly) {
222+
return UndoFileSeq().Open(pos, fReadOnly);
223+
}
224+
225+
fs::path GetBlockPosFilename(const FlatFilePos &pos)
226+
{
227+
return BlockFileSeq().FileName(pos);
228+
}
229+
230+
bool FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigned int nHeight, CChain& active_chain, uint64_t nTime, bool fKnown = false)
231+
{
232+
LOCK(cs_LastBlockFile);
233+
234+
unsigned int nFile = fKnown ? pos.nFile : nLastBlockFile;
235+
if (vinfoBlockFile.size() <= nFile) {
236+
vinfoBlockFile.resize(nFile + 1);
237+
}
238+
239+
bool finalize_undo = false;
240+
if (!fKnown) {
241+
while (vinfoBlockFile[nFile].nSize + nAddSize >= (gArgs.GetBoolArg("-fastprune", false) ? 0x10000 /* 64kb */ : MAX_BLOCKFILE_SIZE)) {
242+
// when the undo file is keeping up with the block file, we want to flush it explicitly
243+
// when it is lagging behind (more blocks arrive than are being connected), we let the
244+
// undo block write case handle it
245+
assert(std::addressof(::ChainActive()) == std::addressof(active_chain));
246+
finalize_undo = (vinfoBlockFile[nFile].nHeightLast == (unsigned int)active_chain.Tip()->nHeight);
247+
nFile++;
248+
if (vinfoBlockFile.size() <= nFile) {
249+
vinfoBlockFile.resize(nFile + 1);
250+
}
251+
}
252+
pos.nFile = nFile;
253+
pos.nPos = vinfoBlockFile[nFile].nSize;
254+
}
255+
256+
if ((int)nFile != nLastBlockFile) {
257+
if (!fKnown) {
258+
LogPrint(BCLog::VALIDATION, "Leaving block file %i: %s\n", nLastBlockFile, vinfoBlockFile[nLastBlockFile].ToString());
259+
}
260+
FlushBlockFile(!fKnown, finalize_undo);
261+
nLastBlockFile = nFile;
262+
}
263+
264+
vinfoBlockFile[nFile].AddBlock(nHeight, nTime);
265+
if (fKnown)
266+
vinfoBlockFile[nFile].nSize = std::max(pos.nPos + nAddSize, vinfoBlockFile[nFile].nSize);
267+
else
268+
vinfoBlockFile[nFile].nSize += nAddSize;
269+
270+
if (!fKnown) {
271+
bool out_of_space;
272+
size_t bytes_allocated = BlockFileSeq().Allocate(pos, nAddSize, out_of_space);
273+
if (out_of_space) {
274+
return AbortNode("Disk space is too low!", _("Disk space is too low!"));
275+
}
276+
if (bytes_allocated != 0 && fPruneMode) {
277+
fCheckForPruning = true;
278+
}
279+
}
280+
281+
setDirtyFileInfo.insert(nFile);
282+
return true;
283+
}
284+
285+
static bool FindUndoPos(BlockValidationState &state, int nFile, FlatFilePos &pos, unsigned int nAddSize)
286+
{
287+
pos.nFile = nFile;
288+
289+
LOCK(cs_LastBlockFile);
290+
291+
pos.nPos = vinfoBlockFile[nFile].nUndoSize;
292+
vinfoBlockFile[nFile].nUndoSize += nAddSize;
293+
setDirtyFileInfo.insert(nFile);
294+
295+
bool out_of_space;
296+
size_t bytes_allocated = UndoFileSeq().Allocate(pos, nAddSize, out_of_space);
297+
if (out_of_space) {
298+
return AbortNode(state, "Disk space is too low!", _("Disk space is too low!"));
299+
}
300+
if (bytes_allocated != 0 && fPruneMode) {
301+
fCheckForPruning = true;
302+
}
303+
304+
return true;
305+
}
89306

90307
static bool WriteBlockToDisk(const CBlock& block, FlatFilePos& pos, const CMessageHeader::MessageStartChars& messageStart)
91308
{
@@ -110,6 +327,33 @@ static bool WriteBlockToDisk(const CBlock& block, FlatFilePos& pos, const CMessa
110327
return true;
111328
}
112329

330+
bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams)
331+
{
332+
// Write undo information to disk
333+
if (pindex->GetUndoPos().IsNull()) {
334+
FlatFilePos _pos;
335+
if (!FindUndoPos(state, pindex->nFile, _pos, ::GetSerializeSize(blockundo, CLIENT_VERSION) + 40))
336+
return error("ConnectBlock(): FindUndoPos failed");
337+
if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart()))
338+
return AbortNode(state, "Failed to write undo data");
339+
// rev files are written in block height order, whereas blk files are written as blocks come in (often out of order)
340+
// we want to flush the rev (undo) file once we've written the last block, which is indicated by the last height
341+
// in the block file info as below; note that this does not catch the case where the undo writes are keeping up
342+
// with the block writes (usually when a synced up node is getting newly mined blocks) -- this case is caught in
343+
// the FindBlockPos function
344+
if (_pos.nFile < nLastBlockFile && static_cast<uint32_t>(pindex->nHeight) == vinfoBlockFile[_pos.nFile].nHeightLast) {
345+
FlushUndoFile(_pos.nFile, true);
346+
}
347+
348+
// update nUndoPos in block index
349+
pindex->nUndoPos = _pos.nPos;
350+
pindex->nStatus |= BLOCK_HAVE_UNDO;
351+
setDirtyBlockIndex.insert(pindex);
352+
}
353+
354+
return true;
355+
}
356+
113357
bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::Params& consensusParams)
114358
{
115359
block.SetNull();

src/node/blockstorage.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
#include <protocol.h> // For CMessageHeader::MessageStartChars
1313

1414
class ArgsManager;
15+
class BlockValidationState;
1516
class CBlock;
17+
class CBlockFileInfo;
1618
class CBlockIndex;
1719
class CBlockUndo;
1820
class CChain;
@@ -47,13 +49,30 @@ bool IsBlockPruned(const CBlockIndex* pblockindex);
4749

4850
void CleanupBlockRevFiles();
4951

52+
/** Open a block file (blk?????.dat) */
53+
FILE* OpenBlockFile(const FlatFilePos &pos, bool fReadOnly = false);
54+
/** Translation to a filesystem path */
55+
fs::path GetBlockPosFilename(const FlatFilePos &pos);
56+
57+
/** Get block file info entry for one block file */
58+
CBlockFileInfo* GetBlockFileInfo(size_t n);
59+
60+
/** Calculate the amount of disk space the block & undo files currently use */
61+
uint64_t CalculateCurrentUsage();
62+
63+
/**
64+
* Actually unlink the specified files
65+
*/
66+
void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
67+
5068
/** Functions for disk access for blocks */
5169
bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::Params& consensusParams);
5270
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams);
5371
bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start);
5472
bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const CBlockIndex* pindex, const CMessageHeader::MessageStartChars& message_start);
5573

5674
bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex);
75+
bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams);
5776

5877
FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const CChainParams& chainparams, const FlatFilePos* dbp);
5978

0 commit comments

Comments
 (0)