diff options
8 files changed, 79 insertions, 37 deletions
diff --git a/buildscripts/resmokeconfig/suites/tenant_migration_jscore_passthrough.yml b/buildscripts/resmokeconfig/suites/tenant_migration_jscore_passthrough.yml index 240a9c94609..0dc9bb17995 100644 --- a/buildscripts/resmokeconfig/suites/tenant_migration_jscore_passthrough.yml +++ b/buildscripts/resmokeconfig/suites/tenant_migration_jscore_passthrough.yml @@ -67,7 +67,7 @@ executor: load('jstests/libs/override_methods/inject_tenant_prefix.js'); global_vars: TestData: &TestData - dbPrefix: "tenantMigrationDbPrefix_" + dbPrefix: "tenantMigrationDbPrefix" # TODO (SERVER-50494): Implement proxy's retry logic for batch write commands. disableBatchWrites: true readMode: commands diff --git a/jstests/libs/override_methods/inject_tenant_prefix.js b/jstests/libs/override_methods/inject_tenant_prefix.js index 3d180875019..0f87ca1af4c 100644 --- a/jstests/libs/override_methods/inject_tenant_prefix.js +++ b/jstests/libs/override_methods/inject_tenant_prefix.js @@ -30,7 +30,7 @@ function prependDbPrefixToDbNameIfApplicable(dbName) { // ignored. return dbName; } - return isBlacklistedDb(dbName) ? dbName : TestData.dbPrefix + dbName; + return isBlacklistedDb(dbName) ? dbName : TestData.tenantMigrationDbPrefix + "_" + dbName; } /** @@ -51,7 +51,7 @@ function prependDbPrefixToNsIfApplicable(ns) { * If the given database name starts TestData.dbPrefix, removes the prefix. */ function extractOriginalDbName(dbName) { - return dbName.replace(TestData.dbPrefix, ""); + return dbName.replace(TestData.tenantMigrationDbPrefix + "_", ""); } /** @@ -67,7 +67,7 @@ function extractOriginalNs(ns) { * Removes all occurrences of TestDatabase.dbPrefix in the string. */ function removeDbPrefixFromString(string) { - return string.replace(new RegExp(TestData.dbPrefix, "g"), ""); + return string.replace(new RegExp(TestData.tenantMigrationDbPrefix + "_", "g"), ""); } /** diff --git a/jstests/replsets/reads_during_tenant_migration.js b/jstests/replsets/reads_during_tenant_migration.js index 330cc3b604c..7a64864217d 100644 --- a/jstests/replsets/reads_during_tenant_migration.js +++ b/jstests/replsets/reads_during_tenant_migration.js @@ -28,18 +28,19 @@ recipientRst.startSet(); recipientRst.initiate(); const kCollName = "testColl"; +const kTenantDefinedDbName = "0"; const kRecipientConnString = recipientRst.getURL(); const kMaxTimeMS = 5 * 1000; const kConfigDonorsNS = "config.tenantMigrationDonors"; -function startMigration(host, dbName, recipientConnString) { +function startMigration(host, dbPrefix, recipientConnString) { const primary = new Mongo(host); return primary.adminCommand({ donorStartMigration: 1, migrationId: UUID(), recipientConnectionString: recipientConnString, - databasePrefix: dbName, + databasePrefix: dbPrefix, readPreference: {mode: "primary"} }); } @@ -81,12 +82,13 @@ function runCommand(db, cmd, expectedError) { */ function testReadIsRejectedIfSentAfterMigrationHasCommitted(rst, testCase, dbName, collName) { let primary = rst.getPrimary(); + const dbPrefix = dbName.split('_')[0]; assert.commandWorked(primary.adminCommand({ donorStartMigration: 1, migrationId: UUID(), recipientConnectionString: kRecipientConnString, - databasePrefix: dbName, + databasePrefix: dbPrefix, readPreference: {mode: "primary"} })); @@ -96,7 +98,7 @@ function testReadIsRejectedIfSentAfterMigrationHasCommitted(rst, testCase, dbNam // atClusterTime have read timestamp >= commitTimestamp. rst.awaitLastOpCommitted(); - const donorDoc = primary.getCollection(kConfigDonorsNS).findOne({databasePrefix: dbName}); + const donorDoc = primary.getCollection(kConfigDonorsNS).findOne({databasePrefix: dbPrefix}); const nodes = testCase.isSupportedOnSecondaries ? rst.nodes : [primary]; nodes.forEach(node => { const db = node.getDB(dbName); @@ -117,6 +119,7 @@ function testReadIsRejectedIfSentAfterMigrationHasCommitted(rst, testCase, dbNam * Tests that the donor does not reject reads after the migration aborts. */ function testReadIsAcceptedIfSentAfterMigrationHasAborted(rst, testCase, dbName, collName) { + const dbPrefix = dbName.split('_')[0]; const primary = rst.getPrimary(); let abortFp = configureFailPoint(primary, "abortTenantMigrationAfterBlockingStarts"); @@ -124,7 +127,7 @@ function testReadIsAcceptedIfSentAfterMigrationHasAborted(rst, testCase, dbName, donorStartMigration: 1, migrationId: UUID(), recipientConnectionString: kRecipientConnString, - databasePrefix: dbName, + databasePrefix: dbPrefix, readPreference: {mode: "primary"} }), ErrorCodes.TenantMigrationAborted); @@ -136,7 +139,7 @@ function testReadIsAcceptedIfSentAfterMigrationHasAborted(rst, testCase, dbName, // atClusterTime have read timestamp >= abortTimestamp. rst.awaitLastOpCommitted(); - const donorDoc = primary.getCollection(kConfigDonorsNS).findOne({databasePrefix: dbName}); + const donorDoc = primary.getCollection(kConfigDonorsNS).findOne({databasePrefix: dbPrefix}); const nodes = testCase.isSupportedOnSecondaries ? rst.nodes : [primary]; nodes.forEach(node => { const db = node.getDB(dbName); @@ -154,10 +157,11 @@ function testReadIsAcceptedIfSentAfterMigrationHasAborted(rst, testCase, dbName, * blockingTimestamp but does not block linearizable reads. */ function testReadBlocksIfMigrationIsInBlocking(rst, testCase, dbName, collName) { + const dbPrefix = dbName.split('_')[0]; const primary = rst.getPrimary(); let blockingFp = configureFailPoint(primary, "pauseTenantMigrationAfterBlockingStarts"); - let migrationThread = new Thread(startMigration, primary.host, dbName, kRecipientConnString); + let migrationThread = new Thread(startMigration, primary.host, dbPrefix, kRecipientConnString); // Wait for the migration to enter the blocking state. migrationThread.start(); @@ -168,7 +172,7 @@ function testReadBlocksIfMigrationIsInBlocking(rst, testCase, dbName, collName) // unspecified atClusterTime have read timestamp >= blockTimestamp. rst.awaitLastOpCommitted(); - const donorDoc = primary.getCollection(kConfigDonorsNS).findOne({databasePrefix: dbName}); + const donorDoc = primary.getCollection(kConfigDonorsNS).findOne({databasePrefix: dbPrefix}); const command = testCase.requiresReadTimestamp ? testCase.command(collName, donorDoc.blockTimestamp) : testCase.command(collName); @@ -196,6 +200,7 @@ function testBlockedReadGetsUnblockedAndRejectedIfMigrationCommits( return; } + const dbPrefix = dbName.split('_')[0]; const primary = rst.getPrimary(); let blockingFp = configureFailPoint(primary, "pauseTenantMigrationAfterBlockingStarts"); @@ -206,7 +211,7 @@ function testBlockedReadGetsUnblockedAndRejectedIfMigrationCommits( .count + 1; - let migrationThread = new Thread(startMigration, primary.host, dbName, kRecipientConnString); + let migrationThread = new Thread(startMigration, primary.host, dbPrefix, kRecipientConnString); let resumeMigrationThread = new Thread(resumeMigrationAfterBlockingRead, primary.host, targetBlockedReads); @@ -220,7 +225,7 @@ function testBlockedReadGetsUnblockedAndRejectedIfMigrationCommits( // unspecified atClusterTime have read timestamp >= blockTimestamp. rst.awaitLastOpCommitted(); - const donorDoc = primary.getCollection(kConfigDonorsNS).findOne({databasePrefix: dbName}); + const donorDoc = primary.getCollection(kConfigDonorsNS).findOne({databasePrefix: dbPrefix}); const command = testCase.requiresReadTimestamp ? testCase.command(collName, donorDoc.blockTimestamp) : testCase.command(collName); @@ -249,6 +254,7 @@ function testBlockedReadGetsUnblockedAndSucceedsIfMigrationAborts(rst, testCase, return; } + const dbPrefix = dbName.split('_')[0]; const primary = rst.getPrimary(); let blockingFp = configureFailPoint(primary, "pauseTenantMigrationAfterBlockingStarts"); @@ -260,7 +266,7 @@ function testBlockedReadGetsUnblockedAndSucceedsIfMigrationAborts(rst, testCase, .count + 1; - let migrationThread = new Thread(startMigration, primary.host, dbName, kRecipientConnString); + let migrationThread = new Thread(startMigration, primary.host, dbPrefix, kRecipientConnString); let resumeMigrationThread = new Thread(resumeMigrationAfterBlockingRead, primary.host, targetBlockedReads); @@ -274,7 +280,7 @@ function testBlockedReadGetsUnblockedAndSucceedsIfMigrationAborts(rst, testCase, // unspecified atClusterTime have read timestamp >= blockTimestamp. rst.awaitLastOpCommitted(); - const donorDoc = primary.getCollection(kConfigDonorsNS).findOne({databasePrefix: dbName}); + const donorDoc = primary.getCollection(kConfigDonorsNS).findOne({databasePrefix: dbPrefix}); const command = testCase.requiresReadTimestamp ? testCase.command(collName, donorDoc.blockTimestamp) : testCase.command(collName); @@ -370,7 +376,6 @@ const testCases = { } }; -// Run test cases. const testFuncs = { inCommitted: testReadIsRejectedIfSentAfterMigrationHasCommitted, inAborted: testReadIsAcceptedIfSentAfterMigrationHasAborted, @@ -380,8 +385,9 @@ const testFuncs = { }; for (const [testName, testFunc] of Object.entries(testFuncs)) { - for (const [commandName, testCase] of Object.entries(testCases)) { - let dbName = commandName + "-" + testName + "0"; + for (const [testCaseName, testCase] of Object.entries(testCases)) { + // Database name is [tenant_id (database prefix)]_[tenant defined database name] + let dbName = testCaseName + "-" + testName + "_" + kTenantDefinedDbName; testFunc(donorRst, testCase, dbName, kCollName); } } diff --git a/jstests/replsets/writes_during_tenant_migration.js b/jstests/replsets/writes_during_tenant_migration.js index 174c25bd17b..33f1c97b878 100644 --- a/jstests/replsets/writes_during_tenant_migration.js +++ b/jstests/replsets/writes_during_tenant_migration.js @@ -29,6 +29,7 @@ const primary = donorRst.getPrimary(); const kRecipientConnString = recipientRst.getURL(); const kCollName = "testColl"; +const kTenantDefinedDbName = "0"; const kTestDoc = { x: -1 }; @@ -50,11 +51,12 @@ const kMaxTimeMS = 1 * 1000; function startMigration(host, dbName, recipientConnString) { const primary = new Mongo(host); + const dbPrefix = dbName.split('_')[0]; return primary.adminCommand({ donorStartMigration: 1, migrationId: UUID(), recipientConnectionString: recipientConnString, - databasePrefix: dbName, + databasePrefix: dbPrefix, readPreference: {mode: "primary"} }); } @@ -229,11 +231,12 @@ function testWriteNoMigration(testCase, testOpts) { * Tests that the donor rejects writes after the migration commits. */ function testWriteIsRejectedIfSentAfterMigrationHasCommitted(testCase, testOpts) { + const dbPrefix = testOpts.dbName.split('_')[0]; assert.commandWorked(testOpts.primaryDB.adminCommand({ donorStartMigration: 1, migrationId: UUID(), recipientConnectionString: kRecipientConnString, - databasePrefix: testOpts.dbName, + databasePrefix: dbPrefix, readPreference: {mode: "primary"} })); @@ -246,11 +249,12 @@ function testWriteIsRejectedIfSentAfterMigrationHasCommitted(testCase, testOpts) */ function testWriteIsAcceptedIfSentAfterMigrationHasAborted(testCase, testOpts) { let abortFp = configureFailPoint(testOpts.primaryDB, "abortTenantMigrationAfterBlockingStarts"); + const dbPrefix = testOpts.dbName.split('_')[0]; assert.commandFailedWithCode(testOpts.primaryDB.adminCommand({ donorStartMigration: 1, migrationId: UUID(), recipientConnectionString: kRecipientConnString, - databasePrefix: testOpts.dbName, + databasePrefix: dbPrefix, readPreference: {mode: "primary"} }), ErrorCodes.TenantMigrationAborted); @@ -845,6 +849,7 @@ const testFuncs = { for (const [testName, testFunc] of Object.entries(testFuncs)) { for (const [commandName, testCase] of Object.entries(testCases)) { + // Database name is [tenant_id (database prefix)]_[tenant defined database name] let baseDbName = commandName + "-" + testName + "0"; if (testCase.skip) { @@ -852,7 +857,12 @@ for (const [testName, testFunc] of Object.entries(testFuncs)) { continue; } - runTest(primary, testCase, testFunc, baseDbName + "Basic", kCollName); + runTest(primary, + testCase, + testFunc, + baseDbName + "Basic" + + "_" + kTenantDefinedDbName, + kCollName); // TODO (SERVER-49844): Test transactional writes during migration. if (testCase.isSupportedInTransaction && testName == "noMigration") { @@ -861,9 +871,13 @@ for (const [testName, testFunc] of Object.entries(testFuncs)) { } if (testCase.isRetryableWriteCommand) { - runTest(primary, testCase, testFunc, baseDbName + "Retryable", kCollName, { - useRetryableWrite: true - }); + runTest(primary, + testCase, + testFunc, + baseDbName + "Retryable" + + "_" + kTenantDefinedDbName, + kCollName, + {useRetryableWrite: true}); } } } diff --git a/src/mongo/db/repl/tenant_migration_access_blocker_by_prefix.cpp b/src/mongo/db/repl/tenant_migration_access_blocker_by_prefix.cpp index ff8a63467b0..ff8abd87672 100644 --- a/src/mongo/db/repl/tenant_migration_access_blocker_by_prefix.cpp +++ b/src/mongo/db/repl/tenant_migration_access_blocker_by_prefix.cpp @@ -63,17 +63,16 @@ void TenantMigrationAccessBlockerByPrefix::remove(StringData dbPrefix) { } std::shared_ptr<TenantMigrationAccessBlocker> -TenantMigrationAccessBlockerByPrefix::getTenantMigrationAccessBlocker(StringData dbName) { +TenantMigrationAccessBlockerByPrefix::getTenantMigrationAccessBlockerForDbName(StringData dbName) { stdx::lock_guard<Latch> lg(_mutex); - // TODO (SERVER-50440): Make TenantMigrationAccessBlockerByPrefix include '_' when doing lookup. auto it = std::find_if( _tenantMigrationAccessBlockers.begin(), _tenantMigrationAccessBlockers.end(), [dbName]( const std::pair<std::string, std::shared_ptr<TenantMigrationAccessBlocker>>& blocker) { StringData dbPrefix = blocker.first; - return dbName.startsWith(dbPrefix); + return dbName.startsWith(dbPrefix + "_"); }); if (it == _tenantMigrationAccessBlockers.end()) { @@ -83,6 +82,19 @@ TenantMigrationAccessBlockerByPrefix::getTenantMigrationAccessBlocker(StringData } } +std::shared_ptr<TenantMigrationAccessBlocker> +TenantMigrationAccessBlockerByPrefix::getTenantMigrationAccessBlockerForDbPrefix( + StringData dbPrefix) { + stdx::lock_guard<Latch> lg(_mutex); + + auto it = _tenantMigrationAccessBlockers.find(dbPrefix); + if (it != _tenantMigrationAccessBlockers.end()) { + return it->second; + } else { + return nullptr; + } +} + void TenantMigrationAccessBlockerByPrefix::appendInfoForServerStatus(BSONObjBuilder* builder) { stdx::lock_guard<Latch> lg(_mutex); diff --git a/src/mongo/db/repl/tenant_migration_access_blocker_by_prefix.h b/src/mongo/db/repl/tenant_migration_access_blocker_by_prefix.h index 208ef7595bd..c8e513f378e 100644 --- a/src/mongo/db/repl/tenant_migration_access_blocker_by_prefix.h +++ b/src/mongo/db/repl/tenant_migration_access_blocker_by_prefix.h @@ -60,10 +60,17 @@ public: * returns the first TenantMigrationAccessBlocker it finds whose dbPrefix is a prefix for * dbName. */ - std::shared_ptr<TenantMigrationAccessBlocker> getTenantMigrationAccessBlocker( + std::shared_ptr<TenantMigrationAccessBlocker> getTenantMigrationAccessBlockerForDbName( StringData dbName); /** + * Searches through TenantMigrationAccessBlockers and + * returns the TenantMigrationAccessBlocker that matches dbPrefix. + */ + std::shared_ptr<TenantMigrationAccessBlocker> getTenantMigrationAccessBlockerForDbPrefix( + StringData dbPrefix); + + /** * Iterates through each of the TenantMigrationAccessBlockers stored by the mapping * and appends the server status of each blocker to the BSONObjBuilder. */ diff --git a/src/mongo/db/repl/tenant_migration_donor_util.cpp b/src/mongo/db/repl/tenant_migration_donor_util.cpp index 90d50cfa444..296e041658d 100644 --- a/src/mongo/db/repl/tenant_migration_donor_util.cpp +++ b/src/mongo/db/repl/tenant_migration_donor_util.cpp @@ -63,7 +63,8 @@ void onTransitionToBlocking(OperationContext* opCtx, TenantMigrationDonorDocumen invariant(donorStateDoc.getBlockTimestamp()); auto& mtabByPrefix = TenantMigrationAccessBlockerByPrefix::get(opCtx->getServiceContext()); - auto mtab = mtabByPrefix.getTenantMigrationAccessBlocker(donorStateDoc.getDatabasePrefix()); + auto mtab = + mtabByPrefix.getTenantMigrationAccessBlockerForDbPrefix(donorStateDoc.getDatabasePrefix()); if (!opCtx->writesAreReplicated()) { // A primary must create the TenantMigrationAccessBlocker and call startBlockingWrites on it @@ -95,7 +96,8 @@ void onTransitionToCommitted(OperationContext* opCtx, TenantMigrationDonorDocume invariant(donorStateDoc.getCommitOrAbortOpTime()); auto& mtabByPrefix = TenantMigrationAccessBlockerByPrefix::get(opCtx->getServiceContext()); - auto mtab = mtabByPrefix.getTenantMigrationAccessBlocker(donorStateDoc.getDatabasePrefix()); + auto mtab = + mtabByPrefix.getTenantMigrationAccessBlockerForDbPrefix(donorStateDoc.getDatabasePrefix()); invariant(mtab); mtab->commit(donorStateDoc.getCommitOrAbortOpTime().get()); } @@ -108,7 +110,8 @@ void onTransitionToAborted(OperationContext* opCtx, TenantMigrationDonorDocument invariant(donorStateDoc.getCommitOrAbortOpTime()); auto& mtabByPrefix = TenantMigrationAccessBlockerByPrefix::get(opCtx->getServiceContext()); - auto mtab = mtabByPrefix.getTenantMigrationAccessBlocker(donorStateDoc.getDatabasePrefix()); + auto mtab = + mtabByPrefix.getTenantMigrationAccessBlockerForDbPrefix(donorStateDoc.getDatabasePrefix()); invariant(mtab); mtab->abort(donorStateDoc.getCommitOrAbortOpTime().get()); } @@ -150,7 +153,7 @@ void onDonorStateTransition(OperationContext* opCtx, const BSONObj& donorStateDo void checkIfCanReadOrBlock(OperationContext* opCtx, StringData dbName) { auto mtab = TenantMigrationAccessBlockerByPrefix::get(opCtx->getServiceContext()) - .getTenantMigrationAccessBlocker(dbName); + .getTenantMigrationAccessBlockerForDbName(dbName); if (!mtab) { return; @@ -179,7 +182,7 @@ void checkIfLinearizableReadWasAllowedOrThrow(OperationContext* opCtx, StringDat if (repl::ReadConcernArgs::get(opCtx).getLevel() == repl::ReadConcernLevel::kLinearizableReadConcern) { if (auto mtab = TenantMigrationAccessBlockerByPrefix::get(opCtx->getServiceContext()) - .getTenantMigrationAccessBlocker(dbName)) { + .getTenantMigrationAccessBlockerForDbName(dbName)) { mtab->checkIfLinearizableReadWasAllowedOrThrow(opCtx); } } @@ -187,7 +190,7 @@ void checkIfLinearizableReadWasAllowedOrThrow(OperationContext* opCtx, StringDat void onWriteToDatabase(OperationContext* opCtx, StringData dbName) { auto& mtabByPrefix = TenantMigrationAccessBlockerByPrefix::get(opCtx->getServiceContext()); - auto mtab = mtabByPrefix.getTenantMigrationAccessBlocker(dbName); + auto mtab = mtabByPrefix.getTenantMigrationAccessBlockerForDbName(dbName); if (mtab) { mtab->checkIfCanWriteOrThrow(); diff --git a/src/mongo/db/repl/tenant_migration_donor_util.h b/src/mongo/db/repl/tenant_migration_donor_util.h index 15fce6eedd6..5b1d9ef4168 100644 --- a/src/mongo/db/repl/tenant_migration_donor_util.h +++ b/src/mongo/db/repl/tenant_migration_donor_util.h @@ -107,7 +107,7 @@ void migrationConflictHandler(OperationContext* opCtx, auto migrationConflictInfo = ex.extraInfo<TenantMigrationConflictInfo>(); invariant(migrationConflictInfo); - if (auto mtab = mtabByPrefix.getTenantMigrationAccessBlocker( + if (auto mtab = mtabByPrefix.getTenantMigrationAccessBlockerForDbPrefix( migrationConflictInfo->getDatabasePrefix())) { replyBuilder->getBodyBuilder().resetToEmpty(); mtab->checkIfCanWriteOrBlock(opCtx); |