@@ -9,18 +9,19 @@ import (
99 ds "github.com/ipfs/go-datastore"
1010 "github.com/rs/zerolog"
1111
12+ "github.com/evstack/ev-node/pkg/config"
1213 "github.com/evstack/ev-node/pkg/store"
1314)
1415
1516const (
16- DefaultPruneInterval = 15 * time .Minute
17+ defaultPruneInterval = 15 * time .Minute
1718 // maxPruneBatch limits how many heights we prune per cycle to bound work.
1819 maxPruneBatch = uint64 (1000 )
1920)
2021
21- // ExecMetaPruner removes execution metadata at a given height.
22- type ExecMetaPruner interface {
23- PruneExecMeta (ctx context.Context , height uint64 ) error
22+ // ExecPruner removes execution metadata at a given height.
23+ type ExecPruner interface {
24+ PruneExec (ctx context.Context , height uint64 ) error
2425}
2526
2627type stateDeleter interface {
@@ -31,22 +32,24 @@ type stateDeleter interface {
3132type Pruner struct {
3233 store store.Store
3334 stateDeleter stateDeleter
34- execPruner ExecMetaPruner
35- retention uint64
36- interval time.Duration
35+ execPruner ExecPruner
36+ cfg config.NodeConfig
3737 logger zerolog.Logger
3838 lastPruned uint64
3939
40+ // Lifecycle
41+ ctx context.Context
4042 wg sync.WaitGroup
4143 cancel context.CancelFunc
4244}
4345
4446// New creates a new Pruner instance.
45- func New (store store.Store , execMetaPruner ExecMetaPruner , retention uint64 , interval time.Duration , logger zerolog.Logger ) * Pruner {
46- if interval <= 0 {
47- interval = DefaultPruneInterval
48- }
49-
47+ func New (
48+ logger zerolog.Logger ,
49+ store store.Store ,
50+ execPruner ExecPruner ,
51+ cfg config.NodeConfig ,
52+ ) * Pruner {
5053 var deleter stateDeleter
5154 if store != nil {
5255 if sd , ok := store .(stateDeleter ); ok {
@@ -57,75 +60,66 @@ func New(store store.Store, execMetaPruner ExecMetaPruner, retention uint64, int
5760 return & Pruner {
5861 store : store ,
5962 stateDeleter : deleter ,
60- execPruner : execMetaPruner ,
61- retention : retention ,
62- interval : interval ,
63- logger : logger ,
63+ execPruner : execPruner ,
64+ cfg : cfg ,
65+ logger : logger .With ().Str ("component" , "prune" ).Logger (),
6466 }
6567}
6668
6769// Start begins the pruning loop.
6870func (p * Pruner ) Start (ctx context.Context ) error {
69- if p .retention == 0 {
70- return nil
71- }
71+ p .ctx , p .cancel = context .WithCancel (ctx )
7272
73- loopCtx , cancel := context .WithCancel (ctx )
74- p .cancel = cancel
75-
76- p .wg .Add (1 )
77- go p .pruneLoop (loopCtx )
73+ // Start pruner loop
74+ p .wg .Go (p .pruneLoop )
7875
76+ p .logger .Info ().Msg ("pruner started" )
7977 return nil
8078}
8179
8280// Stop stops the pruning loop.
8381func (p * Pruner ) Stop () error {
84- if p == nil || p .cancel = = nil {
85- return nil
82+ if p .cancel ! = nil {
83+ p . cancel ()
8684 }
87-
88- p .cancel ()
8985 p .wg .Wait ()
86+
87+ p .logger .Info ().Msg ("pruner stopped" )
9088 return nil
9189}
9290
93- func (p * Pruner ) pruneLoop (ctx context.Context ) {
94- defer p .wg .Done ()
95- ticker := time .NewTicker (p .interval )
91+ func (p * Pruner ) pruneLoop () {
92+ ticker := time .NewTicker (defaultPruneInterval )
9693 defer ticker .Stop ()
9794
98- if err := p .pruneOnce (ctx ); err != nil {
99- p .logger .Error ().Err (err ).Msg ("failed to prune recovery history" )
100- }
101-
10295 for {
10396 select {
10497 case <- ticker .C :
105- if err := p .pruneOnce ( ctx ); err != nil {
98+ if err := p .pruneRecoveryHistory ( p . ctx , p . cfg . RecoveryHistoryDepth ); err != nil {
10699 p .logger .Error ().Err (err ).Msg ("failed to prune recovery history" )
107100 }
108- case <- ctx .Done ():
101+
102+ // TODO: add pruning of old blocks // https://github.com/evstack/ev-node/pull/2984
103+ case <- p .ctx .Done ():
109104 return
110105 }
111106 }
112107}
113108
114- func (p * Pruner ) pruneOnce (ctx context.Context ) error {
115- if p .retention == 0 || p .store == nil {
116- return nil
117- }
118-
109+ // pruneRecoveryHistory prunes old state and execution metadata entries based on the configured retention depth.
110+ // It does not prunes old blocks, as those are handled by the pruning logic.
111+ // 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.
112+ func (p * Pruner ) pruneRecoveryHistory (ctx context.Context , retention uint64 ) error {
119113 height , err := p .store .Height (ctx )
120114 if err != nil {
121115 return err
122116 }
123117
124- if height <= p . retention {
118+ if height <= retention {
125119 return nil
126120 }
127121
128- target := height - p . retention
122+ target := height - retention
129123 if target <= p .lastPruned {
130124 return nil
131125 }
@@ -143,7 +137,7 @@ func (p *Pruner) pruneOnce(ctx context.Context) error {
143137 }
144138 }
145139 if p .execPruner != nil {
146- if err := p .execPruner .PruneExecMeta (ctx , h ); err != nil && ! errors .Is (err , ds .ErrNotFound ) {
140+ if err := p .execPruner .PruneExec (ctx , h ); err != nil && ! errors .Is (err , ds .ErrNotFound ) {
147141 return err
148142 }
149143 }
0 commit comments