summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVishnu Kaushik <vishnu.kaushik@mongodb.com>2021-06-09 20:04:10 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-06-10 20:27:13 +0000
commit0d7c224fc2671e939ea97d94237003dd74805b54 (patch)
tree68a2a4ede2cb8c822df9ea70d14f5ab6fa75073f
parentefec3cc4b253d02fa9e11947ce92d53b727181b0 (diff)
downloadmongo-0d7c224fc2671e939ea97d94237003dd74805b54.tar.gz
SERVER-57532 Use donor specs for _id index in tenant migration collection cloner
-rw-r--r--jstests/replsets/tenant_migration_v1_id_index.js64
-rw-r--r--src/mongo/db/repl/storage_interface.h4
-rw-r--r--src/mongo/db/repl/storage_interface_impl.cpp6
-rw-r--r--src/mongo/db/repl/storage_interface_impl.h4
-rw-r--r--src/mongo/db/repl/storage_interface_mock.h4
-rw-r--r--src/mongo/db/repl/tenant_collection_cloner.cpp6
6 files changed, 82 insertions, 6 deletions
diff --git a/jstests/replsets/tenant_migration_v1_id_index.js b/jstests/replsets/tenant_migration_v1_id_index.js
new file mode 100644
index 00000000000..52196aa489b
--- /dev/null
+++ b/jstests/replsets/tenant_migration_v1_id_index.js
@@ -0,0 +1,64 @@
+/**
+ * Tests that the index spec used for the '_id' index on the donor for a particular collection is
+ * maintained on the recipient after migration.
+ *
+ * @tags: [requires_fcv_49, requires_majority_read_concern, requires_persistence,
+ * incompatible_with_eft, incompatible_with_windows_tls, incompatible_with_macos]
+ */
+
+(function() {
+"use strict";
+
+load("jstests/libs/uuid_util.js");
+load("jstests/replsets/libs/tenant_migration_test.js");
+
+const tenantMigrationTest = new TenantMigrationTest({name: jsTestName()});
+if (!tenantMigrationTest.isFeatureFlagEnabled()) {
+ jsTestLog("Skipping test because the tenant migrations feature flag is disabled");
+ return;
+}
+
+const tenantId = 'testTenantId';
+const migrationOpts = {
+ migrationIdString: extractUUIDFromObject(UUID()),
+ tenantId: tenantId
+};
+const dbName = tenantMigrationTest.tenantDB(tenantId, "testDB");
+
+// Collection names for the collections with "v: 1" and "v: 2" '_id' indexes.
+const collWithV1Index = "testCollV1";
+const collWithV2Index = "testCollV2";
+
+const donorPrimary = tenantMigrationTest.getDonorPrimary();
+const tenantDb = donorPrimary.getDB(dbName);
+
+jsTestLog("Creating collections on donor.");
+// Create collections with the appropriate default '_id' indexes.
+assert.commandWorked(
+ tenantDb.createCollection(collWithV1Index, {idIndex: {key: {_id: 1}, name: "_id_", v: 1}}));
+assert.commandWorked(
+ tenantDb.createCollection(collWithV2Index, {idIndex: {key: {_id: 1}, name: "_id_", v: 2}}));
+
+// Insert documents into the collections.
+tenantMigrationTest.insertDonorDB(
+ dbName,
+ collWithV1Index,
+ [...Array(30).keys()].map((i) => ({a: i, job: "Musician", name: "Dr. BMK"})));
+tenantMigrationTest.insertDonorDB(
+ dbName,
+ collWithV2Index,
+ [...Array(30).keys()].map((i) => ({a: i, job: "Professor", name: "Donald Knuth"})));
+
+jsTestLog(`Starting a tenant migration with migrationID ${
+ migrationOpts.migrationIdString}, and tenantId ${tenantId}`);
+assert.commandWorked(tenantMigrationTest.startMigration(migrationOpts));
+
+// Allow the migration to run to completion. This will check the db hashes between the donor and
+// recipient to make sure everything (including collection attributes such as indexes) is identical.
+jsTestLog("Allowing migration to run to completion.");
+TenantMigrationTest.assertCommitted(tenantMigrationTest.waitForMigrationToComplete(migrationOpts));
+
+assert.commandWorked(tenantMigrationTest.forgetMigration(migrationOpts.migrationIdString));
+
+tenantMigrationTest.stop();
+})(); \ No newline at end of file
diff --git a/src/mongo/db/repl/storage_interface.h b/src/mongo/db/repl/storage_interface.h
index 3e7ac3059ab..6ae980e490c 100644
--- a/src/mongo/db/repl/storage_interface.h
+++ b/src/mongo/db/repl/storage_interface.h
@@ -169,7 +169,9 @@ public:
*/
virtual Status createCollection(OperationContext* opCtx,
const NamespaceString& nss,
- const CollectionOptions& options) = 0;
+ const CollectionOptions& options,
+ const bool createIdIndex = true,
+ const BSONObj& idIndexSpec = BSONObj()) = 0;
/**
* Creates all the specified non-_id indexes on a given collection, which must be empty.
diff --git a/src/mongo/db/repl/storage_interface_impl.cpp b/src/mongo/db/repl/storage_interface_impl.cpp
index 352f2799ecf..7f99a956cbf 100644
--- a/src/mongo/db/repl/storage_interface_impl.cpp
+++ b/src/mongo/db/repl/storage_interface_impl.cpp
@@ -469,7 +469,9 @@ StatusWith<size_t> StorageInterfaceImpl::getOplogMaxSize(OperationContext* opCtx
Status StorageInterfaceImpl::createCollection(OperationContext* opCtx,
const NamespaceString& nss,
- const CollectionOptions& options) {
+ const CollectionOptions& options,
+ const bool createIdIndex,
+ const BSONObj& idIndexSpec) {
return writeConflictRetry(opCtx, "StorageInterfaceImpl::createCollection", nss.ns(), [&] {
AutoGetDb databaseWriteGuard(opCtx, nss.db(), MODE_IX);
auto db = databaseWriteGuard.ensureDbExists();
@@ -481,7 +483,7 @@ Status StorageInterfaceImpl::createCollection(OperationContext* opCtx,
Lock::CollectionLock lk(opCtx, nss, MODE_IX);
WriteUnitOfWork wuow(opCtx);
try {
- auto coll = db->createCollection(opCtx, nss, options);
+ auto coll = db->createCollection(opCtx, nss, options, createIdIndex, idIndexSpec);
invariant(coll);
} catch (const AssertionException& ex) {
return ex.toStatus();
diff --git a/src/mongo/db/repl/storage_interface_impl.h b/src/mongo/db/repl/storage_interface_impl.h
index 409ae9ea99b..fbb5c90c57a 100644
--- a/src/mongo/db/repl/storage_interface_impl.h
+++ b/src/mongo/db/repl/storage_interface_impl.h
@@ -81,7 +81,9 @@ public:
Status createCollection(OperationContext* opCtx,
const NamespaceString& nss,
- const CollectionOptions& options) override;
+ const CollectionOptions& options,
+ const bool createIdIndex = true,
+ const BSONObj& idIndexSpec = BSONObj()) override;
Status createIndexesOnEmptyCollection(OperationContext* opCtx,
const NamespaceString& nss,
diff --git a/src/mongo/db/repl/storage_interface_mock.h b/src/mongo/db/repl/storage_interface_mock.h
index ae8c396fe04..8c913443f0e 100644
--- a/src/mongo/db/repl/storage_interface_mock.h
+++ b/src/mongo/db/repl/storage_interface_mock.h
@@ -170,7 +170,9 @@ public:
Status createCollection(OperationContext* opCtx,
const NamespaceString& nss,
- const CollectionOptions& options) override {
+ const CollectionOptions& options,
+ const bool createIdIndex = true,
+ const BSONObj& idIndexSpec = BSONObj()) override {
return createCollFn(opCtx, nss, options);
}
diff --git a/src/mongo/db/repl/tenant_collection_cloner.cpp b/src/mongo/db/repl/tenant_collection_cloner.cpp
index 087e0da1261..7dc2a965097 100644
--- a/src/mongo/db/repl/tenant_collection_cloner.cpp
+++ b/src/mongo/db/repl/tenant_collection_cloner.cpp
@@ -387,7 +387,11 @@ BaseCloner::AfterStageBehavior TenantCollectionCloner::createCollectionStage() {
// means that we have a collection with the same namespace but a different UUID, in which
// case we should also fail the migration.
auto status =
- getStorageInterface()->createCollection(opCtx.get(), _sourceNss, _collectionOptions);
+ getStorageInterface()->createCollection(opCtx.get(),
+ _sourceNss,
+ _collectionOptions,
+ !_idIndexSpec.isEmpty() /* createIdIndex */,
+ _idIndexSpec);
uassertStatusOKWithContext(status, "Tenant collection cloner: create collection");
}