aminghadersohi commented on code in PR #45845:
URL: https://github.com/apache/superset/pull/45845#discussion_r4431913416
##########
superset/db_engine_specs/impala.py:
##########
@@ -136,30 +139,43 @@ def execute(
@classmethod
def fetch_data(cls, cursor: Any, limit: int | None = None) ->
list[tuple[Any, ...]]:
"""Wait for asynchronous operations using the public cursor API."""
- if callable(getattr(cursor, "execute_async", None)):
- from impala.error import Error
-
- deadline = time.monotonic() + app.config["SQLLAB_TIMEOUT"]
+ try:
+ if callable(getattr(cursor, "execute_async", None)):
+ from impala.error import Error
+
+ deadline = time.monotonic() + app.config["SQLLAB_TIMEOUT"]
+ try:
+ while cursor.is_executing():
+ if time.monotonic() >= deadline:
+ cls._cancel_operation(cursor)
+ raise TimeoutError(
+ "Timed out waiting for the Impala operation"
+ )
+ time.sleep(0.1)
+ if cursor.execution_failed():
+ # Fetching surfaces the driver's detailed asynchronous
error,
+ # including errors on statements that produce no
result set.
+ cursor.fetchall()
+ except Error as ex:
+ raise cls.get_dbapi_mapped_exception(ex) from ex
+ return super().fetch_data(cursor, limit)
+ except TIME_LIMIT_EXCEPTIONS:
+ # The operation is released before the time limit propagates so
+ # it does not keep running on the coordinator.
try:
- while cursor.is_executing():
- if time.monotonic() >= deadline:
- cursor.cancel_operation()
- raise TimeoutError("Timed out waiting for the Impala
operation")
- time.sleep(0.1)
- if cursor.execution_failed():
- # Fetching surfaces the driver's detailed asynchronous
error,
- # including errors on statements that produce no result
set.
- cursor.fetchall()
- except Error as ex:
- raise cls.get_dbapi_mapped_exception(ex) from ex
- return super().fetch_data(cursor, limit)
+ cursor.cancel_operation()
+ except TIME_LIMIT_EXCEPTIONS:
+ raise
+ except Exception: # pylint: disable=broad-except
+ logger.warning("cancel_operation() failed after a time limit")
+ raise
Review Comment:
I missed the proxy `_closed` and cleanup-RPC cases in my earlier replies.
This follow-up is in 2e1b2559617d4e5089b4d88bf1405f1ed972a0bd.
- `_LimitedCursor` forwards driver state writes to the real cursor,
including nested wrappers and the truncation probe. Abandonment clears the
operation handle and description as well as setting `_closed`, so cursor
close/finalization and later metadata/status/log reads send no further
operation RPCs.
- A second time limit or an unread/invalid reply during CancelOperation,
CloseOperation or CloseSession abandons the cursor and drops/resets the
transport instead of continuing cleanup. Cleanup failures are logged without
replacing the original time-limit exception. Stop/deadline cleanup uses the
same abandonment rule. A fully consumed error-status reply can still release
the handles.
- Hive polling/fetching also abandons interrupted operations. PyHive
connection close is made local-only before dropping the socket, so even an
interrupted local drop cannot cause a later CloseSession RPC on stale bytes.
Regression evidence (real buffered Thrift transports and locally served
HiveServer2 replies, not just mocked RPC order):
- Before, at 365c5e877d6cb893da2e2b590bed770a4c2c4c41: `pytest -q
tests/unit_tests/db_engine_specs/test_impala_transport.py -k 'row_limited or
time_limit_during_cleanup'` → **48 failed, 37 deselected**. Failures included
`TTransportException: read timeout` while closing the real cursor after an
interrupted reply.
- Before: `pytest -q
tests/unit_tests/db_engine_specs/test_hive_transport.py` → **12 failed**.
Separately, `-k test_connection_close_sends_no_rpc_after_an_interrupted_reply`
→ **4 failed, 24 deselected**, with the traceback inside PyHive
`Connection.close` → `recv_CloseSession`, reading stale bytes.
- After, at 2e1b2559617d4e5089b4d88bf1405f1ed972a0bd:
`test_impala_transport.py` → **175 passed**; `test_hive_transport.py` → **28
passed**. The expanded cases include
`test_row_limited_fetch_sends_nothing_after_a_skipped_cancel`,
`test_time_limit_during_cleanup_abandons_the_cursor`,
`test_failed_stop_cleanup_rpc_abandons_the_cursor`,
`test_cleanup_sends_nothing_after_an_interrupted_reply`,
`test_connection_close_sends_no_rpc_after_an_interrupted_reply`, and
`test_failed_transport_drop_preserves_timeout_and_disables_session_close`. They
exercise both SoftTimeLimitExceeded and SupersetTimeoutException,
status/log/row interruptions, binary/SASL PLAIN/HTTP for impyla, and
binary/SASL PLAIN for PyHive. The original exception's identity and the last
RPC received are asserted.
Compatibility suites at the same commit: `test_impala.py` 61 passed;
`test_impala_pending.py` 42 passed; `test_hive.py` 29 passed; `test_base.py`
147 passed; `test_presto.py` 135 passed; `test_executor.py` 280 passed. Total:
897 passed.
All pytest commands used `PYTHONPATH=$PWD/superset-core/src:$PWD` and
deselected `manual` and `llm_compliance`. Pre-commit, including mypy, passed on
the staged changes; branch-file checks also passed.
Siblings checked:
- superset/db_engine_specs/impala.py:140,167,203,344,370 — changed: fetch,
poll/status/log, deadline and Stop cleanup abandon interrupted operations; no
retry after a cleanup limit. Real transport tests cover CancelOperation,
CloseOperation and CloseSession. Abandonment clears the real operation handle
and cached description so metadata/status/log calls cannot use it afterwards.
- superset/sql/execution/executor.py:208,231,385,922,1648 — changed:
row-limit and truncation wrappers forward driver writes to the real cursor; the
enclosing closing(real_cursor) therefore sees abandonment. Nested wrapper
regression plus real row/probe interrupted replies.
- superset/db_engine_specs/hive.py:200,220,460,469 — changed: poll/log/row
time limits clear the operation and replace PyHive connection.close with local
transport close before dropping the socket. Tests isolate Connection.close as
well as cursor close, including a failed or interrupted local drop.
- superset/sql_lab.py:369,375,905 — not affected independently: delegates
fetch/execute/poll to the changed specs, wraps the resulting time limit, and
its cancellation fallback opens a fresh connection, not the interrupted cursor
transport. Cursor cleanup is exercised through closing(real_cursor) in the
transport regressions.
- superset/models/core.py:725,837 — not affected independently:
get_raw_connection defaults to NullPool and closes the DB-API connection; the
changed Hive helper makes that close local-only, and impyla HS2Service.close
(installed impala/hiveserver2.py:1272) closes only its transport.
- superset/db_engine_specs/base.py:144,1624,2067,2101 — not affected
independently: defines the two time-limit classes; base fetch only
reads/converts rows and maps exceptions, and base handle_cursor is a no-op. The
driver wrappers reach the changed spec handlers; Base tests pass.
- superset/db_engine_specs/presto.py:1400,1415 — not affected: Presto uses
HTTP JSON polling and cursor.cancel, not HiveServer2 Thrift reply buffers or
impyla cleanup; its fetch caller still dispatches through cls.fetch_data.
Presto tests pass.
- superset/db_engine_specs/trino.py:331,410,500 — not affected: Trino cursor
polling/cancellation uses the Trino HTTP client, not the impyla/PyHive
HiveServer2 transport or a cursor proxy.
- superset/db_engine_specs/ocient.py:322,383 — not affected: pyocient row
conversion and query-ID mapping; no HiveServer2 cleanup or attribute proxy.
- superset/db_engine_specs/exasol.py:165 — not affected: only converts rows
returned by Base.fetch_data; no cleanup RPC/proxy.
- superset/db_engine_specs/mssql.py:194 — not affected: only converts pyodbc
rows returned by Base.fetch_data; no cleanup RPC/proxy.
- superset/db_engine_specs/crate.py:99 — not affected: converts timestamp
values from CrateDB HTTP results; no HiveServer2 transport/cleanup.
- superset/db_engine_specs/datastore.py:319 — not affected: converts Google
Datastore row values; no HiveServer2 transport/cleanup.
- superset/db_engine_specs/drill.py:187 — not affected: special-cases a
RuntimeError for empty Drill results; no HiveServer2 cleanup or proxy.
- superset/db_engine_specs/bigquery.py:416,509 — not affected: BigQuery
progressive row fetching and Base fallback; no impyla/PyHive cleanup or proxy.
- superset/db_engine_specs/elasticsearch.py:70,146,274,392 — not affected:
Elasticsearch/OpenDistro close uses an HTTP perform_request with a pagination
token, not a Thrift cursor/transport/proxy.
- superset/db_engine_specs/postgres.py:115 — not affected: psycopg
connection-validation cursor close after SELECT version(); not HiveServer2.
- superset/db_engine_specs/redshift.py:44,430 — not affected: one match is a
release comment; executable close follows PostgreSQL pg_cancel_backend SQL, not
HiveServer2.
- superset/db_engine_specs/databend.py:424 — not affected: module-level
__getattr__ is a backwards-compatible engine-class alias, not a cursor-state
proxy. No other cursor proxy exists in db_engine_specs (rg
class/attribute-delegation search).
- superset/db_engine_specs/clickhouse.py:722,837,936 — not affected:
port-error text, inherited Base.handle_cursor, and a race-condition comment; no
HiveServer2 reply/cleanup path.
- superset/db_engine_specs/mysql.py:156,158,164,172,180,211 — not affected:
fail-closed TLS policy names/comments, not cursor close/reconnect.
- superset/db_engine_specs/doris.py:149 — not affected: TLS fail-closed
comment, not cursor close.
- superset/db_engine_specs/duckdb.py:48 — not affected: close=y in an
authentication URL, not cursor cleanup.
- superset/db_engine_specs/databricks.py:722 — not affected: closed-port
error message, not cursor cleanup.
- superset/db_engine_specs/couchbase.py:271 — not affected: closed-port
error message, not cursor cleanup.
Remaining: real Impala server acceptance, coordinator admission-slot/session
release, and LDAP/GSSAPI security-layer negotiation were not rerun here. When
cleanup is abandoned, server-side handles remain subject to Impala/Hive
query/session timeouts; these tests do not establish server-side release.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]