You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by fh...@apache.org on 2011/11/29 01:05:44 UTC

svn commit: r1207712 - in /tomcat/trunk/modules/jdbc-pool: doc/jdbc-pool.xml src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java src/test/java/org/apache/tomcat/jdbc/test/PoolCleanerTest.java

Author: fhanik
Date: Tue Nov 29 00:05:43 2011
New Revision: 1207712

URL: http://svn.apache.org/viewvc?rev=1207712&view=rev
Log:
Conserve threads by allowing multiple pools in the same classloader to share a pool cleaner thread

Added:
    tomcat/trunk/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/PoolCleanerTest.java   (with props)
Modified:
    tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml
    tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java

Modified: tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml?rev=1207712&r1=1207711&r2=1207712&view=diff
==============================================================================
--- tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml (original)
+++ tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml Tue Nov 29 00:05:43 2011
@@ -281,7 +281,8 @@
       <p>(int) The number of milliseconds to sleep between runs of the idle connection validation/cleaner thread.
          This value should not be set under 1 second. It dictates how often we check for idle, abandoned connections, and how often
          we validate idle connections.
-         The default value is <code>5000</code> (5 seconds).</p>
+         The default value is <code>5000</code> (5 seconds). <br/>
+      </p>
     </attribute>
 
     <attribute name="numTestsPerEvictionRun" required="false">
@@ -816,6 +817,9 @@
         ant test      (runs tests, expects a test database to be setup)
       </source>
     </p>
+    <p>
+      The system is structured for a Maven build, but does generate release artifacts. Just the library itself.    
+    </p>
   </subsection>
 </section>
 </body>

Modified: tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java?rev=1207712&r1=1207711&r2=1207712&view=diff
==============================================================================
--- tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java (original)
+++ tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java Tue Nov 29 00:05:43 2011
@@ -21,8 +21,14 @@ import java.lang.reflect.InvocationHandl
 import java.lang.reflect.Proxy;
 import java.sql.Connection;
 import java.sql.SQLException;
+import java.util.Collections;
 import java.util.ConcurrentModificationException;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.CountDownLatch;
