| 444 | } |
| 445 | |
| 446 | void Channel::CallMethod(const google::protobuf::MethodDescriptor* method, |
| 447 | google::protobuf::RpcController* controller_base, |
| 448 | const google::protobuf::Message* request, |
| 449 | google::protobuf::Message* response, |
| 450 | google::protobuf::Closure* done) { |
| 451 | const int64_t start_send_real_us = butil::gettimeofday_us(); |
| 452 | Controller* cntl = static_cast<Controller*>(controller_base); |
| 453 | cntl->OnRPCBegin(start_send_real_us); |
| 454 | // Override max_retry first to reset the range of correlation_id |
| 455 | if (cntl->max_retry() == UNSET_MAGIC_NUM) { |
| 456 | cntl->set_max_retry(_options.max_retry); |
| 457 | } |
| 458 | if (cntl->max_retry() < 0) { |
| 459 | // this is important because #max_retry decides #versions allocated |
| 460 | // in correlation_id. negative max_retry causes undefined behavior. |
| 461 | cntl->set_max_retry(0); |
| 462 | } |
| 463 | // HTTP needs this field to be set before any SetFailed() |
| 464 | cntl->_request_protocol = _options.protocol; |
| 465 | if (_options.protocol.has_param()) { |
| 466 | CHECK(cntl->protocol_param().empty()); |
| 467 | cntl->protocol_param() = _options.protocol.param(); |
| 468 | } |
| 469 | if (_options.protocol == brpc::PROTOCOL_HTTP && (_scheme == "https" || _scheme == "http")) { |
| 470 | URI& uri = cntl->http_request().uri(); |
| 471 | if (uri.host().empty() && !_service_name.empty()) { |
| 472 | uri.SetHostAndPort(_service_name); |
| 473 | } |
| 474 | } |
| 475 | cntl->_preferred_index = _preferred_index; |
| 476 | cntl->_retry_policy = _options.retry_policy; |
| 477 | if (_options.enable_circuit_breaker) { |
| 478 | cntl->add_flag(Controller::FLAGS_ENABLED_CIRCUIT_BREAKER); |
| 479 | } |
| 480 | const CallId correlation_id = cntl->call_id(); |
| 481 | const int rc = bthread_id_lock_and_reset_range( |
| 482 | correlation_id, NULL, 2 + cntl->max_retry()); |
| 483 | if (rc != 0) { |
| 484 | CHECK_EQ(EINVAL, rc); |
| 485 | if (!cntl->FailedInline()) { |
| 486 | cntl->SetFailed(EINVAL, "Fail to lock call_id=%" PRId64, |
| 487 | correlation_id.value); |
| 488 | } |
| 489 | LOG_IF(ERROR, cntl->is_used_by_rpc()) |
| 490 | << "Controller=" << cntl << " was used by another RPC before. " |
| 491 | "Did you forget to Reset() it before reuse?"; |
| 492 | // Have to run done in-place. If the done runs in another thread, |
| 493 | // Join() on this RPC is no-op and probably ends earlier than running |
| 494 | // the callback and releases resources used in the callback. |
| 495 | // Since this branch is only entered by wrongly-used RPC, the |
| 496 | // potentially introduced deadlock(caused by locking RPC and done with |
| 497 | // the same non-recursive lock) is acceptable and removable by fixing |
| 498 | // user's code. |
| 499 | if (done) { |
| 500 | done->Run(); |
| 501 | } |
| 502 | return; |
| 503 | } |
no test coverage detected