public final class BufferPool {
private final long totalMemory;
private final int poolableSize;
private final ReentrantLock lock;
private final Deque<ByteBuffer> free;
private final Deque<Condition> waiters;
private long availableMemory;
private final Metrics metrics;
private final Time time;
private final Sensor waitTime;
public BufferPool(long memory, int poolableSize, Metrics metrics, Time time, String metricGrpName) {
this.poolableSize = poolableSize;
this.lock = new ReentrantLock();
this.free = new ArrayDeque();
this.waiters = new ArrayDeque();
this.totalMemory = memory;
this.availableMemory = memory;
this.metrics = metrics;
this.time = time;
this.waitTime = this.metrics.sensor("bufferpool-wait-time");
MetricName metricName = metrics.metricName("bufferpool-wait-ratio", metricGrpName, "The fraction of time an appender waits for space allocation.");
this.waitTime.add(metricName, new Rate(TimeUnit.NANOSECONDS));
}
public ByteBuffer allocate(int size, long maxTimeToBlockMs) throws InterruptedException {
if ((long)size > this.totalMemory) {
throw new IllegalArgumentException("Attempt to allocate " + size + " bytes, but there is a hard limit of " + this.totalMemory + " on memory allocations.");
} else {
this.lock.lock();
ByteBuffer var5;
try {
if (size == this.poolableSize && !this.free.isEmpty()) {
ByteBuffer var31 = (ByteBuffer)this.free.pollFirst();
return var31;
}
int freeListSize = this.free.size() * this.poolableSize;
if (this.availableMemory + (long)freeListSize < (long)size) {
int accumulated = 0;
ByteBuffer buffer = null;
Condition moreMemory = this.lock.newCondition();
long remainingTimeToBlockNs = TimeUnit.MILLISECONDS.toNanos(maxTimeToBlockMs);
this.waiters.addLast(moreMemory);
while(accumulated < size) {
long startWaitNs = this.time.nanoseconds();
boolean var27 = false;
long timeNs;
boolean waitingTimeElapsed;
try {
var27 = true;
waitingTimeElapsed = !moreMemory.await(remainingTimeToBlockNs, TimeUnit.NANOSECONDS);
var27 = false;
} catch (InterruptedException var28) {
this.waiters.remove(moreMemory);
throw var28;
} finally {
if (var27) {
long endWaitNs = this.time.nanoseconds();
timeNs = Math.max(0L, endWaitNs - startWaitNs);
this.waitTime.record((double)timeNs, this.time.milliseconds());
}
}
long endWaitNs = this.time.nanoseconds();
timeNs = Math.max(0L, endWaitNs - startWaitNs);
this.waitTime.record((double)timeNs, this.time.milliseconds());
if (waitingTimeElapsed) {
this.waiters.remove(moreMemory);
throw new TimeoutException("Failed to allocate memory within the configured max blocking time " + maxTimeToBlockMs + " ms.");
}
remainingTimeToBlockNs -= timeNs;
if (accumulated == 0 && size == this.poolableSize && !this.free.isEmpty()) {
buffer = (ByteBuffer)this.free.pollFirst();
accumulated = size;
} else {
this.freeUp(size - accumulated);
int got = (int)Math.min((long)(size - accumulated), this.availableMemory);
this.availableMemory -= (long)got;
accumulated += got;
}
}
Condition removed = (Condition)this.waiters.removeFirst();
if (removed != moreMemory) {
throw new IllegalStateException("Wrong condition: this shouldn't happen.");
}
if ((this.availableMemory > 0L || !this.free.isEmpty()) && !this.waiters.isEmpty()) {
((Condition)this.waiters.peekFirst()).signal();
}
this.lock.unlock();
ByteBuffer var11;
if (buffer == null) {
var11 = ByteBuffer.allocate(size);
return var11;
}
var11 = buffer;
return var11;
}
this.freeUp(size);
this.availableMemory -= (long)size;
this.lock.unlock();
var5 = ByteBuffer.allocate(size);
} finally {
if (this.lock.isHeldByCurrentThread()) {
this.lock.unlock();
}
}
return var5;
}
}
kafka的缓存池源码
最新推荐文章于 2024-07-21 18:15:30 发布