Skip to content

Commit

Permalink
Merge bitcoin/bitcoin#28483: refactor: Return CAutoFile from BlockMan…
Browse files Browse the repository at this point in the history
…ager::Open*File()

fa56c42 Return CAutoFile from BlockManager::Open*File() (MarcoFalke)
9999b89 Make BufferedFile to be a CAutoFile wrapper (MarcoFalke)
fa389d9 refactor: Drop unused fclose() from BufferedFile (MarcoFalke)

Pull request description:

  This is required for bitcoin/bitcoin#28052, but makes sense on its own, because offloading logic to `CAutoFile` instead of re-implementing it allows to delete code and complexity.

ACKs for top commit:
  TheCharlatan:
    Re-ACK fa56c42
  willcl-ark:
    tACK fa56c42

Tree-SHA512: fe4638f3a6bd3f9d968cfb9ae3259c9d6cd278fe2912cbc90289851311c8c781099db4c160e775960975c4739098d9af801a8d2d12603f371f8edfe134d8f85a
  • Loading branch information
fanquake committed Sep 26, 2023
2 parents dcfbf3c + fa56c42 commit c9f2882
Show file tree
Hide file tree
Showing 12 changed files with 66 additions and 84 deletions.
3 changes: 2 additions & 1 deletion src/bench/load_external.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <bench/bench.h>
#include <bench/data.h>
#include <chainparams.h>
#include <clientversion.h>
#include <test/util/setup_common.h>
#include <util/chaintype.h>
#include <validation.h>
Expand Down Expand Up @@ -54,7 +55,7 @@ static void LoadExternalBlockFile(benchmark::Bench& bench)
bench.run([&] {
// "rb" is "binary, O_RDONLY", positioned to the start of the file.
// The file will be closed by LoadExternalBlockFile().
FILE* file{fsbridge::fopen(blkfile, "rb")};
CAutoFile file{fsbridge::fopen(blkfile, "rb"), CLIENT_VERSION};
testing_setup->m_node.chainman->LoadExternalBlockFile(file, &pos, &blocks_with_unknown_parent);
});
fs::remove(blkfile);
Expand Down
16 changes: 10 additions & 6 deletions src/bench/streams_findbyte.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,31 @@

#include <bench/bench.h>

#include <util/fs.h>
#include <streams.h>
#include <util/fs.h>

#include <cstddef>
#include <cstdint>
#include <cstdio>

static void FindByte(benchmark::Bench& bench)
{
// Setup
FILE* file = fsbridge::fopen("streams_tmp", "w+b");
CAutoFile file{fsbridge::fopen("streams_tmp", "w+b"), 0};
const size_t file_size = 200;
uint8_t data[file_size] = {0};
data[file_size-1] = 1;
fwrite(&data, sizeof(uint8_t), file_size, file);
rewind(file);
BufferedFile bf{file, /*nBufSize=*/file_size + 1, /*nRewindIn=*/file_size, 0};
file << data;
std::rewind(file.Get());
BufferedFile bf{file, /*nBufSize=*/file_size + 1, /*nRewindIn=*/file_size};

bench.run([&] {
bf.SetPos(0);
bf.FindByte(std::byte(1));
});

// Cleanup
bf.fclose();
file.fclose();
fs::remove("streams_tmp");
}

Expand Down
2 changes: 1 addition & 1 deletion src/index/txindex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ bool TxIndex::FindTx(const uint256& tx_hash, uint256& block_hash, CTransactionRe
return false;
}

CAutoFile file{m_chainstate->m_blockman.OpenBlockFile(postx, true), CLIENT_VERSION};
CAutoFile file{m_chainstate->m_blockman.OpenBlockFile(postx, true)};
if (file.IsNull()) {
return error("%s: OpenBlockFile failed", __func__);
}
Expand Down
28 changes: 14 additions & 14 deletions src/node/blockstorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ bool BlockManager::LoadBlockIndexDB()
}
for (std::set<int>::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++) {
FlatFilePos pos(*it, 0);
if (AutoFile{OpenBlockFile(pos, true)}.IsNull()) {
if (OpenBlockFile(pos, true).IsNull()) {
return false;
}
}
Expand Down Expand Up @@ -592,7 +592,7 @@ CBlockFileInfo* BlockManager::GetBlockFileInfo(size_t n)
bool BlockManager::UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock) const
{
// Open history file to append
AutoFile fileout{OpenUndoFile(pos)};
CAutoFile fileout{OpenUndoFile(pos)};
if (fileout.IsNull()) {
return error("%s: OpenUndoFile failed", __func__);
}
Expand Down Expand Up @@ -627,7 +627,7 @@ bool BlockManager::UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex& in
}

