mirror of
https://github.com/apache/impala.git
synced 2025-12-19 18:12:08 -05:00
Adds support to cancel a query during Frontend planning or metadata operations. Frontend planning is handled by createExecRequest, so registers Java Threads executing createExecRequest by their query ID and provides cancelExecRequest to interrupt the Thread for a particular query ID. Cancellation is implemented by setting a boolean for the thread, and calling Thread.interrupt to trigger InterruptedException from any wait calls. Several ignored wait calls are updated to check the boolean and throw an exception if the query has been cancelled, interrupting those operations. Adds periodic checks to the planning process to interrupt planning. They're primarily useful when planning is waiting on catalogd/HMS. If planning gets into an algorithmically complex operation, it will not be interrupted. Removes check_inflight, as we can now cancel a query before it's inflight. In the case that cancellation doesn't happen immediately - because we're in a busy frontend loop that can't be interrupted - /cancel will block until the frontend reaches an interruption point and returns to the backend to finalize the query. When analysis returns, cancellation is finalized in the backend. The /cancel_query request returns once the query is cancelled. Cancelling a request can no longer fail, so additional checks for whether the request has been cancelled before it started executing are added. Removes setting UpdateQueryStatus when GetExecRequest returns because that's already handled in ImpalaServer::Execute when it calls UnregisterQuery in response to an error, and constitutes an update race on the status with UnregisterQuery triggered by CancelQueryHandler. We want to use the status from CancelQueryHandler in this case as it provides more context (about who initiated the cancel); the result of GetExecRequest is just UserCancelledException. Avoids calling UnregisterQuery in Execute if the query is already finalized to avoid redundant "Invalid or unknown query handle" logs. Extends idle_query_statuses_ to save status for any query interrupted by an external process - cancelled by a user or timeout - so they can be handled consistently. Testing: - updates test_query_cancel_created to cancel a CREATED query - added tests to cancel a query while metadata loading is delayed - removes test_query_cancel_exception, as it no longer demonstrates relevant behavior; cancelling a query that will encounter an exception before the exception occurs is no different than other queries - ran query_test/test_cancellation.py in exhaustive mode - ran query_test/test_cancellation.py w/ DEFAULT_TEST_PROTOCOL=beeswax - updates cancellation tests that expect INVALID_QUERY_HANDLE to accept Cancelled, which is sometimes returned by interrupted query status. Change-Id: I0d25d4c7fb0b8dcc7dad9510db1e8dca220eeb86 Reviewed-on: http://gerrit.cloudera.org:8080/21803 Reviewed-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com> Tested-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com>
84 lines
3.0 KiB
Python
84 lines
3.0 KiB
Python
# Licensed to the Apache Software Foundation (ASF) under one
|
|
# or more contributor license agreements. See the NOTICE file
|
|
# distributed with this work for additional information
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
# to you under the Apache License, Version 2.0 (the
|
|
# "License"); you may not use this file except in compliance
|
|
# with the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing,
|
|
# software distributed under the License is distributed on an
|
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
# KIND, either express or implied. See the License for the
|
|
# specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from __future__ import absolute_import, division, print_function
|
|
|
|
from tests.common.impala_test_suite import ImpalaTestSuite
|
|
from tests.common.test_dimensions import create_client_protocol_dimension
|
|
from tests.util.cancel_util import (
|
|
QueryToKill,
|
|
assert_kill_error,
|
|
assert_kill_ok
|
|
)
|
|
|
|
|
|
class TestKillQuery(ImpalaTestSuite):
|
|
@classmethod
|
|
def add_test_dimensions(cls):
|
|
cls.ImpalaTestMatrix.add_dimension(create_client_protocol_dimension())
|
|
|
|
def test_same_coordinator(self, vector):
|
|
protocol = vector.get_value('protocol')
|
|
with self.create_client_for_nth_impalad(0, protocol) as client, \
|
|
QueryToKill(self, protocol) as query_id_to_kill:
|
|
assert_kill_ok(client, query_id_to_kill)
|
|
|
|
def test_different_coordinator(self, vector):
|
|
protocol = vector.get_value('protocol')
|
|
with self.create_client_for_nth_impalad(1, protocol) as client, \
|
|
QueryToKill(self, protocol, nth_impalad=0) as query_id_to_kill:
|
|
assert_kill_ok(client, query_id_to_kill)
|
|
|
|
def test_invalid_query_id(self, vector):
|
|
with self.create_impala_client(protocol=vector.get_value('protocol')) as client:
|
|
assert_kill_error(
|
|
client,
|
|
"ParseException: Syntax error",
|
|
sql="KILL QUERY 123:456",
|
|
)
|
|
assert_kill_error(
|
|
client,
|
|
"AnalysisException: Invalid query id: ''",
|
|
sql="KILL QUERY ''",
|
|
)
|
|
assert_kill_error(
|
|
client,
|
|
"AnalysisException: Invalid query id: 'f:g'",
|
|
sql="KILL QUERY 'f:g'",
|
|
)
|
|
assert_kill_error(
|
|
client,
|
|
"AnalysisException: Invalid query id: '123'",
|
|
sql="KILL QUERY '123'",
|
|
)
|
|
|
|
def test_idempotence(self, vector):
|
|
protocol = vector.get_value('protocol')
|
|
with self.create_impala_client(protocol=protocol) as client, \
|
|
QueryToKill(self, protocol) as query_id_to_kill:
|
|
assert_kill_ok(client, query_id_to_kill)
|
|
assert_kill_error(
|
|
client,
|
|
["Could not find query on any coordinator", "Cancelled"],
|
|
query_id=query_id_to_kill,
|
|
)
|
|
assert_kill_error(
|
|
client,
|
|
["Could not find query on any coordinator", "Cancelled"],
|
|
query_id=query_id_to_kill,
|
|
)
|