diff options
author | Suganthi Mani <suganthi.mani@mongodb.com> | 2021-10-23 01:21:32 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-10-23 01:50:13 +0000 |
commit | 56a5ddbf5a2ba92169e81ec24f9387c5fe1c0931 (patch) | |
tree | 9d045046d63e41db85bd5d827d6b39d104129c33 | |
parent | 58bc7ee16dcc0bbda6c5c1a437b39982b9630cd0 (diff) | |
download | mongo-56a5ddbf5a2ba92169e81ec24f9387c5fe1c0931.tar.gz |
SERVER-59495 Donor and recipient tenant migration state machines will persist the migration protocol info and tenantId info will be an empty string for 'Merge' protcol.
Added a new optional "protocol" field to 'recipientSyncData' cmd & made 'tenantId' field as optional.
21 files changed, 355 insertions, 117 deletions
diff --git a/buildscripts/idl/idl/generator.py b/buildscripts/idl/idl/generator.py index 51569af4d4f..c806d016296 100644 --- a/buildscripts/idl/idl/generator.py +++ b/buildscripts/idl/idl/generator.py @@ -230,24 +230,15 @@ class _FastFieldUsageChecker(_FieldUsageCheckerBase): with writer.IndentedScopedBlock(self._writer, 'if (MONGO_unlikely(!usedFields.all())) {', '}'): for field in self._fields: - if (not field.optional) and (not field.ignore): + # If 'field.default' is true, the fields(members) gets initialized with the default + # value in the class definition. So, it's ok to skip setting the field to + # default value here. + if (not field.optional) and (not field.ignore) and (not field.default): with writer.IndentedScopedBlock( self._writer, 'if (!usedFields[%s]) {' % (_gen_field_usage_constant(field)), '}'): - if field.default: - default_value = (field.type.cpp_type + "::" + field.default) \ - if field.type.is_enum else field.default - if field.chained_struct_field: - self._writer.write_line( - '%s.%s(%s);' % - (_get_field_member_name(field.chained_struct_field), - _get_field_member_setter_name(field), default_value)) - else: - self._writer.write_line( - '%s = %s;' % (_get_field_member_name(field), default_value)) - else: - self._writer.write_line( - 'ctxt.throwMissingField(%s);' % (_get_field_constant_name(field))) + self._writer.write_line( + 'ctxt.throwMissingField(%s);' % (_get_field_constant_name(field))) class _SlowFieldUsageChecker(_FastFieldUsageChecker): diff --git a/jstests/replsets/libs/tenant_migration_util.js b/jstests/replsets/libs/tenant_migration_util.js index 9d89ceee585..6a07a83065c 100644 --- a/jstests/replsets/libs/tenant_migration_util.js +++ b/jstests/replsets/libs/tenant_migration_util.js @@ -37,7 +37,7 @@ var TenantMigrationUtil = (function() { */ function donorStartMigrationWithProtocol(cmd, db) { // If we don't pass "protocol", the server uses "multitenant migrations" by default. - if (isShardMergeEnabled(db)) { + if (cmd['protocol'] === undefined && isShardMergeEnabled(db)) { return Object.assign(Object.assign({}, cmd), {protocol: "shard merge"}); } diff --git a/jstests/replsets/shard_merge_enabled.js b/jstests/replsets/shard_merge_enabled.js index 8c02658fad0..66760137999 100644 --- a/jstests/replsets/shard_merge_enabled.js +++ b/jstests/replsets/shard_merge_enabled.js @@ -7,6 +7,7 @@ "use strict"; load("jstests/replsets/libs/tenant_migration_util.js"); +load("jstests/libs/fail_point_util.js"); function runTest(downgradeFCV) { let rst = new ReplSetTest({nodes: 1}); @@ -16,37 +17,62 @@ function runTest(downgradeFCV) { let primary = rst.getPrimary(); let adminDB = primary.getDB("admin"); const kDummyConnStr = "mongodb://localhost/?replicaSet=foo"; + const readPreference = {mode: 'primary'}; + const migrationCertificates = TenantMigrationUtil.makeMigrationCertificatesForTest(); + // A function, not a constant, to ensure unique UUIDs. function donorStartMigrationCmd() { return { donorStartMigration: 1, protocol: "shard merge", - tenantId: "foo", migrationId: UUID(), recipientConnectionString: kDummyConnStr, - readPreference: {mode: "primary"}, + readPreference: readPreference, + donorCertificateForRecipient: migrationCertificates.donorCertificateForRecipient, + recipientCertificateForDonor: migrationCertificates.recipientCertificateForDonor + }; + } + + function recipientSyncDataCmd() { + return { + recipientSyncData: 1, + protocol: "shard merge", + migrationId: UUID(), + donorConnectionString: kDummyConnStr, + readPreference: readPreference, + startMigrationDonorTimestamp: Timestamp(1, 1), + recipientCertificateForDonor: migrationCertificates.recipientCertificateForDonor }; } + // Enable below fail points to prevent starting the donor/recipient POS instance. + configureFailPoint(primary, "returnResponseCommittedForDonorStartMigrationCmd"); + configureFailPoint(primary, "returnResponseOkForRecipientSyncDataCmd"); + // Preconditions: the shard merge feature is enabled and our fresh RS is on the latest FCV. assert(TenantMigrationUtil.isShardMergeEnabled(adminDB)); assert.eq(getFCVConstants().latest, adminDB.system.version.findOne({_id: 'featureCompatibilityVersion'}).version); - // Shard merge is enabled, so this call will fail for some *other* reason, e.g. no certificates, - // recipient is unavailable. - let res = adminDB.runCommand(donorStartMigrationCmd()); - assert.neq(res.code, - 5949300, - "donorStartMigration shouldn't reject 'shard merge' protocol when it's enabled"); + // Shard merge is enabled, so this call should work. + assert.commandWorked( + adminDB.runCommand(donorStartMigrationCmd()), + "donorStartMigration shouldn't reject 'shard merge' protocol when it's enabled"); + assert.commandWorked( + adminDB.runCommand(recipientSyncDataCmd()), + "recipientSyncDataCmd shouldn't reject 'shard merge' protocol when it's enabled"); assert.commandWorked(adminDB.adminCommand({setFeatureCompatibilityVersion: downgradeFCV})); // Now that FCV is downgraded, shard merge is automatically disabled. assert.commandFailedWithCode( adminDB.runCommand(donorStartMigrationCmd()), - 5949300, + ErrorCodes.IllegalOperation, "donorStartMigration should reject 'shard merge' protocol when it's disabled"); + assert.commandFailedWithCode( + adminDB.runCommand(recipientSyncDataCmd()), + ErrorCodes.IllegalOperation, + "recipientSyncDataCmd should reject 'shard merge' protocol when it's disabled"); rst.stopSet(); } diff --git a/jstests/replsets/tenant_migration_invalid_inputs.js b/jstests/replsets/tenant_migration_invalid_inputs.js index a680a7164d8..3ac39c57fe0 100644 --- a/jstests/replsets/tenant_migration_invalid_inputs.js +++ b/jstests/replsets/tenant_migration_invalid_inputs.js @@ -9,6 +9,7 @@ * incompatible_with_macos, * incompatible_with_windows_tls, * requires_persistence, + * requires_fcv_51, * ] */ @@ -32,6 +33,21 @@ const migrationCertificates = TenantMigrationUtil.makeMigrationCertificatesForTe jsTestLog("Testing 'donorStartMigration' command provided with invalid options."); +// Test missing tenantId field for protocol 'multitenant migrations'. +assert.commandFailedWithCode( + donorPrimary.adminCommand( + TenantMigrationUtil.donorStartMigrationWithProtocol({ + donorStartMigration: 1, + protocol: 'multitenant migrations', + migrationId: UUID(), + recipientConnectionString: tenantMigrationTest.getRecipientRst().getURL(), + readPreference: readPreference, + donorCertificateForRecipient: migrationCertificates.donorCertificateForRecipient, + recipientCertificateForDonor: migrationCertificates.recipientCertificateForDonor, + }, + donorPrimary.getDB("admin"))), + ErrorCodes.InvalidOptions); + // Test unsupported database prefixes. const unsupportedtenantIds = ['', 'admin', 'local', 'config']; unsupportedtenantIds.forEach((invalidTenantId) => { @@ -98,6 +114,18 @@ assert.commandFailedWithCode( jsTestLog("Testing 'recipientSyncData' command provided with invalid options."); +// Test missing tenantId field for protocol 'multitenant migrations'. +assert.commandFailedWithCode(recipientPrimary.adminCommand({ + recipientSyncData: 1, + protocol: 'multitenant migrations', + migrationId: UUID(), + donorConnectionString: tenantMigrationTest.getDonorRst().getURL(), + startMigrationDonorTimestamp: Timestamp(1, 1), + readPreference: readPreference, + recipientCertificateForDonor: migrationCertificates.recipientCertificateForDonor, +}), + ErrorCodes.InvalidOptions); + // Test unsupported database prefixes. unsupportedtenantIds.forEach((invalidTenantId) => { assert.commandFailedWithCode(recipientPrimary.adminCommand({ diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript index a9281408827..92de98db68b 100644 --- a/src/mongo/db/commands/SConscript +++ b/src/mongo/db/commands/SConscript @@ -625,6 +625,7 @@ env.Library( '$BUILD_DIR/mongo/client/read_preference', '$BUILD_DIR/mongo/db/repl/repl_coordinator_interface', '$BUILD_DIR/mongo/db/repl/tenant_migration_state_machine_idl', + '$BUILD_DIR/mongo/db/serverless/serverless_types_idl', '$BUILD_DIR/mongo/idl/idl_parser', ] ) diff --git a/src/mongo/db/commands/tenant_migration_donor_cmds.cpp b/src/mongo/db/commands/tenant_migration_donor_cmds.cpp index fb78d7099b1..f23c320391a 100644 --- a/src/mongo/db/commands/tenant_migration_donor_cmds.cpp +++ b/src/mongo/db/commands/tenant_migration_donor_cmds.cpp @@ -26,6 +26,7 @@ * exception statement from all source files in the program, then also delete * it in the license file. */ +#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand #include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" @@ -36,10 +37,13 @@ #include "mongo/db/repl/replication_coordinator.h" #include "mongo/db/repl/tenant_migration_access_blocker_util.h" #include "mongo/db/repl/tenant_migration_donor_service.h" +#include "mongo/logv2/log.h" namespace mongo { namespace { +MONGO_FAIL_POINT_DEFINE(returnResponseCommittedForDonorStartMigrationCmd); + class DonorStartMigrationCmd : public TypedCommand<DonorStartMigrationCmd> { public: using Request = DonorStartMigration; @@ -68,19 +72,14 @@ public: const auto& cmd = request(); - if (cmd.getProtocol().value_or(MigrationProtocolEnum::kMultitenantMigrations) == - MigrationProtocolEnum::kShardMerge) { - uassert(5949300, - "protocol \"shard merge\" not supported", - repl::feature_flags::gShardMerge.isEnabled( - serverGlobalParams.featureCompatibility)); - } + tenant_migration_util::protocolCompatibilityCheck(cmd.getProtocol(), + cmd.getTenantId().toString()); - // TODO (SERVER-59494): tenantId should be optional in the state doc. Include protocol. TenantMigrationDonorDocument stateDoc(cmd.getMigrationId(), cmd.getRecipientConnectionString().toString(), cmd.getReadPreference(), - cmd.getTenantId().toString()); + cmd.getTenantId().toString(), + cmd.getProtocol()); if (!repl::tenantMigrationDisableX509Auth) { uassert(ErrorCodes::InvalidOptions, @@ -97,6 +96,14 @@ public: const auto stateDocBson = stateDoc.toBSON(); + if (MONGO_unlikely(returnResponseCommittedForDonorStartMigrationCmd.shouldFail())) { + LOGV2(5949401, + "Immediately returning committed because " + "'returnResponseCommittedForDonorStartMigrationCmd' failpoint is enabled", + "tenantMigrationDonorInstance"_attr = stateDoc.toBSON()); + return Response(TenantMigrationDonorStateEnum::kCommitted); + } + auto donorService = repl::PrimaryOnlyServiceRegistry::get(opCtx->getServiceContext()) ->lookupServiceByName(TenantMigrationDonorService::kServiceName); diff --git a/src/mongo/db/commands/tenant_migration_donor_cmds.idl b/src/mongo/db/commands/tenant_migration_donor_cmds.idl index 750504590f9..3c08f095093 100644 --- a/src/mongo/db/commands/tenant_migration_donor_cmds.idl +++ b/src/mongo/db/commands/tenant_migration_donor_cmds.idl @@ -35,17 +35,10 @@ global: imports: - "mongo/client/read_preference_setting.idl" - "mongo/db/repl/tenant_migration_state_machine.idl" + - "mongo/db/serverless/serverless_types.idl" - "mongo/idl/basic_types.idl" - "mongo/s/sharding_types.idl" -enums: - MigrationProtocol: - description: "Determines which tenant migration protocol to use." - type: string - values: - kMultitenantMigrations: "multitenant migrations" - kShardMerge: "shard merge" - structs: DonorStartMigrationResponse: description: "Response of the donorStartMigration command" @@ -78,6 +71,7 @@ commands: tenantId: description: "The prefix from which the migrating database will be matched. The prefixes 'admin', 'local', 'config', the empty string, are not allowed." type: string + default: '""' validator: callback: "tenant_migration_util::validateDatabasePrefix" readPreference: @@ -98,9 +92,9 @@ commands: # TODO (SERVER-54085): Remove server parameter tenantMigrationDisableX509Auth. optional: true protocol: - description: "Which migration protocol to use, default 'multitenant migrations'." + description: "Which migration protocol to use." type: MigrationProtocol - optional: true + default: kMultitenantMigrations donorForgetMigration: description: "Parser for the 'donorForgetMigration' command." diff --git a/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp b/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp index b18f5b4c013..dc9f4d9889e 100644 --- a/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp +++ b/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp @@ -34,7 +34,6 @@ #include "mongo/db/commands/tenant_migration_donor_cmds_gen.h" #include "mongo/db/commands/tenant_migration_recipient_cmds_gen.h" #include "mongo/db/repl/primary_only_service.h" -#include "mongo/db/repl/repl_server_parameters_gen.h" #include "mongo/db/repl/tenant_migration_recipient_service.h" #include "mongo/logv2/log.h" @@ -70,11 +69,16 @@ public: const auto& cmd = request(); + tenant_migration_util::protocolCompatibilityCheck(cmd.getProtocol(), + cmd.getTenantId().toString()); + TenantMigrationRecipientDocument stateDoc(cmd.getMigrationId(), cmd.getDonorConnectionString().toString(), cmd.getTenantId().toString(), cmd.getStartMigrationDonorTimestamp(), - cmd.getReadPreference()); + cmd.getReadPreference(), + cmd.getProtocol()); + if (!repl::tenantMigrationDisableX509Auth) { uassert(ErrorCodes::InvalidOptions, @@ -88,7 +92,8 @@ public: if (MONGO_unlikely(returnResponseOkForRecipientSyncDataCmd.shouldFail())) { LOGV2(4879608, - "'returnResponseOkForRecipientSyncDataCmd' failpoint enabled.", + "Immediately returning OK because 'returnResponseOkForRecipientSyncDataCmd' " + "failpoint is enabled.", "tenantMigrationRecipientInstance"_attr = stateDoc.toBSON()); return Response(repl::OpTime()); } @@ -180,6 +185,9 @@ public: const auto& cmd = request(); + tenant_migration_util::protocolCompatibilityCheck(cmd.getProtocol(), + cmd.getTenantId().toString()); + opCtx->setAlwaysInterruptAtStepDownOrUp(); auto recipientService = repl::PrimaryOnlyServiceRegistry::get(opCtx->getServiceContext()) @@ -195,7 +203,8 @@ public: cmd.getDonorConnectionString().toString(), cmd.getTenantId().toString(), kUnusedStartMigrationTimestamp, - cmd.getReadPreference()); + cmd.getReadPreference(), + cmd.getProtocol()); if (!repl::tenantMigrationDisableX509Auth) { uassert(ErrorCodes::InvalidOptions, str::stream() << "'" << Request::kRecipientCertificateForDonorFieldName diff --git a/src/mongo/db/commands/tenant_migration_recipient_cmds.idl b/src/mongo/db/commands/tenant_migration_recipient_cmds.idl index 6a4b44c9752..60ed03fa4de 100644 --- a/src/mongo/db/commands/tenant_migration_recipient_cmds.idl +++ b/src/mongo/db/commands/tenant_migration_recipient_cmds.idl @@ -36,6 +36,7 @@ global: imports: - "mongo/client/read_preference_setting.idl" - "mongo/db/repl/tenant_migration_pem_payload.idl" + - "mongo/db/serverless/serverless_types.idl" - "mongo/idl/basic_types.idl" - "mongo/s/sharding_types.idl" - "mongo/db/repl/replication_types.idl" @@ -68,6 +69,7 @@ structs: The prefix from which the migrating database will be matched. The prefixes 'admin', 'local', 'config', the empty string, are not allowed. type: string + default: '""' validator: callback: "tenant_migration_util::validateDatabasePrefix" readPreference: @@ -81,6 +83,10 @@ structs: type: TenantMigrationPEMPayload # TODO (SERVER-54085): Remove server parameter tenantMigrationDisableX509Auth. optional: true + protocol: + description: "Which migration protocol to use." + type: MigrationProtocol + default: kMultitenantMigrations commands: recipientSyncData: diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript index 2a35874c14b..adb0d690fc7 100644 --- a/src/mongo/db/repl/SConscript +++ b/src/mongo/db/repl/SConscript @@ -1277,6 +1277,7 @@ env.Library( '$BUILD_DIR/mongo/client/connection_string', '$BUILD_DIR/mongo/client/read_preference', '$BUILD_DIR/mongo/db/commands/mongod_fcv', + '$BUILD_DIR/mongo/db/serverless/serverless_types_idl', '$BUILD_DIR/mongo/idl/idl_parser', '$BUILD_DIR/mongo/util/net/ssl_manager', 'optime', diff --git a/src/mongo/db/repl/tenant_migration_donor_service.cpp b/src/mongo/db/repl/tenant_migration_donor_service.cpp index b029481101f..6b93c558456 100644 --- a/src/mongo/db/repl/tenant_migration_donor_service.cpp +++ b/src/mongo/db/repl/tenant_migration_donor_service.cpp @@ -235,10 +235,11 @@ TenantMigrationDonorService::Instance::Instance(ServiceContext* const serviceCon _serviceContext(serviceContext), _donorService(donorService), _stateDoc(tenant_migration_access_blocker::parseDonorStateDocument(initialState)), - _instanceName(kServiceName + "-" + _stateDoc.getTenantId()), + _instanceName(kServiceName + "-" + _stateDoc.getId().toString()), _recipientUri( uassertStatusOK(MongoURI::parse(_stateDoc.getRecipientConnectionString().toString()))), _tenantId(_stateDoc.getTenantId()), + _protocol(_stateDoc.getProtocol()), _recipientConnectionString(_stateDoc.getRecipientConnectionString()), _readPreference(_stateDoc.getReadPreference()), _migrationUuid(_stateDoc.getId()), @@ -246,6 +247,7 @@ TenantMigrationDonorService::Instance::Instance(ServiceContext* const serviceCon _recipientCertificateForDonor(_stateDoc.getRecipientCertificateForDonor()), _sslMode(repl::tenantMigrationDisableX509Auth ? transport::kGlobalSSLMode : transport::kEnableSSL) { + _recipientCmdExecutor = _makeRecipientCmdExecutor(); _recipientCmdExecutor->startup(); @@ -384,7 +386,7 @@ Status TenantMigrationDonorService::Instance::checkIfOptionsConflict( stdx::lock_guard<Latch> lg(_mutex); invariant(stateDoc.getId() == _migrationUuid); - if (stateDoc.getTenantId() == _tenantId && + if (stateDoc.getProtocol() == _protocol && stateDoc.getTenantId() == _tenantId && stateDoc.getRecipientConnectionString() == _recipientConnectionString && stateDoc.getReadPreference().equals(_readPreference) && stateDoc.getDonorCertificateForRecipient() == _donorCertificateForRecipient && @@ -716,8 +718,11 @@ ExecutorFuture<void> TenantMigrationDonorService::Instance::_sendRecipientSyncDa request.setDbName(NamespaceString::kAdminDb); MigrationRecipientCommonData commonData( - _migrationUuid, donorConnString.toString(), _tenantId, _readPreference); + _migrationUuid, donorConnString.toString(), _readPreference); commonData.setRecipientCertificateForDonor(_recipientCertificateForDonor); + commonData.setProtocol(_protocol); + // TODO: Pass tenantId only for 'kMultitenantMigrations' protocol. + commonData.setTenantId(_tenantId); request.setMigrationRecipientCommonData(commonData); stdx::lock_guard<Latch> lg(_mutex); @@ -743,8 +748,11 @@ ExecutorFuture<void> TenantMigrationDonorService::Instance::_sendRecipientForget request.setDbName(NamespaceString::kAdminDb); MigrationRecipientCommonData commonData( - _migrationUuid, donorConnString.toString(), _tenantId, _readPreference); + _migrationUuid, donorConnString.toString(), _readPreference); commonData.setRecipientCertificateForDonor(_recipientCertificateForDonor); + commonData.setProtocol(_protocol); + // TODO: Pass tenantId only for 'kMultitenantMigrations' protocol. + commonData.setTenantId(_tenantId); request.setMigrationRecipientCommonData(commonData); return _sendCommandToRecipient(executor, recipientTargeterRS, request.toBSON(BSONObj()), token); diff --git a/src/mongo/db/repl/tenant_migration_donor_service.h b/src/mongo/db/repl/tenant_migration_donor_service.h index 5322703b201..5a167edeb81 100644 --- a/src/mongo/db/repl/tenant_migration_donor_service.h +++ b/src/mongo/db/repl/tenant_migration_donor_service.h @@ -33,7 +33,6 @@ #include "mongo/client/fetcher.h" #include "mongo/client/remote_command_targeter_rs.h" #include "mongo/db/repl/primary_only_service.h" -#include "mongo/db/repl/repl_server_parameters_gen.h" #include "mongo/db/repl/tenant_migration_access_blocker_util.h" #include "mongo/executor/thread_pool_task_executor.h" #include "mongo/util/cancellation.h" @@ -139,6 +138,10 @@ public: return _stateDoc.getTenantId(); } + MigrationProtocolEnum getProtocol() const { + return _stateDoc.getProtocol(); + } + StringData getRecipientConnectionString() const { return _stateDoc.getRecipientConnectionString(); } @@ -330,6 +333,7 @@ public: // This data is provided in the initial state doc and never changes. We keep copies to // avoid having to obtain the mutex to access them. const std::string _tenantId; + const MigrationProtocolEnum _protocol; const std::string _recipientConnectionString; const ReadPreferenceSetting _readPreference; const UUID _migrationUuid; diff --git a/src/mongo/db/repl/tenant_migration_donor_service_test.cpp b/src/mongo/db/repl/tenant_migration_donor_service_test.cpp index 53588c3c158..94c244e40d9 100644 --- a/src/mongo/db/repl/tenant_migration_donor_service_test.cpp +++ b/src/mongo/db/repl/tenant_migration_donor_service_test.cpp @@ -186,7 +186,8 @@ TEST_F(TenantMigrationDonorServiceTest, CheckSettingMigrationStartDate) { migrationUUID, "donor-rs/localhost:12345", ReadPreferenceSetting(ReadPreference::PrimaryOnly, TagSet::primaryOnly()), - "tenantA"); + "tenantA", + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setDonorCertificateForRecipient(kDonorPEMPayload); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); 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 980f5243591..6d2aa049d85 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 @@ -116,7 +116,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, AddTenantMigrationRecipientStat "donor-rs0/localhost:12345", "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); activeTenantAStateDoc.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_OK(insertStateDoc(opCtx.get(), activeTenantAStateDoc)); ASSERT_TRUE(checkStateDocPersisted(opCtx.get(), activeTenantAStateDoc)); @@ -126,7 +127,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, AddTenantMigrationRecipientStat "donor-rs1/localhost:12345", "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); stateDoc1.setRecipientCertificateForDonor(kRecipientPEMPayload); auto status = insertStateDoc(opCtx.get(), stateDoc1); ASSERT_EQUALS(ErrorCodes::ConflictingOperationInProgress, status.code()); @@ -137,7 +139,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, AddTenantMigrationRecipientStat "donor-rs0/localhost:12345", "tenantB", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); stateDoc2.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_THROWS_CODE( insertStateDoc(opCtx.get(), stateDoc2), DBException, ErrorCodes::DuplicateKey); @@ -148,7 +151,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, AddTenantMigrationRecipientStat "donor-rs0/localhost:12345", "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); stateDoc3.setRecipientCertificateForDonor(kRecipientPEMPayload); status = insertStateDoc(opCtx.get(), stateDoc3); ASSERT_EQUALS(ErrorCodes::ConflictingOperationInProgress, status.code()); @@ -159,7 +163,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, AddTenantMigrationRecipientStat "donor-rs0/localhost:12345", "tenantB", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); stateDoc4.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_OK(insertStateDoc(opCtx.get(), stateDoc4)); ASSERT_TRUE(checkStateDocPersisted(opCtx.get(), stateDoc4)); @@ -175,7 +180,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, "donor-rs0/localhost:12345", "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); inactiveTenantAStateDoc.setRecipientCertificateForDonor(kRecipientPEMPayload); inactiveTenantAStateDoc.setExpireAt(Date_t::now()); ASSERT_OK(insertStateDoc(opCtx.get(), inactiveTenantAStateDoc)); @@ -186,7 +192,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, "donor-rs1/localhost:12345", "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); stateDoc1.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_THROWS_CODE( insertStateDoc(opCtx.get(), stateDoc1), DBException, ErrorCodes::DuplicateKey); @@ -197,7 +204,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, "donor-rs0/localhost:12345", "tenantB", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); stateDoc2.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_THROWS_CODE( insertStateDoc(opCtx.get(), stateDoc2), DBException, ErrorCodes::DuplicateKey); @@ -208,7 +216,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, "donor-rs0/localhost:12345", "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); stateDoc3.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_OK(insertStateDoc(opCtx.get(), stateDoc3)); ASSERT_TRUE(checkStateDocPersisted(opCtx.get(), stateDoc3)); @@ -218,7 +227,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, "donor-rs0/localhost:12345", "tenantC", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); stateDoc4.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_OK(insertStateDoc(opCtx.get(), stateDoc4)); ASSERT_TRUE(checkStateDocPersisted(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 9c23744955e..877fa85568c 100644 --- a/src/mongo/db/repl/tenant_migration_recipient_service.cpp +++ b/src/mongo/db/repl/tenant_migration_recipient_service.cpp @@ -306,6 +306,7 @@ TenantMigrationRecipientService::Instance::Instance( _stateDoc(TenantMigrationRecipientDocument::parse(IDLParserErrorContext("recipientStateDoc"), stateDoc)), _tenantId(_stateDoc.getTenantId().toString()), + _protocol(_stateDoc.getProtocol()), _migrationUuid(_stateDoc.getId()), _donorConnectionString(_stateDoc.getDonorConnectionString().toString()), _donorUri(uassertStatusOK(MongoURI::parse(_stateDoc.getDonorConnectionString().toString()))), @@ -409,7 +410,7 @@ Status TenantMigrationRecipientService::Instance::checkIfOptionsConflict( stdx::lock_guard<Latch> lg(_mutex); invariant(stateDoc.getId() == _migrationUuid); - if (stateDoc.getTenantId() == _tenantId && + if (stateDoc.getProtocol() == _protocol && stateDoc.getTenantId() == _tenantId && stateDoc.getDonorConnectionString() == _donorConnectionString && stateDoc.getReadPreference().equals(_readPreference) && stateDoc.getRecipientCertificateForDonor() == _recipientCertificateForDonor) { @@ -2487,5 +2488,9 @@ const std::string& TenantMigrationRecipientService::Instance::getTenantId() cons return _tenantId; } +const MigrationProtocolEnum TenantMigrationRecipientService::Instance::getProtocol() const { + return _protocol; +} + } // namespace repl } // namespace mongo diff --git a/src/mongo/db/repl/tenant_migration_recipient_service.h b/src/mongo/db/repl/tenant_migration_recipient_service.h index 4fbb25126a7..99ee45ba6d1 100644 --- a/src/mongo/db/repl/tenant_migration_recipient_service.h +++ b/src/mongo/db/repl/tenant_migration_recipient_service.h @@ -138,6 +138,11 @@ public: */ const std::string& getTenantId() const; + /* + * Returns the migration protocol. + */ + const MigrationProtocolEnum getProtocol() const; + /** * To be called on the instance returned by PrimaryOnlyService::getOrCreate(). Returns an * error if the options this Instance was created with are incompatible with the options @@ -572,6 +577,7 @@ public: // This data is provided in the initial state doc and never changes. We keep copies to // avoid having to obtain the mutex to access them. const std::string _tenantId; // (R) + const MigrationProtocolEnum _protocol; // (R) const UUID _migrationUuid; // (R) const std::string _donorConnectionString; // (R) const MongoURI _donorUri; // (R) 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 b30dee191a0..4eca8a03fb0 100644 --- a/src/mongo/db/repl/tenant_migration_recipient_service_test.cpp +++ b/src/mongo/db/repl/tenant_migration_recipient_service_test.cpp @@ -479,7 +479,8 @@ TEST_F(TenantMigrationRecipientServiceTest, BasicTenantMigrationRecipientService "donor-rs/localhost:12345", "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly, TagSet::primaryOnly())); + ReadPreferenceSetting(ReadPreference::PrimaryOnly, TagSet::primaryOnly()), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -504,7 +505,8 @@ TEST_F(TenantMigrationRecipientServiceTest, InstanceReportsErrorOnFailureWhilePe "donor-rs/localhost:12345", "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly, TagSet::primaryOnly())); + ReadPreferenceSetting(ReadPreference::PrimaryOnly, TagSet::primaryOnly()), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -539,7 +541,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientConnection_P replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -590,7 +593,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientConnection_S replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::SecondaryOnly)); + ReadPreferenceSetting(ReadPreference::SecondaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -642,7 +646,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Hang the migration before attempting to connect to clients. @@ -700,7 +705,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Hang the migration before attempting to connect to clients. @@ -772,7 +778,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::Nearest)); + ReadPreferenceSetting(ReadPreference::Nearest), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Hang the migration before attempting to connect to clients. @@ -833,7 +840,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryPreferred)); + ReadPreferenceSetting(ReadPreference::PrimaryPreferred), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Hang the migration before attempting to connect to clients. @@ -902,7 +910,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryPreferred)); + ReadPreferenceSetting(ReadPreference::PrimaryPreferred), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Hang the migration before attempting to connect to clients. @@ -974,7 +983,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::SecondaryOnly)); + ReadPreferenceSetting(ReadPreference::SecondaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Hang the migration before attempting to connect to clients. @@ -1035,7 +1045,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::SecondaryPreferred)); + ReadPreferenceSetting(ReadPreference::SecondaryPreferred), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Hang the migration before attempting to connect to clients. @@ -1114,7 +1125,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryPreferred)); + ReadPreferenceSetting(ReadPreference::PrimaryPreferred), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); initialStateDocument.setStartApplyingDonorOpTime(startApplyingOpTime); @@ -1172,7 +1184,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", startMigrationDonorTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryPreferred)); + ReadPreferenceSetting(ReadPreference::PrimaryPreferred), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -1233,7 +1246,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientConnection_P replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryPreferred)); + ReadPreferenceSetting(ReadPreference::PrimaryPreferred), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -1277,7 +1291,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientConnection_B "broken,connect,string,no,set,name", "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -1299,7 +1314,8 @@ TEST_F(TenantMigrationRecipientServiceTest, "localhost:12345", "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -1325,7 +1341,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientGetStartOpTi replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -1364,7 +1381,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -1409,7 +1427,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientGetStartOpTi replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -1456,7 +1475,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -1492,7 +1512,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. Fail to populate the remote oplog mock. @@ -1527,7 +1548,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientStartOplogFe replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); auto opCtx = makeOperationContext(); @@ -1582,7 +1604,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientStartsCloner replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); auto opCtx = makeOperationContext(); @@ -1637,7 +1660,8 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogFetcherFailsDuringOplogApplicat replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Skip the cloners in this test, so we provide an empty list of databases. @@ -1693,7 +1717,8 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogFetcherResumesFromTopOfOplogBuf replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // We skip cloning here as a way to simulate that the recipient service has detected an existing @@ -1800,7 +1825,8 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogFetcherNoDocInBufferToResumeFro replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // We skip cloning here as a way to simulate that the recipient service has detected an existing @@ -1909,7 +1935,8 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogApplierResumesFromLastNoOpOplog replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // We skip cloning here as a way to simulate that the recipient service has detected an existing @@ -2034,7 +2061,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // We skip cloning here as a way to simulate that the recipient service has detected an existing @@ -2207,7 +2235,8 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogApplierResumesFromStartDonorApp replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // We skip cloning here as a way to simulate that the recipient service has detected an existing @@ -2352,7 +2381,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // We skip cloning here as a way to simulate that the recipient service has detected an existing @@ -2458,7 +2488,8 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogApplierFails) { replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Skip the cloners in this test, so we provide an empty list of databases. @@ -2524,7 +2555,8 @@ TEST_F(TenantMigrationRecipientServiceTest, StoppingApplierAllowsCompletion) { replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Skip the cloners in this test, so we provide an empty list of databases. @@ -2579,7 +2611,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientAddResumeTok replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Skip the cloners in this test, so we provide an empty list of databases. @@ -2682,7 +2715,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_BeforeRun) replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); auto fp = globalFailPointRegistry().find("pauseBeforeRunTenantMigrationRecipientInstance"); @@ -2720,7 +2754,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_FailToIniti replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); auto opCtx = makeOperationContext(); @@ -2754,7 +2789,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_WaitUntilSt replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); auto fp = globalFailPointRegistry().find("pauseAfterRunTenantMigrationRecipientInstance"); @@ -2838,7 +2874,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_AfterStartO replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -2901,7 +2938,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_AfterConsis replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Skip the cloners in this test, so we provide an empty list of databases. @@ -2989,7 +3027,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_AfterFail) replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Skip the cloners in this test, so we provide an empty list of databases. @@ -3071,7 +3110,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_FailToMarkG replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -3123,7 +3163,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientServiceRecor replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -3158,7 +3199,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Add an FCV value as if it was from a previous attempt. @@ -3197,7 +3239,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Add an FCV value as if it was from a previous attempt, making sure we set a different @@ -3244,7 +3287,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -3279,7 +3323,8 @@ TEST_F(TenantMigrationRecipientServiceTest, WaitUntilMigrationReachesReturnAfter replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Skip the cloners in this test, so we provide an empty list of databases. @@ -3339,7 +3384,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientReceivesRetriableFetcherErr replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -3403,7 +3449,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientReceivesNonRetriableFetcher replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -3462,7 +3509,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientWillNotRetryOnExternalInter replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -3520,7 +3568,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientReceivesRetriableClonerErro replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -3592,7 +3641,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientReceivesNonRetriableClonerE replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. @@ -3646,7 +3696,8 @@ TEST_F(TenantMigrationRecipientServiceTest, IncrementNumRestartsDueToRecipientFa replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Starting a migration where the state is not 'kUninitialized' indicates that we are restarting // from failover. @@ -3697,7 +3748,8 @@ TEST_F(TenantMigrationRecipientServiceTest, replSet.getConnectionString(), "tenantA", kDefaultStartMigrationTimestamp, - ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + ReadPreferenceSetting(ReadPreference::PrimaryOnly), + MigrationProtocolEnum::kMultitenantMigrations); initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Starting a migration where the state is not 'kUninitialized' indicates that we are restarting // from failover. diff --git a/src/mongo/db/repl/tenant_migration_state_machine.idl b/src/mongo/db/repl/tenant_migration_state_machine.idl index f8a6291d5a6..fb0644bfeaf 100644 --- a/src/mongo/db/repl/tenant_migration_state_machine.idl +++ b/src/mongo/db/repl/tenant_migration_state_machine.idl @@ -36,6 +36,7 @@ imports: - "mongo/client/read_preference_setting.idl" - "mongo/db/repl/replication_types.idl" - "mongo/db/repl/tenant_migration_pem_payload.idl" + - "mongo/db/serverless/serverless_types.idl" - "mongo/idl/basic_types.idl" enums: @@ -137,6 +138,9 @@ structs: description: >- The wall-clock time at which the migration has started. optional: true + protocol: + description: "Which migration protocol to use." + type: MigrationProtocol tenantMigrationRecipientDocument: description: "Represents an in-progress tenant migration on the migration recipient." @@ -171,6 +175,9 @@ structs: description: >- The read preference setting that the recipient will use to determine which node in the donor replica set to clone from. + protocol: + description: "Which migration protocol to use." + type: MigrationProtocol state: type: TenantMigrationRecipientState description: "The state of the tenant migration." diff --git a/src/mongo/db/repl/tenant_migration_util.h b/src/mongo/db/repl/tenant_migration_util.h index 18d303d6984..29fef1c44fe 100644 --- a/src/mongo/db/repl/tenant_migration_util.h +++ b/src/mongo/db/repl/tenant_migration_util.h @@ -38,7 +38,9 @@ #include "mongo/db/catalog/database.h" #include "mongo/db/keys_collection_document_gen.h" #include "mongo/db/pipeline/pipeline.h" +#include "mongo/db/repl/repl_server_parameters_gen.h" #include "mongo/db/repl/replication_coordinator.h" +#include "mongo/db/serverless/serverless_types_gen.h" #include "mongo/executor/scoped_task_executor.h" #include "mongo/util/net/ssl_util.h" #include "mongo/util/str.h" @@ -128,6 +130,34 @@ inline Status validatePrivateKeyPEMPayload(const StringData& payload) { #endif } +inline void protocolCompatibilityCheck(const MigrationProtocolEnum protocol, + const std::string& tenantId) { + switch (protocol) { + case MigrationProtocolEnum::kShardMerge: { + uassert(ErrorCodes::IllegalOperation, + str::stream() << "protocol '" << MigrationProtocol_serializer(protocol) + << "' not supported", + repl::feature_flags::gShardMerge.isEnabled( + serverGlobalParams.featureCompatibility)); + + // TODO: SERVER-59495 Add a check to ensure tenantId is not provided for 'Merge' + // protocol. + break; + } + case MigrationProtocolEnum::kMultitenantMigrations: { + uassert(ErrorCodes::InvalidOptions, + str::stream() << "'tenantId' is required for protocol '" + << MigrationProtocol_serializer(protocol) << "'", + !tenantId.empty()); + + + break; + } + default: + MONGO_UNREACHABLE; + } +} + /* * Creates an ExternalKeysCollectionDocument representing an config.external_validation_keys * document from the given the admin.system.keys document BSONObj. diff --git a/src/mongo/db/serverless/SConscript b/src/mongo/db/serverless/SConscript index 0f3259271f6..b2ebb792ae7 100644 --- a/src/mongo/db/serverless/SConscript +++ b/src/mongo/db/serverless/SConscript @@ -4,6 +4,18 @@ Import("env") env = env.Clone() env.Library( + target='serverless_types_idl', + source=[ + 'serverless_types.idl', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/idl/basic_types', + '$BUILD_DIR/mongo/idl/idl_parser' + ], +) + +env.Library( target='tenant_split_state_machine', source=[ 'tenant_split_state_machine.idl', diff --git a/src/mongo/db/serverless/serverless_types.idl b/src/mongo/db/serverless/serverless_types.idl new file mode 100644 index 00000000000..e906e7a52c3 --- /dev/null +++ b/src/mongo/db/serverless/serverless_types.idl @@ -0,0 +1,40 @@ +# Copyright (C) 2021-present MongoDB, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the Server Side Public License, version 1, +# as published by MongoDB, Inc. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# Server Side Public License for more details. +# +# You should have received a copy of the Server Side Public License +# along with this program. If not, see +# <http://www.mongodb.com/licensing/server-side-public-license>. +# +# As a special exception, the copyright holders give permission to link the +# code of portions of this program with the OpenSSL library under certain +# conditions as described in each individual source file and distribute +# linked combinations including the program with the OpenSSL library. You +# must comply with the Server Side Public License in all respects for +# all of the code used other than as permitted herein. If you modify file(s) +# with this exception, you may extend this exception to your version of the +# file(s), but you are not obligated to do so. If you do not wish to do so, +# delete this exception statement from your version. If you delete this +# exception statement from all source files in the program, then also delete +# it in the license file. +# +global: + cpp_namespace: "mongo" + +imports: + - "mongo/idl/basic_types.idl" + +enums: + MigrationProtocol: + description: "Determines which tenant migration protocol to use." + type: string + values: + kMultitenantMigrations: "multitenant migrations" + kShardMerge: "shard merge" |