diff options
4 files changed, 91 insertions, 5 deletions
diff --git a/jstests/multiVersion/remove_config_term_on_replset_downgrade.js b/jstests/multiVersion/remove_config_term_on_replset_downgrade.js new file mode 100644 index 00000000000..4315fdcc506 --- /dev/null +++ b/jstests/multiVersion/remove_config_term_on_replset_downgrade.js @@ -0,0 +1,73 @@ +/** + * Test the downgrade of a replica set from latest version to last-stable version succeeds and + * removes the "term" field of config document. + */ + +(function() { +'use strict'; + +load('jstests/multiVersion/libs/multi_rs.js'); +load('jstests/libs/test_background_ops.js'); + +let newVersion = "latest"; +let oldVersion = "last-stable"; + +let nodes = { + n1: {binVersion: newVersion}, + n2: {binVersion: newVersion}, + n3: {binVersion: newVersion} +}; + +let rst = new ReplSetTest({nodes: nodes}); +rst.startSet(); +rst.initiate(); + +let primary = rst.getPrimary(); + +// The default FCV is latestFCV for non-shard replica sets. +let primaryAdminDB = rst.getPrimary().getDB("admin"); +checkFCV(primaryAdminDB, latestFCV); + +// Reconfig in FCV 4.4. +let originalConfig = rst.getReplSetConfigFromNode(); +originalConfig.version++; +reconfig(rst, originalConfig); +rst.awaitNodesAgreeOnConfigVersion(); + +// Check that the term field exists in the config document on all nodes. +rst.nodes.forEach(function(node) { + jsTestLog("Checking the config term on node " + tojson(node.host) + " before downgrade."); + let config = node.getDB("local").getCollection("system.replset").findOne(); + assert(config.hasOwnProperty("term")); +}); + +// Remember the config from the primary before the downgrade. +let configInNewVersion = rst.getReplSetConfigFromNode(); + +jsTest.log("Downgrading FCV to 4.2"); +assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: lastStableFCV})); +rst.awaitReplication(); +// Check that the term field doesn't exist in the config document on all nodes. +rst.nodes.forEach(function(node) { + jsTestLog("Checking the config term on node " + tojson(node.host) + " after FCV downgrade."); + let config = node.getDB("local").getCollection("system.replset").findOne(); + assert(!config.hasOwnProperty("term"), tojson(config)); + config.term = configInNewVersion.term; + assert.docEq(configInNewVersion, config); +}); + +jsTest.log("Downgrading replica set.."); +rst.upgradeSet({binVersion: oldVersion}); +jsTest.log("Downgrade complete."); + +// Check that the term field doesn't exist in the config document on all nodes. +rst.nodes.forEach(function(node) { + reconnect(node); + jsTestLog("Checking the config term on node " + tojson(node.host) + " after binary downgrade."); + let config = node.getDB("local").getCollection("system.replset").findOne(); + assert(!config.hasOwnProperty("term"), tojson(config)); + config.term = configInNewVersion.term; + assert.docEq(configInNewVersion, config); +}); +rst.stopSet(); +})(); diff --git a/jstests/replsets/reconfig_ignores_term_field.js b/jstests/replsets/reconfig_ignores_term_field.js index bfe3d5b9d20..2cc48ac950d 100644 --- a/jstests/replsets/reconfig_ignores_term_field.js +++ b/jstests/replsets/reconfig_ignores_term_field.js @@ -25,7 +25,6 @@ assert.commandWorked(primary.getDB("admin").runCommand({replSetReconfig: config} replTest.awaitReplication(); config = primary.getDB("local").system.replset.findOne(); -// TODO SERVER-45408: uncomment once we enable serialization of the term field. -// assert.eq(config.term, 1); +assert.eq(config.term, 1); replTest.stopSet(); }());
\ No newline at end of file diff --git a/src/mongo/db/commands/feature_compatibility_version.cpp b/src/mongo/db/commands/feature_compatibility_version.cpp index 48ed157c26f..c98457c1f86 100644 --- a/src/mongo/db/commands/feature_compatibility_version.cpp +++ b/src/mongo/db/commands/feature_compatibility_version.cpp @@ -162,6 +162,17 @@ void FeatureCompatibilityVersion::onInsertOrUpdate(OperationContext* opCtx, cons << FeatureCompatibilityVersionParser::toString(newVersion); } + // Remove term field of config document on downgrade. + if (newVersion == ServerGlobalParams::FeatureCompatibility::Version::kFullyDowngradedTo42 && + repl::ReplicationCoordinator::get(opCtx)->getReplicationMode() == + repl::ReplicationCoordinator::modeReplSet) { + auto storageInterface = repl::StorageInterface::get(opCtx); + repl::UnreplicatedWritesBlock uwb(opCtx); + repl::TimestampedBSONObj update{BSON("$unset" << BSON("term" << 1)), Timestamp()}; + uassertStatusOK(storageInterface->updateSingleton( + opCtx, NamespaceString::kSystemReplSetNamespace, {}, update)); + } + opCtx->recoveryUnit()->onCommit([opCtx, newVersion](boost::optional<Timestamp>) { serverGlobalParams.featureCompatibility.setVersion(newVersion); updateMinWireVersion(); diff --git a/src/mongo/db/repl/repl_set_config.cpp b/src/mongo/db/repl/repl_set_config.cpp index 375e2a73d61..5094f610c8e 100644 --- a/src/mongo/db/repl/repl_set_config.cpp +++ b/src/mongo/db/repl/repl_set_config.cpp @@ -862,9 +862,12 @@ BSONObj ReplSetConfig::toBSON() const { BSONObjBuilder configBuilder; configBuilder.append(kIdFieldName, _replSetName); configBuilder.appendIntOrLL(kVersionFieldName, _version); - // TODO (SERVER-45408): Enable serialization of the config "term" field once we can handle it - // properly in upgrade/downgrade scenarios. - // configBuilder.appendIntOrLL(kTermFieldName, _term); + + if (serverGlobalParams.featureCompatibility.isVersion( + ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo44)) { + configBuilder.appendIntOrLL(kTermFieldName, _term); + } + if (_configServer) { // Only include "configsvr" field if true configBuilder.append(kConfigServerFieldName, _configServer); |