github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/store/prolly/tree/node_builder.go (about) 1 // Copyright 2022 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package tree 16 17 import ( 18 "context" 19 "sync" 20 21 "github.com/dolthub/dolt/go/store/prolly/message" 22 23 "github.com/dolthub/dolt/go/store/hash" 24 ) 25 26 type novelNode struct { 27 node Node 28 addr hash.Hash 29 lastKey Item 30 treeCount uint64 31 } 32 33 func writeNewNode[S message.Serializer](ctx context.Context, ns NodeStore, bld *nodeBuilder[S]) (novelNode, error) { 34 node, err := bld.build() 35 if err != nil { 36 return novelNode{}, err 37 } 38 39 addr, err := ns.Write(ctx, node) 40 if err != nil { 41 return novelNode{}, err 42 } 43 44 var lastKey Item 45 if node.count > 0 { 46 k := getLastKey(node) 47 lastKey = ns.Pool().Get(uint64(len(k))) 48 copy(lastKey, k) 49 } 50 51 cnt, err := node.TreeCount() 52 if err != nil { 53 return novelNode{}, err 54 } 55 56 return novelNode{ 57 addr: addr, 58 node: node, 59 lastKey: lastKey, 60 treeCount: uint64(cnt), 61 }, nil 62 } 63 64 func newNodeBuilder[S message.Serializer](serializer S, level int) (nb *nodeBuilder[S]) { 65 nb = &nodeBuilder[S]{ 66 level: level, 67 serializer: serializer, 68 } 69 return 70 } 71 72 type nodeBuilder[S message.Serializer] struct { 73 keys, values [][]byte 74 size, level int 75 subtrees subtreeCounts 76 serializer S 77 } 78 79 func (nb *nodeBuilder[S]) hasCapacity(key, value Item) bool { 80 sum := nb.size + len(key) + len(value) 81 return sum <= int(message.MaxVectorOffset) 82 } 83 84 func (nb *nodeBuilder[S]) addItems(key, value Item, subtree uint64) { 85 if nb.keys == nil { 86 nb.keys = getItemSlices() 87 nb.values = getItemSlices() 88 nb.subtrees = getSubtreeSlice() 89 } 90 nb.keys = append(nb.keys, key) 91 nb.values = append(nb.values, value) 92 nb.size += len(key) + len(value) 93 nb.subtrees = append(nb.subtrees, subtree) 94 } 95 96 func (nb *nodeBuilder[S]) count() int { 97 return len(nb.keys) 98 } 99 100 func (nb *nodeBuilder[S]) build() (node Node, err error) { 101 msg := nb.serializer.Serialize(nb.keys, nb.values, nb.subtrees, nb.level) 102 nb.recycleBuffers() 103 nb.size = 0 104 return NodeFromBytes(msg) 105 } 106 107 func (nb *nodeBuilder[S]) recycleBuffers() { 108 putItemSlices(nb.keys[:0]) 109 putItemSlices(nb.values[:0]) 110 putSubtreeSlice(nb.subtrees[:0]) 111 nb.keys = nil 112 nb.values = nil 113 nb.subtrees = nil 114 } 115 116 // todo(andy): replace with NodeStore.Pool() 117 const nodeBuilderListSize = 256 118 119 var itemsPool = sync.Pool{ 120 New: func() any { 121 return make([][]byte, 0, nodeBuilderListSize) 122 }, 123 } 124 125 func getItemSlices() [][]byte { 126 sl := itemsPool.Get().([][]byte) 127 return sl[:0] 128 } 129 130 func putItemSlices(sl [][]byte) { 131 itemsPool.Put(sl[:0]) 132 } 133 134 var subtreePool = sync.Pool{ 135 New: func() any { 136 return make([]uint64, 0, nodeBuilderListSize) 137 }, 138 } 139 140 func getSubtreeSlice() []uint64 { 141 sl := subtreePool.Get().([]uint64) 142 return sl[:0] 143 } 144 145 func putSubtreeSlice(sl []uint64) { 146 subtreePool.Put(sl[:0]) 147 }