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

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


The following commit(s) were added to refs/heads/master by this push:
     new b73c2cd5 [POOL-407] Threads get stuck when idleObjects list is empty
b73c2cd5 is described below

commit b73c2cd56384569bbec268990ce3a1a48e7acf6f
Author: Gary Gregory <garydgreg...@gmail.com>
AuthorDate: Fri Oct 7 20:11:46 2022 -0400

    [POOL-407] Threads get stuck when idleObjects list is empty
    
    Add working test case for non-keyed version of the code
---
 .../pool2/BaseKeyedPooledObjectFactory.java        |  4 +-
 .../commons/pool2/BasePooledObjectFactory.java     |  4 +-
 .../commons/pool2/pool407/KeyedPool407Factory.java |  5 +-
 .../org/apache/commons/pool2/pool407/Pool407.java  | 27 ++++++++
 .../commons/pool2/pool407/Pool407Config.java       | 31 +++++++++
 ...eyedPool407Factory.java => Pool407Factory.java} | 19 +++---
 .../commons/pool2/pool407/Pool407Fixture.java      | 22 +++++++
 .../apache/commons/pool2/pool407/Pool407Test.java  | 75 ++++++++++++++++++++++
 8 files changed, 172 insertions(+), 15 deletions(-)

diff --git 
a/src/main/java/org/apache/commons/pool2/BaseKeyedPooledObjectFactory.java 
b/src/main/java/org/apache/commons/pool2/BaseKeyedPooledObjectFactory.java
index 369550b1..0c894101 100644
--- a/src/main/java/org/apache/commons/pool2/BaseKeyedPooledObjectFactory.java
+++ b/src/main/java/org/apache/commons/pool2/BaseKeyedPooledObjectFactory.java
@@ -16,6 +16,8 @@
  */
 package org.apache.commons.pool2;
 
+import java.util.Objects;
+
 /**
  * A base implementation of {@code KeyedPooledObjectFactory}.
  * <p>
@@ -76,7 +78,7 @@ public abstract class BaseKeyedPooledObjectFactory<K, V, E 
extends Exception> ex
 
     @Override
     public PooledObject<V> makeObject(final K key) throws E {
-        return wrap(create(key));
+        return wrap(Objects.requireNonNull(create(key), 
"BaseKeyedPooledObjectFactory.create(key)"));
     }
 
     /**
diff --git 
a/src/main/java/org/apache/commons/pool2/BasePooledObjectFactory.java 
b/src/main/java/org/apache/commons/pool2/BasePooledObjectFactory.java
index d7ae8de6..da8c456b 100644
--- a/src/main/java/org/apache/commons/pool2/BasePooledObjectFactory.java
+++ b/src/main/java/org/apache/commons/pool2/BasePooledObjectFactory.java
@@ -16,6 +16,8 @@
  */
 package org.apache.commons.pool2;
 
