From da82e5278ca717d3228e4837a3e815c5ced876e0 Mon Sep 17 00:00:00 2001 From: jannaerin Date: Mon, 6 Dec 2021 16:19:51 +0000 Subject: SERVER-61474 Ban directoryPerDb and directoryForIndexes with Merge --- jstests/replsets/shard_merge_invalid_options.js | 74 ++++++++++++++++++++++ .../db/commands/tenant_migration_donor_cmds.cpp | 2 + .../commands/tenant_migration_recipient_cmds.cpp | 2 + src/mongo/db/repl/tenant_migration_util.h | 16 +++++ src/mongo/db/storage/storage_engine.h | 2 + src/mongo/db/storage/storage_engine_impl.h | 4 ++ src/mongo/db/storage/storage_engine_mock.h | 3 + 7 files changed, 103 insertions(+) create mode 100644 jstests/replsets/shard_merge_invalid_options.js diff --git a/jstests/replsets/shard_merge_invalid_options.js b/jstests/replsets/shard_merge_invalid_options.js new file mode 100644 index 00000000000..4d7eee88a40 --- /dev/null +++ b/jstests/replsets/shard_merge_invalid_options.js @@ -0,0 +1,74 @@ +/** + * Tests that the donorStartMigration and recipientSyncData commands throw when a node has options + * set that are incompatible with protocol shard merge. + * + * @tags: [requires_fcv_53, featureFlagShardMerge] + * ] + */ + +(function() { +"use strict"; + +load("jstests/replsets/libs/tenant_migration_util.js"); +load("jstests/libs/fail_point_util.js"); + +function runTest(nodeOptions, expectedError) { + let rst = new ReplSetTest({nodes: 1, nodeOptions: nodeOptions}); + rst.startSet(); + rst.initiate(); + + let primary = rst.getPrimary(); + let adminDB = primary.getDB("admin"); + const kDummyConnStr = "mongodb://localhost/?replicaSet=foo"; + const readPreference = {mode: 'primary'}; + const migrationCertificates = TenantMigrationUtil.makeMigrationCertificatesForTest(); + + // Enable below fail points to prevent starting the donor/recipient POS instance. + configureFailPoint(primary, "returnResponseCommittedForDonorStartMigrationCmd"); + configureFailPoint(primary, "returnResponseOkForRecipientSyncDataCmd"); + configureFailPoint(primary, "returnResponseOkForRecipientForgetMigrationCmd"); + + // Ensure the feature flag is enabled and FCV is latest + assert(TenantMigrationUtil.isShardMergeEnabled(adminDB)); + assert.eq(getFCVConstants().latest, + adminDB.system.version.findOne({_id: 'featureCompatibilityVersion'}).version); + + // Assert that donorStartMigration fails with the expected code + assert.commandFailedWithCode( + adminDB.runCommand({ + donorStartMigration: 1, + protocol: "shard merge", + migrationId: UUID(), + recipientConnectionString: kDummyConnStr, + readPreference: readPreference, + donorCertificateForRecipient: migrationCertificates.donorCertificateForRecipient, + recipientCertificateForDonor: migrationCertificates.recipientCertificateForDonor + }), + expectedError, + "Expected donorStartMigration to fail when protocol is 'shard merge' and node options " + + tojson(nodeOptions) + " are set, but did not"); + + // Assert that recipientSyncData fails with the expected code + assert.commandFailedWithCode( + adminDB.runCommand({ + recipientSyncData: 1, + protocol: "shard merge", + migrationId: UUID(), + donorConnectionString: kDummyConnStr, + readPreference: readPreference, + startMigrationDonorTimestamp: Timestamp(1, 1), + recipientCertificateForDonor: migrationCertificates.recipientCertificateForDonor + }), + expectedError, + "Expected recipientSyncData to fail when protocol is 'shard merge' and node options " + + tojson(nodeOptions) + " are set, but did not"); + + rst.stopSet(); +} + +// Shard merge is not allowed when directoryperdb is enabled +runTest({directoryperdb: ""}, ErrorCodes.InvalidOptions); + +// Shard merge is not allowed when directoryForIndexes is enabled +runTest({"wiredTigerDirectoryForIndexes": ""}, ErrorCodes.InvalidOptions); +})(); diff --git a/src/mongo/db/commands/tenant_migration_donor_cmds.cpp b/src/mongo/db/commands/tenant_migration_donor_cmds.cpp index 00e283d8563..e94f865d1cb 100644 --- a/src/mongo/db/commands/tenant_migration_donor_cmds.cpp +++ b/src/mongo/db/commands/tenant_migration_donor_cmds.cpp @@ -76,6 +76,8 @@ public: uassertStatusOK(tenant_migration_util::protocolTenantIdCompatibilityCheck( migrationProtocol, cmd.getTenantId().toString())); + tenant_migration_util::protocolStorageOptionsCompatibilityCheck(opCtx, + migrationProtocol); TenantMigrationDonorDocument stateDoc(cmd.getMigrationId(), cmd.getRecipientConnectionString().toString(), diff --git a/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp b/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp index 9952d301d47..c81f8ecb697 100644 --- a/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp +++ b/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp @@ -74,6 +74,8 @@ public: uassertStatusOK(tenant_migration_util::protocolTenantIdCompatibilityCheck( migrationProtocol, cmd.getTenantId().toString())); + tenant_migration_util::protocolStorageOptionsCompatibilityCheck(opCtx, + migrationProtocol); TenantMigrationRecipientDocument stateDoc(cmd.getMigrationId(), cmd.getDonorConnectionString().toString(), diff --git a/src/mongo/db/repl/tenant_migration_util.h b/src/mongo/db/repl/tenant_migration_util.h index 818ffba2649..f3350458182 100644 --- a/src/mongo/db/repl/tenant_migration_util.h +++ b/src/mongo/db/repl/tenant_migration_util.h @@ -186,6 +186,22 @@ inline Status protocolTenantIdCompatibilityCheck(const MigrationProtocolEnum& pr return Status::OK(); } +inline void protocolStorageOptionsCompatibilityCheck(OperationContext* opCtx, + const MigrationProtocolEnum& protocol) { + if (protocol != MigrationProtocolEnum::kShardMerge) + return; + + uassert(ErrorCodes::InvalidOptions, + str::stream() << "protocol '" << MigrationProtocol_serializer(protocol) + << "' is not allowed when storage option 'directoryPerDb' is enabled", + !storageGlobalParams.directoryperdb); + uassert( + ErrorCodes::InvalidOptions, + str::stream() << "protocol '" << MigrationProtocol_serializer(protocol) + << "' is not allowed when storage option 'directoryForIndexes' is enabled", + !opCtx->getServiceContext()->getStorageEngine()->isUsingDirectoryForIndexes()); +} + /* * 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/storage/storage_engine.h b/src/mongo/db/storage/storage_engine.h index f7c706b96a6..2160a430aa0 100644 --- a/src/mongo/db/storage/storage_engine.h +++ b/src/mongo/db/storage/storage_engine.h @@ -643,6 +643,8 @@ public: virtual bool isUsingDirectoryPerDb() const = 0; + virtual bool isUsingDirectoryForIndexes() const = 0; + virtual KVEngine* getEngine() = 0; virtual const KVEngine* getEngine() const = 0; virtual DurableCatalog* getCatalog() = 0; diff --git a/src/mongo/db/storage/storage_engine_impl.h b/src/mongo/db/storage/storage_engine_impl.h index f2b69e8d2ee..4f25de8f7d2 100644 --- a/src/mongo/db/storage/storage_engine_impl.h +++ b/src/mongo/db/storage/storage_engine_impl.h @@ -348,6 +348,10 @@ public: return _options.directoryPerDB; } + bool isUsingDirectoryForIndexes() const override { + return _options.directoryForIndexes; + } + StatusWith pinOldestTimestamp(OperationContext* opCtx, const std::string& requestingServiceName, Timestamp requestedTimestamp, diff --git a/src/mongo/db/storage/storage_engine_mock.h b/src/mongo/db/storage/storage_engine_mock.h index 7032a3afe87..93a187c7615 100644 --- a/src/mongo/db/storage/storage_engine_mock.h +++ b/src/mongo/db/storage/storage_engine_mock.h @@ -179,6 +179,9 @@ public: bool isUsingDirectoryPerDb() const final { return false; } + bool isUsingDirectoryForIndexes() const final { + return false; + } KVEngine* getEngine() final { return nullptr; } -- cgit v1.2.1