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/06/05 19:15:00 UTC

[jira] [Commented] (POOL-412) [GenericKeyedObjectPool] ensureMinIdle not work if last idle evicted

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

Phil Steitz commented on POOL-412:
----------------------------------

This is an interesting use case.  Honestly, I think GKOP is working as designed here.  There is no contract to maintain an immutable, durable set of keys.  Once the last object instance under a key is destroyed, that key no longer exists and ensureMinIdle can't be expected to replenish instances under the key that is no longer there.  Admittedly, eviction as the cause of key death is a little extreme, but I can imagine use cases where that is the desired behavior.   To "fix" this would require that we keep the key alive which for the OPs use case is desired, but may not be desired in other cases and would have to be extended to failed validations, abandoned objects and all other cases where keyed pools are exhausted.  As a workaround for the OP,  I would recommend using addObject to restore the keyed pool when it has been removed.  I would not recommend changing the GKOP contract to support durable keys.

> [GenericKeyedObjectPool] ensureMinIdle not work if last idle evicted
> --------------------------------------------------------------------
>
>                 Key: POOL-412
>                 URL: https://issues.apache.org/jira/browse/POOL-412
>             Project: Commons Pool
>          Issue Type: Bug
>    Affects Versions: 2.11.1
>            Reporter: Oleksandr Porytskyi
>            Priority: Major
>
> I'm trying to use GenericKeyedObjectPool with setMinIdlePerKey(1) and setTestWhileIdle(true).  When object failed validation it is removed but never add new one.
> Evictor has two stages:
> 1. In evict() call destroy() -> deregister(key) -> poolMap.remove(k)
> For some reason it removes key if there are no more objects of it.
>  
> 2. In ensureMinIdle() -> 
> for (final K k : poolMap.keySet()) {
> ensureMinIdle(k);
> }
> poolMap does not have my key anymore so will not create object for it.
>  
> Here one test for GenericObjectPool which pass and one for GenericKeyedObjectPool which not pass for same scenario:
> {code:java}
> @Test
> void testGenericKeyedObjectPool() throws Exception {
>   BaseKeyedPooledObjectFactory<String, Object> baseKeyedPooledObjectFactory = new BaseKeyedPooledObjectFactory<>() {
>     @Override
>     public Object create(String key) throws Exception {
>       return null;
>     }
>     @Override
>     public PooledObject<Object> wrap(Object value) {
>       return new DefaultPooledObject<>(value);
>     }
>   };
>   GenericKeyedObjectPoolConfig<Object> genericKeyedObjectPoolConfig = new GenericKeyedObjectPoolConfig<>();
>   int minIdlePerKey = 1;
>   genericKeyedObjectPoolConfig.setMinIdlePerKey(minIdlePerKey);
>   genericKeyedObjectPoolConfig.setTimeBetweenEvictionRuns(Duration.ofSeconds(1));
>   genericKeyedObjectPoolConfig.setMinEvictableIdleTime(Duration.ofSeconds(5));
>   GenericKeyedObjectPool<String, Object> genericKeyedObjectPool = new GenericKeyedObjectPool<>(
>       baseKeyedPooledObjectFactory, genericKeyedObjectPoolConfig);
>   String key = "key";
>   genericKeyedObjectPool.preparePool(key);
>   Assertions.assertTimeoutPreemptively(Duration.ofMinutes(1), () -> {
>     while (genericKeyedObjectPool.getNumIdle(key) != minIdlePerKey)
>       ;
>   });
>   System.out.println("we prepared pool so we have idle");
>   Assertions.assertTimeoutPreemptively(Duration.ofMinutes(1), () -> {
>     while (genericKeyedObjectPool.getNumIdle(key) != 0)
>       ;
>   });
>   System.out.println("after eviction we have no idle");
>   Assertions.assertTimeoutPreemptively(Duration.ofMinutes(1), () -> {
>     while (genericKeyedObjectPool.getNumIdle(key) != minIdlePerKey)
>       ;
>   });
>   System.out.println("NEVER HAPPEN: after eviction ensure min idle");
> }
> @Test
> void testGenericObjectPool() throws Exception {
>   BasePooledObjectFactory<Object> basePooledObjectFactory = new BasePooledObjectFactory<>() {
>     @Override
>     public Object create() throws Exception {
>       return null;
>     }
>     @Override
>     public PooledObject<Object> wrap(Object obj) {
>       return new DefaultPooledObject<>(obj);
>     }
>   };
>   GenericObjectPoolConfig<Object> genericObjectPoolConfig = new GenericObjectPoolConfig<>();
>   int minIdle = 1;
>   genericObjectPoolConfig.setTimeBetweenEvictionRuns(Duration.ofSeconds(1));
>   genericObjectPoolConfig.setMinIdle(minIdle);
>   genericObjectPoolConfig.setMinEvictableIdleTime(Duration.ofSeconds(5));
>   GenericObjectPool<Object> genericObjectPool = new GenericObjectPool<>(basePooledObjectFactory,
>       genericObjectPoolConfig);
>   genericObjectPool.preparePool();
>   Assertions.assertTimeoutPreemptively(Duration.ofMinutes(1), () -> {
>     while (genericObjectPool.getNumIdle() != minIdle)
>       ;
>   });
>   System.out.println("we prepared pool so we have idle");
>   Assertions.assertTimeoutPreemptively(Duration.ofMinutes(1), () -> {
>     while (genericObjectPool.getNumIdle() != 0)
>       ;
>   });
>   System.out.println("after eviction we have no idle");
>   Assertions.assertTimeoutPreemptively(Duration.ofMinutes(1), () -> {
>     while (genericObjectPool.getNumIdle() != minIdle)
>       ;
>   });
>   System.out.println("after eviction ensure min idle");
> }
>  {code}
> As workaround I can't just subclass GenericKeyedObjectPool and alter deregister as it private.



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