netty5/buffer/src/main/java/io/net5/buffer/AbstractPooledDerivedByteBu...

323 lines
9.7 KiB
Java

/*
* Copyright 2016 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 io.net5.util.internal.ObjectPool.Handle;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Abstract base class for derived {@link ByteBuf} implementations.
*/
abstract class AbstractPooledDerivedByteBuf extends AbstractReferenceCountedByteBuf {
private final Handle<AbstractPooledDerivedByteBuf> recyclerHandle;
private AbstractByteBuf rootParent;
/**
* Deallocations of a pooled derived buffer should always propagate through the entire chain of derived buffers.
* This is because each pooled derived buffer maintains its own reference count and we should respect each one.
* If deallocations cause a release of the "root parent" then then we may prematurely release the underlying
* content before all the derived buffers have been released.
*/
private ByteBuf parent;
@SuppressWarnings("unchecked")
AbstractPooledDerivedByteBuf(Handle<? extends AbstractPooledDerivedByteBuf> recyclerHandle) {
super(0);
this.recyclerHandle = (Handle<AbstractPooledDerivedByteBuf>) recyclerHandle;
}
// Called from within SimpleLeakAwareByteBuf and AdvancedLeakAwareByteBuf.
final void parent(ByteBuf newParent) {
assert newParent instanceof SimpleLeakAwareByteBuf;
parent = newParent;
}
@Override
public final AbstractByteBuf unwrap() {
return rootParent;
}
final <U extends AbstractPooledDerivedByteBuf> U init(
AbstractByteBuf unwrapped, ByteBuf wrapped, int readerIndex, int writerIndex, int maxCapacity) {
wrapped.retain(); // Retain up front to ensure the parent is accessible before doing more work.
parent = wrapped;
rootParent = unwrapped;
try {
maxCapacity(maxCapacity);
setIndex0(readerIndex, writerIndex); // It is assumed the bounds checking is done by the caller.
resetRefCnt();
@SuppressWarnings("unchecked")
final U castThis = (U) this;
wrapped = null;
return castThis;
} finally {
if (wrapped != null) {
parent = rootParent = null;
wrapped.release();
}
}
}
@Override
protected final void deallocate() {
// We need to first store a reference to the parent before recycle this instance. This is needed as
// otherwise it is possible that the same AbstractPooledDerivedByteBuf is again obtained and init(...) is
// called before we actually have a chance to call release(). This leads to call release() on the wrong parent.
ByteBuf parent = this.parent;
recyclerHandle.recycle(this);
parent.release();
}
@Override
public final ByteBufAllocator alloc() {
return unwrap().alloc();
}
@Override
@Deprecated
public final ByteOrder order() {
return unwrap().order();
}
@Override
public boolean isReadOnly() {
return unwrap().isReadOnly();
}
@Override
public final boolean isDirect() {
return unwrap().isDirect();
}
@Override
public boolean hasArray() {
return unwrap().hasArray();
}
@Override
public byte[] array() {
return unwrap().array();
}
@Override
public boolean hasMemoryAddress() {
return unwrap().hasMemoryAddress();
}
@Override
public boolean isContiguous() {
return unwrap().isContiguous();
}
@Override
public final int nioBufferCount() {
return unwrap().nioBufferCount();
}
@Override
public final ByteBuffer internalNioBuffer(int index, int length) {
return nioBuffer(index, length);
}
@Override
public final ByteBuf retainedSlice() {
final int index = readerIndex();
return retainedSlice(index, writerIndex() - index);
}
@Override
public ByteBuf slice(int index, int length) {
ensureAccessible();
// All reference count methods should be inherited from this object (this is the "parent").
return new PooledNonRetainedSlicedByteBuf(this, unwrap(), index, length);
}
final ByteBuf duplicate0() {
ensureAccessible();
// All reference count methods should be inherited from this object (this is the "parent").
return new PooledNonRetainedDuplicateByteBuf(this, unwrap());
}
private static final class PooledNonRetainedDuplicateByteBuf extends UnpooledDuplicatedByteBuf {
private final ByteBuf referenceCountDelegate;
PooledNonRetainedDuplicateByteBuf(ByteBuf referenceCountDelegate, AbstractByteBuf buffer) {
super(buffer);
this.referenceCountDelegate = referenceCountDelegate;
}
@Override
boolean isAccessible0() {
return referenceCountDelegate.isAccessible();
}
@Override
int refCnt0() {
return referenceCountDelegate.refCnt();
}
@Override
ByteBuf retain0() {
referenceCountDelegate.retain();
return this;
}
@Override
ByteBuf retain0(int increment) {
referenceCountDelegate.retain(increment);
return this;
}
@Override
ByteBuf touch0() {
referenceCountDelegate.touch();
return this;
}
@Override
ByteBuf touch0(Object hint) {
referenceCountDelegate.touch(hint);
return this;
}
@Override
boolean release0() {
return referenceCountDelegate.release();
}
@Override
boolean release0(int decrement) {
return referenceCountDelegate.release(decrement);
}
@Override
public ByteBuf duplicate() {
ensureAccessible();
return new PooledNonRetainedDuplicateByteBuf(referenceCountDelegate, this);
}
@Override
public ByteBuf retainedDuplicate() {
return PooledDuplicatedByteBuf.newInstance(unwrap(), this, readerIndex(), writerIndex());
}
@Override
public ByteBuf slice(int index, int length) {
checkIndex(index, length);
return new PooledNonRetainedSlicedByteBuf(referenceCountDelegate, unwrap(), index, length);
}
@Override
public ByteBuf retainedSlice() {
// Capacity is not allowed to change for a sliced ByteBuf, so length == capacity()
return retainedSlice(readerIndex(), capacity());
}
@Override
public ByteBuf retainedSlice(int index, int length) {
return PooledSlicedByteBuf.newInstance(unwrap(), this, index, length);
}
}
private static final class PooledNonRetainedSlicedByteBuf extends UnpooledSlicedByteBuf {
private final ByteBuf referenceCountDelegate;
PooledNonRetainedSlicedByteBuf(ByteBuf referenceCountDelegate,
AbstractByteBuf buffer, int index, int length) {
super(buffer, index, length);
this.referenceCountDelegate = referenceCountDelegate;
}
@Override
boolean isAccessible0() {
return referenceCountDelegate.isAccessible();
}
@Override
int refCnt0() {
return referenceCountDelegate.refCnt();
}
@Override
ByteBuf retain0() {
referenceCountDelegate.retain();
return this;
}
@Override
ByteBuf retain0(int increment) {
referenceCountDelegate.retain(increment);
return this;
}
@Override
ByteBuf touch0() {
referenceCountDelegate.touch();
return this;
}
@Override
ByteBuf touch0(Object hint) {
referenceCountDelegate.touch(hint);
return this;
}
@Override
boolean release0() {
return referenceCountDelegate.release();
}
@Override
boolean release0(int decrement) {
return referenceCountDelegate.release(decrement);
}
@Override
public ByteBuf duplicate() {
ensureAccessible();
return new PooledNonRetainedDuplicateByteBuf(referenceCountDelegate, unwrap())
.setIndex(idx(readerIndex()), idx(writerIndex()));
}
@Override
public ByteBuf retainedDuplicate() {
return PooledDuplicatedByteBuf.newInstance(unwrap(), this, idx(readerIndex()), idx(writerIndex()));
}
@Override
public ByteBuf slice(int index, int length) {
checkIndex(index, length);
return new PooledNonRetainedSlicedByteBuf(referenceCountDelegate, unwrap(), idx(index), length);
}
@Override
public ByteBuf retainedSlice() {
// Capacity is not allowed to change for a sliced ByteBuf, so length == capacity()
return retainedSlice(0, capacity());
}
@Override
public ByteBuf retainedSlice(int index, int length) {
return PooledSlicedByteBuf.newInstance(unwrap(), this, idx(index), length);
}
}
}