diff options
author | Matthew Russotto <matthew.russotto@mongodb.com> | 2021-05-26 18:21:45 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-05-27 15:12:27 +0000 |
commit | 11b41d28993c539b2b383d44f7969e6dd8e3f968 (patch) | |
tree | e292c3613ef951c2ab2d1b38ca637dfeb84fa87b /src/mongo/db/commands | |
parent | 105b03e1250bc3c412566be6262a155d764d8c32 (diff) | |
download | mongo-11b41d28993c539b2b383d44f7969e6dd8e3f968.tar.gz |
SERVER-53643 Wait for FCV to be majority committed before reporting it.
Diffstat (limited to 'src/mongo/db/commands')
-rw-r--r-- | src/mongo/db/commands/feature_compatibility_version.cpp | 42 | ||||
-rw-r--r-- | src/mongo/db/commands/feature_compatibility_version.h | 13 |
2 files changed, 55 insertions, 0 deletions
diff --git a/src/mongo/db/commands/feature_compatibility_version.cpp b/src/mongo/db/commands/feature_compatibility_version.cpp index ca316c343b3..1aa87581e8f 100644 --- a/src/mongo/db/commands/feature_compatibility_version.cpp +++ b/src/mongo/db/commands/feature_compatibility_version.cpp @@ -195,6 +195,10 @@ private: * setFCV takes this lock in exclusive mode when changing the FCV value. */ Lock::ResourceMutex fcvLock("featureCompatibilityVersionLock"); +// lastFCVUpdateTimestamp contains the latest oplog entry timestamp which updated the FCV. +// It is reset on rollback. +Timestamp lastFCVUpdateTimestamp; +SimpleMutex lastFCVUpdateTimestampMutex; bool isWriteableStorageEngine() { return !storageGlobalParams.readOnly && (storageGlobalParams.engine != "devnull"); @@ -502,6 +506,19 @@ Lock::ExclusiveLock FeatureCompatibilityVersion::enterFCVChangeRegion(OperationC return Lock::ExclusiveLock(opCtx->lockState(), fcvLock); } +void FeatureCompatibilityVersion::advanceLastFCVUpdateTimestamp(Timestamp fcvUpdateTimestamp) { + stdx::lock_guard lk(lastFCVUpdateTimestampMutex); + if (fcvUpdateTimestamp > lastFCVUpdateTimestamp) { + lastFCVUpdateTimestamp = fcvUpdateTimestamp; + } +} + +void FeatureCompatibilityVersion::clearLastFCVUpdateTimestamp() { + stdx::lock_guard lk(lastFCVUpdateTimestampMutex); + lastFCVUpdateTimestamp = Timestamp(); +} + + /** * Read-only server parameter for featureCompatibilityVersion. */ @@ -522,6 +539,31 @@ void FeatureCompatibilityVersionParameter::append(OperationContext* opCtx, auto version = serverGlobalParams.featureCompatibility.getVersion(); FeatureCompatibilityVersionDocument fcvDoc = fcvTransitions.getFCVDocument(version); featureCompatibilityVersionBuilder.appendElements(fcvDoc.toBSON().removeField("_id")); + if (!fcvDoc.getTargetVersion()) { + // If the FCV has been recently set to the fully upgraded FCV but is not part of the + // majority snapshot, then if we do a binary upgrade, we may see the old FCV at startup. It + // is not safe to do oplog application on the new binary at that point. So we make sure + // that when we report the FCV, it is in the majority snapshot. + // (The same consideration applies at downgrade, where if a recently-set fully downgraded + // FCV is not part of the majority snapshot, the downgraded binary will see the upgrade FCV + // and fail.) + const auto replCoordinator = repl::ReplicationCoordinator::get(opCtx); + const bool isReplSet = replCoordinator && + replCoordinator->getReplicationMode() == repl::ReplicationCoordinator::modeReplSet; + auto neededMajorityTimestamp = [] { + stdx::lock_guard lk(lastFCVUpdateTimestampMutex); + return lastFCVUpdateTimestamp; + }(); + if (isReplSet && !neededMajorityTimestamp.isNull()) { + auto status = replCoordinator->awaitTimestampCommitted(opCtx, neededMajorityTimestamp); + // If majority reads are not supported, we will take a full snapshot on clean shutdown + // and the new FCV will be included, so upgrade is possible. + if (status.code() != ErrorCodes::CommandNotSupported) + uassertStatusOK( + status.withContext("Most recent 'featureCompatibilityVersion' was not in the " + "majority snapshot on this node")); + } + } } Status FeatureCompatibilityVersionParameter::setFromString(const std::string&) { diff --git a/src/mongo/db/commands/feature_compatibility_version.h b/src/mongo/db/commands/feature_compatibility_version.h index dc7a2ca8ef3..93c4065fde6 100644 --- a/src/mongo/db/commands/feature_compatibility_version.h +++ b/src/mongo/db/commands/feature_compatibility_version.h @@ -109,6 +109,19 @@ public: * concurrent 'FixedFCVRegions'. */ static Lock::ExclusiveLock enterFCVChangeRegion(OperationContext* opCtx); + + /** + * Used by the FCV OpObserver to set the timestamp of the last opTime where the FCV was updated. + * We use this to ensure the user does not see a non-transitional FCV that is not in the + * majority snapshot, since upgrading or downgrading will not work in that circumstance. + */ + static void advanceLastFCVUpdateTimestamp(Timestamp fcvUpdateTimestamp); + + /** + * Used by the FCV OpObserver at rollback time. The rollback FCV is always in the + * majority snapshot, so it is safe to clear the lastFCVUpdateTimestamp then. + */ + static void clearLastFCVUpdateTimestamp(); }; /** |