diff --git a/db_iter.go b/db_iter.go index a4180ab93c..288ca6f41d 100644 --- a/db_iter.go +++ b/db_iter.go @@ -9,9 +9,9 @@ import ( type dbIterPos int8 const ( - dbIterCur dbIterPos = iota - dbIterNext - dbIterPrev + dbIterCur dbIterPos = 0 + dbIterNext = 1 + dbIterPrev = -1 ) type dbIter struct { @@ -64,6 +64,7 @@ func (i *dbIter) findNextEntry() bool { return false } } + return false } @@ -100,6 +101,7 @@ func (i *dbIter) findPrevEntry() bool { return false } } + return false } @@ -114,6 +116,7 @@ func (i *dbIter) mergeNext() bool { for { i.iter.Next() if !i.iter.Valid() { + i.pos = dbIterNext return true } key := i.iter.Key() @@ -156,6 +159,7 @@ func (i *dbIter) mergePrev() bool { for { i.iter.Prev() if !i.iter.Valid() { + i.pos = dbIterPrev return true } key := i.iter.Key() @@ -223,8 +227,13 @@ func (i *dbIter) Next() bool { if i.err != nil { return false } - if i.pos != dbIterNext { + switch i.pos { + case dbIterCur: i.iter.NextUserKey() + case dbIterPrev: + i.iter.NextUserKey() + i.iter.NextUserKey() + case dbIterNext: } return i.findNextEntry() } @@ -233,8 +242,13 @@ func (i *dbIter) Prev() bool { if i.err != nil { return false } - if i.pos != dbIterPrev { + switch i.pos { + case dbIterCur: + i.iter.PrevUserKey() + case dbIterNext: + i.iter.PrevUserKey() i.iter.PrevUserKey() + case dbIterPrev: } return i.findPrevEntry() } diff --git a/db_iter_test.go b/db_iter_test.go index 4c8a7682bf..332fce1590 100644 --- a/db_iter_test.go +++ b/db_iter_test.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "math/rand" + "strconv" "strings" "testing" "time" @@ -16,11 +17,20 @@ func TestDBIter(t *testing.T) { var keys []db.InternalKey var vals [][]byte + newIter := func(seqNum uint64) *dbIter { + return &dbIter{ + cmp: db.DefaultComparer.Compare, + merge: db.DefaultMerger.Merge, + iter: &fakeIter{keys: keys, vals: vals}, + seqNum: seqNum, + } + } + datadriven.RunTest(t, "testdata/db_iter", func(d *datadriven.TestData) string { switch d.Cmd { case "define": - keys = nil - vals = nil + keys = keys[:0] + vals = vals[:0] for _, key := range strings.Split(d.Input, "\n") { j := strings.Index(key, ":") keys = append(keys, makeIkey(key[:j])) @@ -28,37 +38,47 @@ func TestDBIter(t *testing.T) { } return "" - case "next": - seek := fakeIkey(strings.TrimSpace(d.Input)) - iter := &dbIter{ - cmp: db.DefaultComparer.Compare, - iter: &fakeIter{keys: keys, vals: vals}, - seqNum: seek.SeqNum(), - } - - var b bytes.Buffer - for iter.SeekGE([]byte(seek.UserKey)); iter.Valid(); iter.Next() { - fmt.Fprintf(&b, "%s:%s\n", iter.Key(), iter.Value()) + case "iter": + if len(d.CmdArgs) != 1 || len(d.CmdArgs[0].Vals) != 1 || d.CmdArgs[0].Key != "seq" { + return fmt.Sprintf("iter seq=\n") } - if err := iter.Error(); err != nil { - fmt.Fprintf(&b, "err=%v\n", err) - } - return b.String() - - case "prev": - seek := fakeIkey(strings.TrimSpace(d.Input)) - iter := &dbIter{ - cmp: db.DefaultComparer.Compare, - iter: &fakeIter{keys: keys, vals: vals}, - seqNum: seek.SeqNum(), + seqNum, err := strconv.Atoi(d.CmdArgs[0].Vals[0]) + if err != nil { + return err.Error() } + iter := newIter(uint64(seqNum)) var b bytes.Buffer - for iter.SeekLT([]byte(seek.UserKey)); iter.Valid(); iter.Prev() { - fmt.Fprintf(&b, "%s:%s\n", iter.Key(), iter.Value()) - } - if err := iter.Error(); err != nil { - fmt.Fprintf(&b, "err=%v\n", err) + for _, line := range strings.Split(d.Input, "\n") { + parts := strings.Fields(line) + if len(parts) == 0 { + continue + } + switch parts[0] { + case "seek-ge": + if len(parts) != 2 { + return fmt.Sprintf("seek-ge \n") + } + iter.SeekGE([]byte(strings.TrimSpace(parts[1]))) + case "seek-lt": + if len(parts) != 2 { + return fmt.Sprintf("seek-lt \n") + } + iter.SeekLT([]byte(strings.TrimSpace(parts[1]))) + case "next": + iter.Next() + case "prev": + iter.Prev() + default: + return fmt.Sprintf("unknown op: %s", parts[0]) + } + if iter.Valid() { + fmt.Fprintf(&b, "%s:%s\n", iter.Key(), iter.Value()) + } else if err := iter.Error(); err != nil { + fmt.Fprintf(&b, "err=%v\n", err) + } else { + fmt.Fprintf(&b, ".\n") + } } return b.String() } diff --git a/iterator_test.go b/iterator_test.go index f5744e798b..69341125ba 100644 --- a/iterator_test.go +++ b/iterator_test.go @@ -71,6 +71,15 @@ func (f *fakeIter) SeekLT(key []byte) { break } } + if f.Valid() { + key := f.keys[f.index] + for ; f.index > 0; f.index-- { + pkey := f.keys[f.index-1] + if db.DefaultComparer.Compare(pkey.UserKey, key.UserKey) < 0 { + break + } + } + } } func (f *fakeIter) First() { @@ -91,6 +100,9 @@ func (f *fakeIter) NextUserKey() bool { if f.index == -1 { return f.Next() } + if f.index == len(f.keys) { + return false + } key := f.keys[f.index] for f.Next() { if db.DefaultComparer.Compare(key.UserKey, f.Key().UserKey) < 0 { diff --git a/testdata/db_iter b/testdata/db_iter index 7746cdeb51..1eadcceb2c 100644 --- a/testdata/db_iter +++ b/testdata/db_iter @@ -2,14 +2,24 @@ define a.SET.1:b ---- +iter seq=1 +seek-ge a next -a:1 +prev ---- a:b +. +a:b -prev -a:1 +iter seq=1 +seek-ge b +---- +. + +iter seq=1 +seek-lt a ---- +. define @@ -17,23 +27,23 @@ a.SET.2:c a.SET.1:b ---- +iter seq=1 +seek-ge a next -a:1 +prev ---- a:b +. +a:b +iter seq=2 +seek-ge a next -a:2 ----- -a:c - prev -a:1 ----- - -prev -a:2 ---- +a:c +. +a:c define @@ -41,18 +51,31 @@ a.DEL.2: a.SET.1:b ---- -next -a:2 +iter seq=2 +seek-ge a ---- +. +iter seq=1 +seek-ge 1 next -a:1 ---- a:b +. + +iter seq=2 +seek-lt b +---- +. +iter seq=1 +seek-lt b prev -a:2 +next ---- +a:b +. +a:b define @@ -61,24 +84,23 @@ a.SET.1:b b.SET.3:c ---- +iter seq=3 +seek-ge a next -a:3 ---- b:c +. -next -a:2 +iter seq=2 +seek-ge a ---- +. -next -a:1 +iter seq=1 +seek-ge a ---- a:b -prev -a:3 ----- - define a.SET.1:a @@ -86,59 +108,231 @@ b.SET.2:b c.SET.3:c ---- +iter seq=3 +seek-ge a +next +next next -a:3 ---- a:a b:b c:c +. +iter seq=3 +seek-ge b next -b:3 ---- b:b c:c -next -c:3 +iter seq=3 +seek-ge c ---- c:c -prev -a:3 +iter seq=3 +seek-lt a ---- +. +iter seq=3 +seek-lt b prev -b:3 +next ---- a:a +. +a:a +iter seq=3 +seek-lt c prev -c:3 +prev +next ---- b:b a:a +. +a:a + +iter seq=3 +seek-lt d +prev +prev +prev +next +---- +c:c +b:b +a:a +. +a:a define a.SET.b2:b b.SET.2:c ---- +iter seq=1 +seek-ge a next -a:1 +prev ---- a:b +. +a:b -next -b:1 +iter seq=1 +seek-ge b ---- +. +iter seq=1 +seek-lt a +---- +. + +iter seq=1 +seek-lt b prev -a:1 +next ---- +a:b +. +a:b +iter seq=1 +seek-lt c prev -b:1 +next ---- a:b +. +a:b + + +define +a.MERGE.3:b +a.MERGE.2:c +a.SET.1:d +b.MERGE.2:a +b.MERGE.1:b +---- + +iter seq=3 +seek-ge a +next +next +prev +---- +a:bcd +b:ab +. +b:ab + +iter seq=2 +seek-ge a +next +---- +a:cd +b:ab + +iter seq=1 +seek-ge a +next +---- +a:d +b:b + +iter seq=3 +seek-lt c +prev +prev +next +---- +b:ab +a:bcd +. +a:bcd + +iter seq=2 +seek-lt c +prev +---- +b:ab +a:cd + +iter seq=1 +seek-lt c +prev +---- +b:b +a:d + +iter seq=3 +seek-ge a +next +prev +next +---- +a:bcd +b:ab +a:bcd +b:ab + +iter seq=2 +seek-ge a +next +prev +next +---- +a:cd +b:ab +a:cd +b:ab + +iter seq=1 +seek-ge a +next +prev +next +---- +a:d +b:b +a:d +b:b + +iter seq=3 +seek-lt c +prev +next +prev +---- +b:ab +a:bcd +b:ab +a:bcd + +iter seq=2 +seek-lt c +prev +next +prev +---- +b:ab +a:cd +b:ab +a:cd + +iter seq=1 +seek-lt c +prev +next +prev +---- +b:b +a:d +b:b +a:d diff --git a/version_test.go b/version_test.go index 41591a76e6..53d9e84557 100644 --- a/version_test.go +++ b/version_test.go @@ -81,9 +81,10 @@ func TestIkeyRange(t *testing.T) { } var makeIkeyKinds = map[string]db.InternalKeyKind{ - "DEL": db.InternalKeyKindDelete, - "MAX": db.InternalKeyKindMax, - "SET": db.InternalKeyKindSet, + "DEL": db.InternalKeyKindDelete, + "MAX": db.InternalKeyKindMax, + "SET": db.InternalKeyKindSet, + "MERGE": db.InternalKeyKindMerge, } // makeIkey converts a string like "foo.DEL.123" into an internal key