Configure fair queue by default, its faster.
authorfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Thu, 23 Apr 2009 14:40:16 +0000 (14:40 +0000)
committerfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Thu, 23 Apr 2009 14:40:16 +0000 (14:40 +0000)
Implement logic around when/how connections are treated as abandoned.
First one is by pool utilization, abandonWhenPercentageFull, the second one is to add a ResetAbandonTimer interceptor, so when successful invokations take place on the connection, it resets the time

git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@767934 13f79535-47bb-0310-9956-ffa450edef68

modules/jdbc-pool/doc/jdbc-pool.xml
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSource.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractQueryReport.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/ResetAbandonedTimer.java [new file with mode: 0644]
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java
modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java

index 27880ce..84cf4ea 100644 (file)
          This flag is required when you want to use asynchronous connection retrieval.
       </p>
     </attribute>
+
+    <attribute name="abandonWhenPercentageFull" required="false">
+      <p>(int) Connections that have been abandoned (timed out) wont get closed and reported up unless
+         the number of connections in use are above the percentage defined by <code>abandonWhenPercentageFull</code>.
+         The value should be between 0-100.
+         The default value is <code>0</code>, which implies that connections are eligible for closure as soon
+         as <code>removeAbandonedTimeout</code> has been reached.</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.
     <attributes>
     </attributes>
   </subsection>
+  <subsection name="org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer">
+    <p>
+        The abandoned timer starts when a connection is checked out from the pool.
+        This means if you have a 30second timeout and run 10x10second queries using the connection
+        it will be marked abandoned and potentially reclaimed depending on the <code>abandonWhenPercentageFull</code>
+        attribute. 
+        Using this interceptor it will reset the checkout timer every time you perform an operation on the connection or execute a 
+        query successfully.
+    </p>   
+    <attributes>
+    </attributes>
+  </subsection>
 </section>
 
 <section name="Code Example">
index 2cea90d..f5a39a2 100644 (file)
@@ -654,9 +654,19 @@ public class ConnectionPool {
         } //end if
     } //checkIn
 
