This is an automated email from the ASF dual-hosted git repository. ggregory 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 421deb60 Sort members 421deb60 is described below commit 421deb604a9da37b5150bec916d2ff8b751fc55b Author: Gary Gregory <garydgreg...@gmail.com> AuthorDate: Tue Jun 10 09:42:14 2025 -0400 Sort members --- .../commons/pool2/impl/BaseGenericObjectPool.java | 52 +++--- .../pool2/impl/TestGenericKeyedObjectPool.java | 82 +++++----- .../commons/pool2/impl/TestGenericObjectPool.java | 182 ++++++++++----------- 3 files changed, 158 insertions(+), 158 deletions(-) diff --git a/src/main/java/org/apache/commons/pool2/impl/BaseGenericObjectPool.java b/src/main/java/org/apache/commons/pool2/impl/BaseGenericObjectPool.java index 9c24de41..44a93c99 100644 --- a/src/main/java/org/apache/commons/pool2/impl/BaseGenericObjectPool.java +++ b/src/main/java/org/apache/commons/pool2/impl/BaseGenericObjectPool.java @@ -482,6 +482,16 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject implements Aut return remove; } + /** + * Returns the duration since the given start time. + * + * @param startInstant the start time + * @return the duration since the given start time + */ + final Duration durationSince(final Instant startInstant) { + return Duration.between(startInstant, Instant.now()); + } + /** * Tries to ensure that the configured minimum number of idle instances are * available in the pool. @@ -1938,32 +1948,6 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject implements Aut } } - /** - * Returns the duration since the given start time. - * - * @param startInstant the start time - * @return the duration since the given start time - */ - final Duration durationSince(final Instant startInstant) { - return Duration.between(startInstant, Instant.now()); - } - - /** - * Waits for notification on the given object for the specified duration. - * Duration.ZERO causes the thread to wait indefinitely. - * - * @param obj the object to wait on - * @param duration the duration to wait - * @throws InterruptedException if interrupted while waiting - * @throws IllegalArgumentException if the duration is negative - */ - final void wait(final Object obj, final Duration duration) throws InterruptedException { - if (!duration.isNegative()) { - obj.wait(duration.toMillis(), duration.getNano() % 1_000_000); - } - } - - /** * Stops the evictor. */ @@ -1971,6 +1955,7 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject implements Aut startEvictor(Duration.ofMillis(-1L)); } + /** * Swallows an exception and notifies the configured listener for swallowed * exceptions queue. @@ -2095,4 +2080,19 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject implements Aut activeTimes.add(activeTime); } + /** + * Waits for notification on the given object for the specified duration. + * Duration.ZERO causes the thread to wait indefinitely. + * + * @param obj the object to wait on + * @param duration the duration to wait + * @throws InterruptedException if interrupted while waiting + * @throws IllegalArgumentException if the duration is negative + */ + final void wait(final Object obj, final Duration duration) throws InterruptedException { + if (!duration.isNegative()) { + obj.wait(duration.toMillis(), duration.getNano() % 1_000_000); + } + } + } diff --git a/src/test/java/org/apache/commons/pool2/impl/TestGenericKeyedObjectPool.java b/src/test/java/org/apache/commons/pool2/impl/TestGenericKeyedObjectPool.java index c0e1c46c..e8034d65 100644 --- a/src/test/java/org/apache/commons/pool2/impl/TestGenericKeyedObjectPool.java +++ b/src/test/java/org/apache/commons/pool2/impl/TestGenericKeyedObjectPool.java @@ -2046,47 +2046,6 @@ public class TestGenericKeyedObjectPool extends AbstractTestKeyedObjectPool { assertThrows(NoSuchElementException.class, () -> gkoPool.borrowObject("a")); } - /** - * JIRA: POOL-420 (clone of POOL-418 for GKOP) - * - * Test to make sure that a client thread that triggers a create that fails does - * not wait longer than the maxWait time. - * - * Bug was that the time spent waiting for the create to complete was not being - * counted against the maxWait time. - */ - @Test - void testMaxWaitTimeOutOnTime() throws Exception { - final Duration maxWaitDuration = Duration.ofSeconds(1); - final SimpleFactory<String> factory = new SimpleFactory<>(); - factory.makeLatency = 500; - factory.setValidationEnabled(true); // turn on factory-level validatiom - factory.setValid(false); // make validation fail uniformly - final GenericKeyedObjectPool<String, String> pool = new GenericKeyedObjectPool<>(factory); - - pool.setBlockWhenExhausted(true); - pool.setMaxWait(maxWaitDuration); - pool.setMaxTotalPerKey(1); - pool.setMaxTotal(1); - pool.setTestOnCreate(true); - final Instant startTime = Instant.now(); - - // Try to borrow an object. Validation will fail. - // Then we will wait on the pool. - try { - pool.borrowObject("a"); - } catch (NoSuchElementException ex) { - // expected - } - - // Should have timeed out after 1000 ms from the start time - final Duration duration = Duration.between(startTime, Instant.now()); - assertTrue(duration.toMillis() < maxWaitDuration.toMillis() + 10, // allow for some timing delay - "Thread A should have timed out after " + maxWaitDuration.toMillis() + " ms, but took " + duration.toMillis() + " ms"); - pool.close(); - } - - /* * Test multi-threaded pool access. Multiple keys, multiple threads, but maxActive only allows half the threads to succeed. * @@ -2133,6 +2092,47 @@ public class TestGenericKeyedObjectPool extends AbstractTestKeyedObjectPool { assertEquals(wtt.length / 2, failed, "Expected half the threads to fail"); } + + /** + * JIRA: POOL-420 (clone of POOL-418 for GKOP) + * + * Test to make sure that a client thread that triggers a create that fails does + * not wait longer than the maxWait time. + * + * Bug was that the time spent waiting for the create to complete was not being + * counted against the maxWait time. + */ + @Test + void testMaxWaitTimeOutOnTime() throws Exception { + final Duration maxWaitDuration = Duration.ofSeconds(1); + final SimpleFactory<String> factory = new SimpleFactory<>(); + factory.makeLatency = 500; + factory.setValidationEnabled(true); // turn on factory-level validatiom + factory.setValid(false); // make validation fail uniformly + final GenericKeyedObjectPool<String, String> pool = new GenericKeyedObjectPool<>(factory); + + pool.setBlockWhenExhausted(true); + pool.setMaxWait(maxWaitDuration); + pool.setMaxTotalPerKey(1); + pool.setMaxTotal(1); + pool.setTestOnCreate(true); + final Instant startTime = Instant.now(); + + // Try to borrow an object. Validation will fail. + // Then we will wait on the pool. + try { + pool.borrowObject("a"); + } catch (NoSuchElementException ex) { + // expected + } + + // Should have timeed out after 1000 ms from the start time + final Duration duration = Duration.between(startTime, Instant.now()); + assertTrue(duration.toMillis() < maxWaitDuration.toMillis() + 10, // allow for some timing delay + "Thread A should have timed out after " + maxWaitDuration.toMillis() + " ms, but took " + duration.toMillis() + " ms"); + pool.close(); + } + @Test @Timeout(value = 60_000, unit = TimeUnit.MILLISECONDS) void testMinIdle() throws Exception { 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 133621af..763ed306 100644 --- a/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java +++ b/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java @@ -806,6 +806,20 @@ class TestGenericObjectPool extends TestBaseObjectPool { }; } + private BasePooledObjectFactory<Object> createPooledObjectFactory() { + return new BasePooledObjectFactory<Object>() { + @Override + public Object create() { + return new Object(); + } + + @Override + public PooledObject<Object> wrap(final Object obj) { + return new DefaultPooledObject<>(obj); + } + }; + } + private BasePooledObjectFactory<String> createSlowObjectFactory(final Duration sleepDuration) { return new BasePooledObjectFactory<String>() { @Override @@ -948,6 +962,23 @@ class TestGenericObjectPool extends TestBaseObjectPool { assertEquals(0, genericObjectPool.getNumActive(), "should be zero active"); } + @Test + @Timeout(value = 400, unit = TimeUnit.MILLISECONDS) + void testAddObjectFastReturn() throws Exception { + final SimpleFactory simpleFactory = new SimpleFactory(); + simpleFactory.makeLatency = 500; + final GenericObjectPool<String> pool = new GenericObjectPool<>(simpleFactory); + pool.setMaxTotal(1); + pool.setBlockWhenExhausted(true); + pool.setMaxWait(Duration.ofMillis(1000)); + // Start a test thread. The thread will trigger a create, which will take 500 ms to complete + final TestThread<String> thread = new TestThread<>(pool); + final Thread t = new Thread(thread); + t.start(); + Thread.sleep(50); // Wait for the thread to start + pool.addObject(); // Should return immediately + } + @Test void testAppendStats() { assertFalse(genericObjectPool.getMessageStatistics()); @@ -2443,6 +2474,65 @@ class TestGenericObjectPool extends TestBaseObjectPool { pool.close(); } + /* + * Test for POOL-419. + * https://issues.apache.org/jira/browse/POOL-419 + */ + @Test + void testPool419() throws Exception { + + final ExecutorService executor = Executors.newFixedThreadPool(100); + + final GenericObjectPoolConfig<Object> config = new GenericObjectPoolConfig<>(); + + final int maxConnections = 10000; + + config.setMaxTotal(maxConnections); + config.setMaxIdle(maxConnections); + config.setMinIdle(1); + + final BasePooledObjectFactory<Object> pof = createPooledObjectFactory(); + + try (ObjectPool<Object> connectionPool = new GenericObjectPool<>(pof, config)) { + assertNotNull(connectionPool); + + final CountDownLatch startLatch = new CountDownLatch(1); + + final List<Object> poolObjects = new ArrayList<>(); + + final List<FutureTask<Boolean>> tasks = new ArrayList<>(); + + for (int i = 0; i < maxConnections; i++) { + poolObjects.add(connectionPool.borrowObject()); + } + + for (Object poolObject : poolObjects) { + + tasks.add(new FutureTask<>(() -> { + startLatch.await(); + connectionPool.invalidateObject(poolObject); + return true; + })); + + tasks.add(new FutureTask<>(() -> { + startLatch.await(); + connectionPool.returnObject(poolObject); + return true; + })); + } + + tasks.forEach(executor::submit); + + startLatch.countDown(); // Start all tasks simultaneously + + executor.shutdown(); + assertTrue(executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS)); + + assertEquals(0, connectionPool.getNumActive(), "getNumActive() must not return a negative value"); + + } + } + @Test void testPreparePool() throws Exception { genericObjectPool.setMinIdle(1); @@ -2878,6 +2968,7 @@ class TestGenericObjectPool extends TestBaseObjectPool { genericObjectPool.close(); } + @Test @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS) void testWhenExhaustedFail() throws Exception { @@ -2890,95 +2981,4 @@ class TestGenericObjectPool extends TestBaseObjectPool { assertEquals(1, genericObjectPool.getNumIdle()); genericObjectPool.close(); } - - @Test - @Timeout(value = 400, unit = TimeUnit.MILLISECONDS) - void testAddObjectFastReturn() throws Exception { - final SimpleFactory simpleFactory = new SimpleFactory(); - simpleFactory.makeLatency = 500; - final GenericObjectPool<String> pool = new GenericObjectPool<>(simpleFactory); - pool.setMaxTotal(1); - pool.setBlockWhenExhausted(true); - pool.setMaxWait(Duration.ofMillis(1000)); - // Start a test thread. The thread will trigger a create, which will take 500 ms to complete - final TestThread<String> thread = new TestThread<>(pool); - final Thread t = new Thread(thread); - t.start(); - Thread.sleep(50); // Wait for the thread to start - pool.addObject(); // Should return immediately - } - - private BasePooledObjectFactory<Object> createPooledObjectFactory() { - return new BasePooledObjectFactory<Object>() { - @Override - public Object create() { - return new Object(); - } - - @Override - public PooledObject<Object> wrap(final Object obj) { - return new DefaultPooledObject<>(obj); - } - }; - } - - - /* - * Test for POOL-419. - * https://issues.apache.org/jira/browse/POOL-419 - */ - @Test - void testPool419() throws Exception { - - final ExecutorService executor = Executors.newFixedThreadPool(100); - - final GenericObjectPoolConfig<Object> config = new GenericObjectPoolConfig<>(); - - final int maxConnections = 10000; - - config.setMaxTotal(maxConnections); - config.setMaxIdle(maxConnections); - config.setMinIdle(1); - - final BasePooledObjectFactory<Object> pof = createPooledObjectFactory(); - - try (ObjectPool<Object> connectionPool = new GenericObjectPool<>(pof, config)) { - assertNotNull(connectionPool); - - final CountDownLatch startLatch = new CountDownLatch(1); - - final List<Object> poolObjects = new ArrayList<>(); - - final List<FutureTask<Boolean>> tasks = new ArrayList<>(); - - for (int i = 0; i < maxConnections; i++) { - poolObjects.add(connectionPool.borrowObject()); - } - - for (Object poolObject : poolObjects) { - - tasks.add(new FutureTask<>(() -> { - startLatch.await(); - connectionPool.invalidateObject(poolObject); - return true; - })); - - tasks.add(new FutureTask<>(() -> { - startLatch.await(); - connectionPool.returnObject(poolObject); - return true; - })); - } - - tasks.forEach(executor::submit); - - startLatch.countDown(); // Start all tasks simultaneously - - executor.shutdown(); - assertTrue(executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS)); - - assertEquals(0, connectionPool.getNumActive(), "getNumActive() must not return a negative value"); - - } - } }