Skip to content
Permalink
Browse files

[CONJ-672] Batch using multi-send can hang when using query timeout

(cherry picked from commit 272de14)
  • Loading branch information...
rusher committed Jan 10, 2019
1 parent 6c36108 commit 89fbb60ffe915c737ca48e8113e0431457e0a12c
Showing with 128 additions and 129 deletions.
  1. +128 −129 src/test/java/org/mariadb/jdbc/CancelTest.java
@@ -52,157 +52,156 @@

package org.mariadb.jdbc;

import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.sql.*;
import java.sql.BatchUpdateException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLTimeoutException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;

public class CancelTest extends BaseTest {


@Before
public void cancelSupported() throws SQLException {
requireMinimumVersion(5, 0);
Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null);
@Before
public void cancelSupported() throws SQLException {
requireMinimumVersion(5, 0);
Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null);
}

@Test
public void cancelTest() {
Assume.assumeFalse(sharedIsAurora());
try (Connection tmpConnection = openNewConnection(connUri, new Properties())) {

Statement stmt = tmpConnection.createStatement();
ExecutorService exec = Executors.newFixedThreadPool(1);
//check blacklist shared
exec.execute(new CancelThread(stmt));
stmt.execute(
"select * from information_schema.columns as c1, information_schema.tables, information_schema.tables as t2");

//wait for thread endings
exec.shutdown();
Assert.fail();
} catch (SQLException e) {
//normal exception
}

@Test
public void cancelTest() throws SQLException {
Assume.assumeFalse(sharedIsAurora());
Connection tmpConnection = null;
try {
tmpConnection = openNewConnection(connUri, new Properties());

Statement stmt = tmpConnection.createStatement();
ExecutorService exec = Executors.newFixedThreadPool(1);
//check blacklist shared
exec.execute(new CancelThread(stmt));
stmt.execute("select * from information_schema.columns as c1, information_schema.tables, information_schema.tables as t2");

//wait for thread endings
exec.shutdown();
Assert.fail();
} catch (SQLException e) {
//normal exception
} finally {
if (tmpConnection != null) tmpConnection.close();
}
}

@Test(timeout = 20000, expected = SQLTimeoutException.class)
public void timeoutSleep() throws Exception {
Assume.assumeFalse(sharedIsAurora());
try (Connection tmpConnection = openNewConnection(connUri, new Properties())) {
Statement stmt = tmpConnection.createStatement();
stmt.setQueryTimeout(1); //query take more than 20 seconds (local DB)
stmt.execute(
"select * from information_schema.columns as c1, information_schema.tables, information_schema.tables as t2");
}

@Test(timeout = 20000, expected = SQLTimeoutException.class)
public void timeoutSleep() throws Exception {
Assume.assumeFalse(sharedIsAurora());
Connection tmpConnection = null;
try {
tmpConnection = openNewConnection(connUri, new Properties());
Statement stmt = tmpConnection.createStatement();
stmt.setQueryTimeout(1); //query take more than 20 seconds (local DB)
stmt.execute("select * from information_schema.columns as c1, information_schema.tables, information_schema.tables as t2");
} finally {
tmpConnection.close();
}
}

@Test(timeout = 20000, expected = SQLTimeoutException.class)
public void timeoutPrepareSleep() throws Exception {
Assume.assumeFalse(sharedIsAurora());
try (Connection tmpConnection = openNewConnection(connUri, new Properties())) {
try (PreparedStatement stmt = tmpConnection.prepareStatement(
"select * from information_schema.columns as c1, information_schema.tables, information_schema.tables as t2")) {
stmt.setQueryTimeout(1); //query take more than 20 seconds (local DB)
stmt.execute();
}
}

@Test(timeout = 20000, expected = SQLTimeoutException.class)
public void timeoutPrepareSleep() throws Exception {
Assume.assumeFalse(sharedIsAurora());
Connection tmpConnection = null;
try {
tmpConnection = openNewConnection(connUri, new Properties());
PreparedStatement stmt = tmpConnection.prepareStatement(
"select * from information_schema.columns as c1, information_schema.tables, information_schema.tables as t2");
stmt.setQueryTimeout(1); //query take more than 20 seconds (local DB)
stmt.execute();
} finally {
tmpConnection.close();
}
}

@Test(timeout = 5000, expected = BatchUpdateException.class)
public void timeoutBatch() throws Exception {
Assume.assumeFalse(sharedIsAurora());
Assume.assumeTrue(!sharedOptions().allowMultiQueries && !sharedIsRewrite());
createTable("timeoutBatch", "aa text");

Statement stmt = sharedConnection.createStatement();
char[] arr = new char[1000];
Arrays.fill(arr, 'a');
String str = String.valueOf(arr);
for (int i = 0; i < 20000; i++) {
stmt.addBatch("INSERT INTO timeoutBatch VALUES ('" + str + "')");
}

@Test(timeout = 5000, expected = BatchUpdateException.class)
public void timeoutBatch() throws Exception {
Assume.assumeFalse(sharedIsAurora());
Assume.assumeTrue(!sharedOptions().allowMultiQueries && !sharedIsRewrite());
createTable("timeoutBatch", "aa text");

Statement stmt = sharedConnection.createStatement();
char[] arr = new char[1000];
Arrays.fill(arr, 'a');
String str = String.valueOf(arr);
stmt.setQueryTimeout(1);
stmt.executeBatch();
}

@Test(timeout = 5000)
public void timeoutPrepareBatch() throws Exception {
Assume.assumeFalse(sharedIsAurora());
Assume.assumeTrue(!sharedOptions().allowMultiQueries && !sharedIsRewrite());
Assume.assumeTrue(!(sharedOptions().useBulkStmts && isMariadbServer() && minVersion(10, 2)));
createTable("timeoutBatch", "aa text");
try (Connection tmpConnection = openNewConnection(connUri, new Properties())) {
char[] arr = new char[1000];
Arrays.fill(arr, 'a');
String str = String.valueOf(arr);
try (PreparedStatement stmt = tmpConnection
.prepareStatement("INSERT INTO timeoutBatch VALUES (?)")) {
stmt.setQueryTimeout(1);
for (int i = 0; i < 20000; i++) {
stmt.addBatch("INSERT INTO timeoutBatch VALUES ('" + str + "')");
stmt.setString(1, str);
stmt.addBatch();
}
stmt.setQueryTimeout(1);
stmt.executeBatch();
}

@Test(timeout = 5000, expected = BatchUpdateException.class)
public void timeoutPrepareBatch() throws Exception {
Assume.assumeFalse(sharedIsAurora());
Assume.assumeTrue(!sharedOptions().allowMultiQueries && !sharedIsRewrite());
Assume.assumeTrue(!(sharedOptions().useBulkStmts && isMariadbServer() && minVersion(10,2)));
createTable("timeoutBatch", "aa text");
Connection tmpConnection = null;
try {
tmpConnection = openNewConnection(connUri, new Properties());


char[] arr = new char[1000];
Arrays.fill(arr, 'a');
String str = String.valueOf(arr);
PreparedStatement stmt = tmpConnection.prepareStatement("INSERT INTO timeoutBatch VALUES (?)");
stmt.setQueryTimeout(1);
for (int i = 0; i < 20000; i++) {
stmt.setString(1, str);
stmt.addBatch();
}
stmt.executeBatch();

} finally {
tmpConnection.close();
stmt.executeBatch();
Assert.fail();
} catch (BatchUpdateException b) {
ResultSet rs2 = stmt.executeQuery("SELECT 2");
assertTrue(rs2.next());
assertEquals("2", rs2.getString(1));
}
}
}

@Test
public void noTimeoutSleep() throws Exception {
Statement stmt = sharedConnection.createStatement();
stmt.setQueryTimeout(1);
stmt.execute("select sleep(0.5)");
}

@Test
public void noTimeoutSleep() throws Exception {
Statement stmt = sharedConnection.createStatement();
stmt.setQueryTimeout(1);
stmt.execute("select sleep(0.5)");
}

@Test
public void cancelIdleStatement() throws Exception {
Statement stmt = sharedConnection.createStatement();
stmt.cancel();
ResultSet rs = stmt.executeQuery("select 1");
assertTrue(rs.next());
assertEquals(rs.getInt(1), 1);
}

private static class CancelThread implements Runnable {

private final Statement stmt;

public CancelThread(Statement stmt) {
this.stmt = stmt;
}

@Test
public void cancelIdleStatement() throws Exception {
Statement stmt = sharedConnection.createStatement();
@Override
public void run() {
try {
Thread.sleep(100);
stmt.cancel();
ResultSet rs = stmt.executeQuery("select 1");
assertTrue(rs.next());
assertEquals(rs.getInt(1), 1);
}

private static class CancelThread implements Runnable {
private final Statement stmt;

public CancelThread(Statement stmt) {
this.stmt = stmt;
}

@Override
public void run() {
try {
Thread.sleep(100);
stmt.cancel();
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (SQLException | InterruptedException e) {
e.printStackTrace();
}
}
}
}

0 comments on commit 89fbb60

Please sign in to comment.
You can’t perform that action at this time.