Fixes #10211 - NPE in ArrayByteBufferPool.findOldestEntry() (#10212)

* Fixes #10211 - NPE in ArrayByteBufferPool.findOldestEntry()

Fixed algorithm to check for oldest entry to avoid NPE.
Added comments for clarity.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
Simone Bordet 2023-08-02 22:26:53 +02:00 committed by GitHub
parent 86312f1d11
commit 30ed83f3d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 19 additions and 9 deletions

View File

@ -382,6 +382,8 @@ public class ArrayRetainableByteBufferPool implements RetainableByteBufferPool,
while (totalClearedCapacity < excess) while (totalClearedCapacity < excess)
{ {
// Run through all the buckets to avoid removing
// the buffers only from the first bucket(s).
for (RetainedBucket bucket : buckets) for (RetainedBucket bucket : buckets)
{ {
RetainedBucket.Entry oldestEntry = findOldestEntry(now, bucket); RetainedBucket.Entry oldestEntry = findOldestEntry(now, bucket);
@ -390,13 +392,14 @@ public class ArrayRetainableByteBufferPool implements RetainableByteBufferPool,
if (oldestEntry.remove()) if (oldestEntry.remove())
{ {
int clearedCapacity = oldestEntry.getPooled().capacity(); RetainableByteBuffer buffer = oldestEntry.getPooled();
int clearedCapacity = buffer.capacity();
if (direct) if (direct)
_currentDirectMemory.addAndGet(-clearedCapacity); _currentDirectMemory.addAndGet(-clearedCapacity);
else else
_currentHeapMemory.addAndGet(-clearedCapacity); _currentHeapMemory.addAndGet(-clearedCapacity);
totalClearedCapacity += clearedCapacity; totalClearedCapacity += clearedCapacity;
removed(oldestEntry.getPooled()); removed(buffer);
} }
// else a concurrent thread evicted the same entry -> do not account for its capacity. // else a concurrent thread evicted the same entry -> do not account for its capacity.
} }
@ -430,18 +433,25 @@ public class ArrayRetainableByteBufferPool implements RetainableByteBufferPool,
private Pool<RetainableByteBuffer>.Entry findOldestEntry(long now, Pool<RetainableByteBuffer> bucket) private Pool<RetainableByteBuffer>.Entry findOldestEntry(long now, Pool<RetainableByteBuffer> bucket)
{ {
// This method may be in the hot path, do not use Java streams.
RetainedBucket.Entry oldestEntry = null; RetainedBucket.Entry oldestEntry = null;
RetainableByteBuffer oldestBuffer = null;
long oldestAge = 0;
for (RetainedBucket.Entry entry : bucket.values()) for (RetainedBucket.Entry entry : bucket.values())
{ {
if (oldestEntry != null) RetainableByteBuffer buffer = entry.getPooled();
// A null buffer means the entry is reserved
// but not acquired yet, try the next.
if (buffer != null)
{ {
long entryAge = NanoTime.elapsed(entry.getPooled().getLastUpdate(), now); long age = NanoTime.elapsed(buffer.getLastUpdate(), now);
if (entryAge > NanoTime.elapsed(oldestEntry.getPooled().getLastUpdate(), now)) if (oldestBuffer == null || age > oldestAge)
{
oldestEntry = entry; oldestEntry = entry;
} oldestBuffer = buffer;
else oldestAge = age;
{ }
oldestEntry = entry;
} }
} }
return oldestEntry; return oldestEntry;