Repository: commons-dbcp
Updated Branches:
  refs/heads/master 51124f92b -> afc2d3ddd


DBCP-513 create a unit test to reproduce the issue

This is a timing glitch. So it's sometimes not easy to reproduce it.
On my box (12 core Ryzen 2600X) it happens every second test run.
It might have another behaviour depending on cpu cores.
The higher the core count, the more likely it hangs obviously.


Project: http://git-wip-us.apache.org/repos/asf/commons-dbcp/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-dbcp/commit/f36ff599
Tree: http://git-wip-us.apache.org/repos/asf/commons-dbcp/tree/f36ff599
Diff: http://git-wip-us.apache.org/repos/asf/commons-dbcp/diff/f36ff599

Branch: refs/heads/master
Commit: f36ff599a7670c025010ed7d86ea0fbda7e26bee
Parents: 51124f9
Author: Mark Struberg <strub...@apache.org>
Authored: Tue Oct 23 20:21:07 2018 +0200
Committer: Mark Struberg <strub...@apache.org>
Committed: Tue Oct 23 20:21:07 2018 +0200

----------------------------------------------------------------------
 .../dbcp2/TestParallelCreationWithNoIdle.java   | 146 +++++++++++++++++++
 1 file changed, 146 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/f36ff599/src/test/java/org/apache/commons/dbcp2/TestParallelCreationWithNoIdle.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/commons/dbcp2/TestParallelCreationWithNoIdle.java 
b/src/test/java/org/apache/commons/dbcp2/TestParallelCreationWithNoIdle.java
new file mode 100644
index 0000000..6d7367a
--- /dev/null
+++ b/src/test/java/org/apache/commons/dbcp2/TestParallelCreationWithNoIdle.java
@@ -0,0 +1,146 @@
+package org.apache.commons.dbcp2;
+
+import org.apache.commons.logging.LogFactory;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test if the pooling if no idle objects are used
+ */
+public class TestParallelCreationWithNoIdle  {
+
+
+    protected BasicDataSource ds = null;
+    private static final String CATALOG = "test catalog";
+
+    @BeforeClass
+    public static void setUpClass() {
+        // register a custom logger which supports inspection of the log 
messages
+        LogFactory.getFactory().setAttribute("org.apache.commons.logging.Log", 
"org.apache.commons.dbcp2.StackMessageLog");
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        ds = new BasicDataSource();
+        
ds.setDriverClassName("org.apache.commons.dbcp2.TesterConnectionDelayDriver");
+        ds.setUrl("jdbc:apache:commons:testerConnectionDelayDriver:50");
+        ds.setMaxTotal(10);
+
+        // this one is actually very important.
+        // see DBCP-513
+        ds.setMaxIdle(0);
+
+        // wait a minute. Usually the test runs in ~ 1 second
+        // but often it's getting stuck ^^
+        // you have one second to get a thread dump ;)
+        ds.setMaxWaitMillis(60000);
+
+        ds.setDefaultAutoCommit(Boolean.TRUE);
+        ds.setDefaultReadOnly(Boolean.FALSE);
+        
ds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
+        ds.setDefaultCatalog(CATALOG);
+        ds.setUsername("userName");
+        ds.setPassword("password");
+        ds.setValidationQuery("SELECT DUMMY FROM DUAL");
+        ds.setConnectionInitSqls(Arrays.asList(new String[] { "SELECT 1", 
"SELECT 2"}));
+        ds.setDriverClassLoader(new TesterClassLoader());
+        ds.setJmxName("org.apache.commons.dbcp2:name=test");
+    }
+
+    /**
+     * Fire up 100 Threads but only have 10 maxActive and forcedBlock.
+     * See
+     * @throws Exception
+     */
+    @Test
+    public void testMassiveConcurrentInitBorrow() throws Exception {
+        final int numThreads = 200;
+        
ds.setDriverClassName("org.apache.commons.dbcp2.TesterConnectionDelayDriver");
+        ds.setUrl("jdbc:apache:commons:testerConnectionDelayDriver:20");
+        ds.setInitialSize(8);
+        final List<Throwable> errors = Collections.synchronizedList(new 
ArrayList<>());
+
+        Thread[] threads = new Thread[numThreads];
+        for (int i = 0; i < numThreads; i++) {
+            threads[i] = new TestThread(2, 0, 50);
+            threads[i].setUncaughtExceptionHandler((t, e) -> errors.add(e));
+        }
+
+        for (int i = 0; i < numThreads; i++) {
+            threads[i].start();
+
+            if (i%4 == 0) {
+                Thread.sleep(20);
+            }
+        }
+
+        for (int i = 0; i < numThreads; i++) {
+            threads[i].join();
+        }
+
+        assertEquals(0, errors.size());
+        ds.close();
+    }
+
+
+
+    class TestThread extends Thread {
+        java.util.Random _random = new java.util.Random();
+        final int iter;
+        final int delay;
+        final int delayAfter;
+
+
+        public TestThread(final int iter, final int delay, final int 
delayAfter) {
+            this.iter = iter;
+            this.delay = delay;
+            this.delayAfter = delayAfter;
+        }
+
+
+        @Override
+        public void run() {
+            System.out.println("Thread started " + 
Thread.currentThread().toString());
+            for(int i = 0; i< iter; i++) {
+                sleepMax(delay);
+                try (Connection conn = ds.getConnection();
+                     PreparedStatement stmt = conn.prepareStatement(
+                             "select 'literal', SYSDATE from dual");
+                     ) {
+                    System.out.println("Got Connection " + 
Thread.currentThread().toString());
+                    ResultSet rset = stmt.executeQuery();
+                    rset.next();
+                    sleepMax(delayAfter);
+                    rset.close();
+                } catch(final Exception e) {
+                    e.printStackTrace();
+                    throw new RuntimeException(e);
+                }
+            }
+            System.out.println("Thread done " + 
Thread.currentThread().toString());
+        }
+
+        private void sleepMax(int timeMax) {
+            if (timeMax == 0) {
+                return;
+            }
+            try {
+                Thread.sleep(_random.nextInt(timeMax));
+            } catch(final Exception e) {
+                // ignored
+            }
+        }
+    }
+
+}

Reply via email to