Author: fhanik Date: Thu Apr 30 19:41:07 2009 New Revision: 770411 URL: http://svn.apache.org/viewvc?rev=770411&view=rev Log: Add the following features - max age for a connection kept alive - an ability to reset the abandon timer when queries are executed - an abandoned test, abandon when a percentage of the pool has been utilized
Added: tomcat/trunk/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/AbandonPercentageTest.java (with props) Modified: tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSource.java tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.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=770411&r1=770410&r2=770411&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml (original) +++ tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml Thu Apr 30 19:41:07 2009 @@ -73,6 +73,15 @@ that has over 200 source files(last time we checked), Tomcat jdbc has a core of 8 files, the connection pool itself is about half that. As bugs may occur, they will be faster to track down, and easier to fix. Complexity reduction has been a focus from inception.</li> <li>Asynchronous connection retrieval - you can queue your request for a connection and receive a Future<Connection> back.</li> + <li>Better idle connection handling. Instead of closing connections directly, it can still pool connections and sizes the idle pool with a smarter algorithm.</li> + <li>You can decide at what moment connections are considered abandoned, is it when the pool is full, or directly at a timeout + by specifying a threshold. + </li> + <li>The abandon connection timer will reset upon a statement/query activity. Allowing a connections that is in use for a long time to not timeout. + This is achieved using the ResetAbandonedTimer + </li> + <li>Close connections after they have been connected for a certain time. Age based close upon return to the pool. + </li> </ol> </p> @@ -338,6 +347,14 @@ as <code>removeAbandonedTimeout</code> has been reached.</p> </attribute> + <attribute name="maxAge" required="false"> + <p>(long) Time in milliseconds to keep this connection. When a connection is returned to the pool, + the pool will check to see if the <code>now - time-when-connected > maxAge</code> has been reached, + and if so, it closes the connection rather than returning it to the pool. + The default value is <code>0</code>, which implies that connections will be left open and no age check + will be done upon returning the connection to the pool.</p> + </attribute> + <attribute name="useEquals" required="false"> <p>(boolean) Set to true if you wish the <code>ProxyConnection</code> class to use <code>String.equals</code> instead of <code>==</code> when comparing method names. This property does not apply to added interceptors as those are configured individually. Modified: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java?rev=770411&r1=770410&r2=770411&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java (original) +++ tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java Thu Apr 30 19:41:07 2009 @@ -609,6 +609,17 @@ } } + protected boolean shouldClose(PooledConnection con, int action) { + if (con.isDiscarded()) return true; + if (isClosed()) return true; + if (!con.validate(action)) return true; + if (getPoolProperties().getMaxAge()>0 ) { + return (System.currentTimeMillis()-con.getLastConnected()) > getPoolProperties().getMaxAge(); + } else { + return false; + } + } + /** * Returns a connection to the pool * @param con PooledConnection @@ -626,8 +637,8 @@ con.lock(); if (busy.remove(con)) { - if ((!con.isDiscarded()) && (!isClosed()) && - con.validate(PooledConnection.VALIDATE_RETURN)) { + + if (!shouldClose(con,PooledConnection.VALIDATE_RETURN)) { con.setStackTrace(null); con.setTimestamp(System.currentTimeMillis()); if (((idle.size()>=poolProperties.getMaxIdle()) && !poolProperties.isPoolSweeperEnabled()) || (!idle.offer(con))) { @@ -654,12 +665,11 @@ } //end if } //checkIn - public boolean shouldAbandon() { + protected boolean shouldAbandon() { if (poolProperties.getAbandonWhenPercentageFull()==0) return true; float used = (float)busy.size(); float max = (float)poolProperties.getMaxActive(); float perc = (float)poolProperties.getAbandonWhenPercentageFull(); - System.out.println("Abandon rate:"+(used/max*100f)); return (used/max*100f)>=perc; } Modified: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSource.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSource.java?rev=770411&r1=770410&r2=770411&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSource.java (original) +++ tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSource.java Thu Apr 30 19:41:07 2009 @@ -249,6 +249,14 @@ throw new RuntimeException(x); } } + + public long getMaxAge() { + try { + return createPool().getPoolProperties().getMaxAge(); + }catch (SQLException x) { + throw new RuntimeException(x); + } + } public String getName() { try { Modified: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java?rev=770411&r1=770410&r2=770411&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java (original) +++ tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java Thu Apr 30 19:41:07 2009 @@ -78,6 +78,7 @@ protected final static String PROP_MINIDLE = "minIdle"; protected final static String PROP_INITIALSIZE = "initialSize"; protected final static String PROP_MAXWAIT = "maxWait"; + protected final static String PROP_MAXAGE = "maxAge"; protected final static String PROP_TESTONBORROW = "testOnBorrow"; protected final static String PROP_TESTONRETURN = "testOnReturn"; @@ -149,7 +150,8 @@ PROP_FAIR_QUEUE, PROP_USE_EQUALS, OBJECT_NAME, - PROP_ABANDONWHENPERCENTAGEFULL + PROP_ABANDONWHENPERCENTAGEFULL, + PROP_MAXAGE }; // -------------------------------------------------- ObjectFactory Methods @@ -417,6 +419,11 @@ poolProperties.setAbandonWhenPercentageFull(Integer.parseInt(value)); } + value = properties.getProperty(PROP_MAXAGE); + if (value != null) { + poolProperties.setMaxAge(Long.parseLong(value)); + } + return poolProperties; } Modified: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java?rev=770411&r1=770410&r2=770411&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java (original) +++ tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java Thu Apr 30 19:41:07 2009 @@ -71,6 +71,7 @@ protected boolean fairQueue = true; protected boolean useEquals = false; protected int abandonWhenPercentageFull = 0; + protected long maxAge = 0; private InterceptorDefinition[] interceptors = null; @@ -523,4 +524,14 @@ this.useEquals = useEquals; } + public long getMaxAge() { + return maxAge; + } + + public void setMaxAge(long maxAge) { + this.maxAge = maxAge; + } + + + } Modified: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java?rev=770411&r1=770410&r2=770411&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java (original) +++ tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java Thu Apr 30 19:41:07 2009 @@ -86,6 +86,10 @@ */ protected boolean discarded = false; /** + * The Timestamp when the last time the connect() method was called successfully + */ + protected volatile long lastConnected = -1; + /** * timestamp to keep track of validation intervals */ protected long lastValidated = System.currentTimeMillis(); @@ -163,6 +167,7 @@ if (poolProperties.getDefaultTransactionIsolation()!=DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION) connection.setTransactionIsolation(poolProperties.getDefaultTransactionIsolation()); } this.discarded = false; + this.lastConnected = System.currentTimeMillis(); } /** @@ -193,6 +198,7 @@ } } connection = null; + lastConnected = -1; if (finalize) parent.finalize(this); } @@ -381,6 +387,12 @@ public java.sql.Connection getConnection() { return this.connection; } + + + + public long getLastConnected() { + return lastConnected; + } /** * Returns the first handler in the interceptor chain Modified: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java?rev=770411&r1=770410&r2=770411&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java (original) +++ tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java Thu Apr 30 19:41:07 2009 @@ -276,5 +276,8 @@ public int getAbandonWhenPercentageFull() { return pool.getPoolProperties().getAbandonWhenPercentageFull(); } + public long getMaxAge() { + return pool.getPoolProperties().getMaxAge(); + } } Modified: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java?rev=770411&r1=770410&r2=770411&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java (original) +++ tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java Thu Apr 30 19:41:07 2009 @@ -118,4 +118,6 @@ public int getAbandonWhenPercentageFull(); + public long getMaxAge(); + } Added: tomcat/trunk/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/AbandonPercentageTest.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/AbandonPercentageTest.java?rev=770411&view=auto ============================================================================== --- tomcat/trunk/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/AbandonPercentageTest.java (added) +++ tomcat/trunk/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/AbandonPercentageTest.java Thu Apr 30 19:41:07 2009 @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jdbc.test; + +import java.sql.Connection; +import java.sql.SQLException; + +import org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer; + +public class AbandonPercentageTest extends DefaultTestCase { + + public AbandonPercentageTest(String name) { + super(name); + } + + public void testDefaultAbandon() throws Exception { + this.init(); + this.datasource.setMaxActive(100); + this.datasource.setMaxIdle(100); + this.datasource.setInitialSize(0); + this.datasource.getPoolProperties().setAbandonWhenPercentageFull(0); + this.datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(100); + this.datasource.getPoolProperties().setRemoveAbandoned(true); + this.datasource.getPoolProperties().setRemoveAbandonedTimeout(1); + Connection con = datasource.getConnection(); + long start = System.currentTimeMillis(); + assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive()); + Thread.sleep(2000); + assertEquals("Number of connections active/busy should be 0",0,datasource.getPool().getActive()); + con.close(); + } + + public void testMaxedOutAbandon() throws Exception { + int size = 100; + this.init(); + this.datasource.setMaxActive(size); + this.datasource.setMaxIdle(size); + this.datasource.setInitialSize(0); + this.datasource.getPoolProperties().setAbandonWhenPercentageFull(100); + this.datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(100); + this.datasource.getPoolProperties().setRemoveAbandoned(true); + this.datasource.getPoolProperties().setRemoveAbandonedTimeout(1); + Connection con = datasource.getConnection(); + long start = System.currentTimeMillis(); + assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive()); + Thread.sleep(2000); + assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive()); + con.close(); + } + + public void testResetConnection() throws Exception { + int size = 1; + this.init(); + this.datasource.setMaxActive(size); + this.datasource.setMaxIdle(size); + this.datasource.setInitialSize(0); + this.datasource.getPoolProperties().setAbandonWhenPercentageFull(100); + this.datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(100); + this.datasource.getPoolProperties().setRemoveAbandoned(true); + this.datasource.getPoolProperties().setRemoveAbandonedTimeout(1); + this.datasource.getPoolProperties().setJdbcInterceptors(ResetAbandonedTimer.class.getName()); + Connection con = datasource.getConnection(); + long start = System.currentTimeMillis(); + assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive()); + for (int i=0; i<20; i++) { + Thread.sleep(200); + con.isClosed(); + } + assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive()); + con.close(); + } + + public void testHalfway() throws Exception { + int size = 100; + this.init(); + this.datasource.setMaxActive(size); + this.datasource.setMaxIdle(size); + this.datasource.setInitialSize(0); + this.datasource.getPoolProperties().setAbandonWhenPercentageFull(50); + this.datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(500); + this.datasource.getPoolProperties().setRemoveAbandoned(true); + this.datasource.getPoolProperties().setRemoveAbandonedTimeout(1); + Connection[] con = new Connection[size]; + con[0] = datasource.getConnection(); + long start = System.currentTimeMillis(); + assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive()); + for (int i=1; i<25; i++) { + con[i] = datasource.getConnection(); + } + assertEquals("Number of connections active/busy should be 25",25,datasource.getPool().getActive()); + Thread.sleep(2500); + assertEquals("Number of connections active/busy should be 25",25,datasource.getPool().getActive()); + for (int i=25; i<con.length; i++) { + con[i] = datasource.getConnection(); + } + int active = datasource.getPool().getActive(); + System.out.println("Active!:"+active); + assertEquals("Number of connections active/busy should be "+con.length,con.length,datasource.getPool().getActive()); + Thread.sleep(2500); + assertEquals("Number of connections active/busy should be 0",0,datasource.getPool().getActive()); + } +} Propchange: tomcat/trunk/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/AbandonPercentageTest.java ------------------------------------------------------------------------------ svn:eol-style = native --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org