Skip to content

Commit bca72bd

Browse files
author
raju.gupta
committed
POOL-425 addObject() should respect maxIdle property.
1 parent cdb0699 commit bca72bd

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

src/main/java/org/apache/commons/pool3/impl/GenericObjectPool.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,11 @@ private PooledObject<T> create(final Duration maxWaitDurationRequest) throws E {
513513
if (localMaxTotal < 0) {
514514
localMaxTotal = Integer.MAX_VALUE;
515515
}
516+
int localMaxIdle = getMaxIdle();
517+
if (localMaxIdle < 0) {
518+
localMaxIdle = Integer.MAX_VALUE;
519+
}
520+
final int maxCapacity = Math.min(localMaxTotal, localMaxIdle);
516521
final Instant localStartInstant = Instant.now();
517522
// Flag that indicates if create should:
518523
// - TRUE: call the factory to create an object
@@ -525,7 +530,7 @@ private PooledObject<T> create(final Duration maxWaitDurationRequest) throws E {
525530
final Duration remainingWaitDuration = maxWaitDuration.minus(durationSince(startInstant));
526531
synchronized (makeObjectCountLock) {
527532
final long newCreateCount = createCount.incrementAndGet();
528-
if (newCreateCount > localMaxTotal) {
533+
if (newCreateCount > maxCapacity) {
529534
// The pool is currently at capacity or in the process of
530535
// making enough new objects to take it to capacity.
531536
createCount.decrementAndGet();

src/test/java/org/apache/commons/pool3/impl/TestGenericObjectPool.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@
4343
import java.util.Set;
4444
import java.util.Timer;
4545
import java.util.TimerTask;
46+
import java.util.concurrent.CountDownLatch;
47+
import java.util.concurrent.ExecutorService;
48+
import java.util.concurrent.Executors;
4649
import java.util.concurrent.Semaphore;
4750
import java.util.concurrent.TimeUnit;
4851
import java.util.concurrent.atomic.AtomicBoolean;
@@ -1012,6 +1015,71 @@ void testAddObject() throws Exception {
10121015
assertEquals(0, genericObjectPool.getNumActive(), "should be zero active");
10131016
}
10141017

1018+
1019+
/*https://issues.apache.org/jira/browse/POOL-425*/
1020+
@Test
1021+
@Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1022+
void testAddObjectRespectsMaxIdleLimit() throws Exception {
1023+
genericObjectPool.setMaxIdle(1);
1024+
genericObjectPool.addObject();
1025+
genericObjectPool.addObject();
1026+
assertEquals(1, genericObjectPool.getNumIdle(), "should be one idle");
1027+
1028+
genericObjectPool.setMaxIdle(-1);
1029+
genericObjectPool.addObject();
1030+
genericObjectPool.addObject();
1031+
genericObjectPool.addObject();
1032+
assertEquals(4, genericObjectPool.getNumIdle(), "should be four idle");
1033+
}
1034+
1035+
@Test
1036+
@Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1037+
void testAddObjectConcurrentCallsRespectsMaxIdle() throws Exception {
1038+
final int maxIdleLimit = 5;
1039+
final int numThreads = 10;
1040+
genericObjectPool.setMaxIdle(maxIdleLimit);
1041+
1042+
final CountDownLatch startLatch = new CountDownLatch(1);
1043+
final CountDownLatch doneLatch = new CountDownLatch(numThreads);
1044+
1045+
List<Runnable> tasks = getRunnables(numThreads, startLatch, doneLatch);
1046+
1047+
ExecutorService executorService = Executors.newFixedThreadPool(numThreads);
1048+
tasks.forEach(executorService::submit);
1049+
try {
1050+
startLatch.countDown(); // Start all threads simultaneously
1051+
doneLatch.await(); // Wait for all threads to complete
1052+
} finally {
1053+
executorService.shutdown();
1054+
assertTrue(executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS));
1055+
}
1056+
1057+
assertTrue(genericObjectPool.getNumIdle() <= maxIdleLimit,
1058+
"Concurrent addObject() calls should not exceed maxIdle limit of " + maxIdleLimit +
1059+
", but found " + genericObjectPool.getNumIdle() + " idle objects");
1060+
}
1061+
1062+
private List<Runnable> getRunnables(final int numThreads,
1063+
final CountDownLatch startLatch,
1064+
final CountDownLatch doneLatch) {
1065+
List<Runnable> tasks = new ArrayList<>();
1066+
1067+
for(int i = 0; i < numThreads; i++) {
1068+
tasks.add(() -> {
1069+
try {
1070+
startLatch.await(); // Wait for all threads to be ready
1071+
genericObjectPool.addObject();
1072+
} catch (Exception e) {
1073+
Thread.currentThread().interrupt(); // Restore interrupt status
1074+
} finally {
1075+
doneLatch.countDown();
1076+
}
1077+
});
1078+
}
1079+
return tasks;
1080+
}
1081+
1082+
10151083
@Test
10161084
void testAppendStats() {
10171085
assertFalse(genericObjectPool.getMessageStatistics());

0 commit comments

Comments
 (0)