Skip to content

Commit c19fa27

Browse files
authored
Add AscendKeysRange and DescendKeysRange functions (#323)
* Add AscendKeysRange and DescendKeysRange functions to support key iteration within a specified range
1 parent 0b2637b commit c19fa27

File tree

1 file changed

+102
-30
lines changed

1 file changed

+102
-30
lines changed

db.go

Lines changed: 102 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -446,34 +446,70 @@ func (db *DB) AscendGreaterOrEqual(key []byte, handleFn func(k []byte, v []byte)
446446
// Since our expiry time is stored in the value, if you want to filter expired keys,
447447
// you need to set parameter filterExpired to true. But the performance will be affected.
448448
// Because we need to read the value of each key to determine if it is expired.
449-
func (db *DB) AscendKeys(pattern []byte, filterExpired bool, handleFn func(k []byte) (bool, error)) {
449+
func (db *DB) AscendKeys(pattern []byte, filterExpired bool, handleFn func(k []byte) (bool, error)) error {
450450
db.mu.RLock()
451451
defer db.mu.RUnlock()
452452

453453
var reg *regexp.Regexp
454454
if len(pattern) > 0 {
455-
reg = regexp.MustCompile(string(pattern))
455+
var err error
456+
reg, err = regexp.Compile(string(pattern))
457+
if err != nil {
458+
return err
459+
}
456460
}
457461

458462
db.index.Ascend(func(key []byte, pos *wal.ChunkPosition) (bool, error) {
459-
if reg == nil || reg.Match(key) {
460-
var invalid bool
461-
if filterExpired {
462-
chunk, err := db.dataFiles.Read(pos)
463-
if err != nil {
464-
return false, err
465-
}
466-
if value := db.checkValue(chunk); value == nil {
467-
invalid = true
468-
}
463+
if reg != nil && !reg.Match(key) {
464+
return true, nil
465+
}
466+
if filterExpired {
467+
chunk, err := db.dataFiles.Read(pos)
468+
if err != nil {
469+
return false, err
469470
}
470-
if invalid {
471+
if value := db.checkValue(chunk); value == nil {
471472
return true, nil
472473
}
473-
return handleFn(key)
474474
}
475-
return true, nil
475+
return handleFn(key)
476476
})
477+
return nil
478+
}
479+
480+
// AscendKeysRange calls handleFn for keys within a range in the db in ascending order.
481+
// Since our expiry time is stored in the value, if you want to filter expired keys,
482+
// you need to set parameter filterExpired to true. But the performance will be affected.
483+
// Because we need to read the value of each key to determine if it is expired.
484+
func (db *DB) AscendKeysRange(startKey, endKey, pattern []byte, filterExpired bool, handleFn func(k []byte) (bool, error)) error {
485+
db.mu.RLock()
486+
defer db.mu.RUnlock()
487+
488+
var reg *regexp.Regexp
489+
if len(pattern) > 0 {
490+
var err error
491+
reg, err = regexp.Compile(string(pattern))
492+
if err != nil {
493+
return err
494+
}
495+
}
496+
497+
db.index.AscendRange(startKey, endKey, func(key []byte, pos *wal.ChunkPosition) (bool, error) {
498+
if reg != nil && !reg.Match(key) {
499+
return true, nil
500+
}
501+
if filterExpired {
502+
chunk, err := db.dataFiles.Read(pos)
503+
if err != nil {
504+
return false, err
505+
}
506+
if value := db.checkValue(chunk); value == nil {
507+
return true, nil
508+
}
509+
}
510+
return handleFn(key)
511+
})
512+
return nil
477513
}
478514

479515
// Descend calls handleFn for each key/value pair in the db in descending order.
@@ -531,34 +567,70 @@ func (db *DB) DescendLessOrEqual(key []byte, handleFn func(k []byte, v []byte) (
531567
// Since our expiry time is stored in the value, if you want to filter expired keys,
532568
// you need to set parameter filterExpired to true. But the performance will be affected.
533569
// Because we need to read the value of each key to determine if it is expired.
534-
func (db *DB) DescendKeys(pattern []byte, filterExpired bool, handleFn func(k []byte) (bool, error)) {
570+
func (db *DB) DescendKeys(pattern []byte, filterExpired bool, handleFn func(k []byte) (bool, error)) error {
535571
db.mu.RLock()
536572
defer db.mu.RUnlock()
537573

538574
var reg *regexp.Regexp
539575
if len(pattern) > 0 {
540-
reg = regexp.MustCompile(string(pattern))
576+
var err error
577+
reg, err = regexp.Compile(string(pattern))
578+
if err != nil {
579+
return err
580+
}
541581
}
542582

543583
db.index.Descend(func(key []byte, pos *wal.ChunkPosition) (bool, error) {
544-
if reg == nil || reg.Match(key) {
545-
var invalid bool
546-
if filterExpired {
547-
chunk, err := db.dataFiles.Read(pos)
548-
if err != nil {
549-
return false, err
550-
}
551-
if value := db.checkValue(chunk); value == nil {
552-
invalid = true
553-
}
584+
if reg != nil && !reg.Match(key) {
585+
return true, nil
586+
}
587+
if filterExpired {
588+
chunk, err := db.dataFiles.Read(pos)
589+
if err != nil {
590+
return false, err
554591
}
555-
if invalid {
592+
if value := db.checkValue(chunk); value == nil {
556593
return true, nil
557594
}
558-
return handleFn(key)
559595
}
560-
return true, nil
596+
return handleFn(key)
561597
})
598+
return nil
599+
}
600+
601+
// DescendKeysRange calls handleFn for keys within a range in the db in descending order.
602+
// Since our expiry time is stored in the value, if you want to filter expired keys,
603+
// you need to set parameter filterExpired to true. But the performance will be affected.
604+
// Because we need to read the value of each key to determine if it is expired.
605+
func (db *DB) DescendKeysRange(startKey, endKey, pattern []byte, filterExpired bool, handleFn func(k []byte) (bool, error)) error {
606+
db.mu.RLock()
607+
defer db.mu.RUnlock()
608+
609+
var reg *regexp.Regexp
610+
if len(pattern) > 0 {
611+
var err error
612+
reg, err = regexp.Compile(string(pattern))
613+
if err != nil {
614+
return err
615+
}
616+
}
617+
618+
db.index.DescendRange(startKey, endKey, func(key []byte, pos *wal.ChunkPosition) (bool, error) {
619+
if reg != nil && !reg.Match(key) {
620+
return true, nil
621+
}
622+
if filterExpired {
623+
chunk, err := db.dataFiles.Read(pos)
624+
if err != nil {
625+
return false, err
626+
}
627+
if value := db.checkValue(chunk); value == nil {
628+
return true, nil
629+
}
630+
}
631+
return handleFn(key)
632+
})
633+
return nil
562634
}
563635

564636
func (db *DB) checkValue(chunk []byte) []byte {

0 commit comments

Comments
 (0)