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&lt;Connection&gt; 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

Reply via email to