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  }