// Open history file to read
AutoFile filein{OpenUndoFile(pos, true)};
CAutoFile filein{OpenUndoFile(pos, true)};
if (filein.IsNull()) {
return error("%s: OpenUndoFile failed", __func__);
}
Expand Down Expand Up @@ -715,15 +715,15 @@ FlatFileSeq BlockManager::UndoFileSeq() const
return FlatFileSeq(m_opts.blocks_dir, "rev", UNDOFILE_CHUNK_SIZE);
}

FILE* BlockManager::OpenBlockFile(const FlatFilePos& pos, bool fReadOnly) const
CAutoFile BlockManager::OpenBlockFile(const FlatFilePos& pos, bool fReadOnly) const
{
return BlockFileSeq().Open(pos, fReadOnly);
return CAutoFile{BlockFileSeq().Open(pos, fReadOnly), CLIENT_VERSION};
}

/** Open an undo file (rev?????.dat) */
FILE* BlockManager::OpenUndoFile(const FlatFilePos& pos, bool fReadOnly) const
CAutoFile BlockManager::OpenUndoFile(const FlatFilePos& pos, bool fReadOnly) const
{
return UndoFileSeq().Open(pos, fReadOnly);
return CAutoFile{UndoFileSeq().Open(pos, fReadOnly), CLIENT_VERSION};
}

