io.netty.buffer.PooledByteBuf Maven / Gradle / Ivy
/*
* 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:
*
* http://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.netty.buffer;
import io.netty.util.ResourceLeak;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayDeque;
import java.util.Queue;
abstract class PooledByteBuf extends AbstractReferenceCountedByteBuf {
private final ResourceLeak leak = leakDetector.open(this);
protected PoolChunk chunk;
protected long handle;
protected T memory;
protected int offset;
protected int length;
private int maxLength;
private ByteBuffer tmpNioBuf;
private Queue> suspendedDeallocations;
protected PooledByteBuf(int maxCapacity) {
super(maxCapacity);
}
void init(PoolChunk chunk, long handle, int offset, int length, int maxLength) {
assert handle >= 0;
assert chunk != null;
this.chunk = chunk;
this.handle = handle;
memory = chunk.memory;
this.offset = offset;
this.length = length;
this.maxLength = maxLength;
setIndex(0, 0);
tmpNioBuf = null;
}
void initUnpooled(PoolChunk 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;
}
@Override
public final ByteBuf capacity(int newCapacity) {
ensureAccessible();
// 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;
return this;
}
} else if (newCapacity < length) {
if (newCapacity > maxLength >>> 1) {
if (maxLength <= 512) {
if (newCapacity > maxLength - 16) {
length = newCapacity;
setIndex(Math.min(readerIndex(), newCapacity), Math.min(writerIndex(), newCapacity));
return this;
}
} else { // > 512 (i.e. >= 1024)
length = newCapacity;
setIndex(Math.min(readerIndex(), newCapacity), Math.min(writerIndex(), newCapacity));
return this;
}
}
} else {
return this;
}
}
// Reallocation required.
if (suspendedDeallocations == null) {
chunk.arena.reallocate(this, newCapacity, true);
} else {
Allocation old = new Allocation(chunk, handle);
chunk.arena.reallocate(this, newCapacity, false);
suspendedDeallocations.add(old);
}
return this;
}
@Override
public final ByteBufAllocator alloc() {
return chunk.arena.parent;
}
@Override
public final ByteOrder order() {
return ByteOrder.BIG_ENDIAN;
}
@Override
public final ByteBuf unwrap() {
return null;
}
protected final ByteBuffer internalNioBuffer() {
ByteBuffer tmpNioBuf = this.tmpNioBuf;
if (tmpNioBuf == null) {
this.tmpNioBuf = tmpNioBuf = newInternalNioBuffer(memory);
}
return tmpNioBuf;
}
protected abstract ByteBuffer newInternalNioBuffer(T memory);
@Override
public final ByteBuf suspendIntermediaryDeallocations() {
ensureAccessible();
if (suspendedDeallocations == null) {
suspendedDeallocations = new ArrayDeque>(2);
}
return this;
}
@Override
public final ByteBuf resumeIntermediaryDeallocations() {
if (suspendedDeallocations == null) {
return this;
}
Queue> suspendedDeallocations = this.suspendedDeallocations;
this.suspendedDeallocations = null;
if (suspendedDeallocations.isEmpty()) {
return this;
}
for (Allocation a: suspendedDeallocations) {
a.chunk.arena.free(a.chunk, a.handle);
}
return this;
}
@Override
protected final void deallocate() {
if (handle >= 0) {
resumeIntermediaryDeallocations();
final long handle = this.handle;
this.handle = -1;
memory = null;
chunk.arena.free(chunk, handle);
leak.close();
}
}
protected final int idx(int index) {
return offset + index;
}
private static final class Allocation {
final PoolChunk chunk;
final long handle;
Allocation(PoolChunk chunk, long handle) {
this.chunk = chunk;
this.handle = handle;
}
}
}