diff --git a/crates/prune/prune/src/db_ext.rs b/crates/prune/prune/src/db_ext.rs index 642063378a..3e715373c6 100644 --- a/crates/prune/prune/src/db_ext.rs +++ b/crates/prune/prune/src/db_ext.rs @@ -9,6 +9,16 @@ use std::{fmt::Debug, ops::RangeBounds}; use tracing::debug; pub(crate) trait DbTxPruneExt: DbTxMut + DbTx { + /// Clear the entire table in a single operation. + /// + /// This is much faster than iterating entry-by-entry for `PruneMode::Full`. + /// Returns the number of entries that were in the table. + fn clear_table(&self) -> Result { + let count = self.entries::()?; + ::clear::(self)?; + Ok(count) + } + /// Prune the table for the specified pre-sorted key iterator. /// /// Returns number of rows pruned. diff --git a/crates/prune/prune/src/segments/user/sender_recovery.rs b/crates/prune/prune/src/segments/user/sender_recovery.rs index 9569532e8b..948afe75a8 100644 --- a/crates/prune/prune/src/segments/user/sender_recovery.rs +++ b/crates/prune/prune/src/segments/user/sender_recovery.rs @@ -6,7 +6,7 @@ use crate::{ use reth_db_api::{tables, transaction::DbTxMut}; use reth_provider::{BlockReader, DBProvider, TransactionsProvider}; use reth_prune_types::{ - PruneMode, PrunePurpose, PruneSegment, SegmentOutput, SegmentOutputCheckpoint, + PruneMode, PruneProgress, PrunePurpose, PruneSegment, SegmentOutput, SegmentOutputCheckpoint, }; use tracing::{instrument, trace}; @@ -48,6 +48,25 @@ where }; let tx_range_end = *tx_range.end(); + // For PruneMode::Full, clear the entire table in one operation + if self.mode.is_full() { + let pruned = provider.tx_ref().clear_table::()?; + trace!(target: "pruner", %pruned, "Cleared transaction senders table"); + + let last_pruned_block = provider + .block_by_transaction_id(tx_range_end)? + .ok_or(PrunerError::InconsistentData("Block for transaction is not found"))?; + + return Ok(SegmentOutput { + progress: PruneProgress::Finished, + pruned, + checkpoint: Some(SegmentOutputCheckpoint { + block_number: Some(last_pruned_block), + tx_number: Some(tx_range_end), + }), + }); + } + let mut limiter = input.limiter; let mut last_pruned_transaction = tx_range_end; diff --git a/crates/prune/prune/src/segments/user/transaction_lookup.rs b/crates/prune/prune/src/segments/user/transaction_lookup.rs index 6f227455fa..614abb1af7 100644 --- a/crates/prune/prune/src/segments/user/transaction_lookup.rs +++ b/crates/prune/prune/src/segments/user/transaction_lookup.rs @@ -8,7 +8,7 @@ use rayon::prelude::*; use reth_db_api::{tables, transaction::DbTxMut}; use reth_provider::{BlockReader, DBProvider, PruneCheckpointReader, StaticFileProviderFactory}; use reth_prune_types::{ - PruneCheckpoint, PruneMode, PrunePurpose, PruneSegment, SegmentOutputCheckpoint, + PruneCheckpoint, PruneMode, PruneProgress, PrunePurpose, PruneSegment, SegmentOutputCheckpoint, }; use reth_static_file_types::StaticFileSegment; use tracing::{debug, instrument, trace}; @@ -82,6 +82,26 @@ where } } .into_inner(); + + // For PruneMode::Full, clear the entire table in one operation + if self.mode.is_full() { + let pruned = provider.tx_ref().clear_table::()?; + trace!(target: "pruner", %pruned, "Cleared transaction lookup table"); + + let last_pruned_block = provider + .block_by_transaction_id(end)? + .ok_or(PrunerError::InconsistentData("Block for transaction is not found"))?; + + return Ok(SegmentOutput { + progress: PruneProgress::Finished, + pruned, + checkpoint: Some(SegmentOutputCheckpoint { + block_number: Some(last_pruned_block), + tx_number: Some(end), + }), + }); + } + let tx_range = start..= Some(end) .min(