Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Seek and Prev to Iterator interface #11

Merged
merged 1 commit into from
Dec 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions engines/leveldb/iter.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ type ldbIterator struct {
// Type check for the ldbIterator
var _ honuiter.Iterator = &ldbIterator{}

func (i *ldbIterator) Next() bool { return i.ldb.Next() }
func (i *ldbIterator) Prev() bool { return i.ldb.Prev() }
func (i *ldbIterator) Error() error { return i.ldb.Error() }
func (i *ldbIterator) Release() { i.ldb.Release() }
func (i *ldbIterator) Next() bool { return i.ldb.Next() }
func (i *ldbIterator) Prev() bool { return i.ldb.Prev() }
func (i *ldbIterator) Seek(key []byte) bool { return i.ldb.Seek(key) }
func (i *ldbIterator) Error() error { return i.ldb.Error() }
func (i *ldbIterator) Release() { i.ldb.Release() }

func (i *ldbIterator) Key() []byte {
// Fetch the key then split the namespace from the key
Expand Down
1 change: 1 addition & 0 deletions iterator/empty.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func (i *emptyIterator) rErr() {

func (i *emptyIterator) Next() bool { i.rErr(); return false }
func (i *emptyIterator) Prev() bool { i.rErr(); return false }
func (i *emptyIterator) Seek(key []byte) bool { i.rErr(); return false }
func (*emptyIterator) Key() []byte { return nil }
func (*emptyIterator) Value() []byte { return nil }
func (*emptyIterator) Object() (*pb.Object, error) { return nil, nil }
Expand Down
57 changes: 57 additions & 0 deletions iterator/empty_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package iterator_test

import (
"errors"
"testing"

. "github.com/rotationalio/honu/iterator"
"github.com/stretchr/testify/require"
)

func TestEmptyIterator(t *testing.T) {
// Check that the empty iterator returns expected values
iter := NewEmptyIterator(nil)
require.False(t, iter.Next())
require.False(t, iter.Prev())
require.False(t, iter.Seek([]byte("foo")))
require.Nil(t, iter.Key())
require.Nil(t, iter.Value())
require.NoError(t, iter.Error())

obj, err := iter.Object()
require.NoError(t, err)
require.Nil(t, obj)

// After calling release the empty iterator should still have no error
iter.Release()
require.NoError(t, iter.Error())

// However if next is called after release, then the iterator should error
require.False(t, iter.Next())
require.EqualError(t, iter.Error(), ErrIterReleased.Error())

// Check that the empty iterator can be initialized with an error
iter = NewEmptyIterator(errors.New("something bad happened"))
require.EqualError(t, iter.Error(), "something bad happened")

// Ensure that calling any of the iterator methods do not change the error
require.False(t, iter.Next())
require.False(t, iter.Prev())
require.False(t, iter.Seek([]byte("foo")))
require.Nil(t, iter.Key())
require.Nil(t, iter.Value())

obj, err = iter.Object()
require.NoError(t, err)
require.Nil(t, obj)

require.EqualError(t, iter.Error(), "something bad happened")

// Ensure calling Release doesn't change the error
iter.Release()
require.EqualError(t, iter.Error(), "something bad happened")

// Ensure calling Next after Release doesn't change the error
iter.Next()
require.EqualError(t, iter.Error(), "something bad happened")
}
8 changes: 8 additions & 0 deletions iterator/iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ type Iterator interface {
// It returns false if the iterator has been exhausted.
Next() bool

// Prev moves the iterator to the previous key/value pair or row.
// It returns false if the iterator has been exhausted.
Prev() bool

// Error returns any accumulated error. Exhausting all rows or key/value pairs is
// not considered to be an error.
Error() error
Expand All @@ -52,4 +56,8 @@ type Iterator interface {
// iterator. Release can be called multiple times without error but after it has
// been called, no Iterator methods will return data.
Release()

// Seek moves the iterator to the first key/value pair whose key is greater than or
// equal to the given key. It returns whether such pair exists.
Seek(key []byte) bool
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like this is equivalent to pebble's SeekGE.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a relief - I'm hoping Badger also has something similar!

}