@@ -785,13 +791,12 @@ public class ConnectionPool {
     protected boolean terminateTransaction(PooledConnection con) {
         try {
             if (con.getPoolProperties().getDefaultAutoCommit()==Boolean.FALSE) {
-                boolean autocommit = con.getConnection().getAutoCommit();
-                if (!autocommit) {
-                    if (this.getPoolProperties().getRollbackOnReturn()) {
-                        con.getConnection().rollback();
-                    } else if (this.getPoolProperties().getCommitOnReturn()) {
-                        con.getConnection().commit();
-                    }
+                if (this.getPoolProperties().getRollbackOnReturn()) {
+                    boolean autocommit = con.getConnection().getAutoCommit();
+                    if (!autocommit) con.getConnection().rollback();
+                } else if (this.getPoolProperties().getCommitOnReturn()) {
+                    boolean autocommit = con.getConnection().getAutoCommit();
+                    if (!autocommit) con.getConnection().commit();
                 }
             }
             return true;
@@ -1185,14 +1190,54 @@ public class ConnectionPool {
         }
 
     }
+    
+    
+
+    private static volatile Timer poolCleanTimer = null;
+    private static HashSet<PoolCleaner> cleaners = new HashSet<PoolCleaner>();
+
+    private static synchronized void registerCleaner(PoolCleaner cleaner) {
+        unregisterCleaner(cleaner);
+        cleaners.add(cleaner);
+        if (poolCleanTimer == null) {
+            poolCleanTimer = new Timer("PoolCleaner["
+                    + System.identityHashCode(ConnectionPool.class
+                            .getClassLoader()) + ":"
+                    + System.currentTimeMillis() + "]", true);
+        }
+        poolCleanTimer.scheduleAtFixedRate(cleaner, cleaner.sleepTime,
+                cleaner.sleepTime);
+    }
+
+    private static synchronized void unregisterCleaner(PoolCleaner cleaner) {
+        boolean removed = cleaners.remove(cleaner);
+        if (removed) {
+            cleaner.cancel();
+            if (poolCleanTimer != null) {
+                poolCleanTimer.purge();
+                if (cleaners.size() == 0) {
+                    poolCleanTimer.cancel();
+                    poolCleanTimer = null;
+                }
+            }
+        }
+    }
+    
+    public static Set<TimerTask> getPoolCleaners() {
+        return Collections.<TimerTask>unmodifiableSet(cleaners);
+    }
+    
+    public static Timer getPoolTimer() {
+        return poolCleanTimer;
+    }
 
-    protected class PoolCleaner extends Thread {
+    protected class PoolCleaner extends TimerTask {
         protected ConnectionPool pool;
         protected long sleepTime;
         protected volatile boolean run = true;
+        protected volatile long lastRun = 0;
+
         PoolCleaner(String name, ConnectionPool pool, long sleepTime) {
-            super(name);
-            this.setDaemon(true);
             this.pool = pool;
             this.sleepTime = sleepTime;
             if (sleepTime <= 0) {
@@ -1205,37 +1250,32 @@ public class ConnectionPool {
 
         @Override
         public void run() {
-            while (run) {
+            if (pool.isClosed()) {
+                if (pool.getSize() <= 0) {
+                    run = false;
+                }
+            } else if ((System.currentTimeMillis() - lastRun) > sleepTime) {
+                lastRun = System.currentTimeMillis();
                 try {
-                    sleep(sleepTime);
-                } catch (InterruptedException e) {
-                    // ignore it
-                    Thread.interrupted();
-                    continue;
-                } //catch
+                    if (pool.getPoolProperties().isRemoveAbandoned())
+                        pool.checkAbandoned();
+                    if (pool.getPoolProperties().getMinIdle() < pool.idle
+                            .size())
+                        pool.checkIdle();
+                    if (pool.getPoolProperties().isTestWhileIdle())
+                        pool.testAllIdle();
+                } catch (Exception x) {
+                    log.error("", x);
+                } // catch
+            } // end if
+        } // run
 
-                if (pool.isClosed()) {
-                    if (pool.getSize() <= 0) {
-                        run = false;
-                    }
-                } else {
-                    try {
-                        if (pool.getPoolProperties().isRemoveAbandoned())
-                            pool.checkAbandoned();
-                        if (pool.getPoolProperties().getMinIdle()<pool.idle.size())
-                            pool.checkIdle();
-                        if (pool.getPoolProperties().isTestWhileIdle())
-                            pool.testAllIdle();
-                    } catch (Exception x) {
-                        log.error("", x);
-                    } //catch
-                } //end if
-            } //while
-        } //run
+        public void start() {
+            registerCleaner(this);
+        }
 
         public void stopRunning() {
-            run = false;
-            interrupt();
+            unregisterCleaner(this);
         }
     }
 }

Added: tomcat/trunk/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/PoolCleanerTest.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/PoolCleanerTest.java?rev=1207712&view=auto
==============================================================================
--- tomcat/trunk/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/PoolCleanerTest.java (added)
+++ tomcat/trunk/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/PoolCleanerTest.java Tue Nov 29 00:05:43 2011
@@ -0,0 +1,66 @@
+package org.apache.tomcat.jdbc.test;
+
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.DataSource;
+
+public class PoolCleanerTest extends DefaultTestCase {
+
+    public PoolCleanerTest(String name) {
+        super(name);
+    }
+    
+    public void testPoolCleaner() throws Exception {
+        datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(2000);
+        datasource.getPoolProperties().setTestWhileIdle(true);
+        assertEquals("Pool cleaner should not be started yet.",0,ConnectionPool.getPoolCleaners().size() );
+        assertNull("Pool timer should be null", ConnectionPool.getPoolTimer());
+        
+        datasource.getConnection().close();
+        assertEquals("Pool cleaner should have 1 cleaner.",1,ConnectionPool.getPoolCleaners().size() );
+        assertNotNull("Pool timer should not be null", ConnectionPool.getPoolTimer());
+        
+        datasource.close();
+        assertEquals("Pool shutdown, no cleaners should be present.",0,ConnectionPool.getPoolCleaners().size() );
+        assertNull("Pool timer should be null after shutdown", ConnectionPool.getPoolTimer());
+    }
+
+    public void test2PoolCleaners() throws Exception {
+        datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(2000);
+        datasource.getPoolProperties().setTestWhileIdle(true);
+        
+        DataSource ds2 = new DataSource(datasource.getPoolProperties());
+        
+        assertEquals("Pool cleaner should not be started yet.",0,ConnectionPool.getPoolCleaners().size() );
+        assertNull("Pool timer should be null", ConnectionPool.getPoolTimer());
+        
+        datasource.getConnection().close();
+        ds2.getConnection().close();
+        assertEquals("Pool cleaner should have 2 cleaner.",2,ConnectionPool.getPoolCleaners().size() );
+        assertNotNull("Pool timer should not be null", ConnectionPool.getPoolTimer());
+        
+        datasource.close();
+        assertEquals("Pool cleaner should have 1 cleaner.",1,ConnectionPool.getPoolCleaners().size() );
+        assertNotNull("Pool timer should not be null", ConnectionPool.getPoolTimer());
+
+        ds2.close();
+        assertEquals("Pool shutdown, no cleaners should be present.",0,ConnectionPool.getPoolCleaners().size() );
+        assertNull("Pool timer should be null after shutdown", ConnectionPool.getPoolTimer());
+    }
+    
+    public void testIdleTimeout() throws Exception {
+        datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(2000);
+        datasource.getPoolProperties().setTestWhileIdle(true);
+        datasource.getPoolProperties().setMaxIdle(0);
+        datasource.getPoolProperties().setInitialSize(0);
+        datasource.getPoolProperties().setMinIdle(0);
+        datasource.getPoolProperties().setMinEvictableIdleTimeMillis(1000);
+        datasource.getConnection().close();
+        assertEquals("Pool should have 1 idle.", 1, datasource.getIdle());
+        Thread.sleep(3000);
+        assertEquals("Pool should have 0 idle.", 0, datasource.getIdle());
+        
+        
+    }
+    
+    
+}

Propchange: tomcat/trunk/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/PoolCleanerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org