diff options
-rw-r--r-- | jstests/multiVersion/initiate_shard_server_with_secondaryDelaySecs.js | 126 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_set_config_checks.cpp | 44 |
2 files changed, 153 insertions, 17 deletions
diff --git a/jstests/multiVersion/initiate_shard_server_with_secondaryDelaySecs.js b/jstests/multiVersion/initiate_shard_server_with_secondaryDelaySecs.js new file mode 100644 index 00000000000..7b46a84ea7b --- /dev/null +++ b/jstests/multiVersion/initiate_shard_server_with_secondaryDelaySecs.js @@ -0,0 +1,126 @@ +/** + * Tests that new shard servers using the 'latest' binary in 'lastLTSFCV' are able to use the + * 'secondaryDelaySecs' field. Once the shard is added to a sharded cluster, it must abide by + * the FCV restrictions of that cluster. + */ + +(function() { +"use strict"; + +function checkForSecondaryDelaySecs(primaryDB) { + let config = primaryDB.runCommand({replSetGetConfig: 1}).config; + assert.eq(config.members[0].secondaryDelaySecs, 0, config); + assert(!config.members[0].hasOwnProperty('slaveDelay'), config); +} + +function checkForSlaveDelaySecs(primaryDB) { + let config = primaryDB.runCommand({replSetGetConfig: 1}).config; + assert.eq(config.members[0].slaveDelay, 0, config); + assert(!config.members[0].hasOwnProperty('secondaryDelaySecs'), config); +} + +// A 'latest' binary cluster started with clean data files will initialize shard servers +// with 'lastLTSFCV' and then use addShard to get them to 'latestFCV'. +const st = new ShardingTest({ + shards: {rs0: {nodes: [{binVersion: "latest"}]}}, +}); +const mongosAdminDB = st.s.getDB("admin"); +const configPrimaryAdminDB = st.configRS.getPrimary().getDB("admin"); +const shardPrimaryAdminDB = st.rs0.getPrimary().getDB("admin"); + +checkFCV(configPrimaryAdminDB, latestFCV); +checkFCV(shardPrimaryAdminDB, latestFCV); + +jsTestLog("Test adding a shard server to cluster running 'latest' binaries and 'latestFCV'"); +// A 'latest' binary replica set started as a shard server defaults to 'lastLTSFCV'. Allow +// the use of 'secondaryDelaySecs' before the shard server is added to a cluster. +let shard2 = new ReplSetTest({ + name: "shard2", + nodes: [{binVersion: "latest", rsConfig: {secondaryDelaySecs: 0}}], + nodeOptions: {shardsvr: ""}, + useHostName: true +}); + +shard2.startSet(); +shard2.initiate(); +let latestShardPrimaryAdminDB = shard2.getPrimary().getDB("admin"); +checkFCV(latestShardPrimaryAdminDB, lastLTSFCV); +// Even though shard2 is in the 'lastLTSFCV', its config should still have the +// 'secondaryDelaySecs' field. +let config = checkForSecondaryDelaySecs(latestShardPrimaryAdminDB); + +// The cluster is in the 'latestFCV', so adding shard2 to the cluster should update shard2's +// FCV. +assert.commandWorked(mongosAdminDB.runCommand({addShard: shard2.getURL()})); +checkFCV(latestShardPrimaryAdminDB, latestFCV); + +// FCV can be set to 'lastLTSFCV' on mongos. +assert.commandWorked(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: lastLTSFCV})); + +// featureCompatibilityVersion propagates to the config, existing shard, and newly added shard. +checkFCV(configPrimaryAdminDB, lastLTSFCV); +checkFCV(shardPrimaryAdminDB, lastLTSFCV); +checkFCV(latestShardPrimaryAdminDB, lastLTSFCV); + +// The FCV was downgraded to 'lastLTSFCV', which is 4.4 in this case. During FCV downgrade, the +// 'secondaryDelaySecs' will automatically be changed to 'slaveDelay'. +checkForSlaveDelaySecs(latestShardPrimaryAdminDB); +checkForSlaveDelaySecs(configPrimaryAdminDB); +checkForSlaveDelaySecs(shardPrimaryAdminDB); + +jsTestLog("Test adding a shard server to cluster running 'latest' binaries and 'lastLTSFCV'"); +// A 'latest' binary replica set started as a shard server defaults to 'lastLTSFCV'. Allow +// the use of 'secondaryDelaySecs' before the shard server is added to a cluster. +let shard3 = new ReplSetTest({ + name: "shard3", + nodes: [{binVersion: "latest", rsConfig: {secondaryDelaySecs: 0}}], + nodeOptions: {shardsvr: ""}, + useHostName: true +}); + +shard3.startSet(); +shard3.initiate(); +latestShardPrimaryAdminDB = shard3.getPrimary().getDB("admin"); +checkFCV(latestShardPrimaryAdminDB, lastLTSFCV); +// Even though shard3 is in the 'lastLTSFCV', its config should still have the +// 'secondaryDelaySecs' field. +checkForSecondaryDelaySecs(latestShardPrimaryAdminDB); + +// The cluster is also in the 'lastLTSFCV', so adding shard3 to a downgraded cluster will not +// update shard3's FCV. +assert.commandWorked(mongosAdminDB.runCommand({addShard: shard3.getURL()})); +checkFCV(latestShardPrimaryAdminDB, lastLTSFCV); +// Since the FCV was not updated, secondaryDelaySecs is still present in the config. +checkForSecondaryDelaySecs(latestShardPrimaryAdminDB); + +// The cluster wide FCV is 'lastLTSFCV', which is 4.4 in this case. Despite replSetGetConfig +// returning 'secondaryDelaySecs' for shard3, future reconfigs on shard3 must use 'slaveDelay'. +config = latestShardPrimaryAdminDB.runCommand({replSetGetConfig: 1}).config; +config.version++; +assert.commandFailedWithCode(latestShardPrimaryAdminDB.runCommand({replSetReconfig: config}), + ErrorCodes.NewReplicaSetConfigurationIncompatible); + +delete config.members[0].secondaryDelaySecs; +config.members[0].slaveDelay = 0; +config.version++; + +// Test that a reconfig with 'slaveDelay' succeeds. +assert.commandWorked(latestShardPrimaryAdminDB.runCommand({replSetReconfig: config})); +checkForSlaveDelaySecs(latestShardPrimaryAdminDB); + +// FCV can be set to 'latestFCV' on mongos. +assert.commandWorked(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: latestFCV})); +checkFCV(st.configRS.getPrimary().getDB("admin"), latestFCV); +checkFCV(shardPrimaryAdminDB, latestFCV); +checkFCV(latestShardPrimaryAdminDB, latestFCV); + +checkForSecondaryDelaySecs(latestShardPrimaryAdminDB); +checkForSecondaryDelaySecs(configPrimaryAdminDB); +checkForSecondaryDelaySecs(shardPrimaryAdminDB); + +// Call ShardingTest.stop before shutting down shard2 and shard3, so that the UUID check in +// ShardingTest.stop can talk to them. +st.stop(); +shard2.stopSet(); +shard3.stopSet(); +})(); diff --git a/src/mongo/db/repl/repl_set_config_checks.cpp b/src/mongo/db/repl/repl_set_config_checks.cpp index 20ad4106e2f..e4da3276793 100644 --- a/src/mongo/db/repl/repl_set_config_checks.cpp +++ b/src/mongo/db/repl/repl_set_config_checks.cpp @@ -37,6 +37,7 @@ #include "mongo/db/repl/repl_server_parameters_gen.h" #include "mongo/db/repl/repl_set_config.h" #include "mongo/db/repl/replication_coordinator_external_state.h" +#include "mongo/db/s/sharding_state.h" #include "mongo/db/service_context.h" #include "mongo/util/str.h" @@ -105,6 +106,11 @@ Status ensureNoNewlyAddedMembers(const ReplSetConfig& config) { */ Status isFCVCompatible(const ReplSetConfig& config) { auto version = serverGlobalParams.featureCompatibility.getVersion(); + // New shard servers using 'latest' binaries will default to the 'lastLTS' FCV prior to being + // added to the cluster. If they have not yet been added to a sharded cluster via addShard, + // allow them to use 'secondaryDelaySecs'. + bool isNewShardServer = (serverGlobalParams.clusterRole == ClusterRole::ShardServer && + !ShardingState::get(getGlobalServiceContext())->enabled()); // TODO (SERVER-53354) If we are currently upgrading, we check if the feature flag is enabled // for the target version. We use the generic FCV references here to avoid having to update the // FCV constants used after each continuous release. After release, we should make sure to @@ -121,24 +127,28 @@ Status isFCVCompatible(const ReplSetConfig& config) { bool isEnabled = feature_flags::gUseSecondaryDelaySecs.isEnabled(targetFCV); // We must check that every member config has a valid delay field name. for (auto iter = config.membersBegin(); iter != config.membersEnd(); ++iter) { - if ((isEnabled && iter->hasSlaveDelay()) || (!isEnabled && iter->hasSecondaryDelaySecs())) { - // TODO (SERVER-53354) If the feature flag is disabled, getVersion() will throw. In this - // case, the version should default to kLatest. We use the generic FCV references here - // to avoid having to update the FCV constants used after each continuous release. After - // release, we should make sure to remove these references while removing the feature - // flag. - // - //(Generic FCV reference): feature flag support - auto featureFlagVersion = isEnabled - ? FeatureCompatibilityVersionParser::toString( - feature_flags::gUseSecondaryDelaySecs.getVersion()) - : FeatureCompatibilityVersionParser::toString( - ServerGlobalParams::FeatureCompatibility::kLatest); + // TODO (SERVER-53354) If the feature flag is disabled, getVersion() will throw. In this + // case, the version should default to kLatest. We use the generic FCV references here + // to avoid having to update the FCV constants used after each continuous release. After + // release, we should make sure to remove these references while removing the feature + // flag. + // + //(Generic FCV reference): feature flag support + if (isEnabled && iter->hasSlaveDelay()) { + auto featureFlagVersion = FeatureCompatibilityVersionParser::toString( + feature_flags::gUseSecondaryDelaySecs.getVersion()); return Status(ErrorCodes::BadValue, - str::stream() << "If the node is in FCV " << featureFlagVersion - << ", we must use the secondaryDelaySecs field name " - "instead of slaveDelay. Only nodes below FCV " - << featureFlagVersion << " should use slaveDelay."); + str::stream() + << "Incompatible delay field name. If the node is in FCV " + << featureFlagVersion << ", it must use secondaryDelaySecs."); + } + //(Generic FCV reference): feature flag support + if (!isEnabled && iter->hasSecondaryDelaySecs() && !isNewShardServer) { + auto latestVersion = FeatureCompatibilityVersionParser::toString( + ServerGlobalParams::FeatureCompatibility::kLatest); + return Status(ErrorCodes::BadValue, + str::stream() << "Incompatible delay field name. In FCV versions below " + << latestVersion << ", nodes must use slaveDelay."); } } |