github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/storage/index/block_bench_test.go (about) 1 // Copyright (c) 2018 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package index 22 23 import ( 24 "fmt" 25 "math/rand" 26 "os" 27 "strings" 28 "testing" 29 "time" 30 31 "github.com/m3db/m3/src/dbnode/namespace" 32 "github.com/m3db/m3/src/m3ninx/doc" 33 "github.com/m3db/m3/src/x/resource" 34 xtime "github.com/m3db/m3/src/x/time" 35 36 "github.com/golang/mock/gomock" 37 "github.com/pkg/profile" 38 "github.com/stretchr/testify/require" 39 ) 40 41 func BenchmarkBlockWrite(b *testing.B) { 42 ctrl := gomock.NewController(b) 43 defer ctrl.Finish() 44 45 testMD := newTestNSMetadata(b) 46 blockSize := time.Hour 47 48 now := xtime.Now() 49 blockStart := now.Truncate(blockSize) 50 51 bl, err := NewBlock(blockStart, testMD, BlockOptions{}, 52 namespace.NewRuntimeOptionsManager("foo"), testOpts) 53 require.NoError(b, err) 54 defer func() { 55 require.NoError(b, bl.Close()) 56 }() 57 58 var onIndexSeries mockOnIndexSeries 59 batch := NewWriteBatch(WriteBatchOptions{ 60 IndexBlockSize: blockSize, 61 }) 62 63 fieldValues := map[string][]string{ 64 "fruit": {"apple", "banana", "orange", "watermelon"}, 65 "vegetable": {"broccoli", "carrot", "celery", "cucumber"}, 66 "meat": {"beef", "chicken", "pork", "steak"}, 67 "cheese": {"cheddar", "swiss", "brie", "bleu"}, 68 } 69 70 for i := 0; i < 4096; i++ { 71 fields := make([]doc.Field, 0, len(fieldValues)) 72 for key, values := range fieldValues { 73 fields = append(fields, doc.Field{ 74 Name: []byte(key), 75 Value: []byte(values[rand.Intn(len(values))]), 76 }) 77 } 78 batch.Append(WriteBatchEntry{ 79 Timestamp: now, 80 OnIndexSeries: onIndexSeries, 81 EnqueuedAt: now.ToTime(), 82 }, doc.Metadata{ 83 ID: []byte(fmt.Sprintf("doc.%d", i)), 84 Fields: fields, 85 }) 86 } 87 88 if strings.ToLower(os.Getenv("PROFILE_CPU")) == "true" { 89 p := profile.Start(profile.CPUProfile) 90 defer p.Stop() 91 } 92 93 b.ResetTimer() 94 95 b.StartTimer() 96 for i := 0; i < b.N; i++ { 97 // Simulate all documents being pending on consequent 98 // write batch calls 99 for _, entry := range batch.entries { 100 entry.result.Done = false 101 } 102 103 _, err := bl.WriteBatch(batch) 104 require.NoError(b, err) 105 106 // Reset state 107 bl.(*block).Lock() 108 bl.(*block).mutableSegments.foregroundSegments = nil 109 bl.(*block).Unlock() 110 } 111 b.StopTimer() 112 } 113 114 // mockOnIndexSeries is a by hand generated struct since using the 115 // gomock generated ones is really slow so makes them almost 116 // useless to use in benchmarks 117 type mockOnIndexSeries struct{} 118 119 var _ doc.OnIndexSeries = mockOnIndexSeries{} 120 121 func (m mockOnIndexSeries) StringID() string { return "mock" } 122 func (m mockOnIndexSeries) OnIndexSuccess(xtime.UnixNano) {} 123 func (m mockOnIndexSeries) OnIndexFinalize(xtime.UnixNano) {} 124 func (m mockOnIndexSeries) OnIndexPrepare(xtime.UnixNano) {} 125 func (m mockOnIndexSeries) TryReconcileDuplicates() {} 126 func (m mockOnIndexSeries) NeedsIndexUpdate(xtime.UnixNano) bool { 127 return false 128 } 129 func (m mockOnIndexSeries) DecrementReaderWriterCount() {} 130 func (m mockOnIndexSeries) IfAlreadyIndexedMarkIndexSuccessAndFinalize(xtime.UnixNano) bool { 131 return false 132 } 133 func (m mockOnIndexSeries) IndexedForBlockStart(xtime.UnixNano) bool { return false } 134 func (m mockOnIndexSeries) IndexedOrAttemptedAny() bool { return false } 135 func (m mockOnIndexSeries) TryMarkIndexGarbageCollected() bool { return false } 136 func (m mockOnIndexSeries) NeedsIndexGarbageCollected() bool { return false } 137 func (m mockOnIndexSeries) MergeEntryIndexBlockStates(states doc.EntryIndexBlockStates) {} 138 func (m mockOnIndexSeries) IndexedRange() (xtime.UnixNano, xtime.UnixNano) { 139 return 0, 0 140 } 141 142 func (m mockOnIndexSeries) ReconciledOnIndexSeries() (doc.OnIndexSeries, resource.SimpleCloser, bool) { 143 return m, resource.SimpleCloserFn(func() {}), false 144 }