Skip to content

Commit b5eaf02

Browse files
committed
refactor StartEndPrefixToLowerUpperBound
1 parent a725247 commit b5eaf02

File tree

4 files changed

+30
-13
lines changed

4 files changed

+30
-13
lines changed

storage/operation/badgerimpl/iterator.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import (
99
)
1010

1111
type badgerIterator struct {
12-
iter *badger.Iterator
13-
lowerBound []byte
14-
upperBound []byte
12+
iter *badger.Iterator
13+
lowerBound []byte
14+
upperBound []byte
15+
hasUpperBound bool // whether there's an upper bound
1516
}
1617

1718
var _ storage.Iterator = (*badgerIterator)(nil)
@@ -25,12 +26,13 @@ func newBadgerIterator(db *badger.DB, startPrefix, endPrefix []byte, ops storage
2526
tx := db.NewTransaction(false)
2627
iter := tx.NewIterator(options)
2728

28-
lowerBound, upperBound := storage.StartEndPrefixToLowerUpperBound(startPrefix, endPrefix)
29+
lowerBound, upperBound, hasUpperBound := storage.StartEndPrefixToLowerUpperBound(startPrefix, endPrefix)
2930

3031
return &badgerIterator{
31-
iter: iter,
32-
lowerBound: lowerBound,
33-
upperBound: upperBound,
32+
iter: iter,
33+
lowerBound: lowerBound,
34+
upperBound: upperBound,
35+
hasUpperBound: hasUpperBound,
3436
}
3537
}
3638

@@ -54,7 +56,7 @@ func (i *badgerIterator) Valid() bool {
5456
}
5557

5658
// if upper bound is nil, then there's no upper bound, so it's always valid
57-
if i.upperBound == nil {
59+
if !i.hasUpperBound {
5860
return true
5961
}
6062

storage/operation/pebbleimpl/iterator.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,18 @@ type pebbleIterator struct {
1515
var _ storage.Iterator = (*pebbleIterator)(nil)
1616

1717
func newPebbleIterator(reader pebble.Reader, startPrefix, endPrefix []byte, ops storage.IteratorOption) (*pebbleIterator, error) {
18-
lowerBound, upperBound := storage.StartEndPrefixToLowerUpperBound(startPrefix, endPrefix)
18+
lowerBound, upperBound, hasUpperBound := storage.StartEndPrefixToLowerUpperBound(startPrefix, endPrefix)
1919

2020
options := pebble.IterOptions{
2121
LowerBound: lowerBound,
2222
UpperBound: upperBound,
2323
}
2424

25+
// setting UpperBound to nil if there is no upper bound
26+
if !hasUpperBound {
27+
options.UpperBound = nil
28+
}
29+
2530
iter, err := reader.NewIter(&options)
2631
if err != nil {
2732
return nil, fmt.Errorf("can not create iterator: %w", err)

storage/operation/pebbleimpl/writer.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ func (b *ReaderBatchWriter) Delete(key []byte) error {
106106
func (b *ReaderBatchWriter) DeleteByRange(globalReader storage.Reader, startPrefix, endPrefix []byte) error {
107107
// DeleteRange takes the prefix range with start (inclusive) and end (exclusive, note: not inclusive).
108108
// therefore, we need to increment the endPrefix to make it inclusive.
109-
start, end := storage.StartEndPrefixToLowerUpperBound(startPrefix, endPrefix)
110-
if len(end) > 0 {
109+
start, end, hasUpperBound := storage.StartEndPrefixToLowerUpperBound(startPrefix, endPrefix)
110+
if hasUpperBound {
111111
return b.batch.DeleteRange(start, end, pebble.Sync)
112112
}
113113

storage/operations.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,19 +135,29 @@ func OnCommitSucceed(b ReaderBatchWriter, onSuccessFn func()) {
135135
// the lower and upper bounds are used for the key iteration.
136136
// The return value lowerBound specifies the smallest key to iterate and it's inclusive.
137137
// The return value upperBound specifies the largest key to iterate and it's exclusive (not inclusive)
138+
// The return value hasUpperBound specifies whether there is upperBound
138139
// in order to match all keys prefixed with `endPrefix`, we increment the bytes of `endPrefix` by 1,
139140
// for instance, to iterate keys between "hello" and "world",
140141
// we use "hello" as LowerBound, "worle" as UpperBound, so that "world", "world1", "worldffff...ffff"
141142
// will all be included.
142-
func StartEndPrefixToLowerUpperBound(startPrefix, endPrefix []byte) (lowerBound, upperBound []byte) {
143-
return startPrefix, PrefixUpperBound(endPrefix)
143+
func StartEndPrefixToLowerUpperBound(startPrefix, endPrefix []byte) (lowerBound, upperBound []byte, hasUpperBound bool) {
144+
// if the endPrefix is all 1s, such as []byte{0xff, 0xff, ...}, there is no upper-bound
145+
// so we return the startPrefix as the lower-bound, and nil as the upper-bound, and false for hasUpperBound
146+
upperBound = PrefixUpperBound(endPrefix)
147+
if upperBound == nil {
148+
return startPrefix, nil, false
149+
}
150+
151+
return startPrefix, upperBound, true
144152
}
145153

146154
// PrefixUpperBound returns a key K such that all possible keys beginning with the input prefix
147155
// sort lower than K according to the byte-wise lexicographic key ordering.
148156
// This is used to define an upper bound for iteration, when we want to iterate over
149157
// all keys beginning with a given prefix.
150158
// referred to https://pkg.go.dev/github.com/cockroachdb/pebble#example-Iterator-PrefixIteration
159+
// when the prefix is all 1s, such as []byte{0xff}, or []byte(0xff, 0xff} etc, there is no upper-bound
160+
// It returns nil in this case.
151161
func PrefixUpperBound(prefix []byte) []byte {
152162
end := make([]byte, len(prefix))
153163
copy(end, prefix)

0 commit comments

Comments
 (0)