diff options
author | Jason Chan <jason.chan@mongodb.com> | 2020-09-09 19:50:15 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-09-24 16:30:58 +0000 |
commit | 3a6bde797e31d9e06e982aa20b89a856cfeef95c (patch) | |
tree | 9a82a3bae80a2c66ffd09deac4d0e1c6c924cbab /src/mongo | |
parent | 1bf955ec900a5e78ba9437f90a76dab906dbc2f2 (diff) | |
download | mongo-3a6bde797e31d9e06e982aa20b89a856cfeef95c.tar.gz |
SERVER-50706 Add fromConfigServer parameter to allow transitioning a shard server from lastLTS FCV to lastContinuousFCV
Diffstat (limited to 'src/mongo')
11 files changed, 276 insertions, 151 deletions
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 8b7b0e82f39..31afa9701a4 100644 --- a/src/mongo/db/s/SConscript +++ b/src/mongo/db/s/SConscript @@ -535,6 +535,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 |