Files
wehub-resource-sync 5357c39144
Fuzzer / Run Fuzzer (push) Has been cancelled
Race tests / Go race tests (ubuntu-22.04) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:01:40 +08:00

151 lines
3.2 KiB
Go

// Copyright 2022 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tree
import (
"context"
"sync"
"github.com/dolthub/dolt/go/store/prolly/message"
"github.com/dolthub/dolt/go/store/hash"
)
type novelNode struct {
node *Node
lastKey Item
treeCount uint64
addr hash.Hash
}
func writeNewNode[S message.Serializer](ctx context.Context, ns NodeStore, bld *nodeBuilder[S]) (novelNode, error) {
node, err := bld.build()
if err != nil {
return novelNode{}, err
}
addr, err := ns.Write(ctx, node)
if err != nil {
return novelNode{}, err
}
var lastKey Item
if node.Count() > 0 {
k := getLastKey(node)
lastKey = ns.Pool().Get(uint64(len(k)))
copy(lastKey, k)
}
cnt, err := node.TreeCount()
if err != nil {
return novelNode{}, err
}
return novelNode{
addr: addr,
node: node,
lastKey: lastKey,
treeCount: uint64(cnt),
}, nil
}
func newNodeBuilder[S message.Serializer](serializer S, level int) (nb *nodeBuilder[S]) {
nb = &nodeBuilder[S]{
level: level,
serializer: serializer,
}
return
}
type nodeBuilder[S message.Serializer] struct {
serializer S
keys [][]byte
values [][]byte
subtrees subtreeCounts
size int
level int
}
func (nb *nodeBuilder[S]) hasCapacity(key, value Item) bool {
sum := nb.size + len(key) + len(value)
return sum <= int(message.MaxVectorOffset)
}
func (nb *nodeBuilder[S]) addItems(key, value Item, subtree uint64) {
if nb.keys == nil {
nb.keys = getItemSlices()
nb.values = getItemSlices()
nb.subtrees = getSubtreeSlice()
}
nb.keys = append(nb.keys, key)
nb.values = append(nb.values, value)
nb.size += len(key) + len(value)
nb.subtrees = append(nb.subtrees, subtree)
}
func (nb *nodeBuilder[S]) count() int {
return len(nb.keys)
}
func (nb *nodeBuilder[S]) build() (node *Node, err error) {
msg := nb.serializer.Serialize(nb.keys, nb.values, nb.subtrees, nb.level)
nb.recycleBuffers()
nb.size = 0
node, _, err = NodeFromBytes(msg)
return
}
func (nb *nodeBuilder[S]) recycleBuffers() {
putItemSlices(nb.keys[:0])
putItemSlices(nb.values[:0])
putSubtreeSlice(nb.subtrees[:0])
nb.keys = nil
nb.values = nil
nb.subtrees = nil
}
// todo(andy): replace with NodeStore.Pool()
const nodeBuilderListSize = 256
var itemsPool = sync.Pool{
New: func() any {
return make([][]byte, 0, nodeBuilderListSize)
},
}
func getItemSlices() [][]byte {
sl := itemsPool.Get().([][]byte)
return sl[:0]
}
func putItemSlices(sl [][]byte) {
itemsPool.Put(sl[:0])
}
var subtreePool = sync.Pool{
New: func() any {
return make([]uint64, 0, nodeBuilderListSize)
},
}
func getSubtreeSlice() []uint64 {
sl := subtreePool.Get().([]uint64)
return sl[:0]
}
func putSubtreeSlice(sl []uint64) {
subtreePool.Put(sl[:0])
}