@@ -10,7 +10,6 @@ import (
10
10
"time"
11
11
12
12
"github.com/ipfs/go-datastore"
13
- contextds "github.com/ipfs/go-datastore/context"
14
13
15
14
"github.com/celestiaorg/go-header"
16
15
)
@@ -100,27 +99,37 @@ var (
100
99
func (s * Store [H ]) deleteRange (ctx context.Context , from , to uint64 ) (err error ) {
101
100
startTime := time .Now ()
102
101
103
- var height uint64
102
+ var (
103
+ height uint64
104
+ missing int
105
+ )
104
106
defer func () {
105
107
if err != nil {
106
108
if errors .Is (err , errDeleteTimeout ) {
107
109
log .Warnw ("partial delete" ,
108
110
"from_height" , from ,
109
111
"expected_to_height" , to ,
110
112
"actual_to_height" , height ,
113
+ "hdrs_not_found" , missing ,
111
114
"took(s)" , time .Since (startTime ),
112
115
)
113
116
} else {
114
117
log .Errorw ("partial delete with error" ,
115
118
"from_height" , from ,
116
119
"expected_to_height" , to ,
117
120
"actual_to_height" , height ,
121
+ "hdrs_not_found" , missing ,
118
122
"took(s)" , time .Since (startTime ),
119
123
"err" , err ,
120
124
)
121
125
}
122
126
} else if to - from > 1 {
123
- log .Debugw ("deleted headers" , "from_height" , from , "to_height" , to , "took(s)" , time .Since (startTime ).Seconds ())
127
+ log .Debugw ("deleted headers" ,
128
+ "from_height" , from ,
129
+ "to_height" , to ,
130
+ "hdrs_not_found" , missing ,
131
+ "took(s)" , time .Since (startTime ).Seconds (),
132
+ )
124
133
}
125
134
126
135
if derr := s .setTail (ctx , s .ds , height ); derr != nil {
@@ -140,9 +149,9 @@ func (s *Store[H]) deleteRange(ctx context.Context, from, to uint64) (err error)
140
149
}
141
150
142
151
if to - from < deleteRangeParallelThreshold {
143
- height , err = s .deleteSequential (deleteCtx , from , to )
152
+ height , missing , err = s .deleteSequential (deleteCtx , from , to )
144
153
} else {
145
- height , err = s .deleteParallel (deleteCtx , from , to )
154
+ height , missing , err = s .deleteParallel (deleteCtx , from , to )
146
155
}
147
156
148
157
return err
@@ -153,7 +162,6 @@ func (s *Store[H]) deleteRange(ctx context.Context, from, to uint64) (err error)
153
162
func (s * Store [H ]) deleteSingle (
154
163
ctx context.Context ,
155
164
height uint64 ,
156
- batch datastore.Batch ,
157
165
onDelete []func (ctx context.Context , height uint64 ) error ,
158
166
) error {
159
167
// some of the methods may not handle context cancellation properly
@@ -162,10 +170,6 @@ func (s *Store[H]) deleteSingle(
162
170
}
163
171
164
172
hash , err := s .heightIndex .HashByHeight (ctx , height , false )
165
- if errors .Is (err , datastore .ErrNotFound ) {
166
- log .Debugw ("attempt to delete header that's not found" , "height" , height )
167
- return nil
168
- }
169
173
if err != nil {
170
174
return fmt .Errorf ("hash by height %d: %w" , height , err )
171
175
}
@@ -176,10 +180,10 @@ func (s *Store[H]) deleteSingle(
176
180
}
177
181
}
178
182
179
- if err := batch .Delete (ctx , hashKey (hash )); err != nil {
183
+ if err := s . ds .Delete (ctx , hashKey (hash )); err != nil {
180
184
return fmt .Errorf ("delete hash key (%X): %w" , hash , err )
181
185
}
182
- if err := batch .Delete (ctx , heightKey (height )); err != nil {
186
+ if err := s . ds .Delete (ctx , heightKey (height )); err != nil {
183
187
return fmt .Errorf ("delete height key (%d): %w" , height , err )
184
188
}
185
189
@@ -194,36 +198,38 @@ func (s *Store[H]) deleteSingle(
194
198
func (s * Store [H ]) deleteSequential (
195
199
ctx context.Context ,
196
200
from , to uint64 ,
197
- ) (highest uint64 , err error ) {
201
+ ) (highest uint64 , missing int , err error ) {
198
202
log .Debugw ("starting delete range sequential" , "from_height" , from , "to_height" , to )
199
203
200
- batch , err := s .ds .Batch (ctx )
201
- if err != nil {
202
- return 0 , fmt .Errorf ("new batch: %w" , err )
203
- }
204
- ctx = contextds .WithWrite (ctx , batch )
204
+ ctx , done := s .withWriteBatch (ctx )
205
205
defer func () {
206
- if derr := batch . Commit ( ctx ); derr != nil {
206
+ if derr := done ( ); derr != nil {
207
207
err = errors .Join (err , fmt .Errorf ("committing batch: %w" , derr ))
208
208
}
209
209
}()
210
+ ctx , doneTx := s .withReadTransaction (ctx )
211
+ defer doneTx ()
210
212
211
213
s .onDeleteMu .Lock ()
212
214
onDelete := slices .Clone (s .onDelete )
213
215
s .onDeleteMu .Unlock ()
214
216
215
217
for height := from ; height < to ; height ++ {
216
- if err := s .deleteSingle (ctx , height , batch , onDelete ); err != nil {
217
- return height , err
218
+ err := s .deleteSingle (ctx , height , onDelete )
219
+ if errors .Is (err , datastore .ErrNotFound ) {
220
+ missing ++
221
+ log .Debugw ("attempt to delete header that's not found" , "height" , height )
222
+ } else if err != nil {
223
+ return height , missing , err
218
224
}
219
225
}
220
226
221
- return to , nil
227
+ return to , missing , nil
222
228
}
223
229
224
230
// deleteParallel deletes [from:to) header range from the store in parallel
225
231
// and returns the highest unprocessed height: 'to' in success case or the failed height in error case.
226
- func (s * Store [H ]) deleteParallel (ctx context.Context , from , to uint64 ) (uint64 , error ) {
232
+ func (s * Store [H ]) deleteParallel (ctx context.Context , from , to uint64 ) (uint64 , int , error ) {
227
233
now := time .Now ()
228
234
s .onDeleteMu .Lock ()
229
235
onDelete := slices .Clone (s .onDelete )
@@ -235,13 +241,16 @@ func (s *Store[H]) deleteParallel(ctx context.Context, from, to uint64) (uint64,
235
241
// require too much RAM, yet shows good performance.
236
242
workerNum := runtime .GOMAXPROCS (- 1 ) * 3
237
243
238
- log .Infow (
239
- "deleting range parallel" , "from_height" , from , "to_height" , to , "worker_num" , workerNum ,
244
+ log .Infow ("deleting range parallel" ,
245
+ "from_height" , from ,
246
+ "to_height" , to ,
247
+ "worker_num" , workerNum ,
240
248
)
241
249
242
250
type result struct {
243
- height uint64
244
- err error
251
+ missing int
252
+ height uint64
253
+ err error
245
254
}
246
255
results := make ([]result , workerNum )
247
256
jobCh := make (chan uint64 , workerNum )
@@ -260,24 +269,25 @@ func (s *Store[H]) deleteParallel(ctx context.Context, from, to uint64) (uint64,
260
269
}
261
270
}()
262
271
263
- batch , err := s .ds .Batch (ctx )
264
- if err != nil {
265
- last .err = fmt .Errorf ("new batch: %w" , err )
266
- return
267
- }
268
- ctx = contextds .WithWrite (ctx , batch )
272
+ workerCtx , done := s .withWriteBatch (ctx )
273
+ defer func () {
274
+ if err := done (); err != nil {
275
+ last .err = errors .Join (last .err , fmt .Errorf ("committing delete batch: %w" , err ))
276
+ }
277
+ }()
278
+ workerCtx , doneTx := s .withReadTransaction (workerCtx )
279
+ defer doneTx ()
269
280
270
281
for height := range jobCh {
271
282
last .height = height
272
- last .err = s .deleteSingle (ctx , height , batch , onDelete )
273
- if last .err != nil {
283
+ last .err = s .deleteSingle (workerCtx , height , onDelete )
284
+ if errors .Is (last .err , datastore .ErrNotFound ) {
285
+ last .missing ++
286
+ log .Debugw ("attempt to delete header that's not found" , "height" , height )
287
+ } else if last .err != nil {
274
288
break
275
289
}
276
290
}
277
-
278
- if err := batch .Commit (ctx ); err != nil {
279
- last .err = errors .Join (last .err , fmt .Errorf ("committing delete batch: %w" , err ))
280
- }
281
291
}
282
292
283
293
var wg sync.WaitGroup
@@ -309,29 +319,30 @@ func (s *Store[H]) deleteParallel(ctx context.Context, from, to uint64) (uint64,
309
319
return int (a .height - b .height ) //nolint:gosec
310
320
})
311
321
// find the highest deleted height
312
- var highest uint64
322
+ var (
323
+ highest uint64
324
+ missing int
325
+ )
313
326
for _ , result := range results {
314
327
if result .err != nil {
315
328
// return the error immediately even if some higher headers may have been deleted
316
329
// this ensures we set tail to the lowest errored height, s.t. retries do not shadowly miss any headers
317
- return result .height , result .err
330
+ return result .height , missing , result .err
318
331
}
319
332
320
333
if result .height > highest {
321
334
highest = result .height
322
335
}
336
+ missing += result .missing
323
337
}
324
338
325
339
// ensures the height after the highest deleted becomes the new tail
326
340
highest ++
327
- log .Infow (
328
- "deleted range parallel" ,
329
- "from_height" ,
330
- from ,
331
- "to_height" ,
332
- to ,
333
- "took(s)" ,
334
- time .Since (now ).Seconds (),
341
+ log .Infow ("deleted range parallel" ,
342
+ "from_height" , from ,
343
+ "to_height" , to ,
344
+ "hdrs_not_found" , missing ,
345
+ "took(s)" , time .Since (now ).Seconds (),
335
346
)
336
- return highest , nil
347
+ return highest , missing , nil
337
348
}
0 commit comments