diff --git a/src/test/java/com/zaxxer/hikari/pool/AddConnectionRaceConditionTest.java b/src/test/java/com/zaxxer/hikari/pool/AddConnectionRaceConditionTest.java new file mode 100644 index 00000000..b5728234 --- /dev/null +++ b/src/test/java/com/zaxxer/hikari/pool/AddConnectionRaceConditionTest.java @@ -0,0 +1,83 @@ +package com.zaxxer.hikari.pool; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.junit.Test; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; + +/** + * @author Matthew Tambara (matthew.tambara@liferay.com) + */ +public class AddConnectionRaceConditionTest +{ + private HikariPool _hikariPool; + + // @Test + public void testRaceCondition() throws Exception + { + HikariConfig config = new HikariConfig(); + config.setMinimumIdle(0); + config.setMaximumPoolSize(10); + config.setInitializationFailFast(false); + config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource"); + + // Initialize HikariPool with no initial connections and room to grow + try (final HikariDataSource ds = new HikariDataSource(config)) { + _hikariPool = TestElf.getPool(ds); + + ExecutorService threadPool = Executors.newFixedThreadPool(2); + for (int i = 0; i < 100000; i++) { + Future submit1 = threadPool.submit(new Callable() { + /** {@inheritDoc} */ + @Override + public Exception call() throws Exception + { + Connection c2; + try { + c2 = _hikariPool.getConnection(5000); + ds.evictConnection(c2); + } + catch (SQLException e) { + return e; + } + return null; + } + }); + + Future submit2 = threadPool.submit(new Callable() { + /** {@inheritDoc} */ + @Override + public Exception call() throws Exception + { + Connection c2; + try { + c2 = _hikariPool.getConnection(5000); + ds.evictConnection(c2); + } + catch (SQLException e) { + return e; + } + return null; + } + }); + + if (submit1.get() != null) { + throw submit1.get(); + } + if (submit2.get() != null) { + throw submit2.get(); + } + } + } + catch (Exception e) { + throw e; + } + } +} diff --git a/src/test/java/com/zaxxer/hikari/pool/TestConnectionTimeoutRetry.java b/src/test/java/com/zaxxer/hikari/pool/TestConnectionTimeoutRetry.java index 6ebe251c..e2172d91 100644 --- a/src/test/java/com/zaxxer/hikari/pool/TestConnectionTimeoutRetry.java +++ b/src/test/java/com/zaxxer/hikari/pool/TestConnectionTimeoutRetry.java @@ -1,5 +1,7 @@ package com.zaxxer.hikari.pool; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import java.sql.Connection; import java.sql.SQLException; import java.util.concurrent.Executors; @@ -9,6 +11,7 @@ import java.util.concurrent.TimeUnit; import org.junit.Assert; import org.junit.Test; +import com.sun.media.jfxmedia.logging.Logger; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.mocks.StubConnection; @@ -225,6 +228,12 @@ public class TestConnectionTimeoutRetry System.setProperty("com.zaxxer.hikari.housekeeping.periodMs", "400"); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos, true); + TestElf.setSlf4jTargetStream(HikariPool.class, ps); + TestElf.setSlf4jLogLevel(HikariPool.class, Logger.DEBUG); + + boolean success = false; try (HikariDataSource ds = new HikariDataSource(config)) { Connection connection1 = ds.getConnection(); Connection connection2 = ds.getConnection(); @@ -234,7 +243,7 @@ public class TestConnectionTimeoutRetry Connection connection6 = ds.getConnection(); Connection connection7 = ds.getConnection(); - Thread.sleep(2500); + Thread.sleep(900); Assert.assertSame("Total connections not as expected", 10, TestElf.getPool(ds).getTotalConnections()); Assert.assertSame("Idle connections not as expected", 3, TestElf.getPool(ds).getIdleConnections()); @@ -249,9 +258,14 @@ public class TestConnectionTimeoutRetry Assert.assertSame("Totals connections not as expected", 10, TestElf.getPool(ds).getTotalConnections()); Assert.assertSame("Idle connections not as expected", 10, TestElf.getPool(ds).getIdleConnections()); + success = true; } finally { + TestElf.setSlf4jLogLevel(HikariPool.class, Logger.INFO); System.getProperties().remove("com.zaxxer.hikari.housekeeping.periodMs"); + if (!success) { + System.err.println(new String(baos.toByteArray())); + } } } }