0
0
Fork 0

fix logic in Advance() of UpsideDownCouchDocIDReader

also added unit tests for newUpsideDownCouchDocIDReaderOnly
use cases
fixes #449
This commit is contained in:
Marty Schoch 2016-09-26 12:36:24 -04:00
parent 1d81d34a5a
commit 981812ff70
2 changed files with 234 additions and 6 deletions

View File

@ -240,12 +240,16 @@ func (r *UpsideDownCouchDocIDReader) Next() (index.IndexInternalID, error) {
}
func (r *UpsideDownCouchDocIDReader) Advance(docID index.IndexInternalID) (index.IndexInternalID, error) {
bir := NewBackIndexRow(docID, nil, nil)
r.iterator.Seek(bir.Key())
key, val, valid := r.iterator.Current()
r.onlyPos = sort.SearchStrings(r.only, string(docID))
if r.onlyMode {
r.onlyPos = sort.SearchStrings(r.only, string(docID))
if r.onlyPos >= len(r.only) {
// advanced to key after our last only key
return nil, nil
}
r.iterator.Seek(NewBackIndexRow([]byte(r.only[r.onlyPos]), nil, nil).Key())
key, val, valid := r.iterator.Current()
var rv index.IndexInternalID
for valid && r.onlyPos < len(r.only) {
br, err := NewBackIndexRowKV(key, val)
@ -253,11 +257,16 @@ func (r *UpsideDownCouchDocIDReader) Advance(docID index.IndexInternalID) (index
return nil, err
}
if !bytes.Equal(br.doc, []byte(r.only[r.onlyPos])) {
ok := r.nextOnly()
if !ok {
// the only key we seek'd to didn't exist
// now look for the closest key that did exist in only
r.onlyPos = sort.SearchStrings(r.only, string(br.doc))
if r.onlyPos >= len(r.only) {
// advanced to key after our last only key
return nil, nil
}
// now seek to this new only key
r.iterator.Seek(NewBackIndexRow([]byte(r.only[r.onlyPos]), nil, nil).Key())
key, val, valid = r.iterator.Current()
continue
} else {
rv = append([]byte(nil), br.doc...)
@ -272,6 +281,9 @@ func (r *UpsideDownCouchDocIDReader) Advance(docID index.IndexInternalID) (index
return rv, nil
}
} else {
bir := NewBackIndexRow(docID, nil, nil)
r.iterator.Seek(bir.Key())
key, val, valid := r.iterator.Current()
if valid {
br, err := NewBackIndexRowKV(key, val)
if err != nil {

View File

@ -306,3 +306,219 @@ func TestCrashBadBackIndexRow(t *testing.T) {
t.Fatal(err)
}
}
func TestIndexDocIdOnlyReader(t *testing.T) {
defer func() {
err := DestroyTest()
if err != nil {
t.Fatal(err)
}
}()
analysisQueue := index.NewAnalysisQueue(1)
idx, err := NewUpsideDownCouch(boltdb.Name, boltTestConfig, analysisQueue)
if err != nil {
t.Fatal(err)
}
err = idx.Open()
if err != nil {
t.Errorf("error opening index: %v", err)
}
defer func() {
err := idx.Close()
if err != nil {
t.Fatal(err)
}
}()
doc := document.NewDocument("1")
err = idx.Update(doc)
if err != nil {
t.Errorf("Error updating index: %v", err)
}
doc = document.NewDocument("3")
err = idx.Update(doc)
if err != nil {
t.Errorf("Error updating index: %v", err)
}
doc = document.NewDocument("5")
err = idx.Update(doc)
if err != nil {
t.Errorf("Error updating index: %v", err)
}
doc = document.NewDocument("7")
err = idx.Update(doc)
if err != nil {
t.Errorf("Error updating index: %v", err)
}
doc = document.NewDocument("9")
err = idx.Update(doc)
if err != nil {
t.Errorf("Error updating index: %v", err)
}
indexReader, err := idx.Reader()
if err != nil {
t.Error(err)
}
defer func() {
err := indexReader.Close()
if err != nil {
t.Error(err)
}
}()
onlyIds := []string{"1", "5", "9"}
reader, err := indexReader.DocIDReaderOnly(onlyIds)
if err != nil {
t.Errorf("Error accessing doc id reader: %v", err)
}
defer func() {
err := reader.Close()
if err != nil {
t.Fatal(err)
}
}()
id, err := reader.Next()
count := uint64(0)
for id != nil {
count++
id, err = reader.Next()
}
if count != 3 {
t.Errorf("expected 3, got %d", count)
}
// try it again, but jump
reader2, err := indexReader.DocIDReaderOnly(onlyIds)
if err != nil {
t.Errorf("Error accessing doc id reader: %v", err)
}
defer func() {
err := reader2.Close()
if err != nil {
t.Error(err)
}
}()
id, err = reader2.Advance(index.IndexInternalID("5"))
if err != nil {
t.Error(err)
}
if !id.Equals(index.IndexInternalID("5")) {
t.Errorf("expected to find id '5', got '%s'", id)
}
id, err = reader2.Advance(index.IndexInternalID("a"))
if err != nil {
t.Error(err)
}
if id != nil {
t.Errorf("expected to find id '', got '%s'", id)
}
// some keys aren't actually there
onlyIds = []string{"0", "2", "4", "5", "6", "8", "a"}
reader3, err := indexReader.DocIDReaderOnly(onlyIds)
if err != nil {
t.Errorf("Error accessing doc id reader: %v", err)
}
defer func() {
err := reader3.Close()
if err != nil {
t.Error(err)
}
}()
id, err = reader3.Next()
count = uint64(0)
for id != nil {
count++
id, err = reader3.Next()
}
if count != 1 {
t.Errorf("expected 1, got %d", count)
}
// mix advance and next
onlyIds = []string{"0", "1", "3", "5", "6", "9"}
reader4, err := indexReader.DocIDReaderOnly(onlyIds)
if err != nil {
t.Errorf("Error accessing doc id reader: %v", err)
}
defer func() {
err := reader4.Close()
if err != nil {
t.Error(err)
}
}()
// first key is "1"
id, err = reader4.Next()
if err != nil {
t.Error(err)
}
if !id.Equals(index.IndexInternalID("1")) {
t.Errorf("expected to find id '1', got '%s'", id)
}
// advancing to key we dont have gives next
id, err = reader4.Advance(index.IndexInternalID("2"))
if err != nil {
t.Error(err)
}
if !id.Equals(index.IndexInternalID("3")) {
t.Errorf("expected to find id '3', got '%s'", id)
}
// next after advance works
id, err = reader4.Next()
if err != nil {
t.Error(err)
}
if !id.Equals(index.IndexInternalID("5")) {
t.Errorf("expected to find id '5', got '%s'", id)
}
// advancing to key we do have works
id, err = reader4.Advance(index.IndexInternalID("9"))
if err != nil {
t.Error(err)
}
if !id.Equals(index.IndexInternalID("9")) {
t.Errorf("expected to find id '9', got '%s'", id)
}
// advance backwards at end
id, err = reader4.Advance(index.IndexInternalID("4"))
if err != nil {
t.Error(err)
}
if !id.Equals(index.IndexInternalID("5")) {
t.Errorf("expected to find id '5', got '%s'", id)
}
// next after advance works
id, err = reader4.Next()
if err != nil {
t.Error(err)
}
if !id.Equals(index.IndexInternalID("9")) {
t.Errorf("expected to find id '9', got '%s'", id)
}
// advance backwards to key that exists, but not in only set
id, err = reader4.Advance(index.IndexInternalID("7"))
if err != nil {
t.Error(err)
}
if !id.Equals(index.IndexInternalID("9")) {
t.Errorf("expected to find id '9', got '%s'", id)
}
}