summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVishnu Kaushik <vishnu.kaushik@mongodb.com>2021-06-08 16:14:08 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-06-29 16:48:09 +0000
commitab6c88a7db9b16ff8120a6c2ad63f2fe597bc388 (patch)
treedc71359ace371a8a5cd82270f233c59674b31a16
parent17158bd640654e34c376e99ff30cd27d35c53847 (diff)
downloadmongo-ab6c88a7db9b16ff8120a6c2ad63f2fe597bc388.tar.gz
SERVER-55465 Response from all nodes means sufficient responses have been received even if primary gave bad response in catchup takeover dry run
-rw-r--r--src/mongo/db/repl/vote_requester.cpp10
-rw-r--r--src/mongo/db/repl/vote_requester_test.cpp31
2 files changed, 39 insertions, 2 deletions
diff --git a/src/mongo/db/repl/vote_requester.cpp b/src/mongo/db/repl/vote_requester.cpp
index 486dcd5c92c..83efdf7ec25 100644
--- a/src/mongo/db/repl/vote_requester.cpp
+++ b/src/mongo/db/repl/vote_requester.cpp
@@ -184,12 +184,18 @@ bool VoteRequester::Algorithm::hasReceivedSufficientResponses() const {
return true;
}
+ // We require the primary's response during catchup takeover. An error response from the primary
+ // is not a yes, no or pending, but is still a response. Therefore, we handle the case in which
+ // we have received some response (even if error) from all nodes first.
+ if (_responsesProcessed == static_cast<int>(_targets.size())) {
+ return true;
+ }
+
if (_primaryHost && _primaryVote == PrimaryVote::Pending) {
return false;
}
- return _staleTerm || _votes >= _rsConfig.getMajorityVoteCount() ||
- _responsesProcessed == static_cast<int>(_targets.size());
+ return _staleTerm || _votes >= _rsConfig.getMajorityVoteCount();
}
VoteRequester::Result VoteRequester::Algorithm::getResult() const {
diff --git a/src/mongo/db/repl/vote_requester_test.cpp b/src/mongo/db/repl/vote_requester_test.cpp
index 8fc176e0c10..17a87ca274b 100644
--- a/src/mongo/db/repl/vote_requester_test.cpp
+++ b/src/mongo/db/repl/vote_requester_test.cpp
@@ -653,6 +653,37 @@ TEST_F(VoteRequesterCatchupTakeoverDryRunTest, CatchupTakeoverPrimarySaysNoLoseE
stopCapturingLogMessages();
}
+TEST_F(VoteRequesterCatchupTakeoverDryRunTest,
+ CatchupTakeoverAllNodesRespondedMeansSufficientResponses) {
+ startCapturingLogMessages();
+ ASSERT_FALSE(hasReceivedSufficientResponses());
+
+ // Getting a good response from the other secondaries is insufficient.
+ processResponse(requestFrom("host2"), votedYes());
+ processResponse(requestFrom("host3"), votedYes());
+ processResponse(requestFrom("host4"), votedYes());
+ ASSERT_FALSE(hasReceivedSufficientResponses());
+
+ // Getting a bad response from the primary means all targets have responded, and so we have
+ // received sufficient responses.
+ processResponse(requestFrom("host1"), badRemoteCommandResponse());
+ ASSERT_EQUALS(
+ 1,
+ countBSONFormatLogLinesIsSubset(BSON("attr" << BSON("failReason"
+ << "failed to receive response"
+ << "from"
+ << "host1:27017"))));
+ ASSERT_TRUE(hasReceivedSufficientResponses());
+
+ // A bad response from the primary is equivalent to it saying NO.
+ ASSERT(VoteRequester::Result::kPrimaryRespondedNo == getResult());
+
+ // Only the secondaries are counted; the primary is excluded from the responders since it gave a
+ // bad response.
+ ASSERT_EQUALS(3, getNumResponders());
+ stopCapturingLogMessages();
+}
+
} // namespace
} // namespace repl
} // namespace mongo