github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/integration/fs_bootstrap_index_test.go (about) 1 // +build integration 2 3 // Copyright (c) 2018 Uber Technologies, Inc. 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 // 12 // The above copyright notice and this permission notice shall be included in 13 // all copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 // THE SOFTWARE. 22 23 package integration 24 25 import ( 26 "testing" 27 "time" 28 29 "github.com/m3db/m3/src/dbnode/integration/generate" 30 "github.com/m3db/m3/src/dbnode/namespace" 31 "github.com/m3db/m3/src/dbnode/retention" 32 "github.com/m3db/m3/src/dbnode/storage/index" 33 "github.com/m3db/m3/src/m3ninx/doc" 34 "github.com/m3db/m3/src/m3ninx/idx" 35 idxpersist "github.com/m3db/m3/src/m3ninx/persist" 36 "github.com/m3db/m3/src/x/context" 37 "github.com/m3db/m3/src/x/ident" 38 xtime "github.com/m3db/m3/src/x/time" 39 40 "github.com/stretchr/testify/require" 41 "go.uber.org/zap" 42 ) 43 44 func TestFilesystemBootstrapIndexWithIndexingEnabled(t *testing.T) { 45 testFilesystemBootstrapIndexWithIndexingEnabled(t, 46 testFilesystemBootstrapIndexWithIndexingEnabledOptions{}) 47 } 48 49 // TestFilesystemBootstrapIndexWithIndexingEnabledAndCheckTickFreeMmap makes 50 // sure that bootstrapped segments free mmap calls occur. 51 func TestFilesystemBootstrapIndexWithIndexingEnabledAndCheckTickFreeMmap(t *testing.T) { 52 testFilesystemBootstrapIndexWithIndexingEnabled(t, 53 testFilesystemBootstrapIndexWithIndexingEnabledOptions{ 54 test: func(t *testing.T, setup TestSetup) { 55 var ( 56 cancellable = context.NewCancellable() 57 numSegmentsBootstrapped int64 58 freeMmap int64 59 ) 60 for _, ns := range setup.DB().Namespaces() { 61 idx, err := ns.Index() 62 require.NoError(t, err) 63 64 result, err := idx.Tick(cancellable, xtime.Now()) 65 require.NoError(t, err) 66 67 numSegmentsBootstrapped += result.NumSegmentsBootstrapped 68 freeMmap += result.FreeMmap 69 } 70 71 log := setup.StorageOpts().InstrumentOptions().Logger() 72 log.Info("ticked namespaces", 73 zap.Int64("numSegmentsBootstrapped", numSegmentsBootstrapped), 74 zap.Int64("freeMmap", freeMmap)) 75 require.True(t, numSegmentsBootstrapped > 0) 76 require.True(t, freeMmap > 0) 77 }, 78 }) 79 } 80 81 type testFilesystemBootstrapIndexWithIndexingEnabledOptions struct { 82 // test is an extended test to run at the end of the core bootstrap test. 83 test func(t *testing.T, setup TestSetup) 84 } 85 86 func testFilesystemBootstrapIndexWithIndexingEnabled( 87 t *testing.T, 88 testOpts testFilesystemBootstrapIndexWithIndexingEnabledOptions, 89 ) { 90 if testing.Short() { 91 t.SkipNow() // Just skip if we're doing a short run 92 } 93 94 var ( 95 blockSize = 2 * time.Hour 96 rOpts = retention.NewOptions().SetRetentionPeriod(6 * blockSize).SetBlockSize(blockSize) 97 idxOpts = namespace.NewIndexOptions().SetEnabled(true).SetBlockSize(2 * blockSize) 98 nOpts = namespace.NewOptions().SetRetentionOptions(rOpts).SetIndexOptions(idxOpts) 99 ) 100 ns1, err := namespace.NewMetadata(testNamespaces[0], nOpts) 101 require.NoError(t, err) 102 ns2, err := namespace.NewMetadata(testNamespaces[1], nOpts) 103 require.NoError(t, err) 104 105 opts := NewTestOptions(t). 106 SetNamespaces([]namespace.Metadata{ns1, ns2}) 107 108 // Test setup 109 setup, err := NewTestSetup(t, opts, nil) 110 require.NoError(t, err) 111 defer setup.Close() 112 113 require.NoError(t, setup.InitializeBootstrappers(InitializeBootstrappersOptions{ 114 WithFileSystem: true, 115 })) 116 117 // Write test data 118 now := setup.NowFn()() 119 120 fooSeries := generate.Series{ 121 ID: ident.StringID("foo"), 122 Tags: ident.NewTags(ident.StringTag("city", "new_york"), ident.StringTag("foo", "foo")), 123 } 124 fooDoc := doc.Metadata{ 125 ID: fooSeries.ID.Bytes(), 126 Fields: []doc.Field{ 127 {Name: []byte("city"), Value: []byte("new_york")}, 128 {Name: []byte("foo"), Value: []byte("foo")}, 129 }, 130 } 131 132 barSeries := generate.Series{ 133 ID: ident.StringID("bar"), 134 Tags: ident.NewTags(ident.StringTag("city", "new_jersey")), 135 } 136 barDoc := doc.Metadata{ 137 ID: barSeries.ID.Bytes(), 138 Fields: []doc.Field{ 139 {Name: []byte("city"), Value: []byte("new_jersey")}, 140 }, 141 } 142 143 bazSeries := generate.Series{ 144 ID: ident.StringID("baz"), 145 Tags: ident.NewTags(ident.StringTag("city", "seattle")), 146 } 147 bazDoc := doc.Metadata{ 148 ID: bazSeries.ID.Bytes(), 149 Fields: []doc.Field{ 150 {Name: []byte("city"), Value: []byte("seattle")}, 151 }, 152 } 153 154 seriesMaps := generate.BlocksByStart([]generate.BlockConfig{ 155 { 156 IDs: []string{fooSeries.ID.String()}, 157 Tags: fooSeries.Tags, 158 NumPoints: 100, 159 Start: now.Add(-3 * blockSize), 160 }, 161 { 162 IDs: []string{barSeries.ID.String()}, 163 Tags: barSeries.Tags, 164 NumPoints: 100, 165 Start: now.Add(-3 * blockSize), 166 }, 167 { 168 IDs: []string{fooSeries.ID.String()}, 169 Tags: fooSeries.Tags, 170 NumPoints: 50, 171 Start: now, 172 }, 173 { 174 IDs: []string{bazSeries.ID.String()}, 175 Tags: bazSeries.Tags, 176 NumPoints: 50, 177 Start: now, 178 }, 179 }) 180 181 defaultIndexDocs := []doc.Metadata{ 182 fooDoc, 183 barDoc, 184 bazDoc, 185 } 186 187 require.NoError(t, writeTestDataToDisk(ns1, setup, seriesMaps, 0)) 188 require.NoError(t, writeTestDataToDisk(ns2, setup, nil, 0)) 189 require.NoError(t, writeTestIndexDataToDisk( 190 ns1, 191 setup.StorageOpts(), 192 idxpersist.DefaultIndexVolumeType, 193 now.Add(-blockSize), 194 setup.ShardSet().AllIDs(), 195 defaultIndexDocs, 196 )) 197 198 // Start the server with filesystem bootstrapper 199 log := setup.StorageOpts().InstrumentOptions().Logger() 200 log.Debug("filesystem bootstrap test") 201 require.NoError(t, setup.StartServer()) 202 log.Debug("server is now up") 203 204 // Stop the server 205 defer func() { 206 require.NoError(t, setup.StopServerAndVerifyOpenFilesAreClosed()) 207 setup.Close() 208 log.Debug("server is now down") 209 }() 210 211 // Verify data matches what we expect 212 verifySeriesMaps(t, setup, testNamespaces[0], seriesMaps) 213 verifySeriesMaps(t, setup, testNamespaces[1], nil) 214 215 // Issue some index queries 216 session, err := setup.M3DBClient().DefaultSession() 217 require.NoError(t, err) 218 219 start := now.Add(-rOpts.RetentionPeriod()) 220 end := now.Add(blockSize) 221 queryOpts := index.QueryOptions{StartInclusive: start, EndExclusive: end} 222 223 // Match all new_*r* 224 regexpQuery, err := idx.NewRegexpQuery([]byte("city"), []byte("new_.*r.*")) 225 require.NoError(t, err) 226 iter, fetchResponse, err := session.FetchTaggedIDs(ContextWithDefaultTimeout(), 227 ns1.ID(), index.Query{Query: regexpQuery}, queryOpts) 228 require.NoError(t, err) 229 defer iter.Finalize() 230 231 verifyQueryMetadataResults(t, iter, fetchResponse.Exhaustive, verifyQueryMetadataResultsOptions{ 232 namespace: ns1.ID(), 233 exhaustive: true, 234 expected: []generate.Series{fooSeries, barSeries}, 235 }) 236 237 // Match all *e*e* 238 regexpQuery, err = idx.NewRegexpQuery([]byte("city"), []byte(".*e.*e.*")) 239 require.NoError(t, err) 240 iter, fetchResponse, err = session.FetchTaggedIDs(ContextWithDefaultTimeout(), 241 ns1.ID(), index.Query{Query: regexpQuery}, queryOpts) 242 require.NoError(t, err) 243 defer iter.Finalize() 244 245 verifyQueryMetadataResults(t, iter, fetchResponse.Exhaustive, verifyQueryMetadataResultsOptions{ 246 namespace: ns1.ID(), 247 exhaustive: true, 248 expected: []generate.Series{barSeries, bazSeries}, 249 }) 250 251 if testOpts.test != nil { 252 testOpts.test(t, setup) 253 } 254 }