Skip to content

Commit 7860f35

Browse files
committed
perf: remove allocs from cursor
1 parent 816ec70 commit 7860f35

4 files changed

Lines changed: 58 additions & 219 deletions

File tree

CLAUDE.md

Lines changed: 0 additions & 175 deletions
This file was deleted.

crates/storage/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ reth-libmdbx = { workspace = true, optional = true }
2626
page_size = { version = "0.6.0", optional = true }
2727
dashmap = "6.1.0"
2828
tempfile = { workspace = true, optional = true }
29-
itertools.workspace = true
3029

3130

3231
[dev-dependencies]

crates/storage/src/hot/db/inconsistent.rs

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use crate::hot::{
99
tables,
1010
};
1111
use alloy::primitives::{Address, B256, BlockNumber, U256};
12-
use itertools::Itertools;
1312
use reth::{
1413
primitives::{Account, Header, SealedHeader},
1514
revm::db::BundleState,
@@ -310,13 +309,15 @@ pub trait UnsafeHistoryWrite: UnsafeDbWrite + HistoryRead {
310309
// Get the existing last shard (if any) and remember its key so we can
311310
// delete it before writing new shards
312311
let existing = self.last_account_history(acct)?;
313-
let mut last_shard =
314-
existing.as_ref().map(|(_, list)| list.clone()).unwrap_or_default();
312+
// Save the old key before taking ownership of the list
313+
let old_key = existing.as_ref().map(|(key, _)| *key);
314+
// Take ownership instead of cloning
315+
let mut last_shard = existing.map(|(_, list)| list).unwrap_or_default();
315316

316317
last_shard.append(indices).map_err(HistoryError::IntList)?;
317318

318319
// Delete the existing shard before writing new ones to avoid duplicates
319-
if let Some((old_key, _)) = existing {
320+
if let Some(old_key) = old_key {
320321
self.queue_delete_dual::<tables::AccountsHistory>(&acct, &old_key)?;
321322
}
322323

@@ -327,19 +328,22 @@ pub trait UnsafeHistoryWrite: UnsafeDbWrite + HistoryRead {
327328
}
328329

329330
// slow path: rechunk into multiple shards
330-
let chunks = last_shard.iter().chunks(sharded_key::NUM_OF_INDICES_IN_SHARD);
331+
// Reuse a single buffer to avoid allocating a new Vec per chunk
332+
let mut chunk_buf = Vec::with_capacity(sharded_key::NUM_OF_INDICES_IN_SHARD);
333+
let mut iter = last_shard.iter().peekable();
331334

332-
let mut chunks = chunks.into_iter().peekable();
335+
while iter.peek().is_some() {
336+
chunk_buf.clear();
337+
chunk_buf.extend(iter.by_ref().take(sharded_key::NUM_OF_INDICES_IN_SHARD));
333338

334-
while let Some(chunk) = chunks.next() {
335-
let shard = BlockNumberList::new_pre_sorted(chunk);
336-
let highest_block_number = if chunks.peek().is_some() {
337-
shard.iter().next_back().expect("`chunks` does not return empty list")
339+
let highest_block_number = if iter.peek().is_some() {
340+
*chunk_buf.last().expect("chunk_buf is non-empty")
338341
} else {
339342
// Insert last list with `u64::MAX`.
340343
u64::MAX
341344
};
342345

346+
let shard = BlockNumberList::new_pre_sorted(chunk_buf.iter().copied());
343347
self.write_account_history(&acct, highest_block_number, &shard)?;
344348
}
345349
}
@@ -382,13 +386,15 @@ pub trait UnsafeHistoryWrite: UnsafeDbWrite + HistoryRead {
382386
// Get the existing last shard (if any) and remember its key so we can
383387
// delete it before writing new shards
384388
let existing = self.last_storage_history(&addr, &slot)?;
385-
let mut last_shard =
386-
existing.as_ref().map(|(_, list)| list.clone()).unwrap_or_default();
389+
// Save the old key before taking ownership of the list (clone is cheap for ShardedKey)
390+
let old_key = existing.as_ref().map(|(key, _)| key.clone());
391+
// Take ownership instead of cloning the BlockNumberList
392+
let mut last_shard = existing.map(|(_, list)| list).unwrap_or_default();
387393

388394
last_shard.append(indices).map_err(HistoryError::IntList)?;
389395

390396
// Delete the existing shard before writing new ones to avoid duplicates
391-
if let Some((old_key, _)) = existing {
397+
if let Some(old_key) = old_key {
392398
self.queue_delete_dual::<tables::StorageHistory>(&addr, &old_key)?;
393399
}
394400

@@ -399,19 +405,22 @@ pub trait UnsafeHistoryWrite: UnsafeDbWrite + HistoryRead {
399405
}
400406

401407
// slow path: rechunk into multiple shards
402-
let chunks = last_shard.iter().chunks(sharded_key::NUM_OF_INDICES_IN_SHARD);
408+
// Reuse a single buffer to avoid allocating a new Vec per chunk
409+
let mut chunk_buf = Vec::with_capacity(sharded_key::NUM_OF_INDICES_IN_SHARD);
410+
let mut iter = last_shard.iter().peekable();
403411

404-
let mut chunks = chunks.into_iter().peekable();
412+
while iter.peek().is_some() {
413+
chunk_buf.clear();
414+
chunk_buf.extend(iter.by_ref().take(sharded_key::NUM_OF_INDICES_IN_SHARD));
405415

406-
while let Some(chunk) = chunks.next() {
407-
let shard = BlockNumberList::new_pre_sorted(chunk);
408-
let highest_block_number = if chunks.peek().is_some() {
409-
shard.iter().next_back().expect("`chunks` does not return empty list")
416+
let highest_block_number = if iter.peek().is_some() {
417+
*chunk_buf.last().expect("chunk_buf is non-empty")
410418
} else {
411419
// Insert last list with `u64::MAX`.
412420
u64::MAX
413421
};
414422

423+
let shard = BlockNumberList::new_pre_sorted(chunk_buf.iter().copied());
415424
self.write_storage_history(&addr, slot, highest_block_number, &shard)?;
416425
}
417426
}

0 commit comments

Comments
 (0)