Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug Fix: Handle multi-part lists properly in ReadPostingList #4574

Merged
merged 11 commits into from
Jan 22, 2020
1 change: 0 additions & 1 deletion posting/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -1133,7 +1133,6 @@ func (l *List) findPosting(readTs uint64, uid uint64) (found bool, pos *pb.Posti
// Facets gives facets for the posting representing value.
func (l *List) Facets(readTs uint64, param *pb.FacetParams, langs []string,
listType bool) ([]*pb.Facets, error) {

l.RLock()
defer l.RUnlock()

Expand Down
24 changes: 24 additions & 0 deletions posting/mvcc.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ import (
var (
// ErrTsTooOld is returned when a transaction is too old to be applied.
ErrTsTooOld = errors.Errorf("Transaction is too old")
// ErrInvalidKey is returned when trying to read a posting list using
// an invalid key (e.g the key to a single part of a larger multi-part list).
ErrInvalidKey = errors.Errorf("cannot read posting list from this key")
)

// ShouldAbort returns whether the transaction should be aborted.
Expand Down Expand Up @@ -141,6 +144,16 @@ func unmarshalOrCopy(plist *pb.PostingList, item *badger.Item) error {
// Use forward iterator with allversions enabled in iter options.
// key would now be owned by the posting list. So, ensure that it isn't reused elsewhere.
func ReadPostingList(key []byte, it *badger.Iterator) (*List, error) {
pk, err := x.Parse(key)
if err != nil {
return nil, errors.Wrapf(err, "while reading posting list with key [%v]", key)
}
if pk.HasStartUid {
// Trying to read a single part of a multi part list. This type of list
// should be read once using the canonical list (with startUid equal to zero).
return nil, ErrInvalidKey
}

l := new(List)
l.key = key
l.plist = new(pb.PostingList)
Expand All @@ -166,6 +179,17 @@ func ReadPostingList(key []byte, it *badger.Iterator) (*List, error) {
return nil, err
}
l.minTs = item.Version()

// If this list is a multi-part list, advance past the keys holding the parts.
if len(l.plist.GetSplits()) > 0 {
lastKey, err := x.GetSplitKey(key, math.MaxUint64)
if err != nil {
return nil, errors.Wrapf(err,
"while advancing past the end of multi-part list with key [%v]", key)
}
it.Seek(lastKey)
}

// No need to do Next here. The outer loop can take care of skipping
// more versions of the same key.
return l, nil
Expand Down