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; }
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); }