StatusWith<executor::TaskExecutor::EventHandle> AsyncClusterClientCursor::nextEvent() {
    stdx::lock_guard<stdx::mutex> lk(_mutex);

    if (_lifecycleState != kAlive) {
        // Can't schedule further network operations if the ACCC is being killed.
        return Status(ErrorCodes::IllegalOperation,
                      "nextEvent() called on a killed async cluster client cursor");
    }

    if (_currentEvent.isValid()) {
        // We can't make a new event if there's still an unsignaled one, as every event must
        // eventually be signaled.
        return Status(ErrorCodes::IllegalOperation,
                      "nextEvent() called before an outstanding event was signaled");
    }

    // Schedule remote work on hosts for which we need more results.
    for (size_t i = 0; i < _remotes.size(); ++i) {
        auto& remote = _remotes[i];

        // It is illegal to call this method if there is an error received from any shard.
        invariant(remote.status.isOK());

        if (!remote.hasNext() && !remote.exhausted() && !remote.cbHandle.isValid()) {
            // If we already have established a cursor with this remote, and there is no outstanding
            // request for which we have a valid callback handle, send a getMore with the
            // appropriate cursorId. Otherwise, send the cursor-establishing command.
            BSONObj cmdObj = remote.cursorId
                ? GetMoreRequest(_params.nsString, *remote.cursorId, _params.batchSize).toBSON()
                : _params.cmdObj;

            RemoteCommandRequest request(
                remote.hostAndPort, _params.nsString.db().toString(), cmdObj);

            auto callbackStatus = _executor->scheduleRemoteCommand(
                request,
                stdx::bind(&AsyncClusterClientCursor::handleBatchResponse,
                           this,
                           stdx::placeholders::_1,
                           i));
            if (!callbackStatus.isOK()) {
                return callbackStatus.getStatus();
            }

            remote.cbHandle = callbackStatus.getValue();
        }
    }

    auto eventStatus = _executor->makeEvent();
    if (!eventStatus.isOK()) {
        return eventStatus;
    }
    _currentEvent = eventStatus.getValue();
    return _currentEvent;
}
Status AsyncResultsMerger::askForNextBatch_inlock(size_t remoteIndex) {
    auto& remote = _remotes[remoteIndex];

    invariant(!remote.cbHandle.isValid());

    // If mongod returned less docs than the requested batchSize then modify the next getMore
    // request to fetch the remaining docs only. If the remote node has a plan with OR for top k and
    // a full sort as is the case for the OP_QUERY find then this optimization will prevent
    // switching to the full sort plan branch.
    BSONObj cmdObj;

    if (remote.cursorId) {
        auto adjustedBatchSize = _params.batchSize;

        if (_params.batchSize && *_params.batchSize > remote.fetchedCount) {
            adjustedBatchSize = *_params.batchSize - remote.fetchedCount;
        }

        cmdObj = GetMoreRequest(_params.nsString,
                                *remote.cursorId,
                                adjustedBatchSize,
                                _awaitDataTimeout,
                                boost::none,
                                boost::none)
                     .toBSON();
    } else {
        // Do the first time shard host resolution.
        invariant(_params.readPreference);
        Status resolveStatus = remote.resolveShardIdToHostAndPort(*_params.readPreference);
        if (!resolveStatus.isOK()) {
            return resolveStatus;
        }

        remote.fetchedCount = 0;
        cmdObj = *remote.initialCmdObj;
    }

    executor::RemoteCommandRequest request(remote.getTargetHost(),
                                           _params.nsString.db().toString(),
                                           cmdObj,
                                           _metadataObj,
                                           _params.txn);

    auto callbackStatus = _executor->scheduleRemoteCommand(
        request,
        stdx::bind(
            &AsyncResultsMerger::handleBatchResponse, this, stdx::placeholders::_1, remoteIndex));
    if (!callbackStatus.isOK()) {
        return callbackStatus.getStatus();
    }

    remote.cbHandle = callbackStatus.getValue();
    return Status::OK();
}
Status AsyncResultsMerger::askForNextBatch_inlock(OperationContext* opCtx, size_t remoteIndex) {
    auto& remote = _remotes[remoteIndex];

    invariant(!remote.cbHandle.isValid());

    // If mongod returned less docs than the requested batchSize then modify the next getMore
    // request to fetch the remaining docs only. If the remote node has a plan with OR for top k and
    // a full sort as is the case for the OP_QUERY find then this optimization will prevent
    // switching to the full sort plan branch.
    auto adjustedBatchSize = _params->batchSize;
    if (_params->batchSize && *_params->batchSize > remote.fetchedCount) {
        adjustedBatchSize = *_params->batchSize - remote.fetchedCount;
    }

    BSONObj cmdObj = GetMoreRequest(_params->nsString,
                                    remote.cursorId,
                                    adjustedBatchSize,
                                    _awaitDataTimeout,
                                    boost::none,
                                    boost::none)
                         .toBSON();

    executor::RemoteCommandRequest request(
        remote.getTargetHost(), _params->nsString.db().toString(), cmdObj, _metadataObj, opCtx);

    auto callbackStatus =
        _executor->scheduleRemoteCommand(request,
                                         stdx::bind(&AsyncResultsMerger::handleBatchResponse,
                                                    this,
                                                    stdx::placeholders::_1,
                                                    opCtx,
                                                    remoteIndex));
    if (!callbackStatus.isOK()) {
        return callbackStatus.getStatus();
    }

    remote.cbHandle = callbackStatus.getValue();
    return Status::OK();
}