From 23f96f672a8e2b8afb65635dc9d221c5df7905b4 Mon Sep 17 00:00:00 2001 From: Jernej Kos Date: Sun, 16 Feb 2020 13:42:37 +0100 Subject: [PATCH] go/storage/mkvs: Make Tree an interface --- .changelog/2691.internal.1.md | 1 + go/oasis-node/cmd/debug/byzantine/executor.go | 2 +- go/runtime/transaction/transaction.go | 2 +- go/storage/api/root_cache.go | 2 +- go/storage/mkvs/urkel/checkpoint/chunk.go | 2 +- go/storage/mkvs/urkel/commit.go | 16 ++-- go/storage/mkvs/urkel/debug.go | 6 +- go/storage/mkvs/urkel/insert.go | 6 +- go/storage/mkvs/urkel/iterator.go | 12 ++- go/storage/mkvs/urkel/lookup.go | 12 +-- go/storage/mkvs/urkel/prefetch.go | 12 ++- go/storage/mkvs/urkel/remove.go | 10 +-- go/storage/mkvs/urkel/syncer_test.go | 2 +- go/storage/mkvs/urkel/tree.go | 77 +++++++++++++++++++ go/storage/mkvs/urkel/urkel.go | 53 +++++-------- go/storage/mkvs/urkel/urkel_test.go | 20 ++--- 16 files changed, 143 insertions(+), 92 deletions(-) create mode 100644 .changelog/2691.internal.1.md create mode 100644 go/storage/mkvs/urkel/tree.go diff --git a/.changelog/2691.internal.1.md b/.changelog/2691.internal.1.md new file mode 100644 index 00000000000..9c4fd6dee4c --- /dev/null +++ b/.changelog/2691.internal.1.md @@ -0,0 +1 @@ +go/storage/mkvs: Make Tree an interface diff --git a/go/oasis-node/cmd/debug/byzantine/executor.go b/go/oasis-node/cmd/debug/byzantine/executor.go index 7c35855ef4f..60f5318466d 100644 --- a/go/oasis-node/cmd/debug/byzantine/executor.go +++ b/go/oasis-node/cmd/debug/byzantine/executor.go @@ -27,7 +27,7 @@ type computeBatchContext struct { ioTree *transaction.Tree txs []*transaction.Transaction - stateTree *urkel.Tree + stateTree urkel.Tree stateWriteLog writelog.WriteLog newStateRoot hash.Hash diff --git a/go/runtime/transaction/transaction.go b/go/runtime/transaction/transaction.go index 732642f7b5f..11b103374a7 100644 --- a/go/runtime/transaction/transaction.go +++ b/go/runtime/transaction/transaction.go @@ -154,7 +154,7 @@ func (t Transaction) asOutputArtifacts() outputArtifacts { // Tree is a Merkle tree containing transaction artifacts. type Tree struct { ioRoot node.Root - tree *urkel.Tree + tree urkel.Tree } // NewTree creates a new transaction artifacts tree. diff --git a/go/storage/api/root_cache.go b/go/storage/api/root_cache.go index 6a4739c41fe..1246ec38a6f 100644 --- a/go/storage/api/root_cache.go +++ b/go/storage/api/root_cache.go @@ -29,7 +29,7 @@ type RootCache struct { // GetTree gets a tree entry from the cache by the root iff present, or creates // a new tree with the specified root in the node database. -func (rc *RootCache) GetTree(ctx context.Context, root Root) (*urkel.Tree, error) { +func (rc *RootCache) GetTree(ctx context.Context, root Root) (urkel.Tree, error) { return urkel.NewWithRoot(rc.remoteSyncer, rc.localDB, root, rc.persistEverything), nil } diff --git a/go/storage/mkvs/urkel/checkpoint/chunk.go b/go/storage/mkvs/urkel/checkpoint/chunk.go index a897e59d356..4900a9c7117 100644 --- a/go/storage/mkvs/urkel/checkpoint/chunk.go +++ b/go/storage/mkvs/urkel/checkpoint/chunk.go @@ -18,7 +18,7 @@ import ( func createChunk( ctx context.Context, - tree *urkel.Tree, + tree urkel.Tree, root node.Root, offset node.Key, chunkSize uint64, diff --git a/go/storage/mkvs/urkel/commit.go b/go/storage/mkvs/urkel/commit.go index 39d8fbf22ee..f594bd6890e 100644 --- a/go/storage/mkvs/urkel/commit.go +++ b/go/storage/mkvs/urkel/commit.go @@ -10,13 +10,8 @@ import ( "github.com/oasislabs/oasis-core/go/storage/mkvs/urkel/writelog" ) -// CommitKnown checks that the computed root matches a known root and -// if so, commits tree updates to the underlying database and returns -// the write log. -// -// In case the computed root doesn't match the known root, the update -// is NOT committed and ErrKnownRootMismatch is returned. -func (t *Tree) CommitKnown(ctx context.Context, root node.Root) (writelog.WriteLog, error) { +// Implements Tree. +func (t *tree) CommitKnown(ctx context.Context, root node.Root) (writelog.WriteLog, error) { writeLog, _, err := t.commitWithHooks(ctx, root.Namespace, root.Round, func(rootHash hash.Hash) error { if !rootHash.Equal(&root.Hash) { return ErrKnownRootMismatch @@ -27,13 +22,12 @@ func (t *Tree) CommitKnown(ctx context.Context, root node.Root) (writelog.WriteL return writeLog, err } -// Commit commits tree updates to the underlying database and returns -// the write log and new merkle root. -func (t *Tree) Commit(ctx context.Context, namespace common.Namespace, round uint64) (writelog.WriteLog, hash.Hash, error) { +// Implements Tree. +func (t *tree) Commit(ctx context.Context, namespace common.Namespace, round uint64) (writelog.WriteLog, hash.Hash, error) { return t.commitWithHooks(ctx, namespace, round, nil) } -func (t *Tree) commitWithHooks( +func (t *tree) commitWithHooks( ctx context.Context, namespace common.Namespace, round uint64, diff --git a/go/storage/mkvs/urkel/debug.go b/go/storage/mkvs/urkel/debug.go index cb8317441fc..9077f7a2897 100644 --- a/go/storage/mkvs/urkel/debug.go +++ b/go/storage/mkvs/urkel/debug.go @@ -9,12 +9,12 @@ import ( "github.com/oasislabs/oasis-core/go/storage/mkvs/urkel/node" ) -// DumpLocal dumps the tree in the local memory into the given writer. -func (t *Tree) DumpLocal(ctx context.Context, w io.Writer, maxDepth node.Depth) { +// Implements Tree. +func (t *tree) DumpLocal(ctx context.Context, w io.Writer, maxDepth node.Depth) { t.doDumpLocal(ctx, w, t.cache.pendingRoot, 0, maxDepth) } -func (t *Tree) doDumpLocal(ctx context.Context, w io.Writer, ptr *node.Pointer, depth node.Depth, maxDepth node.Depth) { +func (t *tree) doDumpLocal(ctx context.Context, w io.Writer, ptr *node.Pointer, depth node.Depth, maxDepth node.Depth) { prefix := strings.Repeat(" ", int(depth)*2) if ptr == nil { fmt.Fprint(w, prefix+"") diff --git a/go/storage/mkvs/urkel/insert.go b/go/storage/mkvs/urkel/insert.go index 79be934f53a..b332f779752 100644 --- a/go/storage/mkvs/urkel/insert.go +++ b/go/storage/mkvs/urkel/insert.go @@ -8,8 +8,8 @@ import ( "github.com/oasislabs/oasis-core/go/storage/mkvs/urkel/node" ) -// Insert inserts a key/value pair into the tree. -func (t *Tree) Insert(ctx context.Context, key []byte, value []byte) error { +// Implements Tree. +func (t *tree) Insert(ctx context.Context, key []byte, value []byte) error { t.cache.Lock() defer t.cache.Unlock() @@ -49,7 +49,7 @@ type insertResult struct { existed bool } -func (t *Tree) doInsert( +func (t *tree) doInsert( ctx context.Context, ptr *node.Pointer, bitDepth node.Depth, diff --git a/go/storage/mkvs/urkel/iterator.go b/go/storage/mkvs/urkel/iterator.go index 2f7cf8e1610..fc57e3892f1 100644 --- a/go/storage/mkvs/urkel/iterator.go +++ b/go/storage/mkvs/urkel/iterator.go @@ -11,9 +11,8 @@ import ( var errClosed = errors.New("iterator: use of closed iterator") -// SyncIterate seeks to a given key and then fetches the specified -// number of following items based on key iteration order. -func (t *Tree) SyncIterate(ctx context.Context, request *syncer.IterateRequest) (*syncer.ProofResponse, error) { +// Implements syncer.ReadSyncer. +func (t *tree) SyncIterate(ctx context.Context, request *syncer.IterateRequest) (*syncer.ProofResponse, error) { t.cache.Lock() defer t.cache.Unlock() @@ -58,7 +57,7 @@ func (t *Tree) SyncIterate(ctx context.Context, request *syncer.IterateRequest) }, nil } -func (t *Tree) newFetcherSyncIterate(key node.Key, prefetch uint16) readSyncFetcher { +func (t *tree) newFetcherSyncIterate(key node.Key, prefetch uint16) readSyncFetcher { return func(ctx context.Context, ptr *node.Pointer, rs syncer.ReadSyncer) (*syncer.Proof, error) { rsp, err := rs.SyncIterate(ctx, &syncer.IterateRequest{ Tree: syncer.TreeID{ @@ -125,7 +124,7 @@ type pathAtom struct { type treeIterator struct { ctx context.Context - tree *Tree + tree *tree prefetch uint16 err error pos []pathAtom @@ -155,8 +154,7 @@ func WithProof(root hash.Hash) IteratorOption { } } -// NewIterator creates a new iterator over the given tree. -func NewIterator(ctx context.Context, tree *Tree, options ...IteratorOption) Iterator { +func newTreeIterator(ctx context.Context, tree *tree, options ...IteratorOption) Iterator { it := &treeIterator{ ctx: ctx, tree: tree, diff --git a/go/storage/mkvs/urkel/lookup.go b/go/storage/mkvs/urkel/lookup.go index 87fdd82d3f9..834625cdee4 100644 --- a/go/storage/mkvs/urkel/lookup.go +++ b/go/storage/mkvs/urkel/lookup.go @@ -8,8 +8,8 @@ import ( "github.com/oasislabs/oasis-core/go/storage/mkvs/urkel/syncer" ) -// Get looks up an existing key. -func (t *Tree) Get(ctx context.Context, key []byte) ([]byte, error) { +// Implements Tree. +func (t *tree) Get(ctx context.Context, key []byte) ([]byte, error) { t.cache.Lock() defer t.cache.Unlock() @@ -23,8 +23,8 @@ func (t *Tree) Get(ctx context.Context, key []byte) ([]byte, error) { return t.doGet(ctx, t.cache.pendingRoot, 0, key, doGetOptions{}, false) } -// SyncGet fetches a single key and returns the corresponding proof. -func (t *Tree) SyncGet(ctx context.Context, request *syncer.GetRequest) (*syncer.ProofResponse, error) { +// Implements syncer.ReadSyncer. +func (t *tree) SyncGet(ctx context.Context, request *syncer.GetRequest) (*syncer.ProofResponse, error) { t.cache.Lock() defer t.cache.Unlock() @@ -59,7 +59,7 @@ func (t *Tree) SyncGet(ctx context.Context, request *syncer.GetRequest) (*syncer }, nil } -func (t *Tree) newFetcherSyncGet(key node.Key, includeSiblings bool) readSyncFetcher { +func (t *tree) newFetcherSyncGet(key node.Key, includeSiblings bool) readSyncFetcher { return func(ctx context.Context, ptr *node.Pointer, rs syncer.ReadSyncer) (*syncer.Proof, error) { rsp, err := rs.SyncGet(ctx, &syncer.GetRequest{ Tree: syncer.TreeID{ @@ -81,7 +81,7 @@ type doGetOptions struct { includeSiblings bool } -func (t *Tree) doGet( +func (t *tree) doGet( ctx context.Context, ptr *node.Pointer, bitDepth node.Depth, diff --git a/go/storage/mkvs/urkel/prefetch.go b/go/storage/mkvs/urkel/prefetch.go index 271e7b4da95..c5c3233b661 100644 --- a/go/storage/mkvs/urkel/prefetch.go +++ b/go/storage/mkvs/urkel/prefetch.go @@ -8,9 +8,8 @@ import ( "github.com/oasislabs/oasis-core/go/storage/mkvs/urkel/syncer" ) -// PrefetchPrefixes populates the in-memory tree with nodes for keys -// starting with given prefixes. -func (t *Tree) PrefetchPrefixes(ctx context.Context, prefixes [][]byte, limit uint16) error { +// Implements Tree. +func (t *tree) PrefetchPrefixes(ctx context.Context, prefixes [][]byte, limit uint16) error { t.cache.Lock() defer t.cache.Unlock() @@ -25,7 +24,7 @@ func (t *Tree) PrefetchPrefixes(ctx context.Context, prefixes [][]byte, limit ui return t.doPrefetchPrefixes(ctx, prefixes, limit) } -func (t *Tree) doPrefetchPrefixes(ctx context.Context, prefixes [][]byte, limit uint16) error { +func (t *tree) doPrefetchPrefixes(ctx context.Context, prefixes [][]byte, limit uint16) error { // TODO: Can we avoid fetching items that we already have? return t.cache.remoteSync( @@ -48,9 +47,8 @@ func (t *Tree) doPrefetchPrefixes(ctx context.Context, prefixes [][]byte, limit ) } -// SyncGetPrefixes fetches all keys under the given prefixes and returns -// the corresponding proofs. -func (t *Tree) SyncGetPrefixes(ctx context.Context, request *syncer.GetPrefixesRequest) (*syncer.ProofResponse, error) { +// Implements syncer.ReadSyncer. +func (t *tree) SyncGetPrefixes(ctx context.Context, request *syncer.GetPrefixesRequest) (*syncer.ProofResponse, error) { t.cache.Lock() defer t.cache.Unlock() diff --git a/go/storage/mkvs/urkel/remove.go b/go/storage/mkvs/urkel/remove.go index 79f77444365..7fde091cfb3 100644 --- a/go/storage/mkvs/urkel/remove.go +++ b/go/storage/mkvs/urkel/remove.go @@ -7,8 +7,8 @@ import ( "github.com/oasislabs/oasis-core/go/storage/mkvs/urkel/node" ) -// RemoveExisting removes a key from the tree and returns the previous value. -func (t *Tree) RemoveExisting(ctx context.Context, key []byte) ([]byte, error) { +// Implements Tree. +func (t *tree) RemoveExisting(ctx context.Context, key []byte) ([]byte, error) { t.cache.Lock() defer t.cache.Unlock() @@ -36,13 +36,13 @@ func (t *Tree) RemoveExisting(ctx context.Context, key []byte) ([]byte, error) { return existing, nil } -// Remove removes a key from the tree. -func (t *Tree) Remove(ctx context.Context, key []byte) error { +// Implements Tree. +func (t *tree) Remove(ctx context.Context, key []byte) error { _, err := t.RemoveExisting(ctx, key) return err } -func (t *Tree) doRemove( +func (t *tree) doRemove( ctx context.Context, ptr *node.Pointer, bitDepth node.Depth, diff --git a/go/storage/mkvs/urkel/syncer_test.go b/go/storage/mkvs/urkel/syncer_test.go index a6eed340707..199b92a6429 100644 --- a/go/storage/mkvs/urkel/syncer_test.go +++ b/go/storage/mkvs/urkel/syncer_test.go @@ -22,7 +22,7 @@ func TestProof(t *testing.T) { keys, values := generateKeyValuePairsEx("", 10) var ns common.Namespace - tree := New(nil, nil) + tree := New(nil, nil).(*tree) for i, key := range keys { err := tree.Insert(ctx, key, values[i]) require.NoError(err, "Insert") diff --git a/go/storage/mkvs/urkel/tree.go b/go/storage/mkvs/urkel/tree.go new file mode 100644 index 00000000000..b757b047eae --- /dev/null +++ b/go/storage/mkvs/urkel/tree.go @@ -0,0 +1,77 @@ +package urkel + +import ( + "context" + "errors" + "io" + + "github.com/oasislabs/oasis-core/go/common" + "github.com/oasislabs/oasis-core/go/common/crypto/hash" + "github.com/oasislabs/oasis-core/go/storage/mkvs/urkel/node" + "github.com/oasislabs/oasis-core/go/storage/mkvs/urkel/syncer" + "github.com/oasislabs/oasis-core/go/storage/mkvs/urkel/writelog" +) + +var ( + // ErrClosed is the error returned when methods are used after Close is called. + ErrClosed = errors.New("urkel: tree is closed") + + // ErrKnownRootMismatch is the error returned by CommitKnown when the known + // root mismatches. + ErrKnownRootMismatch = errors.New("urkel: known root mismatch") +) + +// Tree is a MKVS tree interface. +type Tree interface { + syncer.ReadSyncer + + // Insert inserts a key/value pair into the tree. + Insert(ctx context.Context, key []byte, value []byte) error + + // Get looks up an existing key. + Get(ctx context.Context, key []byte) ([]byte, error) + + // PrefetchPrefixes populates the in-memory tree with nodes for keys + // starting with given prefixes. + PrefetchPrefixes(ctx context.Context, prefixes [][]byte, limit uint16) error + + // RemoveExisting removes a key from the tree and returns the previous value. + RemoveExisting(ctx context.Context, key []byte) ([]byte, error) + + // Remove removes a key from the tree. + Remove(ctx context.Context, key []byte) error + + // NewIterator returns a new iterator over the tree. + NewIterator(ctx context.Context, options ...IteratorOption) Iterator + + // ApplyWriteLog applies the operations from a write log to the current tree. + // + // The caller is responsible for calling Commit. + ApplyWriteLog(ctx context.Context, wl writelog.Iterator) error + + // Close releases resources associated with this tree. After calling this + // method the tree MUST NOT be used anymore and all methods will return + // the ErrClosed error. + // + // Any pending write operations are discarded. If you need to persist them + // you need to call Commit before calling this method. + Close() + + // Size calculates the size of the tree in bytes. + Size() uint64 + + // CommitKnown checks that the computed root matches a known root and + // if so, commits tree updates to the underlying database and returns + // the write log. + // + // In case the computed root doesn't match the known root, the update + // is NOT committed and ErrKnownRootMismatch is returned. + CommitKnown(ctx context.Context, root node.Root) (writelog.WriteLog, error) + + // Commit commits tree updates to the underlying database and returns + // the write log and new merkle root. + Commit(ctx context.Context, namespace common.Namespace, round uint64) (writelog.WriteLog, hash.Hash, error) + + // DumpLocal dumps the tree in the local memory into the given writer. + DumpLocal(ctx context.Context, w io.Writer, maxDepth node.Depth) +} diff --git a/go/storage/mkvs/urkel/urkel.go b/go/storage/mkvs/urkel/urkel.go index 5ccbc0e5bad..2791ef089e4 100644 --- a/go/storage/mkvs/urkel/urkel.go +++ b/go/storage/mkvs/urkel/urkel.go @@ -3,7 +3,6 @@ package urkel import ( "context" - "errors" db "github.com/oasislabs/oasis-core/go/storage/mkvs/urkel/db/api" "github.com/oasislabs/oasis-core/go/storage/mkvs/urkel/node" @@ -11,18 +10,9 @@ import ( "github.com/oasislabs/oasis-core/go/storage/mkvs/urkel/writelog" ) -var ( - // ErrClosed is the error returned when methods are used after Close is called. - ErrClosed = errors.New("urkel: tree is closed") - // ErrKnownRootMismatch is the error returned by CommitKnown when the known - // root mismatches. - ErrKnownRootMismatch = errors.New("urkel: known root mismatch") +var _ Tree = (*tree)(nil) - _ syncer.ReadSyncer = (*Tree)(nil) -) - -// Tree is an Urkel tree. -type Tree struct { +type tree struct { cache *cache // NOTE: This can be a map as updates are commutative. @@ -42,7 +32,7 @@ type pendingEntry struct { } // Option is a configuration option used when instantiating the tree. -type Option func(t *Tree) +type Option func(t *tree) // Capacity sets the capacity of the in-memory cache. // @@ -52,7 +42,7 @@ type Option func(t *Tree) // If a capacity of 0 is specified, the cache will have an unlimited size // (not recommended, as this will cause unbounded memory growth). func Capacity(nodeCapacity uint64, valueCapacityBytes uint64) Option { - return func(t *Tree) { + return func(t *tree) { t.cache.nodeCapacity = nodeCapacity t.cache.valueCapacity = valueCapacityBytes } @@ -63,13 +53,13 @@ func Capacity(nodeCapacity uint64, valueCapacityBytes uint64) Option { // // If not specified, the default is false. func PersistEverythingFromSyncer(doit bool) Option { - return func(t *Tree) { + return func(t *tree) { t.cache.persistEverythingFromSyncer = doit } } // New creates a new empty Urkel tree backed by the given node database. -func New(rs syncer.ReadSyncer, ndb db.NodeDB, options ...Option) *Tree { +func New(rs syncer.ReadSyncer, ndb db.NodeDB, options ...Option) Tree { if rs == nil { rs = syncer.NopReadSyncer } @@ -77,7 +67,7 @@ func New(rs syncer.ReadSyncer, ndb db.NodeDB, options ...Option) *Tree { ndb, _ = db.NewNopNodeDB() } - t := &Tree{ + t := &tree{ cache: newCache(ndb, rs), pendingWriteLog: make(map[string]*pendingEntry), } @@ -91,8 +81,8 @@ func New(rs syncer.ReadSyncer, ndb db.NodeDB, options ...Option) *Tree { // NewWithRoot creates a new Urkel tree with an existing root, backed by // the given node database. -func NewWithRoot(rs syncer.ReadSyncer, ndb db.NodeDB, root node.Root, options ...Option) *Tree { - t := New(rs, ndb, options...) +func NewWithRoot(rs syncer.ReadSyncer, ndb db.NodeDB, root node.Root, options ...Option) Tree { + t := New(rs, ndb, options...).(*tree) t.cache.setPendingRoot(&node.Pointer{ Clean: true, Hash: root.Hash, @@ -101,15 +91,13 @@ func NewWithRoot(rs syncer.ReadSyncer, ndb db.NodeDB, root node.Root, options .. return t } -// NewIterator returns a new iterator over the tree. -func (t *Tree) NewIterator(ctx context.Context, options ...IteratorOption) Iterator { - return NewIterator(ctx, t, options...) +// Implements Tree. +func (t *tree) NewIterator(ctx context.Context, options ...IteratorOption) Iterator { + return newTreeIterator(ctx, t, options...) } -// ApplyWriteLog applies the operations from a write log to the current tree. -// -// The caller is responsible for calling Commit. -func (t *Tree) ApplyWriteLog(ctx context.Context, wl writelog.Iterator) error { +// Implements Tree. +func (t *tree) ApplyWriteLog(ctx context.Context, wl writelog.Iterator) error { for { // Fetch next entry from write log iterator. more, err := wl.Next() @@ -137,13 +125,8 @@ func (t *Tree) ApplyWriteLog(ctx context.Context, wl writelog.Iterator) error { return nil } -// Close releases resources associated with this tree. After calling this -// method the tree MUST NOT be used anymore and all methods will return -// the ErrClosed error. -// -// Any pending write operations are discarded. If you need to persist them -// you need to call Commit before calling this method. -func (t *Tree) Close() { +// Implements Tree. +func (t *tree) Close() { t.cache.Lock() defer t.cache.Unlock() @@ -151,7 +134,7 @@ func (t *Tree) Close() { t.pendingWriteLog = nil } -// Size calculates the size of the tree in bytes. -func (t *Tree) Size() uint64 { +// Implements Tree. +func (t *tree) Size() uint64 { return t.cache.valueSize + t.cache.internalNodeCount*node.InternalNodeSize } diff --git a/go/storage/mkvs/urkel/urkel_test.go b/go/storage/mkvs/urkel/urkel_test.go index fa1e0a1a008..d56fb0d47d1 100644 --- a/go/storage/mkvs/urkel/urkel_test.go +++ b/go/storage/mkvs/urkel/urkel_test.go @@ -311,7 +311,7 @@ func testEmptyKeys(t *testing.T, ndb db.NodeDB) { ctx := context.Background() tree := New(nil, ndb) - testEmptyKeyInsert := func(t *testing.T, ctx context.Context, tree *Tree) { + testEmptyKeyInsert := func(t *testing.T, ctx context.Context, tree Tree) { emptyKey := node.Key("") emptyValue := []byte("empty value") @@ -323,7 +323,7 @@ func testEmptyKeys(t *testing.T, ndb db.NodeDB) { require.Equal(t, emptyValue, value, "empty value after insert") } - testEmptyKeyRemove := func(t *testing.T, ctx context.Context, tree *Tree) { + testEmptyKeyRemove := func(t *testing.T, ctx context.Context, tree Tree) { emptyKey := node.Key("") err := tree.Remove(ctx, emptyKey) @@ -334,7 +334,7 @@ func testEmptyKeys(t *testing.T, ndb db.NodeDB) { require.Equal(t, []byte(nil), value, "empty value after remove") } - testZerothDiscriminatorBitInsert := func(t *testing.T, ctx context.Context, tree *Tree) { + testZerothDiscriminatorBitInsert := func(t *testing.T, ctx context.Context, tree Tree) { key1 := node.Key{0x7f, 0xab} key2 := node.Key{0xff, 0xab} value1 := []byte("value 1") @@ -354,7 +354,7 @@ func testEmptyKeys(t *testing.T, ndb db.NodeDB) { require.Equal(t, value2, value, "empty value after insert") } - testZerothDiscriminatorBitRemove := func(t *testing.T, ctx context.Context, tree *Tree) { + testZerothDiscriminatorBitRemove := func(t *testing.T, ctx context.Context, tree Tree) { key1 := node.Key{0x7f, 0xab} key2 := node.Key{0xff, 0xab} @@ -636,7 +636,7 @@ func testSyncerRootEmptyLabelNeedsDeref(t *testing.T, ndb db.NodeDB) { Hash: rootHash, } - testGet := func(t *testing.T, tree *Tree) { + testGet := func(t *testing.T, tree Tree) { value, err := tree.Get(ctx, []byte{0xFF}) require.NoError(t, err, "Get") require.EqualValues(t, value, []byte("foo")) @@ -645,13 +645,13 @@ func testSyncerRootEmptyLabelNeedsDeref(t *testing.T, ndb db.NodeDB) { require.NoError(t, err, "Get") require.EqualValues(t, value, []byte("bar")) } - testRemove := func(t *testing.T, tree *Tree) { + testRemove := func(t *testing.T, tree Tree) { err := tree.Remove(ctx, []byte{0xFF}) require.NoError(t, err, "Remove") err = tree.Remove(ctx, []byte{0x00}) require.NoError(t, err, "Remove") } - testInsert := func(t *testing.T, tree *Tree) { + testInsert := func(t *testing.T, tree Tree) { err := tree.Insert(ctx, []byte{0xFF, 0xFF}, []byte("foo")) require.NoError(t, err, "Insert") err = tree.Insert(ctx, []byte{0x00, 0x00}, []byte("bar")) @@ -809,7 +809,7 @@ func testSyncerPrefetchPrefixes(t *testing.T, ndb db.NodeDB) { func testValueEviction(t *testing.T, ndb db.NodeDB) { ctx := context.Background() - tree := New(nil, ndb, Capacity(0, 512)) + tree := New(nil, ndb, Capacity(0, 512)).(*tree) keys, values := generateKeyValuePairs() for i := 0; i < len(keys); i++ { @@ -827,7 +827,7 @@ func testValueEviction(t *testing.T, ndb db.NodeDB) { func testNodeEviction(t *testing.T, ndb db.NodeDB) { ctx := context.Background() - tree := New(nil, ndb, Capacity(128, 0)) + tree := New(nil, ndb, Capacity(128, 0)).(*tree) keys, values := generateKeyValuePairsEx("foo", 150) for i := 0; i < len(keys); i++ { @@ -1989,7 +1989,7 @@ func generateLongKeyValuePairs() ([][]byte, [][]byte) { return keys, values } -func generatePopulatedTree(t *testing.T, ndb db.NodeDB) ([][]byte, [][]byte, node.Root, *Tree) { +func generatePopulatedTree(t *testing.T, ndb db.NodeDB) ([][]byte, [][]byte, node.Root, Tree) { ctx := context.Background() tree := New(nil, ndb, Capacity(0, 0))