+import java.util.Objects;
+
 /**
  * A base implementation of {@code PoolableObjectFactory}.
  * <p>
@@ -68,7 +70,7 @@ public abstract class BasePooledObjectFactory<T, E extends 
Exception> extends Ba
 
     @Override
     public PooledObject<T> makeObject() throws E {
-        return wrap(create());
+        return wrap(Objects.requireNonNull(create(), 
"BasePooledObjectFactory.create()"));
     }
 
     /**
diff --git 
a/src/test/java/org/apache/commons/pool2/pool407/KeyedPool407Factory.java 
b/src/test/java/org/apache/commons/pool2/pool407/KeyedPool407Factory.java
index 07db0a88..950bf48a 100644
--- a/src/test/java/org/apache/commons/pool2/pool407/KeyedPool407Factory.java
+++ b/src/test/java/org/apache/commons/pool2/pool407/KeyedPool407Factory.java
@@ -17,8 +17,6 @@
 
 package org.apache.commons.pool2.pool407;
 
-import java.util.Objects;
-
 import org.apache.commons.pool2.BaseKeyedPooledObjectFactory;
 import org.apache.commons.pool2.PooledObject;
 import org.apache.commons.pool2.impl.DefaultPooledObject;
@@ -48,6 +46,7 @@ public final class KeyedPool407Factory extends 
BaseKeyedPooledObjectFactory<Stri
     @Override
     public PooledObject<KeyedPool407Fixture> wrap(final KeyedPool407Fixture 
value) {
         // Require a non-null value.
-        return new DefaultPooledObject<>(Objects.requireNonNull(value, 
"value"));
+        // return new DefaultPooledObject<>(Objects.requireNonNull(value, 
"value"));
+        return new DefaultPooledObject<>(value);
     }
 }
diff --git a/src/test/java/org/apache/commons/pool2/pool407/Pool407.java 
b/src/test/java/org/apache/commons/pool2/pool407/Pool407.java
new file mode 100644
index 00000000..54aa8463
--- /dev/null
+++ b/src/test/java/org/apache/commons/pool2/pool407/Pool407.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.pool2.pool407;
+
+import org.apache.commons.pool2.impl.GenericObjectPool;
+
+public final class Pool407 extends GenericObjectPool<Pool407Fixture, 
RuntimeException> {
+
+    public Pool407(final Pool407Fixture fixture) {
+        super(new Pool407Factory(fixture), new Pool407Config());
+    }
+}
diff --git a/src/test/java/org/apache/commons/pool2/pool407/Pool407Config.java 
b/src/test/java/org/apache/commons/pool2/pool407/Pool407Config.java
new file mode 100644
index 00000000..8cbbe2f7
--- /dev/null
+++ b/src/test/java/org/apache/commons/pool2/pool407/Pool407Config.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.pool2.pool407;
+
+import java.time.Duration;
+
+import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
+
+public final class Pool407Config extends 
GenericObjectPoolConfig<Pool407Fixture> {
+
+    public Pool407Config() {
+        setBlockWhenExhausted(true);
+        setMaxTotal(1);
+        setMaxWait(Duration.ofMillis(-1));
+    }
+}
diff --git 
a/src/test/java/org/apache/commons/pool2/pool407/KeyedPool407Factory.java 
b/src/test/java/org/apache/commons/pool2/pool407/Pool407Factory.java
similarity index 71%
copy from 
src/test/java/org/apache/commons/pool2/pool407/KeyedPool407Factory.java
copy to src/test/java/org/apache/commons/pool2/pool407/Pool407Factory.java
index 07db0a88..11ed07e1 100644
--- a/src/test/java/org/apache/commons/pool2/pool407/KeyedPool407Factory.java
+++ b/src/test/java/org/apache/commons/pool2/pool407/Pool407Factory.java
@@ -17,22 +17,20 @@
 
 package org.apache.commons.pool2.pool407;
 
-import java.util.Objects;
-
-import org.apache.commons.pool2.BaseKeyedPooledObjectFactory;
+import org.apache.commons.pool2.BasePooledObjectFactory;
 import org.apache.commons.pool2.PooledObject;
 import org.apache.commons.pool2.impl.DefaultPooledObject;
 
-public final class KeyedPool407Factory extends 
BaseKeyedPooledObjectFactory<String, KeyedPool407Fixture, RuntimeException> {
+public final class Pool407Factory extends 
BasePooledObjectFactory<Pool407Fixture, RuntimeException> {
 
-    private final KeyedPool407Fixture fixture;
+    private final Pool407Fixture fixture;
 
-    KeyedPool407Factory(final KeyedPool407Fixture fixture) {
+    Pool407Factory(final Pool407Fixture fixture) {
         this.fixture = fixture;
     }
 
     @Override
-    public KeyedPool407Fixture create(final String key) {
+    public Pool407Fixture create() {
         // This is key to the test, creation failed and returns null for 
instance see
         // 
https://github.com/openhab/openhab-core/blob/main/bundles/org.openhab.core.io.transport.modbus/src/main/java/org/openhab/core/io/transport/modbus/internal/pooling/ModbusSlaveConnectionFactoryImpl.java#L163
         // the test passes when this returns new Pool407Fixture();
@@ -40,14 +38,15 @@ public final class KeyedPool407Factory extends 
BaseKeyedPooledObjectFactory<Stri
     }
 
     @Override
-    public boolean validateObject(final String key, final 
PooledObject<KeyedPool407Fixture> p) {
+    public boolean validateObject(final PooledObject<Pool407Fixture> p) {
         // TODO Should this be enough even if wrap() does throw and returns a 
DefaultPooledObject wrapping a null?
         return p.getObject() != null;
     }
 
     @Override
-    public PooledObject<KeyedPool407Fixture> wrap(final KeyedPool407Fixture 
value) {
+    public PooledObject<Pool407Fixture> wrap(final Pool407Fixture value) {
         // Require a non-null value.
-        return new DefaultPooledObject<>(Objects.requireNonNull(value, 
"value"));
+        // return new DefaultPooledObject<>(Objects.requireNonNull(value, 
"value"));
+        return new DefaultPooledObject<>(value);
     }
 }
diff --git a/src/test/java/org/apache/commons/pool2/pool407/Pool407Fixture.java 
b/src/test/java/org/apache/commons/pool2/pool407/Pool407Fixture.java
new file mode 100644
index 00000000..0488bb22
--- /dev/null
+++ b/src/test/java/org/apache/commons/pool2/pool407/Pool407Fixture.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.pool2.pool407;
+
+public final class Pool407Fixture {
+    // empty
+}
diff --git a/src/test/java/org/apache/commons/pool2/pool407/Pool407Test.java 
b/src/test/java/org/apache/commons/pool2/pool407/Pool407Test.java
new file mode 100644
index 00000000..bb1675e3
--- /dev/null
+++ b/src/test/java/org/apache/commons/pool2/pool407/Pool407Test.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.pool2.pool407;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.jupiter.api.Test;
+
+public class Pool407Test {
+
+    private static class Pool407Borrower implements Runnable {
+        private final Pool407 pool;
+
+        public Pool407Borrower(final Pool407 pool) {
+            this.pool = pool;
+        }
+
+        @Override
+        public void run() {
+            try {
+                final Pool407Fixture foo = pool.borrowObject();
+                if (foo != null) {
+                    pool.returnObject(foo);
+                }
+            } catch (final Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    private static final int POOL_SIZE = 3;
+
+    private void test(final Pool407Fixture fixture, final int poolSize) throws 
InterruptedException {
+        final ExecutorService executor = 
Executors.newFixedThreadPool(poolSize);
+        final Pool407 pool = new Pool407(fixture);
+
+        // start 'poolSize' threads that try to borrow a Pool407Fixture with 
the same key
+        for (int i = 0; i < poolSize; i++) {
+            executor.execute(new Pool407Borrower(pool));
+        }
+
+        // this never finishes because two threads are stuck forever
+        executor.shutdown();
+        assertTrue(executor.awaitTermination(10, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testFail() throws InterruptedException {
+        test(null, POOL_SIZE);
+    }
+
+    @Test
+    public void testPass() throws InterruptedException {
+        test(new Pool407Fixture(), 3);
+    }
+}

Reply via email to