Skip to content

Commit

Permalink
Merge pull request #33 from sei-protocol/tony-chen-add-mtx
Browse files Browse the repository at this point in the history
Synchronize potential concurrent access to mutable tree
  • Loading branch information
philipsu522 authored Jun 16, 2023
2 parents 799c1de + 4705ec2 commit 2e3b581
Show file tree
Hide file tree
Showing 15 changed files with 252 additions and 218 deletions.
62 changes: 31 additions & 31 deletions basic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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")
Expand All @@ -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")
Expand All @@ -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")
Expand All @@ -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")
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)
}
}

Expand Down Expand Up @@ -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)))
}
}
}
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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) {
Expand All @@ -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)))
Expand All @@ -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)
Expand All @@ -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)
Expand Down
10 changes: 5 additions & 5 deletions benchmarks/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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++ {
Expand All @@ -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))
Expand Down Expand Up @@ -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")
Expand All @@ -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")
}
Expand Down
6 changes: 3 additions & 3 deletions cmd/iaviewer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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":
Expand All @@ -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":
Expand Down Expand Up @@ -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"))
}

Expand Down
6 changes: 3 additions & 3 deletions export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 2e3b581

Please sign in to comment.