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>
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.
}
}
+ 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
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))) {
} //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;
}
--- /dev/null
+/*
+ * 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());
+ }
+}