Oleksandr Porytskyi created POOL-412:
----------------------------------------

             Summary: [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


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