diff --git a/cmd/chai/commands/pebble.go b/cmd/chai/commands/pebble.go index fbcb5c31..c0f14779 100644 --- a/cmd/chai/commands/pebble.go +++ b/cmd/chai/commands/pebble.go @@ -2,6 +2,7 @@ package commands import ( "github.com/chaisql/chai/cmd/chai/dbutil" + "github.com/chaisql/chai/internal/kv" "github.com/urfave/cli/v2" ) @@ -35,7 +36,8 @@ func NewPebbleCommand() *cli.Command { } defer db.Close() - return dbutil.DumpPebble(c.Context, db.DB.Store.DB(), dbutil.DumpPebbleOptions{ + ng := db.DB.Engine.(*kv.PebbleEngine) + return dbutil.DumpPebble(c.Context, ng.DB(), dbutil.DumpPebbleOptions{ KeysOnly: c.Bool("keys-only"), }) } diff --git a/internal/database/database.go b/internal/database/database.go index f4877e5d..a8c12833 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -6,6 +6,7 @@ import ( "sync/atomic" "time" + "github.com/chaisql/chai/internal/engine" "github.com/chaisql/chai/internal/kv" "github.com/cockroachdb/errors" ) @@ -41,7 +42,7 @@ type Database struct { closeOnce sync.Once // Underlying kv store. - Store *kv.Store + Engine engine.Engine } // Options are passed to Open to control @@ -54,7 +55,7 @@ type Options struct { // It may parse a SQL representation of the catalog // and return a Catalog that represents all entities stored on disk. type CatalogLoader interface { - LoadCatalog(kv.Session) (*Catalog, error) + LoadCatalog(engine.Session) (*Catalog, error) } // TxOptions are passed to Begin to configure transactions. @@ -78,18 +79,18 @@ func Open(path string, opts *Options) (*Database, error) { } db := Database{ - Store: store, + Engine: store, } // ensure the rollback segment doesn't contain any data that needs to be rolled back // due to a previous crash. - err = db.Store.ResetRollbackSegment() + err = db.Engine.Recover() if err != nil { return nil, err } // clean up the transient namespaces - err = db.Store.CleanupTransientNamespaces() + err = db.Engine.CleanupTransientNamespaces() if err != nil { return nil, err } @@ -167,7 +168,7 @@ func (db *Database) closeDatabase() error { return err } - return db.Store.Close() + return db.Engine.Close() } // GetAttachedTx returns the transaction attached to the database. It returns nil if there is no @@ -222,16 +223,16 @@ func (db *Database) beginTx(opts *TxOptions) (*Transaction, error) { opts = &TxOptions{} } - var sess kv.Session + var sess engine.Session if opts.ReadOnly { - sess = db.Store.NewSnapshotSession() + sess = db.Engine.NewSnapshotSession() } else { - sess = db.Store.NewBatchSession() + sess = db.Engine.NewBatchSession() } tx := Transaction{ db: db, - Store: db.Store, + Engine: db.Engine, Session: sess, Writable: !opts.ReadOnly, ID: atomic.AddUint64(&db.TransactionIDs, 1), diff --git a/internal/database/index.go b/internal/database/index.go index 923347c8..5eb81a43 100644 --- a/internal/database/index.go +++ b/internal/database/index.go @@ -4,7 +4,7 @@ import ( "bytes" "fmt" - "github.com/chaisql/chai/internal/kv" + "github.com/chaisql/chai/internal/engine" "github.com/chaisql/chai/internal/tree" "github.com/chaisql/chai/internal/types" "github.com/cockroachdb/errors" @@ -122,7 +122,7 @@ func (idx *Index) Delete(vs []types.Value, key []byte) error { return err } - return errors.WithStack(kv.ErrKeyNotFound) + return errors.WithStack(engine.ErrKeyNotFound) } func (idx *Index) IterateOnRange(rng *tree.Range, reverse bool, fn func(key *tree.Key) error) error { diff --git a/internal/database/table.go b/internal/database/table.go index 2ca44aa4..9477b13a 100644 --- a/internal/database/table.go +++ b/internal/database/table.go @@ -3,8 +3,8 @@ package database import ( "fmt" + "github.com/chaisql/chai/internal/engine" errs "github.com/chaisql/chai/internal/errors" - "github.com/chaisql/chai/internal/kv" "github.com/chaisql/chai/internal/object" "github.com/chaisql/chai/internal/tree" "github.com/chaisql/chai/internal/types" @@ -55,7 +55,7 @@ func (t *Table) Insert(o types.Object) (*tree.Key, Row, error) { err = t.Tree.Put(key, enc) } if err != nil { - if errors.Is(err, kv.ErrKeyAlreadyExists) { + if errors.Is(err, engine.ErrKeyAlreadyExists) { return nil, nil, &ConstraintViolationError{ Constraint: "PRIMARY KEY", Paths: t.Info.PrimaryKey.Paths, @@ -95,7 +95,7 @@ func (t *Table) Delete(key *tree.Key) error { } err := t.Tree.Delete(key) - if errors.Is(err, kv.ErrKeyNotFound) { + if errors.Is(err, engine.ErrKeyNotFound) { return errors.WithStack(errs.NewNotFoundError(key.String())) } @@ -178,7 +178,7 @@ func (t *Table) IterateOnRange(rng *Range, reverse bool, fn func(key *tree.Key, func (t *Table) GetRow(key *tree.Key) (Row, error) { enc, err := t.Tree.Get(key) if err != nil { - if errors.Is(err, kv.ErrKeyNotFound) { + if errors.Is(err, engine.ErrKeyNotFound) { return nil, errors.WithStack(errs.NewNotFoundError(key.String())) } return nil, fmt.Errorf("failed to fetch row %q: %w", key, err) diff --git a/internal/database/transaction.go b/internal/database/transaction.go index 5c681446..82f73873 100644 --- a/internal/database/transaction.go +++ b/internal/database/transaction.go @@ -4,7 +4,7 @@ import ( "sync" "time" - "github.com/chaisql/chai/internal/kv" + "github.com/chaisql/chai/internal/engine" "github.com/cockroachdb/errors" ) @@ -19,8 +19,8 @@ type Transaction struct { // The timestamp must use the local timezone. TxStart time.Time - Session kv.Session - Store *kv.Store + Session engine.Session + Engine engine.Engine ID uint64 Writable bool WriteTxMu *sync.Mutex @@ -41,7 +41,7 @@ func (tx *Transaction) Rollback() error { } if tx.Writable { - err = tx.Store.Rollback() + err = tx.Engine.Rollback() if err != nil { return err } diff --git a/internal/engine/engine.go b/internal/engine/engine.go new file mode 100644 index 00000000..86ee9856 --- /dev/null +++ b/internal/engine/engine.go @@ -0,0 +1,66 @@ +package engine + +import "github.com/cockroachdb/errors" + +// Common errors returned by the engine. +var ( + // ErrKeyNotFound is returned when the targeted key doesn't exist. + ErrKeyNotFound = errors.New("key not found") + + // ErrKeyAlreadyExists is returned when the targeted key already exists. + ErrKeyAlreadyExists = errors.New("key already exists") +) + +type Engine interface { + Close() error + Rollback() error + Recover() error + LockSharedSnapshot() + UnlockSharedSnapshot() + CleanupTransientNamespaces() error + NewSnapshotSession() Session + NewBatchSession() Session + NewTransientSession() Session +} + +type Session interface { + Commit() error + Close() error + // Insert inserts a key-value pair. If it already exists, it returns ErrKeyAlreadyExists. + Insert(k, v []byte) error + // Put stores a key-value pair. If it already exists, it overrides it. + Put(k, v []byte) error + // Get returns a value associated with the given key. If not found, returns ErrKeyNotFound. + Get(k []byte) ([]byte, error) + // Exists returns whether a key exists and is visible by the current session. + Exists(k []byte) (bool, error) + // Delete a record by key. If not found, returns ErrKeyNotFound. + Delete(k []byte) error + DeleteRange(start []byte, end []byte) error + Iterator(opts *IterOptions) (Iterator, error) +} + +type Iterator interface { + Close() error + First() bool + Last() bool + Valid() bool + Next() bool + Prev() bool + Error() error + Key() []byte + Value() ([]byte, error) +} + +type IterOptions struct { + // LowerBound specifies the smallest key (inclusive) that the iterator will + // return during iteration. If the iterator is seeked or iterated past this + // boundary the iterator will return Valid()==false. Setting LowerBound + // effectively truncates the key space visible to the iterator. + LowerBound []byte + // UpperBound specifies the largest key (exclusive) that the iterator will + // return during iteration. If the iterator is seeked or iterated past this + // boundary the iterator will return Valid()==false. Setting UpperBound + // effectively truncates the key space visible to the iterator. + UpperBound []byte +} diff --git a/internal/kv/batch.go b/internal/kv/batch.go index 7ec5647d..24ffb6eb 100644 --- a/internal/kv/batch.go +++ b/internal/kv/batch.go @@ -1,18 +1,19 @@ package kv import ( + "github.com/chaisql/chai/internal/engine" "github.com/cockroachdb/errors" "github.com/cockroachdb/pebble" ) -var _ Session = (*BatchSession)(nil) +var _ engine.Session = (*BatchSession)(nil) var ( tombStone = []byte{0} ) type BatchSession struct { - Store *Store + Store *PebbleEngine DB *pebble.DB Batch *pebble.Batch closed bool @@ -21,7 +22,7 @@ type BatchSession struct { keys map[string]struct{} } -func (s *Store) NewBatchSession() *BatchSession { +func (s *PebbleEngine) NewBatchSession() engine.Session { // before creating a batch session, create a shared snapshot // at this point-in-time. s.LockSharedSnapshot() @@ -142,7 +143,7 @@ func (s *BatchSession) Insert(k, v []byte) error { return err } if ok { - return ErrKeyAlreadyExists + return engine.ErrKeyAlreadyExists } s.keys[string(k)] = struct{}{} @@ -190,7 +191,7 @@ func (s *BatchSession) Delete(k []byte) error { // DeleteRange deletes all keys in the given range. // This implementation deletes all keys one by one to simplify the rollback. func (s *BatchSession) DeleteRange(start []byte, end []byte) error { - it, err := s.Iterator(&IterOptions{ + it, err := s.Iterator(&engine.IterOptions{ LowerBound: start, UpperBound: end, }) @@ -209,7 +210,7 @@ func (s *BatchSession) DeleteRange(start []byte, end []byte) error { return nil } -func (s *BatchSession) Iterator(opts *IterOptions) (Iterator, error) { +func (s *BatchSession) Iterator(opts *engine.IterOptions) (engine.Iterator, error) { err := s.applyBatch() if err != nil { return nil, err diff --git a/internal/kv/store.go b/internal/kv/engine.go similarity index 87% rename from internal/kv/store.go rename to internal/kv/engine.go index 4156adb9..aa37b265 100644 --- a/internal/kv/store.go +++ b/internal/kv/engine.go @@ -20,7 +20,7 @@ const ( defaultMaxTransientBatchSize int = 1 << 19 // 512KB ) -type Store struct { +type PebbleEngine struct { db *pebble.DB opts Options rollbackSegment *RollbackSegment @@ -47,7 +47,7 @@ type Options struct { MaxTransientNamespace uint64 } -func NewEngineWith(path string, opts Options, popts *pebble.Options) (*Store, error) { +func NewEngineWith(path string, opts Options, popts *pebble.Options) (*PebbleEngine, error) { if popts == nil { popts = &pebble.Options{} } @@ -68,7 +68,7 @@ func NewEngineWith(path string, opts Options, popts *pebble.Options) (*Store, er return NewStore(db, opts), nil } -func NewEngine(path string, opts Options) (*Store, error) { +func NewEngine(path string, opts Options) (*PebbleEngine, error) { var popts pebble.Options var pbpath string @@ -116,7 +116,7 @@ var DefaultComparer = &pebble.Comparer{ Name: "leveldb.BytewiseComparator", } -func NewStore(db *pebble.DB, opts Options) *Store { +func NewStore(db *pebble.DB, opts Options) *PebbleEngine { if opts.MaxBatchSize <= 0 { opts.MaxBatchSize = defaultMaxBatchSize } @@ -130,26 +130,26 @@ func NewStore(db *pebble.DB, opts Options) *Store { panic("max transient namespace cannot be 0") } - return &Store{ + return &PebbleEngine{ db: db, opts: opts, rollbackSegment: NewRollbackSegment(db, opts.RollbackSegmentNamespace), } } -func (s *Store) Close() error { +func (s *PebbleEngine) Close() error { return s.db.Close() } -func (s *Store) Rollback() error { +func (s *PebbleEngine) Rollback() error { return s.rollbackSegment.Rollback() } -func (s *Store) ResetRollbackSegment() error { +func (s *PebbleEngine) Recover() error { return s.rollbackSegment.Reset() } -func (s *Store) LockSharedSnapshot() { +func (s *PebbleEngine) LockSharedSnapshot() { s.sharedSnapshot.Lock() s.sharedSnapshot.snapshot = &snapshot{ snapshot: s.db.NewSnapshot(), @@ -159,18 +159,18 @@ func (s *Store) LockSharedSnapshot() { s.sharedSnapshot.Unlock() } -func (s *Store) UnlockSharedSnapshot() { +func (s *PebbleEngine) UnlockSharedSnapshot() { s.sharedSnapshot.Lock() s.sharedSnapshot.snapshot.Done() s.sharedSnapshot.snapshot = nil s.sharedSnapshot.Unlock() } -func (s *Store) DB() *pebble.DB { +func (s *PebbleEngine) DB() *pebble.DB { return s.db } -func (s *Store) CleanupTransientNamespaces() error { +func (s *PebbleEngine) CleanupTransientNamespaces() error { return s.db.DeleteRange( encoding.EncodeUint(nil, uint64(s.minTransientNamespace)), encoding.EncodeUint(nil, uint64(s.maxTransientNamespace)), diff --git a/internal/kv/session.go b/internal/kv/session.go index 4bcf1eda..895e20a7 100644 --- a/internal/kv/session.go +++ b/internal/kv/session.go @@ -1,61 +1,11 @@ package kv import ( + "github.com/chaisql/chai/internal/engine" "github.com/cockroachdb/errors" "github.com/cockroachdb/pebble" ) -// Common errors returned by the engine. -var ( - // ErrKeyNotFound is returned when the targeted key doesn't exist. - ErrKeyNotFound = errors.New("key not found") - - // ErrKeyAlreadyExists is returned when the targeted key already exists. - ErrKeyAlreadyExists = errors.New("key already exists") -) - -type Session interface { - Commit() error - Close() error - // Insert inserts a key-value pair. If it already exists, it returns ErrKeyAlreadyExists. - Insert(k, v []byte) error - // Put stores a key-value pair. If it already exists, it overrides it. - Put(k, v []byte) error - // Get returns a value associated with the given key. If not found, returns ErrKeyNotFound. - Get(k []byte) ([]byte, error) - // Exists returns whether a key exists and is visible by the current session. - Exists(k []byte) (bool, error) - // Delete a record by key. If not found, returns ErrKeyNotFound. - Delete(k []byte) error - DeleteRange(start []byte, end []byte) error - Iterator(opts *IterOptions) (Iterator, error) -} - -type Iterator interface { - Close() error - First() bool - Last() bool - Valid() bool - Next() bool - Prev() bool - Error() error - Key() []byte - Value() ([]byte, error) -} - -type IterOptions struct { - // LowerBound specifies the smallest key (inclusive) that the iterator will - // return during iteration. If the iterator is seeked or iterated past this - // boundary the iterator will return Valid()==false. Setting LowerBound - // effectively truncates the key space visible to the iterator. - LowerBound []byte - // UpperBound specifies the largest key (exclusive) that the iterator will - // return during iteration. If the iterator is seeked or iterated past this - // boundary the iterator will return Valid()==false. Setting UpperBound - // effectively truncates the key space visible to the iterator. - UpperBound []byte -} - type iterator struct { *pebble.Iterator } @@ -69,7 +19,7 @@ func get(r pebble.Reader, k []byte) ([]byte, error) { value, closer, err := r.Get(k) if err != nil { if errors.Is(err, pebble.ErrNotFound) { - return nil, errors.WithStack(ErrKeyNotFound) + return nil, errors.WithStack(engine.ErrKeyNotFound) } return nil, err diff --git a/internal/kv/session_test.go b/internal/kv/session_test.go index e6a4b839..60ba3be9 100644 --- a/internal/kv/session_test.go +++ b/internal/kv/session_test.go @@ -7,13 +7,13 @@ import ( "github.com/chaisql/chai" "github.com/chaisql/chai/internal/encoding" - "github.com/chaisql/chai/internal/kv" + "github.com/chaisql/chai/internal/engine" "github.com/chaisql/chai/internal/testutil" "github.com/chaisql/chai/internal/testutil/assert" "github.com/stretchr/testify/require" ) -func getValue(t *testing.T, st kv.Session, key []byte) []byte { +func getValue(t *testing.T, st engine.Session, key []byte) []byte { v, err := st.Get([]byte(key)) assert.NoError(t, err) return v @@ -44,7 +44,7 @@ func TestReadOnly(t *testing.T) { }) } -func kvBuilder(t testing.TB) kv.Session { +func kvBuilder(t testing.TB) engine.Session { ng := testutil.NewEngine(t) s := ng.NewBatchSession() @@ -121,7 +121,7 @@ func TestRollback(t *testing.T) { for i := int64(9); i >= 0; i-- { key := encoding.EncodeInt(encoding.EncodeInt(nil, 10), i) _, err = snapshot.Get(key) - require.ErrorIs(t, err, kv.ErrKeyNotFound) + require.ErrorIs(t, err, engine.ErrKeyNotFound) } } @@ -181,7 +181,7 @@ func TestStoreGet(t *testing.T) { st := kvBuilder(t) r, err := st.Get(foo) - assert.ErrorIs(t, err, kv.ErrKeyNotFound) + assert.ErrorIs(t, err, engine.ErrKeyNotFound) require.Nil(t, r) }) diff --git a/internal/kv/snapshot.go b/internal/kv/snapshot.go index a61535ca..717e6fc5 100644 --- a/internal/kv/snapshot.go +++ b/internal/kv/snapshot.go @@ -3,6 +3,7 @@ package kv import ( "math" + "github.com/chaisql/chai/internal/engine" "github.com/chaisql/chai/internal/pkg/atomic" "github.com/cockroachdb/errors" "github.com/cockroachdb/pebble" @@ -25,14 +26,14 @@ func (s *snapshot) Done() error { } type SnapshotSession struct { - Store *Store + Store *PebbleEngine Snapshot *snapshot closed bool } -var _ Session = (*SnapshotSession)(nil) +var _ engine.Session = (*SnapshotSession)(nil) -func (s *Store) NewSnapshotSession() *SnapshotSession { +func (s *PebbleEngine) NewSnapshotSession() engine.Session { var sn *snapshot // if there is a shared snapshot, use it. @@ -96,7 +97,7 @@ func (s *SnapshotSession) DeleteRange(start []byte, end []byte) error { return errors.New("cannot delete range in read-only mode") } -func (s *SnapshotSession) Iterator(opts *IterOptions) (Iterator, error) { +func (s *SnapshotSession) Iterator(opts *engine.IterOptions) (engine.Iterator, error) { var popts *pebble.IterOptions if opts != nil { popts = &pebble.IterOptions{ diff --git a/internal/kv/transient.go b/internal/kv/transient.go index 7ae038d0..ae32c8b6 100644 --- a/internal/kv/transient.go +++ b/internal/kv/transient.go @@ -1,21 +1,22 @@ package kv import ( + "github.com/chaisql/chai/internal/engine" "github.com/cockroachdb/errors" "github.com/cockroachdb/pebble" ) -var _ Session = (*TransientSession)(nil) +var _ engine.Session = (*TransientSession)(nil) type TransientSession struct { db *pebble.DB batch *pebble.Batch - store *Store + store *PebbleEngine maxBatchSize int closed bool } -func (s *Store) NewTransientSession() *TransientSession { +func (s *PebbleEngine) NewTransientSession() engine.Session { return &TransientSession{ db: s.db, maxBatchSize: s.opts.MaxTransientBatchSize, @@ -69,7 +70,7 @@ func (s *TransientSession) Put(k, v []byte) error { // Get returns a value associated with the given key. If not found, returns ErrKeyNotFound. func (s *TransientSession) Get(k []byte) ([]byte, error) { if s.batch == nil { - return nil, errors.WithStack(ErrKeyNotFound) + return nil, errors.WithStack(engine.ErrKeyNotFound) } return get(s.batch, k) @@ -87,13 +88,13 @@ func (s *TransientSession) Exists(k []byte) (bool, error) { // Delete a record by key. If not found, returns ErrKeyNotFound. func (s *TransientSession) Delete(k []byte) error { if s.batch == nil { - return errors.WithStack(ErrKeyNotFound) + return errors.WithStack(engine.ErrKeyNotFound) } _, closer, err := s.batch.Get(k) if err != nil { if errors.Is(err, pebble.ErrNotFound) { - return errors.WithStack(ErrKeyNotFound) + return errors.WithStack(engine.ErrKeyNotFound) } return err @@ -114,7 +115,7 @@ func (s *TransientSession) DeleteRange(start []byte, end []byte) error { return s.batch.DeleteRange(start, end, nil) } -func (s *TransientSession) Iterator(opts *IterOptions) (Iterator, error) { +func (s *TransientSession) Iterator(opts *engine.IterOptions) (engine.Iterator, error) { var popts *pebble.IterOptions if opts != nil { popts = &pebble.IterOptions{ diff --git a/internal/stream/rows/temp_tree_sort.go b/internal/stream/rows/temp_tree_sort.go index c0841b6d..37cf497a 100644 --- a/internal/stream/rows/temp_tree_sort.go +++ b/internal/stream/rows/temp_tree_sort.go @@ -36,7 +36,7 @@ func (op *TempTreeSortOperator) Iterate(in *environment.Environment, fn func(out catalog := in.GetTx().Catalog tns := catalog.GetFreeTransientNamespace() - tr, cleanup, err := tree.NewTransient(db.Store.NewTransientSession(), tns, 0) + tr, cleanup, err := tree.NewTransient(db.Engine.NewTransientSession(), tns, 0) if err != nil { return err } diff --git a/internal/stream/union.go b/internal/stream/union.go index cf812360..eb99b8ff 100644 --- a/internal/stream/union.go +++ b/internal/stream/union.go @@ -56,7 +56,7 @@ func (it *UnionOperator) Iterate(in *environment.Environment, fn func(out *envir // create a temporary tree db := in.GetDB() tns := in.GetTx().Catalog.GetFreeTransientNamespace() - temp, cleanup, err = tree.NewTransient(db.Store.NewTransientSession(), tns, 0) + temp, cleanup, err = tree.NewTransient(db.Engine.NewTransientSession(), tns, 0) if err != nil { return err } diff --git a/internal/testutil/db.go b/internal/testutil/db.go index 49693d72..ea899af1 100644 --- a/internal/testutil/db.go +++ b/internal/testutil/db.go @@ -16,7 +16,7 @@ import ( "github.com/stretchr/testify/require" ) -func NewEngine(t testing.TB) *kv.Store { +func NewEngine(t testing.TB) *kv.PebbleEngine { t.Helper() st, err := kv.NewEngine(":memory:", kv.Options{ diff --git a/internal/tree/tree.go b/internal/tree/tree.go index 3b68028e..95f986dc 100644 --- a/internal/tree/tree.go +++ b/internal/tree/tree.go @@ -6,7 +6,7 @@ import ( "time" "github.com/chaisql/chai/internal/encoding" - "github.com/chaisql/chai/internal/kv" + "github.com/chaisql/chai/internal/engine" "github.com/chaisql/chai/internal/types" "github.com/cockroachdb/errors" ) @@ -58,12 +58,12 @@ func (o SortOrder) SetAsc(i int) SortOrder { // of the types package operators. // A Tree doesn't support duplicate keys. type Tree struct { - Session kv.Session + Session engine.Session Namespace Namespace Order SortOrder } -func New(session kv.Session, ns Namespace, order SortOrder) *Tree { +func New(session engine.Session, ns Namespace, order SortOrder) *Tree { return &Tree{ Namespace: ns, Session: session, @@ -71,7 +71,7 @@ func New(session kv.Session, ns Namespace, order SortOrder) *Tree { } } -func NewTransient(session kv.Session, ns Namespace, order SortOrder) (*Tree, func() error, error) { +func NewTransient(session engine.Session, ns Namespace, order SortOrder) (*Tree, func() error, error) { t := Tree{ Namespace: ns, Session: session, @@ -92,7 +92,7 @@ func NewTransient(session kv.Session, ns Namespace, order SortOrder) (*Tree, fun var defaultValue = []byte{0} // Insert adds a key-obj combination to the tree. -// If the key already exists, it returns kv.ErrKeyAlreadyExists. +// If the key already exists, it returns engine.ErrKeyAlreadyExists. func (t *Tree) Insert(key *Key, value []byte) error { if len(value) == 0 { value = defaultValue @@ -121,7 +121,7 @@ func (t *Tree) Put(key *Key, value []byte) error { } // Get a key from the tree. If the key doesn't exist, -// it returns kv.ErrKeyNotFound. +// it returns engine.ErrKeyNotFound. func (t *Tree) Get(key *Key) ([]byte, error) { k, err := key.Encode(t.Namespace, t.Order) if err != nil { @@ -142,7 +142,7 @@ func (t *Tree) Exists(key *Key) (bool, error) { } // Delete a key from the tree. If the key doesn't exist, -// it returns kv.ErrKeyNotFound. +// it returns engine.ErrKeyNotFound. func (t *Tree) Delete(key *Key) error { k, err := key.Encode(t.Namespace, t.Order) if err != nil { @@ -183,7 +183,7 @@ func (t *Tree) IterateOnRange(rng *Range, reverse bool, fn func(*Key, []byte) er return err } - opts := kv.IterOptions{ + opts := engine.IterOptions{ LowerBound: start, UpperBound: end, }