0
0

add test case for seeing prefix iterators outside of range

similar to #256 except for prefix iterators
includes fix for boltdb and gtreap which had incorrect behavior
This commit is contained in:
Marty Schoch 2015-10-26 16:14:29 -04:00
parent 0ba164322b
commit f0d282f5f8
7 changed files with 119 additions and 2 deletions

View File

@ -39,9 +39,17 @@ func (i *Iterator) updateValid() {
}
func (i *Iterator) Seek(k []byte) {
if bytes.Compare(k, i.start) < 0 {
if i.start != nil && bytes.Compare(k, i.start) < 0 {
k = i.start
}
if i.prefix != nil && !bytes.HasPrefix(k, i.prefix) {
if bytes.Compare(k, i.prefix) < 0 {
k = i.prefix
} else {
i.valid = false
return
}
}
i.key, i.val = i.cursor.Seek(k)
i.updateValid()
}

View File

@ -66,6 +66,12 @@ func TestBoltDBPrefixIterator(t *testing.T) {
test.CommonTestPrefixIterator(t, s)
}
func TestBoltDBPrefixIteratorSeek(t *testing.T) {
s := open(t, nil)
defer cleanup(t, s)
test.CommonTestPrefixIteratorSeek(t, s)
}
func TestBoltDBRangeIterator(t *testing.T) {
s := open(t, nil)
defer cleanup(t, s)

View File

@ -69,6 +69,12 @@ func TestGoLevelDBPrefixIterator(t *testing.T) {
test.CommonTestPrefixIterator(t, s)
}
func TestGoLevelDBPrefixIteratorSeek(t *testing.T) {
s := open(t, nil)
defer cleanup(t, s)
test.CommonTestPrefixIteratorSeek(t, s)
}
func TestGoLevelDBRangeIterator(t *testing.T) {
s := open(t, nil)
defer cleanup(t, s)

View File

@ -36,9 +36,26 @@ type Iterator struct {
}
func (w *Iterator) Seek(k []byte) {
if bytes.Compare(k, w.start) < 0 {
if w.start != nil && bytes.Compare(k, w.start) < 0 {
k = w.start
}
if w.prefix != nil && !bytes.HasPrefix(k, w.prefix) {
if bytes.Compare(k, w.prefix) < 0 {
k = w.prefix
} else {
var end []byte
for i := len(w.prefix) - 1; i >= 0; i-- {
c := w.prefix[i]
if c < 0xff {
end = make([]byte, i+1)
copy(end, w.prefix)
end[i] = c + 1
break
}
}
k = end
}
}
w.restart(&Item{k: k})
}

View File

@ -64,6 +64,12 @@ func TestGTreapPrefixIterator(t *testing.T) {
test.CommonTestPrefixIterator(t, s)
}
func TestGTreapPrefixIteratorSeek(t *testing.T) {
s := open(t, nil)
defer cleanup(t, s)
test.CommonTestPrefixIteratorSeek(t, s)
}
func TestGTreapRangeIterator(t *testing.T) {
s := open(t, nil)
defer cleanup(t, s)

View File

@ -53,6 +53,12 @@ func TestMetricsPrefixIterator(t *testing.T) {
test.CommonTestPrefixIterator(t, s)
}
func TestMetricsPrefixIteratorSeek(t *testing.T) {
s := open(t, nil)
defer cleanup(t, s)
test.CommonTestPrefixIteratorSeek(t, s)
}
func TestMetricsRangeIterator(t *testing.T) {
s := open(t, nil)
defer cleanup(t, s)

View File

@ -131,6 +131,74 @@ func CommonTestPrefixIterator(t *testing.T, s store.KVStore) {
}
}
func CommonTestPrefixIteratorSeek(t *testing.T, s store.KVStore) {
data := []testRow{
{[]byte("a"), []byte("val")},
{[]byte("b1"), []byte("val")},
{[]byte("b2"), []byte("val")},
{[]byte("b3"), []byte("val")},
{[]byte("c"), []byte("val")},
}
err := batchWriteRows(s, data)
if err != nil {
t.Fatal(err)
}
// open a reader
reader, err := s.Reader()
if err != nil {
t.Fatal(err)
}
// get an iterator on a central subset of the data
iter := reader.PrefixIterator([]byte("b"))
// check that all keys have prefix
found := []string{}
for ; iter.Valid(); iter.Next() {
found = append(found, string(iter.Key()))
}
for _, f := range found {
if !strings.HasPrefix(f, "b") {
t.Errorf("got key '%s' that doesn't have correct prefix")
}
}
if len(found) != 3 {
t.Errorf("expected 3 keys with prefix, got %d", len(found))
}
// now try to seek before the prefix and repeat
found = []string{}
for iter.Seek([]byte("a")); iter.Valid(); iter.Next() {
found = append(found, string(iter.Key()))
}
for _, f := range found {
if !strings.HasPrefix(f, "b") {
t.Errorf("got key '%s' that doesn't have correct prefix")
}
}
if len(found) != 3 {
t.Errorf("expected 3 keys with prefix, got %d", len(found))
}
// now try to seek after the prefix and repeat
found = []string{}
for iter.Seek([]byte("c")); iter.Valid(); iter.Next() {
found = append(found, string(iter.Key()))
}
for _, f := range found {
if !strings.HasPrefix(f, "b") {
t.Errorf("got key '%s' that doesn't have correct prefix")
}
}
if len(found) != 0 {
t.Errorf("expected 0 keys with prefix, got %d", len(found))
}
}
func CommonTestRangeIterator(t *testing.T, s store.KVStore) {
data := []testRow{