IMPALA-6997: Avoid redundant dumping in SetMemLimitExceeded()

When a UDF hits a MemLimitExceeded, the query does not
immediately abort. Instead, UDFs rely on the caller
checking the query_status_ periodically. This means that
on some codepaths, UDFs can call SetMemLimitExceeded()
many times (e.g. once per row) before the query fragment
exits.

RuntimeState::SetMemLimitExceeded() currently constructs
a MemLimitExceeded Status and dumps it for each call, even
if the query has already hit an error. This is expensive
and can delay an fragment from exiting when UDFs are
repeatedly hitting MemLimitExceeded.

This changes SetMemLimitExceeded() to avoid dumping if
the query_status_ is already not ok.

Change-Id: I92b87f370a68a2f695ebbc2520a98dd143730701
Reviewed-on: http://gerrit.cloudera.org:8080/10364
Reviewed-by: Tim Armstrong <tarmstr...@cloudera.com>
Tested-by: Impala Public Jenkins <impala-public-jenk...@cloudera.com>


Project: http://git-wip-us.apache.org/repos/asf/impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/impala/commit/8e5c18c3
Tree: http://git-wip-us.apache.org/repos/asf/impala/tree/8e5c18c3
Diff: http://git-wip-us.apache.org/repos/asf/impala/diff/8e5c18c3

Branch: refs/heads/2.x
Commit: 8e5c18c3b789da8208611e77cd25899be78d4c8e
Parents: 60fdae7
Author: Joe McDonnell <joemcdonn...@cloudera.com>
Authored: Wed May 9 15:05:37 2018 -0700
Committer: Impala Public Jenkins <impala-public-jenk...@gerrit.cloudera.org>
Committed: Thu May 17 22:03:02 2018 +0000

----------------------------------------------------------------------
 be/src/runtime/runtime-state.cc | 10 ++++++++++
 1 file changed, 10 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/impala/blob/8e5c18c3/be/src/runtime/runtime-state.cc
----------------------------------------------------------------------
diff --git a/be/src/runtime/runtime-state.cc b/be/src/runtime/runtime-state.cc
index 15b3354..041c19b 100644
--- a/be/src/runtime/runtime-state.cc
+++ b/be/src/runtime/runtime-state.cc
@@ -206,6 +206,16 @@ Status RuntimeState::LogOrReturnError(const ErrorMsg& 
message) {
 
 void RuntimeState::SetMemLimitExceeded(MemTracker* tracker,
     int64_t failed_allocation_size, const ErrorMsg* msg) {
+  // Constructing the MemLimitExceeded and logging it is not cheap, so
+  // avoid the cost if the query has already hit an error.
+  // This is particularly important on the UDF codepath, because the UDF 
codepath
+  // cannot abort the fragment immediately. It relies on callers checking 
status
+  // periodically. This means that this function could be called a large 
number of times
+  // (e.g. once per row) before the fragment aborts. See IMPALA-6997.
+  {
+    lock_guard<SpinLock> l(query_status_lock_);
+    if (!query_status_.ok()) return;
+  }
   Status status = tracker->MemLimitExceeded(this, msg == nullptr ? "" : 
msg->msg(),
       failed_allocation_size);
   {

Reply via email to