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

214 lines
6.1 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 prolly
import (
"bytes"
"context"
"encoding/binary"
"errors"
"fmt"
"io"
"github.com/dolthub/dolt/go/serial"
"github.com/dolthub/dolt/go/store/hash"
"github.com/dolthub/dolt/go/store/pool"
"github.com/dolthub/dolt/go/store/prolly/message"
"github.com/dolthub/dolt/go/store/prolly/tree"
"github.com/dolthub/dolt/go/store/types"
)
// Closure values are a long (8 bytes) followed by a hash (20 bytes, hash.ByteLen).
const prefixWidth = 8
type CommitClosureValue []byte
type CommitClosure struct {
closure tree.StaticMap[CommitClosureKey, CommitClosureValue, commitClosureKeyOrdering]
}
type commitClosureKeyOrdering struct{}
var _ tree.Ordering[CommitClosureKey] = commitClosureKeyOrdering{}
func (o commitClosureKeyOrdering) Compare(ctx context.Context, left, right CommitClosureKey) (int, error) {
lh, rh := left.Height(), right.Height()
if lh == rh {
return bytes.Compare(left[prefixWidth:], right[prefixWidth:]), nil
} else if lh < rh {
return -1, nil
}
return 1, nil
}
func NewEmptyCommitClosure(ns tree.NodeStore) (CommitClosure, error) {
// TODO: since this is constant, we should make a constant for it
serializer := message.NewCommitClosureSerializer(ns.Pool())
msg := serializer.Serialize(nil, nil, nil, 0)
node, fileId, err := tree.NodeFromBytes(msg)
if fileId != serial.CommitClosureFileID {
return CommitClosure{}, fmt.Errorf("unexpected file ID for commit closure, expected %s, found %s", serial.CommitClosureFileID, fileId)
}
if err != nil {
return CommitClosure{}, err
}
return NewCommitClosure(node, ns)
}
func NewCommitClosure(node *tree.Node, ns tree.NodeStore) (CommitClosure, error) {
return CommitClosure{
closure: tree.StaticMap[CommitClosureKey, CommitClosureValue, commitClosureKeyOrdering]{
Root: node,
NodeStore: ns,
Order: commitClosureKeyOrdering{},
},
}, nil
}
func (c CommitClosure) Count() (int, error) {
return c.closure.Count()
}
func (c CommitClosure) Height() int {
return c.closure.Height()
}
func (c CommitClosure) Node() *tree.Node {
return c.closure.Root
}
func (c CommitClosure) HashOf() hash.Hash {
return c.closure.HashOf()
}
func (c CommitClosure) Format() *types.NomsBinFormat {
return c.closure.NodeStore.Format()
}
func (c CommitClosure) Editor() CommitClosureEditor {
return CommitClosureEditor{
closure: c.closure.Mutate(),
}
}
func (c CommitClosure) IterAllReverse(ctx context.Context) (CommitClosureIter, error) {
return c.closure.IterAllReverse(ctx)
}
func (c CommitClosure) IterHeight(ctx context.Context, height uint64) (CommitClosureIter, error) {
start := NewCommitClosureKey(c.closure.NodeStore.Pool(), height, hash.Hash{})
stop := NewCommitClosureKey(c.closure.NodeStore.Pool(), height+1, hash.Hash{})
return c.closure.IterKeyRange(ctx, start, stop)
}
func (c CommitClosure) IsEmpty() bool {
return c.Node().Size() == 0
}
func (c CommitClosure) ContainsKey(ctx context.Context, h hash.Hash, height uint64) (bool, error) {
k := NewCommitClosureKey(c.closure.NodeStore.Pool(), height, h)
return c.closure.Has(ctx, k)
}
func (c CommitClosure) AsHashSet(ctx context.Context) (hash.HashSet, error) {
closureIter, err := c.IterAllReverse(ctx)
if err != nil {
return hash.HashSet{}, err
}
skipCmts := hash.NewHashSet()
for {
key, _, err := closureIter.Next(ctx)
if err != nil {
if errors.Is(err, io.EOF) {
break
}
return hash.HashSet{}, err
}
clsrHash := hash.New(key[prefixWidth:])
skipCmts.Insert(clsrHash)
}
return skipCmts, nil
}
type CommitClosureEditor struct {
closure tree.MutableMap[CommitClosureKey, CommitClosureValue, commitClosureKeyOrdering, tree.StaticMap[CommitClosureKey, CommitClosureValue, commitClosureKeyOrdering]]
}
type CommitClosureKey []byte
type CommitClosureIter tree.KvIter[CommitClosureKey, CommitClosureValue]
func NewCommitClosureKey(p pool.BuffPool, height uint64, addr hash.Hash) CommitClosureKey {
r := p.Get(prefixWidth + hash.ByteLen)
binary.LittleEndian.PutUint64(r, height)
copy(r[prefixWidth:], addr[:])
return CommitClosureKey(r)
}
func (k CommitClosureKey) Height() uint64 {
return binary.LittleEndian.Uint64(k)
}
func (k CommitClosureKey) Addr() hash.Hash {
return hash.New(k[prefixWidth:])
}
func (k CommitClosureKey) Less(ctx context.Context, other CommitClosureKey) bool {
cmp, err := commitClosureKeyOrdering{}.Compare(ctx, k, other)
if err != nil {
panic(err)
}
return cmp < 0
}
var emptyCommitClosureValue CommitClosureValue = CommitClosureValue(make([]byte, 1))
func (wr CommitClosureEditor) Add(ctx context.Context, key CommitClosureKey) error {
return wr.closure.Put(ctx, key, emptyCommitClosureValue)
}
func (wr CommitClosureEditor) Delete(ctx context.Context, key CommitClosureKey) error {
return wr.closure.Delete(ctx, key)
}
func (wr CommitClosureEditor) Flush(ctx context.Context) (CommitClosure, error) {
sm := wr.closure.Static
serializer := message.NewCommitClosureSerializer(sm.NodeStore.Pool())
fn := tree.ApplyMutations[CommitClosureKey, commitClosureKeyOrdering, message.CommitClosureSerializer]
root, err := fn(ctx, sm.NodeStore, sm.Root, commitClosureKeyOrdering{}, serializer, wr.closure.Mutations())
if err != nil {
return CommitClosure{}, err
}
return CommitClosure{
closure: tree.StaticMap[CommitClosureKey, CommitClosureValue, commitClosureKeyOrdering]{
Root: root,
NodeStore: sm.NodeStore,
Order: sm.Order,
},
}, nil
}
func DiffCommitClosures(ctx context.Context, from, to CommitClosure, cb tree.DiffFn) error {
considerAllRowsModified := false
return tree.DiffOrderedTrees(ctx, from.closure, to.closure, considerAllRowsModified, cb)
}