void ReplicationCoordinatorImpl::_handleHeartbeatResponseAction(
            const HeartbeatResponseAction& action,
            const StatusWith<ReplSetHeartbeatResponse>& responseStatus) {

        switch (action.getAction()) {
        case HeartbeatResponseAction::NoAction:
            break;
        case HeartbeatResponseAction::Reconfig:
            invariant(responseStatus.isOK());
            _scheduleHeartbeatReconfig(responseStatus.getValue().getConfig());
            break;
        case HeartbeatResponseAction::StartElection:
            _startElectSelf();
            break;
        case HeartbeatResponseAction::StepDownSelf:
            invariant(action.getPrimaryConfigIndex() == _thisMembersConfigIndex);
            _heartbeatStepDownStart();
            break;
        case HeartbeatResponseAction::StepDownRemotePrimary: {
            invariant(action.getPrimaryConfigIndex() != _thisMembersConfigIndex);
            _requestRemotePrimaryStepdown(
                    _rsConfig.getMemberAt(action.getPrimaryConfigIndex()).getHostAndPort());
            break;
        }
        default:
            severe() << "Illegal heartbeat response action code " << int(action.getAction());
            invariant(false);
        }
    }
    void ReplicationCoordinatorImpl::_handleHeartbeatResponse(
            const ReplicationExecutor::RemoteCommandCallbackData& cbData) {

        // 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 = getStatusFromCommandResult(resp);
        }
        if (responseStatus.isOK()) {
            responseStatus = hbResponse.initialize(resp);
        }
        if (!responseStatus.isOK()) {
            LOG(1) << "Error in heartbeat request to " << target << ";" << responseStatus;
            if (!resp.isEmpty()) {
                LOG(3) << "heartbeat response: " << resp;
            }
        }
        const Date_t now = _replExecutor.now();
        const OpTime lastApplied = _getLastOpApplied();  // Locks and unlocks _mutex.
        Milliseconds networkTime(0);
        StatusWith<ReplSetHeartbeatResponse> hbStatusResponse(hbResponse);
        if (cbData.response.isOK()) {
            networkTime = cbData.response.getValue().elapsedMillis;
        }
        else {
            hbStatusResponse = StatusWith<ReplSetHeartbeatResponse>(responseStatus);
        }
        HeartbeatResponseAction action =
            _topCoord->processHeartbeatResponse(
                    now,
                    networkTime,
                    target,
                    hbStatusResponse,
                    lastApplied);

        _scheduleHeartbeatToTarget(
                target,
                std::max(now, action.getNextHeartbeatStartDate()));

        _handleHeartbeatResponseAction(action, hbStatusResponse);
    }
    void ReplicationCoordinatorImpl::_handleHeartbeatResponseAction(
            const HeartbeatResponseAction& action,
            const StatusWith<ReplSetHeartbeatResponse>& responseStatus) {

        switch (action.getAction()) {
        case HeartbeatResponseAction::NoAction:
            // Update the cached member state if different than the current topology member state
            if (_memberState != _topCoord->getMemberState()) {
                boost::unique_lock<boost::mutex> lk(_mutex);
                const PostMemberStateUpdateAction postUpdateAction =
                    _updateMemberStateFromTopologyCoordinator_inlock();
                lk.unlock();
                _performPostMemberStateUpdateAction(postUpdateAction);
            }
            break;
        case HeartbeatResponseAction::Reconfig:
            invariant(responseStatus.isOK());
            _scheduleHeartbeatReconfig(responseStatus.getValue().getConfig());
            break;
        case HeartbeatResponseAction::StartElection:
            if (isV1ElectionProtocol()) {
                _startElectSelfV1();
            }
            else {
                _startElectSelf();
            }
            break;
        case HeartbeatResponseAction::StepDownSelf:
            invariant(action.getPrimaryConfigIndex() == _selfIndex);
            _heartbeatStepDownStart();
            break;
        case HeartbeatResponseAction::StepDownRemotePrimary: {
            invariant(action.getPrimaryConfigIndex() != _selfIndex);
            _requestRemotePrimaryStepdown(
                    _rsConfig.getMemberAt(action.getPrimaryConfigIndex()).getHostAndPort());
            break;
        }
        default:
            severe() << "Illegal heartbeat response action code " << int(action.getAction());
            invariant(false);
        }
    }
    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);
        }
        const bool isUnauthorized = (responseStatus.code() == ErrorCodes::Unauthorized) ||
                                    (responseStatus.code() == ErrorCodes::AuthenticationFailed);
        const Date_t now = _replExecutor.now();
        const Timestamp lastApplied = getMyLastOptime();  // Locks and unlocks _mutex.
        Milliseconds networkTime(0);
        StatusWith<ReplSetHeartbeatResponse> hbStatusResponse(hbResponse);

        if (responseStatus.isOK()) {
            networkTime = cbData.response.getValue().elapsedMillis;
        }
        else {
            log() << "Error in heartbeat request to " << target << "; " << responseStatus;
            if (!resp.isEmpty()) {
                LOG(3) << "heartbeat response: " << resp;
            }

            if (isUnauthorized) {
                networkTime = cbData.response.getValue().elapsedMillis;
            }
            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().getVersion() == _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);
    }