@@ -21,6 +21,7 @@ package memory
21
21
import (
22
22
"bytes"
23
23
"context"
24
+ "iter"
24
25
"log/slog"
25
26
"sync"
26
27
"time"
@@ -276,8 +277,19 @@ func (m *Memory) DeleteRange(ctx context.Context, startKey, endKey backend.Key)
276
277
m .Lock ()
277
278
defer m .Unlock ()
278
279
m .removeExpired ()
279
- re := m .getRange (ctx , startKey , endKey , backend .NoLimit )
280
- for _ , item := range re .Items {
280
+
281
+ var items []backend.Item
282
+ m .tree .AscendGreaterOrEqual (& btreeItem {Item : backend.Item {Key : startKey }}, func (item * btreeItem ) bool {
283
+ if endKey .Compare (item .Key ) < 0 {
284
+ return false
285
+ }
286
+
287
+ items = append (items , item .Item )
288
+
289
+ return true
290
+ })
291
+
292
+ for _ , item := range items {
281
293
event := backend.Event {
282
294
Type : types .OpDelete ,
283
295
Item : item ,
@@ -290,25 +302,106 @@ func (m *Memory) DeleteRange(ctx context.Context, startKey, endKey backend.Key)
290
302
return nil
291
303
}
292
304
293
- // GetRange returns query range
294
- func ( m * Memory ) GetRange ( ctx context. Context , startKey , endKey backend. Key , limit int ) ( * backend. GetResult , error ) {
295
- if startKey . IsZero () {
296
- return nil , trace . BadParameter ( "missing parameter startKey" )
305
+ func ( m * Memory ) Items ( ctx context. Context , params backend. IterateParams ) iter. Seq2 [backend. Item , error ] {
306
+ if params . StartKey . IsZero ( ) {
307
+ err := trace . BadParameter ( "missing parameter startKey" )
308
+ return func ( yield func (backend. Item , error ) bool ) { yield (backend. Item {}, err ) }
297
309
}
298
- if endKey .IsZero () {
299
- return nil , trace .BadParameter ("missing parameter endKey" )
310
+ if params .EndKey .IsZero () {
311
+ err := trace .BadParameter ("missing parameter endKey" )
312
+ return func (yield func (backend.Item , error ) bool ) { yield (backend.Item {}, err ) }
300
313
}
314
+
315
+ limit := params .Limit
301
316
if limit <= 0 {
302
317
limit = backend .DefaultRangeLimit
303
318
}
304
- m .Lock ()
305
- defer m .Unlock ()
306
- m .removeExpired ()
307
- re := m .getRange (ctx , startKey , endKey , limit )
308
- if len (re .Items ) == backend .DefaultRangeLimit {
309
- m .logger .WarnContext (ctx , "Range query hit backend limit. (this is a bug!)" , "start_key" , startKey , "limit" , backend .DefaultRangeLimit )
319
+
320
+ const defaultPageSize = 1000
321
+ return func (yield func (backend.Item , error ) bool ) {
322
+ var totalCount int
323
+ defer func () {
324
+ if totalCount >= backend .DefaultRangeLimit {
325
+ m .logger .WarnContext (ctx , "Range query hit backend limit. (this is a bug!)" , "start_key" , params .StartKey , "limit" , backend .DefaultRangeLimit )
326
+ }
327
+ }()
328
+
329
+ startKey := params .StartKey
330
+ endKey := params .EndKey
331
+ compareDirection := 1
332
+ itemIter := m .tree .AscendGreaterOrEqual
333
+ if params .Descending {
334
+ startKey = params .EndKey
335
+ endKey = params .StartKey
336
+ compareDirection = - 1
337
+ itemIter = m .tree .DescendLessOrEqual
338
+ }
339
+
340
+ btreeItems := func (start * btreeItem ) iter.Seq [* btreeItem ] {
341
+ return func (yield func (* btreeItem ) bool ) {
342
+ m .Lock ()
343
+ defer m .Unlock ()
344
+ m .removeExpired ()
345
+
346
+ itemIter (start , yield )
347
+ }
348
+ }
349
+
350
+ var excludedStart bool
351
+ items := make ([]backend.Item , 0 , min (limit , defaultPageSize ))
352
+ startItem := & btreeItem {Item : backend.Item {Key : startKey }}
353
+ for {
354
+ pageLimit := min (limit - totalCount , defaultPageSize )
355
+ items = items [:0 ]
356
+
357
+ for item := range btreeItems (startItem ) {
358
+ if item .Key .Compare (endKey )* compareDirection > 0 {
359
+ break
360
+ }
361
+
362
+ if excludedStart {
363
+ excludedStart = false
364
+ if item .Key .Compare (startItem .Key ) <= 0 {
365
+ continue
366
+ }
367
+ }
368
+
369
+ items = append (items , item .Item )
370
+ if len (items ) >= pageLimit {
371
+ startItem = item
372
+ excludedStart = true
373
+ break
374
+ }
375
+ }
376
+
377
+ for _ , item := range items {
378
+ if ! yield (item , nil ) {
379
+ return
380
+ }
381
+
382
+ totalCount ++
383
+ if limit != backend .NoLimit && totalCount >= limit {
384
+ return
385
+ }
386
+ }
387
+
388
+ if len (items ) < pageLimit {
389
+ return
390
+ }
391
+ }
392
+ }
393
+ }
394
+
395
+ // GetRange returns query range
396
+ func (m * Memory ) GetRange (ctx context.Context , startKey , endKey backend.Key , limit int ) (* backend.GetResult , error ) {
397
+ var result backend.GetResult
398
+ for item , err := range m .Items (ctx , backend.IterateParams {StartKey : startKey , EndKey : endKey , Limit : limit }) {
399
+ if err != nil {
400
+ return nil , trace .Wrap (err )
401
+ }
402
+ result .Items = append (result .Items , item )
310
403
}
311
- return & re , nil
404
+ return & result , nil
312
405
}
313
406
314
407
// KeepAlive updates TTL on the lease
@@ -439,23 +532,6 @@ func (m *Memory) NewWatcher(ctx context.Context, watch backend.Watch) (backend.W
439
532
return m .buf .NewWatcher (ctx , watch )
440
533
}
441
534
442
- func (m * Memory ) getRange (ctx context.Context , startKey , endKey backend.Key , limit int ) backend.GetResult {
443
- var res backend.GetResult
444
- startItem := & btreeItem {Item : backend.Item {Key : startKey }}
445
- endItem := & btreeItem {Item : backend.Item {Key : endKey }}
446
- m .tree .AscendGreaterOrEqual (startItem , func (item * btreeItem ) bool {
447
- if endItem .Less (item ) {
448
- return false
449
- }
450
- res .Items = append (res .Items , item .Item )
451
- if limit > 0 && len (res .Items ) >= limit {
452
- return false
453
- }
454
- return true
455
- })
456
- return res
457
- }
458
-
459
535
// removeExpired makes a pass through map and removes expired elements
460
536
// returns the number of expired elements removed
461
537
func (m * Memory ) removeExpired () int {
0 commit comments