diff --git a/basic_test.go b/basic_test.go index 13996c7..228809c 100644 --- a/basic_test.go +++ b/basic_test.go @@ -42,7 +42,7 @@ func TestBasic(t *testing.T) { key := []byte{0x00} expected := "" - idx, val, err := tree.GetWithIndex(key) + idx, val, err := tree.ImmutableTree().GetWithIndex(key) require.NoError(t, err) if val != nil { t.Error("Expected no value to exist") @@ -68,7 +68,7 @@ func TestBasic(t *testing.T) { key := []byte("1") expected := "one" - idx, val, err := tree.GetWithIndex(key) + idx, val, err := tree.ImmutableTree().GetWithIndex(key) require.NoError(t, err) if val == nil { t.Error("Expected value to exist") @@ -95,7 +95,7 @@ func TestBasic(t *testing.T) { key := []byte("2") expected := "TWO" - idx, val, err := tree.GetWithIndex(key) + idx, val, err := tree.ImmutableTree().GetWithIndex(key) require.NoError(t, err) if val == nil { t.Error("Expected value to exist") @@ -121,7 +121,7 @@ func TestBasic(t *testing.T) { key := []byte("4") expected := "" - idx, val, err := tree.GetWithIndex(key) + idx, val, err := tree.ImmutableTree().GetWithIndex(key) require.NoError(t, err) if val != nil { t.Error("Expected no value to exist") @@ -147,7 +147,7 @@ func TestBasic(t *testing.T) { key := []byte("6") expected := "" - idx, val, err := tree.GetWithIndex(key) + idx, val, err := tree.ImmutableTree().GetWithIndex(key) require.NoError(t, err) if val != nil { t.Error("Expected no value to exist") @@ -192,31 +192,31 @@ func TestUnit(t *testing.T) { } expectSet := func(tree *MutableTree, i int, repr string, hashCount int64) { - origNode := tree.root + origNode := tree.ImmutableTree().root updated, err := tree.Set(i2b(i), []byte{}) require.NoError(t, err) // ensure node was added & structure is as expected. - if updated || P(tree.root) != repr { + if updated || P(tree.ImmutableTree().root) != repr { t.Fatalf("Adding %v to %v:\nExpected %v\nUnexpectedly got %v updated:%v", - i, P(origNode), repr, P(tree.root), updated) + i, P(origNode), repr, P(tree.ImmutableTree().root), updated) } // ensure hash calculation requirements - expectHash(tree.ImmutableTree, hashCount) - tree.root = origNode + expectHash(tree.ImmutableTree(), hashCount) + tree.ImmutableTree().root = origNode } expectRemove := func(tree *MutableTree, i int, repr string, hashCount int64) { - origNode := tree.root + origNode := tree.ImmutableTree().root value, removed, err := tree.Remove(i2b(i)) require.NoError(t, err) // ensure node was added & structure is as expected. - if len(value) != 0 || !removed || P(tree.root) != repr { + if len(value) != 0 || !removed || P(tree.ImmutableTree().root) != repr { t.Fatalf("Removing %v from %v:\nExpected %v\nUnexpectedly got %v value:%v removed:%v", - i, P(origNode), repr, P(tree.root), value, removed) + i, P(origNode), repr, P(tree.ImmutableTree().root), value, removed) } // ensure hash calculation requirements - expectHash(tree.ImmutableTree, hashCount) - tree.root = origNode + expectHash(tree.ImmutableTree(), hashCount) + tree.ImmutableTree().root = origNode } // Test Set cases: @@ -317,8 +317,8 @@ func TestIntegration(t *testing.T) { if !updated { t.Error("should have been updated") } - if tree.Size() != int64(i+1) { - t.Error("size was wrong", tree.Size(), i+1) + if tree.ImmutableTree().Size() != int64(i+1) { + t.Error("size was wrong", tree.ImmutableTree().Size(), i+1) } } @@ -370,8 +370,8 @@ func TestIntegration(t *testing.T) { t.Error("wrong value") } } - if tree.Size() != int64(len(records)-(i+1)) { - t.Error("size was wrong", tree.Size(), (len(records) - (i + 1))) + if tree.ImmutableTree().Size() != int64(len(records)-(i+1)) { + t.Error("size was wrong", tree.ImmutableTree().Size(), (len(records) - (i + 1))) } } } @@ -427,38 +427,38 @@ func TestIterateRange(t *testing.T) { } trav := traverser{} - tree.IterateRange([]byte("foo"), []byte("goo"), true, trav.view) + tree.ImmutableTree().IterateRange([]byte("foo"), []byte("goo"), true, trav.view) expectTraverse(t, trav, "foo", "food", 5) trav = traverser{} - tree.IterateRange([]byte("aaa"), []byte("abb"), true, trav.view) + tree.ImmutableTree().IterateRange([]byte("aaa"), []byte("abb"), true, trav.view) expectTraverse(t, trav, "", "", 0) trav = traverser{} - tree.IterateRange(nil, []byte("flap"), true, trav.view) + tree.ImmutableTree().IterateRange(nil, []byte("flap"), true, trav.view) expectTraverse(t, trav, "abc", "fan", 2) trav = traverser{} - tree.IterateRange([]byte("foob"), nil, true, trav.view) + tree.ImmutableTree().IterateRange([]byte("foob"), nil, true, trav.view) expectTraverse(t, trav, "foobang", "low", 6) trav = traverser{} - tree.IterateRange([]byte("very"), nil, true, trav.view) + tree.ImmutableTree().IterateRange([]byte("very"), nil, true, trav.view) expectTraverse(t, trav, "", "", 0) // make sure it doesn't include end trav = traverser{} - tree.IterateRange([]byte("fooba"), []byte("food"), true, trav.view) + tree.ImmutableTree().IterateRange([]byte("fooba"), []byte("food"), true, trav.view) expectTraverse(t, trav, "foobang", "foobaz", 3) // make sure backwards also works... (doesn't include end) trav = traverser{} - tree.IterateRange([]byte("fooba"), []byte("food"), false, trav.view) + tree.ImmutableTree().IterateRange([]byte("fooba"), []byte("food"), false, trav.view) expectTraverse(t, trav, "foobaz", "foobang", 3) // make sure backwards also works... trav = traverser{} - tree.IterateRange([]byte("g"), nil, false, trav.view) + tree.ImmutableTree().IterateRange([]byte("g"), nil, false, trav.view) expectTraverse(t, trav, "low", "good", 2) } @@ -513,7 +513,7 @@ func TestProof(t *testing.T) { // Now for each item, construct a proof and verify tree.Iterate(func(key []byte, value []byte) bool { - value2, proof, err := tree.GetWithProof(key) + value2, proof, err := tree.ImmutableTree().GetWithProof(key) assert.NoError(t, err) assert.Equal(t, value, value2) if assert.NotNil(t, proof) { @@ -534,7 +534,7 @@ func TestTreeProof(t *testing.T) { assert.Equal(t, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", hex.EncodeToString(hash)) // should get false for proof with nil root - value, proof, err := tree.GetWithProof([]byte("foo")) + value, proof, err := tree.ImmutableTree().GetWithProof([]byte("foo")) assert.Nil(t, value) assert.Nil(t, proof) assert.Error(t, proof.Verify([]byte(nil))) @@ -551,7 +551,7 @@ func TestTreeProof(t *testing.T) { tree.SaveVersion() // query random key fails - value, proof, err = tree.GetWithProof([]byte("foo")) + value, proof, err = tree.ImmutableTree().GetWithProof([]byte("foo")) assert.Nil(t, value) assert.NotNil(t, proof) assert.NoError(t, err) @@ -564,7 +564,7 @@ func TestTreeProof(t *testing.T) { root, err := tree.WorkingHash() assert.NoError(t, err) for _, key := range keys { - value, proof, err := tree.GetWithProof(key) + value, proof, err := tree.ImmutableTree().GetWithProof(key) if assert.NoError(t, err) { require.Nil(t, err, "Failed to read proof from bytes: %v", err) assert.Equal(t, key, value) diff --git a/benchmarks/bench_test.go b/benchmarks/bench_test.go index f845c02..a388281 100644 --- a/benchmarks/bench_test.go +++ b/benchmarks/bench_test.go @@ -58,7 +58,7 @@ func commitTree(b *testing.B, t *iavl.MutableTree) { // queries random keys against live state. Keys are almost certainly not in the tree. func runQueriesFast(b *testing.B, t *iavl.MutableTree, keyLen int) { - isFastCacheEnabled, err := t.IsFastCacheEnabled() + isFastCacheEnabled, err := t.ImmutableTree().IsFastCacheEnabled() require.NoError(b, err) require.True(b, isFastCacheEnabled) for i := 0; i < b.N; i++ { @@ -69,7 +69,7 @@ func runQueriesFast(b *testing.B, t *iavl.MutableTree, keyLen int) { // queries keys that are known to be in state func runKnownQueriesFast(b *testing.B, t *iavl.MutableTree, keys [][]byte) { - isFastCacheEnabled, err := t.IsFastCacheEnabled() // to ensure fast storage is enabled + isFastCacheEnabled, err := t.ImmutableTree().IsFastCacheEnabled() // to ensure fast storage is enabled require.NoError(b, err) require.True(b, isFastCacheEnabled) l := int32(len(keys)) @@ -123,11 +123,11 @@ func runKnownQueriesSlow(b *testing.B, t *iavl.MutableTree, keys [][]byte) { } func runIterationFast(b *testing.B, t *iavl.MutableTree, expectedSize int) { - isFastCacheEnabled, err := t.IsFastCacheEnabled() + isFastCacheEnabled, err := t.ImmutableTree().IsFastCacheEnabled() require.NoError(b, err) require.True(b, isFastCacheEnabled) // to ensure fast storage is enabled for i := 0; i < b.N; i++ { - itr, err := t.ImmutableTree.Iterator(nil, nil, false) + itr, err := t.ImmutableTree().Iterator(nil, nil, false) require.NoError(b, err) iterate(b, itr, expectedSize) require.Nil(b, itr.Close(), ".Close should not error out") @@ -136,7 +136,7 @@ func runIterationFast(b *testing.B, t *iavl.MutableTree, expectedSize int) { func runIterationSlow(b *testing.B, t *iavl.MutableTree, expectedSize int) { for i := 0; i < b.N; i++ { - itr := iavl.NewIterator(nil, nil, false, t.ImmutableTree) // create slow iterator directly + itr := iavl.NewIterator(nil, nil, false, t.ImmutableTree()) // create slow iterator directly iterate(b, itr, expectedSize) require.Nil(b, itr.Close(), ".Close should not error out") } diff --git a/cmd/iaviewer/main.go b/cmd/iaviewer/main.go index d674a8b..471fd85 100644 --- a/cmd/iaviewer/main.go +++ b/cmd/iaviewer/main.go @@ -49,7 +49,7 @@ func main() { fmt.Fprintf(os.Stderr, "Error hashing tree: %s\n", err) os.Exit(1) } - fmt.Printf("Tree hash is %X, tree size is %X\n", treeHash, tree.Size()) + fmt.Printf("Tree hash is %X, tree size is %X\n", treeHash, tree.ImmutableTree().Size()) switch args[0] { case "data": @@ -60,7 +60,7 @@ func main() { os.Exit(1) } fmt.Printf("Hash: %X\n", hash) - fmt.Printf("Size: %X\n", tree.Size()) + fmt.Printf("Size: %X\n", tree.ImmutableTree().Size()) case "shape": PrintShape(tree) case "versions": @@ -181,7 +181,7 @@ func encodeID(id []byte) string { func PrintShape(tree *iavl.MutableTree) { // shape := tree.RenderShape(" ", nil) //TODO: handle this error - shape, _ := tree.RenderShape(" ", nodeEncoder) + shape, _ := tree.ImmutableTree().RenderShape(" ", nodeEncoder) fmt.Println(strings.Join(shape, "\n")) } diff --git a/export_test.go b/export_test.go index 8b7051f..f75effc 100644 --- a/export_test.go +++ b/export_test.go @@ -102,7 +102,7 @@ func setupExportTreeRandom(t *testing.T) *ImmutableTree { } require.EqualValues(t, versions, tree.Version()) - require.GreaterOrEqual(t, tree.Size(), int64(math.Trunc(versions*versionOps*(1-updateRatio-deleteRatio))/2)) + require.GreaterOrEqual(t, tree.ImmutableTree().Size(), int64(math.Trunc(versions*versionOps*(1-updateRatio-deleteRatio))/2)) itree, err := tree.GetImmutable(version) require.NoError(t, err) @@ -216,13 +216,13 @@ func TestExporter_Import(t *testing.T) { require.NoError(t, err) require.Equal(t, treeHash, newTreeHash, "Tree hash mismatch") - require.Equal(t, tree.Size(), newTree.Size(), "Tree size mismatch") + require.Equal(t, tree.Size(), newTree.ImmutableTree().Size(), "Tree size mismatch") require.Equal(t, tree.Version(), newTree.Version(), "Tree version mismatch") tree.Iterate(func(key, value []byte) bool { index, _, err := tree.GetWithIndex(key) require.NoError(t, err) - newIndex, newValue, err := newTree.GetWithIndex(key) + newIndex, newValue, err := newTree.ImmutableTree().GetWithIndex(key) require.NoError(t, err) require.Equal(t, index, newIndex, "Index mismatch for key %v", key) require.Equal(t, value, newValue, "Value mismatch for key %v", key) diff --git a/mutable_tree.go b/mutable_tree.go index 293090b..2675441 100644 --- a/mutable_tree.go +++ b/mutable_tree.go @@ -28,7 +28,7 @@ var ErrVersionDoesNotExist = errors.New("version does not exist") // // The inner ImmutableTree should not be used directly by callers. type MutableTree struct { - *ImmutableTree // The current, working tree. + immutableTree *ImmutableTree // The current, working tree. lastSaved *ImmutableTree // The most recently saved tree. orphans map[string]int64 // Nodes removed by changes to working tree. versions map[int64]bool // The previous, saved versions of the tree. @@ -40,7 +40,7 @@ type MutableTree struct { separateOrphanStorage bool separateOrphanVersionsToKeep int64 orphandb *orphanDB - mtx *sync.Mutex + mtx *sync.RWMutex } // NewMutableTree returns a new tree with the specified cache size and datastore. @@ -62,7 +62,7 @@ func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastSto } return &MutableTree{ - ImmutableTree: head, + immutableTree: head, lastSaved: head.clone(), orphans: map[string]int64{}, versions: map[int64]bool{}, @@ -74,16 +74,30 @@ func NewMutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastSto separateOrphanStorage: opts.SeparateOrphanStorage, separateOrphanVersionsToKeep: opts.SeparateOphanVersionsToKeep, orphandb: orphandb, - mtx: &sync.Mutex{}, + mtx: &sync.RWMutex{}, }, nil } +func (tree *MutableTree) ImmutableTree() *ImmutableTree { + tree.mtx.RLock() + defer tree.mtx.RUnlock() + return tree.immutableTree +} + +func (tree *MutableTree) LastSaved() *ImmutableTree { + tree.mtx.RLock() + defer tree.mtx.RUnlock() + return tree.lastSaved +} + +func (tree *MutableTree) Has(key []byte) (bool, error) { + return tree.ImmutableTree().Has(key) +} + // IsEmpty returns whether or not the tree has any keys. Only trees that are // not empty can be saved. func (tree *MutableTree) IsEmpty() bool { - tree.mtx.Lock() - defer tree.mtx.Unlock() - return tree.ImmutableTree.Size() == 0 + return tree.ImmutableTree().Size() == 0 } // VersionExists returns whether or not a version exists. @@ -122,12 +136,12 @@ func (tree *MutableTree) AvailableVersions() []int { // Hash returns the hash of the latest saved version of the tree, as returned // by SaveVersion. If no versions have been saved, Hash returns nil. func (tree *MutableTree) Hash() ([]byte, error) { - return tree.lastSaved.Hash() + return tree.LastSaved().Hash() } // WorkingHash returns the hash of the current working tree. func (tree *MutableTree) WorkingHash() ([]byte, error) { - return tree.ImmutableTree.Hash() + return tree.ImmutableTree().Hash() } // String returns a string representation of the tree. @@ -138,7 +152,7 @@ func (tree *MutableTree) String() (string, error) { // Set/Remove will orphan at most tree.Height nodes, // balancing the tree after a Set/Remove will orphan at most 3 nodes. func (tree *MutableTree) prepareOrphansSlice() []*Node { - return make([]*Node, 0, tree.Height()+3) + return make([]*Node, 0, tree.immutableTree.Height()+3) } // Set sets a key in the working tree. Nil values are invalid. The given @@ -163,12 +177,12 @@ func (tree *MutableTree) Set(key, value []byte) (updated bool, err error) { // Get returns the value of the specified key if it exists, or nil otherwise. // The returned value must not be modified, since it may point to data stored within IAVL. func (tree *MutableTree) Get(key []byte) ([]byte, error) { - tree.mtx.Lock() - defer tree.mtx.Unlock() - if tree.root == nil { + if tree.ImmutableTree().root == nil { return nil, nil } + tree.mtx.RLock() + defer tree.mtx.RUnlock() if !tree.skipFastStorageUpgrade { if fastNode, ok := tree.unsavedFastNodeAdditions[unsafeToStr(key)]; ok { return fastNode.value, nil @@ -179,7 +193,8 @@ func (tree *MutableTree) Get(key []byte) ([]byte, error) { } } - return tree.ImmutableTree.Get(key) + // mtx is already acquired + return tree.immutableTree.Get(key) } // Import returns an importer for tree nodes previously exported by ImmutableTree.Export(), @@ -197,20 +212,20 @@ func (tree *MutableTree) Import(version int64) (*Importer, error) { // Iterate iterates over all keys of the tree. The keys and values must not be modified, // since they may point to data stored within IAVL. Returns true if stopped by callnack, false otherwise func (tree *MutableTree) Iterate(fn func(key []byte, value []byte) bool) (stopped bool, err error) { - if tree.root == nil { + if tree.ImmutableTree().root == nil { return false, nil } if tree.skipFastStorageUpgrade { - return tree.ImmutableTree.Iterate(fn) + return tree.ImmutableTree().Iterate(fn) } - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() if err != nil { return false, err } if !isFastCacheEnabled { - return tree.ImmutableTree.Iterate(fn) + return tree.ImmutableTree().Iterate(fn) } itr := NewUnsavedFastIterator(nil, nil, true, tree.ndb, tree.unsavedFastNodeAdditions, tree.unsavedFastNodeRemovals) @@ -227,7 +242,7 @@ func (tree *MutableTree) Iterate(fn func(key []byte, value []byte) bool) (stoppe // CONTRACT: no updates are made to the tree while an iterator is active. func (tree *MutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterator, error) { if !tree.skipFastStorageUpgrade { - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() if err != nil { return nil, err } @@ -237,31 +252,33 @@ func (tree *MutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterat } } - return tree.ImmutableTree.Iterator(start, end, ascending) + return tree.ImmutableTree().Iterator(start, end, ascending) } +// no need to acquire mtx since it's only called by `Set` which already holds the mtx func (tree *MutableTree) set(key []byte, value []byte) (orphans []*Node, updated bool, err error) { if value == nil { return nil, updated, fmt.Errorf("attempt to store nil value at key '%s'", key) } - if tree.ImmutableTree.root == nil { + if tree.immutableTree.root == nil { if !tree.skipFastStorageUpgrade { - tree.addUnsavedAddition(key, NewFastNode(key, value, tree.version+1)) + tree.addUnsavedAddition(key, NewFastNode(key, value, tree.immutableTree.version+1)) } - tree.ImmutableTree.root = NewNode(key, value, tree.version+1) + tree.immutableTree.root = NewNode(key, value, tree.immutableTree.version+1) return nil, updated, nil } orphans = tree.prepareOrphansSlice() - tree.ImmutableTree.root, updated, err = tree.recursiveSet(tree.ImmutableTree.root, key, value, &orphans) + tree.immutableTree.root, updated, err = tree.recursiveSet(tree.immutableTree.root, key, value, &orphans) return orphans, updated, err } +// no need to acquire mtx since it's only called by `set` which already holds the mtx func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orphans *[]*Node) ( newSelf *Node, updated bool, err error, ) { - version := tree.version + 1 + version := tree.immutableTree.version + 1 if node.isLeaf() { if !tree.skipFastStorageUpgrade { @@ -299,7 +316,7 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph } if bytes.Compare(key, node.GetNodeKey()) < 0 { - leftNode, err := node.getLeftNode(tree.ImmutableTree) + leftNode, err := node.getLeftNode(tree.immutableTree) if err != nil { return nil, false, err } @@ -311,7 +328,7 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph node.SetLeftNode(lNode) node.SetLeftHash(nil) // leftHash is yet unknown } else { - rightNode, err := node.getRightNode(tree.ImmutableTree) + rightNode, err := node.getRightNode(tree.immutableTree) if err != nil { return nil, false, err } @@ -327,7 +344,7 @@ func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte, orph if updated { return node, updated, nil } - err = node.calcHeightAndSize(tree.ImmutableTree) + err = node.calcHeightAndSize(tree.immutableTree) if err != nil { return nil, false, err } @@ -359,12 +376,13 @@ func (tree *MutableTree) Remove(key []byte) ([]byte, bool, error) { // remove tries to remove a key from the tree and if removed, returns its // value, nodes orphaned and 'true'. +// no need to acquire mtx since it's only called by `Remove` which already holds the mtx. func (tree *MutableTree) remove(key []byte) (value []byte, orphaned []*Node, removed bool, err error) { - if tree.root == nil { + if tree.immutableTree.root == nil { return nil, nil, false, nil } orphaned = tree.prepareOrphansSlice() - newRootHash, newRoot, _, value, err := tree.recursiveRemove(tree.root, key, &orphaned) + newRootHash, newRoot, _, value, err := tree.recursiveRemove(tree.immutableTree.root, key, &orphaned) if err != nil { return nil, nil, false, err } @@ -377,12 +395,12 @@ func (tree *MutableTree) remove(key []byte) (value []byte, orphaned []*Node, rem } if newRoot == nil && newRootHash != nil { - tree.root, err = tree.ndb.GetNode(newRootHash) + tree.immutableTree.root, err = tree.ndb.GetNode(newRootHash) if err != nil { return nil, nil, false, err } } else { - tree.root = newRoot + tree.immutableTree.root = newRoot } return value, orphaned, true, nil } @@ -394,8 +412,9 @@ func (tree *MutableTree) remove(key []byte) (value []byte, orphaned []*Node, rem // - new leftmost leaf key for tree after successfully removing 'key' if changed. // - the removed value // - the orphaned nodes. +// no need to acquire mtx since it's only called by `remove` which already holds the mtx func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Node) (newHash []byte, newSelf *Node, newKey []byte, newValue []byte, err error) { - version := tree.version + 1 + version := tree.immutableTree.version + 1 if node.isLeaf() { if bytes.Equal(key, node.GetNodeKey()) { @@ -407,7 +426,7 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod // node.key < key; we go to the left to find the key: if bytes.Compare(key, node.GetNodeKey()) < 0 { - leftNode, err := node.getLeftNode(tree.ImmutableTree) + leftNode, err := node.getLeftNode(tree.immutableTree) if err != nil { return nil, nil, nil, nil, err } @@ -431,7 +450,7 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod newNode.SetLeftHash(newLeftHash) newNode.SetLeftNode(newLeftNode) - err = newNode.calcHeightAndSize(tree.ImmutableTree) + err = newNode.calcHeightAndSize(tree.immutableTree) if err != nil { return nil, nil, nil, nil, err } @@ -443,7 +462,7 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod return newNode.GetHash(), newNode, newKey, value, nil } // node.key >= key; either found or look to the right: - rightNode, err := node.getRightNode(tree.ImmutableTree) + rightNode, err := node.getRightNode(tree.immutableTree) if err != nil { return nil, nil, nil, nil, err } @@ -469,7 +488,7 @@ func (tree *MutableTree) recursiveRemove(node *Node, key []byte, orphans *[]*Nod if newKey != nil { newNode.SetKey(newKey) } - err = newNode.calcHeightAndSize(tree.ImmutableTree) + err = newNode.calcHeightAndSize(tree.immutableTree) if err != nil { return nil, nil, nil, nil, err } @@ -507,8 +526,6 @@ func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (toReturn int64, t if latestVersion <= 0 { if targetVersion <= 0 { if !tree.skipFastStorageUpgrade { - tree.mtx.Lock() - defer tree.mtx.Unlock() _, err := tree.enableFastStorageAndCommitIfNotEnabled() return 0, err } @@ -559,7 +576,7 @@ func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (toReturn int64, t } tree.orphans = map[string]int64{} - tree.ImmutableTree = iTree + tree.immutableTree = iTree // mtx is already held tree.lastSaved = iTree.clone() return targetVersion, nil @@ -634,7 +651,7 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (toReturn int64, toErr } tree.orphans = map[string]int64{} - tree.ImmutableTree = t + tree.immutableTree = t // mtx is already held tree.lastSaved = t.clone() tree.allRootLoaded = true @@ -732,12 +749,13 @@ func (tree *MutableTree) enableFastStorageAndCommitIfNotEnabled() (bool, error) func (tree *MutableTree) enableFastStorageAndCommit() error { var err error - itr := NewIteratorUnlocked(nil, nil, true, tree.ImmutableTree) + itr := NewIteratorUnlocked(nil, nil, true, tree.ImmutableTree()) defer itr.Close() + version := tree.ImmutableTree().version var upgradedFastNodes uint64 for ; itr.Valid(); itr.Next() { upgradedFastNodes++ - if err = tree.ndb.SaveFastNodeNoCache(NewFastNode(itr.Key(), itr.Value(), tree.version)); err != nil { + if err = tree.ndb.SaveFastNodeNoCache(NewFastNode(itr.Key(), itr.Value(), version)); err != nil { return err } if upgradedFastNodes%commitGap == 0 { @@ -794,10 +812,12 @@ func (tree *MutableTree) GetImmutable(version int64) (*ImmutableTree, error) { // Rollback resets the working tree to the latest saved version, discarding // any unsaved modifications. func (tree *MutableTree) Rollback() { - if tree.version > 0 { - tree.ImmutableTree = tree.lastSaved.clone() + tree.mtx.Lock() + defer tree.mtx.Unlock() + if tree.immutableTree.version > 0 { + tree.immutableTree = tree.lastSaved.clone() } else { - tree.ImmutableTree = &ImmutableTree{ + tree.immutableTree = &ImmutableTree{ ndb: tree.ndb, version: 0, skipFastStorageUpgrade: tree.skipFastStorageUpgrade, @@ -815,7 +835,7 @@ func (tree *MutableTree) Rollback() { func (tree *MutableTree) GetVersioned(key []byte, version int64) ([]byte, error) { if tree.VersionExists(version) { if !tree.skipFastStorageUpgrade { - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() if err != nil { return nil, err } @@ -849,7 +869,7 @@ func (tree *MutableTree) GetVersioned(key []byte, version int64) ([]byte, error) // the hash being saved is different. In // other words, only SaveVersion can insert new node into the tree. func (tree *MutableTree) SaveCurrentVersion() ([]byte, int64, error) { - version := tree.version + version := tree.ImmutableTree().version if version == 1 && tree.ndb.opts.InitialVersion > 0 { version = int64(tree.ndb.opts.InitialVersion) } @@ -875,12 +895,15 @@ func (tree *MutableTree) SaveCurrentVersion() ([]byte, int64, error) { } if bytes.Equal(existingHash, newHash) { + tree.mtx.Lock() + defer tree.mtx.Unlock() if v, err := tree.commitVersion(version, true); err != nil { return nil, v, err } - tree.version = version - tree.ImmutableTree = tree.ImmutableTree.clone() - tree.lastSaved = tree.ImmutableTree.clone() + clone := tree.immutableTree.clone() + clone.version = version + tree.immutableTree = clone + tree.lastSaved = clone.clone() tree.orphans = map[string]int64{} return existingHash, version, nil } @@ -891,14 +914,12 @@ func (tree *MutableTree) SaveCurrentVersion() ([]byte, int64, error) { // SaveVersion saves a new tree version to disk, based on the current state of // the tree. Returns the hash and new version number. func (tree *MutableTree) SaveVersion() ([]byte, int64, error) { - version := tree.version + 1 + version := tree.ImmutableTree().version + 1 if version == 1 && tree.ndb.opts.InitialVersion > 0 { version = int64(tree.ndb.opts.InitialVersion) } if tree.VersionExists(version) { - tree.mtx.Lock() - defer tree.mtx.Unlock() // If the version already exists, return an error as we're attempting to overwrite. // However, the same hash means idempotent (i.e. no-op). existingHash, err := tree.ndb.getRoot(version) @@ -918,9 +939,12 @@ func (tree *MutableTree) SaveVersion() ([]byte, int64, error) { } if bytes.Equal(existingHash, newHash) { - tree.version = version - tree.ImmutableTree = tree.ImmutableTree.clone() - tree.lastSaved = tree.ImmutableTree.clone() + tree.mtx.Lock() + defer tree.mtx.Unlock() + clone := tree.immutableTree.clone() + clone.version = version + tree.immutableTree = clone + tree.lastSaved = clone.clone() tree.orphans = map[string]int64{} return existingHash, version, nil } @@ -935,19 +959,21 @@ func (tree *MutableTree) SaveVersion() ([]byte, int64, error) { return nil, v, err } - tree.version = version + // mtx is already held at this point + clone := tree.immutableTree.clone() + clone.version = version tree.versions[version] = true // set new working tree - tree.ImmutableTree = tree.ImmutableTree.clone() - tree.lastSaved = tree.ImmutableTree.clone() + tree.immutableTree = clone + tree.lastSaved = clone.clone() tree.orphans = map[string]int64{} if !tree.skipFastStorageUpgrade { tree.unsavedFastNodeAdditions = make(map[string]*FastNode) tree.unsavedFastNodeRemovals = make(map[string]interface{}) } - hash, err := tree.Hash() + hash, err := tree.lastSaved.Hash() if err != nil { return nil, version, err } @@ -998,7 +1024,7 @@ func (tree *MutableTree) handleOrphans(version int64) error { } func (tree *MutableTree) commitVersion(version int64, silentSaveRootError bool) (int64, error) { - if tree.root == nil { + if tree.immutableTree.root == nil { // There can still be orphans, for example if the root is the node being // removed. logger.Debug("SAVE EMPTY TREE %v\n", version) @@ -1010,13 +1036,13 @@ func (tree *MutableTree) commitVersion(version int64, silentSaveRootError bool) } } else { logger.Debug("SAVE TREE %v\n", version) - if _, err := tree.ndb.SaveBranch(tree.root); err != nil { + if _, err := tree.ndb.SaveBranch(tree.immutableTree.root); err != nil { return 0, err } if err := tree.handleOrphans(version); err != nil { return 0, err } - if err := tree.ndb.SaveRoot(tree.root, version); !silentSaveRootError && err != nil { + if err := tree.ndb.SaveRoot(tree.immutableTree.root, version); !silentSaveRootError && err != nil { return 0, err } } @@ -1087,11 +1113,12 @@ func (tree *MutableTree) saveFastNodeRemovals() error { return nil } +// unlocked func (tree *MutableTree) deleteVersion(version int64) error { if version <= 0 { return errors.New("version must be greater than 0") } - if version == tree.version { + if version == tree.ImmutableTree().version { return errors.Errorf("cannot delete latest saved version (%d)", version) } if !tree.VersionExists(version) { @@ -1108,6 +1135,8 @@ func (tree *MutableTree) deleteVersion(version int64) error { // It is only used during the initial SaveVersion() call for a tree with no other versions, // and is otherwise ignored. func (tree *MutableTree) SetInitialVersion(version uint64) { + tree.mtx.Lock() + defer tree.mtx.Unlock() tree.ndb.opts.InitialVersion = version } @@ -1191,8 +1220,9 @@ func (tree *MutableTree) DeleteVersion(version int64) error { } // Rotate right and return the new node and orphan. +// mtx already held func (tree *MutableTree) rotateRight(node *Node) (*Node, *Node, error) { - version := tree.version + 1 + version := tree.immutableTree.version + 1 var err error // TODO: optimize balance & rotate. @@ -1201,7 +1231,7 @@ func (tree *MutableTree) rotateRight(node *Node) (*Node, *Node, error) { return nil, nil, err } - orphaned, err := node.getLeftNode(tree.ImmutableTree) + orphaned, err := node.getLeftNode(tree.immutableTree) if err != nil { return nil, nil, err } @@ -1216,12 +1246,12 @@ func (tree *MutableTree) rotateRight(node *Node) (*Node, *Node, error) { node.SetLeftHash(newNoderHash) node.SetLeftNode(newNoderCached) - err = node.calcHeightAndSize(tree.ImmutableTree) + err = node.calcHeightAndSize(tree.immutableTree) if err != nil { return nil, nil, err } - err = newNode.calcHeightAndSize(tree.ImmutableTree) + err = newNode.calcHeightAndSize(tree.immutableTree) if err != nil { return nil, nil, err } @@ -1231,7 +1261,7 @@ func (tree *MutableTree) rotateRight(node *Node) (*Node, *Node, error) { // Rotate left and return the new node and orphan. func (tree *MutableTree) rotateLeft(node *Node) (*Node, *Node, error) { - version := tree.version + 1 + version := tree.immutableTree.version + 1 var err error // TODO: optimize balance & rotate. @@ -1240,7 +1270,7 @@ func (tree *MutableTree) rotateLeft(node *Node) (*Node, *Node, error) { return nil, nil, err } - orphaned, err := node.getRightNode(tree.ImmutableTree) + orphaned, err := node.getRightNode(tree.immutableTree) if err != nil { return nil, nil, err } @@ -1255,12 +1285,12 @@ func (tree *MutableTree) rotateLeft(node *Node) (*Node, *Node, error) { node.SetRightHash(newNodelHash) node.SetRightNode(newNodelCached) - err = node.calcHeightAndSize(tree.ImmutableTree) + err = node.calcHeightAndSize(tree.immutableTree) if err != nil { return nil, nil, err } - err = newNode.calcHeightAndSize(tree.ImmutableTree) + err = newNode.calcHeightAndSize(tree.immutableTree) if err != nil { return nil, nil, err } @@ -1274,18 +1304,18 @@ func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, e if node.GetPersisted() { return nil, fmt.Errorf("unexpected balance() call on persisted node") } - balance, err := node.calcBalance(tree.ImmutableTree) + balance, err := node.calcBalance(tree.immutableTree) if err != nil { return nil, err } if balance > 1 { - leftNode, err := node.getLeftNode(tree.ImmutableTree) + leftNode, err := node.getLeftNode(tree.immutableTree) if err != nil { return nil, err } - lftBalance, err := leftNode.calcBalance(tree.ImmutableTree) + lftBalance, err := leftNode.calcBalance(tree.immutableTree) if err != nil { return nil, err } @@ -1302,7 +1332,7 @@ func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, e // Left Right Case var leftOrphaned *Node - left, err := node.getLeftNode(tree.ImmutableTree) + left, err := node.getLeftNode(tree.immutableTree) if err != nil { return nil, err } @@ -1322,12 +1352,12 @@ func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, e return newNode, nil } if balance < -1 { - rightNode, err := node.getRightNode(tree.ImmutableTree) + rightNode, err := node.getRightNode(tree.immutableTree) if err != nil { return nil, err } - rightBalance, err := rightNode.calcBalance(tree.ImmutableTree) + rightBalance, err := rightNode.calcBalance(tree.immutableTree) if err != nil { return nil, err } @@ -1343,7 +1373,7 @@ func (tree *MutableTree) balance(node *Node, orphans *[]*Node) (newSelf *Node, e // Right Left Case var rightOrphaned *Node - right, err := node.getRightNode(tree.ImmutableTree) + right, err := node.getRightNode(tree.immutableTree) if err != nil { return nil, err } @@ -1379,3 +1409,7 @@ func (tree *MutableTree) addOrphans(orphans []*Node) error { } return nil } + +func (tree *MutableTree) Version() int64 { + return tree.ImmutableTree().Version() +} diff --git a/mutable_tree_test.go b/mutable_tree_test.go index bd26463..6eeaedb 100644 --- a/mutable_tree_test.go +++ b/mutable_tree_test.go @@ -105,7 +105,7 @@ func TestTraverse(t *testing.T) { tree.set([]byte(fmt.Sprintf("k%d", i)), []byte(fmt.Sprintf("v%d", i))) } - require.Equal(t, 11, tree.nodeSize(), "Size of tree unexpected") + require.Equal(t, 11, tree.ImmutableTree().nodeSize(), "Size of tree unexpected") } func TestMutableTree_DeleteVersions(t *testing.T) { @@ -435,7 +435,7 @@ func TestMutableTree_LazyLoadVersionWithEmptyTree(t *testing.T) { require.NoError(t, err) require.True(t, v1 == v2) - require.True(t, newTree1.root == newTree2.root) + require.True(t, newTree1.ImmutableTree().root == newTree2.ImmutableTree().root) } func TestMutableTree_SetSimple(t *testing.T) { @@ -452,7 +452,7 @@ func TestMutableTree_SetSimple(t *testing.T) { fastValue, err := tree.Get([]byte(testKey1)) require.NoError(t, err) - _, regularValue, err := tree.GetWithIndex([]byte(testKey1)) + _, regularValue, err := tree.ImmutableTree().GetWithIndex([]byte(testKey1)) require.NoError(t, err) require.Equal(t, []byte(testVal1), fastValue) @@ -486,14 +486,14 @@ func TestMutableTree_SetTwoKeys(t *testing.T) { fastValue, err := tree.Get([]byte(testKey1)) require.NoError(t, err) - _, regularValue, err := tree.GetWithIndex([]byte(testKey1)) + _, regularValue, err := tree.ImmutableTree().GetWithIndex([]byte(testKey1)) require.NoError(t, err) require.Equal(t, []byte(testVal1), fastValue) require.Equal(t, []byte(testVal1), regularValue) fastValue2, err := tree.Get([]byte(testKey2)) require.NoError(t, err) - _, regularValue2, err := tree.GetWithIndex([]byte(testKey2)) + _, regularValue2, err := tree.ImmutableTree().GetWithIndex([]byte(testKey2)) require.NoError(t, err) require.Equal(t, []byte(testVal2), fastValue2) require.Equal(t, []byte(testVal2), regularValue2) @@ -528,7 +528,7 @@ func TestMutableTree_SetOverwrite(t *testing.T) { fastValue, err := tree.Get([]byte(testKey1)) require.NoError(t, err) - _, regularValue, err := tree.GetWithIndex([]byte(testKey1)) + _, regularValue, err := tree.ImmutableTree().GetWithIndex([]byte(testKey1)) require.NoError(t, err) require.Equal(t, []byte(testVal2), fastValue) require.Equal(t, []byte(testVal2), regularValue) @@ -554,7 +554,7 @@ func TestMutableTree_SetRemoveSet(t *testing.T) { fastValue, err := tree.Get([]byte(testKey1)) require.NoError(t, err) - _, regularValue, err := tree.GetWithIndex([]byte(testKey1)) + _, regularValue, err := tree.ImmutableTree().GetWithIndex([]byte(testKey1)) require.Equal(t, []byte(testVal1), fastValue) require.Equal(t, []byte(testVal1), regularValue) @@ -580,7 +580,7 @@ func TestMutableTree_SetRemoveSet(t *testing.T) { fastValue, err = tree.Get([]byte(testKey1)) require.NoError(t, err) - _, regularValue, err = tree.GetWithIndex([]byte(testKey1)) + _, regularValue, err = tree.ImmutableTree().GetWithIndex([]byte(testKey1)) require.NoError(t, err) require.Nil(t, fastValue) require.Nil(t, regularValue) @@ -592,7 +592,7 @@ func TestMutableTree_SetRemoveSet(t *testing.T) { fastValue, err = tree.Get([]byte(testKey1)) require.NoError(t, err) - _, regularValue, err = tree.GetWithIndex([]byte(testKey1)) + _, regularValue, err = tree.ImmutableTree().GetWithIndex([]byte(testKey1)) require.NoError(t, err) require.Equal(t, []byte(testVal1), fastValue) require.Equal(t, []byte(testVal1), regularValue) @@ -685,21 +685,21 @@ func TestMutableTree_FastNodeIntegration(t *testing.T) { // Get and GetFast fastValue, err := t2.Get([]byte(key1)) require.NoError(t, err) - _, regularValue, err := tree.GetWithIndex([]byte(key1)) + _, regularValue, err := tree.ImmutableTree().GetWithIndex([]byte(key1)) require.NoError(t, err) require.Equal(t, []byte(testVal1), fastValue) require.Equal(t, []byte(testVal1), regularValue) fastValue, err = t2.Get([]byte(key2)) require.NoError(t, err) - _, regularValue, err = t2.GetWithIndex([]byte(key2)) + _, regularValue, err = t2.ImmutableTree().GetWithIndex([]byte(key2)) require.NoError(t, err) require.Nil(t, fastValue) require.Nil(t, regularValue) fastValue, err = t2.Get([]byte(key3)) require.NoError(t, err) - _, regularValue, err = tree.GetWithIndex([]byte(key3)) + _, regularValue, err = tree.ImmutableTree().GetWithIndex([]byte(key3)) require.NoError(t, err) require.Equal(t, []byte(testVal2), fastValue) require.Equal(t, []byte(testVal2), regularValue) @@ -749,7 +749,7 @@ func TestUpgradeStorageToFast_LatestVersion_Success(t *testing.T) { require.NoError(t, err) // Default version when storage key does not exist in the db - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -768,7 +768,7 @@ func TestUpgradeStorageToFast_LatestVersion_Success(t *testing.T) { require.False(t, isUpgradeable) require.NoError(t, err) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) } @@ -780,7 +780,7 @@ func TestUpgradeStorageToFast_AlreadyUpgraded_Success(t *testing.T) { require.NoError(t, err) // Default version when storage key does not exist in the db - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -795,7 +795,7 @@ func TestUpgradeStorageToFast_AlreadyUpgraded_Success(t *testing.T) { enabled, err := tree.enableFastStorageAndCommitIfNotEnabled() require.NoError(t, err) require.True(t, enabled) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) isUpgradeable, err = tree.IsUpgradeable() @@ -806,7 +806,7 @@ func TestUpgradeStorageToFast_AlreadyUpgraded_Success(t *testing.T) { enabled, err = tree.enableFastStorageAndCommitIfNotEnabled() require.NoError(t, err) require.False(t, enabled) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) @@ -832,7 +832,7 @@ func TestUpgradeStorageToFast_DbErrorConstructor_Failure(t *testing.T) { require.Nil(t, err) require.NotNil(t, tree) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) } @@ -867,7 +867,7 @@ func TestUpgradeStorageToFast_DbErrorEnableFastStorage_Failure(t *testing.T) { require.Nil(t, err) require.NotNil(t, tree) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -875,7 +875,7 @@ func TestUpgradeStorageToFast_DbErrorEnableFastStorage_Failure(t *testing.T) { require.ErrorIs(t, err, expectedError) require.False(t, enabled) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) } @@ -909,13 +909,13 @@ func TestFastStorageReUpgradeProtection_NoForceUpgrade_Success(t *testing.T) { require.NotNil(t, tree) // Pretend that we called Load and have the latest state in the tree - tree.version = latestTreeVersion + tree.ImmutableTree().version = latestTreeVersion latestVersion, err := tree.ndb.getLatestVersion() require.NoError(t, err) require.Equal(t, latestVersion, int64(latestTreeVersion)) // Ensure that the right branch of enableFastStorageAndCommitIfNotEnabled will be triggered - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) shouldForce, err := tree.ndb.shouldForceFastStorageUpgrade() @@ -1002,13 +1002,13 @@ func TestFastStorageReUpgradeProtection_ForceUpgradeFirstTime_NoForceSecondTime_ require.NotNil(t, tree) // Pretend that we called Load and have the latest state in the tree - tree.version = latestTreeVersion + tree.ImmutableTree().version = latestTreeVersion latestVersion, err := tree.ndb.getLatestVersion() require.NoError(t, err) require.Equal(t, latestVersion, int64(latestTreeVersion)) // Ensure that the right branch of enableFastStorageAndCommitIfNotEnabled will be triggered - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) shouldForce, err := tree.ndb.shouldForceFastStorageUpgrade() @@ -1030,7 +1030,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_FastIterator_Success(t *testi // Setup tree, mirror := setupTreeAndMirror(t, 100, false) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err := tree.IsUpgradeable() @@ -1041,7 +1041,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_FastIterator_Success(t *testi _, _, err = tree.SaveVersion() require.NoError(t, err) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) isUpgradeable, err = tree.IsUpgradeable() @@ -1050,7 +1050,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_FastIterator_Success(t *testi sut, _ := NewMutableTree(tree.ndb.db, 1000, false) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err = sut.IsUpgradeable() @@ -1061,7 +1061,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_FastIterator_Success(t *testi version, err := sut.Load() require.NoError(t, err) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) @@ -1080,7 +1080,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_FastIterator_Success(t *testi // Test that upgraded immutable tree iterates as expected t.Run("Immutable tree", func(t *testing.T) { - immutableTree, err := sut.GetImmutable(sut.version) + immutableTree, err := sut.GetImmutable(sut.ImmutableTree().version) require.NoError(t, err) i := 0 @@ -1097,7 +1097,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_GetFast_Success(t *testing.T) // Setup tree, mirror := setupTreeAndMirror(t, 100, false) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err := tree.IsUpgradeable() @@ -1108,7 +1108,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_GetFast_Success(t *testing.T) _, _, err = tree.SaveVersion() require.NoError(t, err) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) isUpgradeable, err = tree.IsUpgradeable() @@ -1117,7 +1117,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_GetFast_Success(t *testing.T) sut, _ := NewMutableTree(tree.ndb.db, 1000, false) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err = sut.IsUpgradeable() @@ -1128,7 +1128,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_GetFast_Success(t *testing.T) version, err := sut.LazyLoadVersion(1) require.NoError(t, err) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) @@ -1143,7 +1143,7 @@ func TestUpgradeStorageToFast_Integration_Upgraded_GetFast_Success(t *testing.T) }) t.Run("Immutable tree", func(t *testing.T) { - immutableTree, err := sut.GetImmutable(sut.version) + immutableTree, err := sut.GetImmutable(sut.ImmutableTree().version) require.NoError(t, err) for _, kv := range mirror { @@ -1284,7 +1284,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Get_Success(t *testin // Setup tree, mirror := setupTreeAndMirror(t, 100, true) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err := tree.IsUpgradeable() @@ -1295,7 +1295,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Get_Success(t *testin _, _, err = tree.SaveVersion() require.NoError(t, err) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err = tree.IsUpgradeable() @@ -1304,7 +1304,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Get_Success(t *testin sut, _ := NewMutableTree(tree.ndb.db, 1000, true) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err = sut.IsUpgradeable() @@ -1316,7 +1316,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Get_Success(t *testin require.NoError(t, err) require.Equal(t, int64(1), version) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -1325,7 +1325,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Get_Success(t *testin require.NoError(t, err) require.Equal(t, int64(1), version) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -1334,7 +1334,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Get_Success(t *testin require.NoError(t, err) require.Equal(t, int64(1), version) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -1343,7 +1343,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Get_Success(t *testin require.NoError(t, err) require.Equal(t, int64(1), version) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -1356,7 +1356,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Get_Success(t *testin }) t.Run("Immutable tree", func(t *testing.T) { - immutableTree, err := sut.GetImmutable(sut.version) + immutableTree, err := sut.GetImmutable(sut.ImmutableTree().version) require.NoError(t, err) for _, kv := range mirror { @@ -1371,7 +1371,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Iterate_Success(t *te // Setup tree, mirror := setupTreeAndMirror(t, 100, true) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err := tree.IsUpgradeable() @@ -1382,7 +1382,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Iterate_Success(t *te _, _, err = tree.SaveVersion() require.NoError(t, err) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err = tree.IsUpgradeable() @@ -1391,7 +1391,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Iterate_Success(t *te sut, _ := NewMutableTree(tree.ndb.db, 1000, true) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) isUpgradeable, err = sut.IsUpgradeable() @@ -1403,7 +1403,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Iterate_Success(t *te require.NoError(t, err) require.Equal(t, int64(1), version) - isFastCacheEnabled, err = sut.IsFastCacheEnabled() + isFastCacheEnabled, err = sut.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -1412,7 +1412,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Iterate_Success(t *te require.NoError(t, err) require.Equal(t, int64(1), version) - isFastCacheEnabled, err = tree.IsFastCacheEnabled() + isFastCacheEnabled, err = tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -1429,7 +1429,7 @@ func TestNoFastStorageUpgrade_Integration_SaveVersion_Load_Iterate_Success(t *te // Test that the immutable tree iterates as expected t.Run("Immutable tree", func(t *testing.T) { - immutableTree, err := sut.GetImmutable(sut.version) + immutableTree, err := sut.GetImmutable(sut.ImmutableTree().version) require.NoError(t, err) i := 0 @@ -1463,7 +1463,7 @@ func TestSaveCurrentVersion_BadVersion(t *testing.T) { _, version, err := tree.SaveVersion() require.NoError(t, err) assert.EqualValues(t, 9, version) - tree.version = 10 + tree.ImmutableTree().version = 10 _, version, err = tree.SaveCurrentVersion() require.Error(t, err) assert.EqualValues(t, 10, version) diff --git a/proof_forgery_test.go b/proof_forgery_test.go index 241db1c..82ab3e5 100644 --- a/proof_forgery_test.go +++ b/proof_forgery_test.go @@ -37,7 +37,7 @@ func TestProofFogery(t *testing.T) { k := []byte{keys[1]} v := values[1] - val, proof, err := tree.GetWithProof(k) + val, proof, err := tree.ImmutableTree().GetWithProof(k) require.NoError(t, err) err = proof.Verify(root) @@ -53,7 +53,7 @@ func TestProofFogery(t *testing.T) { // - a new leaf node to the right // - an empty inner node // - a right entry in the path - _, proof2, _ := tree.GetWithProof(k) + _, proof2, _ := tree.ImmutableTree().GetWithProof(k) forgedNode := proof2.Leaves[0] forgedNode.Key = []byte{0xFF} forgedNode.ValueHash = forgedValueHash diff --git a/proof_iavl_test.go b/proof_iavl_test.go index 7047309..1581ecf 100644 --- a/proof_iavl_test.go +++ b/proof_iavl_test.go @@ -44,7 +44,7 @@ func TestProofOp(t *testing.T) { tc := tc t.Run(fmt.Sprintf("%02x", tc.key), func(t *testing.T) { key := []byte{tc.key} - value, proof, err := tree.GetWithProof(key) + value, proof, err := tree.ImmutableTree().GetWithProof(key) require.NoError(t, err) // Verify that proof is valid. diff --git a/proof_ics23_test.go b/proof_ics23_test.go index fd0a6d1..c375ab4 100644 --- a/proof_ics23_test.go +++ b/proof_ics23_test.go @@ -48,7 +48,7 @@ func TestGetMembership(t *testing.T) { key := GetKey(allkeys, tc.loc) val, err := tree.Get(key) require.NoError(t, err) - proof, err := tree.GetMembershipProof(key) + proof, err := tree.ImmutableTree().GetMembershipProof(key) require.NoError(t, err, "Creating Proof: %+v", err) root, err := tree.Hash() @@ -77,7 +77,7 @@ func TestGetNonMembership(t *testing.T) { performTest := func(tree *MutableTree, allKeys [][]byte, loc Where) { key := GetNonKey(allKeys, loc) - proof, err := tree.GetNonMembershipProof(key) + proof, err := tree.ImmutableTree().GetNonMembershipProof(key) require.NoError(t, err, "Creating Proof: %+v", err) root, err := tree.Hash() @@ -97,7 +97,7 @@ func TestGetNonMembership(t *testing.T) { _, _, err = tree.SaveVersion() require.NoError(t, err) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.True(t, isFastCacheEnabled) @@ -107,7 +107,7 @@ func TestGetNonMembership(t *testing.T) { t.Run("regular-"+name, func(t *testing.T) { tree, allkeys, err := BuildTree(tc.size, 0) require.NoError(t, err, "Creating tree: %+v", err) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(t, err) require.False(t, isFastCacheEnabled) @@ -132,7 +132,7 @@ func BenchmarkGetNonMembership(b *testing.B) { performTest := func(tree *MutableTree, allKeys [][]byte, loc Where) { key := GetNonKey(allKeys, loc) - proof, err := tree.GetNonMembershipProof(key) + proof, err := tree.ImmutableTree().GetNonMembershipProof(key) require.NoError(b, err, "Creating Proof: %+v", err) b.StopTimer() @@ -157,7 +157,7 @@ func BenchmarkGetNonMembership(b *testing.B) { _, _, err = tree.SaveVersion() require.NoError(b, err) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(b, err) require.True(b, isFastCacheEnabled) b.StartTimer() @@ -173,7 +173,7 @@ func BenchmarkGetNonMembership(b *testing.B) { tree, allkeys, err := BuildTree(tc.size, 100000) require.NoError(b, err, "Creating tree: %+v", err) - isFastCacheEnabled, err := tree.IsFastCacheEnabled() + isFastCacheEnabled, err := tree.ImmutableTree().IsFastCacheEnabled() require.NoError(b, err) require.False(b, isFastCacheEnabled) @@ -207,7 +207,7 @@ func GenerateResult(size int, loc Where) (*Result, error) { } key := GetKey(allkeys, loc) - value, proof, err := tree.GetWithProof(key) + value, proof, err := tree.ImmutableTree().GetWithProof(key) if err != nil { return nil, err } diff --git a/proof_test.go b/proof_test.go index 5e1c0ce..c52ea79 100644 --- a/proof_test.go +++ b/proof_test.go @@ -26,7 +26,7 @@ func TestTreeGetWithProof(t *testing.T) { require.NoError(err) key := []byte{0x32} - val, proof, err := tree.GetWithProof(key) + val, proof, err := tree.ImmutableTree().GetWithProof(key) require.NoError(err) require.NotEmpty(val) require.NotNil(proof) @@ -41,7 +41,7 @@ func TestTreeGetWithProof(t *testing.T) { require.NoError(err, "%+v", err) key = []byte{0x1} - val, proof, err = tree.GetWithProof(key) + val, proof, err = tree.ImmutableTree().GetWithProof(key) require.NoError(err) require.Empty(val) require.NotNil(proof) @@ -63,7 +63,7 @@ func TestTreeKeyExistsProof(t *testing.T) { require.NoError(t, err) // should get false for proof with nil root - proof, keys, values, err := tree.getRangeProof([]byte("foo"), nil, 1) + proof, keys, values, err := tree.ImmutableTree().getRangeProof([]byte("foo"), nil, 1) assert.Nil(t, proof) assert.Error(t, proof.Verify(root)) assert.Nil(t, keys) @@ -83,13 +83,13 @@ func TestTreeKeyExistsProof(t *testing.T) { require.NoError(t, err) // query random key fails - proof, _, _, err = tree.getRangeProof([]byte("foo"), nil, 2) + proof, _, _, err = tree.ImmutableTree().getRangeProof([]byte("foo"), nil, 2) assert.Nil(t, err) assert.Nil(t, proof.Verify(root)) assert.Nil(t, proof.VerifyAbsence([]byte("foo")), proof.String()) // query min key fails - proof, _, _, err = tree.getRangeProof([]byte{0x00}, []byte{0x01}, 2) + proof, _, _, err = tree.ImmutableTree().getRangeProof([]byte{0x00}, []byte{0x01}, 2) assert.Nil(t, err) assert.Nil(t, proof.Verify(root)) assert.Nil(t, proof.VerifyAbsence([]byte{0x00})) @@ -97,7 +97,7 @@ func TestTreeKeyExistsProof(t *testing.T) { // valid proof for real keys for i, key := range allkeys { var keys, values [][]byte - proof, keys, values, err = tree.getRangeProof(key, nil, 2) + proof, keys, values, err = tree.ImmutableTree().getRangeProof(key, nil, 2) require.Nil(t, err) require.Equal(t, @@ -186,7 +186,7 @@ func TestTreeKeyInRangeProofs(t *testing.T) { end := []byte{c.end} // Compute range proof. - keys, values, proof, err := tree.GetRangeWithProof(start, end, 0) + keys, values, proof, err := tree.ImmutableTree().GetRangeWithProof(start, end, 0) if c.err { require.Error(err, "%+v", err) diff --git a/repair_test.go b/repair_test.go index 8d17355..a9aaa17 100644 --- a/repair_test.go +++ b/repair_test.go @@ -84,7 +84,7 @@ func TestRepair013Orphans(t *testing.T) { // assertVersion checks the given version (or current if 0) against the expected values. func assertVersion(t *testing.T, tree *MutableTree, version int64) { var err error - itree := tree.ImmutableTree + itree := tree.ImmutableTree() if version > 0 { itree, err = tree.GetImmutable(version) require.NoError(t, err) diff --git a/testutils_test.go b/testutils_test.go index 85b0f1e..f6d8ca5 100644 --- a/testutils_test.go +++ b/testutils_test.go @@ -78,7 +78,7 @@ func T(n *Node) (*MutableTree, error) { if err != nil { return nil, err } - t.root = n + t.ImmutableTree().root = n return t, nil } diff --git a/tree_dotgraph_test.go b/tree_dotgraph_test.go index 017bcae..a4bad9c 100644 --- a/tree_dotgraph_test.go +++ b/tree_dotgraph_test.go @@ -16,5 +16,5 @@ func TestWriteDOTGraph(t *testing.T) { key := []byte{ikey} tree.Set(key, key) } - WriteDOTGraph(ioutil.Discard, tree.ImmutableTree, []PathToLeaf{}) + WriteDOTGraph(ioutil.Discard, tree.ImmutableTree(), []PathToLeaf{}) } diff --git a/tree_random_test.go b/tree_random_test.go index f9aa3f6..ad8d1e2 100644 --- a/tree_random_test.go +++ b/tree_random_test.go @@ -152,7 +152,7 @@ func testRandomOperations(t *testing.T, randSeed int64) { require.NoError(t, err) t.Logf("Saved tree at version %v with %v keys and %v versions", - version, tree.Size(), len(tree.AvailableVersions())) + version, tree.ImmutableTree().Size(), len(tree.AvailableVersions())) // Verify that the version matches the mirror. assertMirror(t, tree, mirror, 0) @@ -391,7 +391,7 @@ func assertMaxVersion(t *testing.T, tree *MutableTree, version int64, mirrors ma // Checks that a mirror, optionally for a given version, matches the tree contents. func assertMirror(t *testing.T, tree *MutableTree, mirror map[string]string, version int64) { var err error - itree := tree.ImmutableTree + itree := tree.ImmutableTree() if version > 0 { itree, err = tree.GetImmutable(version) require.NoError(t, err, "loading version %v", version) diff --git a/tree_test.go b/tree_test.go index c02b0de..0a09a5d 100644 --- a/tree_test.go +++ b/tree_test.go @@ -77,7 +77,7 @@ func TestVersionedRandomTree(t *testing.T) { // db than in the current tree version. nodes, err := tree.ndb.nodes() require.Nil(err) - require.True(len(nodes) >= tree.nodeSize()) + require.True(len(nodes) >= tree.ImmutableTree().nodeSize()) // Ensure it returns all versions in sorted order available := tree.AvailableVersions() @@ -92,7 +92,7 @@ func TestVersionedRandomTree(t *testing.T) { require.Len(tree.versions, 1, "tree must have one version left") tr, err := tree.GetImmutable(int64(versions)) require.NoError(err, "GetImmutable should not error for version %d", versions) - require.Equal(tr.root, tree.root) + require.Equal(tr.root, tree.ImmutableTree().root) // we should only have one available version now available = tree.AvailableVersions() @@ -103,11 +103,11 @@ func TestVersionedRandomTree(t *testing.T) { // in the db as in the current tree version. leafNodes, err = tree.ndb.leafNodes() require.Nil(err) - require.Len(leafNodes, int(tree.Size())) + require.Len(leafNodes, int(tree.ImmutableTree().Size())) nodes, err = tree.ndb.nodes() require.Nil(err) - require.Equal(tree.nodeSize(), len(nodes)) + require.Equal(tree.ImmutableTree().nodeSize(), len(nodes)) } // nolint: dupl @@ -216,9 +216,9 @@ func TestVersionedRandomTreeSmallKeys(t *testing.T) { nodes, err := tree.ndb.nodes() require.Nil(err) - require.Len(leafNodes, int(tree.Size())) - require.Len(nodes, tree.nodeSize()) - require.Len(nodes, singleVersionTree.nodeSize()) + require.Len(leafNodes, int(tree.ImmutableTree().Size())) + require.Len(nodes, tree.ImmutableTree().nodeSize()) + require.Len(nodes, singleVersionTree.ImmutableTree().nodeSize()) // Try getting random keys. for i := 0; i < keysPerVersion; i++ { @@ -266,9 +266,9 @@ func TestVersionedRandomTreeSmallKeysRandomDeletes(t *testing.T) { nodes, err := tree.ndb.nodes() require.Nil(err) - require.Len(leafNodes, int(tree.Size())) - require.Len(nodes, tree.nodeSize()) - require.Len(nodes, singleVersionTree.nodeSize()) + require.Len(leafNodes, int(tree.ImmutableTree().Size())) + require.Len(nodes, tree.ImmutableTree().nodeSize()) + require.Len(nodes, singleVersionTree.ImmutableTree().nodeSize()) // Try getting random keys. for i := 0; i < keysPerVersion; i++ { @@ -301,7 +301,7 @@ func TestVersionedTreeSpecial1(t *testing.T) { nodes, err := tree.ndb.nodes() require.Nil(t, err) - require.Equal(t, tree.nodeSize(), len(nodes)) + require.Equal(t, tree.ImmutableTree().nodeSize(), len(nodes)) } func TestVersionedRandomTreeSpecial2(t *testing.T) { @@ -321,7 +321,7 @@ func TestVersionedRandomTreeSpecial2(t *testing.T) { nodes, err := tree.ndb.nodes() require.NoError(err) - require.Len(nodes, tree.nodeSize()) + require.Len(nodes, tree.ImmutableTree().nodeSize()) } func TestVersionedEmptyTree(t *testing.T) { @@ -364,7 +364,7 @@ func TestVersionedEmptyTree(t *testing.T) { require.False(tree.VersionExists(3)) tree.Set([]byte("k"), []byte("v")) - require.EqualValues(5, tree.root.version) + require.EqualValues(5, tree.ImmutableTree().root.version) // Now reload the tree. @@ -393,7 +393,7 @@ func TestVersionedTree(t *testing.T) { // We start with empty database. require.Equal(0, tree.ndb.size()) require.True(tree.IsEmpty()) - require.False(tree.IsFastCacheEnabled()) + require.False(tree.ImmutableTree().IsFastCacheEnabled()) // version 0 @@ -656,7 +656,7 @@ func TestVersionedTreeVersionDeletingEfficiency(t *testing.T) { tree2.Set([]byte("key3"), []byte("val1")) tree2.SaveVersion() - require.Equal(t, tree2.nodeSize(), tree.nodeSize()) + require.Equal(t, tree2.ImmutableTree().nodeSize(), tree.ImmutableTree().nodeSize()) } func TestVersionedTreeOrphanDeleting(t *testing.T) { @@ -787,7 +787,7 @@ func TestVersionedTreeSpecialCase3(t *testing.T) { nodes, err := tree.ndb.nodes() require.NoError(err) - require.Equal(tree.nodeSize(), len(nodes)) + require.Equal(tree.ImmutableTree().nodeSize(), len(nodes)) } func TestVersionedTreeSaveAndLoad(t *testing.T) { @@ -841,10 +841,10 @@ func TestVersionedTreeSaveAndLoad(t *testing.T) { ntree.DeleteVersion(3) require.False(ntree.IsEmpty()) - require.Equal(int64(4), ntree.Size()) + require.Equal(int64(4), ntree.ImmutableTree().Size()) nodes, err := tree.ndb.nodes() require.NoError(err) - require.Len(nodes, ntree.nodeSize()) + require.Len(nodes, ntree.ImmutableTree().nodeSize()) } func TestVersionedTreeErrors(t *testing.T) { @@ -1172,7 +1172,7 @@ func TestVersionedTreeEfficiency(t *testing.T) { require.InDelta(change, keysAddedPerVersion[i], float64(keysPerVersion)/5) } } - require.Equal(keysAdded-tree.nodeSize(), keysDeleted) + require.Equal(keysAdded-tree.ImmutableTree().nodeSize(), keysDeleted) } func TestVersionedTreeProofs(t *testing.T) { @@ -1360,7 +1360,7 @@ func TestRollback(t *testing.T) { tree.SaveVersion() - require.Equal(int64(2), tree.Size()) + require.Equal(int64(2), tree.ImmutableTree().Size()) val, err := tree.Get([]byte("r")) require.Nil(val) @@ -1904,13 +1904,13 @@ func Benchmark_GetWithIndex(b *testing.B) { runtime.GC() b.Run("fast", func(sub *testing.B) { - isFastCacheEnabled, err := t.IsFastCacheEnabled() + isFastCacheEnabled, err := t.ImmutableTree().IsFastCacheEnabled() require.NoError(b, err) require.True(b, isFastCacheEnabled) b.ResetTimer() for i := 0; i < sub.N; i++ { randKey := rand.Intn(numKeyVals) - t.GetWithIndex(keys[randKey]) + t.ImmutableTree().GetWithIndex(keys[randKey]) } }) @@ -1953,13 +1953,13 @@ func Benchmark_GetByIndex(b *testing.B) { runtime.GC() b.Run("fast", func(sub *testing.B) { - isFastCacheEnabled, err := t.IsFastCacheEnabled() + isFastCacheEnabled, err := t.ImmutableTree().IsFastCacheEnabled() require.NoError(b, err) require.True(b, isFastCacheEnabled) b.ResetTimer() for i := 0; i < sub.N; i++ { randIdx := rand.Intn(numKeyVals) - t.GetByIndex(int64(randIdx)) + t.ImmutableTree().GetByIndex(int64(randIdx)) } })