summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJudah Schvimer <judah@mongodb.com>2017-05-22 10:46:19 -0400
committerJudah Schvimer <judah@mongodb.com>2017-05-22 10:46:19 -0400
commitb035e46ec65088885d8b934af235481f294af77f (patch)
tree5e877abe2482a8bf06d41c0d7b6fa19fa5f98e1a
parent222729e604843568bb7100be1d94b28853c2da8d (diff)
downloadmongo-b035e46ec65088885d8b934af235481f294af77f.tar.gz
SERVER-29090 Nodes provide more information on why they reject a vote
-rw-r--r--jstests/replsets/last_vote.js6
-rw-r--r--jstests/replsets/no_flapping_during_network_partition.js2
-rw-r--r--src/mongo/db/repl/topology_coordinator_impl.cpp57
-rw-r--r--src/mongo/db/repl/topology_coordinator_impl.h6
-rw-r--r--src/mongo/db/repl/topology_coordinator_impl_test.cpp35
-rw-r--r--src/mongo/db/repl/topology_coordinator_impl_v1_test.cpp35
6 files changed, 93 insertions, 48 deletions
diff --git a/jstests/replsets/last_vote.js b/jstests/replsets/last_vote.js
index b9e0474217c..44d349f3237 100644
--- a/jstests/replsets/last_vote.js
+++ b/jstests/replsets/last_vote.js
@@ -134,9 +134,6 @@
"replSetRequestVotes response had the wrong term: " + tojson(response));
assert(!response.voteGranted,
"node granted vote in term before last vote doc: " + tojson(response));
- assert.eq(response.reason,
- "candidate's term is lower than mine",
- "replSetRequestVotes response had the wrong reason: " + tojson(response));
assertNodeHasLastVote(node0, term, rst.nodes[0]);
assertCurrentTerm(node0, term);
@@ -178,9 +175,6 @@
"replSetRequestVotes response had the wrong term: " + tojson(response));
assert(!response.voteGranted,
"node granted vote in term of last vote doc: " + tojson(response));
- assert.eq(response.reason,
- "already voted for another candidate this term",
- "replSetRequestVotes response had the wrong reason: " + tojson(response));
assertNodeHasLastVote(node0, term, rst.nodes[0]);
assertCurrentTerm(node0, term);
diff --git a/jstests/replsets/no_flapping_during_network_partition.js b/jstests/replsets/no_flapping_during_network_partition.js
index 9c70febfc89..5ad03338716 100644
--- a/jstests/replsets/no_flapping_during_network_partition.js
+++ b/jstests/replsets/no_flapping_during_network_partition.js
@@ -39,7 +39,7 @@
primary.disconnect(secondary);
jsTestLog("Wait long enough for the secondary to call for an election.");
- checkLog.contains(secondary, "can see a healthy primary of equal or greater priority");
+ checkLog.contains(secondary, "can see a healthy primary");
checkLog.contains(secondary, "not running for primary");
jsTestLog("Verify the primary and secondary do not change during the partition.");
diff --git a/src/mongo/db/repl/topology_coordinator_impl.cpp b/src/mongo/db/repl/topology_coordinator_impl.cpp
index fef34461b2b..7492bb4bb40 100644
--- a/src/mongo/db/repl/topology_coordinator_impl.cpp
+++ b/src/mongo/db/repl/topology_coordinator_impl.cpp
@@ -1564,7 +1564,7 @@ bool TopologyCoordinatorImpl::_aMajoritySeemsToBeUp() const {
return vUp * 2 > _rsConfig.getTotalVotingMembers();
}
-bool TopologyCoordinatorImpl::_canSeeHealthyPrimaryOfEqualOrGreaterPriority(
+int TopologyCoordinatorImpl::_findHealthyPrimaryOfEqualOrGreaterPriority(
const int candidateIndex) const {
const double candidatePriority = _rsConfig.getMemberAt(candidateIndex).getPriority();
for (auto it = _memberData.begin(); it != _memberData.end(); ++it) {
@@ -1574,11 +1574,11 @@ bool TopologyCoordinatorImpl::_canSeeHealthyPrimaryOfEqualOrGreaterPriority(
const int itIndex = indexOfIterator(_memberData, it);
const double priority = _rsConfig.getMemberAt(itIndex).getPriority();
if (itIndex != candidateIndex && priority >= candidatePriority) {
- return true;
+ return itIndex;
}
}
- return false;
+ return -1;
}
bool TopologyCoordinatorImpl::_isOpTimeCloseEnoughToLatestToElect(const OpTime& otherOpTime) const {
@@ -2899,29 +2899,54 @@ void TopologyCoordinatorImpl::processReplSetRequestVotes(const ReplSetRequestVot
if (args.getTerm() < _term) {
response->setVoteGranted(false);
- response->setReason("candidate's term is lower than mine");
+ response->setReason(str::stream() << "candidate's term (" << args.getTerm()
+ << ") is lower than mine ("
+ << _term
+ << ")");
} else if (args.getConfigVersion() != _rsConfig.getConfigVersion()) {
response->setVoteGranted(false);
- response->setReason("candidate's config version differs from mine");
+ response->setReason(str::stream() << "candidate's config version ("
+ << args.getConfigVersion()
+ << ") differs from mine ("
+ << _rsConfig.getConfigVersion()
+ << ")");
} else if (args.getSetName() != _rsConfig.getReplSetName()) {
response->setVoteGranted(false);
- response->setReason("candidate's set name differs from mine");
+ response->setReason(str::stream() << "candidate's set name (" << args.getSetName()
+ << ") differs from mine ("
+ << _rsConfig.getReplSetName()
+ << ")");
} else if (args.getLastDurableOpTime() < getMyLastAppliedOpTime()) {
response->setVoteGranted(false);
- response->setReason("candidate's data is staler than mine");
+ response
+ ->setReason(str::stream()
+ << "candidate's data is staler than mine. candidate's last applied OpTime: "
+ << args.getLastDurableOpTime().toString()
+ << ", my last applied OpTime: "
+ << getMyLastAppliedOpTime().toString());
} else if (!args.isADryRun() && _lastVote.getTerm() == args.getTerm()) {
response->setVoteGranted(false);
- response->setReason("already voted for another candidate this term");
- } else if (_selfConfig().isArbiter() &&
- _canSeeHealthyPrimaryOfEqualOrGreaterPriority(args.getCandidateIndex())) {
- response->setVoteGranted(false);
- response->setReason("can see a healthy primary of equal or greater priority");
+ response->setReason(str::stream()
+ << "already voted for another candidate ("
+ << _rsConfig.getMemberAt(_lastVote.getCandidateIndex()).getHostAndPort()
+ << ") this term ("
+ << _lastVote.getTerm()
+ << ")");
} else {
- if (!args.isADryRun()) {
- _lastVote.setTerm(args.getTerm());
- _lastVote.setCandidateIndex(args.getCandidateIndex());
+ int betterPrimary = _findHealthyPrimaryOfEqualOrGreaterPriority(args.getCandidateIndex());
+ if (_selfConfig().isArbiter() && betterPrimary >= 0) {
+ response->setVoteGranted(false);
+ response->setReason(str::stream()
+ << "can see a healthy primary ("
+ << _rsConfig.getMemberAt(betterPrimary).getHostAndPort()
+ << ") of equal or greater priority");
+ } else {
+ if (!args.isADryRun()) {
+ _lastVote.setTerm(args.getTerm());
+ _lastVote.setCandidateIndex(args.getCandidateIndex());
+ }
+ response->setVoteGranted(true);
}
- response->setVoteGranted(true);
}
}
diff --git a/src/mongo/db/repl/topology_coordinator_impl.h b/src/mongo/db/repl/topology_coordinator_impl.h
index ce20fd477d5..4f7acbd6a65 100644
--- a/src/mongo/db/repl/topology_coordinator_impl.h
+++ b/src/mongo/db/repl/topology_coordinator_impl.h
@@ -316,9 +316,9 @@ private:
// Sees if a majority number of votes are held by members who are currently "up"
bool _aMajoritySeemsToBeUp() const;
- // Returns true if the node can see a healthy primary of equal or greater priority to the
- // candidate.
- bool _canSeeHealthyPrimaryOfEqualOrGreaterPriority(const int candidateIndex) const;
+ // Checks if the node can see a healthy primary of equal or greater priority to the
+ // candidate. If so, returns the index of that node. Otherwise returns -1.
+ int _findHealthyPrimaryOfEqualOrGreaterPriority(const int candidateIndex) const;
// Is otherOpTime close enough (within 10 seconds) to the latest known optime to qualify
// for an election
diff --git a/src/mongo/db/repl/topology_coordinator_impl_test.cpp b/src/mongo/db/repl/topology_coordinator_impl_test.cpp
index b830cc66c27..b5af086b797 100644
--- a/src/mongo/db/repl/topology_coordinator_impl_test.cpp
+++ b/src/mongo/db/repl/topology_coordinator_impl_test.cpp
@@ -5584,7 +5584,8 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantVotesToTwoDifferentNodesInTheSameTerm) {
// different candidate same term, should be a problem
getTopoCoord().processReplSetRequestVotes(args2, &response2);
- ASSERT_EQUALS("already voted for another candidate this term", response2.getReason());
+ ASSERT_EQUALS("already voted for another candidate (hself:27017) this term (1)",
+ response2.getReason());
ASSERT_FALSE(response2.getVoteGranted());
}
@@ -5698,7 +5699,8 @@ TEST_F(TopoCoordTest, VoteRequestShouldNotPreventDryRunsForThatTerm) {
ReplSetRequestVotesResponse response2;
getTopoCoord().processReplSetRequestVotes(args2, &response2);
- ASSERT_EQUALS("already voted for another candidate this term", response2.getReason());
+ ASSERT_EQUALS("already voted for another candidate (hself:27017) this term (1)",
+ response2.getReason());
ASSERT_FALSE(response2.getVoteGranted());
}
@@ -5732,7 +5734,7 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantVoteWhenReplSetNameDoesNotMatch) {
ReplSetRequestVotesResponse response;
getTopoCoord().processReplSetRequestVotes(args, &response);
- ASSERT_EQUALS("candidate's set name differs from mine", response.getReason());
+ ASSERT_EQUALS("candidate's set name (wrongName) differs from mine (rs0)", response.getReason());
ASSERT_FALSE(response.getVoteGranted());
}
@@ -5766,7 +5768,7 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantVoteWhenConfigVersionDoesNotMatch) {
ReplSetRequestVotesResponse response;
getTopoCoord().processReplSetRequestVotes(args, &response);
- ASSERT_EQUALS("candidate's config version differs from mine", response.getReason());
+ ASSERT_EQUALS("candidate's config version (0) differs from mine (1)", response.getReason());
ASSERT_FALSE(response.getVoteGranted());
}
@@ -5812,7 +5814,8 @@ TEST_F(TopoCoordTest, ArbiterDoesNotGrantVoteWhenItCanSeeAHealthyPrimaryOfEqualO
ReplSetRequestVotesResponse response;
getTopoCoord().processReplSetRequestVotes(args, &response);
- ASSERT_EQUALS("can see a healthy primary of equal or greater priority", response.getReason());
+ ASSERT_EQUALS("can see a healthy primary (h2:27017) of equal or greater priority",
+ response.getReason());
ASSERT_FALSE(response.getVoteGranted());
}
@@ -5850,7 +5853,7 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantVoteWhenTermIsStale) {
ReplSetRequestVotesResponse response;
getTopoCoord().processReplSetRequestVotes(args, &response);
- ASSERT_EQUALS("candidate's term is lower than mine", response.getReason());
+ ASSERT_EQUALS("candidate's term (1) is lower than mine (2)", response.getReason());
ASSERT_EQUALS(2, response.getTerm());
ASSERT_FALSE(response.getVoteGranted());
}
@@ -5887,7 +5890,12 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantVoteWhenOpTimeIsStale) {
getTopoCoord().getMyMemberData()->setLastAppliedOpTime({Timestamp(20, 0), 0}, Date_t());
getTopoCoord().processReplSetRequestVotes(args, &response);
- ASSERT_EQUALS("candidate's data is staler than mine", response.getReason());
+ ASSERT_EQUALS(
+ str::stream() << "candidate's data is staler than mine. candidate's last applied OpTime: "
+ << OpTime().toString()
+ << ", my last applied OpTime: "
+ << OpTime(Timestamp(20, 0), 0).toString(),
+ response.getReason());
ASSERT_FALSE(response.getVoteGranted());
}
@@ -5945,7 +5953,7 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantDryRunVoteWhenReplSetNameDoesNotMatch) {
ReplSetRequestVotesResponse response;
getTopoCoord().processReplSetRequestVotes(args, &response);
- ASSERT_EQUALS("candidate's set name differs from mine", response.getReason());
+ ASSERT_EQUALS("candidate's set name (wrongName) differs from mine (rs0)", response.getReason());
ASSERT_EQUALS(1, response.getTerm());
ASSERT_FALSE(response.getVoteGranted());
}
@@ -6004,7 +6012,7 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantDryRunVoteWhenConfigVersionDoesNotMatch) {
ReplSetRequestVotesResponse response;
getTopoCoord().processReplSetRequestVotes(args, &response);
- ASSERT_EQUALS("candidate's config version differs from mine", response.getReason());
+ ASSERT_EQUALS("candidate's config version (0) differs from mine (1)", response.getReason());
ASSERT_EQUALS(1, response.getTerm());
ASSERT_FALSE(response.getVoteGranted());
}
@@ -6062,7 +6070,7 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantDryRunVoteWhenTermIsStale) {
ReplSetRequestVotesResponse response;
getTopoCoord().processReplSetRequestVotes(args, &response);
- ASSERT_EQUALS("candidate's term is lower than mine", response.getReason());
+ ASSERT_EQUALS("candidate's term (0) is lower than mine (1)", response.getReason());
ASSERT_EQUALS(1, response.getTerm());
ASSERT_FALSE(response.getVoteGranted());
}
@@ -6181,7 +6189,12 @@ TEST_F(TopoCoordTest, DoNotGrantDryRunVoteWhenOpTimeIsStale) {
getTopoCoord().getMyMemberData()->setLastAppliedOpTime({Timestamp(20, 0), 0}, Date_t());
getTopoCoord().processReplSetRequestVotes(args, &response);
- ASSERT_EQUALS("candidate's data is staler than mine", response.getReason());
+ ASSERT_EQUALS(
+ str::stream() << "candidate's data is staler than mine. candidate's last applied OpTime: "
+ << OpTime().toString()
+ << ", my last applied OpTime: "
+ << OpTime(Timestamp(20, 0), 0).toString(),
+ response.getReason());
ASSERT_EQUALS(1, response.getTerm());
ASSERT_FALSE(response.getVoteGranted());
}
diff --git a/src/mongo/db/repl/topology_coordinator_impl_v1_test.cpp b/src/mongo/db/repl/topology_coordinator_impl_v1_test.cpp
index e9d3617ffb7..80fc9c3bf52 100644
--- a/src/mongo/db/repl/topology_coordinator_impl_v1_test.cpp
+++ b/src/mongo/db/repl/topology_coordinator_impl_v1_test.cpp
@@ -2465,7 +2465,8 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantVotesToTwoDifferentNodesInTheSameTerm) {
// different candidate same term, should be a problem
getTopoCoord().processReplSetRequestVotes(args2, &response2);
- ASSERT_EQUALS("already voted for another candidate this term", response2.getReason());
+ ASSERT_EQUALS("already voted for another candidate (hself:27017) this term (1)",
+ response2.getReason());
ASSERT_FALSE(response2.getVoteGranted());
}
@@ -2564,7 +2565,8 @@ TEST_F(TopoCoordTest, DryRunVoteRequestShouldNotPreventSubsequentDryRunsForThatT
ReplSetRequestVotesResponse response4;
getTopoCoord().processReplSetRequestVotes(args4, &response4);
- ASSERT_EQUALS("already voted for another candidate this term", response4.getReason());
+ ASSERT_EQUALS("already voted for another candidate (hself:27017) this term (1)",
+ response4.getReason());
ASSERT_FALSE(response4.getVoteGranted());
}
@@ -2621,7 +2623,8 @@ TEST_F(TopoCoordTest, VoteRequestShouldNotPreventDryRunsForThatTerm) {
ReplSetRequestVotesResponse response2;
getTopoCoord().processReplSetRequestVotes(args2, &response2);
- ASSERT_EQUALS("already voted for another candidate this term", response2.getReason());
+ ASSERT_EQUALS("already voted for another candidate (hself:27017) this term (1)",
+ response2.getReason());
ASSERT_FALSE(response2.getVoteGranted());
}
@@ -2655,7 +2658,7 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantVoteWhenReplSetNameDoesNotMatch) {
ReplSetRequestVotesResponse response;
getTopoCoord().processReplSetRequestVotes(args, &response);
- ASSERT_EQUALS("candidate's set name differs from mine", response.getReason());
+ ASSERT_EQUALS("candidate's set name (wrongName) differs from mine (rs0)", response.getReason());
ASSERT_FALSE(response.getVoteGranted());
}
@@ -2689,7 +2692,7 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantVoteWhenConfigVersionDoesNotMatch) {
ReplSetRequestVotesResponse response;
getTopoCoord().processReplSetRequestVotes(args, &response);
- ASSERT_EQUALS("candidate's config version differs from mine", response.getReason());
+ ASSERT_EQUALS("candidate's config version (0) differs from mine (1)", response.getReason());
ASSERT_FALSE(response.getVoteGranted());
}
@@ -2727,7 +2730,7 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantVoteWhenTermIsStale) {
ReplSetRequestVotesResponse response;
getTopoCoord().processReplSetRequestVotes(args, &response);
- ASSERT_EQUALS("candidate's term is lower than mine", response.getReason());
+ ASSERT_EQUALS("candidate's term (1) is lower than mine (2)", response.getReason());
ASSERT_EQUALS(2, response.getTerm());
ASSERT_FALSE(response.getVoteGranted());
}
@@ -2764,7 +2767,12 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantVoteWhenOpTimeIsStale) {
getTopoCoord().getMyMemberData()->setLastAppliedOpTime({Timestamp(20, 0), 0}, Date_t());
getTopoCoord().processReplSetRequestVotes(args, &response);
- ASSERT_EQUALS("candidate's data is staler than mine", response.getReason());
+ ASSERT_EQUALS(
+ str::stream() << "candidate's data is staler than mine. candidate's last applied OpTime: "
+ << OpTime().toString()
+ << ", my last applied OpTime: "
+ << OpTime(Timestamp(20, 0), 0).toString(),
+ response.getReason());
ASSERT_FALSE(response.getVoteGranted());
}
@@ -2822,7 +2830,7 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantDryRunVoteWhenReplSetNameDoesNotMatch) {
ReplSetRequestVotesResponse response;
getTopoCoord().processReplSetRequestVotes(args, &response);
- ASSERT_EQUALS("candidate's set name differs from mine", response.getReason());
+ ASSERT_EQUALS("candidate's set name (wrongName) differs from mine (rs0)", response.getReason());
ASSERT_EQUALS(1, response.getTerm());
ASSERT_FALSE(response.getVoteGranted());
}
@@ -2881,7 +2889,7 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantDryRunVoteWhenConfigVersionDoesNotMatch) {
ReplSetRequestVotesResponse response;
getTopoCoord().processReplSetRequestVotes(args, &response);
- ASSERT_EQUALS("candidate's config version differs from mine", response.getReason());
+ ASSERT_EQUALS("candidate's config version (0) differs from mine (1)", response.getReason());
ASSERT_EQUALS(1, response.getTerm());
ASSERT_FALSE(response.getVoteGranted());
}
@@ -2939,7 +2947,7 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantDryRunVoteWhenTermIsStale) {
ReplSetRequestVotesResponse response;
getTopoCoord().processReplSetRequestVotes(args, &response);
- ASSERT_EQUALS("candidate's term is lower than mine", response.getReason());
+ ASSERT_EQUALS("candidate's term (0) is lower than mine (1)", response.getReason());
ASSERT_EQUALS(1, response.getTerm());
ASSERT_FALSE(response.getVoteGranted());
}
@@ -3058,7 +3066,12 @@ TEST_F(TopoCoordTest, DoNotGrantDryRunVoteWhenOpTimeIsStale) {
getTopoCoord().getMyMemberData()->setLastAppliedOpTime({Timestamp(20, 0), 0}, Date_t());
getTopoCoord().processReplSetRequestVotes(args, &response);
- ASSERT_EQUALS("candidate's data is staler than mine", response.getReason());
+ ASSERT_EQUALS(
+ str::stream() << "candidate's data is staler than mine. candidate's last applied OpTime: "
+ << OpTime().toString()
+ << ", my last applied OpTime: "
+ << OpTime(Timestamp(20, 0), 0).toString(),
+ response.getReason());
ASSERT_EQUALS(1, response.getTerm());
ASSERT_FALSE(response.getVoteGranted());
}