github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/store/nbs/generational_chunk_store_test.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 nbs 16 17 import ( 18 "context" 19 "math/rand" 20 "testing" 21 22 "github.com/stretchr/testify/require" 23 24 "github.com/dolthub/dolt/go/store/chunks" 25 "github.com/dolthub/dolt/go/store/hash" 26 ) 27 28 var randGen = rand.New(rand.NewSource(0)) 29 30 func genChunks(t *testing.T, count int, max int) []chunks.Chunk { 31 chnks := make([]chunks.Chunk, count) 32 for i := 0; i < count; i++ { 33 bytes := make([]byte, randGen.Int()%max) 34 n, err := randGen.Read(bytes) 35 require.NoError(t, err) 36 chnks[i] = chunks.NewChunk(bytes[:n]) 37 } 38 39 return chnks 40 } 41 42 func mergeMaps(m1, m2 map[int]bool) map[int]bool { 43 m3 := make(map[int]bool) 44 for k := range m1 { 45 m3[k] = true 46 } 47 48 for k := range m2 { 49 m3[k] = true 50 } 51 52 return m3 53 } 54 55 func hashesForChunks(chunks []chunks.Chunk, indexes map[int]bool) hash.HashSet { 56 hashes := make(hash.HashSet) 57 for idx := range indexes { 58 hashes[chunks[idx].Hash()] = struct{}{} 59 } 60 61 return hashes 62 } 63 64 type foundHashes hash.HashSet 65 66 func (fh foundHashes) found(ctx context.Context, chk *chunks.Chunk) { 67 fh[chk.Hash()] = struct{}{} 68 } 69 70 func requireChunks(t *testing.T, ctx context.Context, chunks []chunks.Chunk, genCS *GenerationalNBS, inOld, inNew map[int]bool) { 71 // Has/Get Checks 72 for i, chk := range chunks { 73 has, err := genCS.oldGen.Has(ctx, chk.Hash()) 74 require.NoError(t, err) 75 require.Equal(t, inOld[i], has, "error for index: %d", i) 76 77 retrieved, err := genCS.oldGen.Get(ctx, chk.Hash()) 78 require.NoError(t, err) 79 require.Equal(t, !inOld[i], retrieved.IsEmpty(), "error for index: %d", i) 80 81 has, err = genCS.newGen.Has(ctx, chk.Hash()) 82 require.NoError(t, err) 83 require.Equal(t, inNew[i], has, "error for index: %d", i) 84 85 retrieved, err = genCS.newGen.Get(ctx, chk.Hash()) 86 require.NoError(t, err) 87 require.Equal(t, !inNew[i], retrieved.IsEmpty(), "error for index: %d", i) 88 89 has, err = genCS.Has(ctx, chk.Hash()) 90 require.NoError(t, err) 91 require.Equal(t, inOld[i] || inNew[i], has, "error for index: %d", i) 92 93 retrieved, err = genCS.Get(ctx, chk.Hash()) 94 require.NoError(t, err) 95 require.Equal(t, !(inOld[i] || inNew[i]), retrieved.IsEmpty(), "error for index: %d", i) 96 } 97 98 // HasMany Checks 99 absent, err := genCS.oldGen.HasMany(ctx, hashesForChunks(chunks, inOld)) 100 require.NoError(t, err) 101 require.Len(t, absent, 0) 102 103 absent, err = genCS.newGen.HasMany(ctx, hashesForChunks(chunks, inNew)) 104 require.NoError(t, err) 105 require.Len(t, absent, 0) 106 107 inUnion := mergeMaps(inOld, inNew) 108 absent, err = genCS.HasMany(ctx, hashesForChunks(chunks, inUnion)) 109 require.NoError(t, err) 110 require.Len(t, absent, 0) 111 112 // GetMany Checks 113 expected := hashesForChunks(chunks, inOld) 114 received := foundHashes{} 115 err = genCS.oldGen.GetMany(ctx, expected, received.found) 116 require.NoError(t, err) 117 require.Equal(t, expected, hash.HashSet(received)) 118 119 expected = hashesForChunks(chunks, inNew) 120 received = foundHashes{} 121 err = genCS.newGen.GetMany(ctx, expected, received.found) 122 require.NoError(t, err) 123 require.Equal(t, expected, hash.HashSet(received)) 124 125 expected = hashesForChunks(chunks, inUnion) 126 received = foundHashes{} 127 err = genCS.GetMany(ctx, expected, received.found) 128 require.NoError(t, err) 129 require.Equal(t, expected, hash.HashSet(received)) 130 } 131 132 func putChunks(t *testing.T, ctx context.Context, chunks []chunks.Chunk, cs chunks.ChunkStore, indexesIn map[int]bool, chunkIndexes ...int) { 133 for _, idx := range chunkIndexes { 134 err := cs.Put(ctx, chunks[idx], noopGetAddrs) 135 require.NoError(t, err) 136 indexesIn[idx] = true 137 } 138 } 139 140 func TestGenerationalCS(t *testing.T) { 141 ctx := context.Background() 142 oldGen, _, _ := makeTestLocalStore(t, 64) 143 newGen, _, _ := makeTestLocalStore(t, 64) 144 inOld := make(map[int]bool) 145 inNew := make(map[int]bool) 146 chnks := genChunks(t, 100, 1000) 147 148 putChunks(t, ctx, chnks, oldGen, inOld, 0, 1, 2, 3, 4) 149 150 cs := NewGenerationalCS(oldGen, newGen, nil) // NM4 - I guess we need more test here. 151 requireChunks(t, ctx, chnks, cs, inOld, inNew) 152 153 putChunks(t, ctx, chnks, cs, inNew, 6, 7, 8, 9) 154 requireChunks(t, ctx, chnks, cs, inOld, inNew) 155 156 err := cs.copyToOldGen(ctx, hashesForChunks(chnks, inNew)) 157 require.NoError(t, err) 158 159 inOld = mergeMaps(inOld, inNew) 160 requireChunks(t, ctx, chnks, cs, inOld, inNew) 161 162 putChunks(t, ctx, chnks, cs, inNew, 10, 11, 12, 13, 14) 163 requireChunks(t, ctx, chnks, cs, inOld, inNew) 164 165 err = cs.copyToOldGen(ctx, hashesForChunks(chnks, inNew)) 166 require.NoError(t, err) 167 168 inOld = mergeMaps(inOld, inNew) 169 requireChunks(t, ctx, chnks, cs, inOld, inNew) 170 171 putChunks(t, ctx, chnks, cs, inNew, 15, 16, 17, 18, 19) 172 requireChunks(t, ctx, chnks, cs, inOld, inNew) 173 }