node_test.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. package bbolt
  2. import (
  3. "testing"
  4. "unsafe"
  5. )
  6. // Ensure that a node can insert a key/value.
  7. func TestNode_put(t *testing.T) {
  8. n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{meta: &meta{pgid: 1}}}}
  9. n.put([]byte("baz"), []byte("baz"), []byte("2"), 0, 0)
  10. n.put([]byte("foo"), []byte("foo"), []byte("0"), 0, 0)
  11. n.put([]byte("bar"), []byte("bar"), []byte("1"), 0, 0)
  12. n.put([]byte("foo"), []byte("foo"), []byte("3"), 0, leafPageFlag)
  13. if len(n.inodes) != 3 {
  14. t.Fatalf("exp=3; got=%d", len(n.inodes))
  15. }
  16. if k, v := n.inodes[0].key, n.inodes[0].value; string(k) != "bar" || string(v) != "1" {
  17. t.Fatalf("exp=<bar,1>; got=<%s,%s>", k, v)
  18. }
  19. if k, v := n.inodes[1].key, n.inodes[1].value; string(k) != "baz" || string(v) != "2" {
  20. t.Fatalf("exp=<baz,2>; got=<%s,%s>", k, v)
  21. }
  22. if k, v := n.inodes[2].key, n.inodes[2].value; string(k) != "foo" || string(v) != "3" {
  23. t.Fatalf("exp=<foo,3>; got=<%s,%s>", k, v)
  24. }
  25. if n.inodes[2].flags != uint32(leafPageFlag) {
  26. t.Fatalf("not a leaf: %d", n.inodes[2].flags)
  27. }
  28. }
  29. // Ensure that a node can deserialize from a leaf page.
  30. func TestNode_read_LeafPage(t *testing.T) {
  31. // Create a page.
  32. var buf [4096]byte
  33. page := (*page)(unsafe.Pointer(&buf[0]))
  34. page.flags = leafPageFlag
  35. page.count = 2
  36. // Insert 2 elements at the beginning. sizeof(leafPageElement) == 16
  37. nodes := (*[3]leafPageElement)(unsafe.Pointer(&page.ptr))
  38. nodes[0] = leafPageElement{flags: 0, pos: 32, ksize: 3, vsize: 4} // pos = sizeof(leafPageElement) * 2
  39. nodes[1] = leafPageElement{flags: 0, pos: 23, ksize: 10, vsize: 3} // pos = sizeof(leafPageElement) + 3 + 4
  40. // Write data for the nodes at the end.
  41. data := (*[4096]byte)(unsafe.Pointer(&nodes[2]))
  42. copy(data[:], []byte("barfooz"))
  43. copy(data[7:], []byte("helloworldbye"))
  44. // Deserialize page into a leaf.
  45. n := &node{}
  46. n.read(page)
  47. // Check that there are two inodes with correct data.
  48. if !n.isLeaf {
  49. t.Fatal("expected leaf")
  50. }
  51. if len(n.inodes) != 2 {
  52. t.Fatalf("exp=2; got=%d", len(n.inodes))
  53. }
  54. if k, v := n.inodes[0].key, n.inodes[0].value; string(k) != "bar" || string(v) != "fooz" {
  55. t.Fatalf("exp=<bar,fooz>; got=<%s,%s>", k, v)
  56. }
  57. if k, v := n.inodes[1].key, n.inodes[1].value; string(k) != "helloworld" || string(v) != "bye" {
  58. t.Fatalf("exp=<helloworld,bye>; got=<%s,%s>", k, v)
  59. }
  60. }
  61. // Ensure that a node can serialize into a leaf page.
  62. func TestNode_write_LeafPage(t *testing.T) {
  63. // Create a node.
  64. n := &node{isLeaf: true, inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}}
  65. n.put([]byte("susy"), []byte("susy"), []byte("que"), 0, 0)
  66. n.put([]byte("ricki"), []byte("ricki"), []byte("lake"), 0, 0)
  67. n.put([]byte("john"), []byte("john"), []byte("johnson"), 0, 0)
  68. // Write it to a page.
  69. var buf [4096]byte
  70. p := (*page)(unsafe.Pointer(&buf[0]))
  71. n.write(p)
  72. // Read the page back in.
  73. n2 := &node{}
  74. n2.read(p)
  75. // Check that the two pages are the same.
  76. if len(n2.inodes) != 3 {
  77. t.Fatalf("exp=3; got=%d", len(n2.inodes))
  78. }
  79. if k, v := n2.inodes[0].key, n2.inodes[0].value; string(k) != "john" || string(v) != "johnson" {
  80. t.Fatalf("exp=<john,johnson>; got=<%s,%s>", k, v)
  81. }
  82. if k, v := n2.inodes[1].key, n2.inodes[1].value; string(k) != "ricki" || string(v) != "lake" {
  83. t.Fatalf("exp=<ricki,lake>; got=<%s,%s>", k, v)
  84. }
  85. if k, v := n2.inodes[2].key, n2.inodes[2].value; string(k) != "susy" || string(v) != "que" {
  86. t.Fatalf("exp=<susy,que>; got=<%s,%s>", k, v)
  87. }
  88. }
  89. // Ensure that a node can split into appropriate subgroups.
  90. func TestNode_split(t *testing.T) {
  91. // Create a node.
  92. n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}}
  93. n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0)
  94. n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0)
  95. n.put([]byte("00000003"), []byte("00000003"), []byte("0123456701234567"), 0, 0)
  96. n.put([]byte("00000004"), []byte("00000004"), []byte("0123456701234567"), 0, 0)
  97. n.put([]byte("00000005"), []byte("00000005"), []byte("0123456701234567"), 0, 0)
  98. // Split between 2 & 3.
  99. n.split(100)
  100. var parent = n.parent
  101. if len(parent.children) != 2 {
  102. t.Fatalf("exp=2; got=%d", len(parent.children))
  103. }
  104. if len(parent.children[0].inodes) != 2 {
  105. t.Fatalf("exp=2; got=%d", len(parent.children[0].inodes))
  106. }
  107. if len(parent.children[1].inodes) != 3 {
  108. t.Fatalf("exp=3; got=%d", len(parent.children[1].inodes))
  109. }
  110. }
  111. // Ensure that a page with the minimum number of inodes just returns a single node.
  112. func TestNode_split_MinKeys(t *testing.T) {
  113. // Create a node.
  114. n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}}
  115. n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0)
  116. n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0)
  117. // Split.
  118. n.split(20)
  119. if n.parent != nil {
  120. t.Fatalf("expected nil parent")
  121. }
  122. }
  123. // Ensure that a node that has keys that all fit on a page just returns one leaf.
  124. func TestNode_split_SinglePage(t *testing.T) {
  125. // Create a node.
  126. n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}}
  127. n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0)
  128. n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0)
  129. n.put([]byte("00000003"), []byte("00000003"), []byte("0123456701234567"), 0, 0)
  130. n.put([]byte("00000004"), []byte("00000004"), []byte("0123456701234567"), 0, 0)
  131. n.put([]byte("00000005"), []byte("00000005"), []byte("0123456701234567"), 0, 0)
  132. // Split.
  133. n.split(4096)
  134. if n.parent != nil {
  135. t.Fatalf("expected nil parent")
  136. }
  137. }