summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXueruiFa <xuerui.fa@mongodb.com>2020-09-16 16:09:27 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-11-30 20:08:32 +0000
commitdd3d60643b760ee60d9445e4769fa68b35e0eba7 (patch)
tree25ca5ac89dc72afdede888f1f540b34cd293e9c1
parent2b220b6e36f7db4e39f17527acc66f2490a80cca (diff)
downloadmongo-dd3d60643b760ee60d9445e4769fa68b35e0eba7.tar.gz
SERVER-49159: Return NotPrimaryOrSecondary if currentTime is uninitialized in waitForReadConcernImpl
(cherry picked from commit 9492de5aac55c8c579044dfa54703056d6012d95)
-rw-r--r--src/mongo/db/read_concern_mongod.cpp18
1 files changed, 17 insertions, 1 deletions
diff --git a/src/mongo/db/read_concern_mongod.cpp b/src/mongo/db/read_concern_mongod.cpp
index b7e8b4cf4de..bce6114e505 100644
--- a/src/mongo/db/read_concern_mongod.cpp
+++ b/src/mongo/db/read_concern_mongod.cpp
@@ -322,7 +322,23 @@ Status waitForReadConcernImpl(OperationContext* opCtx,
<< " readConcern without replication enabled"};
}
- auto currentTime = LogicalClock::get(opCtx)->getClusterTime();
+ // We must read the member state before obtaining the cluster time. Otherwise, we can
+ // run into a race where the cluster time is read as uninitialized, but the member state
+ // is set to RECOVERING by another thread before we invariant that the node is in
+ // STARTUP or STARTUP2.
+ const auto memberState = replCoord->getMemberState();
+
+ const auto currentTime = LogicalClock::get(opCtx)->getClusterTime();
+ if (currentTime == LogicalTime::kUninitialized) {
+ // currentTime should only be uninitialized if we are in startup recovery or initial
+ // sync.
+ invariant(memberState.startup() || memberState.startup2());
+ return {ErrorCodes::NotPrimaryOrSecondary,
+ str::stream() << "Current clusterTime is uninitialized, cannot service the "
+ "requested clusterTime. Requested clusterTime: "
+ << targetClusterTime->toString()
+ << "; current clusterTime: " << currentTime.toString()};
+ }
if (currentTime < *targetClusterTime) {
return {ErrorCodes::InvalidOptions,
str::stream() << "readConcern " << readConcernName