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 fd1d75aea2fa1be5bb51624e7c05761da7ce4366 Author: opencode <[email protected]> AuthorDate: Thu Nov 5 12:04:26 2026 +0100 Correct negative idle counts at pool creation checkPoolConfiguration clamped a negative initialSize to zero but stored a negative minIdle or maxIdle unchanged. A negative maxIdle made every return destroy its connection when the sweeper was off, because idle.size() >= maxIdle is always true, and a negative minIdle removed the idle floor. Clamp both idle counts to zero with a warning, before the existing minIdle/maxIdle relation repairs run, and add a regression test. --- .../java/org/apache/tomcat/jdbc/pool/ConnectionPool.java | 8 ++++++++ .../apache/tomcat/jdbc/pool/util/LocalStrings.properties | 2 ++ .../tomcat/jdbc/pool/TestPoolSizeSetterValidation.java | 16 ++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java index 2c9acdf9d7..0246f238fc 100644 --- a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java @@ -1116,6 +1116,14 @@ public class ConnectionPool { log.warn(MessageFactory.get("connectionPool.initialSizeTooSmall")); properties.setInitialSize(0); } + if (properties.getMinIdle() < 0) { + log.warn(MessageFactory.get("connectionPool.minIdleNegative")); + properties.setMinIdle(0); + } + if (properties.getMaxIdle() < 0) { + log.warn(MessageFactory.get("connectionPool.maxIdleNegative")); + properties.setMaxIdle(0); + } if (properties.getMaxActive() < properties.getInitialSize()) { log.warn(MessageFactory.get("connectionPool.initialSizeTooLarge", properties.getMaxActive())); properties.setInitialSize(properties.getMaxActive()); diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/util/LocalStrings.properties b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/util/LocalStrings.properties index 61fbde92c7..10c627c76c 100644 --- a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/util/LocalStrings.properties +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/util/LocalStrings.properties @@ -54,7 +54,9 @@ connectionPool.initialSizeTooSmall=initialSize is negative, setting initialSize connectionPool.interceptorChainHasNoProxyConnection=The configured interceptor chain does not end in a ProxyConnection; the pooled connection cannot be armed for a borrow and is taken out of service. connectionPool.maxActiveTooSmall=maxActive is smaller than 1, setting maxActive to: {0} connectionPool.maxIdleTooLarge=maxIdle is larger than maxActive, setting maxIdle to: {0} +connectionPool.maxIdleNegative=maxIdle is negative, setting maxIdle to: 0 connectionPool.maxIdleTooSmall=maxIdle is smaller than minIdle, setting maxIdle to: {0} +connectionPool.minIdleNegative=minIdle is negative, setting minIdle to: 0 connectionPool.minIdleTooLarge=minIdle is larger than maxActive, setting minIdle to: {0} connectionPool.poolCleanerFailed=The pool maintenance task failed, it will run again at the next scheduled interval. connectionPool.poolClosed=Connection pool closed. diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/TestPoolSizeSetterValidation.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/TestPoolSizeSetterValidation.java index 4b623b5748..2a54842b8a 100644 --- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/TestPoolSizeSetterValidation.java +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/TestPoolSizeSetterValidation.java @@ -144,6 +144,22 @@ class TestPoolSizeSetterValidation extends JdbcPoolBaseTest { "the floor has to stay at or below the ceiling it is bounded by"); } + @Test + void negativeIdleCountsAreCorrectedAtPoolCreation() throws Exception { + DataSource ds = newDataSource(); + ds.getPoolProperties().setInitialSize(0); + ds.getPoolProperties().setMaxActive(4); + ds.getPoolProperties().setMinIdle(-3); + ds.getPoolProperties().setMaxIdle(-1); + + ds.createPool(); + + Assertions.assertEquals(0, ds.getPoolProperties().getMinIdle(), + "a negative idle floor has to be corrected like a negative initial size"); + Assertions.assertEquals(0, ds.getPoolProperties().getMaxIdle(), + "a negative idle ceiling has to be corrected like a negative initial size"); + } + /* * The control, and the reason this is treated as a gap rather than a choice: * the pool's own MBean takes the same three writes and corrects them, so the --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
