You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ps...@apache.org on 2024/02/15 23:07:05 UTC

(commons-dbcp) branch master updated: Make BDS actually implement usage tracking. JIRA: DBCP-590.

This is an automated email from the ASF dual-hosted git repository.

psteitz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-dbcp.git


The following commit(s) were added to refs/heads/master by this push:
     new 4dd9df42 Make BDS actually implement usage tracking. JIRA: DBCP-590.
4dd9df42 is described below

commit 4dd9df42ffe0905c6fd74515017a22505ae863cf
Author: Phil Steitz <ph...@gmail.com>
AuthorDate: Thu Feb 15 16:06:54 2024 -0700

    Make BDS actually implement usage tracking. JIRA: DBCP-590.
---
 src/changes/changes.xml                            |  1 +
 .../org/apache/commons/dbcp2/BasicDataSource.java  |  4 +++
 .../apache/commons/dbcp2/PoolableConnection.java   | 12 +++++++
 .../commons/dbcp2/PoolableConnectionFactory.java   |  4 ++-
 .../dbcp2/TestAbandonedBasicDataSource.java        | 39 ++++++++++++++++++++++
 5 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 020237e7..481b515b 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -64,6 +64,7 @@ The <action> type attribute can be add,update,fix,remove.
   <body>
     <release version="2.11.1" date="2024-MM-DD" description="This is a minor release, including bug fixes and enhancements.">
       <!-- FIX -->
+      <action type="fix" issue="DBCP-590" dev="psteitz" due-to=" RĂ©da Housni Alaoui">BasicDataSource#setAbandonedUsageTracking has no effect.</action>
       <action type="fix" issue="DBCP-596" dev="ggregory" due-to="Aapo Haapanen, Gary Gregory">PoolingConnection.toString() causes StackOverflowError.</action>
       <!-- ADD -->
       <action type="add" dev="ggregory" due-to="Gary Gregory">Add property project.build.outputTimestamp for build reproducibility.</action>
diff --git a/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java b/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java
index 1fb8dac8..48b2fedb 100644
--- a/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java
+++ b/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java
@@ -483,6 +483,10 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
         updateJmxName(config);
         // Disable JMX on the underlying pool if the DS is not registered:
         config.setJmxEnabled(registeredJmxObjectName != null);
+        // Set up usage tracking if enabled
+        if (getAbandonedUsageTracking() && abandonedConfig != null) {
+            abandonedConfig.setUseUsageTracking(true);
+        }
         final GenericObjectPool<PoolableConnection> gop = createObjectPool(factory, config, abandonedConfig);
         gop.setMaxTotal(maxTotal);
         gop.setMaxIdle(maxIdle);
diff --git a/src/main/java/org/apache/commons/dbcp2/PoolableConnection.java b/src/main/java/org/apache/commons/dbcp2/PoolableConnection.java
index 9bc4059a..c99e789a 100644
--- a/src/main/java/org/apache/commons/dbcp2/PoolableConnection.java
+++ b/src/main/java/org/apache/commons/dbcp2/PoolableConnection.java
@@ -34,6 +34,7 @@ import javax.management.NotCompliantMBeanException;
 import javax.management.ObjectName;
 
 import org.apache.commons.pool2.ObjectPool;
+import org.apache.commons.pool2.impl.GenericObjectPool;
 
 /**
  * A delegating connection that, rather than closing the underlying connection, returns itself to an {@link ObjectPool}
@@ -333,6 +334,17 @@ public class PoolableConnection extends DelegatingConnection<Connection> impleme
         super.closeInternal();
     }
 
+    @Override
+    public void setLastUsed() {
+        super.setLastUsed();
+        if (pool instanceof GenericObjectPool<?>) {
+            final GenericObjectPool<PoolableConnection> gop = (GenericObjectPool<PoolableConnection>) pool;
+            if (gop.isAbandonedConfig()) {
+                gop.use(this);
+            }
+        }
+    }
+
     /**
      * Validates the connection, using the following algorithm:
      * <ol>
diff --git a/src/main/java/org/apache/commons/dbcp2/PoolableConnectionFactory.java b/src/main/java/org/apache/commons/dbcp2/PoolableConnectionFactory.java
index 297b4cba..51600251 100644
--- a/src/main/java/org/apache/commons/dbcp2/PoolableConnectionFactory.java
+++ b/src/main/java/org/apache/commons/dbcp2/PoolableConnectionFactory.java
@@ -467,7 +467,9 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
         final PoolableConnection pc = new PoolableConnection(conn, pool, connJmxName, disconnectionSqlCodes, fastFailValidation);
         pc.setCacheState(cacheState);
 
-        return new DefaultPooledObject<>(pc);
+        final DefaultPooledObject<PoolableConnection> pooledObject = new DefaultPooledObject<>(pc);
+        pooledObject.setRequireFullStackTrace(true); 
+        return pooledObject;
     }
 
     @Override
diff --git a/src/test/java/org/apache/commons/dbcp2/TestAbandonedBasicDataSource.java b/src/test/java/org/apache/commons/dbcp2/TestAbandonedBasicDataSource.java
index 8b1d9287..dbd2b929 100644
--- a/src/test/java/org/apache/commons/dbcp2/TestAbandonedBasicDataSource.java
+++ b/src/test/java/org/apache/commons/dbcp2/TestAbandonedBasicDataSource.java
@@ -389,4 +389,43 @@ public class TestAbandonedBasicDataSource extends TestBasicDataSource {
             checkLastUsedStatement(st, conn);
         }
     }
+
+    @Test
+    public void testAbandonedStackTraces() throws Exception {
+        // force abandoned
+        ds.setRemoveAbandonedTimeout(Duration.ZERO);
+        ds.setMaxTotal(1);
+        ds.setAccessToUnderlyingConnectionAllowed(true);
+        ds.setAbandonedUsageTracking(true);
+
+        try (Connection conn1 = getConnection()) {
+            assertNotNull(conn1);
+            assertEquals(1, ds.getNumActive());
+            // Use the connection
+            try (Statement stmt = conn1.createStatement()) {
+                assertNotNull(stmt);
+                stmt.execute("SELECT 1 FROM DUAL");
+            }
+
+            try (Connection conn2 = getConnection()) {
+                // Attempt to borrow object triggers abandoned cleanup
+                // conn1 should be closed by the pool to make room
+                assertNotNull(conn2);
+                assertEquals(1, ds.getNumActive());
+                // Verify that conn1 is closed
+                assertTrue(((DelegatingConnection<?>) conn1).getInnermostDelegate().isClosed());
+                // Verify that conn1 is aborted
+                final TesterConnection tCon = (TesterConnection) ((DelegatingConnection<?>) conn1)
+                        .getInnermostDelegate();
+                assertTrue(tCon.isAborted());
+
+            }
+            assertEquals(0, ds.getNumActive());
+        }
+        assertEquals(0, ds.getNumActive());
+        final String stackTrace = sw.toString();
+        assertTrue(stackTrace.contains("testAbandonedStackTraces"), stackTrace);
+        assertTrue(stackTrace.contains("Pooled object created"), stackTrace);
+        assertTrue(stackTrace.contains("The last code to use this object was:"), stackTrace);
+    }
 }