/**
* 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.
*/
package org.apache.hadoop.hive.ql.exec.tez;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
public class InterruptibleProcessing {
private final static Logger LOG = LoggerFactory.getLogger(InterruptibleProcessing.class);
private static final int CHECK_INTERRUPTION_AFTER_ROWS_DEFAULT = 1000,
CHECK_INTERRUPTION_AFTER_ROWS_MAX = 100000, CHECK_INTERRUPTION_AFTER_ROWS_MIN = 1;
private static final double TARGET_INTERRUPT_CHECK_TIME_NS = 3 * 1000000000.0;
private int checkInterruptionAfterRows = CHECK_INTERRUPTION_AFTER_ROWS_DEFAULT;
private long lastInterruptCheckNs = 0L;
private int nRows;
private volatile boolean isAborted;
// Methods should really be protected, but some places have to use this as a field.
public final void startAbortChecks() {
lastInterruptCheckNs = System.nanoTime();
nRows = 0;
}
public final void addRowAndMaybeCheckAbort() throws InterruptedException {
if (nRows++ < checkInterruptionAfterRows) return;
long time = System.nanoTime();
checkAbortCondition();
long elapsedNs = (time - lastInterruptCheckNs);
if (elapsedNs >= 0) {
// Make sure we don't get stuck at 0 time, however unlikely that is.
double diff = elapsedNs == 0 ? 10 : TARGET_INTERRUPT_CHECK_TIME_NS / elapsedNs;
int newRows = Math.min(CHECK_INTERRUPTION_AFTER_ROWS_MAX,
Math.max(CHECK_INTERRUPTION_AFTER_ROWS_MIN, (int) (diff * checkInterruptionAfterRows)));
if (checkInterruptionAfterRows != newRows && LOG.isDebugEnabled()) {
LOG.debug("Adjusting abort check rows to " + newRows
+ " from " + checkInterruptionAfterRows);
}
checkInterruptionAfterRows = newRows;
}
nRows = 0;
lastInterruptCheckNs = time;
}
public final void checkAbortCondition() throws InterruptedException {
boolean isInterrupted = Thread.currentThread().isInterrupted();
if (!isAborted && !isInterrupted) return;
// Not cleaning the interrupt status.
throw new InterruptedException("Processing thread aborted. Interrupt state: " + isInterrupted);
}
public final void setAborted(boolean b) {
this.isAborted = b;
}
public void abort() {
setAborted(true);
}
public final boolean isAborted() {
return this.isAborted;
}
}