Second, more complete draft of porting over the pooling allocator from Netty
This commit is contained in:
parent
ae2abdd2aa
commit
b4b0afd787
|
@ -1,5 +1,6 @@
|
||||||
package io.netty.buffer.api.pool;
|
package io.netty.buffer.api.pool;
|
||||||
|
|
||||||
|
import io.netty.buffer.api.AllocatorControl;
|
||||||
import io.netty.buffer.api.Buffer;
|
import io.netty.buffer.api.Buffer;
|
||||||
import io.netty.buffer.api.BufferAllocator;
|
import io.netty.buffer.api.BufferAllocator;
|
||||||
import io.netty.buffer.api.MemoryManager;
|
import io.netty.buffer.api.MemoryManager;
|
||||||
|
@ -14,7 +15,7 @@ import java.util.concurrent.atomic.LongAdder;
|
||||||
import static io.netty.buffer.api.pool.PoolChunk.isSubpage;
|
import static io.netty.buffer.api.pool.PoolChunk.isSubpage;
|
||||||
import static java.lang.Math.max;
|
import static java.lang.Math.max;
|
||||||
|
|
||||||
class PoolArena extends SizeClasses implements PoolArenaMetric {
|
class PoolArena extends SizeClasses implements PoolArenaMetric, AllocatorControl {
|
||||||
enum SizeClass {
|
enum SizeClass {
|
||||||
Small,
|
Small,
|
||||||
Normal
|
Normal
|
||||||
|
@ -98,13 +99,13 @@ class PoolArena extends SizeClasses implements PoolArenaMetric {
|
||||||
return manager.isNative();
|
return manager.isNative();
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer allocate(PoolThreadCache cache, int size) {
|
Buffer allocate(PooledAllocatorControl control, PoolThreadCache cache, int size) {
|
||||||
final int sizeIdx = size2SizeIdx(size);
|
final int sizeIdx = size2SizeIdx(size);
|
||||||
|
|
||||||
if (sizeIdx <= smallMaxSizeIdx) {
|
if (sizeIdx <= smallMaxSizeIdx) {
|
||||||
return tcacheAllocateSmall(cache, size, sizeIdx);
|
return tcacheAllocateSmall(control, cache, size, sizeIdx);
|
||||||
} else if (sizeIdx < nSizes) {
|
} else if (sizeIdx < nSizes) {
|
||||||
return tcacheAllocateNormal(cache, size, sizeIdx);
|
return tcacheAllocateNormal(control, cache, size, sizeIdx);
|
||||||
} else {
|
} else {
|
||||||
int normCapacity = directMemoryCacheAlignment > 0
|
int normCapacity = directMemoryCacheAlignment > 0
|
||||||
? normalizeSize(size) : size;
|
? normalizeSize(size) : size;
|
||||||
|
@ -113,9 +114,9 @@ class PoolArena extends SizeClasses implements PoolArenaMetric {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Buffer tcacheAllocateSmall(PoolThreadCache cache, final int size,
|
private Buffer tcacheAllocateSmall(PooledAllocatorControl control, PoolThreadCache cache, final int size,
|
||||||
final int sizeIdx) {
|
final int sizeIdx) {
|
||||||
Buffer buffer = cache.allocateSmall(size, sizeIdx);
|
Buffer buffer = cache.allocateSmall(control, size, sizeIdx);
|
||||||
if (buffer != null) {
|
if (buffer != null) {
|
||||||
// was able to allocate out of the cache so move on
|
// was able to allocate out of the cache so move on
|
||||||
return buffer;
|
return buffer;
|
||||||
|
@ -134,13 +135,13 @@ class PoolArena extends SizeClasses implements PoolArenaMetric {
|
||||||
assert s.doNotDestroy && s.elemSize == sizeIdx2size(sizeIdx);
|
assert s.doNotDestroy && s.elemSize == sizeIdx2size(sizeIdx);
|
||||||
long handle = s.allocate();
|
long handle = s.allocate();
|
||||||
assert handle >= 0;
|
assert handle >= 0;
|
||||||
buffer = s.chunk.allocateBufferWithSubpage(handle, size, cache);
|
buffer = s.chunk.allocateBufferWithSubpage(handle, size, cache, control);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsNormalAllocation) {
|
if (needsNormalAllocation) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
buffer = allocateNormal(size, sizeIdx, cache);
|
buffer = allocateNormal(size, sizeIdx, cache, control);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,45 +149,45 @@ class PoolArena extends SizeClasses implements PoolArenaMetric {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Buffer tcacheAllocateNormal(PoolThreadCache cache, int size, int sizeIdx) {
|
private Buffer tcacheAllocateNormal(PooledAllocatorControl control, PoolThreadCache cache, int size, int sizeIdx) {
|
||||||
Buffer buffer = cache.allocateNormal(this, size, sizeIdx);
|
Buffer buffer = cache.allocateNormal(this, control, size, sizeIdx);
|
||||||
if (buffer != null) {
|
if (buffer != null) {
|
||||||
// was able to allocate out of the cache so move on
|
// was able to allocate out of the cache so move on
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
buffer = allocateNormal(size, sizeIdx, cache);
|
buffer = allocateNormal(size, sizeIdx, cache, control);
|
||||||
allocationsNormal++;
|
allocationsNormal++;
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method must be called inside synchronized(this) { ... } block
|
// Method must be called inside synchronized(this) { ... } block
|
||||||
private Buffer allocateNormal(int size, int sizeIdx, PoolThreadCache threadCache) {
|
private Buffer allocateNormal(int size, int sizeIdx, PoolThreadCache threadCache, PooledAllocatorControl control) {
|
||||||
Buffer buffer = q050.allocate(size, sizeIdx, threadCache);
|
Buffer buffer = q050.allocate(size, sizeIdx, threadCache, control);
|
||||||
if (buffer != null) {
|
if (buffer != null) {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
buffer = q025.allocate(size, sizeIdx, threadCache);
|
buffer = q025.allocate(size, sizeIdx, threadCache, control);
|
||||||
if (buffer != null) {
|
if (buffer != null) {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
buffer = q000.allocate(size, sizeIdx, threadCache);
|
buffer = q000.allocate(size, sizeIdx, threadCache, control);
|
||||||
if (buffer != null) {
|
if (buffer != null) {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
buffer = qInit.allocate(size, sizeIdx, threadCache);
|
buffer = qInit.allocate(size, sizeIdx, threadCache, control);
|
||||||
if (buffer != null) {
|
if (buffer != null) {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
buffer = q075.allocate(size, sizeIdx, threadCache);
|
buffer = q075.allocate(size, sizeIdx, threadCache, control);
|
||||||
if (buffer != null) {
|
if (buffer != null) {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a new chunk.
|
// Add a new chunk.
|
||||||
PoolChunk c = newChunk(pageSize, nPSizes, pageShifts, chunkSize);
|
PoolChunk c = newChunk(pageSize, nPSizes, pageShifts, chunkSize);
|
||||||
buffer = c.allocate(size, sizeIdx, threadCache);
|
buffer = c.allocate(size, sizeIdx, threadCache, control);
|
||||||
assert buffer != null;
|
assert buffer != null;
|
||||||
qInit.add(c);
|
qInit.add(c);
|
||||||
return buffer;
|
return buffer;
|
||||||
|
@ -249,6 +250,18 @@ class PoolArena extends SizeClasses implements PoolArenaMetric {
|
||||||
return smallSubpagePools[sizeIdx];
|
return smallSubpagePools[sizeIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object allocateUntethered(Buffer originator, int size) {
|
||||||
|
throw new AssertionError("PoolChunk base buffers should never need to reallocate.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recoverMemory(Object memory) {
|
||||||
|
// This means we've lost all strong references to a PoolChunk.
|
||||||
|
// Probably means we don't need it anymore, so just free its memory.
|
||||||
|
manager.discardRecoverableMemory(memory);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int numThreadCaches() {
|
public int numThreadCaches() {
|
||||||
return numThreadCaches.get();
|
return numThreadCaches.get();
|
||||||
|
@ -397,7 +410,7 @@ class PoolArena extends SizeClasses implements PoolArenaMetric {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final PoolChunk newChunk(int pageSize, int maxPageIdx, int pageShifts, int chunkSize) {
|
protected final PoolChunk newChunk(int pageSize, int maxPageIdx, int pageShifts, int chunkSize) {
|
||||||
Buffer base = manager.allocateShared(parent, chunkSize, manager.drop(), Statics.CLEANER);
|
Buffer base = manager.allocateShared(this, chunkSize, manager.drop(), Statics.CLEANER);
|
||||||
Object memory = manager.unwrapRecoverableMemory(base);
|
Object memory = manager.unwrapRecoverableMemory(base);
|
||||||
return new PoolChunk(
|
return new PoolChunk(
|
||||||
this, base, memory, pageSize, pageShifts, chunkSize, maxPageIdx);
|
this, base, memory, pageSize, pageShifts, chunkSize, maxPageIdx);
|
||||||
|
@ -454,4 +467,13 @@ class PoolArena extends SizeClasses implements PoolArenaMetric {
|
||||||
} while (s != head);
|
} while (s != head);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
for (PoolSubpage page : smallSubpagePools) {
|
||||||
|
page.destroy();
|
||||||
|
}
|
||||||
|
for (PoolChunkList list : new PoolChunkList[] {qInit, q000, q025, q050, q100}) {
|
||||||
|
list.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,20 +175,6 @@ final class PoolChunk implements PoolChunkMetric {
|
||||||
insertAvailRun(0, pages, initHandle);
|
insertAvailRun(0, pages, initHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a special chunk that is not pooled. */
|
|
||||||
PoolChunk(PoolArena arena, Buffer base, Object memory, int size) {
|
|
||||||
unpooled = true;
|
|
||||||
this.arena = arena;
|
|
||||||
this.base = base;
|
|
||||||
this.memory = memory;
|
|
||||||
pageSize = 0;
|
|
||||||
pageShifts = 0;
|
|
||||||
runsAvailMap = null;
|
|
||||||
runsAvail = null;
|
|
||||||
subpages = null;
|
|
||||||
chunkSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static LongPriorityQueue[] newRunsAvailqueueArray(int size) {
|
private static LongPriorityQueue[] newRunsAvailqueueArray(int size) {
|
||||||
LongPriorityQueue[] queueArray = new LongPriorityQueue[size];
|
LongPriorityQueue[] queueArray = new LongPriorityQueue[size];
|
||||||
for (int i = 0; i < queueArray.length; i++) {
|
for (int i = 0; i < queueArray.length; i++) {
|
||||||
|
@ -263,7 +249,7 @@ final class PoolChunk implements PoolChunkMetric {
|
||||||
return 100 - freePercentage;
|
return 100 - freePercentage;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer allocate(int size, int sizeIdx, PoolThreadCache cache) {
|
Buffer allocate(int size, int sizeIdx, PoolThreadCache cache, PooledAllocatorControl control) {
|
||||||
final long handle;
|
final long handle;
|
||||||
if (sizeIdx <= arena.smallMaxSizeIdx) {
|
if (sizeIdx <= arena.smallMaxSizeIdx) {
|
||||||
// small
|
// small
|
||||||
|
@ -282,7 +268,7 @@ final class PoolChunk implements PoolChunkMetric {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return allocateBuffer(handle, size, cache);
|
return allocateBuffer(handle, size, cache, control);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long allocateRun(int runSize) {
|
private long allocateRun(int runSize) {
|
||||||
|
@ -514,23 +500,25 @@ final class PoolChunk implements PoolChunkMetric {
|
||||||
| (long) inUsed << IS_USED_SHIFT;
|
| (long) inUsed << IS_USED_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer allocateBuffer(long handle, int size, PoolThreadCache threadCache) {
|
Buffer allocateBuffer(long handle, int size, PoolThreadCache threadCache, PooledAllocatorControl control) {
|
||||||
if (isRun(handle)) {
|
if (isRun(handle)) {
|
||||||
int offset = runOffset(handle) << pageShifts;
|
int offset = runOffset(handle) << pageShifts;
|
||||||
int maxLength = runSize(pageShifts, handle);
|
int maxLength = runSize(pageShifts, handle);
|
||||||
PoolThreadCache poolThreadCache = arena.parent.threadCache();
|
PoolThreadCache poolThreadCache = arena.parent.threadCache();
|
||||||
return arena.manager.recoverMemory(arena.parent, memory, offset, size, new Drop<Buffer>() {
|
initAllocatorControl(control, poolThreadCache, handle, maxLength, offset, size);
|
||||||
|
return arena.manager.recoverMemory(control, memory, offset, size, new Drop<Buffer>() {
|
||||||
@Override
|
@Override
|
||||||
public void drop(Buffer obj) {
|
public void drop(Buffer obj) {
|
||||||
arena.free(PoolChunk.this, handle, maxLength, poolThreadCache);
|
arena.free(PoolChunk.this, handle, maxLength, poolThreadCache);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return allocateBufferWithSubpage(handle, size, threadCache);
|
return allocateBufferWithSubpage(handle, size, threadCache, control);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer allocateBufferWithSubpage(long handle, int size, PoolThreadCache threadCache) {
|
Buffer allocateBufferWithSubpage(long handle, int size, PoolThreadCache threadCache,
|
||||||
|
PooledAllocatorControl control) {
|
||||||
int runOffset = runOffset(handle);
|
int runOffset = runOffset(handle);
|
||||||
int bitmapIdx = bitmapIdx(handle);
|
int bitmapIdx = bitmapIdx(handle);
|
||||||
|
|
||||||
|
@ -539,7 +527,8 @@ final class PoolChunk implements PoolChunkMetric {
|
||||||
assert size <= s.elemSize;
|
assert size <= s.elemSize;
|
||||||
|
|
||||||
int offset = (runOffset << pageShifts) + bitmapIdx * s.elemSize;
|
int offset = (runOffset << pageShifts) + bitmapIdx * s.elemSize;
|
||||||
return arena.manager.recoverMemory(arena.parent, memory, offset, size, new Drop<Buffer>() {
|
initAllocatorControl(control, threadCache, handle, s.elemSize, offset, size);
|
||||||
|
return arena.manager.recoverMemory(control, memory, offset, size, new Drop<Buffer>() {
|
||||||
@Override
|
@Override
|
||||||
public void drop(Buffer obj) {
|
public void drop(Buffer obj) {
|
||||||
arena.free(PoolChunk.this, handle, s.elemSize, threadCache);
|
arena.free(PoolChunk.this, handle, s.elemSize, threadCache);
|
||||||
|
@ -547,6 +536,18 @@ final class PoolChunk implements PoolChunkMetric {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initAllocatorControl(PooledAllocatorControl control, PoolThreadCache threadCache, long handle,
|
||||||
|
int normSize, int offset, int size) {
|
||||||
|
control.arena = arena;
|
||||||
|
control.chunk = this;
|
||||||
|
control.threadCache = threadCache;
|
||||||
|
control.handle = handle;
|
||||||
|
control.normSize = normSize;
|
||||||
|
control.memory = memory;
|
||||||
|
control.offset = offset;
|
||||||
|
control.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int chunkSize() {
|
public int chunkSize() {
|
||||||
return chunkSize;
|
return chunkSize;
|
||||||
|
|
|
@ -76,7 +76,7 @@ final class PoolChunkList implements PoolChunkListMetric {
|
||||||
this.prevList = prevList;
|
this.prevList = prevList;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer allocate(int size, int sizeIdx, PoolThreadCache threadCache) {
|
Buffer allocate(int size, int sizeIdx, PoolThreadCache threadCache, PooledAllocatorControl control) {
|
||||||
int normCapacity = arena.sizeIdx2size(sizeIdx);
|
int normCapacity = arena.sizeIdx2size(sizeIdx);
|
||||||
if (normCapacity > maxCapacity) {
|
if (normCapacity > maxCapacity) {
|
||||||
// Either this PoolChunkList is empty, or the requested capacity is larger than the capacity which can
|
// Either this PoolChunkList is empty, or the requested capacity is larger than the capacity which can
|
||||||
|
@ -85,7 +85,7 @@ final class PoolChunkList implements PoolChunkListMetric {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (PoolChunk cur = head; cur != null; cur = cur.next) {
|
for (PoolChunk cur = head; cur != null; cur = cur.next) {
|
||||||
Buffer buffer = cur.allocate(size, sizeIdx, threadCache);
|
Buffer buffer = cur.allocate(size, sizeIdx, threadCache, control);
|
||||||
if (buffer != null) {
|
if (buffer != null) {
|
||||||
if (cur.freeBytes <= freeMinThreshold) {
|
if (cur.freeBytes <= freeMinThreshold) {
|
||||||
remove(cur);
|
remove(cur);
|
||||||
|
@ -223,10 +223,10 @@ final class PoolChunkList implements PoolChunkListMetric {
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy(PoolArena arena) {
|
void destroy() {
|
||||||
PoolChunk chunk = head;
|
PoolChunk chunk = head;
|
||||||
while (chunk != null) {
|
while (chunk != null) {
|
||||||
arena.destroyChunk(chunk);
|
chunk.destroy();
|
||||||
chunk = chunk.next;
|
chunk = chunk.next;
|
||||||
}
|
}
|
||||||
head = null;
|
head = null;
|
||||||
|
|
|
@ -106,24 +106,24 @@ final class PoolThreadCache {
|
||||||
/**
|
/**
|
||||||
* Try to allocate a small buffer out of the cache. Returns {@code true} if successful {@code false} otherwise
|
* Try to allocate a small buffer out of the cache. Returns {@code true} if successful {@code false} otherwise
|
||||||
*/
|
*/
|
||||||
Buffer allocateSmall(int size, int sizeIdx) {
|
Buffer allocateSmall(PooledAllocatorControl control, int size, int sizeIdx) {
|
||||||
return allocate(cacheForSmall(sizeIdx), size);
|
return allocate(cacheForSmall(sizeIdx), control, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to allocate a normal buffer out of the cache. Returns {@code true} if successful {@code false} otherwise
|
* Try to allocate a normal buffer out of the cache. Returns {@code true} if successful {@code false} otherwise
|
||||||
*/
|
*/
|
||||||
Buffer allocateNormal(PoolArena area, int size, int sizeIdx) {
|
Buffer allocateNormal(PoolArena area, PooledAllocatorControl control, int size, int sizeIdx) {
|
||||||
return allocate(cacheForNormal(area, sizeIdx), size);
|
return allocate(cacheForNormal(area, sizeIdx), control, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Buffer allocate(MemoryRegionCache cache, int size) {
|
private Buffer allocate(MemoryRegionCache cache, PooledAllocatorControl control, int size) {
|
||||||
if (cache == null) {
|
if (cache == null) {
|
||||||
// no cache found so just return false here
|
// no cache found so just return false here
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Buffer allocated = cache.allocate(size, this);
|
Buffer allocated = cache.allocate(size, this, control);
|
||||||
if (++ allocations >= freeSweepAllocationThreshold) {
|
if (++allocations >= freeSweepAllocationThreshold) {
|
||||||
allocations = 0;
|
allocations = 0;
|
||||||
trim();
|
trim();
|
||||||
}
|
}
|
||||||
|
@ -237,8 +237,9 @@ final class PoolThreadCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Buffer allocBuf(PoolChunk chunk, long handle, int size, PoolThreadCache threadCache) {
|
protected Buffer allocBuf(PoolChunk chunk, long handle, int size, PoolThreadCache threadCache,
|
||||||
return chunk.allocateBufferWithSubpage(handle, size, threadCache);
|
PooledAllocatorControl control) {
|
||||||
|
return chunk.allocateBufferWithSubpage(handle, size, threadCache, control);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,8 +252,9 @@ final class PoolThreadCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Buffer allocBuf(PoolChunk chunk, long handle, int size, PoolThreadCache threadCache) {
|
protected Buffer allocBuf(PoolChunk chunk, long handle, int size, PoolThreadCache threadCache,
|
||||||
return chunk.allocateBuffer(handle, size, threadCache);
|
PooledAllocatorControl control) {
|
||||||
|
return chunk.allocateBuffer(handle, size, threadCache, control);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,7 +273,8 @@ final class PoolThreadCache {
|
||||||
/**
|
/**
|
||||||
* Allocate a new {@link Buffer} using the provided chunk and handle with the capacity restrictions.
|
* Allocate a new {@link Buffer} using the provided chunk and handle with the capacity restrictions.
|
||||||
*/
|
*/
|
||||||
protected abstract Buffer allocBuf(PoolChunk chunk, long handle, int size, PoolThreadCache threadCache);
|
protected abstract Buffer allocBuf(PoolChunk chunk, long handle, int size, PoolThreadCache threadCache,
|
||||||
|
PooledAllocatorControl control);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add to cache if not already full.
|
* Add to cache if not already full.
|
||||||
|
@ -290,12 +293,12 @@ final class PoolThreadCache {
|
||||||
/**
|
/**
|
||||||
* Allocate something out of the cache if possible and remove the entry from the cache.
|
* Allocate something out of the cache if possible and remove the entry from the cache.
|
||||||
*/
|
*/
|
||||||
public final Buffer allocate(int size, PoolThreadCache threadCache) {
|
public final Buffer allocate(int size, PoolThreadCache threadCache, PooledAllocatorControl control) {
|
||||||
Entry entry = queue.poll();
|
Entry entry = queue.poll();
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Buffer buffer = allocBuf(entry.chunk, entry.handle, size, threadCache);
|
Buffer buffer = allocBuf(entry.chunk, entry.handle, size, threadCache, control);
|
||||||
entry.recycle();
|
entry.recycle();
|
||||||
|
|
||||||
// allocations are not thread-safe which is fine as this is only called from the same thread all time.
|
// allocations are not thread-safe which is fine as this is only called from the same thread all time.
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
package io.netty.buffer.api.pool;
|
||||||
|
|
||||||
|
import io.netty.buffer.api.AllocatorControl;
|
||||||
|
import io.netty.buffer.api.Buffer;
|
||||||
|
|
||||||
|
class PooledAllocatorControl implements AllocatorControl {
|
||||||
|
public PoolArena arena;
|
||||||
|
public PoolChunk chunk;
|
||||||
|
public PoolThreadCache threadCache;
|
||||||
|
public long handle;
|
||||||
|
public int normSize;
|
||||||
|
public Object memory;
|
||||||
|
public int offset;
|
||||||
|
public int size;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object allocateUntethered(Buffer originator, int size) {
|
||||||
|
Buffer allocate = arena.parent.allocate(this, size);
|
||||||
|
return arena.manager.unwrapRecoverableMemory(allocate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recoverMemory(Object memory) {
|
||||||
|
arena.free(chunk, handle, normSize, threadCache);
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class PooledByteBufAllocator implements BufferAllocator, ByteBufAllocatorMetricProvider, AllocatorControl {
|
public class PooledByteBufAllocator implements BufferAllocator, ByteBufAllocatorMetricProvider {
|
||||||
|
|
||||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(PooledByteBufAllocator.class);
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(PooledByteBufAllocator.class);
|
||||||
private static final int DEFAULT_NUM_HEAP_ARENA;
|
private static final int DEFAULT_NUM_HEAP_ARENA;
|
||||||
|
@ -257,7 +257,7 @@ public class PooledByteBufAllocator implements BufferAllocator, ByteBufAllocator
|
||||||
|
|
||||||
// Ensure the resulting chunkSize does not overflow.
|
// Ensure the resulting chunkSize does not overflow.
|
||||||
int chunkSize = pageSize;
|
int chunkSize = pageSize;
|
||||||
for (int i = maxOrder; i > 0; i --) {
|
for (int i = maxOrder; i > 0; i--) {
|
||||||
if (chunkSize > MAX_CHUNK_SIZE / 2) {
|
if (chunkSize > MAX_CHUNK_SIZE / 2) {
|
||||||
throw new IllegalArgumentException(String.format(
|
throw new IllegalArgumentException(String.format(
|
||||||
"pageSize (%d) << maxOrder (%d) must not exceed %d", pageSize, maxOrder, MAX_CHUNK_SIZE));
|
"pageSize (%d) << maxOrder (%d) must not exceed %d", pageSize, maxOrder, MAX_CHUNK_SIZE));
|
||||||
|
@ -269,25 +269,25 @@ public class PooledByteBufAllocator implements BufferAllocator, ByteBufAllocator
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Buffer allocate(int size) {
|
public Buffer allocate(int size) {
|
||||||
|
return allocate(new PooledAllocatorControl(), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer allocate(PooledAllocatorControl control, int size) {
|
||||||
PoolThreadCache cache = threadCache.get();
|
PoolThreadCache cache = threadCache.get();
|
||||||
PoolArena arena = cache.arena;
|
PoolArena arena = cache.arena;
|
||||||
|
|
||||||
if (arena != null) {
|
if (arena != null) {
|
||||||
return arena.allocate(cache, size);
|
return arena.allocate(control, cache, size);
|
||||||
}
|
}
|
||||||
BufferAllocator unpooled = manager.isNative()? BufferAllocator.direct() : BufferAllocator.heap();
|
BufferAllocator unpooled = manager.isNative()? BufferAllocator.direct() : BufferAllocator.heap();
|
||||||
return unpooled.allocate(size);
|
return unpooled.allocate(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object allocateUntethered(Buffer originator, int size) {
|
public void close() {
|
||||||
// TODO
|
for (PoolArena arena : arenas) {
|
||||||
return null;
|
arena.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void recoverMemory(Object memory) {
|
|
||||||
// TODO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue
Block a user