Skip to content

Commit 16589b0

Browse files
authored
CBG-5414: Create indexes in mobile collection only if mobile collections is enabled (#8351)
1 parent 92662ab commit 16589b0

3 files changed

Lines changed: 109 additions & 16 deletions

File tree

rest/database_init_manager.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func (m *DatabaseInitManager) InitializeDatabaseWithStatusCallback(ctx context.C
6666
base.MD(dbConfig.Name))
6767
dbInitWorker, ok := m.workers[dbConfig.Name]
6868

69-
collectionSet := buildCollectionIndexData(dbConfig, defaultCollectionExists)
69+
collectionSet := buildCollectionIndexData(startupConfig, dbConfig, defaultCollectionExists)
7070
if ok {
7171
// If worker exists for the database and the collection sets match, add watcher to the existing worker
7272
if dbInitWorker.collectionsEqual(collectionSet) {
@@ -226,10 +226,14 @@ func (m *DatabaseInitManager) cancelWorkers() {
226226
// customer may drop it once migration completes, at which point those indexes are vestigial and attempting to
227227
// build them on the missing collection would retry until the op times out and fail initialization. When
228228
// _default is gone (and not itself a configured data collection) it is omitted from the index set.
229-
func buildCollectionIndexData(config *DatabaseConfig, defaultCollectionExists bool) CollectionInitData {
229+
func buildCollectionIndexData(startup *StartupConfig, config *DatabaseConfig, defaultCollectionExists bool) CollectionInitData {
230+
useSystemMetadataCollection := resolveUseSystemMetadataCollection(startup, &config.DbConfig)
230231
if len(config.Scopes) == 0 {
231-
// todo: only init these mobile collection indexes when required?
232-
return CollectionInitData{base.DefaultScopeAndCollectionName(): db.IndexesAll, base.MobileSystemScopeAndCollectionName(): db.IndexesMetadataOnly}
232+
if useSystemMetadataCollection {
233+
return CollectionInitData{base.DefaultScopeAndCollectionName(): db.IndexesAll, base.MobileSystemScopeAndCollectionName(): db.IndexesMetadataOnly}
234+
} else {
235+
return CollectionInitData{base.DefaultScopeAndCollectionName(): db.IndexesAll}
236+
}
233237
}
234238

235239
defaultScopeAndCollectionMetadataIndexes := db.IndexesMetadataOnly
@@ -253,8 +257,9 @@ func buildCollectionIndexData(config *DatabaseConfig, defaultCollectionExists bo
253257
if defaultCollectionExists || defaultIsConfiguredCollection {
254258
collectionInitData[base.DefaultScopeAndCollectionName()] = defaultScopeAndCollectionMetadataIndexes
255259
}
256-
// todo: only init these indexes when required?
257-
collectionInitData[base.MobileSystemScopeAndCollectionName()] = db.IndexesMetadataOnly
260+
if useSystemMetadataCollection {
261+
collectionInitData[base.MobileSystemScopeAndCollectionName()] = db.IndexesMetadataOnly
262+
}
258263

259264
return collectionInitData
260265
}

rest/database_init_manager_test.go

Lines changed: 96 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ func TestDatabaseInitConfigChangeSameCollections(t *testing.T) {
109109

110110
dbName := "dbName"
111111
dbConfig := makeDbConfig(tb.GetName(), dbName, collection1and2ScopesConfig)
112+
dbConfig.UseSystemMobileMetadataCollection = base.Ptr(true)
112113
require.NoError(t, dbConfig.setup(ctx, dbName, sc.Config.Bootstrap, nil, nil, false))
113114

114115
// Start first async index creation, blocks after first collection
@@ -199,6 +200,7 @@ func TestDatabaseInitConfigChangeDifferentCollections(t *testing.T) {
199200
dbName := "dbName"
200201
dbConfig := makeDbConfig(tb.GetName(), dbName, collection1and2ScopesConfig)
201202
require.NoError(t, dbConfig.setup(ctx, dbName, sc.Config.Bootstrap, nil, nil, false))
203+
dbConfig.UseSystemMobileMetadataCollection = base.Ptr(true)
202204

203205
// Start first async index creation, should block after first collection
204206
doneChan, err := initMgr.InitializeDatabase(ctx, sc.Config, dbConfig.ToDatabaseConfig(), testUseLegacySyncDocsIndex, true)
@@ -210,6 +212,7 @@ func TestDatabaseInitConfigChangeDifferentCollections(t *testing.T) {
210212
// Make a call to initialize database for the same db name, different collections
211213
modifiedDbConfig := makeDbConfig(tb.GetName(), dbName, collection1and3ScopesConfig)
212214
require.NoError(t, modifiedDbConfig.setup(ctx, dbName, sc.Config.Bootstrap, nil, nil, false))
215+
modifiedDbConfig.UseSystemMobileMetadataCollection = base.Ptr(true)
213216
modifiedDoneChan, err := initMgr.InitializeDatabase(ctx, sc.Config, modifiedDbConfig.ToDatabaseConfig(), testUseLegacySyncDocsIndex, true)
214217
require.NoError(t, err)
215218

@@ -286,10 +289,12 @@ func TestDatabaseInitConcurrentDatabasesSameBucket(t *testing.T) {
286289
db1Name := "db1Name"
287290
db1Config := makeDbConfig(tb.GetName(), db1Name, collection1and2ScopesConfig)
288291
require.NoError(t, db1Config.setup(ctx, db1Name, sc.Config.Bootstrap, nil, nil, false))
292+
db1Config.UseSystemMobileMetadataCollection = base.Ptr(true)
289293

290294
db2Name := "db2Name"
291295
db2Config := makeDbConfig(tb.GetName(), db2Name, collection3ScopesConfig)
292296
require.NoError(t, db2Config.setup(ctx, db2Name, sc.Config.Bootstrap, nil, nil, false))
297+
db2Config.UseSystemMobileMetadataCollection = base.Ptr(true)
293298

294299
// Start first async index creation, should block after first collection
295300
doneChan1, err := initMgr.InitializeDatabase(ctx, sc.Config, db1Config.ToDatabaseConfig(), testUseLegacySyncDocsIndex, true)
@@ -381,10 +386,12 @@ func TestDatabaseInitConcurrentDatabasesDifferentBuckets(t *testing.T) {
381386
db1Name := "db1Name"
382387
db1Config := makeDbConfig(tb1.GetName(), db1Name, collection1and2ScopesConfig)
383388
require.NoError(t, db1Config.setup(ctx, db1Name, sc.Config.Bootstrap, nil, nil, false))
389+
db1Config.UseSystemMobileMetadataCollection = base.Ptr(true)
384390

385391
db2Name := "db2Name"
386392
db2Config := makeDbConfig(tb2.GetName(), db2Name, collection1and2ScopesConfig)
387393
require.NoError(t, db2Config.setup(ctx, db2Name, sc.Config.Bootstrap, nil, nil, false))
394+
db2Config.UseSystemMobileMetadataCollection = base.Ptr(true)
388395

389396
// Start first async index creation, should block after first collection
390397
doneChan1, err := initMgr.InitializeDatabase(ctx, sc.Config, db1Config.ToDatabaseConfig(), testUseLegacySyncDocsIndex, true)
@@ -456,6 +463,7 @@ func TestDatabaseInitTeardownTiming(t *testing.T) {
456463
dbName := "dbName"
457464
dbConfig := makeDbConfig(tb.GetName(), dbName, collection1and2ScopesConfig)
458465
require.NoError(t, dbConfig.setup(ctx, dbName, sc.Config.Bootstrap, nil, nil, false))
466+
dbConfig.UseSystemMobileMetadataCollection = base.Ptr(true)
459467

460468
wg := &sync.WaitGroup{}
461469
wg.Add(1)
@@ -511,30 +519,46 @@ func waitForWorkerDone(t *testing.T, manager *DatabaseInitManager, dbName string
511519
}
512520

513521
func TestBuildCollectionIndexData(t *testing.T) {
522+
bootstrapEnabled := &StartupConfig{Bootstrap: BootstrapConfig{UseSystemMetadataCollection: base.Ptr(true)}}
523+
bootstrapDisabled := &StartupConfig{Bootstrap: BootstrapConfig{UseSystemMetadataCollection: base.Ptr(false)}}
524+
514525
tests := []struct {
515526
name string
516527
config *DatabaseConfig
517528
defaultCollectionExists bool
518529
want CollectionInitData
530+
startupConfig *StartupConfig
519531
}{
532+
// Scope variations — verifies index sets are computed correctly per collection layout.
533+
// Uses per-DB opt-in to show the full output including mobile collection.
520534
{
521535
name: "implicit default collection",
536+
config: &DatabaseConfig{DbConfig: DbConfig{
537+
UseSystemMobileMetadataCollection: base.Ptr(true),
538+
}},
539+
want: CollectionInitData{
540+
base.DefaultScopeAndCollectionName(): db.IndexesAll,
541+
base.MobileSystemScopeAndCollectionName(): db.IndexesMetadataOnly,
542+
},
543+
},
544+
{
545+
name: "implicit default collection with mobile collection disabled",
522546
config: &DatabaseConfig{
523547
DbConfig: DbConfig{
524548
Scopes: nil,
525549
},
526550
},
527551
defaultCollectionExists: true,
528552
want: CollectionInitData{
529-
base.DefaultScopeAndCollectionName(): db.IndexesAll,
530-
base.MobileSystemScopeAndCollectionName(): db.IndexesMetadataOnly,
553+
base.DefaultScopeAndCollectionName(): db.IndexesAll,
531554
},
532555
},
533556
{
534-
name: "explicit default collection",
557+
name: "explicit default collection with mobile collection enabled",
535558
config: &DatabaseConfig{
536559
DbConfig: DbConfig{
537-
Scopes: makeScopesConfig(base.DefaultScope, []string{base.DefaultCollection}),
560+
Scopes: makeScopesConfig(base.DefaultScope, []string{base.DefaultCollection}),
561+
UseSystemMobileMetadataCollection: base.Ptr(true),
538562
},
539563
},
540564
defaultCollectionExists: true,
@@ -544,10 +568,22 @@ func TestBuildCollectionIndexData(t *testing.T) {
544568
},
545569
},
546570
{
547-
name: "one named collection",
571+
name: "explicit default collection with mobile collection disabled",
548572
config: &DatabaseConfig{
549573
DbConfig: DbConfig{
550-
Scopes: makeScopesConfig("scope1", []string{"collection1"}),
574+
Scopes: makeScopesConfig(base.DefaultScope, []string{base.DefaultCollection}),
575+
},
576+
},
577+
want: CollectionInitData{
578+
base.DefaultScopeAndCollectionName(): db.IndexesAll,
579+
},
580+
},
581+
{
582+
name: "one named collection with mobile collection enabled",
583+
config: &DatabaseConfig{
584+
DbConfig: DbConfig{
585+
Scopes: makeScopesConfig("scope1", []string{"collection1"}),
586+
UseSystemMobileMetadataCollection: base.Ptr(true),
551587
},
552588
},
553589
defaultCollectionExists: true,
@@ -559,6 +595,28 @@ func TestBuildCollectionIndexData(t *testing.T) {
559595
},
560596
{
561597
name: "one named and explicit default collection",
598+
config: &DatabaseConfig{DbConfig: DbConfig{
599+
Scopes: makeScopesConfig(base.DefaultScope, []string{base.DefaultCollection, "collection1"}),
600+
UseSystemMobileMetadataCollection: base.Ptr(true),
601+
}},
602+
want: CollectionInitData{
603+
base.DefaultScopeAndCollectionName(): db.IndexesAll,
604+
base.MobileSystemScopeAndCollectionName(): db.IndexesMetadataOnly,
605+
base.NewScopeAndCollectionName(base.DefaultScope, "collection1"): db.IndexesWithoutMetadata,
606+
},
607+
},
608+
// Flag interaction cases — verifies resolveUseSystemMetadataCollection precedence.
609+
// Uses implicit default collection as a representative scope.
610+
{
611+
name: "per-DB enabled, no startup config",
612+
config: &DatabaseConfig{DbConfig: DbConfig{UseSystemMobileMetadataCollection: base.Ptr(true)}},
613+
want: CollectionInitData{
614+
base.DefaultScopeAndCollectionName(): db.IndexesAll,
615+
base.MobileSystemScopeAndCollectionName(): db.IndexesMetadataOnly,
616+
},
617+
},
618+
{
619+
name: "one named and explicit default collection with mobile collection disabled",
562620
config: &DatabaseConfig{
563621
DbConfig: DbConfig{
564622
Scopes: makeScopesConfig(base.DefaultScope, []string{base.DefaultCollection, "collection1"}),
@@ -567,17 +625,45 @@ func TestBuildCollectionIndexData(t *testing.T) {
567625
defaultCollectionExists: true,
568626
want: CollectionInitData{
569627
base.DefaultScopeAndCollectionName(): db.IndexesAll,
570-
base.MobileSystemScopeAndCollectionName(): db.IndexesMetadataOnly,
571628
base.NewScopeAndCollectionName(base.DefaultScope, "collection1"): db.IndexesWithoutMetadata,
572629
},
573630
},
631+
{
632+
// per-DB false falls through to the cluster flag, which is true
633+
name: "bootstrap enabled, per-DB explicitly disabled",
634+
startupConfig: bootstrapEnabled,
635+
config: &DatabaseConfig{DbConfig: DbConfig{UseSystemMobileMetadataCollection: base.Ptr(false)}},
636+
want: CollectionInitData{
637+
base.DefaultScopeAndCollectionName(): db.IndexesAll,
638+
base.MobileSystemScopeAndCollectionName(): db.IndexesMetadataOnly,
639+
},
640+
},
641+
{
642+
name: "bootstrap disabled, per-DB unset",
643+
startupConfig: bootstrapDisabled,
644+
config: &DatabaseConfig{},
645+
want: CollectionInitData{
646+
base.DefaultScopeAndCollectionName(): db.IndexesAll,
647+
},
648+
},
649+
{
650+
// per-DB true always wins, regardless of cluster flag
651+
name: "bootstrap disabled, per-DB explicitly enabled",
652+
startupConfig: bootstrapDisabled,
653+
config: &DatabaseConfig{DbConfig: DbConfig{UseSystemMobileMetadataCollection: base.Ptr(true)}},
654+
want: CollectionInitData{
655+
base.DefaultScopeAndCollectionName(): db.IndexesAll,
656+
base.MobileSystemScopeAndCollectionName(): db.IndexesMetadataOnly,
657+
},
658+
},
574659
{
575660
// _default dropped after migration (e.g. system metadata collection in use): metadata
576661
// indexes must not be targeted at the now-missing _default._default collection.
577662
name: "named collection with _default dropped",
578663
config: &DatabaseConfig{
579664
DbConfig: DbConfig{
580-
Scopes: makeScopesConfig("scope1", []string{"collection1"}),
665+
Scopes: makeScopesConfig("scope1", []string{"collection1"}),
666+
UseSystemMobileMetadataCollection: base.Ptr(true),
581667
},
582668
},
583669
defaultCollectionExists: false,
@@ -589,8 +675,8 @@ func TestBuildCollectionIndexData(t *testing.T) {
589675
}
590676
for _, test := range tests {
591677
t.Run(test.name, func(t *testing.T) {
592-
actual := buildCollectionIndexData(test.config, test.defaultCollectionExists)
593-
assert.Equalf(t, test.want, actual, "buildCollectionIndexData(%v, %v)", test.config, test.defaultCollectionExists)
678+
actual := buildCollectionIndexData(test.startupConfig, test.config, test.defaultCollectionExists)
679+
assert.Equalf(t, test.want, actual, "buildCollectionIndexData(startup=%v, config=%v, defaultCollectionExists=%v)", test.startupConfig, test.config, test.defaultCollectionExists)
594680
})
595681
}
596682
}

rest/indextest/index_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ func TestAsyncOnlineOffline(t *testing.T) {
373373

374374
dbConfig := makeDbConfig(t, tb, syncFunc, importFilter)
375375
dbConfig.StartOffline = base.Ptr(true)
376+
dbConfig.UseSystemMobileMetadataCollection = base.Ptr(true)
376377
dbConfigPayload, err := json.Marshal(dbConfig)
377378
require.NoError(t, err)
378379
dbName := "db"
@@ -503,6 +504,7 @@ func TestAsyncCreateThenDelete(t *testing.T) {
503504

504505
dbConfig := makeDbConfig(t, tb, syncFunc, importFilter)
505506
dbConfig.StartOffline = base.Ptr(true)
507+
dbConfig.UseSystemMobileMetadataCollection = base.Ptr(true)
506508
dbConfigPayload, err := json.Marshal(dbConfig)
507509
require.NoError(t, err)
508510
dbName := "db"

0 commit comments

Comments
 (0)