Implement reference counting

- Related: #1029
- Replace Freeable with ReferenceCounted
- Add AbstractReferenceCounted
- Add AbstractReferenceCountedByteBuf
- Add AbstractDerivedByteBuf
- Add EmptyByteBuf
This commit is contained in:
Trustin Lee 2013-02-10 13:10:09 +09:00
parent 8f895a7e9a
commit b9996908b1
71 changed files with 1710 additions and 610 deletions

View File

@ -182,7 +182,7 @@ public abstract class AbstractByteBuf implements ByteBuf {
@Override @Override
public ByteBuf discardReadBytes() { public ByteBuf discardReadBytes() {
checkUnfreed(); ensureAccessible();
if (readerIndex == 0) { if (readerIndex == 0) {
return this; return this;
} }
@ -201,7 +201,7 @@ public abstract class AbstractByteBuf implements ByteBuf {
@Override @Override
public ByteBuf discardSomeReadBytes() { public ByteBuf discardSomeReadBytes() {
checkUnfreed(); ensureAccessible();
if (readerIndex == 0) { if (readerIndex == 0) {
return this; return this;
} }
@ -972,7 +972,7 @@ public abstract class AbstractByteBuf implements ByteBuf {
@Override @Override
public String toString() { public String toString() {
if (isFreed()) { if (refCnt() == 0) {
return getClass().getSimpleName() + "(freed)"; return getClass().getSimpleName() + "(freed)";
} }
@ -999,7 +999,7 @@ public abstract class AbstractByteBuf implements ByteBuf {
} }
protected final void checkIndex(int index) { protected final void checkIndex(int index) {
checkUnfreed(); ensureAccessible();
if (index < 0 || index >= capacity()) { if (index < 0 || index >= capacity()) {
throw new IndexOutOfBoundsException(String.format( throw new IndexOutOfBoundsException(String.format(
"index: %d (expected: range(0, %d))", index, capacity())); "index: %d (expected: range(0, %d))", index, capacity()));
@ -1007,7 +1007,7 @@ public abstract class AbstractByteBuf implements ByteBuf {
} }
protected final void checkIndex(int index, int fieldLength) { protected final void checkIndex(int index, int fieldLength) {
checkUnfreed(); ensureAccessible();
if (fieldLength < 0) { if (fieldLength < 0) {
throw new IllegalArgumentException("length: " + fieldLength + " (expected: >= 0)"); throw new IllegalArgumentException("length: " + fieldLength + " (expected: >= 0)");
} }
@ -1023,7 +1023,7 @@ public abstract class AbstractByteBuf implements ByteBuf {
* than the specified value. * than the specified value.
*/ */
protected final void checkReadableBytes(int minimumReadableBytes) { protected final void checkReadableBytes(int minimumReadableBytes) {
checkUnfreed(); ensureAccessible();
if (readerIndex > writerIndex - minimumReadableBytes) { if (readerIndex > writerIndex - minimumReadableBytes) {
throw new IndexOutOfBoundsException(String.format( throw new IndexOutOfBoundsException(String.format(
"readerIndex(%d) + length(%d) exceeds writerIndex(%d): %s", "readerIndex(%d) + length(%d) exceeds writerIndex(%d): %s",
@ -1031,8 +1031,8 @@ public abstract class AbstractByteBuf implements ByteBuf {
} }
} }
protected final void checkUnfreed() { protected final void ensureAccessible() {
if (isFreed()) { if (refCnt() <= 0) {
throw new IllegalBufferAccessException(); throw new IllegalBufferAccessException();
} }
} }

View File

@ -0,0 +1,55 @@
/*
* Copyright 2013 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;
public abstract class AbstractDerivedByteBuf extends AbstractByteBuf {
protected AbstractDerivedByteBuf(int maxCapacity) {
super(maxCapacity);
}
@Override
public final int refCnt() {
return unwrap().refCnt();
}
@Override
public final void retain() { }
@Override
public final void retain(int increment) { }
@Override
public final boolean release() {
return false;
}
@Override
public final boolean release(int decrement) {
return false;
}
@Override
public final ByteBuf suspendIntermediaryDeallocations() {
throw new UnsupportedOperationException("derived");
}
@Override
public final ByteBuf resumeIntermediaryDeallocations() {
throw new UnsupportedOperationException("derived");
}
}

View File

@ -22,7 +22,7 @@ import java.util.Collection;
public abstract class AbstractMessageBuf<T> extends AbstractQueue<T> implements MessageBuf<T> { public abstract class AbstractMessageBuf<T> extends AbstractQueue<T> implements MessageBuf<T> {
private final int maxCapacity; private final int maxCapacity;
private boolean freed; private int refCnt = 1;
protected AbstractMessageBuf(int maxCapacity) { protected AbstractMessageBuf(int maxCapacity) {
if (maxCapacity < 0) { if (maxCapacity < 0) {
@ -37,24 +37,79 @@ public abstract class AbstractMessageBuf<T> extends AbstractQueue<T> implements
} }
@Override @Override
public final boolean isFreed() { public final int refCnt() {
return freed; return refCnt;
} }
@Override @Override
public final void free() { public final void retain() {
if (freed) { int refCnt = this.refCnt;
return; if (refCnt <= 0) {
throw new IllegalBufferAccessException();
} }
try { if (refCnt == Integer.MAX_VALUE) {
doFree(); throw new IllegalBufferAccessException("refCnt overflow");
} finally {
freed = true;
} }
this.refCnt = refCnt + 1;
} }
protected abstract void doFree(); @Override
public final void retain(int increment) {
if (increment <= 0) {
throw new IllegalArgumentException("increment: " + increment + " (expected: > 0)");
}
int refCnt = this.refCnt;
if (refCnt <= 0) {
throw new IllegalBufferAccessException();
}
if (refCnt > Integer.MAX_VALUE - increment) {
throw new IllegalBufferAccessException("refCnt overflow");
}
this.refCnt = refCnt + 1;
}
@Override
public final boolean release() {
int refCnt = this.refCnt;
if (refCnt <= 0) {
throw new IllegalBufferAccessException();
}
this.refCnt = refCnt --;
if (refCnt == 0) {
deallocate();
return true;
}
return false;
}
@Override
public final boolean release(int decrement) {
if (decrement <= 0) {
throw new IllegalArgumentException("decrement: " + decrement + " (expected: > 0)");
}
int refCnt = this.refCnt;
if (refCnt < decrement) {
throw new IllegalBufferAccessException();
}
this.refCnt = refCnt -= decrement;
if (refCnt == 0) {
deallocate();
return true;
}
return false;
}
protected abstract void deallocate();
@Override @Override
public final int maxCapacity() { public final int maxCapacity() {
@ -87,8 +142,8 @@ public abstract class AbstractMessageBuf<T> extends AbstractQueue<T> implements
return size() <= maxCapacity - size; return size() <= maxCapacity - size;
} }
protected final void checkUnfreed() { protected final void ensureAccessible() {
if (isFreed()) { if (refCnt <= 0) {
throw new IllegalBufferAccessException(); throw new IllegalBufferAccessException();
} }
} }
@ -133,7 +188,7 @@ public abstract class AbstractMessageBuf<T> extends AbstractQueue<T> implements
@Override @Override
public int drainTo(Collection<? super T> c) { public int drainTo(Collection<? super T> c) {
checkUnfreed(); ensureAccessible();
int cnt = 0; int cnt = 0;
for (;;) { for (;;) {
T o = poll(); T o = poll();
@ -148,7 +203,7 @@ public abstract class AbstractMessageBuf<T> extends AbstractQueue<T> implements
@Override @Override
public int drainTo(Collection<? super T> c, int maxElements) { public int drainTo(Collection<? super T> c, int maxElements) {
checkUnfreed(); ensureAccessible();
int cnt = 0; int cnt = 0;
while (cnt < maxElements) { while (cnt < maxElements) {
T o = poll(); T o = poll();
@ -163,7 +218,7 @@ public abstract class AbstractMessageBuf<T> extends AbstractQueue<T> implements
@Override @Override
public String toString() { public String toString() {
if (isFreed()) { if (refCnt <= 0) {
return getClass().getSimpleName() + "(freed)"; return getClass().getSimpleName() + "(freed)";
} }

View File

@ -0,0 +1,104 @@
/*
* Copyright 2013 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 java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
public abstract class AbstractReferenceCounted implements ReferenceCounted {
private static final AtomicIntegerFieldUpdater<AbstractReferenceCounted> refCntUpdater =
AtomicIntegerFieldUpdater.newUpdater(AbstractReferenceCounted.class, "refCnt");
@SuppressWarnings("FieldMayBeFinal")
private volatile int refCnt = 1;
@Override
public int refCnt() {
return refCnt;
}
@Override
public final void retain() {
do {
int refCnt = this.refCnt;
if (refCnt <= 0) {
throw new IllegalBufferAccessException();
}
if (refCnt == Integer.MAX_VALUE) {
throw new IllegalBufferAccessException("refCnt overflow");
}
} while (!refCntUpdater.compareAndSet(this, refCnt, refCnt + 1));
}
@Override
public final void retain(int increment) {
if (increment <= 0) {
throw new IllegalArgumentException("increment: " + increment + " (expected: > 0)");
}
do {
int refCnt = this.refCnt;
if (refCnt <= 0) {
throw new IllegalBufferAccessException();
}
if (refCnt > Integer.MAX_VALUE - increment) {
throw new IllegalBufferAccessException("refCnt overflow");
}
} while (!refCntUpdater.compareAndSet(this, refCnt, refCnt + increment));
}
@Override
public final boolean release() {
for (;;) {
int refCnt = this.refCnt;
if (refCnt <= 0) {
throw new IllegalBufferAccessException();
}
if (refCntUpdater.compareAndSet(this, refCnt, refCnt - 1)) {
if (refCnt == 1) {
deallocate();
return true;
}
return false;
}
}
}
@Override
public final boolean release(int decrement) {
if (decrement <= 0) {
throw new IllegalArgumentException("decrement: " + decrement + " (expected: > 0)");
}
for (;;) {
int refCnt = this.refCnt;
if (refCnt < decrement) {
throw new IllegalBufferAccessException();
}
if (refCntUpdater.compareAndSet(this, refCnt, refCnt - decrement)) {
if (refCnt == decrement) {
deallocate();
return true;
}
return false;
}
}
}
protected abstract void deallocate();
}

View File

@ -0,0 +1,109 @@
/*
* Copyright 2013 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 java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
public abstract class AbstractReferenceCountedByteBuf extends AbstractByteBuf {
private static final AtomicIntegerFieldUpdater<AbstractReferenceCountedByteBuf> refCntUpdater =
AtomicIntegerFieldUpdater.newUpdater(AbstractReferenceCountedByteBuf.class, "refCnt");
@SuppressWarnings("FieldMayBeFinal")
private volatile int refCnt = 1;
protected AbstractReferenceCountedByteBuf(int maxCapacity) {
super(maxCapacity);
}
@Override
public int refCnt() {
return refCnt;
}
@Override
public final void retain() {
do {
int refCnt = this.refCnt;
if (refCnt <= 0) {
throw new IllegalBufferAccessException();
}
if (refCnt == Integer.MAX_VALUE) {
throw new IllegalBufferAccessException("refCnt overflow");
}
} while (!refCntUpdater.compareAndSet(this, refCnt, refCnt + 1));
}
@Override
public final void retain(int increment) {
if (increment <= 0) {
throw new IllegalArgumentException("increment: " + increment + " (expected: > 0)");
}
do {
int refCnt = this.refCnt;
if (refCnt <= 0) {
throw new IllegalBufferAccessException();
}
if (refCnt > Integer.MAX_VALUE - increment) {
throw new IllegalBufferAccessException("refCnt overflow");
}
} while (!refCntUpdater.compareAndSet(this, refCnt, refCnt + increment));
}
@Override
public final boolean release() {
for (;;) {
int refCnt = this.refCnt;
if (refCnt <= 0) {
throw new IllegalBufferAccessException();
}
if (refCntUpdater.compareAndSet(this, refCnt, refCnt - 1)) {
if (refCnt == 1) {
deallocate();
return true;
}
return false;
}
}
}
@Override
public final boolean release(int decrement) {
if (decrement <= 0) {
throw new IllegalArgumentException("decrement: " + decrement + " (expected: > 0)");
}
for (;;) {
int refCnt = this.refCnt;
if (refCnt < decrement) {
throw new IllegalBufferAccessException();
}
if (refCntUpdater.compareAndSet(this, refCnt, refCnt - decrement)) {
if (refCnt == decrement) {
deallocate();
return true;
}
return false;
}
}
}
protected abstract void deallocate();
}

View File

@ -18,7 +18,7 @@ package io.netty.buffer;
/** /**
* A buffer to operate on * A buffer to operate on
*/ */
public interface Buf extends Freeable { public interface Buf extends ReferenceCounted {
/** /**
* The BufType which will be handled by the Buf implementation * The BufType which will be handled by the Buf implementation
*/ */

View File

@ -43,20 +43,47 @@ public final class BufUtil {
} }
/** /**
* Try to call {@link Freeable#free()} if the specified message implements {@link Freeable}. If the specified * Try to call {@link ReferenceCounted#retain()} if the specified message implements {@link ReferenceCounted}.
* message doesn't implement {@link Freeable}, this method does nothing. * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing.
*/ */
public static void free(Object msg) { public static void retain(Object msg) {
if (msg instanceof Freeable) { if (msg instanceof ReferenceCounted) {
try { ((ReferenceCounted) msg).retain();
((Freeable) msg).free();
} catch (UnsupportedOperationException e) {
// This can happen for derived buffers
// TODO: Think about this
}
} }
} }
/**
* Try to call {@link ReferenceCounted#retain()} if the specified message implements {@link ReferenceCounted}.
* If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing.
*/
public static void retain(Object msg, int increment) {
if (msg instanceof ReferenceCounted) {
((ReferenceCounted) msg).retain(increment);
}
}
/**
* Try to call {@link ReferenceCounted#release()} if the specified message implements {@link ReferenceCounted}.
* If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing.
*/
public static boolean release(Object msg) {
if (msg instanceof ReferenceCounted) {
return ((ReferenceCounted) msg).release();
}
return false;
}
/**
* Try to call {@link ReferenceCounted#release()} if the specified message implements {@link ReferenceCounted}.
* If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing.
*/
public static boolean release(Object msg, int decrement) {
if (msg instanceof ReferenceCounted) {
return ((ReferenceCounted) msg).release(decrement);
}
return false;
}
/** /**
* Returns a <a href="http://en.wikipedia.org/wiki/Hex_dump">hex dump</a> * Returns a <a href="http://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
* of the specified buffer's readable bytes. * of the specified buffer's readable bytes.

View File

@ -1914,19 +1914,4 @@ public interface ByteBuf extends Buf, Comparable<ByteBuf> {
*/ */
@Override @Override
String toString(); String toString();
/**
* Deallocates the internal memory block of this buffer or returns it to the allocator or pool it came from.
* The result of accessing a released buffer is unspecified and can even cause JVM crash.
*
* @throws UnsupportedOperationException if this buffer is derived
*/
@Override
void free();
/**
* Returns {@code true} if and only if this buffer has been deallocated by {@link #free()}.
*/
@Override
boolean isFreed();
} }

View File

@ -16,15 +16,9 @@
package io.netty.buffer; package io.netty.buffer;
/** /**
* A packet which is send or receive. The contract for a {@link ByteBufHolder} is the * A packet which is send or receive.
* following:
*
* When send a {@link ByteBufHolder} the {@link ByteBufHolder} will be freed by calling {@link #free()}
* in the actual transport implementation. When receive a {@link ByteBufHolder} the {@link #free()}
* must be called once is is processed.
*
*/ */
public interface ByteBufHolder extends Freeable { public interface ByteBufHolder extends ReferenceCounted {
/** /**
* Return the data which is held by this {@link ByteBufHolder}. * Return the data which is held by this {@link ByteBufHolder}.
@ -33,20 +27,7 @@ public interface ByteBufHolder extends Freeable {
ByteBuf data(); ByteBuf data();
/** /**
* Create a copy of this {@link ByteBufHolder} which can be used even after {@link #free()} * Create a deep copy of this {@link ByteBufHolder}.
* is called.
*/ */
ByteBufHolder copy(); ByteBufHolder copy();
/**
* Free of the resources that are hold by this instance. This includes the {@link ByteBuf}.
*/
@Override
void free();
/**
* Returns {@code true} if and only if this instances was freed.
*/
@Override
boolean isFreed();
} }

View File

@ -20,7 +20,9 @@ package io.netty.buffer;
* *
*/ */
public class DefaultByteBufHolder implements ByteBufHolder { public class DefaultByteBufHolder implements ByteBufHolder {
private final ByteBuf data; private final ByteBuf data;
public DefaultByteBufHolder(ByteBuf data) { public DefaultByteBufHolder(ByteBuf data) {
if (data == null) { if (data == null) {
throw new NullPointerException("data"); throw new NullPointerException("data");
@ -34,25 +36,40 @@ public class DefaultByteBufHolder implements ByteBufHolder {
@Override @Override
public ByteBuf data() { public ByteBuf data() {
if (data.isFreed()) { if (data.refCnt() <= 0) {
throw new IllegalBufferAccessException(); throw new IllegalBufferAccessException();
} }
return data; return data;
} }
@Override
public void free() {
data.free();
}
@Override
public boolean isFreed() {
return data.isFreed();
}
@Override @Override
public ByteBufHolder copy() { public ByteBufHolder copy() {
return new DefaultByteBufHolder(data().copy()); return new DefaultByteBufHolder(data.copy());
}
@Override
public int refCnt() {
return data.refCnt();
}
@Override
public void retain() {
data.retain();
}
@Override
public void retain(int increment) {
data.retain(increment);
}
@Override
public boolean release() {
return data.release();
}
@Override
public boolean release(int decrement) {
return data.release(decrement);
} }
@Override @Override

View File

@ -40,7 +40,7 @@ import java.util.Queue;
* is recommended to use {@link Unpooled#wrappedBuffer(ByteBuf...)} * is recommended to use {@link Unpooled#wrappedBuffer(ByteBuf...)}
* instead of calling the constructor explicitly. * instead of calling the constructor explicitly.
*/ */
public class DefaultCompositeByteBuf extends AbstractByteBuf implements CompositeByteBuf { public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf implements CompositeByteBuf {
private static final ByteBuffer[] EMPTY_NIOBUFFERS = new ByteBuffer[0]; private static final ByteBuffer[] EMPTY_NIOBUFFERS = new ByteBuffer[0];
@ -1293,7 +1293,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
} }
if (suspendedDeallocations == null) { if (suspendedDeallocations == null) {
buf.free(); // We should not get a NPE here. If so, it must be a bug. buf.release(); // We should not get a NPE here. If so, it must be a bug.
} else { } else {
suspendedDeallocations.add(buf); suspendedDeallocations.add(buf);
} }
@ -1531,12 +1531,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
} }
@Override @Override
public boolean isFreed() { protected void deallocate() {
return freed;
}
@Override
public void free() {
if (freed) { if (freed) {
return; return;
} }
@ -1552,6 +1547,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
@Override @Override
public CompositeByteBuf suspendIntermediaryDeallocations() { public CompositeByteBuf suspendIntermediaryDeallocations() {
ensureAccessible();
if (suspendedDeallocations == null) { if (suspendedDeallocations == null) {
suspendedDeallocations = new ArrayDeque<ByteBuf>(2); suspendedDeallocations = new ArrayDeque<ByteBuf>(2);
} }
@ -1568,7 +1564,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
this.suspendedDeallocations = null; this.suspendedDeallocations = null;
for (ByteBuf buf: suspendedDeallocations) { for (ByteBuf buf: suspendedDeallocations) {
buf.free(); buf.release();
} }
return this; return this;
} }

View File

@ -76,7 +76,7 @@ final class DefaultMessageBuf<T> extends AbstractMessageBuf<T> {
} }
@Override @Override
protected void doFree() { protected void deallocate() {
elements = null; elements = null;
head = 0; head = 0;
tail = 0; tail = 0;

View File

@ -29,7 +29,7 @@ import java.nio.channels.ScatteringByteChannel;
* parent. It is recommended to use {@link ByteBuf#duplicate()} instead * parent. It is recommended to use {@link ByteBuf#duplicate()} instead
* of calling the constructor explicitly. * of calling the constructor explicitly.
*/ */
public class DuplicatedByteBuf extends AbstractByteBuf { public class DuplicatedByteBuf extends AbstractDerivedByteBuf {
private final ByteBuf buffer; private final ByteBuf buffer;
@ -231,25 +231,5 @@ public class DuplicatedByteBuf extends AbstractByteBuf {
public ByteBuffer[] nioBuffers(int index, int length) { public ByteBuffer[] nioBuffers(int index, int length) {
return buffer.nioBuffers(index, length); return buffer.nioBuffers(index, length);
} }
@Override
public boolean isFreed() {
return buffer.isFreed();
}
@Override
public void free() {
throw new UnsupportedOperationException("derived");
}
@Override
public ByteBuf suspendIntermediaryDeallocations() {
throw new UnsupportedOperationException("derived");
}
@Override
public ByteBuf resumeIntermediaryDeallocations() {
throw new UnsupportedOperationException("derived");
}
} }

View File

@ -0,0 +1,850 @@
/*
* Copyright 2013 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 java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ReadOnlyBufferException;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.nio.charset.Charset;
public final class EmptyByteBuf implements ByteBuf {
private static final byte[] EMPTY_ARRAY = new byte[0];
public static final EmptyByteBuf INSTANCE_BE = new EmptyByteBuf(ByteOrder.BIG_ENDIAN);
public static final EmptyByteBuf INSTANCE_LE = new EmptyByteBuf(ByteOrder.LITTLE_ENDIAN);
private final ByteOrder order;
private final ByteBuffer nioBuf = ByteBuffer.allocateDirect(0);
private final byte[] array = EMPTY_ARRAY;
private final String str;
private EmptyByteBuf(ByteOrder order) {
this.order = order;
nioBuf.order(order);
str = getClass().getSimpleName() + (order == ByteOrder.BIG_ENDIAN? "BE" : "LE");
}
@Override
public int capacity() {
return 0;
}
@Override
public ByteBuf capacity(int newCapacity) {
throw new ReadOnlyBufferException();
}
@Override
public ByteBufAllocator alloc() {
return UnpooledByteBufAllocator.HEAP_BY_DEFAULT;
}
@Override
public ByteOrder order() {
return order;
}
@Override
public ByteBuf unwrap() {
return null;
}
@Override
public boolean isDirect() {
return false;
}
@Override
public int maxCapacity() {
return 0;
}
@Override
public ByteBuf order(ByteOrder endianness) {
if (endianness == null) {
throw new NullPointerException("endianness");
}
if (endianness == ByteOrder.BIG_ENDIAN) {
return INSTANCE_BE;
}
return INSTANCE_LE;
}
@Override
public int readerIndex() {
return 0;
}
@Override
public ByteBuf readerIndex(int readerIndex) {
return checkIndex(readerIndex);
}
@Override
public int writerIndex() {
return 0;
}
@Override
public ByteBuf writerIndex(int writerIndex) {
return checkIndex(writerIndex);
}
@Override
public ByteBuf setIndex(int readerIndex, int writerIndex) {
checkIndex(readerIndex);
checkIndex(writerIndex);
return this;
}
@Override
public int readableBytes() {
return 0;
}
@Override
public int writableBytes() {
return 0;
}
@Override
public int maxWritableBytes() {
return 0;
}
@Override
public boolean isReadable() {
return false;
}
@Override
public boolean readable() {
return false;
}
@Override
public boolean isWritable() {
return false;
}
@Override
public boolean writable() {
return false;
}
@Override
public ByteBuf clear() {
return this;
}
@Override
public ByteBuf markReaderIndex() {
return this;
}
@Override
public ByteBuf resetReaderIndex() {
return this;
}
@Override
public ByteBuf markWriterIndex() {
return this;
}
@Override
public ByteBuf resetWriterIndex() {
return this;
}
@Override
public ByteBuf discardReadBytes() {
return this;
}
@Override
public ByteBuf discardSomeReadBytes() {
return this;
}
@Override
public ByteBuf ensureWritable(int minWritableBytes) {
if (minWritableBytes < 0) {
throw new IllegalArgumentException("minWritableBytes: " + minWritableBytes + " (expected: >= 0)");
}
if (minWritableBytes != 0) {
throw new IndexOutOfBoundsException();
}
return this;
}
@Override
public ByteBuf ensureWritableBytes(int minWritableBytes) {
return ensureWritable(minWritableBytes);
}
@Override
public int ensureWritable(int minWritableBytes, boolean force) {
if (minWritableBytes < 0) {
throw new IllegalArgumentException("minWritableBytes: " + minWritableBytes + " (expected: >= 0)");
}
if (minWritableBytes == 0) {
return 0;
}
return 1;
}
@Override
public boolean getBoolean(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public byte getByte(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public short getUnsignedByte(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public short getShort(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public int getUnsignedShort(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public int getMedium(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public int getUnsignedMedium(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public int getInt(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public long getUnsignedInt(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public long getLong(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public char getChar(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public float getFloat(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public double getDouble(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf getBytes(int index, ByteBuf dst) {
return checkIndex(index, dst.writableBytes());
}
@Override
public ByteBuf getBytes(int index, ByteBuf dst, int length) {
return checkIndex(index, length);
}
@Override
public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
return checkIndex(index, length);
}
@Override
public ByteBuf getBytes(int index, byte[] dst) {
return checkIndex(index, dst.length);
}
@Override
public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
return checkIndex(index, length);
}
@Override
public ByteBuf getBytes(int index, ByteBuffer dst) {
return checkIndex(index, dst.remaining());
}
@Override
public ByteBuf getBytes(int index, OutputStream out, int length) {
return checkIndex(index, length);
}
@Override
public int getBytes(int index, GatheringByteChannel out, int length) {
checkIndex(index, length);
return 0;
}
@Override
public ByteBuf setBoolean(int index, boolean value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setByte(int index, int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setShort(int index, int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setMedium(int index, int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setInt(int index, int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setLong(int index, long value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setChar(int index, int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setFloat(int index, float value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setDouble(int index, double value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setBytes(int index, ByteBuf src) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setBytes(int index, ByteBuf src, int length) {
return checkIndex(index, length);
}
@Override
public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
return checkIndex(index, length);
}
@Override
public ByteBuf setBytes(int index, byte[] src) {
return checkIndex(index, src.length);
}
@Override
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
return checkIndex(index, length);
}
@Override
public ByteBuf setBytes(int index, ByteBuffer src) {
return checkIndex(index, src.remaining());
}
@Override
public int setBytes(int index, InputStream in, int length) {
checkIndex(index, length);
return 0;
}
@Override
public int setBytes(int index, ScatteringByteChannel in, int length) {
checkIndex(index, length);
return 0;
}
@Override
public ByteBuf setZero(int index, int length) {
return checkIndex(index, length);
}
@Override
public boolean readBoolean() {
throw new IndexOutOfBoundsException();
}
@Override
public byte readByte() {
throw new IndexOutOfBoundsException();
}
@Override
public short readUnsignedByte() {
throw new IndexOutOfBoundsException();
}
@Override
public short readShort() {
throw new IndexOutOfBoundsException();
}
@Override
public int readUnsignedShort() {
throw new IndexOutOfBoundsException();
}
@Override
public int readMedium() {
throw new IndexOutOfBoundsException();
}
@Override
public int readUnsignedMedium() {
throw new IndexOutOfBoundsException();
}
@Override
public int readInt() {
throw new IndexOutOfBoundsException();
}
@Override
public long readUnsignedInt() {
throw new IndexOutOfBoundsException();
}
@Override
public long readLong() {
throw new IndexOutOfBoundsException();
}
@Override
public char readChar() {
throw new IndexOutOfBoundsException();
}
@Override
public float readFloat() {
throw new IndexOutOfBoundsException();
}
@Override
public double readDouble() {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf readBytes(int length) {
return checkLength(length);
}
@Override
public ByteBuf readSlice(int length) {
return checkLength(length);
}
@Override
public ByteBuf readBytes(ByteBuf dst) {
return checkLength(dst.writableBytes());
}
@Override
public ByteBuf readBytes(ByteBuf dst, int length) {
return checkLength(length);
}
@Override
public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
return checkLength(length);
}
@Override
public ByteBuf readBytes(byte[] dst) {
return checkLength(dst.length);
}
@Override
public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
return checkLength(length);
}
@Override
public ByteBuf readBytes(ByteBuffer dst) {
return checkLength(dst.remaining());
}
@Override
public ByteBuf readBytes(OutputStream out, int length) {
return checkLength(length);
}
@Override
public int readBytes(GatheringByteChannel out, int length) {
checkLength(length);
return 0;
}
@Override
public ByteBuf skipBytes(int length) {
return checkLength(length);
}
@Override
public ByteBuf writeBoolean(boolean value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeByte(int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeShort(int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeMedium(int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeInt(int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeLong(long value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeChar(int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeFloat(float value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeDouble(double value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeBytes(ByteBuf src) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeBytes(ByteBuf src, int length) {
return checkLength(length);
}
@Override
public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
return checkLength(length);
}
@Override
public ByteBuf writeBytes(byte[] src) {
return checkLength(src.length);
}
@Override
public ByteBuf writeBytes(byte[] src, int srcIndex, int length) {
return checkLength(length);
}
@Override
public ByteBuf writeBytes(ByteBuffer src) {
return checkLength(src.remaining());
}
@Override
public int writeBytes(InputStream in, int length) {
checkLength(length);
return 0;
}
@Override
public int writeBytes(ScatteringByteChannel in, int length) {
checkLength(length);
return 0;
}
@Override
public ByteBuf writeZero(int length) {
return checkLength(length);
}
@Override
public int indexOf(int fromIndex, int toIndex, byte value) {
checkIndex(fromIndex);
checkIndex(toIndex);
return -1;
}
@Override
public int indexOf(int fromIndex, int toIndex, ByteBufIndexFinder indexFinder) {
checkIndex(fromIndex);
checkIndex(toIndex);
return -1;
}
@Override
public int bytesBefore(byte value) {
return -1;
}
@Override
public int bytesBefore(ByteBufIndexFinder indexFinder) {
return -1;
}
@Override
public int bytesBefore(int length, byte value) {
checkLength(length);
return -1;
}
@Override
public int bytesBefore(int length, ByteBufIndexFinder indexFinder) {
checkLength(length);
return -1;
}
@Override
public int bytesBefore(int index, int length, byte value) {
checkIndex(index, length);
return -1;
}
@Override
public int bytesBefore(int index, int length, ByteBufIndexFinder indexFinder) {
checkIndex(index, length);
return -1;
}
@Override
public ByteBuf copy() {
return this;
}
@Override
public ByteBuf copy(int index, int length) {
return checkIndex(index, length);
}
@Override
public ByteBuf slice() {
return this;
}
@Override
public ByteBuf slice(int index, int length) {
return checkIndex(index, length);
}
@Override
public ByteBuf duplicate() {
return this;
}
@Override
public int nioBufferCount() {
return 1;
}
@Override
public ByteBuffer nioBuffer() {
return nioBuf;
}
@Override
public ByteBuffer nioBuffer(int index, int length) {
checkIndex(index, length);
return nioBuf;
}
@Override
public ByteBuffer[] nioBuffers() {
return new ByteBuffer[] { nioBuf };
}
@Override
public ByteBuffer[] nioBuffers(int index, int length) {
checkIndex(index, length);
return new ByteBuffer[] { nioBuf };
}
@Override
public boolean hasArray() {
return true;
}
@Override
public byte[] array() {
return array;
}
@Override
public int arrayOffset() {
return 0;
}
@Override
public String toString(Charset charset) {
return "";
}
@Override
public String toString(int index, int length, Charset charset) {
checkIndex(index, length);
return "";
}
@Override
public ByteBuf suspendIntermediaryDeallocations() {
return this;
}
@Override
public ByteBuf resumeIntermediaryDeallocations() {
return this;
}
@Override
public int hashCode() {
return 0;
}
@Override
public boolean equals(Object obj) {
return obj instanceof ByteBuf && !((ByteBuf) obj).isReadable();
}
@Override
public int compareTo(ByteBuf buffer) {
return buffer.isReadable()? -1 : 0;
}
@Override
public String toString() {
return str;
}
@Override
public BufType type() {
return BufType.BYTE;
}
@Override
public boolean isReadable(int size) {
checkLength(size);
return false;
}
@Override
public boolean isWritable(int size) {
checkLength(size);
return false;
}
@Override
public int refCnt() {
return 1;
}
@Override
public void retain() { }
@Override
public void retain(int increment) { }
@Override
public boolean release() {
return false;
}
@Override
public boolean release(int decrement) {
return false;
}
private ByteBuf checkIndex(int index) {
if (index != 0) {
throw new IndexOutOfBoundsException();
}
return this;
}
private ByteBuf checkIndex(int index, int length) {
if (length < 0) {
throw new IllegalArgumentException("length: " + length);
}
if (index != 0 || length != 0) {
throw new IndexOutOfBoundsException();
}
return this;
}
private ByteBuf checkLength(int length) {
if (length < 0) {
throw new IllegalArgumentException("length: " + length + " (expected: >= 0)");
}
if (length != 0) {
throw new IndexOutOfBoundsException();
}
return this;
}
}

View File

@ -195,13 +195,33 @@ public abstract class FilteredMessageBuf implements MessageBuf<Object> {
} }
@Override @Override
public boolean isFreed() { public boolean unfoldAndAdd(Object o) {
return buf.isFreed(); return buf.unfoldAndAdd(o);
} }
@Override @Override
public void free() { public int refCnt() {
buf.free(); return buf.refCnt();
}
@Override
public void retain() {
buf.retain();
}
@Override
public void retain(int increment) {
buf.retain(increment);
}
@Override
public boolean release() {
return buf.release();
}
@Override
public boolean release(int decrement) {
return buf.release(decrement);
} }
@Override @Override

View File

@ -1,32 +0,0 @@
/*
* Copyright 2013 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;
public interface Freeable {
/**
* Returns {@code true} if and only if this resource has been deallocated by {@link #free()}.
*/
boolean isFreed();
/**
* Deallocates the resources.
*
* The result of accessing a freed resource is unspecified and can even cause JVM crash.
*
*/
void free();
}

View File

@ -23,7 +23,7 @@ import java.nio.ByteOrder;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Queue; import java.util.Queue;
abstract class PooledByteBuf<T> extends AbstractByteBuf { abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf {
private final ResourceLeak leak = leakDetector.open(this); private final ResourceLeak leak = leakDetector.open(this);
@ -74,7 +74,7 @@ abstract class PooledByteBuf<T> extends AbstractByteBuf {
@Override @Override
public final ByteBuf capacity(int newCapacity) { public final ByteBuf capacity(int newCapacity) {
checkUnfreed(); ensureAccessible();
// If the request capacity does not require reallocation, just update the length of the memory. // If the request capacity does not require reallocation, just update the length of the memory.
if (chunk.unpooled) { if (chunk.unpooled) {
@ -144,7 +144,7 @@ abstract class PooledByteBuf<T> extends AbstractByteBuf {
@Override @Override
public final ByteBuf suspendIntermediaryDeallocations() { public final ByteBuf suspendIntermediaryDeallocations() {
checkUnfreed(); ensureAccessible();
if (suspendedDeallocations == null) { if (suspendedDeallocations == null) {
suspendedDeallocations = new ArrayDeque<Allocation<T>>(2); suspendedDeallocations = new ArrayDeque<Allocation<T>>(2);
} }
@ -153,7 +153,6 @@ abstract class PooledByteBuf<T> extends AbstractByteBuf {
@Override @Override
public final ByteBuf resumeIntermediaryDeallocations() { public final ByteBuf resumeIntermediaryDeallocations() {
checkUnfreed();
if (suspendedDeallocations == null) { if (suspendedDeallocations == null) {
return this; return this;
} }
@ -172,12 +171,7 @@ abstract class PooledByteBuf<T> extends AbstractByteBuf {
} }
@Override @Override
public final boolean isFreed() { protected final void deallocate() {
return memory == null;
}
@Override
public final void free() {
if (handle >= 0) { if (handle >= 0) {
resumeIntermediaryDeallocations(); resumeIntermediaryDeallocations();
final long handle = this.handle; final long handle = this.handle;

View File

@ -21,7 +21,7 @@ import java.util.Queue;
final class QueueBackedMessageBuf<T> extends AbstractMessageBuf<T> { final class QueueBackedMessageBuf<T> extends AbstractMessageBuf<T> {
private final Queue<T> queue; private Queue<T> queue;
QueueBackedMessageBuf(Queue<T> queue) { QueueBackedMessageBuf(Queue<T> queue) {
super(Integer.MAX_VALUE); super(Integer.MAX_VALUE);
@ -36,19 +36,19 @@ final class QueueBackedMessageBuf<T> extends AbstractMessageBuf<T> {
if (e == null) { if (e == null) {
throw new NullPointerException("e"); throw new NullPointerException("e");
} }
checkUnfreed(); ensureAccessible();
return isWritable() && queue.offer(e); return isWritable() && queue.offer(e);
} }
@Override @Override
public T poll() { public T poll() {
checkUnfreed(); ensureAccessible();
return queue.poll(); return queue.poll();
} }
@Override @Override
public T peek() { public T peek() {
checkUnfreed(); ensureAccessible();
return queue.peek(); return queue.peek();
} }
@ -64,66 +64,66 @@ final class QueueBackedMessageBuf<T> extends AbstractMessageBuf<T> {
@Override @Override
public boolean contains(Object o) { public boolean contains(Object o) {
checkUnfreed(); ensureAccessible();
return queue.contains(o); return queue.contains(o);
} }
@Override @Override
public Iterator<T> iterator() { public Iterator<T> iterator() {
checkUnfreed(); ensureAccessible();
return queue.iterator(); return queue.iterator();
} }
@Override @Override
public Object[] toArray() { public Object[] toArray() {
checkUnfreed(); ensureAccessible();
return queue.toArray(); return queue.toArray();
} }
@Override @Override
public <E> E[] toArray(E[] a) { public <E> E[] toArray(E[] a) {
checkUnfreed(); ensureAccessible();
return queue.toArray(a); return queue.toArray(a);
} }
@Override @Override
public boolean remove(Object o) { public boolean remove(Object o) {
checkUnfreed(); ensureAccessible();
return queue.remove(o); return queue.remove(o);
} }
@Override @Override
public boolean containsAll(Collection<?> c) { public boolean containsAll(Collection<?> c) {
checkUnfreed(); ensureAccessible();
return queue.containsAll(c); return queue.containsAll(c);
} }
@Override @Override
public boolean addAll(Collection<? extends T> c) { public boolean addAll(Collection<? extends T> c) {
checkUnfreed(); ensureAccessible();
return isWritable(c.size()) && queue.addAll(c); return isWritable(c.size()) && queue.addAll(c);
} }
@Override @Override
public boolean removeAll(Collection<?> c) { public boolean removeAll(Collection<?> c) {
checkUnfreed(); ensureAccessible();
return queue.removeAll(c); return queue.removeAll(c);
} }
@Override @Override
public boolean retainAll(Collection<?> c) { public boolean retainAll(Collection<?> c) {
checkUnfreed(); ensureAccessible();
return queue.retainAll(c); return queue.retainAll(c);
} }
@Override @Override
public void clear() { public void clear() {
checkUnfreed(); ensureAccessible();
queue.clear(); queue.clear();
} }
@Override @Override
protected void doFree() { protected void deallocate() {
clear(); queue = null;
} }
} }

View File

@ -29,7 +29,7 @@ import java.nio.channels.ScatteringByteChannel;
* recommended to use {@link Unpooled#unmodifiableBuffer(ByteBuf)} * recommended to use {@link Unpooled#unmodifiableBuffer(ByteBuf)}
* instead of calling the constructor explicitly. * instead of calling the constructor explicitly.
*/ */
public class ReadOnlyByteBuf extends AbstractByteBuf { public class ReadOnlyByteBuf extends AbstractDerivedByteBuf {
private final ByteBuf buffer; private final ByteBuf buffer;
@ -229,24 +229,4 @@ public class ReadOnlyByteBuf extends AbstractByteBuf {
public ByteBuf capacity(int newCapacity) { public ByteBuf capacity(int newCapacity) {
throw new ReadOnlyBufferException(); throw new ReadOnlyBufferException();
} }
@Override
public boolean isFreed() {
return buffer.isFreed();
}
@Override
public void free() {
throw new UnsupportedOperationException("derived");
}
@Override
public ByteBuf suspendIntermediaryDeallocations() {
throw new UnsupportedOperationException("derived");
}
@Override
public ByteBuf resumeIntermediaryDeallocations() {
throw new UnsupportedOperationException("derived");
}
} }

View File

@ -0,0 +1,55 @@
/*
* Copyright 2013 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;
/**
* A reference-counted object that requires explicit deallocation.
* <p>
* When a new {@link ReferenceCounted} is instantiated, it starts with the reference count of {@code 1}.
* {@link #retain()} increases the reference count, and {@link #release()} decreases the reference count.
* If the reference count is decreased to {@code 0}, the object will be deallocated explicitly, and accessing
* the deallocated object will usually result in an access violation.
*/
public interface ReferenceCounted {
/**
* Returns the reference count of this object. If {@code 0}, it means this object has been deallocated.
*/
int refCnt();
/**
* Increases the reference count by {@code 1}.
*/
void retain();
/**
* Increases the reference count by the specified {@code increment}.
*/
void retain(int increment);
/**
* Decreases the reference count by {@code 1}.
*
* @return {@code true} if and only if the reference count became {@code 0} and this object has been deallocated
*/
boolean release();
/**
* Decreases the reference count by the specified {@code decrement}.
*
* @return {@code true} if and only if the reference count became {@code 0} and this object has been deallocated
*/
boolean release(int decrement);
}

View File

@ -30,7 +30,7 @@ import java.nio.channels.ScatteringByteChannel;
* {@link ByteBuf#slice(int, int)} instead of calling the constructor * {@link ByteBuf#slice(int, int)} instead of calling the constructor
* explicitly. * explicitly.
*/ */
public class SlicedByteBuf extends AbstractByteBuf { public class SlicedByteBuf extends AbstractDerivedByteBuf {
private final ByteBuf buffer; private final ByteBuf buffer;
private final int adjustment; private final int adjustment;
@ -282,24 +282,4 @@ public class SlicedByteBuf extends AbstractByteBuf {
checkIndex(index, length); checkIndex(index, length);
return buffer.nioBuffers(index, length); return buffer.nioBuffers(index, length);
} }
@Override
public boolean isFreed() {
return buffer.isFreed();
}
@Override
public void free() {
throw new UnsupportedOperationException("derived");
}
@Override
public ByteBuf suspendIntermediaryDeallocations() {
throw new UnsupportedOperationException("derived");
}
@Override
public ByteBuf resumeIntermediaryDeallocations() {
throw new UnsupportedOperationException("derived");
}
} }

View File

@ -816,13 +816,28 @@ public final class SwappedByteBuf implements ByteBuf {
} }
@Override @Override
public boolean isFreed() { public int refCnt() {
return buf.isFreed(); return buf.refCnt();
} }
@Override @Override
public void free() { public void retain() {
buf.free(); buf.retain();
}
@Override
public void retain(int increment) {
buf.retain(increment);
}
@Override
public boolean release() {
return buf.release();
}
@Override
public boolean release(int decrement) {
return buf.release(decrement);
} }
@Override @Override

View File

@ -15,14 +15,9 @@
*/ */
package io.netty.buffer; package io.netty.buffer;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.CharBuffer; import java.nio.CharBuffer;
import java.nio.ReadOnlyBufferException;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -97,192 +92,7 @@ public final class Unpooled {
/** /**
* A buffer whose capacity is {@code 0}. * A buffer whose capacity is {@code 0}.
*/ */
public static final ByteBuf EMPTY_BUFFER = new AbstractByteBuf(0) { public static final ByteBuf EMPTY_BUFFER = EmptyByteBuf.INSTANCE_BE;
@Override
public int capacity() {
return 0;
}
@Override
public ByteBuf capacity(int newCapacity) {
throw new ReadOnlyBufferException();
}
@Override
public ByteBufAllocator alloc() {
return ALLOC;
}
@Override
public ByteOrder order() {
return BIG_ENDIAN;
}
@Override
public ByteBuf unwrap() {
return null;
}
@Override
public boolean isDirect() {
return false;
}
@Override
public byte getByte(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public short getShort(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public int getUnsignedMedium(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public int getInt(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public long getLong(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf getBytes(int index, ByteBuffer dst) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf getBytes(int index, OutputStream out, int length) {
throw new IndexOutOfBoundsException();
}
@Override
public int getBytes(int index, GatheringByteChannel out, int length) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setByte(int index, int value) {
throw new ReadOnlyBufferException();
}
@Override
public ByteBuf setShort(int index, int value) {
throw new ReadOnlyBufferException();
}
@Override
public ByteBuf setMedium(int index, int value) {
throw new ReadOnlyBufferException();
}
@Override
public ByteBuf setInt(int index, int value) {
throw new ReadOnlyBufferException();
}
@Override
public ByteBuf setLong(int index, long value) {
throw new ReadOnlyBufferException();
}
@Override
public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
throw new ReadOnlyBufferException();
}
@Override
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
throw new ReadOnlyBufferException();
}
@Override
public ByteBuf setBytes(int index, ByteBuffer src) {
throw new ReadOnlyBufferException();
}
@Override
public int setBytes(int index, InputStream in, int length) {
throw new ReadOnlyBufferException();
}
@Override
public int setBytes(int index, ScatteringByteChannel in, int length) {
throw new ReadOnlyBufferException();
}
@Override
public ByteBuf copy(int index, int length) {
throw new IndexOutOfBoundsException();
}
@Override
public int nioBufferCount() {
return 0;
}
@Override
public ByteBuffer nioBuffer(int index, int length) {
return ByteBuffer.allocate(0);
}
@Override
public ByteBuffer[] nioBuffers(int index, int length) {
return new ByteBuffer[0];
}
@Override
public boolean hasArray() {
return true;
}
@Override
public byte[] array() {
return new byte[0];
}
@Override
public int arrayOffset() {
return 0;
}
@Override
public ByteBuf suspendIntermediaryDeallocations() {
return this;
}
@Override
public ByteBuf resumeIntermediaryDeallocations() {
return this;
}
@Override
public void free() {
// do nothing
}
@Override
public boolean isFreed() {
return false;
}
};
public static <T> MessageBuf<T> messageBuffer() { public static <T> MessageBuf<T> messageBuffer() {
return new DefaultMessageBuf<T>(); return new DefaultMessageBuf<T>();

View File

@ -34,7 +34,7 @@ import java.util.Queue;
* and {@link Unpooled#wrappedBuffer(ByteBuffer)} instead of calling the * and {@link Unpooled#wrappedBuffer(ByteBuffer)} instead of calling the
* constructor explicitly. * constructor explicitly.
*/ */
final class UnpooledDirectByteBuf extends AbstractByteBuf { final class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
private final ResourceLeak leak = leakDetector.open(this); private final ResourceLeak leak = leakDetector.open(this);
private final ByteBufAllocator alloc; private final ByteBufAllocator alloc;
@ -134,7 +134,7 @@ final class UnpooledDirectByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf capacity(int newCapacity) { public ByteBuf capacity(int newCapacity) {
checkUnfreed(); ensureAccessible();
if (newCapacity < 0 || newCapacity > maxCapacity()) { if (newCapacity < 0 || newCapacity > maxCapacity()) {
throw new IllegalArgumentException("newCapacity: " + newCapacity); throw new IllegalArgumentException("newCapacity: " + newCapacity);
} }
@ -197,37 +197,37 @@ final class UnpooledDirectByteBuf extends AbstractByteBuf {
@Override @Override
public byte getByte(int index) { public byte getByte(int index) {
checkUnfreed(); ensureAccessible();
return buffer.get(index); return buffer.get(index);
} }
@Override @Override
public short getShort(int index) { public short getShort(int index) {
checkUnfreed(); ensureAccessible();
return buffer.getShort(index); return buffer.getShort(index);
} }
@Override @Override
public int getUnsignedMedium(int index) { public int getUnsignedMedium(int index) {
checkUnfreed(); ensureAccessible();
return (getByte(index) & 0xff) << 16 | (getByte(index + 1) & 0xff) << 8 | getByte(index + 2) & 0xff; return (getByte(index) & 0xff) << 16 | (getByte(index + 1) & 0xff) << 8 | getByte(index + 2) & 0xff;
} }
@Override @Override
public int getInt(int index) { public int getInt(int index) {
checkUnfreed(); ensureAccessible();
return buffer.getInt(index); return buffer.getInt(index);
} }
@Override @Override
public long getLong(int index) { public long getLong(int index) {
checkUnfreed(); ensureAccessible();
return buffer.getLong(index); return buffer.getLong(index);
} }
@Override @Override
public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
checkUnfreed(); ensureAccessible();
if (dst instanceof UnpooledDirectByteBuf) { if (dst instanceof UnpooledDirectByteBuf) {
UnpooledDirectByteBuf bbdst = (UnpooledDirectByteBuf) dst; UnpooledDirectByteBuf bbdst = (UnpooledDirectByteBuf) dst;
ByteBuffer data = bbdst.internalNioBuffer(); ByteBuffer data = bbdst.internalNioBuffer();
@ -274,21 +274,21 @@ final class UnpooledDirectByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf setByte(int index, int value) { public ByteBuf setByte(int index, int value) {
checkUnfreed(); ensureAccessible();
buffer.put(index, (byte) value); buffer.put(index, (byte) value);
return this; return this;
} }
@Override @Override
public ByteBuf setShort(int index, int value) { public ByteBuf setShort(int index, int value) {
checkUnfreed(); ensureAccessible();
buffer.putShort(index, (short) value); buffer.putShort(index, (short) value);
return this; return this;
} }
@Override @Override
public ByteBuf setMedium(int index, int value) { public ByteBuf setMedium(int index, int value) {
checkUnfreed(); ensureAccessible();
setByte(index, (byte) (value >>> 16)); setByte(index, (byte) (value >>> 16));
setByte(index + 1, (byte) (value >>> 8)); setByte(index + 1, (byte) (value >>> 8));
setByte(index + 2, (byte) value); setByte(index + 2, (byte) value);
@ -297,21 +297,21 @@ final class UnpooledDirectByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf setInt(int index, int value) { public ByteBuf setInt(int index, int value) {
checkUnfreed(); ensureAccessible();
buffer.putInt(index, value); buffer.putInt(index, value);
return this; return this;
} }
@Override @Override
public ByteBuf setLong(int index, long value) { public ByteBuf setLong(int index, long value) {
checkUnfreed(); ensureAccessible();
buffer.putLong(index, value); buffer.putLong(index, value);
return this; return this;
} }
@Override @Override
public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
checkUnfreed(); ensureAccessible();
if (src instanceof UnpooledDirectByteBuf) { if (src instanceof UnpooledDirectByteBuf) {
UnpooledDirectByteBuf bbsrc = (UnpooledDirectByteBuf) src; UnpooledDirectByteBuf bbsrc = (UnpooledDirectByteBuf) src;
ByteBuffer data = bbsrc.internalNioBuffer(); ByteBuffer data = bbsrc.internalNioBuffer();
@ -328,7 +328,7 @@ final class UnpooledDirectByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
checkUnfreed(); ensureAccessible();
ByteBuffer tmpBuf = internalNioBuffer(); ByteBuffer tmpBuf = internalNioBuffer();
tmpBuf.clear().position(index).limit(index + length); tmpBuf.clear().position(index).limit(index + length);
tmpBuf.put(src, srcIndex, length); tmpBuf.put(src, srcIndex, length);
@ -337,7 +337,7 @@ final class UnpooledDirectByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf setBytes(int index, ByteBuffer src) { public ByteBuf setBytes(int index, ByteBuffer src) {
checkUnfreed(); ensureAccessible();
ByteBuffer tmpBuf = internalNioBuffer(); ByteBuffer tmpBuf = internalNioBuffer();
if (src == tmpBuf) { if (src == tmpBuf) {
src = src.duplicate(); src = src.duplicate();
@ -350,7 +350,7 @@ final class UnpooledDirectByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException { public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
checkUnfreed(); ensureAccessible();
if (length == 0) { if (length == 0) {
return this; return this;
} }
@ -369,7 +369,7 @@ final class UnpooledDirectByteBuf extends AbstractByteBuf {
@Override @Override
public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
checkUnfreed(); ensureAccessible();
if (length == 0) { if (length == 0) {
return 0; return 0;
} }
@ -381,7 +381,7 @@ final class UnpooledDirectByteBuf extends AbstractByteBuf {
@Override @Override
public int setBytes(int index, InputStream in, int length) throws IOException { public int setBytes(int index, InputStream in, int length) throws IOException {
checkUnfreed(); ensureAccessible();
if (buffer.hasArray()) { if (buffer.hasArray()) {
return in.read(buffer.array(), buffer.arrayOffset() + index, length); return in.read(buffer.array(), buffer.arrayOffset() + index, length);
} else { } else {
@ -399,7 +399,7 @@ final class UnpooledDirectByteBuf extends AbstractByteBuf {
@Override @Override
public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
checkUnfreed(); ensureAccessible();
ByteBuffer tmpNioBuf = internalNioBuffer(); ByteBuffer tmpNioBuf = internalNioBuffer();
tmpNioBuf.clear().position(index).limit(index + length); tmpNioBuf.clear().position(index).limit(index + length);
try { try {
@ -416,7 +416,7 @@ final class UnpooledDirectByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuffer nioBuffer(int index, int length) { public ByteBuffer nioBuffer(int index, int length) {
checkUnfreed(); ensureAccessible();
if (index == 0 && length == capacity()) { if (index == 0 && length == capacity()) {
return buffer.duplicate(); return buffer.duplicate();
} else { } else {
@ -431,7 +431,7 @@ final class UnpooledDirectByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf copy(int index, int length) { public ByteBuf copy(int index, int length) {
checkUnfreed(); ensureAccessible();
ByteBuffer src; ByteBuffer src;
try { try {
src = (ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length); src = (ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length);
@ -456,12 +456,7 @@ final class UnpooledDirectByteBuf extends AbstractByteBuf {
} }
@Override @Override
public boolean isFreed() { protected void deallocate() {
return buffer == null;
}
@Override
public void free() {
ByteBuffer buffer = this.buffer; ByteBuffer buffer = this.buffer;
if (buffer == null) { if (buffer == null) {
return; return;
@ -478,6 +473,7 @@ final class UnpooledDirectByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf suspendIntermediaryDeallocations() { public ByteBuf suspendIntermediaryDeallocations() {
ensureAccessible();
if (suspendedDeallocations == null) { if (suspendedDeallocations == null) {
suspendedDeallocations = new ArrayDeque<ByteBuffer>(2); suspendedDeallocations = new ArrayDeque<ByteBuffer>(2);
} }

View File

@ -27,7 +27,7 @@ import java.nio.channels.ScatteringByteChannel;
/** /**
* Big endian Java heap buffer implementation. * Big endian Java heap buffer implementation.
*/ */
final class UnpooledHeapByteBuf extends AbstractByteBuf { final class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf {
private final ByteBufAllocator alloc; private final ByteBufAllocator alloc;
private byte[] array; private byte[] array;
@ -96,13 +96,13 @@ final class UnpooledHeapByteBuf extends AbstractByteBuf {
@Override @Override
public int capacity() { public int capacity() {
checkUnfreed(); ensureAccessible();
return array.length; return array.length;
} }
@Override @Override
public ByteBuf capacity(int newCapacity) { public ByteBuf capacity(int newCapacity) {
checkUnfreed(); ensureAccessible();
if (newCapacity < 0 || newCapacity > maxCapacity()) { if (newCapacity < 0 || newCapacity > maxCapacity()) {
throw new IllegalArgumentException("newCapacity: " + newCapacity); throw new IllegalArgumentException("newCapacity: " + newCapacity);
} }
@ -136,7 +136,7 @@ final class UnpooledHeapByteBuf extends AbstractByteBuf {
@Override @Override
public byte[] array() { public byte[] array() {
checkUnfreed(); ensureAccessible();
return array; return array;
} }
@ -147,13 +147,13 @@ final class UnpooledHeapByteBuf extends AbstractByteBuf {
@Override @Override
public byte getByte(int index) { public byte getByte(int index) {
checkUnfreed(); ensureAccessible();
return array[index]; return array[index];
} }
@Override @Override
public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
checkUnfreed(); ensureAccessible();
if (dst.hasArray()) { if (dst.hasArray()) {
getBytes(index, dst.array(), dst.arrayOffset() + dstIndex, length); getBytes(index, dst.array(), dst.arrayOffset() + dstIndex, length);
} else { } else {
@ -164,41 +164,41 @@ final class UnpooledHeapByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
checkUnfreed(); ensureAccessible();
System.arraycopy(array, index, dst, dstIndex, length); System.arraycopy(array, index, dst, dstIndex, length);
return this; return this;
} }
@Override @Override
public ByteBuf getBytes(int index, ByteBuffer dst) { public ByteBuf getBytes(int index, ByteBuffer dst) {
checkUnfreed(); ensureAccessible();
dst.put(array, index, Math.min(capacity() - index, dst.remaining())); dst.put(array, index, Math.min(capacity() - index, dst.remaining()));
return this; return this;
} }
@Override @Override
public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException { public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
checkUnfreed(); ensureAccessible();
out.write(array, index, length); out.write(array, index, length);
return this; return this;
} }
@Override @Override
public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
checkUnfreed(); ensureAccessible();
return out.write((ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length)); return out.write((ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length));
} }
@Override @Override
public ByteBuf setByte(int index, int value) { public ByteBuf setByte(int index, int value) {
checkUnfreed(); ensureAccessible();
array[index] = (byte) value; array[index] = (byte) value;
return this; return this;
} }
@Override @Override
public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
checkUnfreed(); ensureAccessible();
if (src.hasArray()) { if (src.hasArray()) {
setBytes(index, src.array(), src.arrayOffset() + srcIndex, length); setBytes(index, src.array(), src.arrayOffset() + srcIndex, length);
} else { } else {
@ -209,27 +209,27 @@ final class UnpooledHeapByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
checkUnfreed(); ensureAccessible();
System.arraycopy(src, srcIndex, array, index, length); System.arraycopy(src, srcIndex, array, index, length);
return this; return this;
} }
@Override @Override
public ByteBuf setBytes(int index, ByteBuffer src) { public ByteBuf setBytes(int index, ByteBuffer src) {
checkUnfreed(); ensureAccessible();
src.get(array, index, src.remaining()); src.get(array, index, src.remaining());
return this; return this;
} }
@Override @Override
public int setBytes(int index, InputStream in, int length) throws IOException { public int setBytes(int index, InputStream in, int length) throws IOException {
checkUnfreed(); ensureAccessible();
return in.read(array, index, length); return in.read(array, index, length);
} }
@Override @Override
public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
checkUnfreed(); ensureAccessible();
try { try {
return in.read((ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length)); return in.read((ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length));
} catch (ClosedChannelException e) { } catch (ClosedChannelException e) {
@ -244,7 +244,7 @@ final class UnpooledHeapByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuffer nioBuffer(int index, int length) { public ByteBuffer nioBuffer(int index, int length) {
checkUnfreed(); ensureAccessible();
return ByteBuffer.wrap(array, index, length); return ByteBuffer.wrap(array, index, length);
} }
@ -255,13 +255,13 @@ final class UnpooledHeapByteBuf extends AbstractByteBuf {
@Override @Override
public short getShort(int index) { public short getShort(int index) {
checkUnfreed(); ensureAccessible();
return (short) (array[index] << 8 | array[index + 1] & 0xFF); return (short) (array[index] << 8 | array[index + 1] & 0xFF);
} }
@Override @Override
public int getUnsignedMedium(int index) { public int getUnsignedMedium(int index) {
checkUnfreed(); ensureAccessible();
return (array[index] & 0xff) << 16 | return (array[index] & 0xff) << 16 |
(array[index + 1] & 0xff) << 8 | (array[index + 1] & 0xff) << 8 |
array[index + 2] & 0xff; array[index + 2] & 0xff;
@ -269,7 +269,7 @@ final class UnpooledHeapByteBuf extends AbstractByteBuf {
@Override @Override
public int getInt(int index) { public int getInt(int index) {
checkUnfreed(); ensureAccessible();
return (array[index] & 0xff) << 24 | return (array[index] & 0xff) << 24 |
(array[index + 1] & 0xff) << 16 | (array[index + 1] & 0xff) << 16 |
(array[index + 2] & 0xff) << 8 | (array[index + 2] & 0xff) << 8 |
@ -278,7 +278,7 @@ final class UnpooledHeapByteBuf extends AbstractByteBuf {
@Override @Override
public long getLong(int index) { public long getLong(int index) {
checkUnfreed(); ensureAccessible();
return ((long) array[index] & 0xff) << 56 | return ((long) array[index] & 0xff) << 56 |
((long) array[index + 1] & 0xff) << 48 | ((long) array[index + 1] & 0xff) << 48 |
((long) array[index + 2] & 0xff) << 40 | ((long) array[index + 2] & 0xff) << 40 |
@ -291,7 +291,7 @@ final class UnpooledHeapByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf setShort(int index, int value) { public ByteBuf setShort(int index, int value) {
checkUnfreed(); ensureAccessible();
array[index] = (byte) (value >>> 8); array[index] = (byte) (value >>> 8);
array[index + 1] = (byte) value; array[index + 1] = (byte) value;
return this; return this;
@ -299,7 +299,7 @@ final class UnpooledHeapByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf setMedium(int index, int value) { public ByteBuf setMedium(int index, int value) {
checkUnfreed(); ensureAccessible();
array[index] = (byte) (value >>> 16); array[index] = (byte) (value >>> 16);
array[index + 1] = (byte) (value >>> 8); array[index + 1] = (byte) (value >>> 8);
array[index + 2] = (byte) value; array[index + 2] = (byte) value;
@ -308,7 +308,7 @@ final class UnpooledHeapByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf setInt(int index, int value) { public ByteBuf setInt(int index, int value) {
checkUnfreed(); ensureAccessible();
array[index] = (byte) (value >>> 24); array[index] = (byte) (value >>> 24);
array[index + 1] = (byte) (value >>> 16); array[index + 1] = (byte) (value >>> 16);
array[index + 2] = (byte) (value >>> 8); array[index + 2] = (byte) (value >>> 8);
@ -318,7 +318,7 @@ final class UnpooledHeapByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf setLong(int index, long value) { public ByteBuf setLong(int index, long value) {
checkUnfreed(); ensureAccessible();
array[index] = (byte) (value >>> 56); array[index] = (byte) (value >>> 56);
array[index + 1] = (byte) (value >>> 48); array[index + 1] = (byte) (value >>> 48);
array[index + 2] = (byte) (value >>> 40); array[index + 2] = (byte) (value >>> 40);
@ -347,12 +347,7 @@ final class UnpooledHeapByteBuf extends AbstractByteBuf {
} }
@Override @Override
public boolean isFreed() { protected void deallocate() {
return array == null;
}
@Override
public void free() {
array = null; array = null;
} }

View File

@ -30,6 +30,7 @@ import java.util.Random;
import java.util.Set; import java.util.Set;
import static io.netty.buffer.Unpooled.*; import static io.netty.buffer.Unpooled.*;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
/** /**
@ -62,8 +63,16 @@ public abstract class AbstractByteBufTest {
@After @After
public void dispose() { public void dispose() {
if (buffer != null) { if (buffer != null) {
if (buffer.unwrap() == null) {
assertThat(buffer.release(), is(true));
assertThat(buffer.refCnt(), is(0));
} else {
assertThat(buffer.release(), is(false));
assertThat(buffer.refCnt(), is(1));
}
try { try {
buffer.free(); buffer.release();
} catch (Exception e) { } catch (Exception e) {
// Ignore. // Ignore.
} }
@ -872,8 +881,8 @@ public abstract class AbstractByteBufTest {
} }
} }
value.free(); value.release();
expectedValue.free(); expectedValue.release();
} }
@Test @Test
@ -1049,7 +1058,7 @@ public abstract class AbstractByteBufTest {
assertEquals(0, value.writerIndex()); assertEquals(0, value.writerIndex());
} }
value.free(); value.release();
} }
@Test @Test
@ -1090,7 +1099,7 @@ public abstract class AbstractByteBufTest {
assertEquals(valueOffset + BLOCK_SIZE, value.writerIndex()); assertEquals(valueOffset + BLOCK_SIZE, value.writerIndex());
} }
value.free(); value.release();
} }
@Test @Test
@ -1623,8 +1632,8 @@ public abstract class AbstractByteBufTest {
assertFalse(set.contains(elemB)); assertFalse(set.contains(elemB));
assertEquals(0, set.size()); assertEquals(0, set.size());
elemB.free(); elemB.release();
elemBCopy.free(); elemBCopy.release();
} }
// Test case for https://github.com/netty/netty/issues/325 // Test case for https://github.com/netty/netty/issues/325

View File

@ -52,7 +52,7 @@ public class UnpooledTest {
assertEquals(12 + 512, buffer.readableBytes()); assertEquals(12 + 512, buffer.readableBytes());
assertEquals(2, buffer.nioBufferCount()); assertEquals(2, buffer.nioBufferCount());
buffer.free(); buffer.release();
} }
@Test @Test
@ -160,11 +160,8 @@ public class UnpooledTest {
@Test @Test
public void shouldReturnEmptyBufferWhenLengthIsZero() { public void shouldReturnEmptyBufferWhenLengthIsZero() {
assertSame(EMPTY_BUFFER, wrappedBuffer(new byte[0])); assertSame(EMPTY_BUFFER, wrappedBuffer(new byte[0]));
assertSame(EMPTY_BUFFER, wrappedBuffer(new byte[0]).order(LITTLE_ENDIAN));
assertSame(EMPTY_BUFFER, wrappedBuffer(new byte[8], 0, 0)); assertSame(EMPTY_BUFFER, wrappedBuffer(new byte[8], 0, 0));
assertSame(EMPTY_BUFFER, wrappedBuffer(new byte[8], 0, 0).order(LITTLE_ENDIAN));
assertSame(EMPTY_BUFFER, wrappedBuffer(new byte[8], 8, 0)); assertSame(EMPTY_BUFFER, wrappedBuffer(new byte[8], 8, 0));
assertSame(EMPTY_BUFFER, wrappedBuffer(new byte[8], 8, 0).order(LITTLE_ENDIAN));
assertSame(EMPTY_BUFFER, wrappedBuffer(ByteBuffer.allocateDirect(0))); assertSame(EMPTY_BUFFER, wrappedBuffer(ByteBuffer.allocateDirect(0)));
assertSame(EMPTY_BUFFER, wrappedBuffer(EMPTY_BUFFER)); assertSame(EMPTY_BUFFER, wrappedBuffer(EMPTY_BUFFER));
assertSame(EMPTY_BUFFER, wrappedBuffer(new byte[0][])); assertSame(EMPTY_BUFFER, wrappedBuffer(new byte[0][]));
@ -177,11 +174,8 @@ public class UnpooledTest {
assertSame(EMPTY_BUFFER, wrappedBuffer(buffer(0), buffer(0))); assertSame(EMPTY_BUFFER, wrappedBuffer(buffer(0), buffer(0)));
assertSame(EMPTY_BUFFER, copiedBuffer(new byte[0])); assertSame(EMPTY_BUFFER, copiedBuffer(new byte[0]));
assertSame(EMPTY_BUFFER, copiedBuffer(new byte[0]).order(LITTLE_ENDIAN));
assertSame(EMPTY_BUFFER, copiedBuffer(new byte[8], 0, 0)); assertSame(EMPTY_BUFFER, copiedBuffer(new byte[8], 0, 0));
assertSame(EMPTY_BUFFER, copiedBuffer(new byte[8], 0, 0).order(LITTLE_ENDIAN));
assertSame(EMPTY_BUFFER, copiedBuffer(new byte[8], 8, 0)); assertSame(EMPTY_BUFFER, copiedBuffer(new byte[8], 8, 0));
assertSame(EMPTY_BUFFER, copiedBuffer(new byte[8], 8, 0).order(LITTLE_ENDIAN));
assertSame(EMPTY_BUFFER, copiedBuffer(ByteBuffer.allocateDirect(0))); assertSame(EMPTY_BUFFER, copiedBuffer(ByteBuffer.allocateDirect(0)));
assertSame(EMPTY_BUFFER, copiedBuffer(EMPTY_BUFFER)); assertSame(EMPTY_BUFFER, copiedBuffer(EMPTY_BUFFER));
assertSame(EMPTY_BUFFER, copiedBuffer(new byte[0][])); assertSame(EMPTY_BUFFER, copiedBuffer(new byte[0][]));

View File

@ -48,13 +48,28 @@ public class DefaultFullHttpRequest extends DefaultHttpRequest implements FullHt
} }
@Override @Override
public boolean isFreed() { public int refCnt() {
return content.isFreed(); return content.refCnt();
} }
@Override @Override
public void free() { public void retain() {
content.free(); content.retain();
}
@Override
public void retain(int increment) {
content.retain(increment);
}
@Override
public boolean release() {
return content.release();
}
@Override
public boolean release(int decrement) {
return content.release(decrement);
} }
@Override @Override

View File

@ -50,13 +50,28 @@ public class DefaultFullHttpResponse extends DefaultHttpResponse implements Full
} }
@Override @Override
public boolean isFreed() { public int refCnt() {
return content.isFreed(); return content.refCnt();
} }
@Override @Override
public void free() { public void retain() {
content.free(); content.retain();
}
@Override
public void retain(int increment) {
content.retain(increment);
}
@Override
public boolean release() {
return content.release();
}
@Override
public boolean release(int decrement) {
return content.release(decrement);
} }
@Override @Override

View File

@ -41,17 +41,32 @@ public class DefaultHttpContent extends DefaultHttpObject implements HttpContent
@Override @Override
public HttpContent copy() { public HttpContent copy() {
return new DefaultHttpContent(data().copy()); return new DefaultHttpContent(content.copy());
} }
@Override @Override
public boolean isFreed() { public int refCnt() {
return content.isFreed(); return content.refCnt();
} }
@Override @Override
public void free() { public void retain() {
content.free(); content.retain();
}
@Override
public void retain(int increment) {
content.retain(increment);
}
@Override
public boolean release() {
return content.release();
}
@Override
public boolean release(int decrement) {
return content.release(decrement);
} }
@Override @Override

View File

@ -156,7 +156,7 @@ public class HttpObjectAggregator extends MessageToMessageDecoder<HttpObject> {
CompositeByteBuf content = (CompositeByteBuf) currentMessage.data(); CompositeByteBuf content = (CompositeByteBuf) currentMessage.data();
if (content.readableBytes() > maxContentLength - chunk.data().readableBytes()) { if (content.readableBytes() > maxContentLength - chunk.data().readableBytes()) {
chunk.free(); chunk.release();
// TODO: Respond with 413 Request Entity Too Large // TODO: Respond with 413 Request Entity Too Large
// and discard the traffic or close the connection. // and discard the traffic or close the connection.
// No need to notify the upstream handlers - just log. // No need to notify the upstream handlers - just log.
@ -171,7 +171,7 @@ public class HttpObjectAggregator extends MessageToMessageDecoder<HttpObject> {
content.addComponent(chunk.data()); content.addComponent(chunk.data());
content.writerIndex(content.writerIndex() + chunk.data().readableBytes()); content.writerIndex(content.writerIndex() + chunk.data().readableBytes());
} else { } else {
chunk.free(); chunk.release();
} }
final boolean last; final boolean last;

View File

@ -55,13 +55,24 @@ public interface LastHttpContent extends HttpContent {
} }
@Override @Override
public boolean isFreed() { public int refCnt() {
return 1;
}
@Override
public void retain() { }
@Override
public void retain(int increment) { }
@Override
public boolean release() {
return false; return false;
} }
@Override @Override
public void free() { public boolean release(int decrement) {
// NOOP return false;
} }
}; };

View File

@ -352,13 +352,4 @@ public abstract class AbstractDiskHttpData extends AbstractHttpData {
public File getFile() throws IOException { public File getFile() throws IOException {
return file; return file;
} }
@Override
public boolean isFreed() {
if (file == null || !file.exists()) {
return true;
}
return false;
}
} }

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.handler.codec.http.multipart; package io.netty.handler.codec.http.multipart;
import io.netty.buffer.AbstractReferenceCounted;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelException; import io.netty.channel.ChannelException;
import io.netty.handler.codec.http.HttpConstants; import io.netty.handler.codec.http.HttpConstants;
@ -25,7 +26,7 @@ import java.nio.charset.Charset;
/** /**
* Abstract HttpData implementation * Abstract HttpData implementation
*/ */
public abstract class AbstractHttpData implements HttpData { public abstract class AbstractHttpData extends AbstractReferenceCounted implements HttpData {
protected final String name; protected final String name;
protected long definedSize; protected long definedSize;
@ -110,8 +111,7 @@ public abstract class AbstractHttpData implements HttpData {
} }
@Override @Override
public void free() { protected void deallocate() {
delete(); delete();
} }
} }

View File

@ -138,7 +138,7 @@ public abstract class AbstractMemoryHttpData extends AbstractHttpData {
@Override @Override
public byte[] get() { public byte[] get() {
if (byteBuf == null) { if (byteBuf == null) {
return new byte[0]; return EMPTY_BUFFER.array();
} }
byte[] array = new byte[byteBuf.readableBytes()]; byte[] array = new byte[byteBuf.readableBytes()];
byteBuf.getBytes(byteBuf.readerIndex(), array); byteBuf.getBytes(byteBuf.readerIndex(), array);
@ -226,9 +226,4 @@ public abstract class AbstractMemoryHttpData extends AbstractHttpData {
public File getFile() throws IOException { public File getFile() throws IOException {
throw new IOException("Not represented by a file"); throw new IOException("Not represented by a file");
} }
@Override
public boolean isFreed() {
return data().isFreed();
}
} }

View File

@ -210,12 +210,27 @@ public class MixedAttribute implements Attribute {
} }
@Override @Override
public void free() { public int refCnt() {
attribute.free(); return attribute.refCnt();
} }
@Override @Override
public boolean isFreed() { public void retain() {
return attribute.isFreed(); attribute.retain();
}
@Override
public void retain(int increment) {
attribute.retain(increment);
}
@Override
public boolean release() {
return attribute.release();
}
@Override
public boolean release(int decrement) {
return attribute.release(decrement);
} }
} }

View File

@ -26,6 +26,7 @@ import java.nio.charset.Charset;
* Mixed implementation using both in Memory and in File with a limit of size * Mixed implementation using both in Memory and in File with a limit of size
*/ */
public class MixedFileUpload implements FileUpload { public class MixedFileUpload implements FileUpload {
private FileUpload fileUpload; private FileUpload fileUpload;
private final long limitSize; private final long limitSize;
@ -235,12 +236,27 @@ public class MixedFileUpload implements FileUpload {
} }
@Override @Override
public void free() { public int refCnt() {
fileUpload.free(); return fileUpload.refCnt();
} }
@Override @Override
public boolean isFreed() { public void retain() {
return fileUpload.isFreed(); fileUpload.retain();
}
@Override
public void retain(int increment) {
fileUpload.retain(increment);
}
@Override
public boolean release() {
return fileUpload.release();
}
@Override
public boolean release(int decrement) {
return fileUpload.release(decrement);
} }
} }

View File

@ -101,7 +101,7 @@ public class DefaultSpdyDataFrame extends DefaultByteBufHolder implements SpdyDa
buf.append(streamId); buf.append(streamId);
buf.append(StringUtil.NEWLINE); buf.append(StringUtil.NEWLINE);
buf.append("--> Size = "); buf.append("--> Size = ");
if (isFreed()) { if (refCnt() <= 0) {
buf.append("(freed)"); buf.append("(freed)");
} else { } else {
buf.append(data().readableBytes()); buf.append(data().readableBytes());

View File

@ -72,7 +72,7 @@ public abstract class SpdyOrHttpChooser extends ChannelDuplexHandler implements
@Override @Override
public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception { public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception {
ctx.inboundByteBuffer().free(); ctx.inboundByteBuffer().release();
} }
@Override @Override

View File

@ -92,7 +92,7 @@ public class SpdySessionHandler
@Override @Override
public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception { public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception {
ctx.inboundByteBuffer().free(); ctx.inboundByteBuffer().release();
} }
@Override @Override
@ -102,7 +102,7 @@ public class SpdySessionHandler
@Override @Override
public void freeOutboundBuffer(ChannelHandlerContext ctx) throws Exception { public void freeOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
ctx.outboundMessageBuffer().free(); ctx.outboundMessageBuffer().release();
} }
@Override @Override

View File

@ -150,7 +150,7 @@ public class WebSocketServerProtocolHandlerTest {
@Override @Override
public void freeOutboundBuffer(ChannelHandlerContext ctx) throws Exception { public void freeOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
ctx.outboundMessageBuffer().free(); ctx.outboundMessageBuffer().release();
} }
@Override @Override

View File

@ -174,10 +174,10 @@ public abstract class MessageToMessageCodec<INBOUND_IN, OUTBOUND_IN>
protected abstract Object decode(ChannelHandlerContext ctx, INBOUND_IN msg) throws Exception; protected abstract Object decode(ChannelHandlerContext ctx, INBOUND_IN msg) throws Exception;
protected void freeInboundMessage(INBOUND_IN msg) throws Exception { protected void freeInboundMessage(INBOUND_IN msg) throws Exception {
BufUtil.free(msg); BufUtil.release(msg);
} }
protected void freeOutboundMessage(OUTBOUND_IN msg) throws Exception { protected void freeOutboundMessage(OUTBOUND_IN msg) throws Exception {
BufUtil.free(msg); BufUtil.release(msg);
} }
} }

View File

@ -879,12 +879,27 @@ final class ReplayingDecoderBuffer implements ByteBuf {
} }
@Override @Override
public boolean isFreed() { public int refCnt() {
return buffer.isFreed(); return buffer.refCnt();
} }
@Override @Override
public void free() { public void retain() {
throw new UnreplayableOperationException();
}
@Override
public void retain(int increment) {
throw new UnreplayableOperationException();
}
@Override
public boolean release() {
throw new UnreplayableOperationException();
}
@Override
public boolean release(int decrement) {
throw new UnreplayableOperationException(); throw new UnreplayableOperationException();
} }

View File

@ -47,9 +47,8 @@ public class ByteArrayDecoderTest {
@Test @Test
public void testDecodeEmpty() { public void testDecodeEmpty() {
byte[] b = new byte[0]; ch.writeInbound(EMPTY_BUFFER);
ch.writeInbound(wrappedBuffer(b)); assertThat((byte[]) ch.readInbound(), is(new byte[0]));
assertThat((byte[]) ch.readInbound(), is(b));
} }
@Test @Test

View File

@ -32,7 +32,8 @@ public class DiscardClientHandler extends ChannelInboundByteHandlerAdapter {
private static final Logger logger = Logger.getLogger( private static final Logger logger = Logger.getLogger(
DiscardClientHandler.class.getName()); DiscardClientHandler.class.getName());
private final byte[] content; private final int messageSize;
private ByteBuf content;
private ChannelHandlerContext ctx; private ChannelHandlerContext ctx;
public DiscardClientHandler(int messageSize) { public DiscardClientHandler(int messageSize) {
@ -40,13 +41,17 @@ public class DiscardClientHandler extends ChannelInboundByteHandlerAdapter {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"messageSize: " + messageSize); "messageSize: " + messageSize);
} }
content = new byte[messageSize]; this.messageSize = messageSize;
} }
@Override @Override
public void channelActive(ChannelHandlerContext ctx) public void channelActive(ChannelHandlerContext ctx)
throws Exception { throws Exception {
this.ctx = ctx; this.ctx = ctx;
// Initialize the message.
content = ctx.alloc().directBuffer(messageSize).writeZero(messageSize);
// Send the initial messages. // Send the initial messages.
generateTraffic(); generateTraffic();
} }
@ -75,7 +80,7 @@ public class DiscardClientHandler extends ChannelInboundByteHandlerAdapter {
// Fill the outbound buffer up to 64KiB // Fill the outbound buffer up to 64KiB
ByteBuf out = ctx.nextOutboundByteBuffer(); ByteBuf out = ctx.nextOutboundByteBuffer();
while (out.readableBytes() < 65536) { while (out.readableBytes() < 65536) {
out.writeBytes(content); out.writeBytes(content, 0, content.readableBytes());
} }
// Flush the outbound buffer to the socket. // Flush the outbound buffer to the socket.

View File

@ -30,6 +30,13 @@ public class DiscardServerHandler extends ChannelInboundByteHandlerAdapter {
private static final Logger logger = Logger.getLogger( private static final Logger logger = Logger.getLogger(
DiscardServerHandler.class.getName()); DiscardServerHandler.class.getName());
@Override
public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
// Use direct buffer if possible.
// If you are going to use a heap buffer, you don't need to override this method.
return ctx.alloc().ioBuffer();
}
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in)
throws Exception { throws Exception {

View File

@ -48,6 +48,13 @@ public class EchoClientHandler extends ChannelInboundByteHandlerAdapter {
} }
} }
@Override
public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
// Use direct buffer if possible.
// If you are going to use a heap buffer, you don't need to override this method.
return ctx.alloc().ioBuffer();
}
@Override @Override
public void channelActive(ChannelHandlerContext ctx) { public void channelActive(ChannelHandlerContext ctx) {
ctx.write(firstMessage); ctx.write(firstMessage);

View File

@ -32,6 +32,13 @@ public class EchoServerHandler extends ChannelInboundByteHandlerAdapter {
private static final Logger logger = Logger.getLogger( private static final Logger logger = Logger.getLogger(
EchoServerHandler.class.getName()); EchoServerHandler.class.getName());
@Override
public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
// Use direct buffer if possible.
// If you are going to use a heap buffer, you don't need to override this method.
return ctx.alloc().ioBuffer();
}
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) { public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) {
ByteBuf out = ctx.nextOutboundByteBuffer(); ByteBuf out = ctx.nextOutboundByteBuffer();

View File

@ -118,7 +118,7 @@ public class ByteLoggingHandler
@Override @Override
public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception { public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception {
ctx.inboundByteBuffer().free(); ctx.inboundByteBuffer().release();
} }
@Override @Override
@ -133,7 +133,7 @@ public class ByteLoggingHandler
@Override @Override
public void freeOutboundBuffer(ChannelHandlerContext ctx) throws Exception { public void freeOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
ctx.outboundByteBuffer().free(); ctx.outboundByteBuffer().release();
} }
@Override @Override

View File

@ -388,7 +388,7 @@ public class SslHandler
@Override @Override
public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception { public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception {
ctx.inboundByteBuffer().free(); ctx.inboundByteBuffer().release();
} }
@Override @Override
@ -403,7 +403,7 @@ public class SslHandler
@Override @Override
public void freeOutboundBuffer(ChannelHandlerContext ctx) throws Exception { public void freeOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
ctx.outboundByteBuffer().free(); ctx.outboundByteBuffer().release();
} }
@Override @Override

View File

@ -98,7 +98,7 @@ public class ChunkedWriteHandler
@Override @Override
public void freeOutboundBuffer(ChannelHandlerContext ctx) throws Exception { public void freeOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
queue.free(); queue.release();
} }
private boolean isWritable() { private boolean isWritable() {

View File

@ -51,7 +51,7 @@ public class ByteBufAllocatorBenchmark extends DefaultBenchmark {
@Override @Override
protected void tearDown() throws Exception { protected void tearDown() throws Exception {
for (ByteBuf b: queue) { for (ByteBuf b: queue) {
b.free(); b.release();
} }
queue.clear(); queue.clear();
} }
@ -63,7 +63,7 @@ public class ByteBufAllocatorBenchmark extends DefaultBenchmark {
for (int i = 0; i < reps; i ++) { for (int i = 0; i < reps; i ++) {
queue.add(alloc.buffer(size)); queue.add(alloc.buffer(size));
queue.removeFirst().free(); queue.removeFirst().release();
} }
} }

View File

@ -17,6 +17,7 @@ package io.netty.testsuite.transport.socket;
import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap; import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.BufUtil;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.Channel; import io.netty.channel.Channel;
@ -234,6 +235,7 @@ public class SocketSpdyEchoTest extends AbstractSocketTest {
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
BufUtil.retain(msg);
ctx.write(msg); ctx.write(msg);
} }

View File

@ -137,7 +137,7 @@ public final class SctpMessage extends DefaultByteBufHolder {
@Override @Override
public String toString() { public String toString() {
if (isFreed()) { if (refCnt() <= 0) {
return "SctpFrame{" + return "SctpFrame{" +
"streamIdentifier=" + streamIdentifier + ", protocolIdentifier=" + protocolIdentifier + "streamIdentifier=" + streamIdentifier + ", protocolIdentifier=" + protocolIdentifier +
", data=(FREED)}"; ", data=(FREED)}";

View File

@ -27,12 +27,12 @@ import io.netty.channel.ChannelException;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelMetadata;
import io.netty.channel.ChannelPromise; import io.netty.channel.ChannelPromise;
import io.netty.channel.sctp.SctpServerChannel;
import io.netty.channel.nio.AbstractNioMessageChannel; import io.netty.channel.nio.AbstractNioMessageChannel;
import io.netty.channel.sctp.DefaultSctpChannelConfig; import io.netty.channel.sctp.DefaultSctpChannelConfig;
import io.netty.channel.sctp.SctpChannelConfig; import io.netty.channel.sctp.SctpChannelConfig;
import io.netty.channel.sctp.SctpMessage; import io.netty.channel.sctp.SctpMessage;
import io.netty.channel.sctp.SctpNotificationHandler; import io.netty.channel.sctp.SctpNotificationHandler;
import io.netty.channel.sctp.SctpServerChannel;
import io.netty.logging.InternalLogger; import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory; import io.netty.logging.InternalLoggerFactory;
@ -288,7 +288,7 @@ public class NioSctpChannel extends AbstractNioMessageChannel implements io.nett
throw new ChannelException(cause); throw new ChannelException(cause);
} finally { } finally {
if (free) { if (free) {
buffer.free(); buffer.release();
} }
} }
} }
@ -333,7 +333,7 @@ public class NioSctpChannel extends AbstractNioMessageChannel implements io.nett
buf.remove(); buf.remove();
// packet was written free up buffer // packet was written free up buffer
packet.free(); packet.release();
if (buf.isEmpty()) { if (buf.isEmpty()) {
// Wrote the outbound buffer completely - clear OP_WRITE. // Wrote the outbound buffer completely - clear OP_WRITE.

View File

@ -27,12 +27,12 @@ import io.netty.channel.ChannelException;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelMetadata;
import io.netty.channel.ChannelPromise; import io.netty.channel.ChannelPromise;
import io.netty.channel.sctp.SctpServerChannel;
import io.netty.channel.oio.AbstractOioMessageChannel; import io.netty.channel.oio.AbstractOioMessageChannel;
import io.netty.channel.sctp.DefaultSctpChannelConfig; import io.netty.channel.sctp.DefaultSctpChannelConfig;
import io.netty.channel.sctp.SctpChannelConfig; import io.netty.channel.sctp.SctpChannelConfig;
import io.netty.channel.sctp.SctpMessage; import io.netty.channel.sctp.SctpMessage;
import io.netty.channel.sctp.SctpNotificationHandler; import io.netty.channel.sctp.SctpNotificationHandler;
import io.netty.channel.sctp.SctpServerChannel;
import io.netty.logging.InternalLogger; import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory; import io.netty.logging.InternalLoggerFactory;
@ -209,7 +209,7 @@ public class OioSctpChannel extends AbstractOioMessageChannel
throw new ChannelException(cause); throw new ChannelException(cause);
} finally { } finally {
if (free) { if (free) {
buffer.free(); buffer.release();
} }
} }
} }
@ -252,7 +252,7 @@ public class OioSctpChannel extends AbstractOioMessageChannel
ch.send(nioData, mi); ch.send(nioData, mi);
} finally { } finally {
packet.free(); packet.release();
} }
} }
writableKeys.clear(); writableKeys.clear();

View File

@ -154,7 +154,7 @@ public class NioUdtMessageConnectorChannel extends AbstractNioMessageChannel
maximumMessageSize); maximumMessageSize);
if (receivedMessageSize <= 0) { if (receivedMessageSize <= 0) {
byteBuf.free(); byteBuf.release();
return 0; return 0;
} }
@ -216,7 +216,7 @@ public class NioUdtMessageConnectorChannel extends AbstractNioMessageChannel
messageQueue.remove(); messageQueue.remove();
message.free(); message.release();
return 1; return 1;
} }

View File

@ -55,7 +55,6 @@ public class EchoMessageHandler extends
} }
message = new UdtMessage(byteBuf); message = new UdtMessage(byteBuf);
} }
@Override @Override
@ -67,24 +66,17 @@ public class EchoMessageHandler extends
final MessageBuf<Object> out = ctx.nextOutboundMessageBuffer(); final MessageBuf<Object> out = ctx.nextOutboundMessageBuffer();
out.add(message); out.add(message);
ctx.flush(); ctx.flush();
} }
@Override @Override
public void exceptionCaught(final ChannelHandlerContext ctx, public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable e) {
final Throwable e) { log.error("exception", e);
log.error("exception : {}", e.getMessage());
ctx.close(); ctx.close();
} }
@Override @Override
protected void messageReceived(final ChannelHandlerContext ctx, protected void messageReceived(final ChannelHandlerContext ctx, final UdtMessage message) throws Exception {
final UdtMessage message) throws Exception {
final ByteBuf byteBuf = message.data(); final ByteBuf byteBuf = message.data();
@ -94,10 +86,8 @@ public class EchoMessageHandler extends
final MessageBuf<Object> out = ctx.nextOutboundMessageBuffer(); final MessageBuf<Object> out = ctx.nextOutboundMessageBuffer();
message.retain();
out.add(message); out.add(message);
ctx.flush(); ctx.flush();
} }
} }

View File

@ -285,7 +285,7 @@ public final class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, Se
@Override @Override
public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception { public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception {
ctx.inboundMessageBuffer().free(); ctx.inboundMessageBuffer().release();
} }
} }

View File

@ -43,7 +43,7 @@ public abstract class ChannelInboundByteHandlerAdapter
@Override @Override
public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception { public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception {
ctx.inboundByteBuffer().free(); ctx.inboundByteBuffer().release();
} }
@Override @Override

View File

@ -71,7 +71,7 @@ public abstract class ChannelInboundMessageHandlerAdapter<I>
@Override @Override
public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception { public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception {
ctx.inboundMessageBuffer().free(); ctx.inboundMessageBuffer().release();
} }
@Override @Override
@ -178,6 +178,6 @@ public abstract class ChannelInboundMessageHandlerAdapter<I>
* just pass-through the input message or need it for later usage. * just pass-through the input message or need it for later usage.
*/ */
protected void freeInboundMessage(I msg) throws Exception { protected void freeInboundMessage(I msg) throws Exception {
BufUtil.free(msg); BufUtil.release(msg);
} }
} }

View File

@ -34,7 +34,7 @@ public abstract class ChannelOutboundByteHandlerAdapter
@Override @Override
public void freeOutboundBuffer(ChannelHandlerContext ctx) throws Exception { public void freeOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
ctx.outboundByteBuffer().free(); ctx.outboundByteBuffer().release();
} }
/** /**

View File

@ -64,7 +64,7 @@ public abstract class ChannelOutboundMessageHandlerAdapter<I>
@Override @Override
public void freeOutboundBuffer(ChannelHandlerContext ctx) throws Exception { public void freeOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
ctx.outboundMessageBuffer().free(); ctx.outboundMessageBuffer().release();
} }
/** /**
@ -179,6 +179,6 @@ public abstract class ChannelOutboundMessageHandlerAdapter<I>
* just pass-through the input message or need it for later usage. * just pass-through the input message or need it for later usage.
*/ */
protected void freeOutboundMessage(I msg) throws Exception { protected void freeOutboundMessage(I msg) throws Exception {
BufUtil.free(msg); BufUtil.release(msg);
} }
} }

View File

@ -1695,7 +1695,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
try { try {
out.writeBytes(data); out.writeBytes(data);
} finally { } finally {
data.free(); data.release();
} }
} }
} }

View File

@ -17,8 +17,8 @@ package io.netty.channel;
import io.netty.buffer.Buf; import io.netty.buffer.Buf;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Freeable;
import io.netty.buffer.MessageBuf; import io.netty.buffer.MessageBuf;
import io.netty.buffer.ReferenceCounted;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.Channel.Unsafe; import io.netty.channel.Channel.Unsafe;
import io.netty.logging.InternalLogger; import io.netty.logging.InternalLogger;
@ -1125,8 +1125,8 @@ final class DefaultChannelPipeline implements ChannelPipeline {
@Override @Override
public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception { public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception {
byteSink.free(); byteSink.release();
msgSink.free(); msgSink.release();
} }
@Override @Override
@ -1148,8 +1148,8 @@ final class DefaultChannelPipeline implements ChannelPipeline {
break; break;
} }
if (m instanceof Freeable) { if (m instanceof ReferenceCounted) {
((Freeable) m).free(); ((ReferenceCounted) m).release();
} }
} }
logger.warn( logger.warn(
@ -1262,8 +1262,8 @@ final class DefaultChannelPipeline implements ChannelPipeline {
@Override @Override
public final void freeOutboundBuffer(ChannelHandlerContext ctx) throws Exception { public final void freeOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
msgSink.free(); msgSink.release();
byteSink.free(); byteSink.release();
} }
} }
@ -1290,8 +1290,8 @@ final class DefaultChannelPipeline implements ChannelPipeline {
discardedMessages ++; discardedMessages ++;
} }
if (m instanceof Freeable) { if (m instanceof ReferenceCounted) {
((Freeable) m).free(); ((ReferenceCounted) m).release();
} }
} }

View File

@ -57,7 +57,7 @@ public final class DatagramPacket extends DefaultByteBufHolder {
@Override @Override
public String toString() { public String toString() {
if (isFreed()) { if (refCnt() <= 0) {
return "DatagramPacket{remoteAddress=" + remoteAddress().toString() + return "DatagramPacket{remoteAddress=" + remoteAddress().toString() +
", data=(FREED)}"; ", data=(FREED)}";
} }

View File

@ -254,7 +254,7 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne
try { try {
if (buf.isReadable()) { if (buf.isReadable()) {
for (;;) { for (;;) {
if (buf.isFreed()) { if (buf.refCnt() <= 0) {
break; break;
} }
// Ensure the readerIndex of the buffer is 0 before beginning an async write. // Ensure the readerIndex of the buffer is 0 before beginning an async write.
@ -370,7 +370,7 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne
channel.writeInProgress = false; channel.writeInProgress = false;
ByteBuf buf = channel.unsafe().directOutboundContext().outboundByteBuffer(); ByteBuf buf = channel.unsafe().directOutboundContext().outboundByteBuffer();
if (buf.isFreed()) { if (buf.refCnt() <= 0) {
return; return;
} }

View File

@ -217,7 +217,7 @@ public final class NioDatagramChannel
throw new ChannelException(cause); throw new ChannelException(cause);
} finally { } finally {
if (free) { if (free) {
buffer.free(); buffer.release();
} }
} }
} }
@ -258,7 +258,7 @@ public final class NioDatagramChannel
buf.remove(); buf.remove();
// packet was written free up buffer // packet was written free up buffer
packet.free(); packet.release();
if (buf.isEmpty()) { if (buf.isEmpty()) {
// Wrote the outbound buffer completely - clear OP_WRITE. // Wrote the outbound buffer completely - clear OP_WRITE.

View File

@ -22,11 +22,11 @@ import io.netty.channel.ChannelException;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelMetadata;
import io.netty.channel.ChannelPromise; import io.netty.channel.ChannelPromise;
import io.netty.channel.oio.AbstractOioMessageChannel;
import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.DatagramChannelConfig; import io.netty.channel.socket.DatagramChannelConfig;
import io.netty.channel.socket.DatagramPacket; import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.DefaultDatagramChannelConfig; import io.netty.channel.socket.DefaultDatagramChannelConfig;
import io.netty.channel.oio.AbstractOioMessageChannel;
import io.netty.logging.InternalLogger; import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory; import io.netty.logging.InternalLoggerFactory;
@ -230,7 +230,7 @@ public class OioDatagramChannel extends AbstractOioMessageChannel
throw new ChannelException(cause); throw new ChannelException(cause);
} finally { } finally {
if (free) { if (free) {
buffer.free(); buffer.release();
} }
} }
} }
@ -255,7 +255,7 @@ public class OioDatagramChannel extends AbstractOioMessageChannel
} }
socket.send(tmpPacket); socket.send(tmpPacket);
} finally { } finally {
p.free(); p.release();
} }
} }

View File

@ -17,7 +17,7 @@ package io.netty.channel;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Freeable; import io.netty.buffer.ReferenceCounted;
import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.local.LocalChannel; import io.netty.channel.local.LocalChannel;
import io.netty.channel.local.LocalEventLoopGroup; import io.netty.channel.local.LocalEventLoopGroup;
@ -121,15 +121,35 @@ public class DefaultChannelPipelineTest {
public void testFreeCalled() throws InterruptedException{ public void testFreeCalled() throws InterruptedException{
final CountDownLatch free = new CountDownLatch(1); final CountDownLatch free = new CountDownLatch(1);
final Freeable holder = new Freeable() { final ReferenceCounted holder = new ReferenceCounted() {
@Override @Override
public void free() { public int refCnt() {
free.countDown(); return (int) free.getCount();
} }
@Override @Override
public boolean isFreed() { public void retain() {
return free.getCount() == 0; fail();
}
@Override
public void retain(int increment) {
fail();
}
@Override
public boolean release() {
assertEquals(1, refCnt());
free.countDown();
return true;
}
@Override
public boolean release(int decrement) {
for (int i = 0; i < decrement; i ++) {
release();
}
return true;
} }
}; };
LocalChannel channel = new LocalChannel(); LocalChannel channel = new LocalChannel();

View File

@ -424,7 +424,7 @@ public class LocalTransportThreadModelTest {
@Override @Override
public void freeOutboundBuffer(ChannelHandlerContext ctx) { public void freeOutboundBuffer(ChannelHandlerContext ctx) {
ctx.outboundByteBuffer().free(); ctx.outboundByteBuffer().release();
} }
@Override @Override
@ -523,7 +523,7 @@ public class LocalTransportThreadModelTest {
@Override @Override
public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception { public void freeInboundBuffer(ChannelHandlerContext ctx) throws Exception {
ctx.inboundByteBuffer().free(); ctx.inboundByteBuffer().release();
} }
@Override @Override