sweep the entries list when the max usage count is changed

Signed-off-by: Ludovic Orban <lorban@bitronix.be>
This commit is contained in:
Ludovic Orban 2020-12-01 10:25:20 +01:00
parent 0ff1bfdd5e
commit 44e6f4aeb8
2 changed files with 61 additions and 7 deletions

View File

@ -29,6 +29,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.component.DumpableCollection;
@ -166,16 +167,42 @@ public class Pool<T> implements AutoCloseable, Dumpable
this.maxMultiplex = maxMultiplex;
}
/**
* Get the maximum number of times the entries of the pool
* can be acquired.
* @return the max usage count.
*/
public int getMaxUsageCount()
{
return maxUsageCount;
}
/**
* Change the max usage count of the pool's entries. All existing
* idle entries over this new max usage are removed and closed.
* @param maxUsageCount the max usage count.
*/
public final void setMaxUsageCount(int maxUsageCount)
{
if (maxUsageCount == 0)
throw new IllegalArgumentException("Max usage count must be != 0");
this.maxUsageCount = maxUsageCount;
// Iterate the entries, remove overused ones and collect a list of the closeable removed ones.
List<Closeable> copy;
try (Locker.Lock l = locker.lock())
{
if (closed)
return;
copy = entries.stream()
.filter(entry -> entry.isIdleAndOverUsed() && remove(entry) && entry.pooled instanceof Closeable)
.map(entry -> (Closeable)entry.pooled)
.collect(Collectors.toList());
}
// Iterate the copy and close the collected entries.
copy.forEach(IO::close);
}
/**
@ -571,13 +598,6 @@ public class Pool<T> implements AutoCloseable, Dumpable
return !(overUsed && newMultiplexingCount == 0);
}
public boolean isOverUsed()
{
int currentMaxUsageCount = maxUsageCount;
int usageCount = state.getHi();
return currentMaxUsageCount > 0 && usageCount >= currentMaxUsageCount;
}
/**
* Try to mark the entry as removed.
* @return true if the entry has to be removed from the containing pool, false otherwise.
@ -618,6 +638,22 @@ public class Pool<T> implements AutoCloseable, Dumpable
return AtomicBiInteger.getHi(encoded) >= 0 && AtomicBiInteger.getLo(encoded) > 0;
}
public boolean isOverUsed()
{
int currentMaxUsageCount = maxUsageCount;
int usageCount = state.getHi();
return currentMaxUsageCount > 0 && usageCount >= currentMaxUsageCount;
}
boolean isIdleAndOverUsed()
{
int currentMaxUsageCount = maxUsageCount;
long encoded = state.get();
int usageCount = AtomicBiInteger.getHi(encoded);
int multiplexCount = AtomicBiInteger.getLo(encoded);
return currentMaxUsageCount > 0 && usageCount >= currentMaxUsageCount && multiplexCount == 0;
}
public int getUsageCount()
{
return Math.max(state.getHi(), 0);

View File

@ -572,6 +572,24 @@ public class PoolTest
assertThat(acquired2, nullValue());
}
@ParameterizedTest
@MethodSource(value = "strategy")
public void testDynamicMaxUsageCountChangeSweep(Factory factory)
{
Pool<String> pool = factory.getPool(2);
Pool<String>.Entry entry1 = pool.reserve(-1);
entry1.enable("aaa", false);
Pool<String>.Entry entry2 = pool.reserve(-1);
entry2.enable("bbb", false);
Pool<String>.Entry acquired1 = pool.acquire();
assertThat(acquired1, notNullValue());
assertThat(pool.release(acquired1), is(true));
pool.setMaxUsageCount(1);
assertThat(pool.size(), is(1));
}
@Test
public void testConfigLimits()
{