Move ImmutableTree to val package as ImmutableValue, and move TextStorage and ByteArray into the val package.

This commit is contained in:
Nick Tobey
2025-02-28 09:44:14 -08:00
parent 068a396f1c
commit 3771c191ab
6 changed files with 123 additions and 107 deletions
@@ -869,7 +869,7 @@ func encodeBytesFromAddress(ctx *sql.Context, addr hash.Hash, ns tree.NodeStore,
if ns == nil {
return nil, fmt.Errorf("nil NodeStore used to encode bytes from address")
}
bytes, err := tree.NewByteArray(addr, ns).ToBytes(ctx)
bytes, err := ns.ReadBytes(ctx, addr)
if err != nil {
return nil, err
}
+8 -99
View File
@@ -15,9 +15,9 @@
package tree
import (
"bytes"
"context"
"errors"
"github.com/dolthub/dolt/go/store/val"
"io"
"github.com/dolthub/go-mysql-server/sql"
@@ -243,42 +243,17 @@ func (b *BlobBuilder) write(ctx context.Context, keys, vals [][]byte, subtrees [
return h, nil
}
const bytePeekLength = 128
type ByteArray struct {
ImmutableTree
}
func NewByteArray(addr hash.Hash, ns NodeStore) *ByteArray {
return &ByteArray{ImmutableTree{Addr: addr, ns: ns}}
}
func (b *ByteArray) ToBytes(ctx context.Context) ([]byte, error) {
return b.bytes(ctx)
}
func (b *ByteArray) ToString(ctx context.Context) (string, error) {
buf, err := b.bytes(ctx)
if err != nil {
return "", err
}
toShow := bytePeekLength
if len(buf) < toShow {
toShow = len(buf)
}
return string(buf[:toShow]), nil
}
type JSONDoc struct {
ImmutableTree
val.ImmutableValue
ns NodeStore
}
func NewJSONDoc(addr hash.Hash, ns NodeStore) *JSONDoc {
return &JSONDoc{ImmutableTree{Addr: addr, ns: ns}}
return &JSONDoc{ImmutableValue: val.NewImmutableValue(addr, ns), ns: ns}
}
func (b *JSONDoc) ToJSONDocument(ctx context.Context) (sqltypes.JSONDocument, error) {
buf, err := b.bytes(ctx)
buf, err := b.GetBytes(ctx)
if err != nil {
return sqltypes.JSONDocument{}, err
}
@@ -291,7 +266,7 @@ func (b *JSONDoc) ToJSONDocument(ctx context.Context) (sqltypes.JSONDocument, er
}
func (b *JSONDoc) ToLazyJSONDocument(ctx context.Context) (sql.JSONWrapper, error) {
buf, err := b.bytes(ctx)
buf, err := b.GetBytes(ctx)
if err != nil {
return sqltypes.JSONDocument{}, err
}
@@ -312,79 +287,13 @@ func (b *JSONDoc) ToIndexedJSONDocument(ctx context.Context) (sql.JSONWrapper, e
}
func (b *JSONDoc) ToString(ctx context.Context) (string, error) {
buf, err := b.bytes(ctx)
buf, err := b.GetBytes(ctx)
if err != nil {
return "", err
}
toShow := bytePeekLength
toShow := val.BytePeekLength
if len(buf) < toShow {
toShow = len(buf)
}
return string(buf[:toShow]), nil
}
type TextStorage struct {
ImmutableTree
}
func NewTextStorage(addr hash.Hash, ns NodeStore) *TextStorage {
return &TextStorage{ImmutableTree{Addr: addr, ns: ns}}
}
func (b *TextStorage) ToBytes(ctx context.Context) ([]byte, error) {
return b.bytes(ctx)
}
func (b *TextStorage) ToString(ctx context.Context) (string, error) {
buf, err := b.bytes(ctx)
if err != nil {
return "", err
}
return string(buf), nil
}
type ImmutableTree struct {
Addr hash.Hash
buf []byte
ns NodeStore
}
func (t *ImmutableTree) load(ctx context.Context) error {
if t.Addr.IsEmpty() {
t.buf = []byte{}
return nil
}
n, err := t.ns.Read(ctx, t.Addr)
if err != nil {
return err
}
return WalkNodes(ctx, n, t.ns, func(ctx context.Context, n Node) error {
if n.IsLeaf() {
t.buf = append(t.buf, n.GetValue(0)...)
}
return nil
})
}
func (t *ImmutableTree) bytes(ctx context.Context) ([]byte, error) {
if t.buf == nil {
err := t.load(ctx)
if err != nil {
return nil, err
}
}
return t.buf[:], nil
}
func (t *ImmutableTree) next() (Node, error) {
panic("not implemented")
}
func (t *ImmutableTree) close() error {
panic("not implemented")
}
func (t *ImmutableTree) Read(_ bytes.Buffer) (int, error) {
panic("not implemented")
}
+14 -3
View File
@@ -208,8 +208,19 @@ func (ns nodeStore) PurgeCaches() {
ns.cache.purge()
}
func (ns nodeStore) ReadBytes(ctx context.Context, h hash.Hash) ([]byte, error) {
return NewByteArray(h, ns).ToBytes(ctx)
func (ns nodeStore) ReadBytes(ctx context.Context, h hash.Hash) (result []byte, err error) {
n, err := ns.Read(ctx, h)
if err != nil {
return nil, err
}
err = WalkNodes(ctx, n, &ns, func(ctx context.Context, n Node) error {
if n.IsLeaf() {
result = append(result, n.GetValue(0)...)
}
return nil
})
return result, err
}
func (ns nodeStore) WriteBytes(ctx context.Context, b []byte) (hash.Hash, error) {
@@ -217,4 +228,4 @@ func (ns nodeStore) WriteBytes(ctx context.Context, b []byte) (hash.Hash, error)
return h, err
}
var _ val.ValueStore = nodeStore{}
var _ val.ValueStore = &nodeStore{}
+1 -1
View File
@@ -109,7 +109,7 @@ func GetField(ctx context.Context, td val.TupleDesc, i int, tup val.Tuple, ns No
var h hash.Hash
h, ok = td.GetGeometryAddr(i, tup)
if ok {
buf, err = NewByteArray(h, ns).ToBytes(ctx)
buf, err = ns.ReadBytes(ctx, h)
if err != nil {
return nil, err
}
+13 -2
View File
@@ -272,8 +272,19 @@ type nodeStoreValidator struct {
bbp *sync.Pool
}
func (v nodeStoreValidator) ReadBytes(ctx context.Context, h hash.Hash) ([]byte, error) {
panic("not implemented")
func (v nodeStoreValidator) ReadBytes(ctx context.Context, h hash.Hash) (result []byte, err error) {
n, err := v.ns.Read(ctx, h)
if err != nil {
return nil, err
}
err = WalkNodes(ctx, n, &v, func(ctx context.Context, n Node) error {
if n.IsLeaf() {
result = append(result, n.GetValue(0)...)
}
return nil
})
return result, err
}
func (v nodeStoreValidator) WriteBytes(ctx context.Context, val []byte) (hash.Hash, error) {
+86 -1
View File
@@ -16,10 +16,12 @@ package val
import (
"context"
"github.com/dolthub/dolt/go/store/hash"
"github.com/dolthub/go-mysql-server/sql/values"
)
const BytePeekLength = 128
// ValueStore is an interface for a key-value store that can store byte sequences, keyed by a content hash.
// The only implementation is tree.NodeStore, but ValueStore can be used without depending on the tree package.
// This is useful for type handlers.
@@ -27,3 +29,86 @@ type ValueStore interface {
ReadBytes(ctx context.Context, h hash.Hash) ([]byte, error)
WriteBytes(ctx context.Context, val []byte) (hash.Hash, error)
}
// ImmutableValue represents a content-addressed value stored in a ValueStore.
// The contents are loaded lazily and stored in |Buf|
type ImmutableValue struct {
Addr hash.Hash
Buf []byte
vs ValueStore
}
func NewImmutableValue(addr hash.Hash, vs ValueStore) ImmutableValue {
return ImmutableValue{Addr: addr, vs: vs}
}
func (t *ImmutableValue) GetBytes(ctx context.Context) ([]byte, error) {
if t.Buf == nil {
if t.Addr.IsEmpty() {
t.Buf = []byte{}
return t.Buf, nil
}
buf, err := t.vs.ReadBytes(ctx, t.Addr)
if err != nil {
return nil, err
}
t.Buf = buf
}
return t.Buf, nil
}
type TextStorage struct {
ImmutableValue
}
func (t TextStorage) Unwrap(ctx context.Context) (string, error) {
buf, err := t.GetBytes(ctx)
if err != nil {
return "", err
}
return string(buf), nil
}
func (t TextStorage) UnwrapAny(ctx context.Context) (interface{}, error) {
return t.Unwrap(ctx)
}
func NewTextStorage(addr hash.Hash, vs ValueStore) *TextStorage {
return &TextStorage{NewImmutableValue(addr, vs)}
}
var _ values.Wrapper[string] = &TextStorage{}
type ByteArray struct {
ImmutableValue
}
func NewByteArray(addr hash.Hash, vs ValueStore) *ByteArray {
return &ByteArray{NewImmutableValue(addr, vs)}
}
func (b *ByteArray) ToBytes(ctx context.Context) ([]byte, error) {
return b.GetBytes(ctx)
}
func (b *ByteArray) ToAny(ctx context.Context) (interface{}, error) {
return b.ToBytes(ctx)
}
func (b ByteArray) Unwrap(ctx context.Context) ([]byte, error) {
return b.GetBytes(ctx)
}
func (b *ByteArray) ToString(ctx context.Context) (string, error) {
buf, err := b.ToBytes(ctx)
if err != nil {
return "", err
}
toShow := BytePeekLength
if len(buf) < toShow {
toShow = len(buf)
}
return string(buf[:toShow]), nil
}
var _ values.Wrapper[[]byte] = &ByteArray{}