summaryrefslogtreecommitdiff
path: root/src/mongo/db/commands/feature_compatibility_version.cpp
diff options
context:
space:
mode:
authorMatthew Russotto <matthew.russotto@mongodb.com>2021-05-26 18:21:45 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-05-27 15:12:27 +0000
commit11b41d28993c539b2b383d44f7969e6dd8e3f968 (patch)
treee292c3613ef951c2ab2d1b38ca637dfeb84fa87b /src/mongo/db/commands/feature_compatibility_version.cpp
parent105b03e1250bc3c412566be6262a155d764d8c32 (diff)
downloadmongo-11b41d28993c539b2b383d44f7969e6dd8e3f968.tar.gz
SERVER-53643 Wait for FCV to be majority committed before reporting it.
Diffstat (limited to 'src/mongo/db/commands/feature_compatibility_version.cpp')
-rw-r--r--src/mongo/db/commands/feature_compatibility_version.cpp42
1 files changed, 42 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&) {