Skip to content

Commit

Permalink
optimization: Bulk serialization writes in SaveBlockUndo and `SaveB…
Browse files Browse the repository at this point in the history
…lock`

Similarly to the serialization reads, buffered writes will enable batched xor calculations - especially since currently we need to copy the write inputs Span to do the obfuscation on it, batching enables doing the xor on the internal buffer instead.

Before:
|               ns/op |                op/s |    err% |     total | benchmark
|--------------------:|--------------------:|--------:|----------:|:----------
|        5,244,636.51 |              190.67 |    0.3% |     11.04 | `SaveBlockBench`

After:
|               ns/op |                op/s |    err% |     total | benchmark
|--------------------:|--------------------:|--------:|----------:|:----------
|        1,787,371.46 |              559.48 |    1.6% |     11.16 | `SaveBlockBench`

Co-authored-by: Cory Fields <[email protected]>
  • Loading branch information
l0rinc and theuni committed Jan 24, 2025
1 parent 763d716 commit c4c3bf1
Showing 1 changed file with 42 additions and 18 deletions.
60 changes: 42 additions & 18 deletions src/node/blockstorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -963,23 +963,34 @@ bool BlockManager::WriteBlockUndo(const CBlockUndo& blockundo, BlockValidationSt
return false;
}
// Open history file to append
AutoFile fileout{OpenUndoFile(pos)};
AutoFile fileout{m_undo_file_seq.Open(pos, false), {}}; // We'll obfuscate ourselves
if (fileout.IsNull()) {
LogError("OpenUndoFile failed");
LogError("FlatFileSeq::Open failed");
return FatalError(m_opts.notifications, state, _("Failed to write undo data."));
}

// Write index header
fileout << GetParams().MessageStart() << blockundo_size;
// Write undo data
{
// Write index header
DataStream header;
header.reserve(BLOCK_SERIALIZATION_HEADER_SIZE);
header << GetParams().MessageStart() << blockundo_size;
util::Xor(header, m_xor_key, pos.nPos);
fileout.write(header);
}
pos.nPos += BLOCK_SERIALIZATION_HEADER_SIZE;
fileout << blockundo;

// Calculate & write checksum
HashWriter hasher{};
hasher << block.pprev->GetBlockHash();
hasher << blockundo;
fileout << hasher.GetHash();
{
// Calculate checksum
HashWriter hasher{};
hasher << block.pprev->GetBlockHash();
hasher << blockundo;

// Write undo data & checksum
DataStream undo_data;
undo_data.reserve(blockundo_size + sizeof(uint256));
undo_data << blockundo << hasher.GetHash();
util::Xor(undo_data, m_xor_key, pos.nPos);
fileout.write(undo_data);
}

// rev files are written in block height order, whereas blk files are written as blocks come in (often out of order)
// we want to flush the rev (undo) file once we've written the last block, which is indicated by the last height
Expand Down Expand Up @@ -1120,18 +1131,31 @@ FlatFilePos BlockManager::WriteBlock(const CBlock& block, int nHeight)
LogError("FindNextBlockPos failed");
return FlatFilePos();
}
AutoFile fileout{OpenBlockFile(pos)};
AutoFile fileout{m_block_file_seq.Open(pos, false), {}}; // We'll obfuscate ourselves
if (fileout.IsNull()) {
LogError("OpenBlockFile failed");
LogError("FlatFileSeq::Open failed");
m_opts.notifications.fatalError(_("Failed to write block."));
return FlatFilePos();
}

// Write index header
fileout << GetParams().MessageStart() << block_size;
// Write block
{
// Write index header
DataStream header;
header.reserve(BLOCK_SERIALIZATION_HEADER_SIZE);
header << GetParams().MessageStart() << block_size;
util::Xor(header, m_xor_key, pos.nPos);
fileout.write(header);
}
pos.nPos += BLOCK_SERIALIZATION_HEADER_SIZE;
fileout << TX_WITH_WITNESS(block);
{
// Write block
DataStream block_data;
block_data.reserve(block_size);
block_data << TX_WITH_WITNESS(block);
util::Xor(block_data, m_xor_key, pos.nPos);
fileout.write(block_data);
}

return pos;
}

Expand Down

0 comments on commit c4c3bf1

Please sign in to comment.