[ 
https://issues.apache.org/jira/browse/HIVE-30245?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Denys Kuzmenko updated HIVE-30245:
----------------------------------
    Description: 
HIVE-27899 makes a task attempt wait for the AM's permission to commit before 
it closes its outputs:
{code:java}
while (!getContext().canCommit()) {
  Thread.sleep(500);
}
{code}
The wait ends only when canCommit() returns true or the sleep throws 
InterruptedException. A killed attempt is no longer running, so canCommit() 
stays false, and the kill's interrupt is the only way out.

A kill (TezTaskRunner2: a kill request, a preemption, a shutdown) first aborts 
the processor and then interrupts the task thread once. If run() consumes that 
interrupt and returns because of the abort, the attempt enters the wait with no 
interrupt pending and never leaves it. In LLAP it keeps its executor until the 
daemon restarts. The query itself succeeds, so nothing fails; the cluster just 
has fewer executors.

h3. How it happens
Observed on TPC-DS 10 TB (Parquet on S3, LLAP, Hadoop 3.4.3, the native Parquet 
cache of HIVE-30059):
# LLAP preempts a running Map attempt. TezTaskRunner2 aborts it, then 
interrupts it.
# The thread is reading a Parquet footer through the native cache 
(LlapParquetIoImpl.getFooterBuffersFromCache <- 
ParquetEncodedDataReader.readFooter) on the S3A analytics stream, the default 
since Hadoop 3.4.3.
# analytics-accelerator-s3 1.3.1 (Block.awaitData) catches the 
InterruptedException and throws IOException("Error while reading data. Read 
interrupted while waiting for data"), without restoring the interrupt flag.
# ParquetColumnVectorProducer catches the IOException and falls back to the 
normal reader ("Parquet native cache: falling back to normal reader").
# run() returns on the abort, and the attempt sits in the canCommit loop 
forever, while TezTaskRunner2 logs "returning canCommit=false since task is not 
in a running state" twice a second.

After one run of the 99 queries, 17 of 144 executors were held this way, all of 
them q16 Map attempts sleeping in TezProcessor.initializeAndRunProcessor. After 
another run, 22 were held.

Any code that swallows an interrupt during run() leads to the same state, so 
the wait must not depend on the interrupt alone.

h3. Fix
The processor is marked aborted before the kill interrupts it. The wait now 
checks that too: an aborted attempt throws InterruptedException("Aborted while 
waiting to commit"). That is the same path a delivered interrupt takes: the 
record processor is aborted and closed, the outputs are aborted, and nothing is 
committed.

h3. Test
TestTezProcessor#testKilledTaskStopsWaitingToCommit: canCommit() returns false, 
and run() aborts the processor and returns without an interrupt. Without the 
fix the test times out; with it, initializeAndRunProcessor throws 
InterruptedException.


> TezProcessor: a killed task attempt whose interrupt was consumed waits 
> forever to commit
> ----------------------------------------------------------------------------------------
>
>                 Key: HIVE-30245
>                 URL: https://issues.apache.org/jira/browse/HIVE-30245
>             Project: Hive
>          Issue Type: Bug
>            Reporter: Denys Kuzmenko
>            Priority: Major
>
> HIVE-27899 makes a task attempt wait for the AM's permission to commit before 
> it closes its outputs:
> {code:java}
> while (!getContext().canCommit()) {
>   Thread.sleep(500);
> }
> {code}
> The wait ends only when canCommit() returns true or the sleep throws 
> InterruptedException. A killed attempt is no longer running, so canCommit() 
> stays false, and the kill's interrupt is the only way out.
> A kill (TezTaskRunner2: a kill request, a preemption, a shutdown) first 
> aborts the processor and then interrupts the task thread once. If run() 
> consumes that interrupt and returns because of the abort, the attempt enters 
> the wait with no interrupt pending and never leaves it. In LLAP it keeps its 
> executor until the daemon restarts. The query itself succeeds, so nothing 
> fails; the cluster just has fewer executors.
> h3. How it happens
> Observed on TPC-DS 10 TB (Parquet on S3, LLAP, Hadoop 3.4.3, the native 
> Parquet cache of HIVE-30059):
> # LLAP preempts a running Map attempt. TezTaskRunner2 aborts it, then 
> interrupts it.
> # The thread is reading a Parquet footer through the native cache 
> (LlapParquetIoImpl.getFooterBuffersFromCache <- 
> ParquetEncodedDataReader.readFooter) on the S3A analytics stream, the default 
> since Hadoop 3.4.3.
> # analytics-accelerator-s3 1.3.1 (Block.awaitData) catches the 
> InterruptedException and throws IOException("Error while reading data. Read 
> interrupted while waiting for data"), without restoring the interrupt flag.
> # ParquetColumnVectorProducer catches the IOException and falls back to the 
> normal reader ("Parquet native cache: falling back to normal reader").
> # run() returns on the abort, and the attempt sits in the canCommit loop 
> forever, while TezTaskRunner2 logs "returning canCommit=false since task is 
> not in a running state" twice a second.
> After one run of the 99 queries, 17 of 144 executors were held this way, all 
> of them q16 Map attempts sleeping in TezProcessor.initializeAndRunProcessor. 
> After another run, 22 were held.
> Any code that swallows an interrupt during run() leads to the same state, so 
> the wait must not depend on the interrupt alone.
> h3. Fix
> The processor is marked aborted before the kill interrupts it. The wait now 
> checks that too: an aborted attempt throws InterruptedException("Aborted 
> while waiting to commit"). That is the same path a delivered interrupt takes: 
> the record processor is aborted and closed, the outputs are aborted, and 
> nothing is committed.
> h3. Test
> TestTezProcessor#testKilledTaskStopsWaitingToCommit: canCommit() returns 
> false, and run() aborts the processor and returns without an interrupt. 
> Without the fix the test times out; with it, initializeAndRunProcessor throws 
> InterruptedException.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to