Ejemplo n.º 1
0
int Sender::IssueRPC(int64_t start_realtime_us) {
    _main_cntl->_current_call.need_feedback = false;
    LoadBalancer::SelectIn sel_in = { start_realtime_us,
                                      true,
                                      _main_cntl->has_request_code(),
                                      _main_cntl->_request_code,
                                      _main_cntl->_accessed };
    ChannelBalancer::SelectOut sel_out;
    const int rc = static_cast<ChannelBalancer*>(_main_cntl->_lb.get())
        ->SelectChannel(sel_in, &sel_out);
    if (rc != 0) {
        _main_cntl->SetFailed(rc, "Fail to select channel, %s", berror(rc));
        return -1;
    }
    DLOG(INFO) << "Selected channel=" << sel_out.channel() << ", size="
                << (_main_cntl->_accessed ? _main_cntl->_accessed->size() : 0);
    _main_cntl->_current_call.need_feedback = sel_out.need_feedback;
    _main_cntl->_current_call.peer_id = sel_out.fake_sock->id();

    Resource r = PopFree();
    if (r.sub_done == NULL) {
        CHECK(false) << "Impossible!";
        _main_cntl->SetFailed("Impossible happens");
        return -1;
    }
    r.sub_done->_cid = _main_cntl->current_id();
    r.sub_done->_peer_id = sel_out.fake_sock->id();
    Controller* sub_cntl = &r.sub_done->_cntl;
    // No need to count timeout. We already managed timeout in schan. If
    // timeout occurs, sub calls are canceled with ERPCTIMEDOUT.
    sub_cntl->_timeout_ms = -1;

    // Inherit following fields of _main_cntl.
    // TODO(gejun): figure out a better way to maintain these fields.
    sub_cntl->set_connection_type(_main_cntl->connection_type());
    sub_cntl->set_type_of_service(_main_cntl->_tos);
    sub_cntl->set_request_compress_type(_main_cntl->request_compress_type());
    sub_cntl->set_log_id(_main_cntl->log_id());
    sub_cntl->set_request_code(_main_cntl->request_code());
    // Forward request attachment to the subcall
    sub_cntl->request_attachment().append(_main_cntl->request_attachment());
    
    sel_out.channel()->CallMethod(_main_cntl->_method,
                                  &r.sub_done->_cntl,
                                  _request,
                                  r.response,
                                  r.sub_done);
    return 0;
}
Ejemplo n.º 2
0
void SubDone::Run() {
    Controller* main_cntl = NULL;
    const int rc = bthread_id_lock(_cid, (void**)&main_cntl);
    if (rc != 0) {
        // _cid must be valid because schan does not dtor before cancelling
        // all sub calls.
        LOG(ERROR) << "Fail to lock correlation_id="
                   << _cid.value << ": " << berror(rc);
        return;
    }
    // NOTE: Copying gettable-but-settable fields which are generally set
    // during the RPC to reflect details.
    main_cntl->_remote_side = _cntl._remote_side;
    // connection_type may be changed during CallMethod. 
    main_cntl->set_connection_type(_cntl.connection_type());
    Resource r;
    r.response = _cntl._response;
    r.sub_done = this;
    if (!_owner->PushFree(r)) {
        return;
    }
    const int saved_error = main_cntl->ErrorCode();
    
    if (_cntl.Failed()) {
        if (_cntl.ErrorCode() == ENODATA || _cntl.ErrorCode() == EHOSTDOWN) {
            // LB could not find a server.
            Socket::SetFailed(_peer_id);  // trigger HC.
        }
        main_cntl->SetFailed(_cntl._error_text);
        main_cntl->_error_code = _cntl._error_code;
    } else {
        if (_cntl._response != main_cntl->_response) {
            main_cntl->_response->GetReflection()->Swap(
                main_cntl->_response, _cntl._response);
        }
    }
    const Controller::CompletionInfo info = { _cid, true };
    main_cntl->OnVersionedRPCReturned(info, false, saved_error);
}