| 667 | } |
| 668 | |
| 669 | bool QueryState::ReportExecStatus() { |
| 670 | #ifndef NDEBUG |
| 671 | if (FLAGS_stress_status_report_delay_ms) { |
| 672 | LOG(INFO) << "Sleeping " << FLAGS_stress_status_report_delay_ms << "ms before " |
| 673 | << "reporting for query " << PrintId(query_id()); |
| 674 | SleepForMs(FLAGS_stress_status_report_delay_ms); |
| 675 | } |
| 676 | #endif |
| 677 | bool instances_started = fis_map_.size() > 0; |
| 678 | |
| 679 | // This will send a report even if we are cancelled. If the query completed correctly |
| 680 | // but fragments still need to be cancelled (e.g. limit reached), the coordinator will |
| 681 | // be waiting for a final report and profile. |
| 682 | ReportExecStatusRequestPB report; |
| 683 | |
| 684 | // Gather the statuses and profiles of the fragment instances. |
| 685 | TRuntimeProfileForest profiles_forest; |
| 686 | ConstructReport(instances_started, &report, &profiles_forest); |
| 687 | |
| 688 | // Serialize the runtime profile with Thrift to 'profile_buf'. Note that the |
| 689 | // serialization output is owned by 'serializer' so this must be alive until RPC |
| 690 | // is done. |
| 691 | ThriftSerializer serializer(true); |
| 692 | uint8_t* profile_buf = nullptr; |
| 693 | uint32_t profile_len = 0; |
| 694 | Status serialize_status = |
| 695 | serializer.SerializeToBuffer(&profiles_forest, &profile_len, &profile_buf); |
| 696 | if (UNLIKELY(!serialize_status.ok() || |
| 697 | profile_len > FLAGS_rpc_max_message_size || |
| 698 | !DebugAction(query_options(), "REPORT_EXEC_STATUS_PROFILE").ok())) { |
| 699 | profile_buf = nullptr; |
| 700 | LOG(ERROR) << Substitute("Failed to create $0profile for query $1: " |
| 701 | "status=$2 len=$3", IsTerminalState() ? "final " : "", PrintId(query_id()), |
| 702 | serialize_status.ok() ? "OK" : serialize_status.GetDetail(), profile_len); |
| 703 | } |
| 704 | |
| 705 | Status rpc_status; |
| 706 | Status result_status; |
| 707 | RpcController rpc_controller; |
| 708 | |
| 709 | // The profile is a thrift structure serialized to a string and sent as a sidecar. |
| 710 | // We keep the runtime profile as Thrift object as Impala client still communicates |
| 711 | // with Impala server with Thrift RPC. |
| 712 | // |
| 713 | // Note that the sidecar is created with faststring so the ownership of the Thrift |
| 714 | // profile buffer is transferred to RPC layer and it is freed after the RPC payload |
| 715 | // is sent. If serialization of the profile to RPC sidecar fails, we will proceed |
| 716 | // without the profile so that the coordinator can still get the status and won't |
| 717 | // conclude that the backend has hung and cancel the query. |
| 718 | if (profile_buf != nullptr) { |
| 719 | kudu::faststring sidecar_buf; |
| 720 | sidecar_buf.assign_copy(profile_buf, profile_len); |
| 721 | unique_ptr<RpcSidecar> sidecar = RpcSidecar::FromFaststring(move(sidecar_buf)); |
| 722 | |
| 723 | int sidecar_idx; |
| 724 | kudu::Status sidecar_status = |
| 725 | rpc_controller.AddOutboundSidecar(move(sidecar), &sidecar_idx); |
| 726 | if (LIKELY(sidecar_status.ok())) { |
nothing calls this directly
no test coverage detected