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

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


The following commit(s) were added to refs/heads/POOL_2_X by this push:
     new c5d63adf Fix for JIRA: POOL-425.  Make addObject no-op when maxIdle is 
attained.
c5d63adf is described below

commit c5d63adfca0d1063cce6a3a53f4be585cf48c4d1
Author: Phil Steitz <[email protected]>
AuthorDate: Wed Nov 5 20:24:51 2025 -0700

    Fix for JIRA: POOL-425.  Make addObject no-op when maxIdle is attained.
---
 src/changes/changes.xml                            |  3 ++-
 .../commons/pool2/impl/GenericObjectPool.java      |  8 +++---
 .../commons/pool2/impl/TestGenericObjectPool.java  | 29 ++++++++++++++++++++++
 3 files changed, 36 insertions(+), 4 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index b6865f13..94b76399 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -47,7 +47,8 @@ The <action> type attribute can be add,update,fix,remove.
   <body>
   <release version="2.13.0" date="YYYY-MM-DD" description="This is a feature 
and maintenance release. Java 8 or later is required.">
     <!-- FIX -->
-    <action type="fix" issue="POOL-350" dev="psteitz" due-to="Phil 
Steitz">Make placement of calls to GKOP reuseCapacity configurable.</action>
+    <action type="fix" issue="POOL-425" dev="psteitz">GenericObjectPool 
addObject does not respect maxIdle.</action>
+    <action type="fix" issue="POOL-350" dev="psteitz">Make placement of calls 
to GKOP reuseCapacity configurable.</action>
     <action type="fix" issue="POOL-290" dev="psteitz" due-to="Serge 
Angelov">TestSoftRefOutOfMemory (unit test) can loop infinitely on 
failure.</action>
     <action type="fix" issue="POOL-419" dev="psteitz" due-to="Raju Gupta, Phil 
Steitz">GenericObjectPool counters and object collections can be corrupted when 
returnObject and invalidate are invoked concurrently by client threads on the 
same pooled object.</action>
     <action type="fix" issue="POOL-421" dev="psteitz" due-to="Phil 
Steitz">GenericObjectPool addObject should return immediately when there is no 
capacity to add.</action>
diff --git a/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java 
b/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java
index 15d4d63c..8927e580 100644
--- a/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java
+++ b/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java
@@ -193,10 +193,11 @@ public class GenericObjectPool<T> extends 
BaseGenericObjectPool<T>
     }
 
     /**
-     * Creates an object, and place it into the pool. addObject() is useful for
+     * Creates an object, and places it into the pool. addObject() is useful 
for
      * "pre-loading" a pool with idle objects.
      * <p>
-     * If there is no capacity available to add to the pool, this is a no-op
+     * If there is no capacity available to add to the pool, or there are 
already
+     * {@link #getMaxIdle()} idle instances in the pool, this is a no-op
      * (no exception, no impact to the pool).
      * </p>
      * <p>
@@ -213,7 +214,8 @@ public class GenericObjectPool<T> extends 
BaseGenericObjectPool<T>
         }
 
         final int localMaxTotal = getMaxTotal();
-        if (localMaxTotal < 0 || createCount.get() < localMaxTotal) {
+        final int localMaxIdle = getMaxIdle();
+        if (getNumIdle() < localMaxIdle && (localMaxTotal < 0 || 
createCount.get() < localMaxTotal)) {
             addIdleObject(create(getMaxWaitDuration()));
         }
     }
diff --git 
a/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java 
b/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java
index 47c1a1b8..9c9ad43b 100644
--- a/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java
+++ b/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java
@@ -750,6 +750,7 @@ class TestGenericObjectPool extends TestBaseObjectPool {
                     trackerPool.setMaxIdle(-1);
                     final int instanceCount = 10 + random.nextInt(20);
                     trackerPool.setMaxTotal(instanceCount);
+                    trackerPool.setMaxIdle(instanceCount);
                     for (int k = 0; k < instanceCount; k++) {
                         trackerPool.addObject();
                     }
@@ -2980,4 +2981,32 @@ class TestGenericObjectPool extends TestBaseObjectPool {
         assertEquals(1, genericObjectPool.getNumIdle());
         genericObjectPool.close();
     }
+
+    @Test
+    void testAddObjectRespectsMaxIdle() throws Exception {
+        genericObjectPool.setMaxIdle(1);
+        genericObjectPool.addObject();
+        genericObjectPool.addObject(); // should be no-op
+        assertEquals(1, genericObjectPool.getNumIdle());
+    }
+
+    @Test
+    void testAddObjectRespectsMaxTotal() throws Exception {
+        genericObjectPool.setMaxTotal(1);
+        genericObjectPool.addObject();
+        genericObjectPool.addObject(); // should be no-op
+        assertEquals(1, genericObjectPool.getNumIdle());
+    }
+
+    @Test
+    void testAddObjectCanAddToMaxIdle() throws Exception {
+        genericObjectPool.setMaxTotal(5);
+        genericObjectPool.borrowObject();
+        genericObjectPool.borrowObject();
+        genericObjectPool.setMaxIdle(3);
+        for (int i = 0; i < 3; i++) {
+            genericObjectPool.addObject();
+        }
+        assertEquals(3, genericObjectPool.getNumIdle());
+    }
 }

Reply via email to