summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/libs/feature_flag_util.js18
-rw-r--r--jstests/multiVersion/genericSetFCVUsage/set_feature_compatibility_version.js11
-rw-r--r--jstests/multiVersion/genericSetFCVUsage/test_replica_set_startup_in_downgrading_state.js9
-rw-r--r--jstests/multiVersion/genericSetFCVUsage/test_sharding_startup_in_downgrading_state.js9
-rw-r--r--jstests/replsets/rollback_set_fcv.js14
-rw-r--r--src/mongo/db/commands/SConscript1
-rw-r--r--src/mongo/db/commands/feature_compatibility_version.cpp37
-rw-r--r--src/mongo/db/repl/repl_server_parameters.idl3
8 files changed, 74 insertions, 28 deletions
diff --git a/jstests/libs/feature_flag_util.js b/jstests/libs/feature_flag_util.js
index 92fb58a5288..4ebb5ef23be 100644
--- a/jstests/libs/feature_flag_util.js
+++ b/jstests/libs/feature_flag_util.js
@@ -7,9 +7,13 @@ load("jstests/libs/fixture_helpers.js");
*/
var FeatureFlagUtil = class {
/**
- * Returns true if feature flag is enabled, false otherwise.
+ * If 'ignoreFCV' is true, return whether or not the given feature flag is enabled,
+ * regardless of the current FCV version (this is used when a feature flag needs to be enabled
+ * in downgraded FCV versions).
+ * If 'ignoreFCV' is false or null, we only return true if the flag is enabled and this FCV
+ * version is greater or equal to the required version for the flag.
*/
- static isEnabled(db, featureFlag, user) {
+ static isEnabled(db, featureFlag, user, ignoreFCV) {
// In order to get an accurate answer for whether a feature flag is enabled, we need to ask
// a mongod. If db represents a connection to mongos, or some other configuration, we need
// to obtain the correct connection to a mongod.
@@ -46,9 +50,11 @@ var FeatureFlagUtil = class {
return false;
}
- return flagDoc.hasOwnProperty(fullFlagName) && flagDoc[fullFlagName].value &&
- (!fcvDoc.hasOwnProperty("featureCompatibilityVersion") ||
- MongoRunner.compareBinVersions(fcvDoc.featureCompatibilityVersion.version,
- flagDoc[fullFlagName].version) >= 0);
+ const flagIsEnabled = flagDoc.hasOwnProperty(fullFlagName) && flagDoc[fullFlagName].value;
+ const flagVersionIsValid = !fcvDoc.hasOwnProperty("featureCompatibilityVersion") ||
+ MongoRunner.compareBinVersions(fcvDoc.featureCompatibilityVersion.version,
+ flagDoc[fullFlagName].version) >= 0;
+
+ return flagIsEnabled && (ignoreFCV || flagVersionIsValid);
}
};
diff --git a/jstests/multiVersion/genericSetFCVUsage/set_feature_compatibility_version.js b/jstests/multiVersion/genericSetFCVUsage/set_feature_compatibility_version.js
index ebd7ce28a8b..08c2dd2e6ce 100644
--- a/jstests/multiVersion/genericSetFCVUsage/set_feature_compatibility_version.js
+++ b/jstests/multiVersion/genericSetFCVUsage/set_feature_compatibility_version.js
@@ -15,6 +15,7 @@ TestData.skipCheckDBHashes = true;
load("jstests/libs/index_catalog_helpers.js");
load("jstests/libs/write_concern_util.js");
load("jstests/replsets/rslib.js");
+load("jstests/libs/feature_flag_util.js");
let dbpath = MongoRunner.dataPath + "feature_compatibility_version";
resetDbpath(dbpath);
@@ -337,6 +338,16 @@ function runReplicaSetTest(downgradeVersion) {
assert.commandFailedWithCode(res, ErrorCodes.WriteConcernFailed);
restartServerReplication(secondary);
+ // If downgrading->upgrading feature is not enabled,
+ // upgrading the FCV should fail if a previous downgrade has not yet completed.
+ if (!FeatureFlagUtil.isEnabled(primaryAdminDB,
+ "DowngradingToUpgrading",
+ null /* user not specified */,
+ true /* ignores FCV */)) {
+ assert.commandFailedWithCode(
+ primary.adminCommand({setFeatureCompatibilityVersion: latestFCV}), 5147403);
+ }
+
if (lastContinuousFCV !== lastLTSFCV) {
// We will fail if we have not yet completed a downgrade and attempt to downgrade to a
// different target version.
diff --git a/jstests/multiVersion/genericSetFCVUsage/test_replica_set_startup_in_downgrading_state.js b/jstests/multiVersion/genericSetFCVUsage/test_replica_set_startup_in_downgrading_state.js
index 49baaf22540..16c85aa1cc2 100644
--- a/jstests/multiVersion/genericSetFCVUsage/test_replica_set_startup_in_downgrading_state.js
+++ b/jstests/multiVersion/genericSetFCVUsage/test_replica_set_startup_in_downgrading_state.js
@@ -1,14 +1,17 @@
/*
* Tests startup with a node in downgrading state.
* Starts a replica set with 2 nodes.
+ *
+ * @tags: [featureFlagDowngradingToUpgrading]
*/
-load('jstests/multiVersion/libs/verify_versions.js');
-load('jstests/libs/fail_point_util.js');
-
(function() {
"use strict";
+load('jstests/multiVersion/libs/verify_versions.js');
+load('jstests/libs/fail_point_util.js');
+load("jstests/libs/feature_flag_util.js");
+
function runReplicaSet() {
let fcvDoc;
diff --git a/jstests/multiVersion/genericSetFCVUsage/test_sharding_startup_in_downgrading_state.js b/jstests/multiVersion/genericSetFCVUsage/test_sharding_startup_in_downgrading_state.js
index 8d48e87b102..02d0590d956 100644
--- a/jstests/multiVersion/genericSetFCVUsage/test_sharding_startup_in_downgrading_state.js
+++ b/jstests/multiVersion/genericSetFCVUsage/test_sharding_startup_in_downgrading_state.js
@@ -1,14 +1,17 @@
/*
* Tests startup with a node in downgrading state.
* Starts a sharded cluster with 2 shards, each with 2 nodes.
+ *
+ * @tags: [featureFlagDowngradingToUpgrading]
*/
-load('jstests/multiVersion/libs/verify_versions.js');
-load('jstests/libs/fail_point_util.js');
-
(function() {
"use strict";
+load('jstests/multiVersion/libs/verify_versions.js');
+load('jstests/libs/fail_point_util.js');
+load("jstests/libs/feature_flag_util.js");
+
function runSharding() {
let fcvDoc;
let shard0PrimaryAdminDB;
diff --git a/jstests/replsets/rollback_set_fcv.js b/jstests/replsets/rollback_set_fcv.js
index 4f15a81f3b8..4a82ed33857 100644
--- a/jstests/replsets/rollback_set_fcv.js
+++ b/jstests/replsets/rollback_set_fcv.js
@@ -16,6 +16,7 @@ load("jstests/replsets/libs/rollback_test.js");
load('jstests/libs/parallel_shell_helpers.js');
load("jstests/libs/fail_point_util.js");
load("jstests/replsets/rslib.js");
+load("jstests/libs/feature_flag_util.js");
function setFCV(fcv) {
assert.commandFailedWithCode(db.adminCommand({setFeatureCompatibilityVersion: fcv}),
@@ -119,11 +120,16 @@ function rollbackFCVFromDowngradedOrUpgraded(fromFCV, toFCV, failPoint) {
checkFCV(secondaryAdminDB, lastLTSFCV, fromFCV);
let newPrimary = rollbackTest.getPrimary();
+ const newPrimaryAdminDB = newPrimary.getDB('admin');
// As a rule, we forbid downgrading a node while a node is still in the upgrading state and
- // vice versa (except for the added path kDowngradingFromLatestToLastLTS ->
- // kUpgradingFromLastLTSToLatest -> kLatest). Ensure that the in-memory and on-disk FCV are
- // consistent by checking that this rule is upheld after rollback.
- if (fromFCV === lastLTSFCV && toFCV === latestFCV) {
+ // vice versa (except for the added path from downgrading to upgrading).
+ // Ensure that the in-memory and on-disk FCV are consistent by checking that this rule is
+ // upheld after rollback.
+ if (fromFCV === lastLTSFCV && toFCV === latestFCV &&
+ FeatureFlagUtil.isEnabled(newPrimaryAdminDB,
+ "DowngradingToUpgrading",
+ null /* user not specified */,
+ true /* ignores FCV */)) {
assert.commandWorked(newPrimary.adminCommand({setFeatureCompatibilityVersion: toFCV}));
} else {
assert.commandFailedWithCode(
diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript
index a97e065d719..d058ade3878 100644
--- a/src/mongo/db/commands/SConscript
+++ b/src/mongo/db/commands/SConscript
@@ -249,6 +249,7 @@ env.Library(
'$BUILD_DIR/mongo/db/commands',
'$BUILD_DIR/mongo/db/dbdirectclient',
'$BUILD_DIR/mongo/db/repl/repl_coordinator_interface',
+ '$BUILD_DIR/mongo/db/repl/repl_server_parameters',
'$BUILD_DIR/mongo/db/repl/repl_settings',
'$BUILD_DIR/mongo/idl/server_parameter',
],
diff --git a/src/mongo/db/commands/feature_compatibility_version.cpp b/src/mongo/db/commands/feature_compatibility_version.cpp
index 8ad7cae43f6..3b8e8a4654d 100644
--- a/src/mongo/db/commands/feature_compatibility_version.cpp
+++ b/src/mongo/db/commands/feature_compatibility_version.cpp
@@ -43,6 +43,7 @@
#include "mongo/db/namespace_string.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/repl/optime.h"
+#include "mongo/db/repl/repl_server_parameters_gen.h"
#include "mongo/db/repl/replication_coordinator.h"
#include "mongo/db/repl/replication_process.h"
#include "mongo/db/repl/storage_interface.h"
@@ -74,7 +75,8 @@ namespace {
* Utility class for recording permitted transitions between feature compatibility versions and
* their on-disk representation as FeatureCompatibilityVersionDocument objects.
*/
-const class FCVTransitions {
+// TODO SERVER-65269: Add back 'const' qualifier to FCVTransitions class declaration
+class FCVTransitions {
public:
FCVTransitions() {
auto makeFCVDoc = [](
@@ -109,10 +111,6 @@ public:
// lastLTS then the second loop iteration just overwrites the first.
_transitions[{from, to, isFromConfigServer}] = upgrading;
_transitions[{upgrading, to, isFromConfigServer}] = to;
- // allow downgrading->upgrading->latest path
- _transitions[{GenericFCV::kDowngradingFromLatestToLastLTS,
- GenericFCV::kLatest,
- isFromConfigServer}] = GenericFCV::kUpgradingFromLastLTSToLatest;
}
_fcvDocuments[upgrading] = makeFCVDoc(from /* effective */, to /* target */);
}
@@ -146,6 +144,20 @@ public:
}
/**
+ * If feature flag gDowngradingToUpgrading is enabled,
+ * we add the new downgrading->upgrading->latest path.
+ */
+ void featureFlaggedAddNewTransitionState() {
+ if (repl::feature_flags::gDowngradingToUpgrading.isEnabledAndIgnoreFCV()) {
+ for (auto isFromConfigServer : std::vector{false, true}) {
+ _transitions[{GenericFCV::kDowngradingFromLatestToLastLTS,
+ GenericFCV::kLatest,
+ isFromConfigServer}] = GenericFCV::kUpgradingFromLastLTSToLatest;
+ }
+ }
+ }
+
+ /**
* True if a server in multiversion::FeatureCompatibilityVersion "fromVersion" can
* transition to "newVersion". Different rules apply if the request is from a config server.
*/
@@ -327,14 +339,13 @@ void FeatureCompatibilityVersion::updateFeatureCompatibilityVersionDocument(
// We may have just stepped down, in which case we should not proceed.
opCtx->checkForInterrupt();
- // Only transition to fully upgraded or downgraded states when we
- // have completed all required upgrade/downgrade behavior.
- // If kDowngradingFromLatestToLastLTS->kLatest, we want to get the transitional version
- // i.e. kUpgradingFromLastLTSToLatest
+ // Only transition to fully upgraded or downgraded states when we have completed all required
+ // upgrade/downgrade behavior, unless it is the newly added downgrading to upgrading path.
auto transitioningVersion = setTargetVersion &&
serverGlobalParams.featureCompatibility.isUpgradingOrDowngrading(fromVersion) &&
- !(fromVersion == GenericFCV::kDowngradingFromLatestToLastLTS &&
- newVersion == GenericFCV::kLatest)
+ !(repl::feature_flags::gDowngradingToUpgrading.isEnabledAndIgnoreFCV() &&
+ (fromVersion == GenericFCV::kDowngradingFromLatestToLastLTS &&
+ newVersion == GenericFCV::kLatest))
? fromVersion
: fcvTransitions.getTransitionalVersion(fromVersion, newVersion, isFromConfigServer);
FeatureCompatibilityVersionDocument fcvDoc =
@@ -487,6 +498,10 @@ void FeatureCompatibilityVersion::fassertInitializedAfterStartup(OperationContex
auto fcvDocument = findFeatureCompatibilityVersionDocument(opCtx);
+ // TODO SERVER-65269: Move downgrading->upgrading transition back to FCVTransitions constructor.
+ // Adding the new fcv downgrading -> upgrading path
+ fcvTransitions.featureFlaggedAddNewTransitionState();
+
auto const storageEngine = opCtx->getServiceContext()->getStorageEngine();
auto dbNames = storageEngine->listDatabases();
bool nonLocalDatabases = std::any_of(dbNames.begin(), dbNames.end(), [](auto dbName) {
diff --git a/src/mongo/db/repl/repl_server_parameters.idl b/src/mongo/db/repl/repl_server_parameters.idl
index d823889e66e..16ae22f7a2a 100644
--- a/src/mongo/db/repl/repl_server_parameters.idl
+++ b/src/mongo/db/repl/repl_server_parameters.idl
@@ -677,4 +677,5 @@ feature_flags:
description: When enabled,
allow kDowngradingFromLatestToLastLTS -> kUpgrading -> kUpgraded path.
cpp_varname: feature_flags::gDowngradingToUpgrading
- default: false \ No newline at end of file
+ default: false
+ \ No newline at end of file