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 }