diff options
author | Matthew Russotto <matthew.russotto@mongodb.com> | 2021-02-12 10:43:46 -0500 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-02-18 22:45:49 +0000 |
commit | 23d05fa8b976208fd5564ace429d90d9f6c93509 (patch) | |
tree | a5bcd1f641cd56c2eb03f68452030a27db517259 /src/mongo | |
parent | 70f68a9cf7077af529fd305fa7789ab0d26dd3d1 (diff) | |
download | mongo-23d05fa8b976208fd5564ace429d90d9f6c93509.tar.gz |
SERVER-53553 Make tenant migration recipient to start cloning tenant data only after the donor node's lastCommittedOpTime is >= startMigrationDonorTimestamp
Diffstat (limited to 'src/mongo')
6 files changed, 192 insertions, 20 deletions
diff --git a/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp b/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp index 0ca25375e55..7d8a25623ba 100644 --- a/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp +++ b/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp @@ -67,6 +67,7 @@ public: TenantMigrationRecipientDocument stateDoc(cmd.getMigrationId(), cmd.getDonorConnectionString().toString(), cmd.getTenantId().toString(), + cmd.getStartMigrationDonorTimestamp(), cmd.getReadPreference()); if (!repl::tenantMigrationDisableX509Auth) { @@ -176,9 +177,11 @@ public: // recipientSyncData. But even if that's the case, we still need to create an instance // and persist a state document that's marked garbage collectable (which is done by the // main chain). + const Timestamp kUnusedStartMigrationTimestamp(1, 1); TenantMigrationRecipientDocument stateDoc(cmd.getMigrationId(), cmd.getDonorConnectionString().toString(), cmd.getTenantId().toString(), + kUnusedStartMigrationTimestamp, cmd.getReadPreference()); if (!repl::tenantMigrationDisableX509Auth) { uassert(ErrorCodes::InvalidOptions, diff --git a/src/mongo/db/repl/tenant_migration_recipient_entry_helpers_test.cpp b/src/mongo/db/repl/tenant_migration_recipient_entry_helpers_test.cpp index fff534b61c0..980f5243591 100644 --- a/src/mongo/db/repl/tenant_migration_recipient_entry_helpers_test.cpp +++ b/src/mongo/db/repl/tenant_migration_recipient_entry_helpers_test.cpp @@ -46,6 +46,8 @@ namespace repl { using namespace tenantMigrationRecipientEntryHelpers; +const Timestamp kDefaultStartMigrationTimestamp(1, 1); + class TenantMigrationRecipientEntryHelpersTest : public ServiceContextMongoDTest { public: void setUp() override { @@ -113,6 +115,7 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, AddTenantMigrationRecipientStat migrationUUID, "donor-rs0/localhost:12345", "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); activeTenantAStateDoc.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_OK(insertStateDoc(opCtx.get(), activeTenantAStateDoc)); @@ -122,6 +125,7 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, AddTenantMigrationRecipientStat TenantMigrationRecipientDocument stateDoc1(migrationUUID, "donor-rs1/localhost:12345", "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); stateDoc1.setRecipientCertificateForDonor(kRecipientPEMPayload); auto status = insertStateDoc(opCtx.get(), stateDoc1); @@ -132,6 +136,7 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, AddTenantMigrationRecipientStat TenantMigrationRecipientDocument stateDoc2(migrationUUID, "donor-rs0/localhost:12345", "tenantB", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); stateDoc2.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_THROWS_CODE( @@ -142,6 +147,7 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, AddTenantMigrationRecipientStat TenantMigrationRecipientDocument stateDoc3(UUID::gen(), "donor-rs0/localhost:12345", "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); stateDoc3.setRecipientCertificateForDonor(kRecipientPEMPayload); status = insertStateDoc(opCtx.get(), stateDoc3); @@ -152,6 +158,7 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, AddTenantMigrationRecipientStat TenantMigrationRecipientDocument stateDoc4(UUID::gen(), "donor-rs0/localhost:12345", "tenantB", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); stateDoc4.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_OK(insertStateDoc(opCtx.get(), stateDoc4)); @@ -167,6 +174,7 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, migrationUUID, "donor-rs0/localhost:12345", "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); inactiveTenantAStateDoc.setRecipientCertificateForDonor(kRecipientPEMPayload); inactiveTenantAStateDoc.setExpireAt(Date_t::now()); @@ -177,6 +185,7 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, TenantMigrationRecipientDocument stateDoc1(migrationUUID, "donor-rs1/localhost:12345", "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); stateDoc1.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_THROWS_CODE( @@ -187,6 +196,7 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, TenantMigrationRecipientDocument stateDoc2(migrationUUID, "donor-rs0/localhost:12345", "tenantB", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); stateDoc2.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_THROWS_CODE( @@ -197,6 +207,7 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, TenantMigrationRecipientDocument stateDoc3(UUID::gen(), "donor-rs0/localhost:12345", "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); stateDoc3.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_OK(insertStateDoc(opCtx.get(), stateDoc3)); @@ -206,6 +217,7 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, TenantMigrationRecipientDocument stateDoc4(UUID::gen(), "donor-rs0/localhost:12345", "tenantC", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); stateDoc4.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_OK(insertStateDoc(opCtx.get(), stateDoc4)); diff --git a/src/mongo/db/repl/tenant_migration_recipient_service.cpp b/src/mongo/db/repl/tenant_migration_recipient_service.cpp index c40612d3045..1768100e54a 100644 --- a/src/mongo/db/repl/tenant_migration_recipient_service.cpp +++ b/src/mongo/db/repl/tenant_migration_recipient_service.cpp @@ -515,31 +515,46 @@ TenantMigrationRecipientService::Instance::_createAndConnectClients() { auto client = _connectAndAuth(serverAddress, applicationName); boost::optional<repl::OpTime> startApplyingOpTime; + Timestamp startMigrationDonorTimestamp; { stdx::lock_guard lk(_mutex); startApplyingOpTime = _stateDoc.getStartApplyingDonorOpTime(); + startMigrationDonorTimestamp = + _stateDoc.getStartMigrationDonorTimestamp(); } - if (startApplyingOpTime) { - auto majoritySnapshotOpTime = _getDonorMajorityOpTime(client); - - if (majoritySnapshotOpTime < *startApplyingOpTime) { - stdx::lock_guard lk(_mutex); - const auto now = - getGlobalServiceContext()->getFastClockSource()->now(); - _excludeDonorHost( - lk, - serverAddress, - now + Milliseconds(tenantMigrationExcludeDonorHostTimeoutMS)); - uasserted( - kDelayedMajorityOpTimeErrorCode, - str::stream() - << "majoritySnapshotOpTime on donor host must not be behind " - "startApplyingDonorOpTime, majoritySnapshotOpTime: " - << majoritySnapshotOpTime.toString() - << "; startApplyingDonorOpTime: " - << (*startApplyingOpTime).toString()); - } + auto majoritySnapshotOpTime = _getDonorMajorityOpTime(client); + if (majoritySnapshotOpTime.getTimestamp() < startMigrationDonorTimestamp) { + stdx::lock_guard lk(_mutex); + const auto now = getGlobalServiceContext()->getFastClockSource()->now(); + _excludeDonorHost( + lk, + serverAddress, + now + Milliseconds(tenantMigrationExcludeDonorHostTimeoutMS)); + uasserted( + kDelayedMajorityOpTimeErrorCode, + str::stream() + << "majoritySnapshotOpTime on donor host must not be behind " + "startMigrationDonorTimestamp, majoritySnapshotOpTime: " + << majoritySnapshotOpTime.toString() + << "; startMigrationDonorTimestamp: " + << startMigrationDonorTimestamp.toString()); + } + if (startApplyingOpTime && majoritySnapshotOpTime < *startApplyingOpTime) { + stdx::lock_guard lk(_mutex); + const auto now = getGlobalServiceContext()->getFastClockSource()->now(); + _excludeDonorHost( + lk, + serverAddress, + now + Milliseconds(tenantMigrationExcludeDonorHostTimeoutMS)); + uasserted( + kDelayedMajorityOpTimeErrorCode, + str::stream() + << "majoritySnapshotOpTime on donor host must not be behind " + "startApplyingDonorOpTime, majoritySnapshotOpTime: " + << majoritySnapshotOpTime.toString() + << "; startApplyingDonorOpTime: " + << (*startApplyingOpTime).toString()); } // Application name is constructed such that it doesn't exceed diff --git a/src/mongo/db/repl/tenant_migration_recipient_service.h b/src/mongo/db/repl/tenant_migration_recipient_service.h index dae86b0dd74..504fffb0596 100644 --- a/src/mongo/db/repl/tenant_migration_recipient_service.h +++ b/src/mongo/db/repl/tenant_migration_recipient_service.h @@ -176,6 +176,10 @@ public: _excludeDonorHost(lk, host, until); } + const auto& getExcludedDonorHosts_forTest() { + return _excludedDonorHosts; + } + private: friend class TenantMigrationRecipientServiceTest; diff --git a/src/mongo/db/repl/tenant_migration_recipient_service_test.cpp b/src/mongo/db/repl/tenant_migration_recipient_service_test.cpp index 6e3e78787be..ab6829fb324 100644 --- a/src/mongo/db/repl/tenant_migration_recipient_service_test.cpp +++ b/src/mongo/db/repl/tenant_migration_recipient_service_test.cpp @@ -76,6 +76,7 @@ namespace repl { namespace { constexpr std::int32_t stopFailPointErrorCode = 4880402; +const Timestamp kDefaultStartMigrationTimestamp(1, 1); OplogEntry makeOplogEntry(OpTime opTime, OpTypeEnum opType, @@ -444,6 +445,7 @@ TEST_F(TenantMigrationRecipientServiceTest, BasicTenantMigrationRecipientService migrationUUID, "donor-rs/localhost:12345", "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly, TagSet::primaryOnly())); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -469,6 +471,7 @@ TEST_F(TenantMigrationRecipientServiceTest, InstanceReportsErrorOnFailureWhilePe migrationUUID, "donor-rs/localhost:12345", "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly, TagSet::primaryOnly())); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -497,10 +500,13 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientConnection_P MockReplicaSet replSet("donorSet", 3, true /* hasPrimary */, true /* dollarPrefixHosts */); + insertTopOfOplog(&replSet, OpTime(kDefaultStartMigrationTimestamp, 1)); + TenantMigrationRecipientDocument initialStateDocument( migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -545,10 +551,13 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientConnection_S MockReplicaSet replSet("donorSet", 2, true /* hasPrimary */, true /* dollarPrefixHosts */); + insertTopOfOplog(&replSet, OpTime(kDefaultStartMigrationTimestamp, 1)); + TenantMigrationRecipientDocument initialStateDocument( migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::SecondaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -594,10 +603,13 @@ TEST_F(TenantMigrationRecipientServiceTest, MockReplicaSet replSet("donorSet", 2); + insertTopOfOplog(&replSet, OpTime(kDefaultStartMigrationTimestamp, 1)); + TenantMigrationRecipientDocument initialStateDocument( migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -666,10 +678,13 @@ TEST_F(TenantMigrationRecipientServiceTest, MockReplicaSet replSet("donorSet", 2); + insertTopOfOplog(&replSet, OpTime(kDefaultStartMigrationTimestamp, 1)); + TenantMigrationRecipientDocument initialStateDocument( migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -735,10 +750,13 @@ TEST_F(TenantMigrationRecipientServiceTest, MockReplicaSet replSet("donorSet", 2); + insertTopOfOplog(&replSet, OpTime(kDefaultStartMigrationTimestamp, 1)); + TenantMigrationRecipientDocument initialStateDocument( migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::Nearest)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -810,10 +828,13 @@ TEST_F(TenantMigrationRecipientServiceTest, MockReplicaSet replSet("donorSet", 2); + insertTopOfOplog(&replSet, OpTime(kDefaultStartMigrationTimestamp, 1)); + TenantMigrationRecipientDocument initialStateDocument( migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryPreferred)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -876,10 +897,13 @@ TEST_F(TenantMigrationRecipientServiceTest, MockReplicaSet replSet("donorSet", 2); + insertTopOfOplog(&replSet, OpTime(kDefaultStartMigrationTimestamp, 1)); + TenantMigrationRecipientDocument initialStateDocument( migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryPreferred)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -957,6 +981,7 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryPreferred)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); initialStateDocument.setStartApplyingDonorOpTime(startApplyingOpTime); @@ -989,6 +1014,70 @@ TEST_F(TenantMigrationRecipientServiceTest, taskFp->setMode(FailPoint::off, 0); } +TEST_F(TenantMigrationRecipientServiceTest, + TenantMigrationRecipientConnection_RemoteMajorityOpTimeBehindStartMigrationDonorTimestamp) { + stopFailPointEnableBlock fp("fpAfterConnectingTenantMigrationRecipientInstance"); + + const UUID migrationUUID = UUID::gen(); + const OpTime remoteMajorityOpTime(Timestamp(5, 1), 1); + const Timestamp startMigrationDonorTimestamp(6, 1); + + auto taskFp = globalFailPointRegistry().find("hangBeforeTaskCompletion"); + auto timesEntered = taskFp->setMode(FailPoint::alwaysOn, 0); + + // Insert the remote majority optime into the oplogs of the first two hosts. + MockReplicaSet replSet("donorSet", 3, true /* hasPrimary */, true /* dollarPrefixHosts */); + const auto hosts = replSet.getHosts(); + const std::vector<HostAndPort> advancedOpTimeHosts = {hosts[0], hosts[1]}; + + insertTopOfOplog(&replSet, remoteMajorityOpTime, advancedOpTimeHosts); + insertTopOfOplog(&replSet, OpTime(startMigrationDonorTimestamp, 1), {hosts.at(2)}); + + TenantMigrationRecipientDocument initialStateDocument( + migrationUUID, + replSet.getConnectionString(), + "tenantA", + startMigrationDonorTimestamp, + ReadPreferenceSetting(ReadPreference::PrimaryPreferred)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); + + // Create and start the instance. + auto opCtx = makeOperationContext(); + auto instance = TenantMigrationRecipientService::Instance::getOrCreate( + opCtx.get(), _service, initialStateDocument.toBSON()); + ASSERT(instance.get()); + ASSERT_EQ(migrationUUID, instance->getMigrationUUID()); + + taskFp->waitForTimesEntered(timesEntered + 1); + + auto* client = getClient(instance.get()); + auto* oplogFetcherClient = getOplogFetcherClient(instance.get()); + // Both clients should be populated. + ASSERT(client); + ASSERT(oplogFetcherClient); + + // Clients should be distinct. + ASSERT(client != oplogFetcherClient); + + // Clients should be connected to donor node at index 2. + auto donorHost = hosts[2].toString(); + ASSERT_EQ(donorHost, client->getServerAddress()); + ASSERT(client->isStillConnected()); + ASSERT_EQ(donorHost, oplogFetcherClient->getServerAddress()); + ASSERT(oplogFetcherClient->isStillConnected()); + + // Since we were using primaryPreferred read preference, we should have tried hosts[0] + // and had it rejected. + const auto& excludedHosts = instance->getExcludedDonorHosts_forTest(); + ASSERT_TRUE(std::find_if(excludedHosts.begin(), + excludedHosts.end(), + [hosts](const std::pair<HostAndPort, Date_t>& a) { + return a.first == hosts[0]; + }) != excludedHosts.end()); + + taskFp->setMode(FailPoint::off, 0); +} + TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientConnection_PrimaryFailsOver) { stopFailPointEnableBlock fp("fpAfterConnectingTenantMigrationRecipientInstance"); @@ -999,6 +1088,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientConnection_P MockReplicaSet replSet("donorSet", 2, true /* hasPrimary */, true /* dollarPrefixHosts */); + insertTopOfOplog(&replSet, OpTime(kDefaultStartMigrationTimestamp, 1)); + // Primary is unavailable. replSet.kill(replSet.getHosts()[0].toString()); @@ -1006,6 +1097,7 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientConnection_P migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryPreferred)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -1049,6 +1141,7 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientConnection_B migrationUUID, "broken,connect,string,no,set,name", "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -1070,6 +1163,7 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, "localhost:12345", "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -1094,6 +1188,7 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientGetStartOpTi migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -1131,6 +1226,7 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -1173,6 +1269,7 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientGetStartOpTi migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -1217,6 +1314,7 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -1251,6 +1349,7 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -1284,6 +1383,7 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientStartOplogFe migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -1337,6 +1437,7 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientStartsCloner migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -1390,6 +1491,7 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogFetcherFailsDuringOplogApplicat migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -1444,6 +1546,7 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogFetcherResumesFromTopOfOplogBuf migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -1546,6 +1649,7 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogFetcherNoDocInBufferToResumeFro migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -1650,6 +1754,7 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogApplierResumesFromLastNoOpOplog migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -1768,6 +1873,7 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogApplierResumesFromStartDonorApp migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -1924,6 +2030,7 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -2028,6 +2135,7 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogApplierFails) { migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -2092,6 +2200,7 @@ TEST_F(TenantMigrationRecipientServiceTest, StoppingApplierAllowsCompletion) { migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -2145,6 +2254,7 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientAddResumeTok migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -2245,6 +2355,7 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_BeforeRun) migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -2280,6 +2391,7 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_FailToIniti migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -2312,6 +2424,7 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_WaitUntilSt migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -2392,6 +2505,7 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_AfterStartO migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -2453,6 +2567,7 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_AfterConsis migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -2539,6 +2654,7 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_AfterFail) migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -2618,6 +2734,7 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_FailToMarkG migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -2663,10 +2780,13 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientServiceRecor const UUID migrationUUID = UUID::gen(); MockReplicaSet replSet("donorSet", 3, true /* hasPrimary */, true /* dollarPrefixHosts */); + insertTopOfOplog(&replSet, OpTime(kDefaultStartMigrationTimestamp, 1)); + TenantMigrationRecipientDocument initialStateDocument( migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -2695,10 +2815,13 @@ TEST_F(TenantMigrationRecipientServiceTest, const UUID migrationUUID = UUID::gen(); MockReplicaSet replSet("donorSet", 3, true /* hasPrimary */, true /* dollarPrefixHosts */); + insertTopOfOplog(&replSet, OpTime(kDefaultStartMigrationTimestamp, 1)); + TenantMigrationRecipientDocument initialStateDocument( migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -2731,10 +2854,13 @@ TEST_F(TenantMigrationRecipientServiceTest, const UUID migrationUUID = UUID::gen(); MockReplicaSet replSet("donorSet", 3, true /* hasPrimary */, true /* dollarPrefixHosts */); + insertTopOfOplog(&replSet, OpTime(kDefaultStartMigrationTimestamp, 1)); + TenantMigrationRecipientDocument initialStateDocument( migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -2776,10 +2902,13 @@ TEST_F(TenantMigrationRecipientServiceTest, const UUID migrationUUID = UUID::gen(); MockReplicaSet replSet("donorSet", 3, true /* hasPrimary */, true /* dollarPrefixHosts */); + insertTopOfOplog(&replSet, OpTime(kDefaultStartMigrationTimestamp, 1)); + TenantMigrationRecipientDocument initialStateDocument( migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); @@ -2813,6 +2942,7 @@ TEST_F(TenantMigrationRecipientServiceTest, WaitUntilTimestampIsMajorityCommitte migrationUUID, replSet.getConnectionString(), "tenantA", + kDefaultStartMigrationTimestamp, ReadPreferenceSetting(ReadPreference::PrimaryOnly)); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); diff --git a/src/mongo/db/repl/tenant_migration_state_machine.idl b/src/mongo/db/repl/tenant_migration_state_machine.idl index e57961e674b..296fd91dd72 100644 --- a/src/mongo/db/repl/tenant_migration_state_machine.idl +++ b/src/mongo/db/repl/tenant_migration_state_machine.idl @@ -153,6 +153,14 @@ structs: description: "The tenantId for the migration." validator: callback: "tenant_migration_util::validateDatabasePrefix" + startMigrationDonorTimestamp: + type: timestamp + description: >- + Timestamp after all index builds for tenant are complete or aborted. Recipient + must not start cloning/fetching oplog entries from the donor until this + timestamp is majority committed. + validator: + callback: "tenant_migration_util::validateTimestampNotNull" readPreference: type: readPreference description: >- |