btree.go 18 KB

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