diff --git common/src/java/org/apache/hadoop/hive/conf/HiveConf.java common/src/java/org/apache/hadoop/hive/conf/HiveConf.java index dcb383d..5fef80f 100644 --- common/src/java/org/apache/hadoop/hive/conf/HiveConf.java +++ common/src/java/org/apache/hadoop/hive/conf/HiveConf.java @@ -2248,6 +2248,10 @@ private static void populateLlapDaemonVarsSet(Set llapDaemonVarsSetLocal "partition columns or non-partition columns while displaying columns in describe\n" + "table. From 0.12 onwards, they are displayed separately. This flag will let you\n" + "get old behavior, if desired. See, test-case in patch for HIVE-6689."), + HIVE_COMPILE_TIMEOUT("hive.compile.timeout", "0s", + new TimeValidator(TimeUnit.SECONDS), + "Number of seconds a query will spend on compilation before it is cancelled. " + + "Use this to avoid long compilation time. Setting it to 0s disables the timeout."), HIVE_SSL_PROTOCOL_BLACKLIST("hive.ssl.protocol.blacklist", "SSLv2,SSLv3", "SSL Versions to disable for all Hive Servers"), diff --git ql/src/java/org/apache/hadoop/hive/ql/Driver.java ql/src/java/org/apache/hadoop/hive/ql/Driver.java index 79e95cf..03ec3d3 100644 --- ql/src/java/org/apache/hadoop/hive/ql/Driver.java +++ ql/src/java/org/apache/hadoop/hive/ql/Driver.java @@ -429,8 +429,18 @@ public int compile(String command, boolean resetTaskIds, boolean deferClose) { // Whether any error occurred during query compilation. Used for query lifetime hook. boolean compileError = false; + CompilationTimeoutThread compileTimeoutThread = null; try { + // Set up a timer thread to timeout the compilation + long timeoutSec = HiveConf.getTimeVar(conf, + ConfVars.HIVE_COMPILE_TIMEOUT, TimeUnit.SECONDS); + + if (timeoutSec > 0) { + compileTimeoutThread = new CompilationTimeoutThread(timeoutSec); + new Thread(compileTimeoutThread).start(); + } + // Initialize the transaction manager. This must be done before analyze is called. final HiveTxnManager txnManager = SessionState.get().initTxnMgr(conf); // In case when user Ctrl-C twice to kill Hive CLI JVM, we want to release locks @@ -600,6 +610,10 @@ public void run() { return error.getErrorCode();//todo: this is bad if returned as cmd shell exit // since it exceeds valid range of shell return values } finally { + if (compileTimeoutThread != null) { + compileTimeoutThread.stop(); + } + // Trigger post compilation hook. Note that if the compilation fails here then // before/after execution hook will never be executed. try { @@ -2442,4 +2456,38 @@ public void resetQueryState() { releaseResources(); this.queryState = new QueryState(queryState.getConf()); } + + private static class CompilationTimeoutThread implements Runnable { + private static final long INTERVAL_SECOND = 1; + private final long timeOutSec; + private final Thread threadToInterrupt; + private volatile boolean shouldStop; + + CompilationTimeoutThread(long timeoutSec) { + this.timeOutSec = timeoutSec; + this.threadToInterrupt = Thread.currentThread(); + this.shouldStop = false; + } + + @Override + public void run() { + long waitedSoFar = 0; + try { + while (!shouldStop && !Thread.currentThread().isInterrupted()) { + if (waitedSoFar >= timeOutSec) { + threadToInterrupt.interrupt(); + break; + } + Thread.sleep(INTERVAL_SECOND * 1000); + waitedSoFar += INTERVAL_SECOND; + } + } catch (InterruptedException e) { + // Do nothing + } + } + + void stop() { + this.shouldStop = true; + } + } }