Author: kkolinko
Date: Fri Mar 22 21:33:35 2013
New Revision: 1460006

URL: http://svn.apache.org/r1460006
Log:
Merged revision 1459769 from tomcat/trunk:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=54732
Fix leak of statements in StatementCache interceptor.
Based on patch by Bertrand Guay-Paquet (BZ 54732) / Patric Rufflar (BZ 54337)

Added:
    
tomcat/tc7.0.x/trunk/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCounterInterceptor.java
      - copied unchanged from r1459769, 
tomcat/trunk/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCounterInterceptor.java
Modified:
    tomcat/tc7.0.x/trunk/   (props changed)
    
tomcat/tc7.0.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java
    
tomcat/tc7.0.x/trunk/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestStatementCache.java
    tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml

Propchange: tomcat/tc7.0.x/trunk/
------------------------------------------------------------------------------
  Merged /tomcat/trunk:r1459769

Modified: 
tomcat/tc7.0.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java?rev=1460006&r1=1460005&r2=1460006&view=diff
==============================================================================
--- 
tomcat/tc7.0.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java
 (original)
+++ 
tomcat/tc7.0.x/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java
 Fri Mar 22 21:33:35 2013
@@ -245,11 +245,11 @@ public class StatementCache extends Stat
                     removeStatement(proxy);
                 }
             }
-            closed = true;
-            delegate = null;
             if (shouldClose) {
                 super.closeInvoked();
             }
+            closed = true;
+            delegate = null;
 
         }
 

Modified: 
tomcat/tc7.0.x/trunk/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestStatementCache.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestStatementCache.java?rev=1460006&r1=1460005&r2=1460006&view=diff
==============================================================================
--- 
tomcat/tc7.0.x/trunk/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestStatementCache.java
 (original)
+++ 
tomcat/tc7.0.x/trunk/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestStatementCache.java
 Fri Mar 22 21:33:35 2013
@@ -16,6 +16,7 @@
  */
 package org.apache.tomcat.jdbc.test;
 
+import java.lang.reflect.Proxy;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 
@@ -23,7 +24,9 @@ import org.junit.After;
 import org.junit.Assert;
 import org.junit.Test;
 
+import org.apache.tomcat.jdbc.pool.JdbcInterceptor;
 import org.apache.tomcat.jdbc.pool.interceptor.StatementCache;
+import org.apache.tomcat.jdbc.pool.interceptor.StatementCounterInterceptor;
 
 public class TestStatementCache extends DefaultTestCase {
 
@@ -108,6 +111,55 @@ public class TestStatementCache extends 
     }
 
     @Test
+    public void testStatementClose1() throws Exception {
+        init();
+        datasource.setJdbcInterceptors(
+                TestStatementCacheInterceptor.class.getName()
+                + "(prepared=true,callable=false,max=1);"
+                + StatementCounterInterceptor.class.getName());
+        Connection con = datasource.getConnection();
+        StatementCounterInterceptor counter = findInterceptor(con, 
StatementCounterInterceptor.class);
+        PreparedStatement ps1, ps2;
+
+        ps1 = con.prepareStatement("select 1");
+        Assert.assertEquals(1, counter.getActiveCount());
+        ps1.close();
+        Assert.assertEquals("Statement goes into cache, not closed", 1, 
counter.getActiveCount());
+
+        ps1 = con.prepareStatement("select 1");
+        Assert.assertEquals("Reusing statement from cache", 1, 
counter.getActiveCount());
+        ps2 = con.prepareStatement("select 1");
+        Assert.assertEquals("Reusing statement from cache", 2, 
counter.getActiveCount());
+
+        ps2.close();
+        Assert.assertEquals("Statement goes into cache, not closed", 2, 
counter.getActiveCount());
+        ps1.close();
+        // Cache has "max=1". The following tests BZ 54732.
+        Assert.assertEquals("Statement does not go into cache, closed", 1, 
counter.getActiveCount());
+
+        con.close();
+        Assert.assertEquals("Connection returned to the pool. Statement is in 
cache", 1, counter.getActiveCount());
+
+        datasource.close();
+        Assert.assertEquals("Pool cleared. All statements in cache are 
closed", 0, counter.getActiveCount());
+    }
+
+    @Test
+    public void testStatementClose2() throws Exception {
+        init();
+        datasource.setJdbcInterceptors(
+                TestStatementCacheInterceptor.class.getName()
+                + "(prepared=false,callable=false,max=10);"
+                + StatementCounterInterceptor.class.getName());
+        Connection con = datasource.getConnection();
+        StatementCounterInterceptor counter = findInterceptor(con, 
StatementCounterInterceptor.class);
+        PreparedStatement ps1 = con.prepareStatement("select 1");
+        Assert.assertEquals(1, counter.getActiveCount());
+        ps1.close();
+        Assert.assertEquals("Statement is not pooled, closes immediately", 0, 
counter.getActiveCount());
+    }
+
+    @Test
     public void testMaxCacheSize() throws Exception {
         init();
         config(true,false,100);
@@ -127,4 +179,27 @@ public class TestStatementCache extends 
             TestStatementCache.interceptor = this;
         }
     }
+
+    /**
+     * Helper method that finds interceptor instance in interceptor chain of a
+     * proxied class.
+     *
+     * @param proxy
+     *            Proxy class
+     * @param clazz
+     *            Interceptor class that we are looking for
+     * @return Instance of <code>clazz</code>
+     */
+    private static <T extends JdbcInterceptor> T findInterceptor(Object proxy,
+            Class<T> clazz) {
+        JdbcInterceptor interceptor = (JdbcInterceptor) Proxy
+                .getInvocationHandler(proxy);
+        while (interceptor != null) {
+            if (clazz.isInstance(interceptor)) {
+                return clazz.cast(interceptor);
+            }
+            interceptor = interceptor.getNext();
+        }
+        return null;
+    }
 }

Modified: tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml?rev=1460006&r1=1460005&r2=1460006&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Fri Mar 22 21:33:35 2013
@@ -65,6 +65,10 @@
         Fix minor threading issue in <code>ConnectionPool</code>.
         (markt/kkolinko)
       </fix>
+      <fix>
+        <bug>54732</bug>: Fix leak of statements in <code>StatementCache</code>
+        interceptor. (kkolinko)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Other">



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to