summaryrefslogtreecommitdiff
path: root/src/mongo/db/repl/replication_coordinator_impl.cpp
diff options
context:
space:
mode:
authorA. Jesse Jiryu Davis <jesse@mongodb.com>2020-03-14 23:10:12 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-03-17 23:10:40 +0000
commit5adb80de95ab4f7784eb2905f82e4d8712578e3a (patch)
tree39ca3fd597fa23573fae531af87f1298ba86f282 /src/mongo/db/repl/replication_coordinator_impl.cpp
parent9e10d4f30058fcc7a2a770cac6148c1fdc2a83ac (diff)
downloadmongo-5adb80de95ab4f7784eb2905f82e4d8712578e3a.tar.gz
SERVER-46667 Avoid invariant from invalid candidateIndex
Diffstat (limited to 'src/mongo/db/repl/replication_coordinator_impl.cpp')
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl.cpp43
1 files changed, 23 insertions, 20 deletions
diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp
index 0f873be6cd5..23ea924189d 100644
--- a/src/mongo/db/repl/replication_coordinator_impl.cpp
+++ b/src/mongo/db/repl/replication_coordinator_impl.cpp
@@ -4747,28 +4747,17 @@ Status ReplicationCoordinatorImpl::processReplSetRequestVotes(
return Status(ErrorCodes::ShutdownInProgress, "In the process of shutting down");
}
- _topCoord->processReplSetRequestVotes(args, response);
- }
-
- if (!args.isADryRun()) {
const int candidateIndex = args.getCandidateIndex();
- LastVote lastVote{args.getTerm(), candidateIndex};
-
- const bool votedForCandidate = response->getVoteGranted();
-
- if (votedForCandidate) {
- Status status = _externalState->storeLocalLastVoteDocument(opCtx, lastVote);
- if (!status.isOK()) {
- LOGV2_ERROR(21428,
- "replSetRequestVotes failed to store LastVote document; {error}",
- "replSetRequestVotes failed to store LastVote document",
- "error"_attr = status);
- return status;
- }
+ if (candidateIndex < 0 || candidateIndex >= _rsConfig.getNumMembers()) {
+ return Status(ErrorCodes::BadValue,
+ str::stream() << "Invalid candidateIndex: " << candidateIndex
+ << ". Must be between 0 and "
+ << _rsConfig.getNumMembers() - 1 << " inclusive");
}
- // If the vote was not granted to the candidate, we still want to track metrics around the
- // node's participation in the election.
+ _topCoord->processReplSetRequestVotes(args, response);
+
+ const bool votedForCandidate = response->getVoteGranted();
const long long electionTerm = args.getTerm();
const Date_t lastVoteDate = _replExecutor->now();
const int electionCandidateMemberId =
@@ -4777,7 +4766,6 @@ Status ReplicationCoordinatorImpl::processReplSetRequestVotes(
const OpTime lastAppliedOpTime = _topCoord->getMyLastAppliedOpTime();
const OpTime maxAppliedOpTime = _topCoord->latestKnownOpTime();
const double priorityAtElection = _rsConfig.getMemberAt(_selfIndex).getPriority();
-
ReplicationMetrics::get(getServiceContext())
.setElectionParticipantMetrics(votedForCandidate,
electionTerm,
@@ -4788,6 +4776,21 @@ Status ReplicationCoordinatorImpl::processReplSetRequestVotes(
maxAppliedOpTime,
priorityAtElection);
}
+
+ // It's safe to store lastVote outside of _mutex. The topology coordinator grants only one
+ // vote per term, and storeLocalLastVoteDocument does nothing unless lastVote has a higher term
+ // than the previous lastVote, so threads racing to store votes from different terms will
+ // eventually store the latest vote.
+ if (!args.isADryRun() && response->getVoteGranted()) {
+ LastVote lastVote{args.getTerm(), args.getCandidateIndex()};
+ Status status = _externalState->storeLocalLastVoteDocument(opCtx, lastVote);
+ if (!status.isOK()) {
+ LOGV2_ERROR(21428,
+ "replSetRequestVotes failed to store LastVote document",
+ "error"_attr = status);
+ return status;
+ }
+ }
return Status::OK();
}