summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Chan <jason.chan@mongodb.com>2020-09-09 19:50:15 +0000
committerJason Chan <jason.chan@mongodb.com>2020-09-24 20:42:23 +0000
commitaa2faa36250d818ae54287323ec5d72cfa00b7ef (patch)
tree254394a4eae3cbd9ebd9dddabeda62afb5805d92
parent80e15a92ba7d167f1aa4b0c24307d1c067c60ce9 (diff)
downloadmongo-aa2faa36250d818ae54287323ec5d72cfa00b7ef.tar.gz
SERVER-50706 Add fromConfigServer parameter to allow transitioning a shard server from lastLTS FCV to lastContinuousFCV
(cherry picked from commit 3a6bde797e31d9e06e982aa20b89a856cfeef95c) (cherry picked from commit c8a178cbacb46b3d44cc0a4bb8ba77645bc42c6b)
-rw-r--r--buildscripts/linter/simplecpplint.py2
-rw-r--r--jstests/multiVersion/genericSetFCVUsage/set_feature_compatibility_version.js85
-rw-r--r--jstests/noPassthrough/feature_compatibility_version.js18
-rw-r--r--jstests/noPassthroughWithMongod/fcv_changes_close_connections.js4
-rw-r--r--jstests/replsets/awaitable_ismaster_fcv_change.js87
-rw-r--r--src/mongo/db/commands/feature_compatibility_version.cpp101
-rw-r--r--src/mongo/db/commands/feature_compatibility_version.h7
-rw-r--r--src/mongo/db/commands/feature_compatibility_version_parser.cpp61
-rw-r--r--src/mongo/db/commands/feature_compatibility_version_parser.h55
-rw-r--r--src/mongo/db/commands/set_feature_compatibility_version.idl5
-rw-r--r--src/mongo/db/commands/set_feature_compatibility_version_command.cpp67
-rw-r--r--src/mongo/db/fcv_op_observer.cpp12
-rw-r--r--src/mongo/db/s/SConscript1
-rw-r--r--src/mongo/db/s/config/sharding_catalog_manager_add_shard_test.cpp12
-rw-r--r--src/mongo/db/s/config/sharding_catalog_manager_shard_operations.cpp91
-rw-r--r--src/mongo/db/server_options.h15
16 files changed, 452 insertions, 171 deletions
diff --git a/buildscripts/linter/simplecpplint.py b/buildscripts/linter/simplecpplint.py
index 5ca79216de0..a1cd50f94d3 100644
--- a/buildscripts/linter/simplecpplint.py
+++ b/buildscripts/linter/simplecpplint.py
@@ -69,6 +69,8 @@ GENERIC_FCV = [
r'::kDowngradingFromLatestToLastLTS',
r'::kDowngradingFromLatestToLastContinuous',
r'\.isUpgradingOrDowngrading',
+ r'::kDowngradingFromLatestToLastContinuous',
+ r'::kUpgradingFromLastLTSToLastContinuous',
]
_RE_GENERIC_FCV_REF = re.compile(r'(' + '|'.join(GENERIC_FCV) + r')\b')
diff --git a/jstests/multiVersion/genericSetFCVUsage/set_feature_compatibility_version.js b/jstests/multiVersion/genericSetFCVUsage/set_feature_compatibility_version.js
index 75ef8ad1841..badce28a6b2 100644
--- a/jstests/multiVersion/genericSetFCVUsage/set_feature_compatibility_version.js
+++ b/jstests/multiVersion/genericSetFCVUsage/set_feature_compatibility_version.js
@@ -69,8 +69,8 @@ function runStandaloneTest(downgradeVersion) {
{setFeatureCompatibilityVersion: downgradeFCV, downgradeOnDiskChanges: false}),
ErrorCodes.IllegalOperation);
} else {
- jsTestLog(
- "Test that setFeatureCompatibilityVersion succeeds with downgradeOnDiskChanges parameter when FCV is last-continuous");
+ jsTestLog("Test that setFeatureCompatibilityVersion succeeds with downgradeOnDiskChanges " +
+ "parameter when FCV is last-continuous");
assert.commandWorked(adminDB.runCommand(
{setFeatureCompatibilityVersion: downgradeFCV, downgradeOnDiskChanges: true}));
checkFCV(adminDB, downgradeFCV);
@@ -132,18 +132,38 @@ function runStandaloneTest(downgradeVersion) {
checkFCV(adminDB, downgradeFCV);
// setFeatureCompatibilityVersion does not support upgrading/downgrading between last-lts and
- // last-continuous FCV.
+ // last-continuous FCV by default. Upgrading from last-lts to last-continuous is allowed if
+ // fromConfigServer is set to true.
if (lastContinuousFCV !== lastLTSFCV) {
if (downgradeFCV === lastContinuousFCV) {
// Attempt to downgrade FCV from last-continuous to last-lts.
assert.commandFailedWithCode(
adminDB.runCommand({setFeatureCompatibilityVersion: lastLTSFCV}),
ErrorCodes.IllegalOperation);
+ // Downgrading from last-continuous to last-lts is not allowed even with
+ // fromConfigServer: true.
+ assert.commandFailedWithCode(
+ adminDB.runCommand(
+ {setFeatureCompatibilityVersion: lastLTSFCV, fromConfigServer: true}),
+ ErrorCodes.IllegalOperation);
} else {
// Attempt to upgrade FCV from last-lts to last-continuous.
assert.commandFailedWithCode(
- adminDB.runCommand({setFeatureCompatibilityVersion: lastContinuousFCV}),
- ErrorCodes.IllegalOperation);
+ adminDB.runCommand({setFeatureCompatibilityVersion: lastContinuousFCV}), 5070603);
+
+ assert.commandFailedWithCode(
+ adminDB.runCommand(
+ {setFeatureCompatibilityVersion: lastContinuousFCV, fromConfigServer: false}),
+ 5070603);
+ assert.commandWorked(adminDB.runCommand(
+ {setFeatureCompatibilityVersion: lastContinuousFCV, fromConfigServer: true}));
+ checkFCV(adminDB, lastContinuousFCV);
+
+ // Reset the FCV back to last-lts.
+ assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: latestFCV}));
+ checkFCV(adminDB, latestFCV);
+ assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: lastLTSFCV}));
+ checkFCV(adminDB, lastLTSFCV);
}
}
@@ -210,12 +230,12 @@ function runStandaloneTest(downgradeVersion) {
MongoRunner.stopMongod(conn);
// A 'latest' binary mongod started with --shardsvr and clean data files defaults to
- // 'downgradeFCV'.
+ // lastLTSFCV.
conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest, shardsvr: ""});
assert.neq(
null, conn, "mongod was unable to start up with version=" + latest + " and no data files");
adminDB = conn.getDB("admin");
- checkFCV(adminDB, downgradeFCV);
+ checkFCV(adminDB, lastLTSFCV);
MongoRunner.stopMongod(conn);
}
@@ -292,6 +312,16 @@ function runReplicaSetTest(downgradeVersion) {
primary.adminCommand({setFeatureCompatibilityVersion: downgradeFCV}),
ErrorCodes.IllegalOperation);
+ if (downgradeFCV === lastLTSFCV && lastLTSFCV !== lastContinuousFCV) {
+ // Upgrading to last-continuous should fail if we are in the middle of upgrading to latest.
+ assert.commandFailedWithCode(
+ primary.adminCommand({setFeatureCompatibilityVersion: lastContinuousFCV}), 5070602);
+ assert.commandFailedWithCode(
+ primary.adminCommand(
+ {setFeatureCompatibilityVersion: lastContinuousFCV, fromConfigServer: true}),
+ 5070602);
+ }
+
// Because the failed upgrade command left the primary in an intermediary state, complete the
// upgrade.
assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: latestFCV}));
@@ -319,6 +349,32 @@ function runReplicaSetTest(downgradeVersion) {
// Complete the downgrade.
assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: downgradeFCV}));
+ if (downgradeFCV === lastLTSFCV && lastContinuousFCV !== lastLTSFCV) {
+ // The command should fail because wtimeout expires before a majority responds.
+ stopServerReplication(secondary);
+ res = primary.adminCommand({
+ setFeatureCompatibilityVersion: lastContinuousFCV,
+ fromConfigServer: true,
+ writeConcern: {wtimeout: 1000}
+ });
+ assert.eq(0, res.ok);
+ assert.commandFailedWithCode(res, ErrorCodes.WriteConcernFailed);
+ restartServerReplication(secondary);
+
+ // Upgrading the FCV to latest should fail if a previous upgrade to lastContinuous has not
+ // yet completed.
+ assert.commandFailedWithCode(
+ primary.adminCommand({setFeatureCompatibilityVersion: latestFCV}), 5070602);
+
+ // Complete the upgrade to last-continuous.
+ assert.commandWorked(primary.adminCommand(
+ {setFeatureCompatibilityVersion: lastContinuousFCV, fromConfigServer: true}));
+
+ // Reset the FCV back to last-lts.
+ assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: latestFCV}));
+ assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV}));
+ }
+
secondary = rst.add({binVersion: downgradeVersion});
secondaryAdminDB = secondary.getDB("admin");
@@ -439,7 +495,7 @@ function runShardingTest(downgradeVersion) {
checkFCV(configPrimaryAdminDB, downgradeFCV);
checkFCV(shardPrimaryAdminDB, downgradeFCV);
- // A 'latest' binary replica set started as a shard server defaults to 'downgradeFCV'.
+ // A 'latest' binary replica set started as a shard server defaults to 'lastLTSFCV'.
let latestShard = new ReplSetTest({
name: "latestShard",
nodes: [{binVersion: latest}, {binVersion: latest}],
@@ -449,7 +505,7 @@ function runShardingTest(downgradeVersion) {
latestShard.startSet();
latestShard.initiate();
let latestShardPrimaryAdminDB = latestShard.getPrimary().getDB("admin");
- checkFCV(latestShardPrimaryAdminDB, downgradeFCV);
+ checkFCV(latestShardPrimaryAdminDB, lastLTSFCV);
assert.commandWorked(mongosAdminDB.runCommand({addShard: latestShard.getURL()}));
checkFCV(latestShardPrimaryAdminDB, downgradeFCV);
@@ -489,12 +545,13 @@ function runShardingTest(downgradeVersion) {
downgradedShard.stopSet();
}
-runStandaloneTest('last-continuous');
runStandaloneTest('last-lts');
-
-runReplicaSetTest('last-continuous');
runReplicaSetTest('last-lts');
-
-runShardingTest('last-continuous');
runShardingTest('last-lts');
+
+if (lastLTSFCV != lastContinuousFCV) {
+ runStandaloneTest('last-continuous');
+ runReplicaSetTest('last-continuous');
+ runShardingTest('last-continuous');
+}
})();
diff --git a/jstests/noPassthrough/feature_compatibility_version.js b/jstests/noPassthrough/feature_compatibility_version.js
index fa02e5eaada..2ee5627d2ed 100644
--- a/jstests/noPassthrough/feature_compatibility_version.js
+++ b/jstests/noPassthrough/feature_compatibility_version.js
@@ -20,7 +20,7 @@ for (let oldVersion of [lastLTSFCV, lastContinuousFCV]) {
{$set: {version: oldVersion}}));
checkFCV(adminDB, oldVersion);
- // Upgrading to lastest.
+ // Upgrading to latest.
assert.commandWorked(
adminDB.system.version.update({_id: "featureCompatibilityVersion"},
{$set: {version: oldVersion, targetVersion: latestFCV}}));
@@ -51,6 +51,22 @@ for (let oldVersion of [lastLTSFCV, lastContinuousFCV]) {
checkFCV(adminDB, latestFCV);
}
+if (lastLTSFCV !== lastContinuousFCV) {
+ // Test that we can update from last-lts to last-continuous when the two versions are not equal.
+ // This upgrade path is exposed to users through the setFeatureCompatibilityVersion command with
+ // fromConfigServer: true.
+ assert.commandWorked(adminDB.system.version.update(
+ {_id: "featureCompatibilityVersion"},
+ {$set: {version: lastLTSFCV, targetVersion: lastContinuousFCV}}));
+ checkFCV(adminDB, lastLTSFCV, lastContinuousFCV);
+
+ // Reset to latestFCV.
+ assert.commandWorked(adminDB.system.version.update(
+ {_id: "featureCompatibilityVersion"},
+ {$set: {version: latestFCV}, $unset: {targetVersion: true, previousVersion: true}}));
+ checkFCV(adminDB, latestFCV);
+}
+
// Updating the featureCompatibilityVersion document with an invalid version fails.
assert.writeErrorWithCode(
adminDB.system.version.update({_id: "featureCompatibilityVersion"}, {$set: {version: "3.2"}}),
diff --git a/jstests/noPassthroughWithMongod/fcv_changes_close_connections.js b/jstests/noPassthroughWithMongod/fcv_changes_close_connections.js
index 552f13dcc20..f78d3fcf41e 100644
--- a/jstests/noPassthroughWithMongod/fcv_changes_close_connections.js
+++ b/jstests/noPassthroughWithMongod/fcv_changes_close_connections.js
@@ -98,6 +98,10 @@ function runTest(oldVersion) {
// 'last-lts'.
if (lastContinuousFCV !== lastLTSFCV) {
runTest(lastContinuousFCV);
+
+ // Upgrading from last-lts to last-continuous. This FCV transition is allowed through the
+ // setFeatureCompatibilityVersion command with fromConfigServer: true.
+ testFCVChange({fcvDoc: {version: lastLTSFCV, targetVersion: lastContinuousFCV}});
}
// Test upgrade/downgrade between 'latest' and 'last-lts'.
diff --git a/jstests/replsets/awaitable_ismaster_fcv_change.js b/jstests/replsets/awaitable_ismaster_fcv_change.js
index 41ed644e5e6..3a99851bba7 100644
--- a/jstests/replsets/awaitable_ismaster_fcv_change.js
+++ b/jstests/replsets/awaitable_ismaster_fcv_change.js
@@ -165,17 +165,94 @@ function runTest(downgradeFCV) {
assert.eq(0, numAwaitingTopologyChangeOnSecondary);
// Get the new topologyVersion.
- const primaryResponseAfterDowngrade = isMasterAsInternalClient();
+ let primaryResponseAfterDowngrade = isMasterAsInternalClient();
assert(primaryResponseAfterDowngrade.hasOwnProperty("topologyVersion"),
tojson(primaryResponseAfterDowngrade));
- const primaryTopologyVersionAfterDowngrade = primaryResponseAfterDowngrade.topologyVersion;
- const minWireVersionAfterDowngrade = primaryResponseAfterDowngrade.minWireVersion;
+ let primaryTopologyVersionAfterDowngrade = primaryResponseAfterDowngrade.topologyVersion;
+ let minWireVersionAfterDowngrade = primaryResponseAfterDowngrade.minWireVersion;
- const secondaryResponseAfterDowngrade =
+ let secondaryResponseAfterDowngrade =
assert.commandWorked(secondaryAdminDB.runCommand({isMaster: 1}));
assert(secondaryResponseAfterDowngrade.hasOwnProperty("topologyVersion"),
tojson(secondaryResponseAfterDowngrade));
- const secondaryTopologyVersionAfterDowngrade = secondaryResponseAfterDowngrade.topologyVersion;
+ let secondaryTopologyVersionAfterDowngrade = secondaryResponseAfterDowngrade.topologyVersion;
+
+ if (downgradeFCV === lastLTSFCV && lastLTSFCV !== lastContinuousFCV) {
+ // Test upgrading from last-lts to last-continuous FCV. We allow this upgrade path via the
+ // setFeatureCompatibilityVersion command with fromConfigServer: true.
+
+ // Reconfigure the failpoint to refresh the number of times the failpoint has been entered.
+ primaryFailPoint = configureFailPoint(primary, "waitForIsMasterResponse");
+ secondaryFailPoint = configureFailPoint(secondary, "waitForIsMasterResponse");
+ let awaitIsMasterBeforeUpgradeOnPrimary =
+ startParallelShell(funWithArgs(runAwaitableIsMasterBeforeFCVChange,
+ primaryTopologyVersionAfterDowngrade,
+ lastContinuousFCV,
+ true /* isPrimary */,
+ minWireVersionAfterDowngrade,
+ maxWireVersion),
+ primary.port);
+ let awaitIsMasterBeforeUpgradeOnSecondary =
+ startParallelShell(funWithArgs(runAwaitableIsMasterBeforeFCVChange,
+ secondaryTopologyVersionAfterDowngrade,
+ lastContinuousFCV,
+ false /* isPrimary */,
+ minWireVersionAfterDowngrade,
+ maxWireVersion),
+ secondary.port);
+ primaryFailPoint.wait();
+ secondaryFailPoint.wait();
+
+ // Each node has one isMaster request waiting on a topology change.
+ numAwaitingTopologyChangeOnPrimary =
+ primaryAdminDB.serverStatus().connections.awaitingTopologyChanges;
+ numAwaitingTopologyChangeOnSecondary =
+ secondaryAdminDB.serverStatus().connections.awaitingTopologyChanges;
+ assert.eq(1, numAwaitingTopologyChangeOnPrimary);
+ assert.eq(1, numAwaitingTopologyChangeOnSecondary);
+
+ // Upgrade the FCV to last-continuous.
+ assert.commandWorked(primaryAdminDB.runCommand(
+ {setFeatureCompatibilityVersion: lastContinuousFCV, fromConfigServer: true}));
+ awaitIsMasterBeforeUpgradeOnPrimary();
+ awaitIsMasterBeforeUpgradeOnSecondary();
+
+ // Ensure the featureCompatibilityVersion document update has been replicated.
+ rst.awaitReplication();
+ checkFCV(primaryAdminDB, lastContinuousFCV);
+ checkFCV(secondaryAdminDB, lastContinuousFCV);
+
+ // All isMaster requests should have been responded to after the FCV change.
+ numAwaitingTopologyChangeOnPrimary =
+ primaryAdminDB.serverStatus().connections.awaitingTopologyChanges;
+ numAwaitingTopologyChangeOnSecondary =
+ secondaryAdminDB.serverStatus().connections.awaitingTopologyChanges;
+ assert.eq(0, numAwaitingTopologyChangeOnPrimary);
+ assert.eq(0, numAwaitingTopologyChangeOnSecondary);
+
+ // Reset the FCV back to last-lts and the get the new isMaster parameters.
+ // We must upgrade to latestFCV first since downgrading from last-continuous to last-stable
+ // is forbidden.
+ assert.commandWorked(
+ primaryAdminDB.runCommand({setFeatureCompatibilityVersion: latestFCV}));
+ assert.commandWorked(
+ primaryAdminDB.runCommand({setFeatureCompatibilityVersion: lastLTSFCV}));
+ rst.awaitReplication();
+ checkFCV(primaryAdminDB, lastLTSFCV);
+ checkFCV(secondaryAdminDB, lastLTSFCV);
+
+ primaryResponseAfterDowngrade = isMasterAsInternalClient();
+ assert(primaryResponseAfterDowngrade.hasOwnProperty("topologyVersion"),
+ tojson(primaryResponseAfterDowngrade));
+ primaryTopologyVersionAfterDowngrade = primaryResponseAfterDowngrade.topologyVersion;
+ minWireVersionAfterDowngrade = primaryResponseAfterDowngrade.minWireVersion;
+
+ secondaryResponseAfterDowngrade =
+ assert.commandWorked(secondaryAdminDB.runCommand({isMaster: 1}));
+ assert(secondaryResponseAfterDowngrade.hasOwnProperty("topologyVersion"),
+ tojson(secondaryResponseAfterDowngrade));
+ secondaryTopologyVersionAfterDowngrade = secondaryResponseAfterDowngrade.topologyVersion;
+ }
// Reconfigure the failpoint to refresh the number of times the failpoint has been entered.
primaryFailPoint = configureFailPoint(primary, "waitForIsMasterResponse");
diff --git a/src/mongo/db/commands/feature_compatibility_version.cpp b/src/mongo/db/commands/feature_compatibility_version.cpp
index 4e4ddb99af7..ce27ffd1ae1 100644
--- a/src/mongo/db/commands/feature_compatibility_version.cpp
+++ b/src/mongo/db/commands/feature_compatibility_version.cpp
@@ -118,17 +118,64 @@ void runUpdateCommand(OperationContext* opCtx, const FeatureCompatibilityVersion
client.runCommand(nss.db().toString(), updateCmd.obj(), updateResult);
uassertStatusOK(getStatusFromWriteCommandReply(updateResult));
}
+
+/**
+ * Returns the expected value of the 'targetVersion' field in the FCV document based on the
+ * in-memory FCV value. Returns boost::none if current FCV is not currently upgrading or
+ * downgrading.
+ */
+boost::optional<FeatureCompatibilityParams::Version> getFcvDocTargetVersionField() {
+ if (!serverGlobalParams.featureCompatibility.isUpgradingOrDowngrading()) {
+ return boost::none;
+ }
+ const auto currentFcv = serverGlobalParams.featureCompatibility.getVersion();
+ if (currentFcv == FeatureCompatibilityParams::kUpgradingFromLastLTSToLatest ||
+ currentFcv == FeatureCompatibilityParams::kUpgradingFromLastContinuousToLatest) {
+ return FeatureCompatibilityParams::kLatest;
+ } else if (currentFcv == FeatureCompatibilityParams::kUpgradingFromLastLTSToLastContinuous ||
+ currentFcv == FeatureCompatibilityParams::kDowngradingFromLatestToLastContinuous) {
+ return FeatureCompatibilityParams::kLastContinuous;
+ } else {
+ invariant(currentFcv == FeatureCompatibilityParams::kDowngradingFromLatestToLastLTS);
+ return FeatureCompatibilityParams::kLastLTS;
+ }
+}
+
+/**
+ * Returns the expected value of the 'version' field in the FCV document based on the in-memory FCV
+ * value.
+ */
+FeatureCompatibilityParams::Version getFcvDocVersionField() {
+ if (!serverGlobalParams.featureCompatibility.isUpgradingOrDowngrading()) {
+ return serverGlobalParams.featureCompatibility.getVersion();
+ }
+ const auto currentFcv = serverGlobalParams.featureCompatibility.getVersion();
+ if (currentFcv == FeatureCompatibilityParams::kUpgradingFromLastContinuousToLatest ||
+ currentFcv == FeatureCompatibilityParams::kDowngradingFromLatestToLastContinuous) {
+ return FeatureCompatibilityParams::kLastContinuous;
+ } else {
+ invariant(currentFcv == FeatureCompatibilityParams::kUpgradingFromLastLTSToLastContinuous ||
+ currentFcv == FeatureCompatibilityParams::kUpgradingFromLastLTSToLatest ||
+ currentFcv == FeatureCompatibilityParams::kDowngradingFromLatestToLastLTS);
+ return FeatureCompatibilityParams::kLastLTS;
+ }
+}
} // namespace
void FeatureCompatibilityVersion::setTargetUpgradeFrom(
- OperationContext* opCtx, FeatureCompatibilityParams::Version fromVersion) {
+ OperationContext* opCtx,
+ FeatureCompatibilityParams::Version fromVersion,
+ FeatureCompatibilityParams::Version newVersion) {
+ invariant(fromVersion < newVersion);
+
FeatureCompatibilityParams::Version version;
// It is possible that we did not fully complete a previous upgrade. In that case, we
// must set the source version to be the fully downgraded version as the FCV document
// serializer does not recognize upgrading/downgrading states.
if (fromVersion == FeatureCompatibilityParams::kUpgradingFromLastContinuousToLatest) {
version = FeatureCompatibilityParams::kLastContinuous;
- } else if (fromVersion == FeatureCompatibilityParams::kUpgradingFromLastLTSToLatest) {
+ } else if (fromVersion == FeatureCompatibilityParams::kUpgradingFromLastLTSToLatest ||
+ fromVersion == FeatureCompatibilityParams::kUpgradingFromLastLTSToLastContinuous) {
version = FeatureCompatibilityParams::kLastLTS;
} else {
version = fromVersion;
@@ -136,9 +183,9 @@ void FeatureCompatibilityVersion::setTargetUpgradeFrom(
// Sets both 'version' and 'targetVersion' fields.
FeatureCompatibilityVersionDocument fcvDoc;
fcvDoc.setVersion(version);
- fcvDoc.setTargetVersion(FeatureCompatibilityParams::kLatest);
+ fcvDoc.setTargetVersion(newVersion);
runUpdateCommand(opCtx, fcvDoc);
-}
+} // namespace mongo
void FeatureCompatibilityVersion::setTargetDowngrade(OperationContext* opCtx,
FeatureCompatibilityParams::Version version) {
@@ -211,25 +258,24 @@ bool FeatureCompatibilityVersion::isCleanStartUp() {
void FeatureCompatibilityVersion::updateMinWireVersion() {
WireSpec& wireSpec = WireSpec::instance();
-
- if (serverGlobalParams.featureCompatibility.isGreaterThanOrEqualTo(
- FeatureCompatibilityParams::kLatest) ||
- serverGlobalParams.featureCompatibility.isUpgradingOrDowngrading()) {
- // FCV == kLatest or FCV is upgrading/downgrading.
+ const auto currentFcv = serverGlobalParams.featureCompatibility.getVersion();
+ if (currentFcv == FeatureCompatibilityParams::kLatest ||
+ (serverGlobalParams.featureCompatibility.isUpgradingOrDowngrading() &&
+ currentFcv != FeatureCompatibilityParams::kUpgradingFromLastLTSToLastContinuous)) {
+ // FCV == kLatest or FCV is upgrading/downgrading to or from kLatest.
WireSpec::Specification newSpec = *wireSpec.get();
newSpec.incomingInternalClient.minWireVersion = LATEST_WIRE_VERSION;
newSpec.outgoing.minWireVersion = LATEST_WIRE_VERSION;
wireSpec.reset(std::move(newSpec));
- } else if (serverGlobalParams.featureCompatibility.isGreaterThanOrEqualTo(
- FeatureCompatibilityParams::kLastContinuous)) {
- // FCV == kLastContinuous
+ } else if (currentFcv == FeatureCompatibilityParams::kUpgradingFromLastLTSToLastContinuous ||
+ currentFcv == FeatureCompatibilityParams::kLastContinuous) {
+ // FCV == kLastContinuous or upgrading to kLastContinuous.
WireSpec::Specification newSpec = *wireSpec.get();
newSpec.incomingInternalClient.minWireVersion = LAST_CONT_WIRE_VERSION;
newSpec.outgoing.minWireVersion = LAST_CONT_WIRE_VERSION;
wireSpec.reset(std::move(newSpec));
} else {
- // FCV == kLastLTS
- invariant(serverGlobalParams.featureCompatibility.isVersionInitialized());
+ invariant(currentFcv == FeatureCompatibilityParams::kLastLTS);
WireSpec::Specification newSpec = *wireSpec.get();
newSpec.incomingInternalClient.minWireVersion = LAST_LTS_WIRE_VERSION;
newSpec.outgoing.minWireVersion = LAST_LTS_WIRE_VERSION;
@@ -337,23 +383,16 @@ void FeatureCompatibilityVersionParameter::append(OperationContext* opCtx,
FeatureCompatibilityVersionDocument fcvDoc;
BSONObjBuilder featureCompatibilityVersionBuilder(b.subobjStart(name));
auto version = serverGlobalParams.featureCompatibility.getVersion();
- switch (version) {
- case ServerGlobalParams::FeatureCompatibility::kLatest:
- case ServerGlobalParams::FeatureCompatibility::kLastLTS:
- fcvDoc.setVersion(version);
- break;
- case ServerGlobalParams::FeatureCompatibility::kUpgradingFromLastLTSToLatest:
- fcvDoc.setVersion(ServerGlobalParams::FeatureCompatibility::kLastLTS);
- fcvDoc.setTargetVersion(ServerGlobalParams::FeatureCompatibility::kLatest);
- break;
- case ServerGlobalParams::FeatureCompatibility::kDowngradingFromLatestToLastLTS:
- fcvDoc.setVersion(ServerGlobalParams::FeatureCompatibility::kLastLTS);
- fcvDoc.setTargetVersion(ServerGlobalParams::FeatureCompatibility::kLastLTS);
- fcvDoc.setPreviousVersion(ServerGlobalParams::FeatureCompatibility::kLatest);
- break;
- case ServerGlobalParams::FeatureCompatibility::Version::kUnsetDefault44Behavior:
- // getVersion() does not return this value.
- MONGO_UNREACHABLE;
+ if (serverGlobalParams.featureCompatibility.isUpgradingOrDowngrading()) {
+ fcvDoc.setVersion(getFcvDocVersionField());
+ fcvDoc.setTargetVersion(getFcvDocTargetVersionField());
+ if (version == FeatureCompatibilityParams::kDowngradingFromLatestToLastContinuous ||
+ version == FeatureCompatibilityParams::kDowngradingFromLatestToLastLTS) {
+ // We only support downgrading from the latest FCV.
+ fcvDoc.setPreviousVersion(FeatureCompatibilityParams::kLatest);
+ }
+ } else {
+ fcvDoc.setVersion(version);
}
featureCompatibilityVersionBuilder.appendElements(fcvDoc.toBSON().removeField("_id"));
}
diff --git a/src/mongo/db/commands/feature_compatibility_version.h b/src/mongo/db/commands/feature_compatibility_version.h
index 3f458066614..57f39cd7d60 100644
--- a/src/mongo/db/commands/feature_compatibility_version.h
+++ b/src/mongo/db/commands/feature_compatibility_version.h
@@ -67,12 +67,13 @@ public:
static void fassertInitializedAfterStartup(OperationContext* opCtx);
/**
- * Records intent to perform a currentVersion -> kLatest upgrade by updating the on-disk
+ * Records intent to perform a fromVersion -> newVersion upgrade by updating the on-disk
* feature compatibility version document to have 'version'=currentVersion,
- * 'targetVersion'=kLatest. Should be called before schemas are modified.
+ * 'targetVersion'=newVersion. Should be called before schemas are modified.
*/
static void setTargetUpgradeFrom(OperationContext* opCtx,
- ServerGlobalParams::FeatureCompatibility::Version fromVersion);
+ ServerGlobalParams::FeatureCompatibility::Version fromVersion,
+ ServerGlobalParams::FeatureCompatibility::Version newVersion);
/**
* Records intent to perform a downgrade from the latest version by updating the on-disk feature
diff --git a/src/mongo/db/commands/feature_compatibility_version_parser.cpp b/src/mongo/db/commands/feature_compatibility_version_parser.cpp
index 650557ca644..76fa31fa030 100644
--- a/src/mongo/db/commands/feature_compatibility_version_parser.cpp
+++ b/src/mongo/db/commands/feature_compatibility_version_parser.cpp
@@ -39,22 +39,24 @@
namespace mongo {
+using FeatureCompatibilityParams = ServerGlobalParams::FeatureCompatibility;
+
constexpr StringData FeatureCompatibilityVersionParser::kParameterName;
constexpr StringData FeatureCompatibilityVersionParser::kLastLTS;
constexpr StringData FeatureCompatibilityVersionParser::kLastContinuous;
constexpr StringData FeatureCompatibilityVersionParser::kLatest;
-ServerGlobalParams::FeatureCompatibility::Version FeatureCompatibilityVersionParser::parseVersion(
+FeatureCompatibilityParams::Version FeatureCompatibilityVersionParser::parseVersion(
StringData versionString) {
if (versionString == kLastLTS) {
- return ServerGlobalParams::FeatureCompatibility::kLastLTS;
+ return FeatureCompatibilityParams::kLastLTS;
}
if (versionString == kLastContinuous) {
- return ServerGlobalParams::FeatureCompatibility::kLastContinuous;
+ return FeatureCompatibilityParams::kLastContinuous;
}
if (versionString == kLatest) {
- return ServerGlobalParams::FeatureCompatibility::kLatest;
+ return FeatureCompatibilityParams::kLatest;
}
uasserted(4926900,
str::stream() << "Invalid value for " << kParameterName << "document in "
@@ -66,14 +68,14 @@ ServerGlobalParams::FeatureCompatibility::Version FeatureCompatibilityVersionPar
}
StringData FeatureCompatibilityVersionParser::serializeVersion(
- ServerGlobalParams::FeatureCompatibility::Version version) {
- if (version == ServerGlobalParams::FeatureCompatibility::kLastLTS) {
+ FeatureCompatibilityParams::Version version) {
+ if (version == FeatureCompatibilityParams::kLastLTS) {
return kLastLTS;
}
- if (version == ServerGlobalParams::FeatureCompatibility::kLastContinuous) {
+ if (version == FeatureCompatibilityParams::kLastContinuous) {
return kLastContinuous;
}
- if (version == ServerGlobalParams::FeatureCompatibility::kLatest) {
+ if (version == FeatureCompatibilityParams::kLatest) {
return kLatest;
}
// It is a bug if we hit here.
@@ -82,16 +84,16 @@ StringData FeatureCompatibilityVersionParser::serializeVersion(
}
Status FeatureCompatibilityVersionParser::validatePreviousVersionField(
- ServerGlobalParams::FeatureCompatibility::Version version) {
- if (version == ServerGlobalParams::FeatureCompatibility::kLatest) {
+ FeatureCompatibilityParams::Version version) {
+ if (version == FeatureCompatibilityParams::kLatest) {
return Status::OK();
}
return Status(ErrorCodes::Error(4926901),
"when present, 'previousVersion' field must be the latest binary version");
}
-StatusWith<ServerGlobalParams::FeatureCompatibility::Version>
-FeatureCompatibilityVersionParser::parse(const BSONObj& featureCompatibilityVersionDoc) {
+StatusWith<FeatureCompatibilityParams::Version> FeatureCompatibilityVersionParser::parse(
+ const BSONObj& featureCompatibilityVersionDoc) {
try {
auto fcvDoc = FeatureCompatibilityVersionDocument::parse(
IDLParserErrorContext("FeatureCompatibilityVersionParser"),
@@ -101,8 +103,8 @@ FeatureCompatibilityVersionParser::parse(const BSONObj& featureCompatibilityVers
auto previousVersion = fcvDoc.getPreviousVersion();
// Downgrading FCV.
- if ((version == ServerGlobalParams::FeatureCompatibility::kLastLTS ||
- version == ServerGlobalParams::FeatureCompatibility::kLastContinuous) &&
+ if ((version == FeatureCompatibilityParams::kLastLTS ||
+ version == FeatureCompatibilityParams::kLastContinuous) &&
version == targetVersion) {
// Downgrading FCV must have a "previousVersion" field.
if (!previousVersion) {
@@ -117,12 +119,11 @@ FeatureCompatibilityVersionParser::parse(const BSONObj& featureCompatibilityVers
<< feature_compatibility_version_documentation::kCompatibilityLink
<< ".");
}
- if (version == ServerGlobalParams::FeatureCompatibility::kLastLTS) {
+ if (version == FeatureCompatibilityParams::kLastLTS) {
// Downgrading to last-lts.
- return ServerGlobalParams::FeatureCompatibility::kDowngradingFromLatestToLastLTS;
+ return FeatureCompatibilityParams::kDowngradingFromLatestToLastLTS;
} else {
- return ServerGlobalParams::FeatureCompatibility::
- kDowngradingFromLatestToLastContinuous;
+ return FeatureCompatibilityParams::kDowngradingFromLatestToLastContinuous;
}
}
@@ -142,9 +143,9 @@ FeatureCompatibilityVersionParser::parse(const BSONObj& featureCompatibilityVers
// Upgrading FCV.
if (targetVersion) {
- // For upgrading FCV, "targetVersion" must be kLatest and "version" must be
- // kLastContinuous or kLastLTS.
- if (targetVersion != ServerGlobalParams::FeatureCompatibility::kLatest ||
+ // For upgrading FCV, "targetVersion" must be kLatest or kLastContinuous and "version"
+ // must be kLastContinuous or kLastLTS.
+ if (targetVersion == FeatureCompatibilityParams::kLastLTS ||
version == ServerGlobalParams::FeatureCompatibility::kLatest) {
return Status(ErrorCodes::Error(4926904),
str::stream()
@@ -155,12 +156,20 @@ FeatureCompatibilityVersionParser::parse(const BSONObj& featureCompatibilityVers
<< ".");
}
- if (version == ServerGlobalParams::FeatureCompatibility::kLastLTS) {
- return ServerGlobalParams::FeatureCompatibility::kUpgradingFromLastLTSToLatest;
+ if (version == FeatureCompatibilityParams::kLastLTS) {
+ return targetVersion == FeatureCompatibilityParams::kLastContinuous
+ ? FeatureCompatibilityParams::kUpgradingFromLastLTSToLastContinuous
+ : FeatureCompatibilityParams::kUpgradingFromLastLTSToLatest;
} else {
- invariant(version == ServerGlobalParams::FeatureCompatibility::kLastContinuous);
- return ServerGlobalParams::FeatureCompatibility::
- kUpgradingFromLastContinuousToLatest;
+ uassert(5070601,
+ str::stream()
+ << "Invalid " << kParameterName << " document in "
+ << NamespaceString::kServerConfigurationNamespace.toString() << ": "
+ << featureCompatibilityVersionDoc << ". See "
+ << feature_compatibility_version_documentation::kCompatibilityLink
+ << ".",
+ version == ServerGlobalParams::FeatureCompatibility::kLastContinuous);
+ return FeatureCompatibilityParams::kUpgradingFromLastContinuousToLatest;
}
}
diff --git a/src/mongo/db/commands/feature_compatibility_version_parser.h b/src/mongo/db/commands/feature_compatibility_version_parser.h
index 6c9f9ab4364..d1e90016ab3 100644
--- a/src/mongo/db/commands/feature_compatibility_version_parser.h
+++ b/src/mongo/db/commands/feature_compatibility_version_parser.h
@@ -32,6 +32,7 @@
#include "mongo/db/server_options.h"
namespace mongo {
+using FeatureCompatibilityParams = ServerGlobalParams::FeatureCompatibility;
/**
* Helpers to parse featureCompatibilityVersion document BSON objects into
@@ -51,40 +52,56 @@ public:
static constexpr StringData kLastLTS = kVersion44;
static constexpr StringData kLastContinuous = kVersion44;
static constexpr StringData kLatest = kVersion47;
+ static constexpr StringData kUpgradingFromLastLTSToLatest = kVersionUpgradingFrom44To47;
+ static constexpr StringData kUpgradingFromLastContinuousToLatest = kVersionUpgradingFrom44To47;
+ // kVersionUpgradingFromLastLTSToLastContinuous should assigned kVersionUnset when kLastLTS and
+ // kLastContinuous are equal.
+ static constexpr StringData kVersionUpgradingFromLastLTSToLastContinuous = kVersionUnset;
+ static constexpr StringData kDowngradingFromLatestToLastLTS = kVersionDowngradingFrom47To44;
+ static constexpr StringData kDowngradingFromLatestToLastContinuous =
+ kVersionDowngradingFrom47To44;
- static ServerGlobalParams::FeatureCompatibility::Version parseVersion(StringData versionString);
+ static FeatureCompatibilityParams::Version parseVersion(StringData versionString);
- static StringData serializeVersion(ServerGlobalParams::FeatureCompatibility::Version version);
+ static StringData serializeVersion(FeatureCompatibilityParams::Version version);
- static Status validatePreviousVersionField(
- ServerGlobalParams::FeatureCompatibility::Version version);
+ static Status validatePreviousVersionField(FeatureCompatibilityParams::Version version);
/**
* Parses the featureCompatibilityVersion document from the server configuration collection
* (admin.system.version), and returns the state represented by the combination of the
* targetVersion and version.
*/
- static StatusWith<ServerGlobalParams::FeatureCompatibility::Version> parse(
+ static StatusWith<FeatureCompatibilityParams::Version> parse(
const BSONObj& featureCompatibilityVersionDoc);
/**
* Useful for message logging.
*/
- static StringData toString(ServerGlobalParams::FeatureCompatibility::Version version) {
- switch (version) {
- case ServerGlobalParams::FeatureCompatibility::Version::kUnsetDefault44Behavior:
- return kVersionUnset;
- case ServerGlobalParams::FeatureCompatibility::Version::kFullyDowngradedTo44:
- return kVersion44;
- case ServerGlobalParams::FeatureCompatibility::Version::kUpgradingFrom44To47:
- return kVersionUpgradingFrom44To47;
- case ServerGlobalParams::FeatureCompatibility::Version::kDowngradingFrom47To44:
- return kVersionDowngradingFrom47To44;
- case ServerGlobalParams::FeatureCompatibility::Version::kVersion47:
- return kVersion47;
- default:
- MONGO_UNREACHABLE;
+ static StringData toString(FeatureCompatibilityParams::Version version) {
+ if (version == FeatureCompatibilityParams::Version::kUnsetDefault44Behavior) {
+ return kVersionUnset;
+ } else if (version == FeatureCompatibilityParams::kLastLTS) {
+ return kLastLTS;
+ } else if (version == FeatureCompatibilityParams::kDowngradingFromLatestToLastLTS) {
+ return kDowngradingFromLatestToLastLTS;
+ } else if (version == FeatureCompatibilityParams::kUpgradingFromLastLTSToLastContinuous) {
+ // kUpgradingFromLastLTSToLastContinuous is only a valid FCV state when last-continuous
+ // and last-lts are not equal. Otherwise, it is set to kInvalid.
+ invariant(version != FeatureCompatibilityParams::Version::kInvalid);
+ return kVersionUpgradingFromLastLTSToLastContinuous;
+ } else if (version == FeatureCompatibilityParams::kUpgradingFromLastLTSToLatest) {
+ return kUpgradingFromLastLTSToLatest;
+ } else if (version == FeatureCompatibilityParams::kLastContinuous) {
+ return kLastContinuous;
+ } else if (version == FeatureCompatibilityParams::kDowngradingFromLatestToLastContinuous) {
+ return kDowngradingFromLatestToLastContinuous;
+ } else if (version == FeatureCompatibilityParams::kUpgradingFromLastContinuousToLatest) {
+ return kUpgradingFromLastContinuousToLatest;
+ } else if (version == FeatureCompatibilityParams::kLatest) {
+ return kLatest;
}
+ MONGO_UNREACHABLE;
}
};
diff --git a/src/mongo/db/commands/set_feature_compatibility_version.idl b/src/mongo/db/commands/set_feature_compatibility_version.idl
index b1c7df315d7..793fa587098 100644
--- a/src/mongo/db/commands/set_feature_compatibility_version.idl
+++ b/src/mongo/db/commands/set_feature_compatibility_version.idl
@@ -49,3 +49,8 @@ commands:
downgraded featureCompatibilityVersion."
type: safeBool
optional: true
+ fromConfigServer:
+ description: "A boolean that indicates whether the command is being requested by a
+ config server."
+ type: safeBool
+ optional: true
diff --git a/src/mongo/db/commands/set_feature_compatibility_version_command.cpp b/src/mongo/db/commands/set_feature_compatibility_version_command.cpp
index 48b3c04c5b7..0be6e6b0e5f 100644
--- a/src/mongo/db/commands/set_feature_compatibility_version_command.cpp
+++ b/src/mongo/db/commands/set_feature_compatibility_version_command.cpp
@@ -135,18 +135,44 @@ Status validateDowngradeRequest(FeatureCompatibilityParams::Version actualVersio
}
Status validateUpgradeRequest(FeatureCompatibilityParams::Version actualVersion,
- FeatureCompatibilityParams::Version requestedVersion) {
+ FeatureCompatibilityParams::Version requestedVersion,
+ boost::optional<bool> fromConfigServer) {
+ invariant(actualVersion < requestedVersion);
+
if (actualVersion == FeatureCompatibilityParams::kDowngradingFromLatestToLastLTS ||
actualVersion == FeatureCompatibilityParams::kDowngradingFromLatestToLastContinuous) {
return Status(ErrorCodes::IllegalOperation,
str::stream() << "cannot initiate featureCompatibilityVersion upgrade to "
- << FCVP::kLatest
+ << FCVP::toString(requestedVersion)
<< " while a previous featureCompatibilityVersion downgrade to "
<< FCVP::kLastLTS << " or " << FCVP::kLastContinuous
<< " has not completed. Finish downgrade then upgrade to "
<< FCVP::kLatest);
}
+ if ((actualVersion == FeatureCompatibilityParams::kUpgradingFromLastLTSToLatest &&
+ requestedVersion == FeatureCompatibilityParams::kLastContinuous) ||
+ (actualVersion == FeatureCompatibilityParams::kUpgradingFromLastLTSToLastContinuous &&
+ requestedVersion == FeatureCompatibilityParams::kLatest)) {
+ auto incompleteUpgradeVersionString =
+ actualVersion == FeatureCompatibilityParams::kUpgradingFromLastLTSToLatest
+ ? FCVP::kLatest
+ : FCVP::kLastContinuous;
+ return Status(ErrorCodes::Error(5070602),
+ str::stream()
+ << "cannot initiate featureCompatibilityVersion upgrade to "
+ << FCVP::toString(requestedVersion) << " while a previous upgrade to "
+ << incompleteUpgradeVersionString
+ << " has not yet completed. Finish upgrade then try again.");
+ }
+
+ if (requestedVersion == FeatureCompatibilityParams::kLastContinuous &&
+ !fromConfigServer.get_value_or(false)) {
+ return Status(ErrorCodes::Error(5070603),
+ str::stream() << "cannot initiate featureCompatibilityVersion upgrade from "
+ << FCVP::kLastLTS << " to " << FCVP::kLastContinuous << ".");
+ }
+
return Status::OK();
}
@@ -243,9 +269,9 @@ public:
const auto requestedVersionString = FCVP::serializeVersion(requestedVersion);
FeatureCompatibilityParams::Version actualVersion =
serverGlobalParams.featureCompatibility.getVersion();
-
if (request.getDowngradeOnDiskChanges() &&
- requestedVersion != FeatureCompatibilityParams::kLastContinuous) {
+ (requestedVersion != FeatureCompatibilityParams::kLastContinuous ||
+ actualVersion < requestedVersion)) {
std::stringstream downgradeOnDiskErrorSS;
downgradeOnDiskErrorSS
<< "cannot set featureCompatibilityVersion to " << requestedVersionString
@@ -255,18 +281,19 @@ public:
uasserted(ErrorCodes::IllegalOperation, downgradeOnDiskErrorSS.str());
}
- if (requestedVersion == FeatureCompatibilityParams::kLatest) {
- uassertStatusOK(validateUpgradeRequest(actualVersion, requestedVersion));
- if (actualVersion == FeatureCompatibilityParams::kLatest) {
- // Set the client's last opTime to the system last opTime so no-ops wait for
- // writeConcern.
- repl::ReplClientInfo::forClient(opCtx->getClient())
- .setLastOpToSystemLastOpTime(opCtx);
- return true;
- }
+ if (actualVersion == requestedVersion) {
+ // Set the client's last opTime to the system last opTime so no-ops wait for
+ // writeConcern.
+ repl::ReplClientInfo::forClient(opCtx->getClient()).setLastOpToSystemLastOpTime(opCtx);
+ return true;
+ }
- FeatureCompatibilityVersion::setTargetUpgradeFrom(opCtx, actualVersion);
+ if (actualVersion < requestedVersion) {
+ uassertStatusOK(validateUpgradeRequest(
+ actualVersion, requestedVersion, request.getFromConfigServer()));
+ FeatureCompatibilityVersion::setTargetUpgradeFrom(
+ opCtx, actualVersion, requestedVersion);
{
// Take the global lock in S mode to create a barrier for operations taking the
// global IX or X locks. This ensures that either
@@ -298,19 +325,9 @@ public:
hangWhileUpgrading.pauseWhileSet(opCtx);
FeatureCompatibilityVersion::unsetTargetUpgradeOrDowngrade(opCtx, requestedVersion);
- } else if (requestedVersion == FeatureCompatibilityParams::kLastLTS ||
- requestedVersion == FeatureCompatibilityParams::kLastContinuous) {
+ } else {
uassertStatusOK(validateDowngradeRequest(actualVersion, requestedVersion));
- if (actualVersion == FeatureCompatibilityParams::kLastLTS ||
- actualVersion == FeatureCompatibilityParams::kLastContinuous) {
- // Set the client's last opTime to the system last opTime so no-ops wait for
- // writeConcern.
- repl::ReplClientInfo::forClient(opCtx->getClient())
- .setLastOpToSystemLastOpTime(opCtx);
- return true;
- }
-
auto replCoord = repl::ReplicationCoordinator::get(opCtx);
const bool isReplSet =
replCoord->getReplicationMode() == repl::ReplicationCoordinator::modeReplSet;
diff --git a/src/mongo/db/fcv_op_observer.cpp b/src/mongo/db/fcv_op_observer.cpp
index bb70616821c..73d8b4b23ee 100644
--- a/src/mongo/db/fcv_op_observer.cpp
+++ b/src/mongo/db/fcv_op_observer.cpp
@@ -52,6 +52,11 @@ using FeatureCompatibilityParams = ServerGlobalParams::FeatureCompatibility;
void FcvOpObserver::_setVersion(OperationContext* opCtx,
ServerGlobalParams::FeatureCompatibility::Version newVersion) {
+ boost::optional<FeatureCompatibilityParams::Version> prevVersion;
+
+ if (serverGlobalParams.featureCompatibility.isVersionInitialized()) {
+ prevVersion = serverGlobalParams.featureCompatibility.getVersion();
+ }
serverGlobalParams.mutableFeatureCompatibility.setVersion(newVersion);
FeatureCompatibilityVersion::updateMinWireVersion();
@@ -92,9 +97,12 @@ void FcvOpObserver::_setVersion(OperationContext* opCtx,
// (Generic FCV reference): This FCV check should exist across LTS binary versions.
const auto shouldIncrementTopologyVersion =
newVersion == FeatureCompatibilityParams::kLastLTS ||
- newVersion == FeatureCompatibilityParams::kLastContinuous ||
+ (prevVersion &&
+ prevVersion.get() == FeatureCompatibilityParams::kDowngradingFromLatestToLastContinuous) ||
newVersion == FeatureCompatibilityParams::kUpgradingFromLastLTSToLatest ||
- newVersion == FeatureCompatibilityParams::kUpgradingFromLastContinuousToLatest;
+ newVersion == FeatureCompatibilityParams::kUpgradingFromLastContinuousToLatest ||
+ newVersion == FeatureCompatibilityParams::kUpgradingFromLastLTSToLastContinuous;
+
if (isReplSet && shouldIncrementTopologyVersion) {
replCoordinator->incrementTopologyVersion();
}
diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript
index 4f97f81b966..cf207a09d28 100644
--- a/src/mongo/db/s/SConscript
+++ b/src/mongo/db/s/SConscript
@@ -531,6 +531,7 @@ env.CppUnitTest(
],
LIBDEPS=[
'$BUILD_DIR/mongo/db/auth/authmocks',
+ '$BUILD_DIR/mongo/db/commands/set_feature_compatibility_version_idl',
'$BUILD_DIR/mongo/db/pipeline/document_source_mock',
'$BUILD_DIR/mongo/db/read_write_concern_defaults_mock',
'$BUILD_DIR/mongo/db/repl/replication_info',
diff --git a/src/mongo/db/s/config/sharding_catalog_manager_add_shard_test.cpp b/src/mongo/db/s/config/sharding_catalog_manager_add_shard_test.cpp
index 08c2dced011..777b23622ee 100644
--- a/src/mongo/db/s/config/sharding_catalog_manager_add_shard_test.cpp
+++ b/src/mongo/db/s/config/sharding_catalog_manager_add_shard_test.cpp
@@ -37,6 +37,7 @@
#include "mongo/client/remote_command_targeter_factory_mock.h"
#include "mongo/client/remote_command_targeter_mock.h"
#include "mongo/db/commands.h"
+#include "mongo/db/commands/set_feature_compatibility_version_gen.h"
#include "mongo/db/ops/write_ops.h"
#include "mongo/db/repl/replication_coordinator_mock.h"
#include "mongo/db/s/add_shard_cmd_gen.h"
@@ -134,13 +135,16 @@ protected:
void expectSetFeatureCompatibilityVersion(const HostAndPort& target,
StatusWith<BSONObj> response,
BSONObj writeConcern) {
+ // (Generic FCV reference): This FCV reference should exist across LTS binary versions.
+ SetFeatureCompatibilityVersion fcvCmd(ServerGlobalParams::FeatureCompatibility::kLatest);
+ fcvCmd.setFromConfigServer(true);
+ fcvCmd.setDbName(NamespaceString::kAdminDb);
+ const auto setFcvObj = fcvCmd.toBSON(BSON("writeConcern" << writeConcern));
+
onCommandForAddShard([&, target, response](const RemoteCommandRequest& request) {
ASSERT_EQ(request.target, target);
ASSERT_EQ(request.dbname, "admin");
- ASSERT_BSONOBJ_EQ(request.cmdObj,
- BSON("setFeatureCompatibilityVersion"
- << "4.7"
- << "writeConcern" << writeConcern));
+ ASSERT_BSONOBJ_EQ(request.cmdObj, setFcvObj);
return response;
});
diff --git a/src/mongo/db/s/config/sharding_catalog_manager_shard_operations.cpp b/src/mongo/db/s/config/sharding_catalog_manager_shard_operations.cpp
index f03ee603838..d10ba0288d3 100644
--- a/src/mongo/db/s/config/sharding_catalog_manager_shard_operations.cpp
+++ b/src/mongo/db/s/config/sharding_catalog_manager_shard_operations.cpp
@@ -84,6 +84,7 @@ using CallbackHandle = executor::TaskExecutor::CallbackHandle;
using CallbackArgs = executor::TaskExecutor::CallbackArgs;
using RemoteCommandCallbackArgs = executor::TaskExecutor::RemoteCommandCallbackArgs;
using RemoteCommandCallbackFn = executor::TaskExecutor::RemoteCommandCallbackFn;
+using FeatureCompatibilityParams = ServerGlobalParams::FeatureCompatibility;
const ReadPreferenceSetting kConfigReadSelector(ReadPreference::Nearest, TagSet{});
@@ -338,23 +339,24 @@ StatusWith<ShardType> ShardingCatalogManager::_validateHostAsShard(
<< "field when attempting to add "
<< connectionString.toString() << " as a shard");
}
+ const auto currentFcv = serverGlobalParams.featureCompatibility.getVersion();
// (Generic FCV reference): These FCV checks should exist across LTS binary versions.
- if (serverGlobalParams.featureCompatibility.isGreaterThanOrEqualTo(
- ServerGlobalParams::FeatureCompatibility::kLatest) ||
- serverGlobalParams.featureCompatibility.isUpgradingOrDowngrading()) {
- // If the cluster's FCV is kLatest, or upgrading to / downgrading from, the node being added
- // must be a version kLatest binary.
+ if (currentFcv == FeatureCompatibilityParams::kLatest ||
+ currentFcv == FeatureCompatibilityParams::kDowngradingFromLatestToLastContinuous ||
+ currentFcv == FeatureCompatibilityParams::kDowngradingFromLatestToLastLTS ||
+ currentFcv == FeatureCompatibilityParams::kUpgradingFromLastContinuousToLatest ||
+ currentFcv == FeatureCompatibilityParams::kUpgradingFromLastLTSToLatest) {
+ // If the cluster's FCV is kLatest, or upgrading to / downgrading from kLatest, the node
+ // being added must be a version kLatest binary.
invariant(maxWireVersion == WireVersion::LATEST_WIRE_VERSION);
- } else if (serverGlobalParams.featureCompatibility.isGreaterThanOrEqualTo(
- ServerGlobalParams::FeatureCompatibility::kLastContinuous)) {
- // If we are using the kLastContinuous FCV, the node being added must be of the
- // last-continuous or latest binary version.
+ } else if (currentFcv == FeatureCompatibilityParams::kLastContinuous ||
+ currentFcv == FeatureCompatibilityParams::kUpgradingFromLastLTSToLastContinuous) {
+ // If we are using the kLastContinuous or upgrading to kLastContinuous FCV, the node being
+ // added must be of the last-continuous or latest binary version.
invariant(maxWireVersion >= WireVersion::LAST_CONT_WIRE_VERSION);
} else {
- // If we are using the kLastLTS FCV, the node being added must be of the last-lts or latest
- // binary version.
- invariant(maxWireVersion == WireVersion::LAST_LTS_WIRE_VERSION ||
- maxWireVersion == WireVersion::LATEST_WIRE_VERSION);
+ // (Generic FCV reference): These FCV checks should exist across LTS binary versions.
+ invariant(currentFcv == FeatureCompatibilityParams::kLastLTS);
}
// Check whether there is a master. If there isn't, the replica set may not have been
@@ -656,32 +658,49 @@ StatusWith<std::string> ShardingCatalogManager::addShard(
invariant(!opCtx->lockState()->isLocked());
Lock::SharedLock lk(opCtx->lockState(), FeatureCompatibilityVersion::fcvLock);
- BSONObjBuilder setFCVBuilder;
- // (Generic FCV reference): These FCV checks should exist across LTS binary versions.
- switch (serverGlobalParams.featureCompatibility.getVersion()) {
- case ServerGlobalParams::FeatureCompatibility::kLatest:
- case ServerGlobalParams::FeatureCompatibility::Version::kUpgradingFrom44To47: {
- SetFeatureCompatibilityVersion setLatestCmd(
- ServerGlobalParams::FeatureCompatibility::kLatest);
- // The serialize function generated by IDL requires the DB name to be set.
- setLatestCmd.setDbName(NamespaceString::kAdminDb);
- setLatestCmd.serialize({}, &setFCVBuilder);
- break;
- }
- default:
+ // Get the target version that the newly added shard should be set to.
+ const FeatureCompatibilityParams::Version setVersion = [] {
+ const auto currentFcv = serverGlobalParams.featureCompatibility.getVersion();
+ // (Generic FCV reference): These FCV checks should exist across LTS binary versions.
+ if (currentFcv == FeatureCompatibilityParams::kLatest ||
+ currentFcv == FeatureCompatibilityParams::kUpgradingFromLastContinuousToLatest ||
+ currentFcv == FeatureCompatibilityParams::kUpgradingFromLastLTSToLatest) {
+ return FeatureCompatibilityParams::kLatest;
+ } else if (currentFcv == FeatureCompatibilityParams::kLastContinuous ||
+ currentFcv ==
+ FeatureCompatibilityParams::kDowngradingFromLatestToLastContinuous ||
+ currentFcv ==
+ FeatureCompatibilityParams::kUpgradingFromLastLTSToLastContinuous) {
+ // (Generic FCV reference): These FCV checks should exist across LTS binary
+ // versions.
+ return FeatureCompatibilityParams::kLastContinuous;
+ } else {
// (Generic FCV reference): This FCV reference should exist across LTS binary
// versions.
- SetFeatureCompatibilityVersion setLastLTSCmd(
- ServerGlobalParams::FeatureCompatibility::kLastLTS);
- // The serialize function generated by IDL requires the DB name to be set.
- setLastLTSCmd.setDbName(NamespaceString::kAdminDb);
- setLastLTSCmd.serialize({}, &setFCVBuilder);
- break;
+ invariant(currentFcv ==
+ FeatureCompatibilityParams::kDowngradingFromLatestToLastLTS ||
+ currentFcv == FeatureCompatibilityParams::kLastLTS);
+ return FeatureCompatibilityParams::kLastLTS;
+ }
+ }();
+
+ SetFeatureCompatibilityVersion setFcvCmd(setVersion);
+ setFcvCmd.setDbName(NamespaceString::kAdminDb);
+ // TODO (SERVER-50954): Remove this FCV check once 4.4 is no longer the last LTS
+ // version.
+ if (serverGlobalParams.featureCompatibility.isGreaterThanOrEqualTo(
+ FeatureCompatibilityParams::Version::kVersion47)) {
+ // fromConfigServer is a new parameter added to 4.8 with intention to be backported
+ // to 4.7.
+ setFcvCmd.setFromConfigServer(true);
}
- setFCVBuilder.append(WriteConcernOptions::kWriteConcernField,
- opCtx->getWriteConcern().toBSON());
- auto versionResponse = _runCommandForAddShard(
- opCtx, targeter.get(), NamespaceString::kAdminDb, setFCVBuilder.obj());
+
+ auto versionResponse =
+ _runCommandForAddShard(opCtx,
+ targeter.get(),
+ NamespaceString::kAdminDb,
+ setFcvCmd.toBSON(BSON(WriteConcernOptions::kWriteConcernField
+ << opCtx->getWriteConcern().toBSON())));
if (!versionResponse.isOK()) {
return versionResponse.getStatus();
}
diff --git a/src/mongo/db/server_options.h b/src/mongo/db/server_options.h
index dcdc09967bb..ae3a87ec5e1 100644
--- a/src/mongo/db/server_options.h
+++ b/src/mongo/db/server_options.h
@@ -193,11 +193,12 @@ struct ServerGlobalParams {
// The order of these enums matter, higher upgrades having higher values, so that
// features can be active or inactive if the version is higher than some minimum or
// lower than some maximum, respectively.
- kUnsetDefault44Behavior = 0,
- kFullyDowngradedTo44 = 1,
- kDowngradingFrom47To44 = 2,
- kUpgradingFrom44To47 = 3,
- kVersion47 = 4,
+ kInvalid = 0,
+ kUnsetDefault44Behavior = 1,
+ kFullyDowngradedTo44 = 2,
+ kDowngradingFrom47To44 = 3,
+ kUpgradingFrom44To47 = 4,
+ kVersion47 = 5,
};
// These constants should only be used for generic FCV references. Generic references are
@@ -215,6 +216,10 @@ struct ServerGlobalParams {
static constexpr Version kDowngradingFromLatestToLastLTS = Version::kDowngradingFrom47To44;
static constexpr Version kDowngradingFromLatestToLastContinuous =
Version::kDowngradingFrom47To44;
+ // kUpgradingFromLastLTSToLastContinuous is only ever set to a valid FCV when
+ // kLastLTS and kLastContinuous are not equal. Otherwise, this value should be set to
+ // kInvalid.
+ static constexpr Version kUpgradingFromLastLTSToLastContinuous = Version::kInvalid;
/**
* On startup, the featureCompatibilityVersion may not have been explicitly set yet. This