From c9cefc35fa92da5a580db487235f250d49a5e8f5 Mon Sep 17 00:00:00 2001 From: siddontang Date: Wed, 7 May 2014 14:18:11 +0800 Subject: [PATCH] iterator update --- leveldb/db.go | 14 ++++----- leveldb/iterator.go | 65 ++++++++++++++++++++--------------------- leveldb/leveldb_test.go | 56 ++++++++++------------------------- leveldb/snapshot.go | 9 +++--- 4 files changed, 59 insertions(+), 85 deletions(-) diff --git a/leveldb/db.go b/leveldb/db.go index a7a3221..384c498 100644 --- a/leveldb/db.go +++ b/leveldb/db.go @@ -116,7 +116,7 @@ func (db *DB) Destroy() { } func (db *DB) Clear() { - it := db.Iterator(NewRange(nil, nil), 0) + it := db.Iterator(nil, nil, 0, 0) for ; it.Valid(); it.Next() { db.Delete(it.Key()) } @@ -141,14 +141,14 @@ func (db *DB) NewWriteBatch() *WriteBatch { return wb } -//limit <= 0, no limit -func (db *DB) Iterator(r *Range, limit int) *Iterator { - return newIterator(db, db.iteratorOpts, r, limit, forward) +//limit <= 0, unlimit +func (db *DB) Iterator(min []byte, max []byte, rangeType uint8, limit int) *Iterator { + return newIterator(db, db.iteratorOpts, NewRange(min, max, rangeType), limit, IteratorForward) } -//limit <= 0, no limit -func (db *DB) ReverseIterator(r *Range, limit int) *Iterator { - return newIterator(db, db.iteratorOpts, r, limit, backward) +//limit <= 0, unlimit +func (db *DB) RevIterator(min []byte, max []byte, rangeType uint8, limit int) *Iterator { + return newIterator(db, db.iteratorOpts, NewRange(min, max, rangeType), limit, IteratorBackward) } func (db *DB) NewSnapshot() *Snapshot { diff --git a/leveldb/iterator.go b/leveldb/iterator.go index 588f09b..01dd0f4 100644 --- a/leveldb/iterator.go +++ b/leveldb/iterator.go @@ -5,35 +5,33 @@ import ( "github.com/jmhodges/levigo" ) -const forward uint8 = 0 -const backward uint8 = 1 +const ( + IteratorForward uint8 = 0 + IteratorBackward uint8 = 1 +) + +const ( + RangeClose uint8 = 0x00 + RangeLOpen uint8 = 0x01 + RangeROpen uint8 = 0x10 + RangeOpen uint8 = 0x11 +) //min must less or equal than max -//MinEx if true, range is left open interval (min, ... -//MaxEx if true, range is right open interval ..., max) -//Default range is close interval +//range type: +//close: [min, max] +//open: (min, max) +//lopen: (min, max] +//ropen: [min, max) type Range struct { Min []byte Max []byte - MinEx bool - MaxEx bool + Type uint8 } -func NewRange(min []byte, max []byte) *Range { - return &Range{min, max, false, false} -} - -func NewOpenRange(min []byte, max []byte) *Range { - return &Range{min, max, true, true} -} - -func NewLOpenRange(min []byte, max []byte) *Range { - return &Range{min, max, true, false} -} - -func NewROpenRange(min []byte, max []byte) *Range { - return &Range{min, max, true, true} +func NewRange(min []byte, max []byte, tp uint8) *Range { + return &Range{min, max, tp} } type Iterator struct { @@ -45,7 +43,7 @@ type Iterator struct { step int - //0 for forward, 1 for backward + //0 for IteratorForward, 1 for IteratorBackward direction uint8 } @@ -56,15 +54,16 @@ func newIterator(db *DB, opts *levigo.ReadOptions, r *Range, limit int, directio it.r = r it.limit = limit it.direction = direction + it.step = 0 - if direction == forward { + if direction == IteratorForward { if r.Min == nil { it.it.SeekToFirst() } else { it.it.Seek(r.Min) - if r.MinEx { + if r.Type&RangeLOpen > 0 { if it.Valid() && bytes.Equal(it.Key(), r.Min) { it.it.Next() } @@ -80,7 +79,7 @@ func newIterator(db *DB, opts *levigo.ReadOptions, r *Range, limit int, directio it.it.Prev() } - if r.MaxEx { + if r.Type&RangeROpen > 0 { if it.Valid() && bytes.Equal(it.Key(), r.Max) { it.it.Prev() } @@ -100,22 +99,22 @@ func (it *Iterator) Valid() bool { return false } - if it.direction == forward { + if it.direction == IteratorForward { if it.r.Max != nil { r := bytes.Compare(it.Key(), it.r.Max) - if !it.r.MaxEx { - return !(r > 0) - } else { + if it.r.Type&RangeROpen > 0 { return !(r >= 0) + } else { + return !(r > 0) } } } else { if it.r.Min != nil { r := bytes.Compare(it.Key(), it.r.Min) - if !it.r.MinEx { - return !(r < 0) - } else { + if it.r.Type&RangeLOpen > 0 { return !(r <= 0) + } else { + return !(r < 0) } } } @@ -130,7 +129,7 @@ func (it *Iterator) GetError() error { func (it *Iterator) Next() { it.step++ - if it.direction == forward { + if it.direction == IteratorForward { it.it.Next() } else { it.it.Prev() diff --git a/leveldb/leveldb_test.go b/leveldb/leveldb_test.go index 62f53b9..62cd074 100644 --- a/leveldb/leveldb_test.go +++ b/leveldb/leveldb_test.go @@ -129,34 +129,6 @@ func checkIterator(it *Iterator, cv ...int) error { return nil } -func testKeyRange(min int, max int) *Range { - return &Range{ - []byte(fmt.Sprintf("key_%d", min)), - []byte(fmt.Sprintf("key_%d", max)), - false, - false, - } -} - -func testLKeyRange(min int, max int) *Range { - r := testKeyRange(min, max) - r.MinEx = true - return r -} - -func testRKeyRange(min int, max int) *Range { - r := testKeyRange(min, max) - r.MaxEx = true - return r -} - -func testOpenKeyRange(min int, max int) *Range { - r := testKeyRange(min, max) - r.MinEx = true - r.MaxEx = true - return r -} - func TestIterator(t *testing.T) { db := getTestDB() @@ -170,52 +142,56 @@ func TestIterator(t *testing.T) { var it *Iterator - it = db.Iterator(testKeyRange(1, 5), 0) + k := func(i int) []byte { + return []byte(fmt.Sprintf("key_%d", i)) + } + + it = db.Iterator(k(1), k(5), RangeClose, 0) if err := checkIterator(it, 1, 2, 3, 4, 5); err != nil { t.Fatal(err) } - it = db.Iterator(testKeyRange(1, 9), 5) - if err := checkIterator(it, 1, 2, 3, 4, 5); err != nil { + it = db.Iterator(k(1), k(5), RangeClose, 3) + if err := checkIterator(it, 1, 2, 3); err != nil { t.Fatal(err) } - it = db.Iterator(testLKeyRange(1, 5), 0) + it = db.Iterator(k(1), k(5), RangeLOpen, 0) if err := checkIterator(it, 2, 3, 4, 5); err != nil { t.Fatal(err) } - it = db.Iterator(testRKeyRange(1, 5), 0) + it = db.Iterator(k(1), k(5), RangeROpen, 0) if err := checkIterator(it, 1, 2, 3, 4); err != nil { t.Fatal(err) } - it = db.Iterator(testOpenKeyRange(1, 5), 0) + it = db.Iterator(k(1), k(5), RangeOpen, 0) if err := checkIterator(it, 2, 3, 4); err != nil { t.Fatal(err) } - it = db.ReverseIterator(testKeyRange(1, 5), 0) + it = db.RevIterator(k(1), k(5), RangeClose, 0) if err := checkIterator(it, 5, 4, 3, 2, 1); err != nil { t.Fatal(err) } - it = db.ReverseIterator(testKeyRange(1, 9), 5) - if err := checkIterator(it, 9, 8, 7, 6, 5); err != nil { + it = db.RevIterator(k(1), k(5), RangeClose, 3) + if err := checkIterator(it, 5, 4, 3); err != nil { t.Fatal(err) } - it = db.ReverseIterator(testLKeyRange(1, 5), 0) + it = db.RevIterator(k(1), k(5), RangeLOpen, 0) if err := checkIterator(it, 5, 4, 3, 2); err != nil { t.Fatal(err) } - it = db.ReverseIterator(testRKeyRange(1, 5), 0) + it = db.RevIterator(k(1), k(5), RangeROpen, 0) if err := checkIterator(it, 4, 3, 2, 1); err != nil { t.Fatal(err) } - it = db.ReverseIterator(testOpenKeyRange(1, 5), 0) + it = db.RevIterator(k(1), k(5), RangeOpen, 0) if err := checkIterator(it, 4, 3, 2); err != nil { t.Fatal(err) } diff --git a/leveldb/snapshot.go b/leveldb/snapshot.go index 72eb40f..dbbed3c 100644 --- a/leveldb/snapshot.go +++ b/leveldb/snapshot.go @@ -37,13 +37,12 @@ func (s *Snapshot) Get(key []byte) ([]byte, error) { return s.db.db.Get(s.readOpts, key) } -//same as db iterator and reverse iterator -func (s *Snapshot) Iterator(r *Range, limit int) *Iterator { - return newIterator(s.db, s.iteratorOpts, r, limit, forward) +func (s *Snapshot) Iterator(min []byte, max []byte, rangeType uint8, limit int) *Iterator { + return newIterator(s.db, s.iteratorOpts, NewRange(min, max, rangeType), limit, IteratorForward) } -func (s *Snapshot) ReverseIterator(r *Range, limit int) *Iterator { - return newIterator(s.db, s.iteratorOpts, r, limit, backward) +func (s *Snapshot) RevIterator(min []byte, max []byte, rangeType uint8, limit int) *Iterator { + return newIterator(s.db, s.iteratorOpts, NewRange(min, max, rangeType), limit, IteratorBackward) } func (s *Snapshot) GetInt(key []byte) (int64, error) {