Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add prune for ancient sidecars data #95

Merged
merged 1 commit into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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