feat(pruner): limit number of blocks to prune per run (#5627)

This commit is contained in:
Alexey Shekhirin
2023-11-29 19:29:39 +00:00
committed by GitHub
parent 15992d9bdf
commit 471c28e889
3 changed files with 28 additions and 10 deletions

View File

@ -289,9 +289,10 @@ impl<Ext: RethCliExt> NodeCommand<Ext> {
Arc::clone(&consensus), Arc::clone(&consensus),
EvmProcessorFactory::new(self.chain.clone()), EvmProcessorFactory::new(self.chain.clone()),
); );
let tree_config = BlockchainTreeConfig::default();
let tree = BlockchainTree::new( let tree = BlockchainTree::new(
tree_externals, tree_externals,
BlockchainTreeConfig::default(), tree_config,
prune_config.clone().map(|config| config.segments), prune_config.clone().map(|config| config.segments),
)? )?
.with_sync_metrics_tx(sync_metrics_tx.clone()); .with_sync_metrics_tx(sync_metrics_tx.clone());
@ -473,6 +474,7 @@ impl<Ext: RethCliExt> NodeCommand<Ext> {
let mut pruner = self.build_pruner( let mut pruner = self.build_pruner(
&prune_config, &prune_config,
db.clone(), db.clone(),
tree_config,
snapshotter.highest_snapshot_receiver(), snapshotter.highest_snapshot_receiver(),
); );
@ -975,6 +977,7 @@ impl<Ext: RethCliExt> NodeCommand<Ext> {
&self, &self,
config: &PruneConfig, config: &PruneConfig,
db: DB, db: DB,
tree_config: BlockchainTreeConfig,
highest_snapshots_rx: HighestSnapshotsTracker, highest_snapshots_rx: HighestSnapshotsTracker,
) -> Pruner<DB> { ) -> Pruner<DB> {
let segments = SegmentSet::default() let segments = SegmentSet::default()
@ -1012,6 +1015,7 @@ impl<Ext: RethCliExt> NodeCommand<Ext> {
segments.into_vec(), segments.into_vec(),
config.block_interval, config.block_interval,
self.chain.prune_delete_limit, self.chain.prune_delete_limit,
tree_config.max_reorg_depth() as usize,
highest_snapshots_rx, highest_snapshots_rx,
) )
} }

View File

@ -533,6 +533,7 @@ where
vec![], vec![],
5, 5,
self.base_config.chain_spec.prune_delete_limit, self.base_config.chain_spec.prune_delete_limit,
config.max_reorg_depth() as usize,
watch::channel(None).1, watch::channel(None).1,
); );

View File

@ -34,6 +34,9 @@ pub struct Pruner<DB> {
previous_tip_block_number: Option<BlockNumber>, previous_tip_block_number: Option<BlockNumber>,
/// Maximum total entries to prune (delete from database) per block. /// Maximum total entries to prune (delete from database) per block.
delete_limit: usize, delete_limit: usize,
/// Maximum number of blocks to be pruned per run, as an additional restriction to
/// `previous_tip_block_number`.
prune_max_blocks_per_run: usize,
#[allow(dead_code)] #[allow(dead_code)]
highest_snapshots_tracker: HighestSnapshotsTracker, highest_snapshots_tracker: HighestSnapshotsTracker,
metrics: Metrics, metrics: Metrics,
@ -48,6 +51,7 @@ impl<DB: Database> Pruner<DB> {
segments: Vec<Arc<dyn Segment<DB>>>, segments: Vec<Arc<dyn Segment<DB>>>,
min_block_interval: usize, min_block_interval: usize,
delete_limit: usize, delete_limit: usize,
prune_max_blocks_per_run: usize,
highest_snapshots_tracker: HighestSnapshotsTracker, highest_snapshots_tracker: HighestSnapshotsTracker,
) -> Self { ) -> Self {
Self { Self {
@ -56,6 +60,7 @@ impl<DB: Database> Pruner<DB> {
min_block_interval, min_block_interval,
previous_tip_block_number: None, previous_tip_block_number: None,
delete_limit, delete_limit,
prune_max_blocks_per_run,
highest_snapshots_tracker, highest_snapshots_tracker,
metrics: Metrics::default(), metrics: Metrics::default(),
listeners: Default::default(), listeners: Default::default(),
@ -87,14 +92,22 @@ impl<DB: Database> Pruner<DB> {
// TODO(alexey): prune snapshotted segments of data (headers, transactions) // TODO(alexey): prune snapshotted segments of data (headers, transactions)
let highest_snapshots = *self.highest_snapshots_tracker.borrow(); let highest_snapshots = *self.highest_snapshots_tracker.borrow();
// Multiply `delete_limit` (number of row to delete per block) by number of blocks since // Multiply `self.delete_limit` (number of rows to delete per block) by number of blocks
// last pruner run. `previous_tip_block_number` is close to `tip_block_number`, usually // since last pruner run. `self.previous_tip_block_number` is close to
// within `self.block_interval` blocks, so `delete_limit` will not be too high. Also see // `tip_block_number`, usually within `self.block_interval` blocks, so
// docs for `self.previous_tip_block_number`. // `delete_limit` will not be too high. If it's too high, we additionally limit it by
let mut delete_limit = self.delete_limit * // `self.prune_max_blocks_per_run`.
self.previous_tip_block_number //
.map_or(1, |previous_tip_block_number| tip_block_number - previous_tip_block_number) // Also see docs for `self.previous_tip_block_number`.
as usize; let blocks_since_last_run =
(self.previous_tip_block_number.map_or(1, |previous_tip_block_number| {
// Saturating subtraction is needed for the case when the chain was reverted,
// meaning current block number might be less than the previous tip
// block number.
tip_block_number.saturating_sub(previous_tip_block_number) as usize
}))
.min(self.prune_max_blocks_per_run);
let mut delete_limit = self.delete_limit * blocks_since_last_run;
for segment in &self.segments { for segment in &self.segments {
if delete_limit == 0 { if delete_limit == 0 {
@ -259,7 +272,7 @@ mod tests {
#[test] #[test]
fn is_pruning_needed() { fn is_pruning_needed() {
let db = create_test_rw_db(); let db = create_test_rw_db();
let mut pruner = Pruner::new(db, MAINNET.clone(), vec![], 5, 0, watch::channel(None).1); let mut pruner = Pruner::new(db, MAINNET.clone(), vec![], 5, 0, 5, watch::channel(None).1);
// No last pruned block number was set before // No last pruned block number was set before
let first_block_number = 1; let first_block_number = 1;