281 lines
9.0 KiB
Java
281 lines
9.0 KiB
Java
/*
|
|
* Copyright 2012 The Netty Project
|
|
*
|
|
* The Netty Project licenses this file to you under the Apache License,
|
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at:
|
|
*
|
|
* https://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
|
|
package io.net5.buffer;
|
|
|
|
import static io.net5.util.internal.ObjectUtil.checkPositiveOrZero;
|
|
|
|
import io.net5.util.ResourceLeakDetector;
|
|
import io.net5.util.ResourceLeakTracker;
|
|
import io.net5.util.internal.MathUtil;
|
|
import io.net5.util.internal.PlatformDependent;
|
|
import io.net5.util.internal.StringUtil;
|
|
|
|
/**
|
|
* Skeletal {@link ByteBufAllocator} implementation to extend.
|
|
*/
|
|
public abstract class AbstractByteBufAllocator implements ByteBufAllocator {
|
|
static final int DEFAULT_INITIAL_CAPACITY = 256;
|
|
static final int DEFAULT_MAX_CAPACITY = Integer.MAX_VALUE;
|
|
static final int DEFAULT_MAX_COMPONENTS = 16;
|
|
static final int CALCULATE_THRESHOLD = 1048576 * 4; // 4 MiB page
|
|
|
|
static {
|
|
ResourceLeakDetector.addExclusions(AbstractByteBufAllocator.class, "toLeakAwareBuffer");
|
|
}
|
|
|
|
protected static ByteBuf toLeakAwareBuffer(ByteBuf buf) {
|
|
ResourceLeakTracker<ByteBuf> leak;
|
|
switch (ResourceLeakDetector.getLevel()) {
|
|
case SIMPLE:
|
|
leak = AbstractByteBuf.leakDetector.track(buf);
|
|
if (leak != null) {
|
|
buf = new SimpleLeakAwareByteBuf(buf, leak);
|
|
}
|
|
break;
|
|
case ADVANCED:
|
|
case PARANOID:
|
|
leak = AbstractByteBuf.leakDetector.track(buf);
|
|
if (leak != null) {
|
|
buf = new AdvancedLeakAwareByteBuf(buf, leak);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
protected static CompositeByteBuf toLeakAwareBuffer(CompositeByteBuf buf) {
|
|
ResourceLeakTracker<ByteBuf> leak;
|
|
switch (ResourceLeakDetector.getLevel()) {
|
|
case SIMPLE:
|
|
leak = AbstractByteBuf.leakDetector.track(buf);
|
|
if (leak != null) {
|
|
buf = new SimpleLeakAwareCompositeByteBuf(buf, leak);
|
|
}
|
|
break;
|
|
case ADVANCED:
|
|
case PARANOID:
|
|
leak = AbstractByteBuf.leakDetector.track(buf);
|
|
if (leak != null) {
|
|
buf = new AdvancedLeakAwareCompositeByteBuf(buf, leak);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
private final boolean directByDefault;
|
|
private final ByteBuf emptyBuf;
|
|
|
|
/**
|
|
* Instance use heap buffers by default
|
|
*/
|
|
protected AbstractByteBufAllocator() {
|
|
this(false);
|
|
}
|
|
|
|
/**
|
|
* Create new instance
|
|
*
|
|
* @param preferDirect {@code true} if {@link #buffer(int)} should try to allocate a direct buffer rather than
|
|
* a heap buffer
|
|
*/
|
|
protected AbstractByteBufAllocator(boolean preferDirect) {
|
|
directByDefault = preferDirect && PlatformDependent.hasUnsafe();
|
|
emptyBuf = new EmptyByteBuf(this);
|
|
}
|
|
|
|
@Override
|
|
public ByteBuf buffer() {
|
|
if (directByDefault) {
|
|
return directBuffer();
|
|
}
|
|
return heapBuffer();
|
|
}
|
|
|
|
@Override
|
|
public ByteBuf buffer(int initialCapacity) {
|
|
if (directByDefault) {
|
|
return directBuffer(initialCapacity);
|
|
}
|
|
return heapBuffer(initialCapacity);
|
|
}
|
|
|
|
@Override
|
|
public ByteBuf buffer(int initialCapacity, int maxCapacity) {
|
|
if (directByDefault) {
|
|
return directBuffer(initialCapacity, maxCapacity);
|
|
}
|
|
return heapBuffer(initialCapacity, maxCapacity);
|
|
}
|
|
|
|
@Override
|
|
public ByteBuf ioBuffer() {
|
|
if (PlatformDependent.hasUnsafe() || isDirectBufferPooled()) {
|
|
return directBuffer(DEFAULT_INITIAL_CAPACITY);
|
|
}
|
|
return heapBuffer(DEFAULT_INITIAL_CAPACITY);
|
|
}
|
|
|
|
@Override
|
|
public ByteBuf ioBuffer(int initialCapacity) {
|
|
if (PlatformDependent.hasUnsafe() || isDirectBufferPooled()) {
|
|
return directBuffer(initialCapacity);
|
|
}
|
|
return heapBuffer(initialCapacity);
|
|
}
|
|
|
|
@Override
|
|
public ByteBuf ioBuffer(int initialCapacity, int maxCapacity) {
|
|
if (PlatformDependent.hasUnsafe() || isDirectBufferPooled()) {
|
|
return directBuffer(initialCapacity, maxCapacity);
|
|
}
|
|
return heapBuffer(initialCapacity, maxCapacity);
|
|
}
|
|
|
|
@Override
|
|
public ByteBuf heapBuffer() {
|
|
return heapBuffer(DEFAULT_INITIAL_CAPACITY, DEFAULT_MAX_CAPACITY);
|
|
}
|
|
|
|
@Override
|
|
public ByteBuf heapBuffer(int initialCapacity) {
|
|
return heapBuffer(initialCapacity, DEFAULT_MAX_CAPACITY);
|
|
}
|
|
|
|
@Override
|
|
public ByteBuf heapBuffer(int initialCapacity, int maxCapacity) {
|
|
if (initialCapacity == 0 && maxCapacity == 0) {
|
|
return emptyBuf;
|
|
}
|
|
validate(initialCapacity, maxCapacity);
|
|
return newHeapBuffer(initialCapacity, maxCapacity);
|
|
}
|
|
|
|
@Override
|
|
public ByteBuf directBuffer() {
|
|
return directBuffer(DEFAULT_INITIAL_CAPACITY, DEFAULT_MAX_CAPACITY);
|
|
}
|
|
|
|
@Override
|
|
public ByteBuf directBuffer(int initialCapacity) {
|
|
return directBuffer(initialCapacity, DEFAULT_MAX_CAPACITY);
|
|
}
|
|
|
|
@Override
|
|
public ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
|
|
if (initialCapacity == 0 && maxCapacity == 0) {
|
|
return emptyBuf;
|
|
}
|
|
validate(initialCapacity, maxCapacity);
|
|
return newDirectBuffer(initialCapacity, maxCapacity);
|
|
}
|
|
|
|
@Override
|
|
public CompositeByteBuf compositeBuffer() {
|
|
if (directByDefault) {
|
|
return compositeDirectBuffer();
|
|
}
|
|
return compositeHeapBuffer();
|
|
}
|
|
|
|
@Override
|
|
public CompositeByteBuf compositeBuffer(int maxNumComponents) {
|
|
if (directByDefault) {
|
|
return compositeDirectBuffer(maxNumComponents);
|
|
}
|
|
return compositeHeapBuffer(maxNumComponents);
|
|
}
|
|
|
|
@Override
|
|
public CompositeByteBuf compositeHeapBuffer() {
|
|
return compositeHeapBuffer(DEFAULT_MAX_COMPONENTS);
|
|
}
|
|
|
|
@Override
|
|
public CompositeByteBuf compositeHeapBuffer(int maxNumComponents) {
|
|
return toLeakAwareBuffer(new CompositeByteBuf(this, false, maxNumComponents));
|
|
}
|
|
|
|
@Override
|
|
public CompositeByteBuf compositeDirectBuffer() {
|
|
return compositeDirectBuffer(DEFAULT_MAX_COMPONENTS);
|
|
}
|
|
|
|
@Override
|
|
public CompositeByteBuf compositeDirectBuffer(int maxNumComponents) {
|
|
return toLeakAwareBuffer(new CompositeByteBuf(this, true, maxNumComponents));
|
|
}
|
|
|
|
private static void validate(int initialCapacity, int maxCapacity) {
|
|
checkPositiveOrZero(initialCapacity, "initialCapacity");
|
|
if (initialCapacity > maxCapacity) {
|
|
throw new IllegalArgumentException(String.format(
|
|
"initialCapacity: %d (expected: not greater than maxCapacity(%d)",
|
|
initialCapacity, maxCapacity));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a heap {@link ByteBuf} with the given initialCapacity and maxCapacity.
|
|
*/
|
|
protected abstract ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity);
|
|
|
|
/**
|
|
* Create a direct {@link ByteBuf} with the given initialCapacity and maxCapacity.
|
|
*/
|
|
protected abstract ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity);
|
|
|
|
@Override
|
|
public String toString() {
|
|
return StringUtil.simpleClassName(this) + "(directByDefault: " + directByDefault + ')';
|
|
}
|
|
|
|
@Override
|
|
public int calculateNewCapacity(int minNewCapacity, int maxCapacity) {
|
|
checkPositiveOrZero(minNewCapacity, "minNewCapacity");
|
|
if (minNewCapacity > maxCapacity) {
|
|
throw new IllegalArgumentException(String.format(
|
|
"minNewCapacity: %d (expected: not greater than maxCapacity(%d)",
|
|
minNewCapacity, maxCapacity));
|
|
}
|
|
final int threshold = CALCULATE_THRESHOLD; // 4 MiB page
|
|
|
|
if (minNewCapacity == threshold) {
|
|
return threshold;
|
|
}
|
|
|
|
// If over threshold, do not double but just increase by threshold.
|
|
if (minNewCapacity > threshold) {
|
|
int newCapacity = minNewCapacity / threshold * threshold;
|
|
if (newCapacity > maxCapacity - threshold) {
|
|
newCapacity = maxCapacity;
|
|
} else {
|
|
newCapacity += threshold;
|
|
}
|
|
return newCapacity;
|
|
}
|
|
|
|
// 64 <= newCapacity is a power of 2 <= threshold
|
|
final int newCapacity = MathUtil.findNextPositivePowerOfTwo(Math.max(minNewCapacity, 64));
|
|
return Math.min(newCapacity, maxCapacity);
|
|
}
|
|
}
|