You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

260 lines
5.9 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. package merkle
  2. import (
  3. "bytes"
  4. "fmt"
  5. "github.com/tendermint/tendermint/binary"
  6. . "github.com/tendermint/tendermint/common"
  7. "github.com/tendermint/tendermint/db"
  8. "runtime"
  9. "testing"
  10. )
  11. func randstr(length int) string {
  12. return RandStr(length)
  13. }
  14. // Convenience for a new node
  15. func N(l, r interface{}) *IAVLNode {
  16. var left, right *IAVLNode
  17. if _, ok := l.(*IAVLNode); ok {
  18. left = l.(*IAVLNode)
  19. } else {
  20. left = NewIAVLNode(l, "")
  21. }
  22. if _, ok := r.(*IAVLNode); ok {
  23. right = r.(*IAVLNode)
  24. } else {
  25. right = NewIAVLNode(r, "")
  26. }
  27. n := &IAVLNode{
  28. key: right.lmd(nil).key,
  29. value: "",
  30. leftNode: left,
  31. rightNode: right,
  32. }
  33. n.calcHeightAndSize(nil)
  34. return n
  35. }
  36. // Setup a deep node
  37. func T(n *IAVLNode) *IAVLTree {
  38. t := NewIAVLTree(binary.BasicCodec, binary.BasicCodec, 0, nil)
  39. n.hashWithCount(t)
  40. t.root = n
  41. return t
  42. }
  43. // Convenience for simple printing of keys & tree structure
  44. func P(n *IAVLNode) string {
  45. if n.height == 0 {
  46. return fmt.Sprintf("%v", n.key)
  47. } else {
  48. return fmt.Sprintf("(%v %v)", P(n.leftNode), P(n.rightNode))
  49. }
  50. }
  51. func TestUnit(t *testing.T) {
  52. expectHash := func(tree *IAVLTree, hashCount uint64) {
  53. // ensure number of new hash calculations is as expected.
  54. hash, count := tree.HashWithCount()
  55. if count != hashCount {
  56. t.Fatalf("Expected %v new hashes, got %v", hashCount, count)
  57. }
  58. // nuke hashes and reconstruct hash, ensure it's the same.
  59. tree.root.traverse(tree, func(node *IAVLNode) bool {
  60. node.hash = nil
  61. return false
  62. })
  63. // ensure that the new hash after nuking is the same as the old.
  64. newHash, _ := tree.HashWithCount()
  65. if bytes.Compare(hash, newHash) != 0 {
  66. t.Fatalf("Expected hash %v but got %v after nuking", hash, newHash)
  67. }
  68. }
  69. expectSet := func(tree *IAVLTree, i int, repr string, hashCount uint64) {
  70. origNode := tree.root
  71. updated := tree.Set(i, "")
  72. // ensure node was added & structure is as expected.
  73. if updated == true || P(tree.root) != repr {
  74. t.Fatalf("Adding %v to %v:\nExpected %v\nUnexpectedly got %v updated:%v",
  75. i, P(origNode), repr, P(tree.root), updated)
  76. }
  77. // ensure hash calculation requirements
  78. expectHash(tree, hashCount)
  79. tree.root = origNode
  80. }
  81. expectRemove := func(tree *IAVLTree, i int, repr string, hashCount uint64) {
  82. origNode := tree.root
  83. value, removed := tree.Remove(i)
  84. // ensure node was added & structure is as expected.
  85. if value != "" || !removed || P(tree.root) != repr {
  86. t.Fatalf("Removing %v from %v:\nExpected %v\nUnexpectedly got %v value:%v removed:%v",
  87. i, P(origNode), repr, P(tree.root), value, removed)
  88. }
  89. // ensure hash calculation requirements
  90. expectHash(tree, hashCount)
  91. tree.root = origNode
  92. }
  93. //////// Test Set cases:
  94. // Case 1:
  95. t1 := T(N(4, 20))
  96. expectSet(t1, 8, "((4 8) 20)", 3)
  97. expectSet(t1, 25, "(4 (20 25))", 3)
  98. t2 := T(N(4, N(20, 25)))
  99. expectSet(t2, 8, "((4 8) (20 25))", 3)
  100. expectSet(t2, 30, "((4 20) (25 30))", 4)
  101. t3 := T(N(N(1, 2), 6))
  102. expectSet(t3, 4, "((1 2) (4 6))", 4)
  103. expectSet(t3, 8, "((1 2) (6 8))", 3)
  104. t4 := T(N(N(1, 2), N(N(5, 6), N(7, 9))))
  105. expectSet(t4, 8, "(((1 2) (5 6)) ((7 8) 9))", 5)
  106. expectSet(t4, 10, "(((1 2) (5 6)) (7 (9 10)))", 5)
  107. //////// Test Remove cases:
  108. t10 := T(N(N(1, 2), 3))
  109. expectRemove(t10, 2, "(1 3)", 1)
  110. expectRemove(t10, 3, "(1 2)", 0)
  111. t11 := T(N(N(N(1, 2), 3), N(4, 5)))
  112. expectRemove(t11, 4, "((1 2) (3 5))", 2)
  113. expectRemove(t11, 3, "((1 2) (4 5))", 1)
  114. }
  115. func TestIntegration(t *testing.T) {
  116. type record struct {
  117. key string
  118. value string
  119. }
  120. records := make([]*record, 400)
  121. var tree *IAVLTree = NewIAVLTree(binary.BasicCodec, binary.BasicCodec, 0, nil)
  122. randomRecord := func() *record {
  123. return &record{randstr(20), randstr(20)}
  124. }
  125. for i := range records {
  126. r := randomRecord()
  127. records[i] = r
  128. //t.Log("New record", r)
  129. //PrintIAVLNode(tree.root)
  130. updated := tree.Set(r.key, "")
  131. if updated {
  132. t.Error("should have not been updated")
  133. }
  134. updated = tree.Set(r.key, r.value)
  135. if !updated {
  136. t.Error("should have been updated")
  137. }
  138. if tree.Size() != uint64(i+1) {
  139. t.Error("size was wrong", tree.Size(), i+1)
  140. }
  141. }
  142. for _, r := range records {
  143. if has := tree.Has(r.key); !has {
  144. t.Error("Missing key", r.key)
  145. }
  146. if has := tree.Has(randstr(12)); has {
  147. t.Error("Table has extra key")
  148. }
  149. if _, val := tree.Get(r.key); val.(string) != r.value {
  150. t.Error("wrong value")
  151. }
  152. }
  153. for i, x := range records {
  154. if val, removed := tree.Remove(x.key); !removed {
  155. t.Error("Wasn't removed")
  156. } else if val != x.value {
  157. t.Error("Wrong value")
  158. }
  159. for _, r := range records[i+1:] {
  160. if has := tree.Has(r.key); !has {
  161. t.Error("Missing key", r.key)
  162. }
  163. if has := tree.Has(randstr(12)); has {
  164. t.Error("Table has extra key")
  165. }
  166. _, val := tree.Get(r.key)
  167. if val != r.value {
  168. t.Error("wrong value")
  169. }
  170. }
  171. if tree.Size() != uint64(len(records)-(i+1)) {
  172. t.Error("size was wrong", tree.Size(), (len(records) - (i + 1)))
  173. }
  174. }
  175. }
  176. func TestPersistence(t *testing.T) {
  177. db := db.NewMemDB()
  178. // Create some random key value pairs
  179. records := make(map[string]string)
  180. for i := 0; i < 10000; i++ {
  181. records[randstr(20)] = randstr(20)
  182. }
  183. // Construct some tree and save it
  184. t1 := NewIAVLTree(binary.BasicCodec, binary.BasicCodec, 0, db)
  185. for key, value := range records {
  186. t1.Set(key, value)
  187. }
  188. t1.Save()
  189. hash, _ := t1.HashWithCount()
  190. // Load a tree
  191. t2 := NewIAVLTree(binary.BasicCodec, binary.BasicCodec, 0, db)
  192. t2.Load(hash)
  193. for key, value := range records {
  194. _, t2value := t2.Get(key)
  195. if t2value != value {
  196. t.Fatalf("Invalid value. Expected %v, got %v", value, t2value)
  197. }
  198. }
  199. }
  200. func BenchmarkImmutableAvlTree(b *testing.B) {
  201. b.StopTimer()
  202. t := NewIAVLTree(binary.BasicCodec, binary.BasicCodec, 0, nil)
  203. // 23000ns/op, 43000ops/s
  204. // for i := 0; i < 10000000; i++ {
  205. for i := 0; i < 1000000; i++ {
  206. t.Set(RandUint64(), "")
  207. }
  208. fmt.Println("ok, starting")
  209. runtime.GC()
  210. b.StartTimer()
  211. for i := 0; i < b.N; i++ {
  212. ri := RandUint64()
  213. t.Set(ri, "")
  214. t.Remove(ri)
  215. }
  216. }