void ReplicationCoordinatorImpl::_onDryRunComplete(long long originalTerm) { invariant(_voteRequester); LoseElectionDryRunGuardV1 lossGuard(this); LockGuard lk(_topoMutex); if (_topCoord->getTerm() != originalTerm) { log() << "not running for primary, we have been superceded already"; return; } const VoteRequester::Result endResult = _voteRequester->getResult(); if (endResult == VoteRequester::Result::kInsufficientVotes) { log() << "not running for primary, we received insufficient votes"; return; } else if (endResult == VoteRequester::Result::kStaleTerm) { log() << "not running for primary, we have been superceded already"; return; } else if (endResult != VoteRequester::Result::kSuccessfullyElected) { log() << "not running for primary, we received an unexpected problem"; return; } log() << "dry election run succeeded, running for election"; // Stepdown is impossible from this term update. TopologyCoordinator::UpdateTermResult updateTermResult; _updateTerm_incallback(originalTerm + 1, &updateTermResult); invariant(updateTermResult == TopologyCoordinator::UpdateTermResult::kUpdatedTerm); // Secure our vote for ourself first _topCoord->voteForMyselfV1(); // Store the vote in persistent storage. LastVote lastVote; lastVote.setTerm(originalTerm + 1); lastVote.setCandidateIndex(_selfIndex); auto cbStatus = _replExecutor.scheduleDBWork( [this, lastVote](const ReplicationExecutor::CallbackArgs& cbData) { _writeLastVoteForMyElection(lastVote, cbData); }); if (cbStatus.getStatus() == ErrorCodes::ShutdownInProgress) { return; } fassert(34421, cbStatus.getStatus()); lossGuard.dismiss(); }
void ReplicationCoordinatorImpl::_handleHeartbeatResponse( const ReplicationExecutor::RemoteCommandCallbackData& cbData, int targetIndex) { // remove handle from queued heartbeats _untrackHeartbeatHandle(cbData.myHandle); // Parse and validate the response. At the end of this step, if responseStatus is OK then // hbResponse is valid. Status responseStatus = cbData.response.getStatus(); if (responseStatus == ErrorCodes::CallbackCanceled) { return; } const HostAndPort& target = cbData.request.target; ReplSetHeartbeatResponse hbResponse; BSONObj resp; if (responseStatus.isOK()) { resp = cbData.response.getValue().data; responseStatus = hbResponse.initialize(resp, _topCoord->getTerm()); } const Date_t now = _replExecutor.now(); const OpTime lastApplied = getMyLastOptime(); // Locks and unlocks _mutex. Milliseconds networkTime(0); StatusWith<ReplSetHeartbeatResponse> hbStatusResponse(hbResponse); if (responseStatus.isOK()) { networkTime = cbData.response.getValue().elapsedMillis; _updateTerm_incallback(hbStatusResponse.getValue().getTerm(), nullptr); } else { log() << "Error in heartbeat request to " << target << "; " << responseStatus; if (!resp.isEmpty()) { LOG(3) << "heartbeat response: " << resp; } hbStatusResponse = StatusWith<ReplSetHeartbeatResponse>(responseStatus); } HeartbeatResponseAction action = _topCoord->processHeartbeatResponse( now, networkTime, target, hbStatusResponse, lastApplied); if (action.getAction() == HeartbeatResponseAction::NoAction && hbStatusResponse.isOK() && hbStatusResponse.getValue().hasOpTime() && targetIndex >= 0 && hbStatusResponse.getValue().hasState() && hbStatusResponse.getValue().getState() != MemberState::RS_PRIMARY) { boost::unique_lock<boost::mutex> lk(_mutex); if (hbStatusResponse.getValue().getConfigVersion() == _rsConfig.getConfigVersion()) { _updateOpTimeFromHeartbeat_inlock(targetIndex, hbStatusResponse.getValue().getOpTime()); // TODO: Enable with Data Replicator //lk.unlock(); //_dr.slavesHaveProgressed(); } } _signalStepDownWaiters(); _scheduleHeartbeatToTarget( target, targetIndex, std::max(now, action.getNextHeartbeatStartDate())); _handleHeartbeatResponseAction(action, hbStatusResponse); }