github.com/m3db/m3@v1.5.0/src/dbnode/storage/bootstrap/bootstrapper/fs/source_index_bench_test.go (about) 1 // Copyright (c) 2019 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 fs 22 23 import ( 24 "io/ioutil" 25 "math" 26 "net/http" 27 "net/http/httptest" 28 _ "net/http/pprof" // pprof: for debug listen server if configured 29 "os" 30 "strconv" 31 "strings" 32 "testing" 33 "time" 34 35 "github.com/m3db/m3/src/dbnode/namespace" 36 "github.com/m3db/m3/src/dbnode/persist" 37 "github.com/m3db/m3/src/dbnode/persist/fs" 38 "github.com/m3db/m3/src/dbnode/persist/fs/msgpack" 39 "github.com/m3db/m3/src/dbnode/storage/bootstrap" 40 "github.com/m3db/m3/src/dbnode/storage/bootstrap/result" 41 "github.com/m3db/m3/src/dbnode/storage/series" 42 xtime "github.com/m3db/m3/src/x/time" 43 44 "github.com/davecgh/go-spew/spew" 45 "github.com/pkg/profile" 46 "github.com/stretchr/testify/require" 47 ) 48 49 // BenchmarkBootstrapIndex allows for testing indexing bootstrap time with the 50 // FS bootstrapper, this tests the speed and performance of index segment 51 // building from reading a set of files that sit on disk taken from a real 52 // DB node. 53 // To use test data and capture CPU profile run with: 54 // TEST_TSDB_DIR=/tmp/m3db_data PROFILE_CPU=true go test -v -run none -bench Index 55 func BenchmarkBootstrapIndex(b *testing.B) { 56 dir, err := ioutil.TempDir("", "var_lib_m3db_fake") 57 require.NoError(b, err) 58 defer os.RemoveAll(dir) 59 60 srv := httptest.NewServer(http.DefaultServeMux) 61 spew.Printf("test server with pprof: %v\n", srv.URL) 62 63 timesOpts := testTimesOptions{ 64 numBlocks: 2, 65 } 66 times := newTestBootstrapIndexTimes(timesOpts) 67 68 testNamespace := testNs1ID 69 testNamespaceMetadata := testNsMetadata(b) 70 if testDir := os.Getenv("TEST_TSDB_DIR"); testDir != "" { 71 spew.Printf("using test dir: %s\n", testDir) 72 73 // Allow for test directory overrides, must name the namespace 74 // "test_namespace" in the override directory. 75 dir = testDir 76 77 namespaceDataDirPath := fs.NamespaceDataDirPath(dir, testNamespace) 78 handle, err := os.Open(namespaceDataDirPath) 79 require.NoError(b, err) 80 81 results, err := handle.Readdir(0) 82 require.NoError(b, err) 83 84 require.NoError(b, handle.Close()) 85 86 var shards []uint32 87 for _, result := range results { 88 if !result.IsDir() { 89 // Looking for shard directories. 90 spew.Printf("shard discover: entry not directory, %v\n", result.Name()) 91 continue 92 } 93 94 v, err := strconv.Atoi(result.Name()) 95 if err != nil { 96 // Not a shard directory. 97 spew.Printf("shard discover: not number, %v, %v\n", result.Name(), err) 98 continue 99 } 100 101 shards = append(shards, uint32(v)) 102 } 103 104 spew.Printf("discovered shards: dir=%v, shards=%v\n", 105 namespaceDataDirPath, shards) 106 107 // Clear the shard time ranges and add new ones. 108 times.shardTimeRanges = result.NewShardTimeRanges() 109 times.start = xtime.UnixNano(math.MaxInt64) 110 times.end = xtime.UnixNano(0) 111 for _, shard := range shards { 112 var ( 113 min = xtime.UnixNano(math.MaxInt64) 114 max = xtime.UnixNano(0) 115 ranges = xtime.NewRanges() 116 entries = fs.ReadInfoFiles(dir, testNamespace, shard, 117 0, msgpack.NewDecodingOptions(), persist.FileSetFlushType) 118 ) 119 for _, entry := range entries { 120 if entry.Err != nil { 121 require.NoError(b, entry.Err.Error()) 122 } 123 124 start := xtime.UnixNano(entry.Info.BlockStart) 125 if start.Before(min) { 126 min = start 127 } 128 129 blockSize := time.Duration(entry.Info.BlockSize) 130 end := start.Add(blockSize) 131 if end.After(max) { 132 max = end 133 } 134 135 ranges.AddRange(xtime.Range{Start: start, End: end}) 136 137 // Override the block size if different. 138 namespaceOpts := testNamespaceMetadata.Options() 139 retentionOpts := namespaceOpts.RetentionOptions() 140 currBlockSize := retentionOpts.BlockSize() 141 if blockSize > currBlockSize { 142 newRetentionOpts := retentionOpts. 143 SetBlockSize(blockSize). 144 // 42yrs of retention to make sure blocks are in retention. 145 // Why 42? Because it's the answer to life, the universe and everything. 146 SetRetentionPeriod(42 * 365 * 24 * time.Hour) 147 newIndexOpts := namespaceOpts.IndexOptions().SetBlockSize(blockSize) 148 newNamespaceOpts := namespaceOpts. 149 SetRetentionOptions(newRetentionOpts). 150 SetIndexOptions(newIndexOpts) 151 testNamespaceMetadata, err = namespace.NewMetadata(testNamespace, newNamespaceOpts) 152 require.NoError(b, err) 153 } 154 } 155 156 if ranges.IsEmpty() { 157 continue // Nothing to bootstrap for shard. 158 } 159 160 times.shardTimeRanges.Set(shard, ranges) 161 162 if min.Before(times.start) { 163 times.start = min 164 } 165 if max.After(times.end) { 166 times.end = max 167 } 168 } 169 } else { 170 writeTSDBGoodTaggedSeriesDataFiles(b, dir, testNamespace, times.start) 171 } 172 173 testOpts := newTestOptionsWithPersistManager(b, dir). 174 SetResultOptions(testDefaultResultOpts.SetSeriesCachePolicy(series.CacheLRU)) 175 176 src, err := newFileSystemSource(testOpts) 177 require.NoError(b, err) 178 179 runOpts := testDefaultRunOpts. 180 SetPersistConfig(bootstrap.PersistConfig{ 181 Enabled: true, 182 FileSetType: persist.FileSetFlushType, 183 }) 184 185 tester := bootstrap.BuildNamespacesTester(b, runOpts, 186 times.shardTimeRanges, testNamespaceMetadata) 187 defer tester.Finish() 188 189 spew.Printf("running test with times: %v\n", times) 190 191 if strings.ToLower(os.Getenv("PROFILE_CPU")) == "true" { 192 p := profile.Start(profile.CPUProfile) 193 defer p.Stop() 194 } 195 196 b.ResetTimer() 197 b.StartTimer() 198 tester.TestReadWith(src) 199 b.StopTimer() 200 }