Skip to content

Commit

Permalink
feat: add prune for ancient sidecars data (#95)
Browse files Browse the repository at this point in the history
  • Loading branch information
pythonberg1997 authored Aug 6, 2024
1 parent f9df8a1 commit 9e5545f
Show file tree
Hide file tree
Showing 13 changed files with 311 additions and 10 deletions.
4 changes: 3 additions & 1 deletion crates/config/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,14 +348,16 @@ impl Default for IndexHistoryConfig {
pub struct PruneConfig {
/// Minimum pruning interval measured in blocks.
pub block_interval: usize,
/// The number of recent sidecars to keep in the static file provider.
pub recent_sidecars_kept_blocks: usize,
/// Pruning configuration for every part of the data that can be pruned.
#[serde(alias = "parts")]
pub segments: PruneModes,
}

impl Default for PruneConfig {
fn default() -> Self {
Self { block_interval: 5, segments: PruneModes::none() }
Self { block_interval: 5, recent_sidecars_kept_blocks: 0, segments: PruneModes::none() }
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/consensus/beacon/src/engine/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ where
self.base_config.chain_spec.prune_delete_limit,
None,
watch::channel(FinishedExExHeight::NoExExs).1,
0,
);

let mut hooks = EngineHooks::new();
Expand Down
1 change: 1 addition & 0 deletions crates/engine/tree/src/persistence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ mod tests {
0,
None,
finished_exex_height_rx,
0,
);

PersistenceHandle::spawn_services(provider, pruner)
Expand Down
1 change: 1 addition & 0 deletions crates/node/core/src/args/pruning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ impl PruningArgs {
}
Some(PruneConfig {
block_interval: 5,
recent_sidecars_kept_blocks: 0,
segments: PruneModes {
sender_recovery: Some(PruneMode::Full),
transaction_lookup: None,
Expand Down
13 changes: 13 additions & 0 deletions crates/prune/prune/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ pub struct PrunerBuilder {
timeout: Option<Duration>,
/// The finished height of all `ExEx`'s.
finished_exex_height: watch::Receiver<FinishedExExHeight>,
/// The number of recent sidecars to keep in the static file provider.
recent_sidecars_kept_blocks: usize,
}

impl PrunerBuilder {
Expand All @@ -32,6 +34,7 @@ impl PrunerBuilder {
Self::default()
.block_interval(pruner_config.block_interval)
.segments(pruner_config.segments)
.recent_sidecars_kept_blocks(pruner_config.recent_sidecars_kept_blocks)
}

/// Sets the minimum pruning interval measured in blocks.
Expand Down Expand Up @@ -70,6 +73,12 @@ impl PrunerBuilder {
self
}

/// Sets the number of recent sidecars to keep in the static file provider.
pub const fn recent_sidecars_kept_blocks(mut self, recent_sidecars_kept_blocks: usize) -> Self {
self.recent_sidecars_kept_blocks = recent_sidecars_kept_blocks;
self
}

/// Builds a [Pruner] from the current configuration with the given provider factory.
pub fn build_with_provider_factory<DB: Database>(
self,
Expand All @@ -87,6 +96,7 @@ impl PrunerBuilder {
self.delete_limit,
self.timeout,
self.finished_exex_height,
self.recent_sidecars_kept_blocks,
)
}

Expand All @@ -100,6 +110,7 @@ impl PrunerBuilder {
self.delete_limit,
self.timeout,
self.finished_exex_height,
self.recent_sidecars_kept_blocks,
)
}
}
Expand All @@ -112,6 +123,8 @@ impl Default for PrunerBuilder {
delete_limit: MAINNET.prune_delete_limit,
timeout: None,
finished_exex_height: watch::channel(FinishedExExHeight::NoExExs).1,
recent_sidecars_kept_blocks: 0, /* not enabled by default
* recent_sidecars_kept_blocks: 518400, // 18 days */
}
}
}
2 changes: 2 additions & 0 deletions crates/prune/prune/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use std::collections::HashMap;
pub(crate) struct Metrics {
/// Pruning duration
pub(crate) duration_seconds: Histogram,
/// The height of the oldest sidecars
pub(crate) oldest_sidecars_height: Gauge,
#[metric(skip)]
prune_segments: HashMap<PruneSegment, PrunerSegmentMetrics>,
}
Expand Down
91 changes: 90 additions & 1 deletion crates/prune/prune/src/pruner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ use reth_db_api::database::Database;
use reth_exex_types::FinishedExExHeight;
use reth_provider::{DatabaseProviderRW, ProviderFactory, PruneCheckpointReader};
use reth_prune_types::{PruneLimiter, PruneProgress, PruneSegment, PrunerOutput};
use reth_static_file_types::{find_fixed_range, StaticFileSegment};
use reth_tokio_util::{EventSender, EventStream};
use std::time::{Duration, Instant};
use std::{
fs,
path::Path,
time::{Duration, Instant},
};
use tokio::sync::watch;
use tracing::debug;

Expand Down Expand Up @@ -41,6 +46,8 @@ pub struct Pruner<DB, PF> {
timeout: Option<Duration>,
/// The finished height of all `ExEx`'s.
finished_exex_height: watch::Receiver<FinishedExExHeight>,
/// The number of recent sidecars to keep in the static file provider.
recent_sidecars_kept_blocks: usize,
#[doc(hidden)]
metrics: Metrics,
event_sender: EventSender<PrunerEvent>,
Expand All @@ -54,6 +61,7 @@ impl<DB> Pruner<DB, ()> {
delete_limit: usize,
timeout: Option<Duration>,
finished_exex_height: watch::Receiver<FinishedExExHeight>,
recent_sidecars_kept_blocks: usize,
) -> Self {
Self {
provider_factory: (),
Expand All @@ -63,6 +71,7 @@ impl<DB> Pruner<DB, ()> {
delete_limit,
timeout,
finished_exex_height,
recent_sidecars_kept_blocks,
metrics: Metrics::default(),
event_sender: Default::default(),
}
Expand All @@ -71,13 +80,15 @@ impl<DB> Pruner<DB, ()> {

impl<DB: Database> Pruner<DB, ProviderFactory<DB>> {
/// Crates a new pruner with the given provider factory.
#[allow(clippy::too_many_arguments)]
pub fn new(
provider_factory: ProviderFactory<DB>,
segments: Vec<Box<dyn Segment<DB>>>,
min_block_interval: usize,
delete_limit: usize,
timeout: Option<Duration>,
finished_exex_height: watch::Receiver<FinishedExExHeight>,
recent_sidecars_kept_blocks: usize,
) -> Self {
Self {
provider_factory,
Expand All @@ -87,6 +98,7 @@ impl<DB: Database> Pruner<DB, ProviderFactory<DB>> {
delete_limit,
timeout,
finished_exex_height,
recent_sidecars_kept_blocks,
metrics: Metrics::default(),
event_sender: Default::default(),
}
Expand Down Expand Up @@ -129,6 +141,8 @@ impl<DB: Database, S> Pruner<DB, S> {
let (stats, deleted_entries, output) =
self.prune_segments(provider, tip_block_number, &mut limiter)?;

self.prune_ancient_sidecars(provider, tip_block_number);

self.previous_tip_block_number = Some(tip_block_number);

let elapsed = start.elapsed();
Expand Down Expand Up @@ -294,6 +308,80 @@ impl<DB: Database, S> Pruner<DB, S> {
}
}
}

/// Prunes ancient sidecars data from the static file provider.
pub fn prune_ancient_sidecars(
&mut self,
provider: &DatabaseProviderRW<DB>,
tip_block_number: BlockNumber,
) {
if self.recent_sidecars_kept_blocks == 0 {
return
}

let static_file_provider = provider.static_file_provider();

let prune_target_block =
tip_block_number.saturating_sub(self.recent_sidecars_kept_blocks as u64);
let mut range_start = find_fixed_range(prune_target_block).start();

if range_start == 0 {
return
}

debug!(
target: "pruner",
%tip_block_number,
"Ancient sidecars pruning started",
);

while range_start > 0 {
let range = find_fixed_range(range_start - 1);
let path =
static_file_provider.path().join(StaticFileSegment::Sidecars.filename(&range));

if path.exists() {
delete_static_files(&path);
self.metrics.oldest_sidecars_height.set(range.end() as f64 + 1_f64);
} else {
debug!(target: "pruner", path = %path.display(), "Static file not found, skipping");
break
}

range_start = range.start();
}

debug!(
target: "pruner",
%tip_block_number,
"Ancient sidecars pruning finished",
);
}
}

fn delete_static_files(path: &Path) {
// Delete the main file
if let Err(err) = fs::remove_file(path) {
debug!(target: "pruner", path = %path.display(), %err, "Failed to remove file");
} else {
debug!(target: "pruner", path = %path.display(), "Removed file");
}

// Delete the .conf file
let conf_path = path.with_extension("conf");
if let Err(err) = fs::remove_file(&conf_path) {
debug!(target: "pruner", path = %conf_path.display(), %err, "Failed to remove .conf file");
} else {
debug!(target: "pruner", path = %conf_path.display(), "Removed .conf file");
}

// Delete the .off file
let off_path = path.with_extension("off");
if let Err(err) = fs::remove_file(&off_path) {
debug!(target: "pruner", path = %off_path.display(), %err, "Failed to remove .off file");
} else {
debug!(target: "pruner", path = %off_path.display(), "Removed .off file");
}
}

impl<DB: Database> Pruner<DB, ()> {
Expand Down Expand Up @@ -347,6 +435,7 @@ mod tests {
0,
None,
finished_exex_height_rx,
0,
);

// No last pruned block number was set before
Expand Down
2 changes: 1 addition & 1 deletion crates/prune/prune/src/segments/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use reth_prune_types::{
};
pub use set::SegmentSet;
pub use static_file::{
Headers as StaticFileHeaders, Receipts as StaticFileReceipts,
Headers as StaticFileHeaders, Receipts as StaticFileReceipts, Sidecars as StaticFileSidecars,
Transactions as StaticFileTransactions,
};
use std::{fmt::Debug, ops::RangeInclusive};
Expand Down
8 changes: 5 additions & 3 deletions crates/prune/prune/src/segments/set.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::segments::{
AccountHistory, ReceiptsByLogs, Segment, SenderRecovery, StorageHistory, TransactionLookup,
UserReceipts,
AccountHistory, ReceiptsByLogs, Segment, SenderRecovery, StaticFileSidecars, StorageHistory,
TransactionLookup, UserReceipts,
};
use reth_db_api::database::Database;
use reth_provider::providers::StaticFileProvider;
Expand Down Expand Up @@ -60,7 +60,9 @@ impl<DB: Database> SegmentSet<DB> {
// Static file transactions
.segment(StaticFileTransactions::new(static_file_provider.clone()))
// Static file receipts
.segment(StaticFileReceipts::new(static_file_provider))
.segment(StaticFileReceipts::new(static_file_provider.clone()))
// Static file receipts
.segment(StaticFileSidecars::new(static_file_provider))
// Account history
.segment_opt(account_history.map(AccountHistory::new))
// Storage history
Expand Down
2 changes: 2 additions & 0 deletions crates/prune/prune/src/segments/static_file/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
mod headers;
mod receipts;
mod sidecars;
mod transactions;

pub use headers::Headers;
pub use receipts::Receipts;
pub use sidecars::Sidecars;
pub use transactions::Transactions;
Loading

0 comments on commit 9e5545f

Please sign in to comment.