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-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org