github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/store/prolly/tree/testutils.go (about)

     1  // Copyright 2021 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  	"bytes"
    19  	"context"
    20  	"fmt"
    21  	"math"
    22  	"math/rand"
    23  	"sort"
    24  	"sync"
    25  
    26  	"github.com/dolthub/dolt/go/store/chunks"
    27  	"github.com/dolthub/dolt/go/store/hash"
    28  	"github.com/dolthub/dolt/go/store/pool"
    29  	"github.com/dolthub/dolt/go/store/prolly/message"
    30  	"github.com/dolthub/dolt/go/store/types"
    31  	"github.com/dolthub/dolt/go/store/val"
    32  )
    33  
    34  var testRand = rand.New(rand.NewSource(1))
    35  
    36  func NewTupleLeafNode(keys, values []val.Tuple) Node {
    37  	ks := make([]Item, len(keys))
    38  	for i := range ks {
    39  		ks[i] = Item(keys[i])
    40  	}
    41  	vs := make([]Item, len(values))
    42  	for i := range vs {
    43  		vs[i] = Item(values[i])
    44  	}
    45  	return newLeafNode(ks, vs)
    46  }
    47  
    48  func RandomTuplePairs(count int, keyDesc, valDesc val.TupleDesc, ns NodeStore) (items [][2]val.Tuple) {
    49  	keyBuilder := val.NewTupleBuilder(keyDesc)
    50  	valBuilder := val.NewTupleBuilder(valDesc)
    51  
    52  	items = make([][2]val.Tuple, count)
    53  	for i := range items {
    54  		items[i][0] = RandomTuple(keyBuilder, ns)
    55  		items[i][1] = RandomTuple(valBuilder, ns)
    56  	}
    57  
    58  	dupes := make([]int, 0, count)
    59  	for {
    60  		SortTuplePairs(items, keyDesc)
    61  		for i := range items {
    62  			if i == 0 {
    63  				continue
    64  			}
    65  			if keyDesc.Compare(items[i][0], items[i-1][0]) == 0 {
    66  				dupes = append(dupes, i)
    67  			}
    68  		}
    69  		if len(dupes) == 0 {
    70  			break
    71  		}
    72  
    73  		// replace duplicates and validate again
    74  		for _, d := range dupes {
    75  			items[d][0] = RandomTuple(keyBuilder, ns)
    76  		}
    77  		dupes = dupes[:0]
    78  	}
    79  	return items
    80  }
    81  
    82  func RandomCompositeTuplePairs(count int, keyDesc, valDesc val.TupleDesc, ns NodeStore) (items [][2]val.Tuple) {
    83  	// preconditions
    84  	if count%5 != 0 {
    85  		panic("expected empty divisible by 5")
    86  	}
    87  	if len(keyDesc.Types) < 2 {
    88  		panic("expected composite key")
    89  	}
    90  
    91  	tt := RandomTuplePairs(count, keyDesc, valDesc, ns)
    92  
    93  	tuples := make([][2]val.Tuple, len(tt)*3)
    94  	for i := range tuples {
    95  		j := i % len(tt)
    96  		tuples[i] = tt[j]
    97  	}
    98  
    99  	// permute the second column
   100  	swap := make([]byte, len(tuples[0][0].GetField(1)))
   101  	rand.Shuffle(len(tuples), func(i, j int) {
   102  		f1 := tuples[i][0].GetField(1)
   103  		f2 := tuples[i][0].GetField(1)
   104  		copy(swap, f1)
   105  		copy(f1, f2)
   106  		copy(f2, swap)
   107  	})
   108  
   109  	SortTuplePairs(tuples, keyDesc)
   110  
   111  	tuples = deduplicateTuples(keyDesc, tuples)
   112  
   113  	return tuples[:count]
   114  }
   115  
   116  // Map<Tuple<Uint32>,Tuple<Uint32>>
   117  func AscendingUintTuples(count int) (tuples [][2]val.Tuple, desc val.TupleDesc) {
   118  	desc = val.NewTupleDescriptor(val.Type{Enc: val.Uint32Enc})
   119  	bld := val.NewTupleBuilder(desc)
   120  	tuples = make([][2]val.Tuple, count)
   121  	for i := range tuples {
   122  		bld.PutUint32(0, uint32(i))
   123  		tuples[i][0] = bld.Build(sharedPool)
   124  		bld.PutUint32(0, uint32(i+count))
   125  		tuples[i][1] = bld.Build(sharedPool)
   126  	}
   127  	return
   128  }
   129  
   130  func RandomTuple(tb *val.TupleBuilder, ns NodeStore) (tup val.Tuple) {
   131  	for i, typ := range tb.Desc.Types {
   132  		randomField(tb, i, typ, ns)
   133  	}
   134  	return tb.Build(sharedPool)
   135  }
   136  
   137  func CloneRandomTuples(items [][2]val.Tuple) (clone [][2]val.Tuple) {
   138  	clone = make([][2]val.Tuple, len(items))
   139  	for i := range clone {
   140  		clone[i] = items[i]
   141  	}
   142  	return
   143  }
   144  
   145  func SortTuplePairs(items [][2]val.Tuple, keyDesc val.TupleDesc) {
   146  	sort.Slice(items, func(i, j int) bool {
   147  		return keyDesc.Compare(items[i][0], items[j][0]) < 0
   148  	})
   149  }
   150  
   151  func ShuffleTuplePairs(items [][2]val.Tuple) {
   152  	testRand.Shuffle(len(items), func(i, j int) {
   153  		items[i], items[j] = items[j], items[i]
   154  	})
   155  }
   156  
   157  func NewEmptyTestNode() Node {
   158  	return newLeafNode(nil, nil)
   159  }
   160  
   161  func newLeafNode(keys, values []Item) Node {
   162  	kk := make([][]byte, len(keys))
   163  	for i := range keys {
   164  		kk[i] = keys[i]
   165  	}
   166  	vv := make([][]byte, len(values))
   167  	for i := range vv {
   168  		vv[i] = values[i]
   169  	}
   170  
   171  	s := message.NewProllyMapSerializer(val.TupleDesc{}, sharedPool)
   172  	msg := s.Serialize(kk, vv, nil, 0)
   173  	n, err := NodeFromBytes(msg)
   174  	if err != nil {
   175  		panic(err)
   176  	}
   177  	return n
   178  }
   179  
   180  // assumes a sorted list
   181  func deduplicateTuples(desc val.TupleDesc, tups [][2]val.Tuple) (uniq [][2]val.Tuple) {
   182  	uniq = make([][2]val.Tuple, 1, len(tups))
   183  	uniq[0] = tups[0]
   184  
   185  	for i := 1; i < len(tups); i++ {
   186  		cmp := desc.Compare(tups[i-1][0], tups[i][0])
   187  		if cmp < 0 {
   188  			uniq = append(uniq, tups[i])
   189  		}
   190  	}
   191  	return
   192  }
   193  
   194  func randomField(tb *val.TupleBuilder, idx int, typ val.Type, ns NodeStore) {
   195  	// todo(andy): add NULLs
   196  
   197  	neg := -1
   198  	if testRand.Int()%2 == 1 {
   199  		neg = 1
   200  	}
   201  
   202  	switch typ.Enc {
   203  	case val.Int8Enc:
   204  		v := int8(testRand.Intn(math.MaxInt8) * neg)
   205  		tb.PutInt8(idx, v)
   206  	case val.Uint8Enc:
   207  		v := uint8(testRand.Intn(math.MaxUint8))
   208  		tb.PutUint8(idx, v)
   209  	case val.Int16Enc:
   210  		v := int16(testRand.Intn(math.MaxInt16) * neg)
   211  		tb.PutInt16(idx, v)
   212  	case val.Uint16Enc:
   213  		v := uint16(testRand.Intn(math.MaxUint16))
   214  		tb.PutUint16(idx, v)
   215  	case val.Int32Enc:
   216  		v := testRand.Int31() * int32(neg)
   217  		tb.PutInt32(idx, v)
   218  	case val.Uint32Enc:
   219  		v := testRand.Uint32()
   220  		tb.PutUint32(idx, v)
   221  	case val.Int64Enc:
   222  		v := testRand.Int63() * int64(neg)
   223  		tb.PutInt64(idx, v)
   224  	case val.Uint64Enc:
   225  		v := testRand.Uint64()
   226  		tb.PutUint64(idx, v)
   227  	case val.Float32Enc:
   228  		tb.PutFloat32(idx, testRand.Float32())
   229  	case val.Float64Enc:
   230  		tb.PutFloat64(idx, testRand.Float64())
   231  	case val.StringEnc:
   232  		buf := make([]byte, (testRand.Int63()%40)+10)
   233  		testRand.Read(buf)
   234  		tb.PutString(idx, string(buf))
   235  	case val.ByteStringEnc:
   236  		buf := make([]byte, (testRand.Int63()%40)+10)
   237  		testRand.Read(buf)
   238  		tb.PutByteString(idx, buf)
   239  	case val.Hash128Enc:
   240  		buf := make([]byte, 16)
   241  		testRand.Read(buf)
   242  		tb.PutHash128(idx, buf)
   243  	case val.CommitAddrEnc:
   244  		buf := make([]byte, 20)
   245  		testRand.Read(buf)
   246  		tb.PutCommitAddr(idx, hash.New(buf))
   247  	case val.BytesAddrEnc, val.StringAddrEnc, val.JSONAddrEnc:
   248  		len := (testRand.Int63() % 40) + 10
   249  		buf := make([]byte, len)
   250  		testRand.Read(buf)
   251  		bb := ns.BlobBuilder()
   252  		bb.Init(int(len))
   253  		_, addr, err := bb.Chunk(context.Background(), bytes.NewReader(buf))
   254  		if err != nil {
   255  			panic("failed to write bytes tree")
   256  		}
   257  		tb.PutBytesAddr(idx, addr)
   258  	default:
   259  		panic("unknown encoding")
   260  	}
   261  }
   262  
   263  func NewTestNodeStore() NodeStore {
   264  	ts := &chunks.TestStorage{}
   265  	ns := NewNodeStore(ts.NewViewWithFormat(types.Format_DOLT.VersionString()))
   266  	bb := &blobBuilderPool
   267  	return nodeStoreValidator{ns: ns, bb: bb}
   268  }
   269  
   270  type nodeStoreValidator struct {
   271  	ns NodeStore
   272  	bb *sync.Pool
   273  }
   274  
   275  func (v nodeStoreValidator) Read(ctx context.Context, ref hash.Hash) (Node, error) {
   276  	nd, err := v.ns.Read(ctx, ref)
   277  	if err != nil {
   278  		return Node{}, err
   279  	}
   280  
   281  	actual := hash.Of(nd.msg)
   282  	if ref != actual {
   283  		err = fmt.Errorf("incorrect node hash (%s != %s)", ref, actual)
   284  		return Node{}, err
   285  	}
   286  	return nd, nil
   287  }
   288  
   289  func (v nodeStoreValidator) ReadMany(ctx context.Context, refs hash.HashSlice) ([]Node, error) {
   290  	nodes, err := v.ns.ReadMany(ctx, refs)
   291  	if err != nil {
   292  		return nil, err
   293  	}
   294  	for i := range nodes {
   295  		actual := hash.Of(nodes[i].msg)
   296  		if refs[i] != actual {
   297  			err = fmt.Errorf("incorrect node hash (%s != %s)", refs[i], actual)
   298  			return nil, err
   299  		}
   300  	}
   301  	return nodes, nil
   302  }
   303  
   304  func (v nodeStoreValidator) Write(ctx context.Context, nd Node) (hash.Hash, error) {
   305  	h, err := v.ns.Write(ctx, nd)
   306  	if err != nil {
   307  		return hash.Hash{}, err
   308  	}
   309  
   310  	actual := hash.Of(nd.msg)
   311  	if h != actual {
   312  		err = fmt.Errorf("incorrect node hash (%s != %s)", h, actual)
   313  		return hash.Hash{}, err
   314  	}
   315  	return h, nil
   316  }
   317  
   318  func (v nodeStoreValidator) Pool() pool.BuffPool {
   319  	return v.ns.Pool()
   320  }
   321  
   322  func (v nodeStoreValidator) BlobBuilder() *BlobBuilder {
   323  	bb := v.bb.Get().(*BlobBuilder)
   324  	if bb.ns == nil {
   325  		bb.SetNodeStore(v)
   326  	}
   327  	return bb
   328  }
   329  
   330  func (v nodeStoreValidator) Format() *types.NomsBinFormat {
   331  	return v.ns.Format()
   332  }