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

rmaucher pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 728f86f60e836ed016eb05ab5b461d19ababf010
Author: opencode <[email protected]>
AuthorDate: Thu Nov 5 15:23:04 2026 +0100

    Do not book queries into a released statistics store
    
    SlowQueryReport.getQueryStats() read the cached queries map directly and 
did not consult the store's released flag. After close(false), a connection 
still borrowed by the application therefore kept recording query statistics 
into a store that the name view and the remaining MBean already read as absent.
    
    Check PoolStatistics.isReleased() before booking and take the existing 
lost-store path. Add a test that closes the pool with a connection still 
borrowed and asserts getQueryStats() returns null.
---
 .../jdbc/pool/interceptor/SlowQueryReport.java     |  6 ++++++
 ...estSlowQueryReportSlowLogAfterChainRelease.java | 25 ++++++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git 
a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java
 
b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java
index 054d16c85a..576b99905e 100644
--- 
a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java
+++ 
b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java
@@ -542,6 +542,12 @@ public class SlowQueryReport extends AbstractQueryReport {
             sql = "";
         }
         ConcurrentHashMap<String, QueryStats> queries = 
SlowQueryReport.this.queries;
+        PoolStatistics own = SlowQueryReport.this.poolStatistics;
+        if (own != null && own.isReleased()) {
+            // The pool closed while this session was still borrowed, so the
+            // store is no longer observable: do not book into it.
+            queries = null;
+        }
         if (queries == null) {
             if (reportClosedOrAbandoned() && log.isWarnEnabled()) {
                 
log.warn(MessageFactory.get("slowQueryReport.connectionClosedOrAbandoned"));
diff --git 
a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestSlowQueryReportSlowLogAfterChainRelease.java
 
b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestSlowQueryReportSlowLogAfterChainRelease.java
index 5c1e363eaa..7564854c38 100644
--- 
a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestSlowQueryReportSlowLogAfterChainRelease.java
+++ 
b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestSlowQueryReportSlowLogAfterChainRelease.java
@@ -136,6 +136,31 @@ class TestSlowQueryReportSlowLogAfterChainRelease extends 
JdbcPoolBaseTest {
         }
     }
 
+    @Test
+    void aBorrowedConnectionDoesNotBookIntoAReleasedStore() throws Exception {
+        String poolName = "SlowLogReleasedStore-" + System.nanoTime();
+        DataSource ds = newDataSource();
+        ds.setName(poolName);
+        ds.setJdbcInterceptors(SlowQueryReport.class.getName() + 
"(threshold=0)");
+        ds.getPoolProperties().setInitialSize(0);
+
+        Connection con = ds.getConnection();
+        SlowQueryReport report = interceptorOf(con, SlowQueryReport.class);
+        Assertions.assertNotNull(report, "the chain must hold the report 
instance");
+        try {
+            // close(false) leaves this borrowed session alive but releases
+            // the pool's statistics store.
+            ds.close(false);
+            Assertions.assertNull(SlowQueryReport.getPoolStats(poolName),
+                    "precondition: the closed pool has released its store");
+
+            Assertions.assertNull(report.getQueryStats("SELECT 
released-store"),
+                    "a session left alive by close(false) must not book into 
the released store");
+        } finally {
+            con.close();
+        }
+    }
+
     @Test
     void slowQueryWarnsAndNotifiesTogetherWhenTheStatisticsCannotBeResolved() 
throws Exception {
         String poolName = "SlowLogChannels-" + System.nanoTime();


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to