From af4507fc5178bb9b460b759a6a70073520ec03c0 Mon Sep 17 00:00:00 2001 From: siddontang Date: Wed, 7 May 2014 22:53:24 +0800 Subject: [PATCH] iterator add offset and limit, reviterator bug fix --- leveldb/db.go | 12 ++++++----- leveldb/iterator.go | 44 ++++++++++++++++++++++++----------------- leveldb/leveldb_test.go | 24 +++++++++++----------- leveldb/snapshot.go | 8 ++++---- 4 files changed, 49 insertions(+), 39 deletions(-) diff --git a/leveldb/db.go b/leveldb/db.go index d0fb1b3..e3ad332 100644 --- a/leveldb/db.go +++ b/leveldb/db.go @@ -116,7 +116,7 @@ func (db *DB) Destroy() { } func (db *DB) Clear() { - it := db.Iterator(nil, nil, 0, -1) + it := db.Iterator(nil, nil, 0, 0, -1) for ; it.Valid(); it.Next() { db.Delete(it.Key()) } @@ -142,13 +142,15 @@ func (db *DB) NewWriteBatch() *WriteBatch { } //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) +//offset must >= 0, if < 0, will get nothing +func (db *DB) Iterator(min []byte, max []byte, rangeType uint8, offset int, limit int) *Iterator { + return newIterator(db, db.iteratorOpts, NewRange(min, max, rangeType), offset, limit, IteratorForward) } //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) +//offset must >= 0, if < 0, will get nothing +func (db *DB) RevIterator(min []byte, max []byte, rangeType uint8, offset int, limit int) *Iterator { + return newIterator(db, db.iteratorOpts, NewRange(min, max, rangeType), offset, limit, IteratorBackward) } func (db *DB) NewSnapshot() *Snapshot { diff --git a/leveldb/iterator.go b/leveldb/iterator.go index f53e5c5..d3e19bd 100644 --- a/leveldb/iterator.go +++ b/leveldb/iterator.go @@ -39,7 +39,8 @@ type Iterator struct { r *Range - limit int + offset int + limit int step int @@ -47,16 +48,21 @@ type Iterator struct { direction uint8 } -func newIterator(db *DB, opts *levigo.ReadOptions, r *Range, limit int, direction uint8) *Iterator { +func newIterator(db *DB, opts *levigo.ReadOptions, r *Range, offset int, limit int, direction uint8) *Iterator { it := new(Iterator) it.it = db.db.NewIterator(opts) it.r = r + it.offset = offset it.limit = limit it.direction = direction it.step = 0 + if offset < 0 { + return it + } + if direction == IteratorForward { if r.Min == nil { it.it.SeekToFirst() @@ -64,7 +70,7 @@ func newIterator(db *DB, opts *levigo.ReadOptions, r *Range, limit int, directio it.it.Seek(r.Min) if r.Type&RangeLOpen > 0 { - if it.Valid() && bytes.Equal(it.Key(), r.Min) { + if it.it.Valid() && bytes.Equal(it.it.Key(), r.Min) { it.it.Next() } } @@ -74,9 +80,13 @@ func newIterator(db *DB, opts *levigo.ReadOptions, r *Range, limit int, directio it.it.SeekToLast() } else { it.it.Seek(r.Max) - if it.Valid() && !bytes.Equal(it.Key(), r.Max) { - //key must bigger than max, so we must go prev - it.it.Prev() + + if !it.it.Valid() { + it.it.SeekToLast() + } else { + if !bytes.Equal(it.it.Key(), r.Max) { + it.it.Prev() + } } if r.Type&RangeROpen > 0 { @@ -87,15 +97,21 @@ func newIterator(db *DB, opts *levigo.ReadOptions, r *Range, limit int, directio } } + for i := 0; i < offset; i++ { + if it.Valid() { + it.Next() + } + } + return it } func (it *Iterator) Valid() bool { - if !it.it.Valid() { + if it.offset < 0 { return false - } - - if it.limit >= 0 && it.step >= it.limit { + } else if !it.it.Valid() { + return false + } else if it.limit >= 0 && it.step >= it.limit { return false } @@ -136,14 +152,6 @@ func (it *Iterator) Next() { } } -func (it *Iterator) Skip(offset int64) { - for i := int64(0); i < offset; i++ { - if it.Valid() { - it.Next() - } - } -} - func (it *Iterator) Key() []byte { return it.it.Key() } diff --git a/leveldb/leveldb_test.go b/leveldb/leveldb_test.go index 2fd4e14..4f478f3 100644 --- a/leveldb/leveldb_test.go +++ b/leveldb/leveldb_test.go @@ -146,52 +146,52 @@ func TestIterator(t *testing.T) { return []byte(fmt.Sprintf("key_%d", i)) } - it = db.Iterator(k(1), k(5), RangeClose, -1) + it = db.Iterator(k(1), k(5), RangeClose, 0, -1) if err := checkIterator(it, 1, 2, 3, 4, 5); err != nil { t.Fatal(err) } - it = db.Iterator(k(1), k(5), RangeClose, 3) - if err := checkIterator(it, 1, 2, 3); err != nil { + it = db.Iterator(k(1), k(5), RangeClose, 1, 3) + if err := checkIterator(it, 2, 3); err != nil { t.Fatal(err) } - it = db.Iterator(k(1), k(5), RangeLOpen, -1) + it = db.Iterator(k(1), k(5), RangeLOpen, 0, -1) if err := checkIterator(it, 2, 3, 4, 5); err != nil { t.Fatal(err) } - it = db.Iterator(k(1), k(5), RangeROpen, -1) + it = db.Iterator(k(1), k(5), RangeROpen, 0, -1) if err := checkIterator(it, 1, 2, 3, 4); err != nil { t.Fatal(err) } - it = db.Iterator(k(1), k(5), RangeOpen, -1) + it = db.Iterator(k(1), k(5), RangeOpen, 0, -1) if err := checkIterator(it, 2, 3, 4); err != nil { t.Fatal(err) } - it = db.RevIterator(k(1), k(5), RangeClose, -1) + it = db.RevIterator(k(1), k(5), RangeClose, 0, -1) if err := checkIterator(it, 5, 4, 3, 2, 1); err != nil { t.Fatal(err) } - it = db.RevIterator(k(1), k(5), RangeClose, 3) - if err := checkIterator(it, 5, 4, 3); err != nil { + it = db.RevIterator(k(1), k(5), RangeClose, 1, 3) + if err := checkIterator(it, 4, 3); err != nil { t.Fatal(err) } - it = db.RevIterator(k(1), k(5), RangeLOpen, -1) + it = db.RevIterator(k(1), k(5), RangeLOpen, 0, -1) if err := checkIterator(it, 5, 4, 3, 2); err != nil { t.Fatal(err) } - it = db.RevIterator(k(1), k(5), RangeROpen, -1) + it = db.RevIterator(k(1), k(5), RangeROpen, 0, -1) if err := checkIterator(it, 4, 3, 2, 1); err != nil { t.Fatal(err) } - it = db.RevIterator(k(1), k(5), RangeOpen, -1) + it = db.RevIterator(k(1), k(5), RangeOpen, 0, -1) if err := checkIterator(it, 4, 3, 2); err != nil { t.Fatal(err) } diff --git a/leveldb/snapshot.go b/leveldb/snapshot.go index dbbed3c..eca2041 100644 --- a/leveldb/snapshot.go +++ b/leveldb/snapshot.go @@ -37,12 +37,12 @@ func (s *Snapshot) Get(key []byte) ([]byte, error) { return s.db.db.Get(s.readOpts, key) } -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) Iterator(min []byte, max []byte, rangeType uint8, offset int, limit int) *Iterator { + return newIterator(s.db, s.iteratorOpts, NewRange(min, max, rangeType), offset, limit, IteratorForward) } -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) RevIterator(min []byte, max []byte, rangeType uint8, offset int, limit int) *Iterator { + return newIterator(s.db, s.iteratorOpts, NewRange(min, max, rangeType), offset, limit, IteratorBackward) } func (s *Snapshot) GetInt(key []byte) (int64, error) {