reth_prune_types/pruner.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
use crate::{PruneCheckpoint, PruneLimiter, PruneMode, PruneSegment};
use alloy_primitives::{BlockNumber, TxNumber};
/// Pruner run output.
#[derive(Debug)]
pub struct PrunerOutput {
/// Pruning progress.
pub progress: PruneProgress,
/// Pruning output for each segment.
pub segments: Vec<(PruneSegment, SegmentOutput)>,
}
impl From<PruneProgress> for PrunerOutput {
fn from(progress: PruneProgress) -> Self {
Self { progress, segments: Vec::new() }
}
}
/// Represents information of a pruner run for a segment.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PrunedSegmentInfo {
/// The pruned segment
pub segment: PruneSegment,
/// Number of pruned entries
pub pruned: usize,
/// Prune progress
pub progress: PruneProgress,
}
/// Segment pruning output.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct SegmentOutput {
/// Segment pruning progress.
pub progress: PruneProgress,
/// Number of entries pruned, i.e. deleted from the database.
pub pruned: usize,
/// Pruning checkpoint to save to database, if any.
pub checkpoint: Option<SegmentOutputCheckpoint>,
}
impl SegmentOutput {
/// Returns a [`SegmentOutput`] with `done = true`, `pruned = 0` and `checkpoint = None`.
/// Use when no pruning is needed.
pub const fn done() -> Self {
Self { progress: PruneProgress::Finished, pruned: 0, checkpoint: None }
}
/// Returns a [`SegmentOutput`] with `done = false`, `pruned = 0` and `checkpoint = None`.
/// Use when pruning is needed but cannot be done.
pub const fn not_done(
reason: PruneInterruptReason,
checkpoint: Option<SegmentOutputCheckpoint>,
) -> Self {
Self { progress: PruneProgress::HasMoreData(reason), pruned: 0, checkpoint }
}
}
/// Segment pruning checkpoint.
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
pub struct SegmentOutputCheckpoint {
/// Highest pruned block number. If it's [None], the pruning for block `0` is not finished yet.
pub block_number: Option<BlockNumber>,
/// Highest pruned transaction number, if applicable.
pub tx_number: Option<TxNumber>,
}
impl SegmentOutputCheckpoint {
/// Converts [`PruneCheckpoint`] to [`SegmentOutputCheckpoint`].
pub const fn from_prune_checkpoint(checkpoint: PruneCheckpoint) -> Self {
Self { block_number: checkpoint.block_number, tx_number: checkpoint.tx_number }
}
/// Converts [`SegmentOutputCheckpoint`] to [`PruneCheckpoint`] with the provided [`PruneMode`]
pub const fn as_prune_checkpoint(&self, prune_mode: PruneMode) -> PruneCheckpoint {
PruneCheckpoint { block_number: self.block_number, tx_number: self.tx_number, prune_mode }
}
}
/// Progress of pruning.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PruneProgress {
/// There is more data to prune.
HasMoreData(PruneInterruptReason),
/// Pruning has been finished.
Finished,
}
/// Reason for interrupting a prune run.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PruneInterruptReason {
/// Prune run timed out.
Timeout,
/// Limit on the number of deleted entries (rows in the database) per prune run was reached.
DeletedEntriesLimitReached,
/// Unknown reason for stopping prune run.
Unknown,
}
impl PruneInterruptReason {
/// Creates new [`PruneInterruptReason`] based on the [`PruneLimiter`].
pub fn new(limiter: &PruneLimiter) -> Self {
if limiter.is_time_limit_reached() {
Self::Timeout
} else if limiter.is_deleted_entries_limit_reached() {
Self::DeletedEntriesLimitReached
} else {
Self::Unknown
}
}
/// Returns `true` if the reason is timeout.
pub const fn is_timeout(&self) -> bool {
matches!(self, Self::Timeout)
}
/// Returns `true` if the reason is reaching the limit on deleted entries.
pub const fn is_entries_limit_reached(&self) -> bool {
matches!(self, Self::DeletedEntriesLimitReached)
}
}
impl PruneProgress {
/// Creates new [`PruneProgress`].
///
/// If `done == true`, returns [`PruneProgress::Finished`], otherwise
/// [`PruneProgress::HasMoreData`] is returned with [`PruneInterruptReason`] according to the
/// passed limiter.
pub fn new(done: bool, limiter: &PruneLimiter) -> Self {
if done {
Self::Finished
} else {
Self::HasMoreData(PruneInterruptReason::new(limiter))
}
}
/// Returns `true` if prune run is finished.
pub const fn is_finished(&self) -> bool {
matches!(self, Self::Finished)
}
}