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 }