You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by "Phil Steitz (Jira)" <ji...@apache.org> on 2023/07/11 23:58:00 UTC

[jira] [Commented] (POOL-407) Threads get stuck when idleObjects list is empty.

    [ https://issues.apache.org/jira/browse/POOL-407?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17742216#comment-17742216 ] 

Phil Steitz commented on POOL-407:
----------------------------------

Looking more carefully at this, the sequence in the description can happen and it is a liveness limitation of the pool.  There are other scenarios that can lead to this.  Neither GKOP nor GOP currently have a way to recover from factory "outages."  My suggestion to use ensureIdle above is not a good idea because it could lead to looping in borrowObject.  

The tests added above are not really testing anything.  You can see in the console NPE stack traces that don't cause the Junit tests to fail because the runner is not picking them up.  A more complex setup would be needed to catch them.  That setup would cause the ones where the factory returns null to fail.  By design, pool create methods throw NPE when factories return null.  This is documented in the javadoc for create, but missing from that of the pool methods.  

> Threads get stuck when idleObjects list is empty.
> -------------------------------------------------
>
>                 Key: POOL-407
>                 URL: https://issues.apache.org/jira/browse/POOL-407
>             Project: Commons Pool
>          Issue Type: Bug
>    Affects Versions: 2.8.1
>            Reporter: Sarthak Shukla
>            Priority: Major
>
> While borrowing object from pool, threads are getting stuck. I initialised the pool size as 1. And had 3 threads created. First thread enters borrowObject method, since there are no idle objects to poll from, it will create one object and move forward.
> {code:java}
> p = (PooledObject)this.idleObjects.pollFirst();
> if (p == null) {
>   p = this.create();
>   if (p != null) {
>      create = true;
>   }
> } {code}
> The other two threads will also follow same path and check for idle objects(there are none), will try to create one object but the pool size is set to 1. Thus, the two threads will move forward and enter *idleObjects.takeFirst()* function. Value of blockWhenExhausted is true and borrowMaxWaitMillis is -1 as we don't want timeout.
> {code:java}
> if (blockWhenExhausted) {
>    if (p == null) {
>       if (borrowMaxWaitMillis < 0L) {
>            p = (PooledObject)this.idleObjects.takeFirst();
>       } else {
>            p = (PooledObject)this.idleObjects.pollFirst(borrowMaxWaitMillis, TimeUnit.MILLISECONDS);
>       }
>    }
>    if (p == null) {
>       throw new NoSuchElementException("Timeout waiting for idle object");
>    }
> }{code}
> Now, the main thread does *this.factory.activateObject(p);* and object gets activated. Now, when the validation is checked *validate = this.factory.validateObject(p);* it comes out to be false as provider might have been disconnected.
> So, the object is destroyed by calling *this.destroy(p);*
> {code:java}
> private void destroy(PooledObject<T> toDestroy) throws Exception {
>      toDestroy.invalidate();
>      this.idleObjects.remove(toDestroy);
>      this.allObjects.remove(new BaseGenericObjectPool.IdentityWrapper(toDestroy.getObject()));
>      try {
>         this.factory.destroyObject(toDestroy);
>      } finally {
>         this.destroyedCount.incrementAndGet();
>         this.createCount.decrementAndGet();
>      }
> }{code}
> The object which was created is now destroyed and removed from idleObject and allObjects list. Now, the other two threads are still waiting to take object from idle objects list but there are no object present. Hence, the two threads are in wait state for infinite period and the application waits forever until we kill the process.
> {code:java}
> public E takeFirst() throws InterruptedException {
>    this.lock.lock();
>    Object var2;
>    try {
>       Object x;
>       while((x = this.unlinkFirst()) == null) {
>          this.notEmpty.await();
>       }
>       var2 = x;
>     } finally {
>       this.lock.unlock();
>     }
>     return var2;
> } {code}



--
This message was sent by Atlassian Jira
(v8.20.10#820010)