| 305 | } |
| 306 | |
| 307 | void RuntimeState::SetMemLimitExceeded(MemTracker* tracker, |
| 308 | int64_t failed_allocation_size, const ErrorMsg* msg) { |
| 309 | // Constructing the MemLimitExceeded and logging it is not cheap, so |
| 310 | // avoid the cost if the query has already hit an error. |
| 311 | // This is particularly important on the UDF codepath, because the UDF codepath |
| 312 | // cannot abort the fragment immediately. It relies on callers checking status |
| 313 | // periodically. This means that this function could be called a large number of times |
| 314 | // (e.g. once per row) before the fragment aborts. See IMPALA-6997. |
| 315 | if (!is_query_status_ok_.Load()) return; |
| 316 | Status status = tracker->MemLimitExceeded(this, msg == nullptr ? "" : msg->msg(), |
| 317 | failed_allocation_size); |
| 318 | { |
| 319 | lock_guard<SpinLock> l(query_status_lock_); |
| 320 | if (query_status_.ok()) { |
| 321 | query_status_ = status; |
| 322 | bool set_query_status_ok_ = is_query_status_ok_.CompareAndSwap(true, false); |
| 323 | DCHECK(set_query_status_ok_); |
| 324 | } |
| 325 | } |
| 326 | LogError(status.msg()); |
| 327 | // Add warning about missing stats except for compute stats child queries. |
| 328 | if (!query_ctx().__isset.parent_query_id && |
| 329 | query_ctx().__isset.tables_missing_stats && |
| 330 | !query_ctx().tables_missing_stats.empty()) { |
| 331 | LogError(ErrorMsg(TErrorCode::GENERAL, |
| 332 | GetTablesMissingStatsWarning(query_ctx().tables_missing_stats))); |
| 333 | } |
| 334 | } |
| 335 | |
| 336 | Status RuntimeState::CheckQueryState() { |
| 337 | DCHECK(instance_mem_tracker_ != nullptr); |
no test coverage detected