github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/iavl/testutils_test.go (about) 1 package iavl 2 3 import ( 4 "bytes" 5 "fmt" 6 mrand "math/rand" 7 "runtime" 8 "testing" 9 10 "github.com/stretchr/testify/require" 11 12 "github.com/gnolang/gno/tm2/pkg/amino" 13 "github.com/gnolang/gno/tm2/pkg/db" 14 _ "github.com/gnolang/gno/tm2/pkg/db/memdb" 15 "github.com/gnolang/gno/tm2/pkg/random" 16 ) 17 18 func randstr(length int) string { 19 return random.RandStr(length) 20 } 21 22 func i2b(i int) []byte { 23 buf := new(bytes.Buffer) 24 amino.EncodeInt32(buf, int32(i)) 25 return buf.Bytes() 26 } 27 28 func b2i(bz []byte) int { 29 i, _, _ := amino.DecodeInt32(bz) 30 return int(i) 31 } 32 33 // Convenience for a new node 34 func N(l, r interface{}) *Node { 35 var left, right *Node 36 if _, ok := l.(*Node); ok { 37 left = l.(*Node) 38 } else { 39 left = NewNode(i2b(l.(int)), nil, 0) 40 } 41 if _, ok := r.(*Node); ok { 42 right = r.(*Node) 43 } else { 44 right = NewNode(i2b(r.(int)), nil, 0) 45 } 46 47 n := &Node{ 48 key: right.lmd(nil).key, 49 value: nil, 50 leftNode: left, 51 rightNode: right, 52 } 53 n.calcHeightAndSize(nil) 54 return n 55 } 56 57 // Setup a deep node 58 func T(n *Node) *MutableTree { 59 d, err := db.NewDB("test", db.MemDBBackend, "") 60 if err != nil { 61 panic(err) 62 } 63 64 t := NewMutableTree(d, 0) 65 66 n.hashWithCount() 67 t.root = n 68 return t 69 } 70 71 // Convenience for simple printing of keys & tree structure 72 func P(n *Node) string { 73 if n.height == 0 { 74 return fmt.Sprintf("%v", b2i(n.key)) 75 } 76 return fmt.Sprintf("(%v %v)", P(n.leftNode), P(n.rightNode)) 77 } 78 79 func randBytes(length int) []byte { 80 key := make([]byte, length) 81 // math.rand.Read always returns err=nil 82 // we do not need cryptographic randomness for this test: 83 mrand.Read(key) 84 return key 85 } 86 87 type traverser struct { 88 first string 89 last string 90 count int 91 } 92 93 func (t *traverser) view(key, value []byte) bool { 94 if t.first == "" { 95 t.first = string(key) 96 } 97 t.last = string(key) 98 t.count++ 99 return false 100 } 101 102 func expectTraverse(t *testing.T, trav traverser, start, end string, count int) { 103 t.Helper() 104 105 if trav.first != start { 106 t.Error("Bad start", start, trav.first) 107 } 108 if trav.last != end { 109 t.Error("Bad end", end, trav.last) 110 } 111 if trav.count != count { 112 t.Error("Bad count", count, trav.count) 113 } 114 } 115 116 func BenchmarkImmutableAvlTreeMemDB(b *testing.B) { 117 if testing.Short() { 118 b.Skip("skipping testing in short mode") 119 } 120 121 db, err := db.NewDB("test", db.MemDBBackend, "") 122 require.NoError(b, err) 123 124 b.ResetTimer() 125 126 benchmarkImmutableAvlTreeWithDB(b, db) 127 } 128 129 func benchmarkImmutableAvlTreeWithDB(b *testing.B, db db.DB) { 130 b.Helper() 131 132 defer db.Close() 133 134 b.StopTimer() 135 136 t := NewMutableTree(db, 100000) 137 value := []byte{} 138 for i := 0; i < 1000000; i++ { 139 t.Set(i2b(int(random.RandInt31())), value) 140 if i > 990000 && i%1000 == 999 { 141 t.SaveVersion() 142 } 143 } 144 b.ReportAllocs() 145 t.SaveVersion() 146 147 runtime.GC() 148 149 b.StartTimer() 150 for i := 0; i < b.N; i++ { 151 ri := i2b(int(random.RandInt31())) 152 t.Set(ri, value) 153 t.Remove(ri) 154 if i%100 == 99 { 155 t.SaveVersion() 156 } 157 } 158 }