Core: Fix background thread leak in ScanTaskIterable#16768
Core: Fix background thread leak in ScanTaskIterable#16768sejal-gupta-ksolves wants to merge 1 commit into
Conversation
|
At present, In StarRocks FE deployment, when a query is cancelled or times out during the DeployScanRanges / scan-planning phase, close() can be invoked? |
07f4e38 to
be101a2
Compare
|
@chenwyi2 Yes, During query planning and range deployment, StarRocks processes the file splits via Iceberg's Because this patch unifies the cleanup paths by having the iterator directly delegate to |
70f17fc to
a9100e3
Compare
|
but when i test the case, kill the query and use jstack, see the thread, ScanTaskIterable is still not closed. 2026-06-16 16:53:22.901+08:00 INFO (starrocks-mysql-nio-pool-0|166) [StmtExecutor] execute Exception, sql: SELECT * FROM xxx, error: killed manually: KILL QUERY 16777572 "iceberg_catalog-sr-iceberg-worker-pool-0" #775 daemon prio=5 os_prio=0 cpu=1518.93ms elapsed=33.72s tid=0x00007f47883b35e0 nid=0x85ccb runnable [0x00007f47709fe000] it seems that when killing the query, close() is not invoked automatically by StarRocks FE ? maybe i should cherry-pick StarRocks/starrocks#68678 this pr |
|
@chenwyi2 Thank you for the The thread dump confirms that StarRocks FE is not calling This Iceberg PR provides the framework to clean up those background pools, but it depends on the engine to trigger it. Cherry-picking that StarRocks PR to ensure |
|
@chenwyi2 seems like its explictly calls iterator close seems like starrocks is already calling the iterator close... i believe closing iterator is correct thing to do . |
a9100e3 to
d4e8aad
Compare
Fixes an issue where background PlanTaskWorker threads remain indefinitely blocked in offerWithTimeout() when a query is cancelled or abandoned early because the outer ScanTaskIterable.close() method was a no-op.
d4e8aad to
8a2f264
Compare
Closes: #16758
Problem
When downstream query engines (such as StarRocks, Trino, or Spark) cancel or abort a REST table scan early due to client disconnects, timeouts, or query limits, they trigger the cleanup sequence on the outer execution container.
In Apache Iceberg,
ScanTaskIterable.close()was implemented as an empty no-op method. Because this outerclose()call failed to cascade the shutdown signal to the underlying data structures:shutdownstate atomic flag remainedfalse.PlanTaskWorkerthreads continued running indefinitely.taskQueuereached its1000item capacity limit, all active worker threads became permanently deadlocked insideofferWithTimeout(), leading to thread pool exhaustion on the engine coordinator side.Solution
ScanTaskIterable.close()utilizingshutdown.compareAndSet(false, true).taskQueue,planTasks, andinitialFileScanTaskslists upon termination. This allows background threads stuck in anofferwait cycle to instantly unblock, evaluate the flipped shutdown state, and exit gracefully.ScanTasksIterator.close()block to eliminate redundant code duplication, rewriting it to delegate its cleanup tasks straight up toScanTaskIterable.this.close(). This ensures unified thread termination safety across all potential entry points.TestScanTaskIterableLeakunder theorg.apache.iceberg.resttest package, proving that active planning thread allocations successfully scale back down to0upon premature termination.Verification Testing