Skip to content

Commit 22bc5e7

Browse files
committed
prevent aggresive pruning
1 parent 83b4500 commit 22bc5e7

File tree

3 files changed

+68
-9
lines changed

3 files changed

+68
-9
lines changed

block/components.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ func NewSyncComponents(
182182
if p, ok := exec.(coreexecutor.ExecPruner); ok {
183183
execPruner = p
184184
}
185-
pruner := pruner.New(logger, store, execPruner, config.Pruning)
185+
pruner := pruner.New(logger, store, execPruner, config.Pruning, config.Node.BlockTime.Duration)
186186

187187
// Create submitter for sync nodes (no signer, only DA inclusion processing)
188188
var daSubmitter submitting.DASubmitterAPI = submitting.NewDASubmitter(daClient, config, genesis, blockOpts, metrics, logger, headerDAHintAppender, dataDAHintAppender)
@@ -271,7 +271,7 @@ func NewAggregatorComponents(
271271
if p, ok := exec.(coreexecutor.ExecPruner); ok {
272272
execPruner = p
273273
}
274-
pruner := pruner.New(logger, store, execPruner, config.Pruning)
274+
pruner := pruner.New(logger, store, execPruner, config.Pruning, config.Node.BlockTime.Duration)
275275

276276
reaper, err := reaping.NewReaper(
277277
exec,

block/internal/pruner/pruner.go

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type Pruner struct {
2222
store store.Store
2323
execPruner coreexecutor.ExecPruner
2424
cfg config.PruningConfig
25+
blockTime time.Duration
2526
logger zerolog.Logger
2627

2728
// Lifecycle
@@ -36,11 +37,13 @@ func New(
3637
store store.Store,
3738
execPruner coreexecutor.ExecPruner,
3839
cfg config.PruningConfig,
40+
blockTime time.Duration,
3941
) *Pruner {
4042
return &Pruner{
4143
store: store,
4244
execPruner: execPruner,
4345
cfg: cfg,
46+
blockTime: blockTime,
4447
logger: logger.With().Str("component", "prune").Logger(),
4548
}
4649
}
@@ -124,19 +127,64 @@ func (p *Pruner) pruneBlocks() error {
124127

125128
targetHeight := upperBound - p.cfg.KeepRecent
126129

127-
if err := p.store.PruneBlocks(p.ctx, targetHeight); err != nil {
128-
p.logger.Error().Err(err).Uint64("target_height", targetHeight).Msg("failed to prune old block data")
130+
// Get the last pruned height to determine batch size
131+
lastPruned, err := p.getLastPrunedBlockHeight(p.ctx)
132+
if err != nil {
133+
return fmt.Errorf("failed to get last pruned block height: %w", err)
134+
}
135+
136+
catchUpBatchSize, normalBatchSize := p.calculateBatchSizes()
137+
138+
remainingToPrune := targetHeight - lastPruned
139+
batchSize := normalBatchSize
140+
if remainingToPrune > catchUpBatchSize {
141+
batchSize = catchUpBatchSize
142+
}
143+
144+
// prune in batches to avoid overwhelming the system
145+
batchEnd := min(lastPruned+batchSize, targetHeight)
146+
147+
if err := p.store.PruneBlocks(p.ctx, batchEnd); err != nil {
148+
p.logger.Error().Err(err).Uint64("target_height", batchEnd).Msg("failed to prune old block data")
149+
return err
129150
}
130151

131152
if p.execPruner != nil {
132-
if err := p.execPruner.PruneExec(p.ctx, targetHeight); err != nil && !errors.Is(err, ds.ErrNotFound) {
153+
if err := p.execPruner.PruneExec(p.ctx, batchEnd); err != nil && !errors.Is(err, ds.ErrNotFound) {
133154
return err
134155
}
135156
}
136157

137158
return nil
138159
}
139160

161+
// calculateBatchSizes returns appropriate batch sizes for catch-up and normal pruning operations.
162+
// The batch sizes are based on the pruning interval and block time to ensure reasonable progress
163+
// without overwhelming the node.
164+
// Catch-up mode is usually triggered when pruning is enabled for the first time ever, and there is a large backlog of blocks to prune.
165+
func (p *Pruner) calculateBatchSizes() (catchUpBatchSize, normalBatchSize uint64) {
166+
// Calculate batch size based on pruning interval and block time.
167+
// We use 2x the blocks produced during one pruning interval as the catch-up batch size,
168+
// and 4x for normal operation. This ensures we make steady progress during catch-up
169+
// without overwhelming the node.
170+
// Example: With 100ms blocks and 15min interval: 15*60/0.1 = 9000 blocks/interval
171+
// - Catch-up batch: 18,000 blocks
172+
// - Normal batch: 36,000 blocks
173+
blocksPerInterval := uint64(p.cfg.Interval.Duration / p.blockTime)
174+
catchUpBatchSize = blocksPerInterval * 2
175+
normalBatchSize = blocksPerInterval * 4
176+
177+
// Ensure reasonable minimums
178+
if catchUpBatchSize < 1000 {
179+
catchUpBatchSize = 1000
180+
}
181+
if normalBatchSize < 10000 {
182+
normalBatchSize = 10000
183+
}
184+
185+
return catchUpBatchSize, normalBatchSize
186+
}
187+
140188
// pruneMetadata prunes old state and execution metadata entries based on the configured retention depth.
141189
// It does not prunes old blocks, as those are handled by the pruning logic.
142190
// Pruning old state does not lose history but limit the ability to recover (replay or rollback) to the last HEAD-N blocks, where N is the retention depth.
@@ -164,19 +212,30 @@ func (p *Pruner) pruneMetadata() error {
164212
return nil
165213
}
166214

167-
for h := lastPrunedState + 1; h <= target; h++ {
215+
catchUpBatchSize, normalBatchSize := p.calculateBatchSizes()
216+
217+
remainingToPrune := target - lastPrunedState
218+
batchSize := normalBatchSize
219+
if remainingToPrune > catchUpBatchSize {
220+
batchSize = catchUpBatchSize
221+
}
222+
223+
// prune in batches to avoid overwhelming the system
224+
batchEnd := min(lastPrunedState+batchSize, target)
225+
226+
for h := lastPrunedState + 1; h <= batchEnd; h++ {
168227
if err := p.store.DeleteStateAtHeight(p.ctx, h); err != nil && !errors.Is(err, ds.ErrNotFound) {
169228
return err
170229
}
171230
}
172231

173232
if p.execPruner != nil {
174-
if err := p.execPruner.PruneExec(p.ctx, target); err != nil && !errors.Is(err, ds.ErrNotFound) {
233+
if err := p.execPruner.PruneExec(p.ctx, batchEnd); err != nil && !errors.Is(err, ds.ErrNotFound) {
175234
return err
176235
}
177236
}
178237

179-
if err := p.setLastPrunedStateHeight(p.ctx, target); err != nil {
238+
if err := p.setLastPrunedStateHeight(p.ctx, batchEnd); err != nil {
180239
return fmt.Errorf("failed to set last pruned block height: %w", err)
181240
}
182241

block/internal/pruner/pruner_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func TestPrunerPruneMetadata(t *testing.T) {
5151
KeepRecent: 1,
5252
}
5353

54-
pruner := New(zerolog.New(zerolog.NewTestWriter(t)), stateStore, execAdapter, cfg)
54+
pruner := New(zerolog.New(zerolog.NewTestWriter(t)), stateStore, execAdapter, cfg, 100*time.Millisecond)
5555
require.NoError(t, pruner.pruneMetadata())
5656

5757
_, err := stateStore.GetStateAtHeight(ctx, 1)

0 commit comments

Comments
 (0)