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)