Skip to content

Commit

Permalink
Merge bitcoin#31490: refactor: inline UndoWriteToDisk and `WriteBlo…
Browse files Browse the repository at this point in the history
…ckToDisk` to reduce serialization calls

223081e scripted-diff: rename block and undo functions for consistency (Lőrinc)
baaa3b2 refactor,blocks: remove costly asserts and modernize affected logs (Lőrinc)
fa39f27 refactor,blocks: deduplicate block's serialized size calculations (Lőrinc)
dfb2f9d refactor,blocks: inline `WriteBlockToDisk` (Lőrinc)
42bc491 refactor,blocks: inline `UndoWriteToDisk` (Lőrinc)
86b85bb bench: add SaveBlockBench (Lőrinc)
34f9a01 refactor,bench: rename bench/readblock.cpp to bench/readwriteblock.cpp (Lőrinc)

Pull request description:

  `UndoWriteToDisk` and `WriteBlockToDisk` were delegating a subset of their functionality to single-use methods that didn't optimally capture a meaningful chunk of the algorithm, resulting in calculating things twice (serialized size, header size).
  This change inlines the awkward methods (asserting that all previous behavior was retained), and in separate commits makes the usages less confusing.
  Besides making the methods slightly more intuitive, the refactorings reduce duplicate calculations as well.

  The speed difference is insignificant for now (~0.5% for the new `SaveBlockToDiskBench`), but are a cleanup for follow-ups such as bitcoin#31539

ACKs for top commit:
  ryanofsky:
    Code review ACK 223081e. Since last review, "Save" was renamed to "Write", uint32_t references were dropped, some log statements and comments were improved as suggested, and a lot of tweaks made to commits and commit messages which should make this easier to review.
  hodlinator:
    ACK 223081e
  TheCharlatan:
    ACK 223081e
  andrewtoth:
    ACK 223081e

Tree-SHA512: 951bc8ad3504c510988afd95c561e3e259c6212bd14f6536fe56e8eb5bf5c35c32a368bbdb1d5aea1acc473d7e5bd9cdcde02008a148b05af1f955e413062d5c
  • Loading branch information
ryanofsky committed Jan 22, 2025
2 parents 7b4d072 + 223081e commit 5d6f6fd
Show file tree
Hide file tree
Showing 20 changed files with 179 additions and 204 deletions.
2 changes: 1 addition & 1 deletion src/bench/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ add_executable(bench_bitcoin
pool.cpp
prevector.cpp
random.cpp
readblock.cpp
readwriteblock.cpp
rollingbloom.cpp
rpc_blockchain.cpp
rpc_mempool.cpp
Expand Down
60 changes: 0 additions & 60 deletions src/bench/readblock.cpp

This file was deleted.

68 changes: 68 additions & 0 deletions src/bench/readwriteblock.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) 2023 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <bench/bench.h>
#include <bench/data/block413567.raw.h>
#include <flatfile.h>
#include <node/blockstorage.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <serialize.h>
#include <span.h>
#include <streams.h>
#include <test/util/setup_common.h>
#include <validation.h>

#include <cassert>
#include <cstdint>
#include <memory>
#include <vector>

static CBlock CreateTestBlock()
{
DataStream stream{benchmark::data::block413567};
CBlock block;
stream >> TX_WITH_WITNESS(block);
return block;
}

static void SaveBlockBench(benchmark::Bench& bench)
{
const auto testing_setup{MakeNoLogFileContext<const TestingSetup>(ChainType::MAIN)};
auto& blockman{testing_setup->m_node.chainman->m_blockman};
const CBlock block{CreateTestBlock()};
bench.run([&] {
const auto pos{blockman.WriteBlock(block, 413'567)};
assert(!pos.IsNull());
});
}

static void ReadBlockBench(benchmark::Bench& bench)
{
const auto testing_setup{MakeNoLogFileContext<const TestingSetup>(ChainType::MAIN)};
auto& blockman{testing_setup->m_node.chainman->m_blockman};
const auto pos{blockman.WriteBlock(CreateTestBlock(), 413'567)};
CBlock block;
bench.run([&] {
const auto success{blockman.ReadBlock(block, pos)};
assert(success);
});
}

static void ReadRawBlockBench(benchmark::Bench& bench)
{
const auto testing_setup{MakeNoLogFileContext<const TestingSetup>(ChainType::MAIN)};
auto& blockman{testing_setup->m_node.chainman->m_blockman};
const auto pos{blockman.WriteBlock(CreateTestBlock(), 413'567)};
std::vector<uint8_t> block_data;
blockman.ReadRawBlock(block_data, pos); // warmup
bench.run([&] {
const auto success{blockman.ReadRawBlock(block_data, pos)};
assert(success);
});
}

BENCHMARK(SaveBlockBench, benchmark::PriorityLevel::HIGH);
BENCHMARK(ReadBlockBench, benchmark::PriorityLevel::HIGH);
BENCHMARK(ReadRawBlockBench, benchmark::PriorityLevel::HIGH);
4 changes: 2 additions & 2 deletions src/index/base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ void BaseIndex::Sync()

CBlock block;
interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex);
if (!m_chainstate->m_blockman.ReadBlockFromDisk(block, *pindex)) {
if (!m_chainstate->m_blockman.ReadBlock(block, *pindex)) {
FatalErrorf("%s: Failed to read block %s from disk",
__func__, pindex->GetBlockHash().ToString());
return;
Expand Down Expand Up @@ -256,7 +256,7 @@ bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_ti
// In the case of a reorg, ensure persisted block locator is not stale.
// Pruning has a minimum of 288 blocks-to-keep and getting the index
// out of sync may be possible but a users fault.
// In case we reorg beyond the pruned depth, ReadBlockFromDisk would
// In case we reorg beyond the pruned depth, ReadBlock would
// throw and lead to a graceful shutdown
SetBestBlockIndex(new_tip);
if (!Commit()) {
Expand Down
2 changes: 1 addition & 1 deletion src/index/blockfilterindex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ bool BlockFilterIndex::CustomAppend(const interfaces::BlockInfo& block)
// pindex variable gives indexing code access to node internals. It
// will be removed in upcoming commit
const CBlockIndex* pindex = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(block.hash));
if (!m_chainstate->m_blockman.UndoReadFromDisk(block_undo, *pindex)) {
if (!m_chainstate->m_blockman.ReadBlockUndo(block_undo, *pindex)) {
return false;
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/index/coinstatsindex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
// pindex variable gives indexing code access to node internals. It
// will be removed in upcoming commit
const CBlockIndex* pindex = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(block.hash));
if (!m_chainstate->m_blockman.UndoReadFromDisk(block_undo, *pindex)) {
if (!m_chainstate->m_blockman.ReadBlockUndo(block_undo, *pindex)) {
return false;
}

Expand Down Expand Up @@ -287,7 +287,7 @@ bool CoinStatsIndex::CustomRewind(const interfaces::BlockRef& current_tip, const
do {
CBlock block;

if (!m_chainstate->m_blockman.ReadBlockFromDisk(block, *iter_tip)) {
if (!m_chainstate->m_blockman.ReadBlock(block, *iter_tip)) {
LogError("%s: Failed to read block %s from disk\n",
__func__, iter_tip->GetBlockHash().ToString());
return false;
Expand Down Expand Up @@ -415,7 +415,7 @@ bool CoinStatsIndex::ReverseBlock(const CBlock& block, const CBlockIndex* pindex

// Ignore genesis block
if (pindex->nHeight > 0) {
if (!m_chainstate->m_blockman.UndoReadFromDisk(block_undo, *pindex)) {
if (!m_chainstate->m_blockman.ReadBlockUndo(block_undo, *pindex)) {
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1587,7 +1587,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
g_zmq_notification_interface = CZMQNotificationInterface::Create(
[&chainman = node.chainman](std::vector<uint8_t>& block, const CBlockIndex& index) {
assert(chainman);
return chainman->m_blockman.ReadRawBlockFromDisk(block, WITH_LOCK(cs_main, return index.GetBlockPos()));
return chainman->m_blockman.ReadRawBlock(block, WITH_LOCK(cs_main, return index.GetBlockPos()));
});

if (g_zmq_notification_interface) {
Expand Down
8 changes: 4 additions & 4 deletions src/net_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2268,7 +2268,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
// Fast-path: in this case it is possible to serve the block directly from disk,
// as the network format matches the format on disk
std::vector<uint8_t> block_data;
if (!m_chainman.m_blockman.ReadRawBlockFromDisk(block_data, block_pos)) {
if (!m_chainman.m_blockman.ReadRawBlock(block_data, block_pos)) {
if (WITH_LOCK(m_chainman.GetMutex(), return m_chainman.m_blockman.IsBlockPruned(*pindex))) {
LogDebug(BCLog::NET, "Block was pruned before it could be read, %s\n", pfrom.DisconnectMsg(fLogIPs));
} else {
Expand All @@ -2282,7 +2282,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
} else {
// Send block from disk
std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
if (!m_chainman.m_blockman.ReadBlockFromDisk(*pblockRead, block_pos)) {
if (!m_chainman.m_blockman.ReadBlock(*pblockRead, block_pos)) {
if (WITH_LOCK(m_chainman.GetMutex(), return m_chainman.m_blockman.IsBlockPruned(*pindex))) {
LogDebug(BCLog::NET, "Block was pruned before it could be read, %s\n", pfrom.DisconnectMsg(fLogIPs));
} else {
Expand Down Expand Up @@ -4096,7 +4096,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,

if (!block_pos.IsNull()) {
CBlock block;
const bool ret{m_chainman.m_blockman.ReadBlockFromDisk(block, block_pos)};
const bool ret{m_chainman.m_blockman.ReadBlock(block, block_pos)};
// If height is above MAX_BLOCKTXN_DEPTH then this block cannot get
// pruned after we release cs_main above, so this read should never fail.
assert(ret);
Expand Down Expand Up @@ -5599,7 +5599,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
PushMessage(*pto, std::move(cached_cmpctblock_msg.value()));
} else {
CBlock block;
const bool ret{m_chainman.m_blockman.ReadBlockFromDisk(block, *pBestIndex)};
const bool ret{m_chainman.m_blockman.ReadBlock(block, *pBestIndex)};
assert(ret);
CBlockHeaderAndShortTxIDs cmpctblock{block, m_rng.rand64()};
MakeAndPushMessage(*pto, NetMsgType::CMPCTBLOCK, cmpctblock);
Expand Down
Loading

0 comments on commit 5d6f6fd

Please sign in to comment.