Skip to content

Commit 3e3a567

Browse files
author
Raju Kumar Gupta
committed
[POOL-419] Fix for POOL-419. Before adding the returned object to the pool, we must check whether it is invalid.
1 parent f8a03c0 commit 3e3a567

File tree

3 files changed

+84
-63
lines changed

3 files changed

+84
-63
lines changed

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

+6
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,12 @@ public void returnObject(final T obj) {
10911091
swallowException(e);
10921092
}
10931093
} else {
1094+
1095+
if (!p.deallocate()) {
1096+
throw new IllegalStateException(
1097+
"Object has already been returned to this pool or is invalid");
1098+
}
1099+
10941100
if (getLifo()) {
10951101
idleObjects.addFirst(p);
10961102
} else {

src/test/java/org/apache/commons/pool3/TestPoolUtils.java

-63
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import static org.junit.jupiter.api.Assertions.assertEquals;
2222
import static org.junit.jupiter.api.Assertions.assertNotNull;
2323
import static org.junit.jupiter.api.Assertions.assertThrows;
24-
import static org.junit.jupiter.api.Assertions.assertTrue;
2524
import static org.junit.jupiter.api.Assertions.fail;
2625

2726
import java.lang.reflect.InvocationHandler;
@@ -34,16 +33,10 @@
3433
import java.util.List;
3534
import java.util.Map;
3635
import java.util.TimerTask;
37-
import java.util.concurrent.CountDownLatch;
38-
import java.util.concurrent.ExecutorService;
39-
import java.util.concurrent.Executors;
40-
import java.util.concurrent.FutureTask;
41-
import java.util.concurrent.TimeUnit;
4236

4337
import org.apache.commons.pool3.impl.DefaultPooledObject;
4438
import org.apache.commons.pool3.impl.GenericKeyedObjectPool;
4539
import org.apache.commons.pool3.impl.GenericObjectPool;
46-
import org.apache.commons.pool3.impl.GenericObjectPoolConfig;
4740
import org.junit.jupiter.api.Test;
4841
import org.opentest4j.AssertionFailedError;
4942

@@ -691,60 +684,4 @@ public void testTimerHolder() {
691684
assertNotNull(h);
692685
assertNotNull(PoolUtils.TimerHolder.MIN_IDLE_TIMER);
693686
}
694-
695-
/*
696-
* Test for POOL-419.
697-
* https://issues.apache.org/jira/browse/POOL-419
698-
*/
699-
@Test
700-
void testPool419() throws Exception{
701-
702-
ExecutorService executor = Executors.newFixedThreadPool(100);
703-
704-
final List<String> calledMethods = new ArrayList<>();
705-
706-
final GenericObjectPoolConfig<Object> config = new GenericObjectPoolConfig<>();
707-
708-
config.setMaxTotal(10000);
709-
config.setMaxIdle(10000);
710-
config.setMinIdle(10000);
711-
712-
@SuppressWarnings("unchecked")
713-
final PooledObjectFactory<Object, RuntimeException> pof = createProxy(PooledObjectFactory.class, calledMethods);
714-
try (final ObjectPool<Object, RuntimeException> connectionPool = new GenericObjectPool<>(pof, config)) {
715-
assertNotNull(connectionPool);
716-
717-
CountDownLatch startLatch = new CountDownLatch(1);
718-
719-
for (int i = 0; i < 10000; i++) {
720-
Object poolObject = connectionPool.borrowObject();
721-
722-
FutureTask<Boolean> invalidateObject = new FutureTask<>(() -> {
723-
startLatch.await();
724-
connectionPool.invalidateObject(poolObject);
725-
return true;
726-
});
727-
728-
FutureTask<Boolean> returnObject = new FutureTask<>(() -> {
729-
startLatch.await();
730-
connectionPool.returnObject(poolObject);
731-
return true;
732-
});
733-
734-
executor.submit(returnObject);
735-
executor.submit(invalidateObject);
736-
737-
}
738-
739-
startLatch.countDown(); // Start all tasks simultaneously
740-
741-
executor.shutdown();
742-
assertTrue(executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS));
743-
744-
assertEquals(0, connectionPool.getNumActive(), "getNumActive() must not return a negative value");
745-
746-
}
747-
}
748-
749687
}
750-

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

+78
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
import java.util.Set;
4242
import java.util.Timer;
4343
import java.util.TimerTask;
44+
import java.util.concurrent.CountDownLatch;
45+
import java.util.concurrent.ExecutorService;
46+
import java.util.concurrent.Executors;
47+
import java.util.concurrent.FutureTask;
4448
import java.util.concurrent.Semaphore;
4549
import java.util.concurrent.TimeUnit;
4650
import java.util.concurrent.atomic.AtomicBoolean;
@@ -3150,4 +3154,78 @@ public void testWhenExhaustedFail() throws Exception {
31503154
genericObjectPool.close();
31513155
}
31523156

3157+
private BasePooledObjectFactory<Object, RuntimeException> createPooledObjectFactory() {
3158+
return new BasePooledObjectFactory<>() {
3159+
@Override
3160+
public Object create() {
3161+
return new Object();
3162+
}
3163+
3164+
@Override
3165+
public PooledObject<Object> wrap(final Object obj) {
3166+
return new DefaultPooledObject<>(obj);
3167+
}
3168+
};
3169+
}
3170+
3171+
3172+
/*
3173+
* Test for POOL-419.
3174+
* https://issues.apache.org/jira/browse/POOL-419
3175+
*/
3176+
@Test
3177+
void testPool419() throws Exception{
3178+
3179+
ExecutorService executor = Executors.newFixedThreadPool(100);
3180+
3181+
final GenericObjectPoolConfig<Object> config = new GenericObjectPoolConfig<>();
3182+
3183+
final int maxConnections = 10000;
3184+
3185+
config.setMaxTotal(maxConnections);
3186+
config.setMaxIdle(maxConnections);
3187+
config.setMinIdle(1);
3188+
3189+
final BasePooledObjectFactory<Object, RuntimeException> pof = createPooledObjectFactory();
3190+
3191+
try (final ObjectPool<Object, RuntimeException> connectionPool = new GenericObjectPool<>(pof, config)) {
3192+
assertNotNull(connectionPool);
3193+
3194+
CountDownLatch startLatch = new CountDownLatch(1);
3195+
3196+
List<Object> poolObjects = new ArrayList<>();
3197+
3198+
List<FutureTask<Boolean>> tasks = new ArrayList<>();
3199+
3200+
for (int i = 0; i < maxConnections; i++) {
3201+
poolObjects.add(connectionPool.borrowObject());
3202+
}
3203+
3204+
for(Object poolObject : poolObjects) {
3205+
3206+
tasks.add(new FutureTask<>(() -> {
3207+
startLatch.await();
3208+
connectionPool.invalidateObject(poolObject);
3209+
return true;
3210+
}));
3211+
3212+
tasks.add(new FutureTask<>(() -> {
3213+
startLatch.await();
3214+
connectionPool.returnObject(poolObject);
3215+
return true;
3216+
}));
3217+
}
3218+
3219+
tasks.forEach(executor::submit);
3220+
3221+
startLatch.countDown(); // Start all tasks simultaneously
3222+
3223+
executor.shutdown();
3224+
assertTrue(executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS));
3225+
3226+
assertEquals(0, connectionPool.getNumActive(), "getNumActive() must not return a negative value");
3227+
3228+
}
3229+
}
3230+
31533231
}

0 commit comments

Comments
 (0)