Remove the notion of ByteBufAllocator.bufferMaxCapacity()

- Allocate the unpooled memory if the requested capacity is greater then the chunkSize
- Fixes #834
This commit is contained in:
Trustin Lee 2012-12-19 17:35:32 +09:00
parent 35c01660da
commit 67da6e4bf9
7 changed files with 103 additions and 49 deletions

View File

@ -18,28 +18,18 @@ package io.netty.buffer;
public abstract class AbstractByteBufAllocator implements ByteBufAllocator {
private final int bufferMaxCapacity;
private final boolean directByDefault;
private final ByteBuf emptyBuf;
protected AbstractByteBufAllocator(int bufferMaxCapacity) {
this(bufferMaxCapacity, false);
protected AbstractByteBufAllocator() {
this(false);
}
protected AbstractByteBufAllocator(int bufferMaxCapacity, boolean directByDefault) {
if (bufferMaxCapacity <= 0) {
throw new IllegalArgumentException("bufferMaxCapacity: " + bufferMaxCapacity + " (expected: 1+)");
}
protected AbstractByteBufAllocator(boolean directByDefault) {
this.directByDefault = directByDefault;
this.bufferMaxCapacity = bufferMaxCapacity;
emptyBuf = new UnpooledHeapByteBuf(this, 0, 0);
}
@Override
public int bufferMaxCapacity() {
return bufferMaxCapacity;
}
@Override
public ByteBuf buffer() {
if (directByDefault) {
@ -66,12 +56,12 @@ public abstract class AbstractByteBufAllocator implements ByteBufAllocator {
@Override
public ByteBuf heapBuffer() {
return heapBuffer(256, bufferMaxCapacity());
return heapBuffer(256, Integer.MAX_VALUE);
}
@Override
public ByteBuf heapBuffer(int initialCapacity) {
return heapBuffer(initialCapacity, bufferMaxCapacity());
return heapBuffer(initialCapacity, Integer.MAX_VALUE);
}
@Override
@ -85,12 +75,12 @@ public abstract class AbstractByteBufAllocator implements ByteBufAllocator {
@Override
public ByteBuf directBuffer() {
return directBuffer(256, bufferMaxCapacity());
return directBuffer(256, Integer.MAX_VALUE);
}
@Override
public ByteBuf directBuffer(int initialCapacity) {
return directBuffer(initialCapacity, bufferMaxCapacity());
return directBuffer(initialCapacity, Integer.MAX_VALUE);
}
@Override
@ -138,10 +128,9 @@ public abstract class AbstractByteBufAllocator implements ByteBufAllocator {
return new DefaultCompositeByteBuf(this, true, maxNumComponents);
}
private void validate(int initialCapacity, int maxCapacity) {
if (maxCapacity > bufferMaxCapacity()) {
throw new IllegalArgumentException(
"maxCapacity: " + maxCapacity + " (expected: not greater than " + bufferMaxCapacity());
private static void validate(int initialCapacity, int maxCapacity) {
if (initialCapacity < 0) {
throw new IllegalArgumentException("initialCapacity: " + initialCapacity + " (expectd: 0+)");
}
if (initialCapacity > maxCapacity) {
throw new IllegalArgumentException(String.format(

View File

@ -34,6 +34,4 @@ public interface ByteBufAllocator {
CompositeByteBuf compositeHeapBuffer(int maxNumComponents);
CompositeByteBuf compositeDirectBuffer();
CompositeByteBuf compositeDirectBuffer(int maxNumComponents);
int bufferMaxCapacity();
}

View File

@ -130,6 +130,9 @@ abstract class PoolArena<T> {
}
}
}
} else if (normCapacity > chunkSize) {
allocateHuge(buf, reqCapacity);
return;
}
allocateNormal(buf, reqCapacity, normCapacity);
@ -150,9 +153,17 @@ abstract class PoolArena<T> {
qInit.add(c);
}
private void allocateHuge(PooledByteBuf<T> buf, int reqCapacity) {
buf.initUnpooled(newUnpooledChunk(reqCapacity), reqCapacity);
}
synchronized void free(PoolChunk<T> chunk, long handle) {
if (chunk.unpooled) {
destroyChunk(chunk);
} else {
chunk.parent.free(chunk, handle);
}
}
void addSubpage(PoolSubpage<T> subpage) {
int tableIdx;
@ -175,8 +186,11 @@ abstract class PoolArena<T> {
}
private int normalizeCapacity(int reqCapacity) {
if (reqCapacity < 0 || reqCapacity > chunkSize) {
throw new IllegalArgumentException("capacity: " + reqCapacity + " (expected: 0-" + chunkSize + ')');
if (reqCapacity < 0) {
throw new IllegalArgumentException("capacity: " + reqCapacity + " (expected: 0+)");
}
if (reqCapacity >= chunkSize) {
return reqCapacity;
}
if ((reqCapacity & 0xFFFFFE00) != 0) { // >= 512
@ -240,6 +254,7 @@ abstract class PoolArena<T> {
}
protected abstract PoolChunk<T> newChunk(int pageSize, int maxOrder, int pageShifts, int chunkSize);
protected abstract PoolChunk<T> newUnpooledChunk(int capacity);
protected abstract PooledByteBuf<T> newByteBuf(int maxCapacity);
protected abstract void memoryCopy(T src, int srcOffset, T dst, int dstOffset, int length);
protected abstract void destroyChunk(PoolChunk<T> chunk);
@ -311,6 +326,11 @@ abstract class PoolArena<T> {
return new PoolChunk<byte[]>(this, new byte[chunkSize], pageSize, maxOrder, pageShifts, chunkSize);
}
@Override
protected PoolChunk<byte[]> newUnpooledChunk(int capacity) {
return new PoolChunk<byte[]>(this, new byte[capacity], capacity);
}
@Override
protected void destroyChunk(PoolChunk<byte[]> chunk) {
// Rely on GC.
@ -343,6 +363,11 @@ abstract class PoolArena<T> {
this, ByteBuffer.allocateDirect(chunkSize), pageSize, maxOrder, pageShifts, chunkSize);
}
@Override
protected PoolChunk<ByteBuffer> newUnpooledChunk(int capacity) {
return new PoolChunk<ByteBuffer>(this, ByteBuffer.allocateDirect(capacity), capacity);
}
@Override
protected void destroyChunk(PoolChunk<ByteBuffer> chunk) {
UnpooledDirectByteBuf.freeDirect(chunk.memory);

View File

@ -28,6 +28,7 @@ final class PoolChunk<T> {
final PoolArena<T> arena;
final T memory;
final boolean unpooled;
private final int[] memoryMap;
private final PoolSubpage<T>[] subpages;
@ -51,6 +52,7 @@ final class PoolChunk<T> {
//private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7;
PoolChunk(PoolArena<T> arena, T memory, int pageSize, int maxOrder, int pageShifts, int chunkSize) {
unpooled = false;
this.arena = arena;
this.memory = memory;
this.pageSize = pageSize;
@ -76,6 +78,20 @@ final class PoolChunk<T> {
subpages = newSubpageArray(maxSubpageAllocs);
}
/** Creates a special chunk that is not pooled. */
PoolChunk(PoolArena<T> arena, T memory, int size) {
unpooled = true;
this.arena = arena;
this.memory = memory;
memoryMap = null;
subpages = null;
subpageOverflowMask = 0;
pageSize = 0;
pageShifts = 0;
chunkSize = size;
maxSubpageAllocs = 0;
}
@SuppressWarnings("unchecked")
private PoolSubpage<T>[] newSubpageArray(int size) {
return new PoolSubpage[size];
@ -266,7 +282,7 @@ final class PoolChunk<T> {
if (bitmapIdx == 0) {
int val = memoryMap[memoryMapIdx];
assert (val & 3) == ST_ALLOCATED : String.valueOf(val & 3);
buf.init(this, handle, memory, runOffset(val), reqCapacity, runLength(val));
buf.init(this, handle, runOffset(val), reqCapacity, runLength(val));
} else {
initBufWithSubpage(buf, handle, bitmapIdx, reqCapacity);
}
@ -288,7 +304,7 @@ final class PoolChunk<T> {
assert reqCapacity <= subpage.elemSize;
buf.init(
this, handle, memory,
this, handle,
runOffset(val) + (bitmapIdx & 0x3FFFFFFF) * subpage.elemSize, reqCapacity, subpage.elemSize);
}

View File

@ -37,13 +37,13 @@ abstract class PooledByteBuf<T> extends AbstractByteBuf {
super(maxCapacity);
}
final void init(PoolChunk<T> chunk, long handle, T memory, int offset, int length, int maxLength) {
final void init(PoolChunk<T> chunk, long handle, int offset, int length, int maxLength) {
assert handle >= 0;
assert memory != null;
assert chunk != null;
this.chunk = chunk;
this.handle = handle;
this.memory = memory;
memory = chunk.memory;
this.offset = offset;
this.length = length;
this.maxLength = maxLength;
@ -51,6 +51,18 @@ abstract class PooledByteBuf<T> extends AbstractByteBuf {
tmpNioBuf = null;
}
final void initUnpooled(PoolChunk<T> chunk, int length) {
assert chunk != null;
this.chunk = chunk;
handle = 0;
memory = chunk.memory;
offset = 0;
this.length = maxLength = length;
setIndex(0, 0);
tmpNioBuf = null;
}
@Override
public final int capacity() {
return length;
@ -61,6 +73,11 @@ abstract class PooledByteBuf<T> extends AbstractByteBuf {
checkUnfreed();
// If the request capacity does not require reallocation, just update the length of the memory.
if (chunk.unpooled) {
if (newCapacity == length) {
return this;
}
} else {
if (newCapacity > length) {
if (newCapacity <= maxLength) {
length = newCapacity;
@ -83,6 +100,7 @@ abstract class PooledByteBuf<T> extends AbstractByteBuf {
} else {
return this;
}
}
// Reallocation required.
if (suspendedDeallocations == null) {
@ -144,7 +162,7 @@ abstract class PooledByteBuf<T> extends AbstractByteBuf {
}
for (Allocation<T> a: suspendedDeallocations) {
chunk.arena.free(a.chunk, a.handle);
a.chunk.arena.free(a.chunk, a.handle);
}
return this;
}

View File

@ -59,7 +59,10 @@ public class PooledByteBufAllocator extends AbstractByteBufAllocator {
public PooledByteBufAllocator(
boolean directByDefault, int nHeapArena, int nDirectArena, int pageSize, int maxOrder) {
super(validateAndCalculateChunkSize(pageSize, maxOrder), directByDefault);
super(directByDefault);
final int chunkSize = validateAndCalculateChunkSize(pageSize, maxOrder);
if (nHeapArena <= 0) {
throw new IllegalArgumentException("nHeapArena: " + nHeapArena + " (expected: 1+)");
}
@ -68,7 +71,6 @@ public class PooledByteBufAllocator extends AbstractByteBufAllocator {
}
int pageShifts = validateAndCalculatePageShifts(pageSize);
int chunkSize = bufferMaxCapacity();
heapArenas = newArenaArray(nHeapArena);
for (int i = 0; i < heapArenas.length; i ++) {
@ -147,11 +149,17 @@ public class PooledByteBufAllocator extends AbstractByteBufAllocator {
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(heapArenas.length);
buf.append(" arena(s):");
buf.append(" heap arena(s):");
buf.append(StringUtil.NEWLINE);
for (PoolArena<byte[]> a: heapArenas) {
buf.append(a);
}
buf.append(directArenas.length);
buf.append(" direct arena(s):");
buf.append(StringUtil.NEWLINE);
for (PoolArena<ByteBuffer> a: directArenas) {
buf.append(a);
}
return buf.toString();
}
}

View File

@ -26,7 +26,7 @@ public final class UnpooledByteBufAllocator extends AbstractByteBufAllocator {
public static final UnpooledByteBufAllocator DIRECT_BY_DEFAULT = new UnpooledByteBufAllocator(true);
private UnpooledByteBufAllocator(boolean directByDefault) {
super(Integer.MAX_VALUE, directByDefault);
super(directByDefault);
}
@Override