btree.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. /*
  2. * Copyright 2020 Dgraph Labs, Inc. and Contributors
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package z
  17. import (
  18. "fmt"
  19. "math"
  20. "os"
  21. "reflect"
  22. "strings"
  23. "unsafe"
  24. "github.com/dgraph-io/ristretto/z/simd"
  25. )
  26. var (
  27. pageSize = os.Getpagesize()
  28. maxKeys = (pageSize / 16) - 1
  29. oneThird = int(float64(maxKeys) / 3)
  30. )
  31. const (
  32. absoluteMax = uint64(math.MaxUint64 - 1)
  33. minSize = 1 << 20
  34. )
  35. // Tree represents the structure for custom mmaped B+ tree.
  36. // It supports keys in range [1, math.MaxUint64-1] and values [1, math.Uint64].
  37. type Tree struct {
  38. buffer *Buffer
  39. data []byte
  40. nextPage uint64
  41. freePage uint64
  42. stats TreeStats
  43. }
  44. func (t *Tree) initRootNode() {
  45. // This is the root node.
  46. t.newNode(0)
  47. // This acts as the rightmost pointer (all the keys are <= this key).
  48. t.Set(absoluteMax, 0)
  49. }
  50. // NewTree returns an in-memory B+ tree.
  51. func NewTree(tag string) *Tree {
  52. const defaultTag = "tree"
  53. if tag == "" {
  54. tag = defaultTag
  55. }
  56. t := &Tree{buffer: NewBuffer(minSize, tag)}
  57. t.Reset()
  58. return t
  59. }
  60. // NewTree returns a persistent on-disk B+ tree.
  61. func NewTreePersistent(path string) (*Tree, error) {
  62. t := &Tree{}
  63. var err error
  64. // Open the buffer from disk and set it to the maximum allocated size.
  65. t.buffer, err = NewBufferPersistent(path, minSize)
  66. if err != nil {
  67. return nil, err
  68. }
  69. t.buffer.offset = uint64(len(t.buffer.buf))
  70. t.data = t.buffer.Bytes()
  71. // pageID can never be 0 if the tree has been initialized.
  72. root := t.node(1)
  73. isInitialized := root.pageID() != 0
  74. if !isInitialized {
  75. t.nextPage = 1
  76. t.freePage = 0
  77. t.initRootNode()
  78. } else {
  79. t.reinit()
  80. }
  81. return t, nil
  82. }
  83. // reinit sets the internal variables of a Tree, which are normally stored
  84. // in-memory, but are lost when loading from disk.
  85. func (t *Tree) reinit() {
  86. // Calculate t.nextPage by finding the first node whose pageID is not set.
  87. t.nextPage = 1
  88. for int(t.nextPage)*pageSize < len(t.data) {
  89. n := t.node(t.nextPage)
  90. if n.pageID() == 0 {
  91. break
  92. }
  93. t.nextPage++
  94. }
  95. maxPageId := t.nextPage - 1
  96. // Calculate t.freePage by finding the page to which no other page points.
  97. // This would be the head of the page linked list.
  98. // tailPages[i] is true if pageId i+1 is not the head of the list.
  99. tailPages := make([]bool, maxPageId)
  100. // Mark all pages containing nodes as tail pages.
  101. t.Iterate(func(n node) {
  102. i := n.pageID() - 1
  103. tailPages[i] = true
  104. // If this is a leaf node, increment the stats.
  105. if n.isLeaf() {
  106. t.stats.NumLeafKeys += n.numKeys()
  107. }
  108. })
  109. // pointedPages is a list of page IDs that the tail pages point to.
  110. pointedPages := make([]uint64, 0)
  111. for i, isTail := range tailPages {
  112. if !isTail {
  113. pageId := uint64(i) + 1
  114. // Skip if nextPageId = 0, as that is equivalent to null page.
  115. if nextPageId := t.node(pageId).uint64(0); nextPageId != 0 {
  116. pointedPages = append(pointedPages, nextPageId)
  117. }
  118. t.stats.NumPagesFree++
  119. }
  120. }
  121. // Mark all pages being pointed to as tail pages.
  122. for _, pageId := range pointedPages {
  123. i := pageId - 1
  124. tailPages[i] = true
  125. }
  126. // There should only be one head page left.
  127. for i, isTail := range tailPages {
  128. if !isTail {
  129. pageId := uint64(i) + 1
  130. t.freePage = pageId
  131. break
  132. }
  133. }
  134. }
  135. // Reset resets the tree and truncates it to maxSz.
  136. func (t *Tree) Reset() {
  137. // Tree relies on uninitialized data being zeroed out, so we need to Memclr
  138. // the data before using it again.
  139. Memclr(t.buffer.buf)
  140. t.buffer.Reset()
  141. t.buffer.AllocateOffset(minSize)
  142. t.data = t.buffer.Bytes()
  143. t.stats = TreeStats{}
  144. t.nextPage = 1
  145. t.freePage = 0
  146. t.initRootNode()
  147. }
  148. // Close releases the memory used by the tree.
  149. func (t *Tree) Close() error {
  150. if t == nil {
  151. return nil
  152. }
  153. return t.buffer.Release()
  154. }
  155. type TreeStats struct {
  156. Allocated int // Derived.
  157. Bytes int // Derived.
  158. NumLeafKeys int // Calculated.
  159. NumPages int // Derived.
  160. NumPagesFree int // Calculated.
  161. Occupancy float64 // Derived.
  162. PageSize int // Derived.
  163. }
  164. // Stats returns stats about the tree.
  165. func (t *Tree) Stats() TreeStats {
  166. numPages := int(t.nextPage - 1)
  167. out := TreeStats{
  168. Bytes: numPages * pageSize,
  169. Allocated: len(t.data),
  170. NumLeafKeys: t.stats.NumLeafKeys,
  171. NumPages: numPages,
  172. NumPagesFree: t.stats.NumPagesFree,
  173. PageSize: pageSize,
  174. }
  175. out.Occupancy = 100.0 * float64(out.NumLeafKeys) / float64(maxKeys*numPages)
  176. return out
  177. }
  178. // BytesToUint64Slice converts a byte slice to a uint64 slice.
  179. func BytesToUint64Slice(b []byte) []uint64 {
  180. if len(b) == 0 {
  181. return nil
  182. }
  183. var u64s []uint64
  184. hdr := (*reflect.SliceHeader)(unsafe.Pointer(&u64s))
  185. hdr.Len = len(b) / 8
  186. hdr.Cap = hdr.Len
  187. hdr.Data = uintptr(unsafe.Pointer(&b[0]))
  188. return u64s
  189. }
  190. func (t *Tree) newNode(bit uint64) node {
  191. var pageId uint64
  192. if t.freePage > 0 {
  193. pageId = t.freePage
  194. t.stats.NumPagesFree--
  195. } else {
  196. pageId = t.nextPage
  197. t.nextPage++
  198. offset := int(pageId) * pageSize
  199. reqSize := offset + pageSize
  200. if reqSize > len(t.data) {
  201. t.buffer.AllocateOffset(reqSize - len(t.data))
  202. t.data = t.buffer.Bytes()
  203. }
  204. }
  205. n := t.node(pageId)
  206. if t.freePage > 0 {
  207. t.freePage = n.uint64(0)
  208. }
  209. zeroOut(n)
  210. n.setBit(bit)
  211. n.setAt(keyOffset(maxKeys), pageId)
  212. return n
  213. }
  214. func getNode(data []byte) node {
  215. return node(BytesToUint64Slice(data))
  216. }
  217. func zeroOut(data []uint64) {
  218. for i := 0; i < len(data); i++ {
  219. data[i] = 0
  220. }
  221. }
  222. func (t *Tree) node(pid uint64) node {
  223. // page does not exist
  224. if pid == 0 {
  225. return nil
  226. }
  227. start := pageSize * int(pid)
  228. return getNode(t.data[start : start+pageSize])
  229. }
  230. // Set sets the key-value pair in the tree.
  231. func (t *Tree) Set(k, v uint64) {
  232. if k == math.MaxUint64 || k == 0 {
  233. panic("Error setting zero or MaxUint64")
  234. }
  235. root := t.set(1, k, v)
  236. if root.isFull() {
  237. right := t.split(1)
  238. left := t.newNode(root.bits())
  239. // Re-read the root as the underlying buffer for tree might have changed during split.
  240. root = t.node(1)
  241. copy(left[:keyOffset(maxKeys)], root)
  242. left.setNumKeys(root.numKeys())
  243. // reset the root node.
  244. zeroOut(root[:keyOffset(maxKeys)])
  245. root.setNumKeys(0)
  246. // set the pointers for left and right child in the root node.
  247. root.set(left.maxKey(), left.pageID())
  248. root.set(right.maxKey(), right.pageID())
  249. }
  250. }
  251. // For internal nodes, they contain <key, ptr>.
  252. // where all entries <= key are stored in the corresponding ptr.
  253. func (t *Tree) set(pid, k, v uint64) node {
  254. n := t.node(pid)
  255. if n.isLeaf() {
  256. t.stats.NumLeafKeys += n.set(k, v)
  257. return n
  258. }
  259. // This is an internal node.
  260. idx := n.search(k)
  261. if idx >= maxKeys {
  262. panic("search returned index >= maxKeys")
  263. }
  264. // If no key at idx.
  265. if n.key(idx) == 0 {
  266. n.setAt(keyOffset(idx), k)
  267. n.setNumKeys(n.numKeys() + 1)
  268. }
  269. child := t.node(n.val(idx))
  270. if child == nil {
  271. child = t.newNode(bitLeaf)
  272. n = t.node(pid)
  273. n.setAt(valOffset(idx), child.pageID())
  274. }
  275. child = t.set(child.pageID(), k, v)
  276. // Re-read n as the underlying buffer for tree might have changed during set.
  277. n = t.node(pid)
  278. if child.isFull() {
  279. // Just consider the left sibling for simplicity.
  280. // if t.shareWithSibling(n, idx) {
  281. // return n
  282. // }
  283. nn := t.split(child.pageID())
  284. // Re-read n and child as the underlying buffer for tree might have changed during split.
  285. n = t.node(pid)
  286. child = t.node(n.uint64(valOffset(idx)))
  287. // Set child pointers in the node n.
  288. // Note that key for right node (nn) already exist in node n, but the
  289. // pointer is updated.
  290. n.set(child.maxKey(), child.pageID())
  291. n.set(nn.maxKey(), nn.pageID())
  292. }
  293. return n
  294. }
  295. // Get looks for key and returns the corresponding value.
  296. // If key is not found, 0 is returned.
  297. func (t *Tree) Get(k uint64) uint64 {
  298. if k == math.MaxUint64 || k == 0 {
  299. panic("Does not support getting MaxUint64/Zero")
  300. }
  301. root := t.node(1)
  302. return t.get(root, k)
  303. }
  304. func (t *Tree) get(n node, k uint64) uint64 {
  305. if n.isLeaf() {
  306. return n.get(k)
  307. }
  308. // This is internal node
  309. idx := n.search(k)
  310. if idx == n.numKeys() || n.key(idx) == 0 {
  311. return 0
  312. }
  313. child := t.node(n.uint64(valOffset(idx)))
  314. assert(child != nil)
  315. return t.get(child, k)
  316. }
  317. // DeleteBelow deletes all keys with value under ts.
  318. func (t *Tree) DeleteBelow(ts uint64) {
  319. root := t.node(1)
  320. t.stats.NumLeafKeys = 0
  321. t.compact(root, ts)
  322. assert(root.numKeys() >= 1)
  323. }
  324. func (t *Tree) compact(n node, ts uint64) int {
  325. if n.isLeaf() {
  326. numKeys := n.compact(ts)
  327. t.stats.NumLeafKeys += n.numKeys()
  328. return numKeys
  329. }
  330. // Not leaf.
  331. N := n.numKeys()
  332. for i := 0; i < N; i++ {
  333. assert(n.key(i) > 0)
  334. childID := n.uint64(valOffset(i))
  335. child := t.node(childID)
  336. if rem := t.compact(child, ts); rem == 0 && i < N-1 {
  337. // If no valid key is remaining we can drop this child. However, don't do that if this
  338. // is the max key.
  339. t.stats.NumLeafKeys -= child.numKeys()
  340. child.setAt(0, t.freePage)
  341. t.freePage = childID
  342. n.setAt(valOffset(i), 0)
  343. t.stats.NumPagesFree++
  344. }
  345. }
  346. // We use ts=1 here because we want to delete all the keys whose value is 0, which means they no
  347. // longer have a valid page for that key.
  348. return n.compact(1)
  349. }
  350. func (t *Tree) iterate(n node, fn func(node)) {
  351. fn(n)
  352. if n.isLeaf() {
  353. return
  354. }
  355. // Explore children.
  356. for i := 0; i < maxKeys; i++ {
  357. if n.key(i) == 0 {
  358. return
  359. }
  360. childID := n.uint64(valOffset(i))
  361. assert(childID > 0)
  362. child := t.node(childID)
  363. t.iterate(child, fn)
  364. }
  365. }
  366. // Iterate iterates over the tree and executes the fn on each node.
  367. func (t *Tree) Iterate(fn func(node)) {
  368. root := t.node(1)
  369. t.iterate(root, fn)
  370. }
  371. // IterateKV iterates through all keys and values in the tree.
  372. // If newVal is non-zero, it will be set in the tree.
  373. func (t *Tree) IterateKV(f func(key, val uint64) (newVal uint64)) {
  374. t.Iterate(func(n node) {
  375. // Only leaf nodes contain keys.
  376. if !n.isLeaf() {
  377. return
  378. }
  379. for i := 0; i < n.numKeys(); i++ {
  380. key := n.key(i)
  381. val := n.val(i)
  382. // A zero value here means that this is a bogus entry.
  383. if val == 0 {
  384. continue
  385. }
  386. newVal := f(key, val)
  387. if newVal != 0 {
  388. n.setAt(valOffset(i), newVal)
  389. }
  390. }
  391. })
  392. }
  393. func (t *Tree) print(n node, parentID uint64) {
  394. n.print(parentID)
  395. if n.isLeaf() {
  396. return
  397. }
  398. pid := n.pageID()
  399. for i := 0; i < maxKeys; i++ {
  400. if n.key(i) == 0 {
  401. return
  402. }
  403. childID := n.uint64(valOffset(i))
  404. child := t.node(childID)
  405. t.print(child, pid)
  406. }
  407. }
  408. // Print iterates over the tree and prints all valid KVs.
  409. func (t *Tree) Print() {
  410. root := t.node(1)
  411. t.print(root, 0)
  412. }
  413. // Splits the node into two. It moves right half of the keys from the original node to a newly
  414. // created right node. It returns the right node.
  415. func (t *Tree) split(pid uint64) node {
  416. n := t.node(pid)
  417. if !n.isFull() {
  418. panic("This should be called only when n is full")
  419. }
  420. // Create a new node nn, copy over half the keys from n, and set the parent to n's parent.
  421. nn := t.newNode(n.bits())
  422. // Re-read n as the underlying buffer for tree might have changed during newNode.
  423. n = t.node(pid)
  424. rightHalf := n[keyOffset(maxKeys/2):keyOffset(maxKeys)]
  425. copy(nn, rightHalf)
  426. nn.setNumKeys(maxKeys - maxKeys/2)
  427. // Remove entries from node n.
  428. zeroOut(rightHalf)
  429. n.setNumKeys(maxKeys / 2)
  430. return nn
  431. }
  432. // shareWithSiblingXXX is unused for now. The idea is to move some keys to
  433. // sibling when a node is full. But, I don't see any special benefits in our
  434. // access pattern. It doesn't result in better occupancy ratios.
  435. func (t *Tree) shareWithSiblingXXX(n node, idx int) bool {
  436. if idx == 0 {
  437. return false
  438. }
  439. left := t.node(n.val(idx - 1))
  440. ns := left.numKeys()
  441. if ns >= maxKeys/2 {
  442. // Sibling is already getting full.
  443. return false
  444. }
  445. right := t.node(n.val(idx))
  446. // Copy over keys from right child to left child.
  447. copied := copy(left[keyOffset(ns):], right[:keyOffset(oneThird)])
  448. copied /= 2 // Considering that key-val constitute one key.
  449. left.setNumKeys(ns + copied)
  450. // Update the max key in parent node n for the left sibling.
  451. n.setAt(keyOffset(idx-1), left.maxKey())
  452. // Now move keys to left for the right sibling.
  453. until := copy(right, right[keyOffset(oneThird):keyOffset(maxKeys)])
  454. right.setNumKeys(until / 2)
  455. zeroOut(right[until:keyOffset(maxKeys)])
  456. return true
  457. }
  458. // Each node in the node is of size pageSize. Two kinds of nodes. Leaf nodes and internal nodes.
  459. // Leaf nodes only contain the data. Internal nodes would contain the key and the offset to the
  460. // child node.
  461. // Internal node would have first entry as
  462. // <0 offset to child>, <1000 offset>, <5000 offset>, and so on...
  463. // Leaf nodes would just have: <key, value>, <key, value>, and so on...
  464. // Last 16 bytes of the node are off limits.
  465. // | pageID (8 bytes) | metaBits (1 byte) | 3 free bytes | numKeys (4 bytes) |
  466. type node []uint64
  467. func (n node) uint64(start int) uint64 { return n[start] }
  468. // func (n node) uint32(start int) uint32 { return *(*uint32)(unsafe.Pointer(&n[start])) }
  469. func keyOffset(i int) int { return 2 * i }
  470. func valOffset(i int) int { return 2*i + 1 }
  471. func (n node) numKeys() int { return int(n.uint64(valOffset(maxKeys)) & 0xFFFFFFFF) }
  472. func (n node) pageID() uint64 { return n.uint64(keyOffset(maxKeys)) }
  473. func (n node) key(i int) uint64 { return n.uint64(keyOffset(i)) }
  474. func (n node) val(i int) uint64 { return n.uint64(valOffset(i)) }
  475. func (n node) data(i int) []uint64 { return n[keyOffset(i):keyOffset(i+1)] }
  476. func (n node) setAt(start int, k uint64) {
  477. n[start] = k
  478. }
  479. func (n node) setNumKeys(num int) {
  480. idx := valOffset(maxKeys)
  481. val := n[idx]
  482. val &= 0xFFFFFFFF00000000
  483. val |= uint64(num)
  484. n[idx] = val
  485. }
  486. func (n node) moveRight(lo int) {
  487. hi := n.numKeys()
  488. assert(hi != maxKeys)
  489. // copy works despite of overlap in src and dst.
  490. // See https://golang.org/pkg/builtin/#copy
  491. copy(n[keyOffset(lo+1):keyOffset(hi+1)], n[keyOffset(lo):keyOffset(hi)])
  492. }
  493. const (
  494. bitLeaf = uint64(1 << 63)
  495. )
  496. func (n node) setBit(b uint64) {
  497. vo := valOffset(maxKeys)
  498. val := n[vo]
  499. val &= 0xFFFFFFFF
  500. val |= b
  501. n[vo] = val
  502. }
  503. func (n node) bits() uint64 {
  504. return n.val(maxKeys) & 0xFF00000000000000
  505. }
  506. func (n node) isLeaf() bool {
  507. return n.bits()&bitLeaf > 0
  508. }
  509. // isFull checks that the node is already full.
  510. func (n node) isFull() bool {
  511. return n.numKeys() == maxKeys
  512. }
  513. // Search returns the index of a smallest key >= k in a node.
  514. func (n node) search(k uint64) int {
  515. N := n.numKeys()
  516. if N < 4 {
  517. for i := 0; i < N; i++ {
  518. if ki := n.key(i); ki >= k {
  519. return i
  520. }
  521. }
  522. return N
  523. }
  524. return int(simd.Search(n[:2*N], k))
  525. // lo, hi := 0, N
  526. // // Reduce the search space using binary seach and then do linear search.
  527. // for hi-lo > 32 {
  528. // mid := (hi + lo) / 2
  529. // km := n.key(mid)
  530. // if k == km {
  531. // return mid
  532. // }
  533. // if k > km {
  534. // // key is greater than the key at mid, so move right.
  535. // lo = mid + 1
  536. // } else {
  537. // // else move left.
  538. // hi = mid
  539. // }
  540. // }
  541. // for i := lo; i <= hi; i++ {
  542. // if ki := n.key(i); ki >= k {
  543. // return i
  544. // }
  545. // }
  546. // return N
  547. }
  548. func (n node) maxKey() uint64 {
  549. idx := n.numKeys()
  550. // idx points to the first key which is zero.
  551. if idx > 0 {
  552. idx--
  553. }
  554. return n.key(idx)
  555. }
  556. // compacts the node i.e., remove all the kvs with value < lo. It returns the remaining number of
  557. // keys.
  558. func (n node) compact(lo uint64) int {
  559. N := n.numKeys()
  560. mk := n.maxKey()
  561. var left, right int
  562. for right = 0; right < N; right++ {
  563. if n.val(right) < lo && n.key(right) < mk {
  564. // Skip over this key. Don't copy it.
  565. continue
  566. }
  567. // Valid data. Copy it from right to left. Advance left.
  568. if left != right {
  569. copy(n.data(left), n.data(right))
  570. }
  571. left++
  572. }
  573. // zero out rest of the kv pairs.
  574. zeroOut(n[keyOffset(left):keyOffset(right)])
  575. n.setNumKeys(left)
  576. // If the only key we have is the max key, and its value is less than lo, then we can indicate
  577. // to the caller by returning a zero that it's OK to drop the node.
  578. if left == 1 && n.key(0) == mk && n.val(0) < lo {
  579. return 0
  580. }
  581. return left
  582. }
  583. func (n node) get(k uint64) uint64 {
  584. idx := n.search(k)
  585. // key is not found
  586. if idx == n.numKeys() {
  587. return 0
  588. }
  589. if ki := n.key(idx); ki == k {
  590. return n.val(idx)
  591. }
  592. return 0
  593. }
  594. // set returns true if it added a new key.
  595. func (n node) set(k, v uint64) (numAdded int) {
  596. idx := n.search(k)
  597. ki := n.key(idx)
  598. if n.numKeys() == maxKeys {
  599. // This happens during split of non-root node, when we are updating the child pointer of
  600. // right node. Hence, the key should already exist.
  601. assert(ki == k)
  602. }
  603. if ki > k {
  604. // Found the first entry which is greater than k. So, we need to fit k
  605. // just before it. For that, we should move the rest of the data in the
  606. // node to the right to make space for k.
  607. n.moveRight(idx)
  608. }
  609. // If the k does not exist already, increment the number of keys.
  610. if ki != k {
  611. n.setNumKeys(n.numKeys() + 1)
  612. numAdded = 1
  613. }
  614. if ki == 0 || ki >= k {
  615. n.setAt(keyOffset(idx), k)
  616. n.setAt(valOffset(idx), v)
  617. return
  618. }
  619. panic("shouldn't reach here")
  620. }
  621. func (n node) iterate(fn func(node, int)) {
  622. for i := 0; i < maxKeys; i++ {
  623. if k := n.key(i); k > 0 {
  624. fn(n, i)
  625. } else {
  626. break
  627. }
  628. }
  629. }
  630. func (n node) print(parentID uint64) {
  631. var keys []string
  632. n.iterate(func(n node, i int) {
  633. keys = append(keys, fmt.Sprintf("%d", n.key(i)))
  634. })
  635. if len(keys) > 8 {
  636. copy(keys[4:], keys[len(keys)-4:])
  637. keys[3] = "..."
  638. keys = keys[:8]
  639. }
  640. fmt.Printf("%d Child of: %d num keys: %d keys: %s\n",
  641. n.pageID(), parentID, n.numKeys(), strings.Join(keys, " "))
  642. }