[ 
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)

Reply via email to