fs::path BlockManager::GetBlockPosFilename(const FlatFilePos& pos) const
Expand Down Expand Up @@ -824,7 +824,7 @@ bool BlockManager::FindUndoPos(BlockValidationState& state, int nFile, FlatFileP
bool BlockManager::WriteBlockToDisk(const CBlock& block, FlatFilePos& pos) const
{
// Open history file to append
CAutoFile fileout{OpenBlockFile(pos), CLIENT_VERSION};
CAutoFile fileout{OpenBlockFile(pos)};
if (fileout.IsNull()) {
return error("WriteBlockToDisk: OpenBlockFile failed");
}
Expand Down Expand Up @@ -880,7 +880,7 @@ bool BlockManager::ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos) cons
block.SetNull();

// Open history file to read
CAutoFile filein{OpenBlockFile(pos, true), CLIENT_VERSION};
CAutoFile filein{OpenBlockFile(pos, true)};
if (filein.IsNull()) {
return error("ReadBlockFromDisk: OpenBlockFile failed for %s", pos.ToString());
}
Expand Down Expand Up @@ -923,7 +923,7 @@ bool BlockManager::ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatF
{
FlatFilePos hpos = pos;
hpos.nPos -= 8; // Seek back 8 bytes for meta header
AutoFile filein{OpenBlockFile(hpos, true)};
CAutoFile filein{OpenBlockFile(hpos, true)};
if (filein.IsNull()) {
return error("%s: OpenBlockFile failed for %s", __func__, pos.ToString());
}
Expand Down Expand Up @@ -1015,8 +1015,8 @@ void ImportBlocks(ChainstateManager& chainman, std::vector<fs::path> vImportFile
if (!fs::exists(chainman.m_blockman.GetBlockPosFilename(pos))) {
break; // No block files left to reindex
}
FILE* file = chainman.m_blockman.OpenBlockFile(pos, true);
if (!file) {
CAutoFile file{chainman.m_blockman.OpenBlockFile(pos, true)};
if (file.IsNull()) {
break; // This error is logged in OpenBlockFile
}
LogPrintf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile);
Expand All @@ -1036,8 +1036,8 @@ void ImportBlocks(ChainstateManager& chainman, std::vector<fs::path> vImportFile

// -loadblock=
for (const fs::path& path : vImportFiles) {
FILE* file = fsbridge::fopen(path, "rb");
if (file) {
CAutoFile file{fsbridge::fopen(path, "rb"), CLIENT_VERSION};
if (!file.IsNull()) {
LogPrintf("Importing blocks file %s...\n", fs::PathToString(path));
chainman.LoadExternalBlockFile(file);
if (chainman.m_interrupt) {
Expand Down
5 changes: 3 additions & 2 deletions src/node/blockstorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <vector>

class BlockValidationState;
class CAutoFile;
class CBlock;
class CBlockFileInfo;
class CBlockUndo;
Expand Down Expand Up @@ -126,7 +127,7 @@ class BlockManager
FlatFileSeq BlockFileSeq() const;
FlatFileSeq UndoFileSeq() const;

FILE* OpenUndoFile(const FlatFilePos& pos, bool fReadOnly = false) const;
CAutoFile OpenUndoFile(const FlatFilePos& pos, bool fReadOnly = false) const;

bool WriteBlockToDisk(const CBlock& block, FlatFilePos& pos) const;
bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock) const;
Expand Down Expand Up @@ -278,7 +279,7 @@ class BlockManager
void UpdatePruneLock(const std::string& name, const PruneLockInfo& lock_info) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);

/** Open a block file (blk?????.dat) */
FILE* OpenBlockFile(const FlatFilePos& pos, bool fReadOnly = false) const;
CAutoFile OpenBlockFile(const FlatFilePos& pos, bool fReadOnly = false) const;

/** Translation to a filesystem path */
fs::path GetBlockPosFilename(const FlatFilePos& pos) const;
Expand Down
36 changes: 8 additions & 28 deletions src/streams.h
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ class CAutoFile : public AutoFile
}
};

/** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to
/** Wrapper around a CAutoFile& that implements a ring buffer to
* deserialize from. It guarantees the ability to rewind a given number of bytes.
*
* Will automatically close the file when it goes out of scope if not null.
Expand All @@ -580,9 +580,7 @@ class CAutoFile : public AutoFile
class BufferedFile
{
private:
const int nVersion;

FILE *src; //!< source file
CAutoFile& m_src;
uint64_t nSrcPos{0}; //!< how many bytes have been read from source
uint64_t m_read_pos{0}; //!< how many bytes have been read from this
uint64_t nReadLimit; //!< up to which position we're allowed to read
Expand All @@ -598,9 +596,9 @@ class BufferedFile
readNow = nAvail;
if (readNow == 0)
return false;
size_t nBytes = fread((void*)&vchBuf[pos], 1, readNow, src);
size_t nBytes{m_src.detail_fread(Span{vchBuf}.subspan(pos, readNow))};
if (nBytes == 0) {
throw std::ios_base::failure(feof(src) ? "BufferedFile::Fill: end of file" : "BufferedFile::Fill: fread failed");
throw std::ios_base::failure{m_src.feof() ? "BufferedFile::Fill: end of file" : "BufferedFile::Fill: fread failed"};
}
nSrcPos += nBytes;
return true;
Expand Down Expand Up @@ -629,36 +627,18 @@ class BufferedFile
}

public:
BufferedFile(FILE* fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nVersionIn)
: nVersion{nVersionIn}, nReadLimit{std::numeric_limits<uint64_t>::max()}, nRewind{nRewindIn}, vchBuf(nBufSize, std::byte{0})
BufferedFile(CAutoFile& file, uint64_t nBufSize, uint64_t nRewindIn)
: m_src{file}, nReadLimit{std::numeric_limits<uint64_t>::max()}, nRewind{nRewindIn}, vchBuf(nBufSize, std::byte{0})
{
if (nRewindIn >= nBufSize)
throw std::ios_base::failure("Rewind limit must be less than buffer size");
src = fileIn;
}

~BufferedFile()
{
fclose();
}

// Disallow copies
BufferedFile(const BufferedFile&) = delete;
BufferedFile& operator=(const BufferedFile&) = delete;

int GetVersion() const { return nVersion; }

void fclose()
{
if (src) {
::fclose(src);
src = nullptr;
}
}
int GetVersion() const { return m_src.GetVersion(); }

//! check whether we're at the end of the source file
bool eof() const {
return m_read_pos == nSrcPos && feof(src);
return m_read_pos == nSrcPos && m_src.feof();
}

//! read a number of bytes
Expand Down
6 changes: 3 additions & 3 deletions src/test/blockmanager_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,13 @@ BOOST_FIXTURE_TEST_CASE(blockmanager_scan_unlink_already_pruned_files, TestChain
// Check that the file is not unlinked after ScanAndUnlinkAlreadyPrunedFiles
// if m_have_pruned is not yet set
WITH_LOCK(chainman->GetMutex(), blockman.ScanAndUnlinkAlreadyPrunedFiles());
BOOST_CHECK(!AutoFile(blockman.OpenBlockFile(pos, true)).IsNull());
BOOST_CHECK(!blockman.OpenBlockFile(pos, true).IsNull());

// Check that the file is unlinked after ScanAndUnlinkAlreadyPrunedFiles
// once m_have_pruned is set
blockman.m_have_pruned = true;
WITH_LOCK(chainman->GetMutex(), blockman.ScanAndUnlinkAlreadyPrunedFiles());
BOOST_CHECK(AutoFile(blockman.OpenBlockFile(pos, true)).IsNull());
BOOST_CHECK(blockman.OpenBlockFile(pos, true).IsNull());

// Check that calling with already pruned files doesn't cause an error
WITH_LOCK(chainman->GetMutex(), blockman.ScanAndUnlinkAlreadyPrunedFiles());
Expand All @@ -90,7 +90,7 @@ BOOST_FIXTURE_TEST_CASE(blockmanager_scan_unlink_already_pruned_files, TestChain
BOOST_CHECK_NE(old_tip, new_tip);
const int new_file_number{WITH_LOCK(chainman->GetMutex(), return new_tip->GetBlockPos().nFile)};
const FlatFilePos new_pos(new_file_number, 0);
BOOST_CHECK(!AutoFile(blockman.OpenBlockFile(new_pos, true)).IsNull());
BOOST_CHECK(!blockman.OpenBlockFile(new_pos, true).IsNull());
}

BOOST_FIXTURE_TEST_CASE(blockmanager_block_data_availability, TestChain100Setup)
Expand Down
9 changes: 3 additions & 6 deletions src/test/fuzz/buffered_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,12 @@ FUZZ_TARGET(buffered_file)
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
FuzzedFileProvider fuzzed_file_provider = ConsumeFile(fuzzed_data_provider);
std::optional<BufferedFile> opt_buffered_file;
FILE* fuzzed_file = fuzzed_file_provider.open();
CAutoFile fuzzed_file{fuzzed_file_provider.open(), 0};
try {
opt_buffered_file.emplace(fuzzed_file, fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096), fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096), fuzzed_data_provider.ConsumeIntegral<int>());
opt_buffered_file.emplace(fuzzed_file, fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096), fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096));
} catch (const std::ios_base::failure&) {
if (fuzzed_file != nullptr) {
fclose(fuzzed_file);
}
}
if (opt_buffered_file && fuzzed_file != nullptr) {
if (opt_buffered_file && !fuzzed_file.IsNull()) {
bool setpos_fail = false;
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
CallOneOf(
Expand Down
5 changes: 3 additions & 2 deletions src/test/fuzz/load_external_block_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chainparams.h>
#include <clientversion.h>
#include <flatfile.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
Expand All @@ -27,8 +28,8 @@ FUZZ_TARGET(load_external_block_file, .init = initialize_load_external_block_fil
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
FuzzedFileProvider fuzzed_file_provider = ConsumeFile(fuzzed_data_provider);
FILE* fuzzed_block_file = fuzzed_file_provider.open();
if (fuzzed_block_file == nullptr) {
CAutoFile fuzzed_block_file{fuzzed_file_provider.open(), CLIENT_VERSION};
if (fuzzed_block_file.IsNull()) {
return;
}
if (fuzzed_data_provider.ConsumeBool()) {
Expand Down
Loading

0 comments on commit c9f2882

Please sign in to comment.