+    public 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;
+    }
+    
     public void checkAbandoned() {
         try {
             if (busy.size()==0) return;
+            if (!shouldAbandon()) return;
             Iterator<PooledConnection> locked = busy.iterator();
             while (locked.hasNext()) {
                 PooledConnection con = locked.next();
index 94b84a6..65eb82d 100644 (file)
@@ -374,6 +374,14 @@ public class DataSource extends DataSourceProxy implements MBeanRegistration,jav
         }
     }
 
+    public int getAbandonWhenPercentageFull() {
+        try {
+            return createPool().getPoolProperties().getAbandonWhenPercentageFull();
+        }catch (SQLException x) {
+            throw new RuntimeException(x);
+        }
+    }
+
     public boolean isTestOnBorrow() {
         try {
             return createPool().getPoolProperties().isTestOnBorrow();
index d78388b..ac09e20 100644 (file)
@@ -94,6 +94,7 @@ public class DataSourceFactory implements ObjectFactory {
     protected final static String PROP_REMOVEABANDONED = "removeAbandoned";
     protected final static String PROP_REMOVEABANDONEDTIMEOUT = "removeAbandonedTimeout";
     protected final static String PROP_LOGABANDONED = "logAbandoned";
+    protected final static String PROP_ABANDONWHENPERCENTAGEFULL = "abandonWhenPercentageFull";
     
     protected final static String PROP_POOLPREPAREDSTATEMENTS = "poolPreparedStatements";
     protected final static String PROP_MAXOPENPREPAREDSTATEMENTS = "maxOpenPreparedStatements";
@@ -147,7 +148,8 @@ public class DataSourceFactory implements ObjectFactory {
         PROP_JMX_ENABLED,
         PROP_FAIR_QUEUE,
         PROP_USE_EQUALS,
-        OBJECT_NAME
+        OBJECT_NAME,
+        PROP_ABANDONWHENPERCENTAGEFULL
     };
 
     // -------------------------------------------------- ObjectFactory Methods
@@ -409,9 +411,13 @@ public class DataSourceFactory implements ObjectFactory {
         if (value != null) {
             poolProperties.setName(ObjectName.quote(value));
         }
-
-        return poolProperties;
         
+        value = properties.getProperty(PROP_ABANDONWHENPERCENTAGEFULL);
+        if (value != null) {
+            poolProperties.setAbandonWhenPercentageFull(Integer.parseInt(value));
+        }
+        
+        return poolProperties;
     }
 
     /**
index 760d347..37e01d2 100644 (file)
@@ -67,12 +67,23 @@ public class PoolProperties {
     protected boolean jmxEnabled = true;
     protected String initSQL;
     protected boolean testOnConnect =false;
-    private String jdbcInterceptors=null;
-    private boolean fairQueue = true;
-    private boolean useEquals = false;
+    protected String jdbcInterceptors=null;
+    protected boolean fairQueue = true;
+    protected boolean useEquals = false;
+    protected int abandonWhenPercentageFull = 0;
 
     private InterceptorDefinition[] interceptors = null;
     
+    public void setAbandonWhenPercentageFull(int percentage) {
+        if (percentage<0) abandonWhenPercentageFull = 0;
+        else if (percentage>100) abandonWhenPercentageFull = 100;
+        else abandonWhenPercentageFull = percentage;
+    }
+    
+    public int getAbandonWhenPercentageFull() {
+        return abandonWhenPercentageFull;
+    }
+    
     public boolean isFairQueue() {
         return fairQueue;
     }
index fe8b26e..46b1763 100644 (file)
@@ -51,7 +51,6 @@ public abstract class AbstractQueryReport extends AbstractCreateStatementInterce
         super();
     }
     
-    
     /**
      * Invoked when prepareStatement has been called and completed.
      * @param sql - the string used to prepare the statement with
diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/ResetAbandonedTimer.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/ResetAbandonedTimer.java
new file mode 100644 (file)
index 0000000..fd0f567
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ *  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.pool.interceptor;
+
+import java.lang.reflect.Method;
+
+import org.apache.tomcat.jdbc.pool.JdbcInterceptor;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+import org.apache.tomcat.jdbc.pool.ProxyConnection;
+
+/**
+ * Class that resets the abandoned timer on any activity on the 
+ * Connection or any successful query executions
+ * @author fhanik
+ *
+ */
+public class ResetAbandonedTimer extends AbstractQueryReport {
+
+    public ResetAbandonedTimer() {
+        // TODO Auto-generated constructor stub
+    }
+    
+    public boolean resetTimer() {
+        boolean result = false;
+        JdbcInterceptor interceptor = this.getNext();
+        while (interceptor!=null && result==false) {
+            if (interceptor instanceof ProxyConnection) {
+                PooledConnection con = ((ProxyConnection)interceptor).getConnection();
+                if (con!=null) {
+                    con.setTimestamp(System.currentTimeMillis());
+                    result = true;
+                } else {
+                    break;
+                }
+            }
+            interceptor = interceptor.getNext();
+        }
+        return result;
+    }
+    
+    
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        // TODO Auto-generated method stub
+        Object result = super.invoke(proxy, method, args);
+        resetTimer();
+        return result;
+    }
+
+    @Override
+    protected void prepareCall(String query, long time) {
+        resetTimer();
+    }
+
+    @Override
+    protected void prepareStatement(String sql, long time) {
+        resetTimer();
+
+    }
+
+    @Override
+    public void closeInvoked() {
+        resetTimer();
+    }
+
+    @Override
+    protected String reportQuery(String query, Object[] args, String name,long start, long delta) {
+        resetTimer();
+        return super.reportQuery(query, args, name, start, delta);
+    }
+
+    @Override
+    protected String reportSlowQuery(String query, Object[] args, String name,long start, long delta) {
+        resetTimer();
+        return super.reportSlowQuery(query, args, name, start, delta);
+    }
+}
index a658d98..cdc18a1 100644 (file)
@@ -273,5 +273,8 @@ public class ConnectionPool extends NotificationBroadcasterSupport implements Co
     public int getWaitCount() {
         return pool.getWaitCount();
     }
+    public int getAbandonWhenPercentageFull() {
+        return pool.getPoolProperties().getAbandonWhenPercentageFull();
+    }
 
 }