Skip to content

Commit 339cfe1

Browse files
committed
Daemonize query cancel scheduler thread (1.4)
This is a backport of the PR duckdb#505 to `v1.4-andium` stable branch. The implementation of `Statement#setQueryTimeout()` added in duckdb#247 uses a background thread to perform the query cancellation on timeout. Because that thread is not marked as "daemon" one, it can prevent JVM shutdown. This change makes the scheduler thread "daemon" and additionally exposes `DuckDBDriver#shutdownQueryCancelScheduler()` method that allows to shut down the scheduler manually. Testing: manual test added that checks that queries with timeout set can be executed (with timeout ineffective) after the scheduler is shut down. Fixes: duckdb#504
1 parent 3b401ee commit 339cfe1

File tree

3 files changed

+43
-3
lines changed

3 files changed

+43
-3
lines changed

src/main/java/org/duckdb/DuckDBDriver.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,14 @@ public class DuckDBDriver implements java.sql.Driver {
5454
static {
5555
try {
5656
DriverManager.registerDriver(new DuckDBDriver());
57-
ThreadFactory tf = r -> new Thread(r, "duckdb-query-cancel-scheduler-thread");
57+
ThreadFactory tf = new ThreadFactory() {
58+
@Override
59+
public Thread newThread(Runnable r) {
60+
Thread th = new Thread(r, "duckdb-query-cancel-scheduler-thread");
61+
th.setDaemon(true);
62+
return th;
63+
}
64+
};
5865
scheduler = new ScheduledThreadPoolExecutor(1, tf);
5966
scheduler.setRemoveOnCancelPolicy(true);
6067
} catch (SQLException e) {
@@ -242,6 +249,14 @@ public static boolean releaseDB(String url) throws SQLException {
242249
}
243250
}
244251

252+
public static boolean shutdownQueryCancelScheduler() {
253+
if (scheduler.isShutdown()) {
254+
return false;
255+
}
256+
scheduler.shutdown();
257+
return true;
258+
}
259+
245260
private static DriverPropertyInfo createDriverPropInfo(String name, String value, String description) {
246261
DriverPropertyInfo dpi = new DriverPropertyInfo(name, value);
247262
dpi.description = description;

src/main/java/org/duckdb/DuckDBPreparedStatement.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import java.util.ArrayList;
3939
import java.util.Calendar;
4040
import java.util.List;
41+
import java.util.concurrent.RejectedExecutionException;
4142
import java.util.concurrent.ScheduledFuture;
4243
import java.util.concurrent.locks.Lock;
4344
import java.util.concurrent.locks.ReentrantLock;
@@ -187,8 +188,14 @@ public boolean execute() throws SQLException {
187188

188189
if (queryTimeoutSeconds > 0) {
189190
cleanupCancelQueryTask();
190-
cancelQueryFuture =
191-
DuckDBDriver.scheduler.schedule(new CancelQueryTask(), queryTimeoutSeconds, SECONDS);
191+
try {
192+
if (!DuckDBDriver.scheduler.isShutdown()) {
193+
cancelQueryFuture =
194+
DuckDBDriver.scheduler.schedule(new CancelQueryTask(), queryTimeoutSeconds, SECONDS);
195+
}
196+
} catch (RejectedExecutionException e) {
197+
// no-op, scheduler was shut down concurrently
198+
}
192199
}
193200

194201
resultRef = DuckDBNative.duckdb_jdbc_execute(stmtRef, params);

src/test/java/org/duckdb/TestClosure.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,4 +322,22 @@ public static void test_stmt_query_timeout() throws Exception {
322322
assertEquals(DuckDBDriver.scheduler.getQueue().size(), 0);
323323
}
324324
}
325+
326+
public static void manual_test_set_query_timeout_wo_scheduler() throws Exception {
327+
assertTrue(DuckDBDriver.shutdownQueryCancelScheduler());
328+
assertFalse(DuckDBDriver.shutdownQueryCancelScheduler());
329+
try (Connection conn = DriverManager.getConnection(JDBC_URL); Statement stmt = conn.createStatement()) {
330+
stmt.setQueryTimeout(1);
331+
stmt.execute("CREATE TABLE test_fib1(i bigint, p double, f double)");
332+
stmt.execute("INSERT INTO test_fib1 values(1, 0, 1)");
333+
long start = System.currentTimeMillis();
334+
stmt.executeQuery(
335+
"WITH RECURSIVE cte AS ("
336+
+
337+
"SELECT * from test_fib1 UNION ALL SELECT cte.i + 1, cte.f, cte.p + cte.f from cte WHERE cte.i < 50000) "
338+
+ "SELECT avg(f) FROM cte");
339+
long elapsed = System.currentTimeMillis() - start;
340+
assertTrue(elapsed > 1500);
341+
}
342+
}
325343
}

0 commit comments

Comments
 (0)