Skip to content

Commit e201d7b

Browse files
authored
Fix for the infinite yieldItemValue recursion. (#503)
Don't repeat the yieldItemValue call, if the move key has already been checked.
1 parent b102210 commit e201d7b

File tree

1 file changed

+40
-33
lines changed

1 file changed

+40
-33
lines changed

iterator.go

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -140,42 +140,49 @@ func (item *Item) DiscardEarlierVersions() bool {
140140
}
141141

142142
func (item *Item) yieldItemValue() ([]byte, func(), error) {
143-
if !item.hasValue() {
144-
return nil, nil, nil
145-
}
143+
key := item.Key() // No need to copy.
144+
for {
145+
if !item.hasValue() {
146+
return nil, nil, nil
147+
}
146148

147-
if item.slice == nil {
148-
item.slice = new(y.Slice)
149-
}
149+
if item.slice == nil {
150+
item.slice = new(y.Slice)
151+
}
150152

151-
if (item.meta & bitValuePointer) == 0 {
152-
val := item.slice.Resize(len(item.vptr))
153-
copy(val, item.vptr)
154-
return val, nil, nil
155-
}
153+
if (item.meta & bitValuePointer) == 0 {
154+
val := item.slice.Resize(len(item.vptr))
155+
copy(val, item.vptr)
156+
return val, nil, nil
157+
}
156158

157-
var vp valuePointer
158-
vp.Decode(item.vptr)
159-
result, cb, err := item.db.vlog.Read(vp, item.slice)
160-
if err != ErrRetry {
161-
return result, cb, err
162-
}
163-
164-
// The value pointer is pointing to a deleted value log. Look for the move key and read that
165-
// instead.
166-
runCallback(cb)
167-
key := y.KeyWithTs(item.Key(), item.Version())
168-
moveKey := append(badgerMove, key...)
169-
vs, err := item.db.get(moveKey)
170-
if err != nil {
171-
return nil, nil, err
172-
}
173-
if vs.Version != item.Version() {
174-
return nil, nil, nil
175-
}
176-
item.vptr = vs.Value
177-
item.meta |= vs.Meta // This meta would only be about value pointer.
178-
return item.yieldItemValue()
159+
var vp valuePointer
160+
vp.Decode(item.vptr)
161+
result, cb, err := item.db.vlog.Read(vp, item.slice)
162+
if err != ErrRetry || bytes.HasPrefix(key, badgerMove) {
163+
// The error is not retry, or we have already searched the move keyspace.
164+
return result, cb, err
165+
}
166+
167+
// The value pointer is pointing to a deleted value log. Look for the
168+
// move key and read that instead.
169+
runCallback(cb)
170+
key = append(badgerMove, y.KeyWithTs(item.Key(), item.Version())...)
171+
// Note that we can't set item.key to move key, because that would
172+
// change the key user sees before and after this call. Also, this move
173+
// logic is internal logic and should not impact the external behavior
174+
// of the retrieval.
175+
vs, err := item.db.get(key)
176+
if err != nil {
177+
return nil, nil, err
178+
}
179+
if vs.Version != item.Version() {
180+
return nil, nil, nil
181+
}
182+
item.vptr = vs.Value
183+
item.meta &^= bitValuePointer // Clear the value pointer bit.
184+
item.meta |= vs.Meta // This meta would only be about value pointer.
185+
}
179186
}
180187

181188
func runCallback(cb func()) {

0 commit comments

Comments
 (0)