iterator add offset and limit, reviterator bug fix

This commit is contained in:
siddontang 2014-05-07 22:53:24 +08:00
parent 8994b2aabd
commit af4507fc51
4 changed files with 49 additions and 39 deletions

View File

@ -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 {

View File

@ -39,6 +39,7 @@ type Iterator struct {
r *Range
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,10 +80,14 @@ 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
if !it.it.Valid() {
it.it.SeekToLast()
} else {
if !bytes.Equal(it.it.Key(), r.Max) {
it.it.Prev()
}
}
if r.Type&RangeROpen > 0 {
if it.Valid() && bytes.Equal(it.Key(), r.Max) {
@ -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()
}

View File

@ -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)
}

View File

@ -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) {