diff options
author | Pavithra Vetriselvan <pavithra.vetriselvan@mongodb.com> | 2020-01-23 17:27:40 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2020-01-23 17:27:40 +0000 |
commit | dbdef20f64f4a9e6cee83967cbb4019af58d92cb (patch) | |
tree | 025cbc0edf034cd8f08d27a1fe909f134c8333ff | |
parent | 3cd3a6da3fe0b6f022b721094bda0b97c3527d23 (diff) | |
download | mongo-dbdef20f64f4a9e6cee83967cbb4019af58d92cb.tar.gz |
SERVER-45080 ignore voteRequest from nodes with lower configs
-rw-r--r-- | src/mongo/db/repl/repl_set_request_votes_args.cpp | 20 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_set_request_votes_args.h | 5 | ||||
-rw-r--r-- | src/mongo/db/repl/topology_coordinator.cpp | 59 | ||||
-rw-r--r-- | src/mongo/db/repl/topology_coordinator_v1_test.cpp | 137 | ||||
-rw-r--r-- | src/mongo/db/repl/vote_requester.cpp | 1 |
5 files changed, 173 insertions, 49 deletions
diff --git a/src/mongo/db/repl/repl_set_request_votes_args.cpp b/src/mongo/db/repl/repl_set_request_votes_args.cpp index 57256d71554..3c8538606ed 100644 --- a/src/mongo/db/repl/repl_set_request_votes_args.cpp +++ b/src/mongo/db/repl/repl_set_request_votes_args.cpp @@ -33,6 +33,7 @@ #include "mongo/bson/util/bson_extract.h" #include "mongo/db/jsobj.h" #include "mongo/db/repl/bson_extract_optime.h" +#include "mongo/db/server_options.h" namespace mongo { namespace repl { @@ -41,6 +42,7 @@ namespace { const std::string kCandidateIndexFieldName = "candidateIndex"; const std::string kCommandName = "replSetRequestVotes"; const std::string kConfigVersionFieldName = "configVersion"; +const std::string kConfigTermFieldName = "configTerm"; const std::string kDryRunFieldName = "dryRun"; // The underlying field name is inaccurate, but changing it requires a fair amount of cross // compatibility work for no real benefit. @@ -56,6 +58,7 @@ const std::string kLegalArgsFieldNames[] = { kCandidateIndexFieldName, kCommandName, kConfigVersionFieldName, + kConfigTermFieldName, kDryRunFieldName, kLastDurableOpTimeFieldName, kSetNameFieldName, @@ -84,6 +87,13 @@ Status ReplSetRequestVotesArgs::initialize(const BSONObj& argsObj) { if (!status.isOK()) return status; + // In order to be compatible with FCV 4.2, default the config term to -1 if we are unable + // parse a configTerm field from the args. + status = bsonExtractIntegerFieldWithDefault( + argsObj, kConfigTermFieldName, OpTime::kUninitializedTerm, &_cfgterm); + if (!status.isOK()) + return status; + status = bsonExtractStringField(argsObj, kSetNameFieldName, &_setName); if (!status.isOK()) return status; @@ -115,6 +125,10 @@ long long ReplSetRequestVotesArgs::getConfigVersion() const { return _cfgver; } +long long ReplSetRequestVotesArgs::getConfigTerm() const { + return _cfgterm; +} + OpTime ReplSetRequestVotesArgs::getLastDurableOpTime() const { return _lastDurableOpTime; } @@ -130,6 +144,12 @@ void ReplSetRequestVotesArgs::addToBSON(BSONObjBuilder* builder) const { builder->append(kTermFieldName, _term); builder->appendIntOrLL(kCandidateIndexFieldName, _candidateIndex); builder->appendIntOrLL(kConfigVersionFieldName, _cfgver); + // Only append the config term field if we are in FCV 4.4 + if (serverGlobalParams.featureCompatibility.isVersionInitialized() && + serverGlobalParams.featureCompatibility.getVersion() == + ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo44) { + builder->appendIntOrLL(kConfigTermFieldName, _cfgterm); + } _lastDurableOpTime.append(builder, kLastDurableOpTimeFieldName); } diff --git a/src/mongo/db/repl/repl_set_request_votes_args.h b/src/mongo/db/repl/repl_set_request_votes_args.h index dfecbdba4d4..1dc74eb4f12 100644 --- a/src/mongo/db/repl/repl_set_request_votes_args.h +++ b/src/mongo/db/repl/repl_set_request_votes_args.h @@ -47,6 +47,7 @@ public: long long getTerm() const; long long getCandidateIndex() const; long long getConfigVersion() const; + long long getConfigTerm() const; OpTime getLastDurableOpTime() const; bool isADryRun() const; @@ -58,7 +59,9 @@ private: long long _term = -1; // Current known term of the command issuer. // replSet config index of the member who sent the replSetRequestVotesCmd. long long _candidateIndex = -1; - long long _cfgver = -1; // replSet config version known to the command issuer. + long long _cfgver = -1; // replSet config version known to the command issuer. + // replSet config term known to the command issuer. + long long _cfgterm = OpTime::kUninitializedTerm; OpTime _lastDurableOpTime; // The last known durable op of the command issuer. bool _dryRun = false; // Indicates this is a pre-election check when true. }; diff --git a/src/mongo/db/repl/topology_coordinator.cpp b/src/mongo/db/repl/topology_coordinator.cpp index df4e7132293..8f7dca8cdcd 100644 --- a/src/mongo/db/repl/topology_coordinator.cpp +++ b/src/mongo/db/repl/topology_coordinator.cpp @@ -2748,41 +2748,60 @@ void TopologyCoordinator::processReplSetRequestVotes(const ReplSetRequestVotesAr return; } + // If either config term is -1, ignore the config term entirely and compare config versions. + bool compareConfigTerms = args.getConfigTerm() != -1 && _rsConfig.getConfigTerm() != -1; + if (args.getTerm() < _term) { response->setVoteGranted(false); - response->setReason(str::stream() << "candidate's term (" << args.getTerm() - << ") is lower than mine (" << _term << ")"); - } else if (args.getConfigVersion() != _rsConfig.getConfigVersion()) { + response->setReason(str::stream() << "candidate's term ({}) is lower than mine ({})"_format( + args.getTerm(), _term)); + } else if (compareConfigTerms && args.getConfigTerm() < _rsConfig.getConfigTerm()) { + response->setVoteGranted(false); + response->setReason(str::stream() + << "candidate's term in config(term, version): ({}, {}) is lower " + "than mine ({}, {})"_format(args.getConfigTerm(), + args.getConfigVersion(), + _rsConfig.getConfigTerm(), + _rsConfig.getConfigVersion())); + } else if ((!compareConfigTerms || args.getConfigTerm() == _rsConfig.getConfigTerm()) && + args.getConfigVersion() < _rsConfig.getConfigVersion()) { + // If the terms should not be compared or if the terms are equal, fall back to version + // comparison. response->setVoteGranted(false); response->setReason(str::stream() - << "candidate's config version (" << args.getConfigVersion() - << ") differs from mine (" << _rsConfig.getConfigVersion() << ")"); + << "ignoring term of -1 for comparison, candidate's version in " + "config(term, version): ({}, {}) is lower than mine ({}, {})"_format( + args.getConfigTerm(), + args.getConfigVersion(), + _rsConfig.getConfigTerm(), + _rsConfig.getConfigVersion())); } else if (args.getSetName() != _rsConfig.getReplSetName()) { response->setVoteGranted(false); response->setReason(str::stream() - << "candidate's set name (" << args.getSetName() - << ") differs from mine (" << _rsConfig.getReplSetName() << ")"); + << "candidate's set name ({}) differs from mine ({})"_format( + args.getSetName(), _rsConfig.getReplSetName())); } else if (args.getLastDurableOpTime() < getMyLastAppliedOpTime()) { response->setVoteGranted(false); - 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()); + response->setReason(str::stream() + << "candidate's data is staler than mine. candidate's last applied " + "OpTime: {}, my last applied OpTime: {}"_format( + args.getLastDurableOpTime().toString(), + getMyLastAppliedOpTime().toString())); } else if (!args.isADryRun() && _lastVote.getTerm() == args.getTerm()) { response->setVoteGranted(false); - response->setReason(str::stream() - << "already voted for another candidate (" - << _rsConfig.getMemberAt(_lastVote.getCandidateIndex()).getHostAndPort() - << ") this term (" << _lastVote.getTerm() << ")"); + response->setReason( + str::stream() << "already voted for another candidate ({}) this " + "term ({})"_format(_rsConfig.getMemberAt(_lastVote.getCandidateIndex()) + .getHostAndPort(), + _lastVote.getTerm())); } else { 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"); + response + ->setReason(str::stream() + << "can see a healthy primary ({}) of equal or greater priority"_format( + _rsConfig.getMemberAt(betterPrimary).getHostAndPort())); } else { if (!args.isADryRun()) { _lastVote.setTerm(args.getTerm()); diff --git a/src/mongo/db/repl/topology_coordinator_v1_test.cpp b/src/mongo/db/repl/topology_coordinator_v1_test.cpp index 5a6da50ee33..54519ab8390 100644 --- a/src/mongo/db/repl/topology_coordinator_v1_test.cpp +++ b/src/mongo/db/repl/topology_coordinator_v1_test.cpp @@ -2484,7 +2484,8 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantVotesToTwoDifferentNodesInTheSameTerm) { args.initialize(BSON("replSetRequestVotes" << 1 << "setName" << "rs0" << "term" << 1LL << "candidateIndex" << 0LL - << "configVersion" << 1LL << "lastCommittedOp" + << "configVersion" << 1LL << "configTerm" << 1LL + << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse response; @@ -2498,7 +2499,8 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantVotesToTwoDifferentNodesInTheSameTerm) { .initialize(BSON("replSetRequestVotes" << 1 << "setName" << "rs0" << "term" << 1LL << "candidateIndex" << 1LL - << "configVersion" << 1LL << "lastCommittedOp" + << "configVersion" << 1LL << "configTerm" << 1LL + << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse response2; @@ -2562,7 +2564,7 @@ TEST_F(TopoCoordTest, DryRunVoteRequestShouldNotPreventSubsequentDryRunsForThatT << "rs0" << "dryRun" << true << "term" << 1LL << "candidateIndex" << 0LL << "configVersion" << 1LL - << "lastCommittedOp" + << "configTerm" << 1LL << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse response; @@ -2578,7 +2580,7 @@ TEST_F(TopoCoordTest, DryRunVoteRequestShouldNotPreventSubsequentDryRunsForThatT << "rs0" << "dryRun" << true << "term" << 1LL << "candidateIndex" << 0LL << "configVersion" << 1LL - << "lastCommittedOp" + << "configTerm" << 1LL << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse response2; @@ -2594,7 +2596,7 @@ TEST_F(TopoCoordTest, DryRunVoteRequestShouldNotPreventSubsequentDryRunsForThatT << "rs0" << "dryRun" << false << "term" << 1LL << "candidateIndex" << 0LL << "configVersion" << 1LL - << "lastCommittedOp" + << "configTerm" << 1LL << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse response3; @@ -2610,7 +2612,7 @@ TEST_F(TopoCoordTest, DryRunVoteRequestShouldNotPreventSubsequentDryRunsForThatT << "rs0" << "dryRun" << false << "term" << 1LL << "candidateIndex" << 0LL << "configVersion" << 1LL - << "lastCommittedOp" + << "configTerm" << 1LL << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse response4; @@ -2640,7 +2642,7 @@ TEST_F(TopoCoordTest, VoteRequestShouldNotPreventDryRunsForThatTerm) { << "rs0" << "dryRun" << false << "term" << 1LL << "candidateIndex" << 0LL << "configVersion" << 1LL - << "lastCommittedOp" + << "configTerm" << 1LL << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse response; @@ -2656,7 +2658,7 @@ TEST_F(TopoCoordTest, VoteRequestShouldNotPreventDryRunsForThatTerm) { << "rs0" << "dryRun" << false << "term" << 1LL << "candidateIndex" << 0LL << "configVersion" << 1LL - << "lastCommittedOp" + << "configTerm" << 1LL << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse response2; @@ -2685,7 +2687,8 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantVoteWhenReplSetNameDoesNotMatch) { args.initialize(BSON("replSetRequestVotes" << 1 << "setName" << "wrongName" << "term" << 1LL << "candidateIndex" << 0LL - << "configVersion" << 1LL << "lastCommittedOp" + << "configVersion" << 1LL << "configTerm" << 1LL + << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse response; @@ -2695,10 +2698,10 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantVoteWhenReplSetNameDoesNotMatch) { ASSERT_FALSE(response.getVoteGranted()); } -TEST_F(TopoCoordTest, NodeDoesNotGrantVoteWhenConfigVersionDoesNotMatch) { +TEST_F(TopoCoordTest, NodeDoesNotGrantVoteWhenConfigVersionIsLower) { updateConfig(BSON("_id" << "rs0" - << "version" << 1 << "members" + << "version" << 1 << "term" << 1LL << "members" << BSON_ARRAY(BSON("_id" << 10 << "host" << "hself") << BSON("_id" << 20 << "host" @@ -2713,13 +2716,47 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantVoteWhenConfigVersionDoesNotMatch) { args.initialize(BSON("replSetRequestVotes" << 1 << "setName" << "rs0" << "term" << 1LL << "candidateIndex" << 1LL - << "configVersion" << 0LL << "lastCommittedOp" + << "configVersion" << 0LL << "configTerm" << 1LL + << "lastCommittedOp" + << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) + .transitional_ignore(); + ReplSetRequestVotesResponse response; + + getTopoCoord().processReplSetRequestVotes(args, &response); + ASSERT_EQUALS( + "ignoring term of -1 for comparison, candidate's version in config(term, version): (1, 0) " + "is lower than mine (1, 1)", + response.getReason()); + ASSERT_FALSE(response.getVoteGranted()); +} + +TEST_F(TopoCoordTest, NodeDoesNotGrantVoteWhenConfigTermIsLower) { + updateConfig(BSON("_id" + << "rs0" + << "version" << 1 << "term" << 2LL << "members" + << BSON_ARRAY(BSON("_id" << 10 << "host" + << "hself") + << BSON("_id" << 20 << "host" + << "h2") + << BSON("_id" << 30 << "host" + << "h3"))), + 0); + setSelfMemberState(MemberState::RS_SECONDARY); + + // lower configTerm + ReplSetRequestVotesArgs args; + args.initialize(BSON("replSetRequestVotes" << 1 << "setName" + << "rs0" + << "term" << 1LL << "candidateIndex" << 1LL + << "configVersion" << 1LL << "configTerm" << 1LL + << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse response; getTopoCoord().processReplSetRequestVotes(args, &response); - ASSERT_EQUALS("candidate's config version (0) differs from mine (1)", response.getReason()); + ASSERT_EQUALS("candidate's term in config(term, version): (1, 1) is lower than mine (2, 1)", + response.getReason()); ASSERT_FALSE(response.getVoteGranted()); } @@ -2745,7 +2782,8 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantVoteWhenTermIsStale) { args.initialize(BSON("replSetRequestVotes" << 1 << "setName" << "rs0" << "term" << 1LL << "candidateIndex" << 1LL - << "configVersion" << 1LL << "lastCommittedOp" + << "configVersion" << 1LL << "configTerm" << 1LL + << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse response; @@ -2775,7 +2813,8 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantVoteWhenOpTimeIsStale) { args.initialize(BSON("replSetRequestVotes" << 1 << "setName" << "rs0" << "term" << 3LL << "candidateIndex" << 1LL - << "configVersion" << 1LL << "lastCommittedOp" + << "configVersion" << 1LL << "configTerm" << 1LL + << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse response; @@ -2811,7 +2850,8 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantDryRunVoteWhenReplSetNameDoesNotMatch) { .initialize(BSON("replSetRequestVotes" << 1 << "setName" << "rs0" << "term" << 1LL << "candidateIndex" << 0LL - << "configVersion" << 1LL << "lastCommittedOp" + << "configVersion" << 1LL << "configTerm" << 1LL + << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse responseForRealVote; @@ -2827,7 +2867,7 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantDryRunVoteWhenReplSetNameDoesNotMatch) { << "wrongName" << "dryRun" << true << "term" << 2LL << "candidateIndex" << 0LL << "configVersion" << 1LL - << "lastCommittedOp" + << "configTerm" << 1LL << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse response; @@ -2838,10 +2878,10 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantDryRunVoteWhenReplSetNameDoesNotMatch) { ASSERT_FALSE(response.getVoteGranted()); } -TEST_F(TopoCoordTest, NodeDoesNotGrantDryRunVoteWhenConfigVersionDoesNotMatch) { +TEST_F(TopoCoordTest, NodeDoesNotGrantDryRunVoteWhenConfigVersionIsLower) { updateConfig(BSON("_id" << "rs0" - << "version" << 1 << "members" + << "version" << 1 << "term" << 1LL << "members" << BSON_ARRAY(BSON("_id" << 10 << "host" << "hself") << BSON("_id" << 20 << "host" @@ -2859,7 +2899,8 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantDryRunVoteWhenConfigVersionDoesNotMatch) { .initialize(BSON("replSetRequestVotes" << 1 << "setName" << "rs0" << "term" << 1LL << "candidateIndex" << 0LL - << "configVersion" << 1LL << "lastCommittedOp" + << "configVersion" << 1LL << "configTerm" << 1LL + << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse responseForRealVote; @@ -2875,13 +2916,16 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantDryRunVoteWhenConfigVersionDoesNotMatch) { << "rs0" << "dryRun" << true << "term" << 2LL << "candidateIndex" << 1LL << "configVersion" << 0LL - << "lastCommittedOp" + << "configTerm" << 1LL << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse response; getTopoCoord().processReplSetRequestVotes(args, &response); - ASSERT_EQUALS("candidate's config version (0) differs from mine (1)", response.getReason()); + ASSERT_EQUALS( + "ignoring term of -1 for comparison, candidate's version in config(term, version): (1, 0) " + "is lower than mine (1, 1)", + response.getReason()); ASSERT_EQUALS(1, response.getTerm()); ASSERT_FALSE(response.getVoteGranted()); } @@ -2907,7 +2951,8 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantDryRunVoteWhenTermIsStale) { .initialize(BSON("replSetRequestVotes" << 1 << "setName" << "rs0" << "term" << 1LL << "candidateIndex" << 0LL - << "configVersion" << 1LL << "lastCommittedOp" + << "configVersion" << 1LL << "configTerm" << 1LL + << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse responseForRealVote; @@ -2922,7 +2967,7 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantDryRunVoteWhenTermIsStale) { << "rs0" << "dryRun" << true << "term" << 0LL << "candidateIndex" << 1LL << "configVersion" << 1LL - << "lastCommittedOp" + << "configTerm" << 1LL << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse response; @@ -2933,6 +2978,40 @@ TEST_F(TopoCoordTest, NodeDoesNotGrantDryRunVoteWhenTermIsStale) { ASSERT_FALSE(response.getVoteGranted()); } +TEST_F(TopoCoordTest, NodeGrantsVoteWhenTermIsHigherButConfigVersionIsLower) { + updateConfig(BSON("_id" + << "rs0" + << "version" << 2 << "term" << 1LL << "members" + << BSON_ARRAY(BSON("_id" << 10 << "host" + << "hself") + << BSON("_id" << 20 << "host" + << "h2") + << BSON("_id" << 30 << "host" + << "h3"))), + 0); + setSelfMemberState(MemberState::RS_SECONDARY); + + // set term to 2 + ASSERT(TopologyCoordinator::UpdateTermResult::kUpdatedTerm == + getTopoCoord().updateTerm(2, now())); + + // mismatched configVersion + ReplSetRequestVotesArgs args; + args.initialize(BSON("replSetRequestVotes" << 1 << "setName" + << "rs0" + << "term" << 2LL << "candidateIndex" << 1LL + << "configVersion" << 1LL << "configTerm" << 2LL + << "lastCommittedOp" + << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) + .transitional_ignore(); + ReplSetRequestVotesResponse response; + + getTopoCoord().processReplSetRequestVotes(args, &response); + // Candidates config(t, v) is (2, 1) and our config is (1, 2). Even though the candidate's + // config version is lower, we grant our vote because the candidate's config term is higher. + ASSERT_TRUE(response.getVoteGranted()); +} + TEST_F(TopoCoordTest, GrantDryRunVoteEvenWhenTermHasBeenSeen) { updateConfig(BSON("_id" << "rs0" @@ -2954,7 +3033,8 @@ TEST_F(TopoCoordTest, GrantDryRunVoteEvenWhenTermHasBeenSeen) { .initialize(BSON("replSetRequestVotes" << 1 << "setName" << "rs0" << "term" << 1LL << "candidateIndex" << 0LL - << "configVersion" << 1LL << "lastCommittedOp" + << "configVersion" << 1LL << "configTerm" << 1LL + << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse responseForRealVote; @@ -2970,7 +3050,7 @@ TEST_F(TopoCoordTest, GrantDryRunVoteEvenWhenTermHasBeenSeen) { << "rs0" << "dryRun" << true << "term" << 1LL << "candidateIndex" << 1LL << "configVersion" << 1LL - << "lastCommittedOp" + << "configTerm" << 1LL << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse response; @@ -3002,7 +3082,8 @@ TEST_F(TopoCoordTest, DoNotGrantDryRunVoteWhenOpTimeIsStale) { .initialize(BSON("replSetRequestVotes" << 1 << "setName" << "rs0" << "term" << 1LL << "candidateIndex" << 0LL - << "configVersion" << 1LL << "lastCommittedOp" + << "configVersion" << 1LL << "configTerm" << 1LL + << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse responseForRealVote; @@ -3018,7 +3099,7 @@ TEST_F(TopoCoordTest, DoNotGrantDryRunVoteWhenOpTimeIsStale) { << "rs0" << "dryRun" << true << "term" << 3LL << "candidateIndex" << 1LL << "configVersion" << 1LL - << "lastCommittedOp" + << "configTerm" << 1LL << "lastCommittedOp" << BSON("ts" << Timestamp(10, 0) << "term" << 0LL))) .transitional_ignore(); ReplSetRequestVotesResponse response; diff --git a/src/mongo/db/repl/vote_requester.cpp b/src/mongo/db/repl/vote_requester.cpp index ad29d5f5725..fbef232b5b2 100644 --- a/src/mongo/db/repl/vote_requester.cpp +++ b/src/mongo/db/repl/vote_requester.cpp @@ -87,6 +87,7 @@ std::vector<RemoteCommandRequest> VoteRequester::Algorithm::getRequests() const requestVotesCmdBuilder.append("term", _term); requestVotesCmdBuilder.append("candidateIndex", _candidateIndex); requestVotesCmdBuilder.append("configVersion", _rsConfig.getConfigVersion()); + requestVotesCmdBuilder.append("configTerm", _rsConfig.getConfigTerm()); _lastDurableOpTime.append(&requestVotesCmdBuilder, "lastCommittedOp"); |