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 a6c43d63943e8df01c2de2cdd802c02b17af1502
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 3780929f6f..39cb7c7bd7 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
@@ -1111,6 +1111,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]

Reply via email to