This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 10.1.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 28330454939d646e3b10aa9608a5c15fdded05dc Author: opencode <[email protected]> AuthorDate: Thu Nov 5 16:24:14 2026 +0100 Create the cache counter for a late StatementCache definition cacheSizeMap was populated only by poolStarted. A StatementCache definition added to a running pool therefore built chains with a null cacheSize, refused every park and closed every statement, while still registering its JMX MBean. Create the pool's counter on the first reset that finds none, under the map's monitor. Add a test that adds the interceptor after pool creation, opens a new physical connection, parks a statement and checks both counters. --- .../jdbc/pool/interceptor/StatementCache.java | 7 +++++ .../TestStatementCacheJmxCacheSize.java | 31 ++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java index cce3f2404e..1407521711 100644 --- a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java @@ -269,6 +269,13 @@ public class StatementCache extends StatementDecoratorInterceptor implements Sta draining = false; synchronized (cacheSizeMap) { cacheSize = cacheSizeMap.get(parent); + if (cacheSize == null) { + // A definition added to a running pool did not exist when + // its start registered the counter; create it on the first + // borrow that builds a chain for the definition. + cacheSize = new AtomicInteger(0); + cacheSizeMap.put(parent, cacheSize); + } } this.pcon = con; if (!pcon.getAttributes().containsKey(STATEMENT_CACHE_ATTR)) { diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestStatementCacheJmxCacheSize.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestStatementCacheJmxCacheSize.java index 35a7b4454f..b4a7203ca0 100644 --- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestStatementCacheJmxCacheSize.java +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestStatementCacheJmxCacheSize.java @@ -84,6 +84,37 @@ class TestStatementCacheJmxCacheSize extends JdbcPoolBaseTest { return added; } + @Test + void aDefinitionAddedToARunningPoolGetsItsCounter() throws Exception { + DataSource ds = newDataSource(); + ds.getPoolProperties().setInitialSize(0); + ds.getPoolProperties().setMaxActive(2); + ds.getPoolProperties().setTimeBetweenEvictionRunsMillis(0); + ds.createPool(); + + // Hold a connection built before the definition is added, so the + // second borrow must create a physical connection and its chain. + Connection first = ds.getConnection(); + try { + ds.getPoolProperties().setJdbcInterceptors( + StatementCache.class.getName() + "(prepared=true,max=5)"); + try (Connection second = ds.getConnection()) { + StatementCache cache = interceptorOf(second, StatementCache.class); + Assertions.assertNotNull(cache, + "the new connection's chain must hold the added definition"); + PreparedStatement statement = second.prepareStatement("SELECT 1"); + statement.close(); + + Assertions.assertEquals(1, cache.getCacheSizePerConnection(), + "a statement closed on the new chain must be parked"); + Assertions.assertEquals(1, cache.getCacheSize(), + "the late definition must have obtained a cache-size counter"); + } + } finally { + first.close(); + } + } + @Test void theCacheSizeAttributeIsADescribedNumber() throws Exception { MBeanServer server = ManagementFactory.getPlatformMBeanServer(); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
