| 269 | } |
| 270 | |
| 271 | void QueryDriver::RetryQueryFromThread( |
| 272 | const Status& error, const shared_ptr<QueryDriver>& query_driver) { |
| 273 | // This method does not require holding the ClientRequestState::lock_ for the original |
| 274 | // query. This ensures that the client can still interact (e.g. poll the state) of the |
| 275 | // original query while the new query is being created. This is necessary as it might |
| 276 | // take a non-trivial amount of time to setup and start running the new query. |
| 277 | |
| 278 | bool orig_do_trace = false; |
| 279 | |
| 280 | DCHECK(query_driver.get() == this); |
| 281 | const TUniqueId& query_id = client_request_state_->query_id(); |
| 282 | VLOG_QUERY << Substitute( |
| 283 | "Retrying query $0 with error message $1", PrintId(query_id), error.GetDetail()); |
| 284 | |
| 285 | // There should be no retried client request state. |
| 286 | ClientRequestState* request_state; |
| 287 | { |
| 288 | lock_guard<SpinLock> l(client_request_state_lock_); |
| 289 | DCHECK(retried_client_request_state_ == nullptr); |
| 290 | DCHECK(client_request_state_ != nullptr); |
| 291 | request_state = client_request_state_.get(); |
| 292 | orig_do_trace = request_state->otel_trace_query(); |
| 293 | } |
| 294 | DCHECK(request_state->retry_state() == ClientRequestState::RetryState::RETRYING) |
| 295 | << Substitute("query=$0 unexpected state $1", PrintId(request_state->query_id()), |
| 296 | request_state->ExecStateToString(request_state->exec_state())); |
| 297 | |
| 298 | shared_ptr<ImpalaServer::SessionState> session = request_state->session(); |
| 299 | |
| 300 | // Cancel the query. We don't worry about whether it's inflight because (1) a retry can |
| 301 | // be triggered when the query is in the INITIALIZED state, and (2) the user could have |
| 302 | // already cancelled the query. |
| 303 | request_state->Cancel(nullptr); |
| 304 | |
| 305 | unique_ptr<ClientRequestState> retry_request_state = nullptr; |
| 306 | CreateRetriedClientRequestState(request_state, &retry_request_state, &session); |
| 307 | DCHECK(retry_request_state != nullptr); |
| 308 | |
| 309 | const TUniqueId& retry_query_id = retry_request_state->query_id(); |
| 310 | VLOG_QUERY << Substitute("Retrying query $0 with new query id $1", PrintId(query_id), |
| 311 | PrintId(retry_query_id)); |
| 312 | |
| 313 | // The steps below mimic what is done when a query is first launched. See |
| 314 | // ImpalaServer::ExecuteStatement. |
| 315 | |
| 316 | // Mark the session as active. This is necessary because a ScopedSessionState may not |
| 317 | // actively be opened at this time. A reference to the session (SessionState::ref_count) |
| 318 | // is necessary when calling ImpalaServer::RegisterQuery with the session. Furthermore, |
| 319 | // a reference to the session is necessary to ensure that the session does not get |
| 320 | // expired while the retry is running. |
| 321 | parent_server_->MarkSessionActive(session); |
| 322 | |
| 323 | // A QueryHandle instance is required for a few of the methods called below. |
| 324 | QueryHandle retry_query_handle; |
| 325 | retry_query_handle.SetHandle(query_driver, retry_request_state.get()); |
| 326 | |
| 327 | // Register the new query. |
| 328 | Status status = |
nothing calls this directly
no test coverage detected