github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/storage/database_test.go (about) 1 // Copyright (c) 2016 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 storage 22 23 import ( 24 stdlibctx "context" 25 "errors" 26 "fmt" 27 "sort" 28 "sync" 29 "testing" 30 "time" 31 32 "github.com/m3db/m3/src/cluster/shard" 33 "github.com/m3db/m3/src/dbnode/client" 34 "github.com/m3db/m3/src/dbnode/generated/proto/annotation" 35 "github.com/m3db/m3/src/dbnode/namespace" 36 "github.com/m3db/m3/src/dbnode/persist/fs/commitlog" 37 "github.com/m3db/m3/src/dbnode/retention" 38 "github.com/m3db/m3/src/dbnode/sharding" 39 "github.com/m3db/m3/src/dbnode/storage/block" 40 dberrors "github.com/m3db/m3/src/dbnode/storage/errors" 41 "github.com/m3db/m3/src/dbnode/storage/index" 42 "github.com/m3db/m3/src/dbnode/storage/index/convert" 43 "github.com/m3db/m3/src/dbnode/storage/repair" 44 "github.com/m3db/m3/src/dbnode/testdata/prototest" 45 "github.com/m3db/m3/src/dbnode/topology" 46 "github.com/m3db/m3/src/dbnode/tracepoint" 47 "github.com/m3db/m3/src/dbnode/ts" 48 "github.com/m3db/m3/src/dbnode/ts/writes" 49 xmetrics "github.com/m3db/m3/src/dbnode/x/metrics" 50 "github.com/m3db/m3/src/m3ninx/idx" 51 xclock "github.com/m3db/m3/src/x/clock" 52 "github.com/m3db/m3/src/x/context" 53 xerrors "github.com/m3db/m3/src/x/errors" 54 "github.com/m3db/m3/src/x/ident" 55 "github.com/m3db/m3/src/x/instrument" 56 "github.com/m3db/m3/src/x/pool" 57 "github.com/m3db/m3/src/x/serialize" 58 xtest "github.com/m3db/m3/src/x/test" 59 xtime "github.com/m3db/m3/src/x/time" 60 xwatch "github.com/m3db/m3/src/x/watch" 61 62 "github.com/fortytw2/leaktest" 63 "github.com/golang/mock/gomock" 64 "github.com/opentracing/opentracing-go" 65 "github.com/opentracing/opentracing-go/mocktracer" 66 "github.com/stretchr/testify/assert" 67 "github.com/stretchr/testify/require" 68 "github.com/uber-go/tally" 69 ) 70 71 var ( 72 defaultTestNs1ID = ident.StringID("testns1") 73 defaultTestNs2ID = ident.StringID("testns2") 74 defaultTestRetentionOpts = retention.NewOptions().SetBufferFuture(10 * time.Minute).SetBufferPast(10 * time.Minute). 75 SetBlockSize(2 * time.Hour).SetRetentionPeriod(2 * 24 * time.Hour) 76 defaultTestNs2RetentionOpts = retention.NewOptions().SetBufferFuture(10 * time.Minute).SetBufferPast(10 * time.Minute). 77 SetBlockSize(4 * time.Hour).SetRetentionPeriod(2 * 24 * time.Hour) 78 defaultTestNs1Opts = namespace.NewOptions().SetRetentionOptions(defaultTestRetentionOpts) 79 defaultTestNs2Opts = namespace.NewOptions().SetRetentionOptions(defaultTestNs2RetentionOpts) 80 testSchemaHistory = prototest.NewSchemaHistory() 81 testClientOptions = client.NewOptions() 82 ) 83 84 type nsMapCh chan namespace.Map 85 86 type mockNsInitializer struct { 87 registry *namespace.MockRegistry 88 updateCh chan struct{} 89 } 90 91 func (mi *mockNsInitializer) Init() (namespace.Registry, error) { 92 return mi.registry, nil 93 } 94 95 func newMockNsInitializer( 96 t *testing.T, 97 ctrl *gomock.Controller, 98 nsMapCh nsMapCh, 99 ) namespace.Initializer { 100 updateCh := make(chan struct{}, 10) 101 watch := xwatch.NewWatchable() 102 go func() { 103 for { 104 v, ok := <-nsMapCh 105 if !ok { // closed channel 106 return 107 } 108 109 watch.Update(v) 110 updateCh <- struct{}{} 111 } 112 }() 113 114 _, w, err := watch.Watch() 115 require.NoError(t, err) 116 117 nsWatch := namespace.NewWatch(w) 118 reg := namespace.NewMockRegistry(ctrl) 119 reg.EXPECT().Watch().Return(nsWatch, nil).AnyTimes() 120 121 return &mockNsInitializer{ 122 registry: reg, 123 updateCh: updateCh, 124 } 125 } 126 127 func testNamespaceMap(t *testing.T) namespace.Map { 128 md1, err := namespace.NewMetadata(defaultTestNs1ID, defaultTestNs1Opts) 129 require.NoError(t, err) 130 md2, err := namespace.NewMetadata(defaultTestNs2ID, defaultTestNs2Opts) 131 require.NoError(t, err) 132 nsMap, err := namespace.NewMap([]namespace.Metadata{md1, md2}) 133 require.NoError(t, err) 134 return nsMap 135 } 136 137 func testRepairOptions(ctrl *gomock.Controller) repair.Options { 138 var ( 139 origin = topology.NewHost("some-id", "some-address") 140 clientOpts = testClientOptions.(client.AdminOptions).SetOrigin(origin) 141 mockClient = client.NewMockAdminClient(ctrl) 142 ) 143 mockClient.EXPECT().Options().Return(clientOpts).AnyTimes() 144 return repair.NewOptions(). 145 SetAdminClients([]client.AdminClient{mockClient}). 146 SetRepairCheckInterval(100 * time.Millisecond) 147 } 148 149 func newMockdatabase(ctrl *gomock.Controller, ns ...databaseNamespace) *Mockdatabase { 150 db := NewMockdatabase(ctrl) 151 db.EXPECT().Options().Return(DefaultTestOptions()).AnyTimes() 152 if len(ns) != 0 { 153 db.EXPECT().OwnedNamespaces().Return(ns, nil).AnyTimes() 154 } 155 return db 156 } 157 158 type newTestDatabaseOpt struct { 159 bs BootstrapState 160 nsMap namespace.Map 161 dbOpt Options 162 } 163 164 func defaultTestDatabase(t *testing.T, ctrl *gomock.Controller, bs BootstrapState) (*db, nsMapCh, xmetrics.TestStatsReporter) { 165 return newTestDatabase(t, ctrl, newTestDatabaseOpt{bs: bs, nsMap: testNamespaceMap(t), dbOpt: DefaultTestOptions()}) 166 } 167 168 func newTestDatabase( 169 t *testing.T, 170 ctrl *gomock.Controller, 171 opt newTestDatabaseOpt, 172 ) (*db, nsMapCh, xmetrics.TestStatsReporter) { 173 testReporter := xmetrics.NewTestStatsReporter(xmetrics.NewTestStatsReporterOptions()) 174 scope, _ := tally.NewRootScope(tally.ScopeOptions{ 175 Reporter: testReporter, 176 }, 100*time.Millisecond) 177 178 mapCh := make(nsMapCh, 10) 179 mapCh <- opt.nsMap 180 181 opts := opt.dbOpt 182 opts = opts.SetInstrumentOptions( 183 opts.InstrumentOptions().SetMetricsScope(scope)). 184 SetRepairEnabled(false). 185 SetRepairOptions(testRepairOptions(ctrl)). 186 SetNamespaceInitializer(newMockNsInitializer(t, ctrl, mapCh)) 187 188 shards := sharding.NewShards([]uint32{0, 1}, shard.Available) 189 shardSet, err := sharding.NewShardSet(shards, nil) 190 require.NoError(t, err) 191 192 database, err := NewDatabase(shardSet, opts) 193 require.NoError(t, err) 194 d := database.(*db) 195 m := d.mediator.(*mediator) 196 bsm := newBootstrapManager(d, m, opts).(*bootstrapManager) 197 bsm.state = opt.bs 198 m.databaseBootstrapManager = bsm 199 200 return d, mapCh, testReporter 201 } 202 203 func dbAddNewMockNamespace( 204 ctrl *gomock.Controller, 205 d *db, 206 id string, 207 ) *MockdatabaseNamespace { 208 ns := ident.StringID(id) 209 mockNamespace := NewMockdatabaseNamespace(ctrl) 210 mockNamespace.EXPECT().ID().Return(ns).AnyTimes() 211 d.namespaces.Set(ns, mockNamespace) 212 return mockNamespace 213 } 214 215 func TestDatabaseOpen(t *testing.T) { 216 ctrl := xtest.NewController(t) 217 defer ctrl.Finish() 218 219 d, mapCh, _ := defaultTestDatabase(t, ctrl, BootstrapNotStarted) 220 defer func() { 221 close(mapCh) 222 leaktest.CheckTimeout(t, time.Second)() 223 }() 224 require.NoError(t, d.Open()) 225 require.Equal(t, errDatabaseAlreadyOpen, d.Open()) 226 require.NoError(t, d.Close()) 227 } 228 229 func TestDatabaseClose(t *testing.T) { 230 ctrl := xtest.NewController(t) 231 defer ctrl.Finish() 232 233 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 234 defer func() { 235 close(mapCh) 236 leaktest.CheckTimeout(t, time.Second)() 237 }() 238 require.NoError(t, d.Open()) 239 require.NoError(t, d.Close()) 240 require.Equal(t, errDatabaseAlreadyClosed, d.Close()) 241 } 242 243 func TestDatabaseTerminate(t *testing.T) { 244 ctrl := xtest.NewController(t) 245 defer ctrl.Finish() 246 247 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 248 defer func() { 249 close(mapCh) 250 leaktest.CheckTimeout(t, time.Second)() 251 }() 252 require.NoError(t, d.Open()) 253 require.NoError(t, d.Terminate()) 254 require.Equal(t, errDatabaseAlreadyClosed, d.Close()) 255 } 256 257 func TestDatabaseReadEncodedNamespaceNonExistent(t *testing.T) { 258 ctrl := xtest.NewController(t) 259 defer ctrl.Finish() 260 261 ctx := context.NewBackground() 262 defer ctx.Close() 263 264 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 265 defer func() { 266 close(mapCh) 267 }() 268 now := xtime.Now() 269 _, err := d.ReadEncoded(ctx, ident.StringID("nonexistent"), 270 ident.StringID("foo"), now, now) 271 require.True(t, dberrors.IsUnknownNamespaceError(err)) 272 } 273 274 func TestDatabaseReadEncoded(t *testing.T) { 275 ctrl := xtest.NewController(t) 276 defer ctrl.Finish() 277 278 ctx := context.NewBackground() 279 defer ctx.Close() 280 281 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 282 defer func() { 283 close(mapCh) 284 }() 285 286 ns := ident.StringID("testns1") 287 id := ident.StringID("bar") 288 end := xtime.Now() 289 start := end.Add(-time.Hour) 290 mockNamespace := NewMockdatabaseNamespace(ctrl) 291 mockNamespace.EXPECT().ReadEncoded(ctx, id, start, end).Return(nil, nil) 292 d.namespaces.Set(ns, mockNamespace) 293 294 res, err := d.ReadEncoded(ctx, ns, id, start, end) 295 require.Nil(t, res) 296 require.Nil(t, err) 297 } 298 299 func TestDatabaseFetchBlocksNamespaceNonExistent(t *testing.T) { 300 ctrl := xtest.NewController(t) 301 defer ctrl.Finish() 302 303 ctx := context.NewBackground() 304 defer ctx.Close() 305 306 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 307 defer func() { 308 close(mapCh) 309 }() 310 311 now := xtime.Now() 312 starts := []xtime.UnixNano{now, now.Add(time.Second), now.Add(-time.Second)} 313 res, err := d.FetchBlocks(ctx, ident.StringID("non-existent-ns"), 0, ident.StringID("foo"), starts) 314 require.Nil(t, res) 315 require.True(t, xerrors.IsInvalidParams(err)) 316 } 317 318 func TestDatabaseFetchBlocks(t *testing.T) { 319 ctrl := xtest.NewController(t) 320 defer ctrl.Finish() 321 322 ctx := context.NewBackground() 323 defer ctx.Close() 324 325 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 326 defer func() { 327 close(mapCh) 328 }() 329 330 ns := ident.StringID("testns1") 331 id := ident.StringID("bar") 332 shardID := uint32(0) 333 now := xtime.Now() 334 starts := []xtime.UnixNano{now, now.Add(time.Second), now.Add(-time.Second)} 335 expected := []block.FetchBlockResult{block.NewFetchBlockResult(starts[0], nil, nil)} 336 mockNamespace := NewMockdatabaseNamespace(ctrl) 337 mockNamespace.EXPECT().FetchBlocks(ctx, shardID, id, starts).Return(expected, nil) 338 d.namespaces.Set(ns, mockNamespace) 339 340 res, err := d.FetchBlocks(ctx, ns, shardID, id, starts) 341 require.Equal(t, expected, res) 342 require.NoError(t, err) 343 } 344 345 func TestDatabaseNamespaces(t *testing.T) { 346 ctrl := xtest.NewController(t) 347 defer ctrl.Finish() 348 349 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 350 defer func() { 351 close(mapCh) 352 }() 353 354 dbAddNewMockNamespace(ctrl, d, "testns1") 355 dbAddNewMockNamespace(ctrl, d, "testns2") 356 357 result := d.Namespaces() 358 require.Equal(t, 2, len(result)) 359 360 sort.Sort(NamespacesByID(result)) 361 assert.Equal(t, "testns1", result[0].ID().String()) 362 assert.Equal(t, "testns2", result[1].ID().String()) 363 } 364 365 func TestOwnedNamespacesErrorIfClosed(t *testing.T) { 366 ctrl := xtest.NewController(t) 367 defer ctrl.Finish() 368 369 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 370 defer func() { 371 close(mapCh) 372 }() 373 374 require.NoError(t, d.Open()) 375 require.NoError(t, d.Terminate()) 376 377 _, err := d.OwnedNamespaces() 378 require.Equal(t, errDatabaseIsClosed, err) 379 } 380 381 func TestDatabaseAssignShardSet(t *testing.T) { 382 ctrl := xtest.NewController(t) 383 defer ctrl.Finish() 384 385 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 386 defer func() { 387 close(mapCh) 388 }() 389 390 var ns []*MockdatabaseNamespace 391 ns = append(ns, dbAddNewMockNamespace(ctrl, d, "testns1")) 392 ns = append(ns, dbAddNewMockNamespace(ctrl, d, "testns2")) 393 394 shards := append(sharding.NewShards([]uint32{0, 1}, shard.Available), 395 sharding.NewShards([]uint32{2}, shard.Initializing)...) 396 shardSet, err := sharding.NewShardSet(shards, nil) 397 require.NoError(t, err) 398 399 var wg sync.WaitGroup 400 wg.Add(len(ns)) 401 for _, n := range ns { 402 n.EXPECT().AssignShardSet(shardSet).Do(func(_ sharding.ShardSet) { 403 wg.Done() 404 }) 405 } 406 407 t1 := d.lastReceivedNewShards 408 d.AssignShardSet(shardSet) 409 require.True(t, d.lastReceivedNewShards.After(t1)) 410 411 wg.Wait() 412 assertFileOpsEnabled(t, d) 413 } 414 415 func TestDatabaseAssignShardSetEnqueueBootstrapWhenMediatorClosed(t *testing.T) { 416 ctrl := xtest.NewController(t) 417 defer ctrl.Finish() 418 419 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 420 defer func() { 421 close(mapCh) 422 }() 423 424 mockMediator := NewMockdatabaseMediator(ctrl) 425 mockMediator.EXPECT().IsOpen().Return(false) 426 mockMediator.EXPECT().BootstrapEnqueue(gomock.Any()) 427 d.mediator = mockMediator 428 d.bootstraps = 1 429 430 var ns []*MockdatabaseNamespace 431 ns = append(ns, 432 dbAddNewMockNamespace(ctrl, d, "testns1"), 433 dbAddNewMockNamespace(ctrl, d, "testns2")) 434 435 shards := append(sharding.NewShards([]uint32{0, 1}, shard.Available), 436 sharding.NewShards([]uint32{2}, shard.Initializing)...) 437 shardSet, err := sharding.NewShardSet(shards, nil) 438 require.NoError(t, err) 439 440 var wg sync.WaitGroup 441 wg.Add(len(ns)) 442 for _, n := range ns { 443 n.EXPECT().AssignShardSet(shardSet).Do(func(_ sharding.ShardSet) { 444 wg.Done() 445 }) 446 } 447 448 t1 := d.lastReceivedNewShards 449 d.AssignShardSet(shardSet) 450 require.True(t, d.lastReceivedNewShards.After(t1)) 451 452 wg.Wait() 453 } 454 455 func TestDatabaseAssignShardSetBehaviorNoNewShards(t *testing.T) { 456 ctrl := xtest.NewController(t) 457 defer ctrl.Finish() 458 459 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 460 defer func() { 461 close(mapCh) 462 }() 463 464 t1 := d.lastReceivedNewShards 465 d.AssignShardSet(d.shardSet) 466 // Ensure that lastReceivedNewShards is not updated if no new shards are assigned. 467 require.True(t, d.lastReceivedNewShards.Equal(t1)) 468 } 469 470 func TestDatabaseBootstrappedAssignShardSet(t *testing.T) { 471 ctrl := xtest.NewController(t) 472 defer ctrl.Finish() 473 474 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 475 defer func() { 476 close(mapCh) 477 }() 478 479 ns := dbAddNewMockNamespace(ctrl, d, "testns") 480 481 mediator := NewMockdatabaseMediator(ctrl) 482 mediator.EXPECT().IsOpen().Return(true).AnyTimes() 483 mediator.EXPECT().DisableFileOpsAndWait().AnyTimes() 484 mediator.EXPECT().EnableFileOps().AnyTimes() 485 mediator.EXPECT().Bootstrap().DoAndReturn(func() (BootstrapResult, error) { 486 return BootstrapResult{}, nil 487 }) 488 d.mediator = mediator 489 490 assert.NoError(t, d.Bootstrap()) 491 492 shards := append(sharding.NewShards([]uint32{0, 1}, shard.Available), 493 sharding.NewShards([]uint32{2}, shard.Initializing)...) 494 shardSet, err := sharding.NewShardSet(shards, nil) 495 require.NoError(t, err) 496 497 ns.EXPECT().AssignShardSet(shardSet) 498 499 var wg sync.WaitGroup 500 wg.Add(1) 501 mediator.EXPECT(). 502 BootstrapEnqueue(gomock.Any()). 503 Do(func(_ BootstrapEnqueueOptions) { 504 wg.Done() 505 }) 506 507 d.AssignShardSet(shardSet) 508 509 wg.Wait() 510 } 511 512 func TestDatabaseAssignShardSetDuringBootstrap(t *testing.T) { 513 ctrl := xtest.NewController(t) 514 defer ctrl.Finish() 515 516 var wgBootstrap, wgAssignShards sync.WaitGroup 517 wgBootstrap.Add(3) 518 wgAssignShards.Add(1) 519 520 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 521 defer func() { 522 close(mapCh) 523 }() 524 525 ns := dbAddNewMockNamespace(ctrl, d, "testns") 526 527 newShards := append(sharding.NewShards([]uint32{0}, shard.Available), 528 shard.NewShard(1).SetState(shard.Leaving), 529 shard.NewShard(2).SetState(shard.Initializing)) 530 531 newShardSet, err := sharding.NewShardSet(newShards, nil) 532 require.NoError(t, err) 533 534 ns.EXPECT().AssignShardSet(newShardSet) 535 536 mediator := NewMockdatabaseMediator(ctrl) 537 mediator.EXPECT().IsOpen().Return(true).AnyTimes() 538 mediator.EXPECT().DisableFileOpsAndWait().AnyTimes() 539 mediator.EXPECT().EnableFileOps().AnyTimes() 540 mediator.EXPECT(). 541 BootstrapEnqueue(gomock.Any()). 542 Do(func(_ BootstrapEnqueueOptions) { 543 wgBootstrap.Done() 544 }) 545 mediator.EXPECT().Bootstrap().DoAndReturn(func() (BootstrapResult, error) { 546 go func() { 547 // make sure bootstrap not finished before assigning new shards. 548 wgAssignShards.Done() 549 d.AssignShardSet(newShardSet) 550 wgBootstrap.Done() 551 }() 552 wgAssignShards.Wait() 553 time.Sleep(time.Second) 554 // AssignShardSet should wait on lock and not update new shardset yet. 555 require.NotEqual(t, newShardSet, d.shardSet) 556 return BootstrapResult{}, nil 557 }) 558 d.mediator = mediator 559 560 go func() { 561 require.NoError(t, d.Bootstrap()) 562 wgBootstrap.Done() 563 }() 564 wgBootstrap.Wait() 565 require.Equal(t, newShardSet, d.shardSet) 566 } 567 568 func TestDatabaseUpdateOwnedNamespacesDuringBootstrap(t *testing.T) { 569 ctrl := xtest.NewController(t) 570 defer ctrl.Finish() 571 572 var wgBootstrap, wgUpdateNs sync.WaitGroup 573 wgBootstrap.Add(3) 574 wgUpdateNs.Add(1) 575 576 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 577 defer func() { 578 close(mapCh) 579 }() 580 581 // check initial namespaces 582 require.Len(t, d.Namespaces(), 2) 583 584 md1, err := namespace.NewMetadata(defaultTestNs1ID, defaultTestNs1Opts) 585 require.NoError(t, err) 586 md2, err := namespace.NewMetadata(defaultTestNs2ID, defaultTestNs2Opts) 587 require.NoError(t, err) 588 md3, err := namespace.NewMetadata(ident.StringID("ns3"), defaultTestNs2Opts) 589 require.NoError(t, err) 590 nsMap, err := namespace.NewMap([]namespace.Metadata{md1, md2, md3}) 591 require.NoError(t, err) 592 593 mediator := NewMockdatabaseMediator(ctrl) 594 mediator.EXPECT().IsOpen().Return(true).AnyTimes() 595 mediator.EXPECT().DisableFileOpsAndWait().AnyTimes() 596 mediator.EXPECT().EnableFileOps().AnyTimes() 597 mediator.EXPECT(). 598 BootstrapEnqueue(gomock.Any()). 599 Do(func(_ BootstrapEnqueueOptions) { 600 wgBootstrap.Done() 601 }) 602 mediator.EXPECT().Bootstrap().DoAndReturn(func() (BootstrapResult, error) { 603 go func() { 604 // make sure bootstrap not finished before updating namespaces. 605 wgUpdateNs.Done() 606 require.NoError(t, d.UpdateOwnedNamespaces(nsMap)) 607 wgBootstrap.Done() 608 }() 609 wgUpdateNs.Wait() 610 time.Sleep(time.Second) 611 // UpdateOwnedNamespaces should wait on lock and not update namespaces yet. 612 require.Len(t, d.Namespaces(), 2) 613 return BootstrapResult{}, nil 614 }) 615 d.mediator = mediator 616 617 go func() { 618 require.NoError(t, d.Bootstrap()) 619 wgBootstrap.Done() 620 }() 621 wgBootstrap.Wait() 622 require.Len(t, d.Namespaces(), 3) 623 } 624 625 func TestDatabaseRemoveNamespace(t *testing.T) { 626 ctrl := xtest.NewController(t) 627 defer ctrl.Finish() 628 629 d, mapCh, testReporter := defaultTestDatabase(t, ctrl, Bootstrapped) 630 require.NoError(t, d.Open()) 631 defer func() { 632 close(mapCh) 633 require.NoError(t, d.Close()) 634 leaktest.CheckTimeout(t, time.Second)() 635 }() 636 637 // retrieve the update channel to track propatation 638 updateCh := d.opts.NamespaceInitializer().(*mockNsInitializer).updateCh 639 640 // check initial namespaces 641 nses := d.Namespaces() 642 require.Len(t, nses, 2) 643 644 // construct new namespace Map 645 md1, err := namespace.NewMetadata(defaultTestNs1ID, defaultTestNs1Opts) 646 require.NoError(t, err) 647 nsMap, err := namespace.NewMap([]namespace.Metadata{md1}) 648 require.NoError(t, err) 649 650 // update the database watch with new Map 651 mapCh <- nsMap 652 653 // wait till the update has propagated 654 <-updateCh 655 <-updateCh 656 657 // the updateCh gets are in-sufficient to determine the update has been applied 658 // to the database, they only measure if the watch itself has been updated. It 659 // can take a few ms until the DB finds those values. 660 require.True(t, xclock.WaitUntil(func() bool { 661 counter, ok := testReporter.Counters()["database.namespace-watch.updates"] 662 return ok && counter == 1 663 }, 2*time.Second)) 664 require.True(t, xclock.WaitUntil(func() bool { 665 return len(d.Namespaces()) == 2 666 }, 2*time.Second)) 667 } 668 669 func TestDatabaseAddNamespace(t *testing.T) { 670 ctrl := xtest.NewController(t) 671 defer ctrl.Finish() 672 673 d, mapCh, testReporter := defaultTestDatabase(t, ctrl, Bootstrapped) 674 require.NoError(t, d.Open()) 675 defer func() { 676 close(mapCh) 677 require.NoError(t, d.Close()) 678 leaktest.CheckTimeout(t, time.Second)() 679 }() 680 681 // retrieve the update channel to track propatation 682 updateCh := d.opts.NamespaceInitializer().(*mockNsInitializer).updateCh 683 684 // check initial namespaces 685 nses := d.Namespaces() 686 require.Len(t, nses, 2) 687 688 md1, md2, _, nsMap := addNamespace(t, "and1") 689 690 // update the database watch with new Map 691 mapCh <- nsMap 692 693 // wait till the update has propagated 694 <-updateCh 695 <-updateCh 696 697 // the updateCh gets are in-sufficient to determine the update has been applied 698 // to the database, they only measure if the watch itself has been updated. It 699 // can take a few ms until the DB finds those values. 700 require.True(t, xclock.WaitUntil(func() bool { 701 counter, ok := testReporter.Counters()["database.namespace-watch.updates"] 702 return ok && counter == 1 703 }, 2*time.Second)) 704 require.True(t, xclock.WaitUntil(func() bool { 705 return len(d.Namespaces()) == 3 706 }, 2*time.Second)) 707 708 // ensure the expected namespaces exist 709 nses = d.Namespaces() 710 require.Len(t, nses, 3) 711 ns1, ok := d.Namespace(defaultTestNs1ID) 712 require.True(t, ok) 713 require.Equal(t, md1.Options(), ns1.Options()) 714 ns2, ok := d.Namespace(defaultTestNs2ID) 715 require.True(t, ok) 716 require.Equal(t, md2.Options(), ns2.Options()) 717 ns3, ok := d.Namespace(ident.StringID("and1")) 718 require.True(t, ok) 719 require.Equal(t, md1.Options(), ns3.Options()) 720 assertFileOpsEnabled(t, d) 721 } 722 723 type testNamespaceHooks struct { 724 sync.Mutex 725 adds int 726 } 727 728 func (th *testNamespaceHooks) addCount() int { 729 th.Lock() 730 defer th.Unlock() 731 return th.adds 732 } 733 734 func (th *testNamespaceHooks) OnCreatedNamespace(Namespace, GetNamespaceFn) error { 735 th.Lock() 736 defer th.Unlock() 737 th.adds++ 738 return nil 739 } 740 741 func TestDatabaseAddNamespaceBootstrapEnqueue(t *testing.T) { 742 ctrl := xtest.NewController(t) 743 defer ctrl.Finish() 744 745 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 746 require.NoError(t, d.Open()) 747 defer func() { 748 close(mapCh) 749 require.NoError(t, d.Close()) 750 leaktest.CheckTimeout(t, time.Second)() 751 }() 752 753 // retrieve the update channel to track propatation 754 updateCh := d.opts.NamespaceInitializer().(*mockNsInitializer).updateCh 755 756 nsHooks := &testNamespaceHooks{} 757 d.opts = d.opts.SetNamespaceHooks(nsHooks) 758 d.bootstraps++ 759 760 // check initial namespaces 761 nses := d.Namespaces() 762 require.Len(t, nses, 2) 763 764 _, _, md3, nsMap := addNamespace(t, "nsNew") 765 766 // update the database watch with new Map 767 mapCh <- nsMap 768 769 // wait till the update has propagated 770 <-updateCh 771 <-updateCh 772 773 // Because ns update will be enqueued and performed later, we need to wait for more time in theory. 774 // Usually this update should complete in a few seconds. 775 require.True(t, xclock.WaitUntil(func() bool { 776 return nsHooks.addCount() == 1 777 }, 1*time.Minute)) 778 require.True(t, xclock.WaitUntil(func() bool { 779 return len(d.Namespaces()) == 3 780 }, 2*time.Second)) 781 782 // ensure the expected namespaces exist 783 nses = d.Namespaces() 784 require.Len(t, nses, 3) 785 ns3, ok := d.Namespace(ident.StringID("nsNew")) 786 require.True(t, ok) 787 require.Equal(t, md3.Options(), ns3.Options()) 788 assertFileOpsEnabled(t, d) 789 } 790 791 type errorNamespaceHooks struct{} 792 793 func (th *errorNamespaceHooks) OnCreatedNamespace(Namespace, GetNamespaceFn) error { 794 return errors.New("failed to create namespace") 795 } 796 797 func TestDatabaseAddNamespaceErrorAfterWaitForFileOps(t *testing.T) { 798 ctrl := xtest.NewController(t) 799 defer ctrl.Finish() 800 801 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 802 require.NoError(t, d.Open()) 803 defer func() { 804 close(mapCh) 805 require.NoError(t, d.Close()) 806 leaktest.CheckTimeout(t, time.Second)() 807 }() 808 809 nsHooks := &errorNamespaceHooks{} 810 d.opts = d.opts.SetNamespaceHooks(nsHooks) 811 812 _, _, _, nsMap := addNamespace(t, "testns3") 813 d.bootstraps = 1 814 815 require.Error(t, d.UpdateOwnedNamespaces(nsMap)) 816 assertFileOpsEnabled(t, d) 817 } 818 819 func TestDatabaseAddNamespaceBootstrapEnqueueMediatorClosed(t *testing.T) { 820 ctrl := xtest.NewController(t) 821 defer ctrl.Finish() 822 823 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 824 require.NoError(t, d.Open()) 825 mediator := d.mediator 826 defer func() { 827 close(mapCh) 828 d.mediator = mediator 829 require.NoError(t, d.Close()) 830 leaktest.CheckTimeout(t, time.Second)() 831 }() 832 833 // retrieve the update channel to track propatation 834 updateCh := d.opts.NamespaceInitializer().(*mockNsInitializer).updateCh 835 836 nsHooks := &testNamespaceHooks{} 837 d.opts = d.opts.SetNamespaceHooks(nsHooks) 838 mockMediator := NewMockdatabaseMediator(ctrl) 839 mockMediator.EXPECT().IsOpen().Return(false).AnyTimes() 840 mockMediator.EXPECT().BootstrapEnqueue(gomock.Any()) 841 d.mediator = mockMediator 842 843 // check initial namespaces 844 nses := d.Namespaces() 845 require.Len(t, nses, 2) 846 847 _, _, md3, nsMap := addNamespace(t, "testns3") 848 d.bootstraps = 1 849 // update the database watch with new Map 850 mapCh <- nsMap 851 852 // wait till the update has propagated 853 <-updateCh 854 <-updateCh 855 856 // Because ns update will be enqueued and performed later, we need to wait for more time in theory. 857 // Usually this update should complete in a few seconds. 858 require.True(t, xclock.WaitUntil(func() bool { 859 return nsHooks.addCount() == 1 860 }, time.Minute)) 861 require.True(t, xclock.WaitUntil(func() bool { 862 return len(d.Namespaces()) == 3 863 }, 2*time.Second)) 864 865 // ensure the expected namespaces exist 866 nses = d.Namespaces() 867 require.Len(t, nses, 3) 868 ns3, ok := d.Namespace(ident.StringID("testns3")) 869 require.True(t, ok) 870 require.Equal(t, md3.Options(), ns3.Options()) 871 } 872 873 func addNamespace( 874 t *testing.T, 875 ns string, 876 ) (namespace.Metadata, namespace.Metadata, namespace.Metadata, namespace.Map) { 877 // construct new namespace Map 878 md1, err := namespace.NewMetadata(defaultTestNs1ID, defaultTestNs1Opts) 879 require.NoError(t, err) 880 md2, err := namespace.NewMetadata(defaultTestNs2ID, defaultTestNs2Opts) 881 require.NoError(t, err) 882 md3, err := namespace.NewMetadata(ident.StringID(ns), defaultTestNs1Opts) 883 require.NoError(t, err) 884 nsMap, err := namespace.NewMap([]namespace.Metadata{md1, md2, md3}) 885 require.NoError(t, err) 886 return md1, md2, md3, nsMap 887 } 888 889 func TestDatabaseUpdateNamespace(t *testing.T) { 890 ctrl := xtest.NewController(t) 891 defer ctrl.Finish() 892 893 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 894 require.NoError(t, d.Open()) 895 defer func() { 896 close(mapCh) 897 require.NoError(t, d.Close()) 898 leaktest.CheckTimeout(t, time.Second)() 899 }() 900 901 // retrieve the update channel to track propatation 902 updateCh := d.opts.NamespaceInitializer().(*mockNsInitializer).updateCh 903 904 // check initial namespaces 905 nses := d.Namespaces() 906 require.Len(t, nses, 2) 907 908 // construct new namespace Map 909 ropts := defaultTestNs1Opts.RetentionOptions().SetRetentionPeriod(2000 * time.Hour) 910 md1, err := namespace.NewMetadata(defaultTestNs1ID, defaultTestNs1Opts.SetRetentionOptions(ropts)) 911 require.NoError(t, err) 912 md2, err := namespace.NewMetadata(defaultTestNs2ID, defaultTestNs2Opts) 913 require.NoError(t, err) 914 nsMap, err := namespace.NewMap([]namespace.Metadata{md1, md2}) 915 require.NoError(t, err) 916 917 // update the database watch with new Map 918 mapCh <- nsMap 919 920 // wait till the update has propagated 921 <-updateCh 922 <-updateCh 923 time.Sleep(10 * time.Millisecond) 924 925 // ensure the namespaces have old properties 926 nses = d.Namespaces() 927 require.Len(t, nses, 2) 928 ns1, ok := d.Namespace(defaultTestNs1ID) 929 require.True(t, ok) 930 require.Equal(t, defaultTestNs1Opts, ns1.Options()) 931 ns2, ok := d.Namespace(defaultTestNs2ID) 932 require.True(t, ok) 933 require.Equal(t, defaultTestNs2Opts, ns2.Options()) 934 935 // Ensure schema is not set and no error 936 require.Nil(t, ns1.Schema()) 937 require.Nil(t, ns2.Schema()) 938 schema, err := d.Options().SchemaRegistry().GetLatestSchema(defaultTestNs2ID) 939 require.NoError(t, err) 940 require.Nil(t, schema) 941 } 942 943 func TestDatabaseCreateSchemaNotSet(t *testing.T) { 944 protoTestDatabaseOptions := DefaultTestOptions(). 945 SetSchemaRegistry(namespace.NewSchemaRegistry(true, nil)) 946 947 ctrl := xtest.NewController(t) 948 defer ctrl.Finish() 949 950 // Start the database with two namespaces, one miss configured (missing schema). 951 nsID1 := ident.StringID("testns1") 952 md1, err := namespace.NewMetadata(nsID1, defaultTestNs1Opts.SetSchemaHistory(testSchemaHistory)) 953 require.NoError(t, err) 954 nsID2 := ident.StringID("testns2") 955 md2, err := namespace.NewMetadata(nsID2, defaultTestNs1Opts) 956 require.NoError(t, err) 957 nsMap, err := namespace.NewMap([]namespace.Metadata{md1, md2}) 958 require.NoError(t, err) 959 960 d, mapCh, _ := newTestDatabase(t, ctrl, newTestDatabaseOpt{bs: Bootstrapped, nsMap: nsMap, dbOpt: protoTestDatabaseOptions}) 961 require.NoError(t, d.Open()) 962 defer func() { 963 close(mapCh) 964 require.NoError(t, d.Close()) 965 leaktest.CheckTimeout(t, time.Second)() 966 }() 967 968 // check initial namespaces 969 nses := d.Namespaces() 970 require.Len(t, nses, 1) 971 972 _, ok := d.Namespace(nsID1) 973 require.True(t, ok) 974 _, ok = d.Namespace(nsID2) 975 require.False(t, ok) 976 } 977 978 func TestDatabaseUpdateNamespaceSchemaNotSet(t *testing.T) { 979 protoTestDatabaseOptions := DefaultTestOptions(). 980 SetSchemaRegistry(namespace.NewSchemaRegistry(true, nil)) 981 982 ctrl := xtest.NewController(t) 983 defer ctrl.Finish() 984 985 // Start db with no namespaces. 986 d, mapCh, _ := newTestDatabase(t, ctrl, newTestDatabaseOpt{bs: Bootstrapped, dbOpt: protoTestDatabaseOptions}) 987 require.NoError(t, d.Open()) 988 defer func() { 989 close(mapCh) 990 require.NoError(t, d.Close()) 991 leaktest.CheckTimeout(t, time.Second)() 992 }() 993 994 // retrieve the update channel to track propatation 995 updateCh := d.opts.NamespaceInitializer().(*mockNsInitializer).updateCh 996 997 // check initial namespaces 998 nses := d.Namespaces() 999 require.Len(t, nses, 0) 1000 1001 // construct new namespace Map 1002 nsID3 := ident.StringID("testns3") 1003 md3, err := namespace.NewMetadata(nsID3, defaultTestNs1Opts) 1004 require.NoError(t, err) 1005 nsMap, err := namespace.NewMap([]namespace.Metadata{md3}) 1006 require.NoError(t, err) 1007 1008 // update the database watch with new Map 1009 mapCh <- nsMap 1010 1011 // wait till the update has propagated 1012 time.Sleep(10 * time.Millisecond) 1013 1014 // ensure the namespace3 is not created successfully. 1015 nses = d.Namespaces() 1016 require.Len(t, nses, 0) 1017 1018 // Update nsID3 schema 1019 md3, err = namespace.NewMetadata(nsID3, defaultTestNs1Opts.SetSchemaHistory(testSchemaHistory)) 1020 require.NoError(t, err) 1021 nsMap, err = namespace.NewMap([]namespace.Metadata{md3}) 1022 require.NoError(t, err) 1023 1024 // update the database watch with new Map 1025 mapCh <- nsMap 1026 1027 // wait till the update has propagated 1028 time.Sleep(10 * time.Millisecond) 1029 1030 // Ensure the namespace3 is created successfully. 1031 nses = d.Namespaces() 1032 require.Len(t, nses, 1) 1033 ns3, ok := d.Namespace(nsID3) 1034 require.True(t, ok) 1035 1036 // Ensure schema is set 1037 require.NotNil(t, ns3.Schema()) 1038 1039 schema, err := d.Options().SchemaRegistry().GetLatestSchema(nsID3) 1040 require.NoError(t, err) 1041 require.NotNil(t, schema) 1042 1043 // Update nsID3 schema to empty 1044 md3, err = namespace.NewMetadata(nsID3, defaultTestNs1Opts) 1045 require.NoError(t, err) 1046 nsMap, err = namespace.NewMap([]namespace.Metadata{md3}) 1047 require.NoError(t, err) 1048 1049 // update the database watch with new Map 1050 mapCh <- nsMap 1051 1052 // wait till the update has propagated 1053 <-updateCh 1054 time.Sleep(10 * time.Millisecond) 1055 1056 // Ensure schema is not set to empty 1057 require.NotNil(t, ns3.Schema()) 1058 1059 schema, err = d.Options().SchemaRegistry().GetLatestSchema(nsID3) 1060 require.NoError(t, err) 1061 require.NotNil(t, schema) 1062 } 1063 1064 func TestDatabaseNamespaceIndexFunctions(t *testing.T) { 1065 testDatabaseNamespaceIndexFunctions(t, true) 1066 } 1067 1068 func TestDatabaseNamespaceIndexFunctionsNoCommitlog(t *testing.T) { 1069 testDatabaseNamespaceIndexFunctions(t, false) 1070 } 1071 1072 func testDatabaseNamespaceIndexFunctions(t *testing.T, commitlogEnabled bool) { 1073 ctrl := xtest.NewController(t) 1074 defer ctrl.Finish() 1075 1076 d, mapCh, _ := defaultTestDatabase(t, ctrl, BootstrapNotStarted) 1077 defer func() { 1078 close(mapCh) 1079 }() 1080 1081 commitLog := d.commitLog 1082 if !commitlogEnabled { 1083 // We don't mock the commitlog so set this to nil to ensure its 1084 // not being used as the test will panic if any methods are called 1085 // on it. 1086 d.commitLog = nil 1087 } 1088 1089 ns := dbAddNewMockNamespace(ctrl, d, "testns") 1090 nsOptions := namespace.NewOptions(). 1091 SetWritesToCommitLog(commitlogEnabled) 1092 1093 ns.EXPECT().OwnedShards().Return([]databaseShard{}).AnyTimes() 1094 ns.EXPECT().Tick(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() 1095 ns.EXPECT().ShardBootstrapState().Return(ShardBootstrapStates{}).AnyTimes() 1096 ns.EXPECT().Options().Return(nsOptions).AnyTimes() 1097 require.NoError(t, d.Open()) 1098 1099 var ( 1100 now = xtime.Now() 1101 namespace = ident.StringID("testns") 1102 ctx = context.NewBackground() 1103 id = ident.StringID("foo") 1104 tagsIter = ident.EmptyTagIterator 1105 seriesWrite = SeriesWrite{ 1106 Series: ts.Series{ 1107 ID: id, 1108 Namespace: namespace, 1109 }, 1110 WasWritten: true, 1111 } 1112 ) 1113 1114 // create initial span from a mock tracer and get ctx 1115 mtr := mocktracer.New() 1116 sp := mtr.StartSpan("root") 1117 ctx.SetGoContext(opentracing.ContextWithSpan(stdlibctx.Background(), sp)) 1118 1119 ns.EXPECT().WriteTagged(gomock.Any(), ident.NewIDMatcher("foo"), gomock.Any(), 1120 now, 1.0, xtime.Second, nil).Return(seriesWrite, nil) 1121 require.NoError(t, d.WriteTagged(ctx, namespace, 1122 id, convert.NewTagsIterMetadataResolver(tagsIter), now, 1123 1.0, xtime.Second, nil)) 1124 1125 ns.EXPECT().WriteTagged(gomock.Any(), ident.NewIDMatcher("foo"), gomock.Any(), 1126 now, 1.0, xtime.Second, nil).Return(SeriesWrite{}, fmt.Errorf("random err")) 1127 require.Error(t, d.WriteTagged(ctx, namespace, 1128 ident.StringID("foo"), convert.EmptyTagMetadataResolver, now, 1129 1.0, xtime.Second, nil)) 1130 1131 var ( 1132 q = index.Query{ 1133 Query: idx.NewTermQuery([]byte("foo"), []byte("bar")), 1134 } 1135 opts = index.QueryOptions{} 1136 res = index.QueryResult{} 1137 aggOpts = index.AggregationOptions{} 1138 aggRes = index.AggregateQueryResult{} 1139 err error 1140 ) 1141 ctx.SetGoContext(opentracing.ContextWithSpan(stdlibctx.Background(), sp)) 1142 ns.EXPECT().QueryIDs(gomock.Any(), q, opts).Return(res, nil) 1143 _, err = d.QueryIDs(ctx, ident.StringID("testns"), q, opts) 1144 require.NoError(t, err) 1145 1146 ns.EXPECT().QueryIDs(gomock.Any(), q, opts).Return(res, fmt.Errorf("random err")) 1147 _, err = d.QueryIDs(ctx, ident.StringID("testns"), q, opts) 1148 require.Error(t, err) 1149 1150 ns.EXPECT().AggregateQuery(gomock.Any(), q, aggOpts).Return(aggRes, nil) 1151 _, err = d.AggregateQuery(ctx, ident.StringID("testns"), q, aggOpts) 1152 require.NoError(t, err) 1153 1154 ns.EXPECT().AggregateQuery(gomock.Any(), q, aggOpts). 1155 Return(aggRes, fmt.Errorf("random err")) 1156 _, err = d.AggregateQuery(ctx, ident.StringID("testns"), q, aggOpts) 1157 require.Error(t, err) 1158 1159 ns.EXPECT().Close().Return(nil) 1160 1161 // Ensure commitlog is set before closing because this will call commitlog.Close() 1162 d.commitLog = commitLog 1163 require.NoError(t, d.Close()) 1164 1165 sp.Finish() 1166 spans := mtr.FinishedSpans() 1167 spanStrs := make([]string, 0, len(spans)) 1168 for _, s := range spans { 1169 spanStrs = append(spanStrs, s.OperationName) 1170 } 1171 exSpans := []string{ 1172 tracepoint.DBQueryIDs, 1173 tracepoint.DBQueryIDs, 1174 tracepoint.DBAggregateQuery, 1175 tracepoint.DBAggregateQuery, 1176 "root", 1177 } 1178 1179 assert.Equal(t, exSpans, spanStrs) 1180 } 1181 1182 func TestDatabaseWriteBatchNoNamespace(t *testing.T) { 1183 ctrl := xtest.NewController(t) 1184 defer ctrl.Finish() 1185 1186 d, mapCh, _ := defaultTestDatabase(t, ctrl, BootstrapNotStarted) 1187 defer func() { 1188 close(mapCh) 1189 }() 1190 require.NoError(t, d.Open()) 1191 1192 var ( 1193 notExistNamespace = ident.StringID("not-exist-namespace") 1194 batchSize = 100 1195 ) 1196 _, err := d.BatchWriter(notExistNamespace, batchSize) 1197 require.Error(t, err) 1198 1199 err = d.WriteBatch(context.NewBackground(), notExistNamespace, nil, nil) 1200 require.Error(t, err) 1201 1202 require.NoError(t, d.Close()) 1203 } 1204 1205 func TestDatabaseWriteTaggedBatchNoNamespace(t *testing.T) { 1206 ctrl := xtest.NewController(t) 1207 defer ctrl.Finish() 1208 1209 d, mapCh, _ := defaultTestDatabase(t, ctrl, BootstrapNotStarted) 1210 defer func() { 1211 close(mapCh) 1212 }() 1213 require.NoError(t, d.Open()) 1214 1215 var ( 1216 notExistNamespace = ident.StringID("not-exist-namespace") 1217 batchSize = 100 1218 ) 1219 _, err := d.BatchWriter(notExistNamespace, batchSize) 1220 require.Error(t, err) 1221 1222 err = d.WriteTaggedBatch(context.NewBackground(), notExistNamespace, nil, nil) 1223 require.Error(t, err) 1224 1225 require.NoError(t, d.Close()) 1226 } 1227 1228 func TestDatabaseWrite(t *testing.T) { 1229 dbWriteTests := []struct { 1230 name string 1231 tagged, commitlogEnabled, skipAll bool 1232 }{ 1233 {"batch", false, false, false}, 1234 {"tagged batch", true, false, false}, 1235 {"batch no commitlog", false, true, false}, 1236 {"tagged batch no commitlog", true, true, false}, 1237 {"batch skip all", false, false, true}, 1238 {"tagged batch skip all", true, false, true}, 1239 {"batch no commitlog skip all", false, true, true}, 1240 {"tagged batch no commitlog skip all", true, true, true}, 1241 } 1242 1243 for _, tt := range dbWriteTests { 1244 t.Run(tt.name, func(t *testing.T) { 1245 testDatabaseWriteBatch(t, tt.tagged, tt.commitlogEnabled, tt.skipAll) 1246 }) 1247 } 1248 } 1249 1250 type fakeIndexedErrorHandler struct { 1251 errs []indexedErr 1252 } 1253 1254 func (f *fakeIndexedErrorHandler) HandleError(index int, err error) { 1255 f.errs = append(f.errs, indexedErr{index, err}) 1256 } 1257 1258 type indexedErr struct { 1259 index int 1260 err error 1261 } 1262 1263 func testDatabaseWriteBatch(t *testing.T, 1264 tagged bool, commitlogEnabled bool, skipAll bool) { 1265 ctrl := xtest.NewController(t) 1266 defer ctrl.Finish() 1267 1268 d, mapCh, _ := defaultTestDatabase(t, ctrl, BootstrapNotStarted) 1269 defer func() { 1270 close(mapCh) 1271 }() 1272 1273 commitLog := d.commitLog 1274 if !commitlogEnabled { 1275 // We don't mock the commitlog so set this to nil to ensure its 1276 // not being used as the test will panic if any methods are called 1277 // on it. 1278 d.commitLog = nil 1279 } 1280 1281 ns := dbAddNewMockNamespace(ctrl, d, "testns") 1282 nsOptions := namespace.NewOptions(). 1283 SetWritesToCommitLog(commitlogEnabled) 1284 1285 ns.EXPECT().OwnedShards().Return([]databaseShard{}).AnyTimes() 1286 ns.EXPECT().Tick(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() 1287 ns.EXPECT().ShardBootstrapState().Return(ShardBootstrapStates{}).AnyTimes() 1288 ns.EXPECT().Options().Return(nsOptions).AnyTimes() 1289 ns.EXPECT().Close().Return(nil).Times(1) 1290 require.NoError(t, d.Open()) 1291 1292 var ( 1293 namespace = ident.StringID("testns") 1294 ctx = context.NewBackground() 1295 tags = ident.NewTags(ident.Tag{ 1296 Name: ident.StringID("foo"), 1297 Value: ident.StringID("bar"), 1298 }, ident.Tag{ 1299 Name: ident.StringID("baz"), 1300 Value: ident.StringID("qux"), 1301 }) 1302 tagsIter = ident.NewTagsIterator(tags) 1303 ) 1304 1305 testTagEncodingPool := serialize.NewTagEncoderPool(serialize.NewTagEncoderOptions(), 1306 pool.NewObjectPoolOptions().SetSize(1)) 1307 testTagEncodingPool.Init() 1308 encoder := testTagEncodingPool.Get() 1309 err := encoder.Encode(tagsIter) 1310 require.NoError(t, err) 1311 1312 encodedTags, ok := encoder.Data() 1313 require.True(t, ok) 1314 1315 testWrites := []struct { 1316 series string 1317 t xtime.UnixNano 1318 v float64 1319 skip bool 1320 err error 1321 }{ 1322 { 1323 series: "won't appear - always skipped", 1324 t: xtime.UnixNano(0 * time.Second), 1325 skip: true, 1326 v: 0.0, 1327 }, 1328 { 1329 series: "foo", 1330 t: xtime.UnixNano(10 * time.Second), 1331 skip: skipAll, 1332 v: 1.0, 1333 }, 1334 { 1335 series: "bar", 1336 t: xtime.UnixNano(20 * time.Second), 1337 skip: skipAll, 1338 v: 2.0, 1339 }, 1340 { 1341 series: "baz", 1342 t: xtime.UnixNano(20 * time.Second), 1343 skip: skipAll, 1344 v: 3.0, 1345 }, 1346 { 1347 series: "qux", 1348 t: xtime.UnixNano(30 * time.Second), 1349 skip: skipAll, 1350 v: 4.0, 1351 }, 1352 { 1353 series: "won't appear - always skipped", 1354 t: xtime.UnixNano(40 * time.Second), 1355 skip: true, 1356 v: 5.0, 1357 }, 1358 { 1359 series: "error-series", 1360 err: errors.New("some-error"), 1361 }, 1362 } 1363 1364 batchWriter, err := d.BatchWriter(namespace, 10) 1365 require.NoError(t, err) 1366 1367 var i int 1368 for _, write := range testWrites { 1369 // Write with the provided index as i*2 so we can assert later that the 1370 // ErrorHandler is called with the provided index, not the actual position 1371 // in the WriteBatch slice. 1372 if tagged { 1373 batchWriter.AddTagged(i*2, ident.StringID(write.series), 1374 encodedTags.Bytes(), write.t, write.v, xtime.Second, nil) 1375 wasWritten := write.err == nil 1376 ns.EXPECT(). 1377 WriteTagged(ctx, ident.NewIDMatcher(write.series), gomock.Any(), 1378 write.t, write.v, xtime.Second, nil). 1379 Return(SeriesWrite{ 1380 Series: ts.Series{ 1381 ID: ident.StringID(write.series + "-updated"), 1382 Namespace: namespace, 1383 }, WasWritten: wasWritten, 1384 }, write.err) 1385 } else { 1386 batchWriter.Add(i*2, ident.StringID(write.series), 1387 write.t, write.v, xtime.Second, nil) 1388 wasWritten := write.err == nil 1389 ns.EXPECT(). 1390 Write(ctx, ident.NewIDMatcher(write.series), 1391 write.t, write.v, xtime.Second, nil). 1392 Return(SeriesWrite{ 1393 Series: ts.Series{ 1394 ID: ident.StringID(write.series + "-updated"), 1395 Namespace: namespace, 1396 }, 1397 WasWritten: wasWritten, 1398 }, write.err) 1399 } 1400 i++ 1401 } 1402 1403 errHandler := &fakeIndexedErrorHandler{} 1404 if tagged { 1405 err = d.WriteTaggedBatch(ctx, namespace, batchWriter.(writes.WriteBatch), 1406 errHandler) 1407 } else { 1408 err = d.WriteBatch(ctx, namespace, batchWriter.(writes.WriteBatch), 1409 errHandler) 1410 } 1411 1412 require.NoError(t, err) 1413 require.Len(t, errHandler.errs, 1) 1414 // Make sure it calls the error handler with the "original" provided index, not the position 1415 // of the write in the WriteBatch slice. 1416 require.Equal(t, (i-1)*2, errHandler.errs[0].index) 1417 1418 // Ensure commitlog is set before closing because this will call commitlog.Close() 1419 d.commitLog = commitLog 1420 require.NoError(t, d.Close()) 1421 } 1422 1423 func TestDatabaseBootstrapState(t *testing.T) { 1424 ctrl := xtest.NewController(t) 1425 defer ctrl.Finish() 1426 1427 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 1428 defer func() { 1429 close(mapCh) 1430 }() 1431 1432 ns1 := dbAddNewMockNamespace(ctrl, d, "testns1") 1433 ns1.EXPECT().ShardBootstrapState().Return(ShardBootstrapStates{ 1434 1: Bootstrapping, 1435 }) 1436 ns2 := dbAddNewMockNamespace(ctrl, d, "testns2") 1437 ns2.EXPECT().ShardBootstrapState().Return(ShardBootstrapStates{ 1438 2: Bootstrapped, 1439 }) 1440 1441 dbBootstrapState := d.BootstrapState() 1442 require.Equal(t, DatabaseBootstrapState{ 1443 NamespaceBootstrapStates: NamespaceBootstrapStates{ 1444 "testns1": ShardBootstrapStates{ 1445 1: Bootstrapping, 1446 }, 1447 "testns2": ShardBootstrapStates{ 1448 2: Bootstrapped, 1449 }, 1450 }, 1451 }, dbBootstrapState) 1452 } 1453 1454 func TestDatabaseFlushState(t *testing.T) { 1455 ctrl := xtest.NewController(t) 1456 defer ctrl.Finish() 1457 1458 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 1459 defer func() { 1460 close(mapCh) 1461 }() 1462 1463 var ( 1464 shardID = uint32(0) 1465 blockStart = xtime.Now().Truncate(2 * time.Hour) 1466 expectedFlushState = fileOpState{ 1467 ColdVersionRetrievable: 2, 1468 } 1469 nsID = "testns1" 1470 ns = dbAddNewMockNamespace(ctrl, d, nsID) 1471 ) 1472 ns.EXPECT().FlushState(shardID, blockStart).Return(expectedFlushState, nil) 1473 1474 flushState, err := d.FlushState(ident.StringID(nsID), shardID, blockStart) 1475 require.NoError(t, err) 1476 require.Equal(t, expectedFlushState, flushState) 1477 1478 _, err = d.FlushState(ident.StringID("not-exist"), shardID, blockStart) 1479 require.Error(t, err) 1480 } 1481 1482 func TestDatabaseIsBootstrapped(t *testing.T) { 1483 ctrl := xtest.NewController(t) 1484 defer ctrl.Finish() 1485 1486 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 1487 defer func() { 1488 close(mapCh) 1489 }() 1490 1491 md := NewMockdatabaseMediator(ctrl) 1492 md.EXPECT().IsBootstrapped().Return(true) 1493 md.EXPECT().IsBootstrapped().Return(false) 1494 d.mediator = md 1495 1496 assert.True(t, d.IsBootstrapped()) 1497 assert.False(t, d.IsBootstrapped()) 1498 } 1499 1500 func TestUpdateBatchWriterBasedOnShardResults(t *testing.T) { 1501 ctrl := xtest.NewController(t) 1502 defer ctrl.Finish() 1503 1504 d, mapCh, _ := defaultTestDatabase(t, ctrl, BootstrapNotStarted) 1505 defer func() { 1506 close(mapCh) 1507 }() 1508 1509 commitLog := d.commitLog 1510 d.commitLog = nil 1511 1512 ns := dbAddNewMockNamespace(ctrl, d, "testns") 1513 nsOptions := namespace.NewOptions(). 1514 SetWritesToCommitLog(false) 1515 ns.EXPECT().OwnedShards().Return([]databaseShard{}).AnyTimes() 1516 ns.EXPECT().Tick(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() 1517 ns.EXPECT().ShardBootstrapState().Return(ShardBootstrapStates{}).AnyTimes() 1518 ns.EXPECT().Options().Return(nsOptions).AnyTimes() 1519 ns.EXPECT().Close().Return(nil).Times(1) 1520 require.NoError(t, d.Open()) 1521 1522 var ( 1523 namespace = ident.StringID("testns") 1524 ctx = context.NewBackground() 1525 seriesWrite1 = SeriesWrite{Series: ts.Series{UniqueIndex: 0}, WasWritten: true} 1526 seriesWrite2 = SeriesWrite{Series: ts.Series{UniqueIndex: 1}, WasWritten: true} 1527 seriesWrite3 = SeriesWrite{Series: ts.Series{UniqueIndex: 2}, WasWritten: false} 1528 seriesWrite4 = SeriesWrite{Series: ts.Series{UniqueIndex: 3}, WasWritten: false} 1529 err = fmt.Errorf("err") 1530 ) 1531 1532 gomock.InOrder( 1533 ns.EXPECT(). 1534 Write(ctx, gomock.Any(), gomock.Any(), gomock.Any(), 1535 gomock.Any(), gomock.Any()). 1536 Return(seriesWrite1, nil), 1537 ns.EXPECT(). 1538 Write(ctx, gomock.Any(), gomock.Any(), gomock.Any(), 1539 gomock.Any(), gomock.Any()). 1540 Return(seriesWrite2, err), 1541 ns.EXPECT(). 1542 Write(ctx, gomock.Any(), gomock.Any(), gomock.Any(), 1543 gomock.Any(), gomock.Any()). 1544 Return(seriesWrite3, err), 1545 ns.EXPECT(). 1546 Write(ctx, gomock.Any(), gomock.Any(), gomock.Any(), 1547 gomock.Any(), gomock.Any()). 1548 Return(seriesWrite4, nil), 1549 ) 1550 1551 write := writes.Write{ 1552 Series: ts.Series{ID: ident.StringID("foo")}, 1553 } 1554 1555 iters := []writes.BatchWrite{ 1556 {Write: write}, 1557 {Write: write}, 1558 {Write: write}, 1559 {Write: write}, 1560 } 1561 1562 batchWriter := writes.NewMockWriteBatch(ctrl) 1563 gomock.InOrder( 1564 batchWriter.EXPECT().Iter().Return(iters), 1565 batchWriter.EXPECT().SetSeries(0, seriesWrite1.Series), 1566 batchWriter.EXPECT().SetError(1, err), 1567 batchWriter.EXPECT().SetError(2, err), 1568 batchWriter.EXPECT().SetSeries(3, seriesWrite4.Series), 1569 batchWriter.EXPECT().SetSkipWrite(3), 1570 batchWriter.EXPECT().PendingIndex().Return(nil), 1571 batchWriter.EXPECT().Finalize(), 1572 ) 1573 1574 errHandler := &fakeIndexedErrorHandler{} 1575 d.WriteBatch(ctx, namespace, batchWriter, errHandler) 1576 require.Equal(t, 2, len(errHandler.errs)) 1577 require.Equal(t, err, errHandler.errs[0].err) 1578 require.Equal(t, err, errHandler.errs[1].err) 1579 d.commitLog = commitLog 1580 require.NoError(t, d.Close()) 1581 } 1582 1583 func TestDatabaseIsOverloaded(t *testing.T) { 1584 ctrl := xtest.NewController(t) 1585 defer ctrl.Finish() 1586 1587 d, mapCh, _ := defaultTestDatabase(t, ctrl, BootstrapNotStarted) 1588 defer func() { 1589 close(mapCh) 1590 }() 1591 1592 d.opts = d.opts.SetCommitLogOptions( 1593 d.opts.CommitLogOptions().SetBacklogQueueSize(100), 1594 ) 1595 1596 mockCL := commitlog.NewMockCommitLog(ctrl) 1597 d.commitLog = mockCL 1598 1599 mockCL.EXPECT().QueueLength().Return(int64(89)) 1600 require.Equal(t, false, d.IsOverloaded()) 1601 1602 mockCL.EXPECT().QueueLength().Return(int64(90)) 1603 require.Equal(t, true, d.IsOverloaded()) 1604 } 1605 1606 func TestDatabaseAggregateTiles(t *testing.T) { 1607 ctrl := xtest.NewController(t) 1608 defer ctrl.Finish() 1609 1610 ctx := context.NewBackground() 1611 defer ctx.Close() 1612 1613 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 1614 defer func() { 1615 close(mapCh) 1616 }() 1617 1618 var ( 1619 sourceNsID = ident.StringID("source") 1620 targetNsID = ident.StringID("target") 1621 start = xtime.Now().Truncate(time.Hour) 1622 process = AggregateTilesAPI 1623 ) 1624 1625 opts, err := NewAggregateTilesOptions( 1626 start, start.Add(-time.Second), time.Minute, targetNsID, process, 1627 false, false, nil, d.opts.InstrumentOptions()) 1628 require.Error(t, err) 1629 opts.InsOptions = d.opts.InstrumentOptions() 1630 1631 sourceNs := dbAddNewMockNamespace(ctrl, d, sourceNsID.String()) 1632 targetNs := dbAddNewMockNamespace(ctrl, d, targetNsID.String()) 1633 targetNs.EXPECT().AggregateTiles(ctx, sourceNs, opts).Return(int64(4), nil) 1634 1635 processedTileCount, err := d.AggregateTiles(ctx, sourceNsID, targetNsID, opts) 1636 require.NoError(t, err) 1637 assert.Equal(t, int64(4), processedTileCount) 1638 } 1639 1640 func TestNewAggregateTilesOptions(t *testing.T) { 1641 var ( 1642 start = xtime.Now().Truncate(time.Hour) 1643 end = start.Add(time.Second) 1644 targetNs = ident.StringID("target") 1645 insOpts = instrument.NewOptions() 1646 process = AggregateTilesRegular 1647 ) 1648 1649 _, err := NewAggregateTilesOptions(start, start.Add(-time.Second), time.Minute, targetNs, process, 1650 false, false, nil, insOpts) 1651 assert.Error(t, err) 1652 1653 _, err = NewAggregateTilesOptions(start, start, time.Minute, targetNs, process, 1654 false, false, nil, insOpts) 1655 assert.Error(t, err) 1656 1657 _, err = NewAggregateTilesOptions(start, end, -time.Minute, targetNs, process, 1658 false, false, nil, insOpts) 1659 assert.Error(t, err) 1660 1661 _, err = NewAggregateTilesOptions(start, end, 0, targetNs, process, 1662 false, false, nil, insOpts) 1663 assert.Error(t, err) 1664 1665 _, err = NewAggregateTilesOptions(start, end, time.Minute, targetNs, process, 1666 false, false, nil, insOpts) 1667 assert.NoError(t, err) 1668 1669 _, err = NewAggregateTilesOptions(start, end, time.Minute, targetNs, process, 1670 true, false, nil, insOpts) 1671 assert.Error(t, err) 1672 1673 _, err = NewAggregateTilesOptions(start, end, time.Minute, targetNs, process, 1674 false, true, nil, insOpts) 1675 assert.Error(t, err) 1676 1677 _, err = NewAggregateTilesOptions(start, end, time.Minute, targetNs, process, 1678 true, true, nil, insOpts) 1679 assert.Error(t, err) 1680 1681 _, err = NewAggregateTilesOptions(start, end, time.Minute, targetNs, process, 1682 true, true, map[string]annotation.Payload{}, insOpts) 1683 assert.NoError(t, err) 1684 } 1685 1686 func TestShardsDelta(t *testing.T) { 1687 ctrl := xtest.NewController(t) 1688 defer ctrl.Finish() 1689 1690 ctx := context.NewBackground() 1691 defer ctx.Close() 1692 1693 d, mapCh, _ := defaultTestDatabase(t, ctrl, Bootstrapped) 1694 defer func() { 1695 close(mapCh) 1696 }() 1697 1698 shards := append(sharding.NewShards([]uint32{0, 1}, shard.Available), 1699 sharding.NewShards([]uint32{2}, shard.Initializing)...) 1700 shardSet, err := sharding.NewShardSet(shards, nil) 1701 require.NoError(t, err) 1702 1703 d.shardSet = shardSet 1704 1705 t.Run("unchanged", func(t *testing.T) { 1706 incoming := append(sharding.NewShards([]uint32{0, 1}, shard.Available), 1707 sharding.NewShards([]uint32{2}, shard.Initializing)...) 1708 shardSet, err = sharding.NewShardSet(incoming, nil) 1709 require.NoError(t, err) 1710 1711 added, removed, updated := d.shardsDeltaWithLock(shardSet) 1712 require.False(t, added) 1713 require.False(t, removed) 1714 require.False(t, updated) 1715 }) 1716 1717 t.Run("added-updated-deleted", func(t *testing.T) { 1718 incomingAddedRemovedUpdated := append(sharding.NewShards([]uint32{1, 2}, shard.Available), 1719 sharding.NewShards([]uint32{3}, shard.Initializing)...) 1720 shardSet, err = sharding.NewShardSet(incomingAddedRemovedUpdated, nil) 1721 require.NoError(t, err) 1722 added, removed, updated := d.shardsDeltaWithLock(shardSet) 1723 require.True(t, added) 1724 require.True(t, removed) 1725 require.True(t, updated) 1726 }) 1727 1728 t.Run("added", func(t *testing.T) { 1729 incomingAdded := append(sharding.NewShards([]uint32{0, 1}, shard.Available), 1730 sharding.NewShards([]uint32{2, 3}, shard.Initializing)...) 1731 shardSet, err = sharding.NewShardSet(incomingAdded, nil) 1732 require.NoError(t, err) 1733 added, removed, updated := d.shardsDeltaWithLock(shardSet) 1734 require.True(t, added) 1735 require.False(t, removed) 1736 require.False(t, updated) 1737 }) 1738 1739 t.Run("updated", func(t *testing.T) { 1740 incomingUpdated := sharding.NewShards([]uint32{0, 1, 2}, shard.Available) 1741 shardSet, err = sharding.NewShardSet(incomingUpdated, nil) 1742 require.NoError(t, err) 1743 added, removed, updated := d.shardsDeltaWithLock(shardSet) 1744 require.False(t, added) 1745 require.False(t, removed) 1746 require.True(t, updated) 1747 }) 1748 1749 t.Run("removed", func(t *testing.T) { 1750 incomingRemoved := sharding.NewShards([]uint32{0, 1}, shard.Available) 1751 shardSet, err = sharding.NewShardSet(incomingRemoved, nil) 1752 require.NoError(t, err) 1753 added, removed, updated := d.shardsDeltaWithLock(shardSet) 1754 require.False(t, added) 1755 require.True(t, removed) 1756 require.False(t, updated) 1757 }) 1758 1759 t.Run("added-updated", func(t *testing.T) { 1760 incomingAddedUpdated := append(sharding.NewShards([]uint32{0, 1, 2}, shard.Available), 1761 sharding.NewShards([]uint32{3}, shard.Initializing)...) 1762 shardSet, err = sharding.NewShardSet(incomingAddedUpdated, nil) 1763 require.NoError(t, err) 1764 added, removed, updated := d.shardsDeltaWithLock(shardSet) 1765 require.True(t, added) 1766 require.False(t, removed) 1767 require.True(t, updated) 1768 }) 1769 1770 t.Run("added-removed", func(t *testing.T) { 1771 incomingAddedRemoved := append(sharding.NewShards([]uint32{1}, shard.Available), 1772 sharding.NewShards([]uint32{3}, shard.Initializing)...) 1773 shardSet, err = sharding.NewShardSet(incomingAddedRemoved, nil) 1774 require.NoError(t, err) 1775 added, removed, updated := d.shardsDeltaWithLock(shardSet) 1776 require.True(t, added) 1777 require.True(t, removed) 1778 require.False(t, updated) 1779 }) 1780 1781 t.Run("updated-removed", func(t *testing.T) { 1782 incomingUpdatedRemoved := append(sharding.NewShards([]uint32{0}, shard.Available), 1783 sharding.NewShards([]uint32{1}, shard.Initializing)...) 1784 shardSet, err = sharding.NewShardSet(incomingUpdatedRemoved, nil) 1785 require.NoError(t, err) 1786 added, removed, updated := d.shardsDeltaWithLock(shardSet) 1787 require.False(t, added) 1788 require.True(t, removed) 1789 require.True(t, updated) 1790 }) 1791 } 1792 1793 func assertFileOpsEnabled(t *testing.T, d *db) { 1794 mediator := d.mediator.(*mediator) 1795 coldFlushManager := mediator.databaseColdFlushManager.(*coldFlushManager) 1796 fileSystemManager := mediator.databaseFileSystemManager.(*fileSystemManager) 1797 1798 coldFlushManager.RLock() 1799 require.True(t, coldFlushManager.enabled) 1800 coldFlushManager.RUnlock() 1801 1802 fileSystemManager.RLock() 1803 require.True(t, fileSystemManager.enabled) 1804 fileSystemManager.RUnlock() 1805 }