github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/store/nbs/stats_test.go (about)

     1  // Copyright 2019 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  // This file incorporates work covered by the following copyright and
    16  // permission notice:
    17  //
    18  // Copyright 2016 Attic Labs, Inc. All rights reserved.
    19  // Licensed under the Apache License, version 2.0:
    20  // http://www.apache.org/licenses/LICENSE-2.0
    21  
    22  package nbs
    23  
    24  import (
    25  	"context"
    26  	"os"
    27  	"testing"
    28  
    29  	"github.com/stretchr/testify/assert"
    30  	"github.com/stretchr/testify/require"
    31  
    32  	"github.com/dolthub/dolt/go/libraries/utils/file"
    33  	"github.com/dolthub/dolt/go/store/chunks"
    34  	"github.com/dolthub/dolt/go/store/constants"
    35  	"github.com/dolthub/dolt/go/store/hash"
    36  )
    37  
    38  func TestStats(t *testing.T) {
    39  	assert := assert.New(t)
    40  
    41  	stats := func(store *NomsBlockStore) Stats {
    42  		return store.Stats().(Stats)
    43  	}
    44  
    45  	dir, err := os.MkdirTemp("", "")
    46  	require.NoError(t, err)
    47  	defer file.RemoveAll(dir)
    48  	store, err := NewLocalStore(context.Background(), constants.FormatDefaultString, dir, testMemTableSize, NewUnlimitedMemQuotaProvider())
    49  	require.NoError(t, err)
    50  	defer store.Close()
    51  
    52  	assert.EqualValues(1, stats(store).OpenLatency.Samples())
    53  
    54  	// Opening a new store will still incur some read IO, to discover that the manifest doesn't exist
    55  	assert.EqualValues(1, stats(store).ReadManifestLatency.Samples())
    56  
    57  	i1, i2, i3, i4, i5 := []byte("abc"), []byte("def"), []byte("ghi"), []byte("jkl"), []byte("mno")
    58  
    59  	c1, c2, c3, c4, c5 := chunks.NewChunk(i1), chunks.NewChunk(i2), chunks.NewChunk(i3), chunks.NewChunk(i4), chunks.NewChunk(i5)
    60  
    61  	// These just go to mem table, only operation stats
    62  	err = store.Put(context.Background(), c1, noopGetAddrs)
    63  	require.NoError(t, err)
    64  	err = store.Put(context.Background(), c2, noopGetAddrs)
    65  	require.NoError(t, err)
    66  	err = store.Put(context.Background(), c3, noopGetAddrs)
    67  	require.NoError(t, err)
    68  	assert.Equal(uint64(3), stats(store).PutLatency.Samples())
    69  	assert.Equal(uint64(0), stats(store).PersistLatency.Samples())
    70  
    71  	assert.True(store.Has(context.Background(), c1.Hash()))
    72  	assert.True(store.Has(context.Background(), c2.Hash()))
    73  	assert.True(store.Has(context.Background(), c3.Hash()))
    74  	assert.Equal(uint64(3), stats(store).HasLatency.Samples())
    75  	assert.Equal(uint64(3), stats(store).AddressesPerHas.Sum())
    76  
    77  	c, err := store.Get(context.Background(), c1.Hash())
    78  	require.NoError(t, err)
    79  	assert.False(c.IsEmpty())
    80  	c, err = store.Get(context.Background(), c2.Hash())
    81  	require.NoError(t, err)
    82  	assert.False(c.IsEmpty())
    83  	c, err = store.Get(context.Background(), c3.Hash())
    84  	require.NoError(t, err)
    85  	assert.False(c.IsEmpty())
    86  	assert.Equal(uint64(3), stats(store).GetLatency.Samples())
    87  	assert.Equal(uint64(0), stats(store).FileReadLatency.Samples())
    88  	assert.Equal(uint64(3), stats(store).ChunksPerGet.Sum())
    89  
    90  	h, err := store.Root(context.Background())
    91  	require.NoError(t, err)
    92  	_, err = store.Commit(context.Background(), h, h)
    93  	require.NoError(t, err)
    94  
    95  	// Commit will update the manifest
    96  	assert.EqualValues(1, stats(store).WriteManifestLatency.Samples())
    97  	assert.EqualValues(1, stats(store).CommitLatency.Samples())
    98  
    99  	// Now we have write IO
   100  	assert.Equal(uint64(1), stats(store).PersistLatency.Samples())
   101  	assert.Equal(uint64(3), stats(store).ChunksPerPersist.Sum())
   102  	assert.Equal(uint64(131), stats(store).BytesPerPersist.Sum())
   103  
   104  	// Now some gets that will incur read IO
   105  	_, err = store.Get(context.Background(), c1.Hash())
   106  	require.NoError(t, err)
   107  	_, err = store.Get(context.Background(), c2.Hash())
   108  	require.NoError(t, err)
   109  	_, err = store.Get(context.Background(), c3.Hash())
   110  	require.NoError(t, err)
   111  	assert.Equal(uint64(3), stats(store).FileReadLatency.Samples())
   112  	assert.Equal(uint64(27), stats(store).FileBytesPerRead.Sum())
   113  
   114  	// Try A GetMany
   115  	chnx := make([]chunks.Chunk, 3)
   116  	chnx[0] = c1
   117  	chnx[1] = c2
   118  	chnx[2] = c3
   119  	hashes := make(hash.HashSlice, len(chnx))
   120  	for i, c := range chnx {
   121  		hashes[i] = c.Hash()
   122  	}
   123  	chunkChan := make(chan *chunks.Chunk, 3)
   124  	err = store.GetMany(context.Background(), hashes.HashSet(), func(ctx context.Context, c *chunks.Chunk) {
   125  		select {
   126  		case chunkChan <- c:
   127  		case <-ctx.Done():
   128  		}
   129  	})
   130  	require.NoError(t, err)
   131  	assert.Equal(uint64(4), stats(store).FileReadLatency.Samples())
   132  	assert.Equal(uint64(54), stats(store).FileBytesPerRead.Sum())
   133  
   134  	// Force a conjoin
   135  	store.c = inlineConjoiner{2}
   136  	err = store.Put(context.Background(), c4, noopGetAddrs)
   137  	require.NoError(t, err)
   138  	h, err = store.Root(context.Background())
   139  	require.NoError(t, err)
   140  	_, err = store.Commit(context.Background(), h, h)
   141  	require.NoError(t, err)
   142  
   143  	err = store.Put(context.Background(), c5, noopGetAddrs)
   144  	require.NoError(t, err)
   145  	h, err = store.Root(context.Background())
   146  	require.NoError(t, err)
   147  	_, err = store.Commit(context.Background(), h, h)
   148  	require.NoError(t, err)
   149  
   150  	assert.Equal(uint64(1), stats(store).ConjoinLatency.Samples())
   151  	// TODO: Once random conjoin hack is out, test other conjoin stats
   152  }