ByteBufAllocator API w/ ByteBuf perf improvements

This commit introduces a new API for ByteBuf allocation which fixes
issue #643 along with refactoring of ByteBuf for simplicity and better
performance. (see #62)

A user can configure the ByteBufAllocator of a Channel via
ChannelOption.ALLOCATOR or ChannelConfig.get/setAllocator().  The
default allocator is currently UnpooledByteBufAllocator.HEAP_BY_DEFAULT.

To allocate a buffer, do not use Unpooled anymore. do the following:

  ctx.alloc().buffer(...); // allocator chooses the buffer type.
  ctx.alloc().heapBuffer(...);
  ctx.alloc().directBuffer(...);

To deallocate a buffer, use the unsafe free() operation:

  ((UnsafeByteBuf) buf).free();

The following is the list of the relevant changes:

- Add ChannelInboundHandler.freeInboundBuffer() and
  ChannelOutboundHandler.freeOutboundBuffer() to let a user free the
  buffer he or she allocated. ChannelHandler adapter classes implement
  is already, so most users won't need to call free() by themselves.
  freeIn/OutboundBuffer() methods are invoked when a Channel is closed
  and deregistered.

- All ByteBuf by contract must implement UnsafeByteBuf. To access an
  unsafe operation: ((UnsafeByteBuf) buf).internalNioBuffer()

- Replace WrappedByteBuf and ByteBuf.Unsafe with UnsafeByteBuf to
  simplify overall class hierarchy and to avoid unnecesary instantiation
  of Unsafe instances on an unsafe operation.

- Remove buffer reference counting which is confusing

- Instantiate SwappedByteBuf lazily to avoid instantiation cost

- Rename ChannelFutureFactory to ChannelPropertyAccess and move common
  methods between Channel and ChannelHandlerContext there. Also made it
  package-private to hide it from a user.

- Remove unused unsafe operations such as newBuffer()

- Add DetectionUtil.canFreeDirectBuffer() so that an allocator decides
  which buffer type to use safely
This commit is contained in:
Trustin Lee 2012-11-16 06:04:37 +09:00
parent 2adebc4c54
commit 81e2db10fa
59 changed files with 1459 additions and 1240 deletions

View File

@ -28,36 +28,24 @@ import java.nio.charset.Charset;
/** /**
* A skeletal implementation of a buffer. * A skeletal implementation of a buffer.
*/ */
public abstract class AbstractByteBuf implements ByteBuf { public abstract class AbstractByteBuf implements UnsafeByteBuf {
private final SwappedByteBuf swappedBuf;
private final ByteOrder order;
private final int maxCapacity;
private int readerIndex; private int readerIndex;
private int writerIndex; private int writerIndex;
private int markedReaderIndex; private int markedReaderIndex;
private int markedWriterIndex; private int markedWriterIndex;
int refCnt = 1; private final int maxCapacity;
protected AbstractByteBuf(ByteOrder endianness, int maxCapacity) { private SwappedByteBuf swappedBuf;
if (endianness == null) {
throw new NullPointerException("endianness"); protected AbstractByteBuf(int maxCapacity) {
}
if (maxCapacity < 0) { if (maxCapacity < 0) {
throw new IllegalArgumentException("maxCapacity: " + maxCapacity + " (expected: >= 0)"); throw new IllegalArgumentException("maxCapacity: " + maxCapacity + " (expected: >= 0)");
} }
order = endianness;
swappedBuf = new SwappedByteBuf(this);
this.maxCapacity = maxCapacity; this.maxCapacity = maxCapacity;
} }
@Override
public boolean isPooled() {
return false;
}
@Override @Override
public ChannelBufType type() { public ChannelBufType type() {
return ChannelBufType.BYTE; return ChannelBufType.BYTE;
@ -266,19 +254,19 @@ public abstract class AbstractByteBuf implements ByteBuf {
return Math.min(newCapacity, maxCapacity); return Math.min(newCapacity, maxCapacity);
} }
@Override
public final ByteOrder order() {
return order;
}
@Override @Override
public ByteBuf order(ByteOrder endianness) { public ByteBuf order(ByteOrder endianness) {
if (endianness == null) { if (endianness == null) {
throw new NullPointerException("endianness"); throw new NullPointerException("endianness");
} }
if (endianness == order()) { if (endianness == order() || capacity() == 0) {
return this; return this;
} }
SwappedByteBuf swappedBuf = this.swappedBuf;
if (swappedBuf == null) {
this.swappedBuf = swappedBuf = new SwappedByteBuf(this);
}
return swappedBuf; return swappedBuf;
} }
@ -521,7 +509,9 @@ public abstract class AbstractByteBuf implements ByteBuf {
if (length == 0) { if (length == 0) {
return Unpooled.EMPTY_BUFFER; return Unpooled.EMPTY_BUFFER;
} }
ByteBuf buf = unsafe().newBuffer(length);
// Use an unpooled heap buffer because there's no way to mandate a user to free the returned buffer.
ByteBuf buf = Unpooled.buffer(length, maxCapacity);
buf.writeBytes(this, readerIndex, length); buf.writeBytes(this, readerIndex, length);
readerIndex += length; readerIndex += length;
return buf; return buf;

View File

@ -0,0 +1,89 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.buffer;
public abstract class AbstractByteBufAllocator implements ByteBufAllocator {
private final boolean directByDefault;
private final ByteBuf emptyBuf;
protected AbstractByteBufAllocator() {
this(false);
}
protected AbstractByteBufAllocator(boolean directByDefault) {
this.directByDefault = directByDefault;
emptyBuf = new UnpooledHeapByteBuf(this, 0, 0);
}
@Override
public ByteBuf buffer() {
if (directByDefault) {
return directBuffer();
}
return heapBuffer();
}
@Override
public ByteBuf buffer(int initialCapacity) {
if (directByDefault) {
return directBuffer(initialCapacity);
}
return heapBuffer(initialCapacity);
}
@Override
public ByteBuf buffer(int initialCapacity, int maxCapacity) {
if (directByDefault) {
return directBuffer(initialCapacity, maxCapacity);
}
return heapBuffer(initialCapacity, maxCapacity);
}
public ByteBuf heapBuffer() {
return heapBuffer(256, Integer.MAX_VALUE);
}
public ByteBuf heapBuffer(int initialCapacity) {
return buffer(initialCapacity, Integer.MAX_VALUE);
}
public ByteBuf heapBuffer(int initialCapacity, int maxCapacity) {
if (initialCapacity == 0 && maxCapacity == 0) {
return emptyBuf;
}
return newHeapBuffer(initialCapacity, maxCapacity);
}
public ByteBuf directBuffer() {
return directBuffer(256, Integer.MAX_VALUE);
}
public ByteBuf directBuffer(int initialCapacity) {
return directBuffer(initialCapacity, Integer.MAX_VALUE);
}
public ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
if (initialCapacity == 0 && maxCapacity == 0) {
return emptyBuf;
}
return newDirectBuffer(initialCapacity, maxCapacity);
}
protected abstract ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity);
protected abstract ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity);
}

View File

@ -1,263 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.buffer;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Abstract base class for WrappedByteBuf implementations.
*/
public abstract class AbstractWrappedByteBuf extends AbstractByteBuf implements WrappedByteBuf {
protected AbstractWrappedByteBuf(ByteOrder endianness, int maxCapacity) {
super(endianness, maxCapacity);
}
@Override
public WrappedByteBuf capacity(int newCapacity) {
throw new UnsupportedOperationException();
}
@Override
public WrappedByteBuf discardReadBytes() {
return (WrappedByteBuf) super.discardReadBytes();
}
@Override
public WrappedByteBuf readerIndex(int readerIndex) {
return (WrappedByteBuf) super.readerIndex(readerIndex);
}
@Override
public WrappedByteBuf writerIndex(int writerIndex) {
return (WrappedByteBuf) super.writerIndex(writerIndex);
}
@Override
public WrappedByteBuf setIndex(int readerIndex, int writerIndex) {
return (WrappedByteBuf) super.setIndex(readerIndex, writerIndex);
}
@Override
public WrappedByteBuf clear() {
return (WrappedByteBuf) super.clear();
}
@Override
public WrappedByteBuf markReaderIndex() {
return (WrappedByteBuf) super.markReaderIndex();
}
@Override
public WrappedByteBuf resetReaderIndex() {
return (WrappedByteBuf) super.resetReaderIndex();
}
@Override
public WrappedByteBuf markWriterIndex() {
return (WrappedByteBuf) super.markWriterIndex();
}
@Override
public WrappedByteBuf resetWriterIndex() {
return (WrappedByteBuf) super.resetWriterIndex();
}
@Override
public WrappedByteBuf ensureWritableBytes(int minWritableBytes) {
return (WrappedByteBuf) super.ensureWritableBytes(minWritableBytes);
}
@Override
public WrappedByteBuf getBytes(int index, ByteBuf dst) {
return (WrappedByteBuf) super.getBytes(index, dst);
}
@Override
public WrappedByteBuf getBytes(int index, ByteBuf dst, int length) {
return (WrappedByteBuf) super.getBytes(index, dst, length);
}
@Override
public WrappedByteBuf getBytes(int index, byte[] dst) {
return (WrappedByteBuf) super.getBytes(index, dst);
}
@Override
public WrappedByteBuf setBoolean(int index, boolean value) {
return (WrappedByteBuf) super.setBoolean(index, value);
}
@Override
public WrappedByteBuf setChar(int index, int value) {
return (WrappedByteBuf) super.setChar(index, value);
}
@Override
public WrappedByteBuf setFloat(int index, float value) {
return (WrappedByteBuf) super.setFloat(index, value);
}
@Override
public WrappedByteBuf setDouble(int index, double value) {
return (WrappedByteBuf) super.setDouble(index, value);
}
@Override
public WrappedByteBuf setBytes(int index, ByteBuf src) {
return (WrappedByteBuf) super.setBytes(index, src);
}
@Override
public WrappedByteBuf setBytes(int index, ByteBuf src, int length) {
return (WrappedByteBuf) super.setBytes(index, src, length);
}
@Override
public WrappedByteBuf setBytes(int index, byte[] src) {
return (WrappedByteBuf) super.setBytes(index, src);
}
@Override
public WrappedByteBuf setZero(int index, int length) {
return (WrappedByteBuf) super.setZero(index, length);
}
@Override
public WrappedByteBuf readBytes(ByteBuf dst) {
return (WrappedByteBuf) super.readBytes(dst);
}
@Override
public WrappedByteBuf readBytes(ByteBuf dst, int length) {
return (WrappedByteBuf) super.readBytes(dst, length);
}
@Override
public WrappedByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
return (WrappedByteBuf) super.readBytes(dst, dstIndex, length);
}
@Override
public WrappedByteBuf readBytes(byte[] dst) {
return (WrappedByteBuf) super.readBytes(dst);
}
@Override
public WrappedByteBuf readBytes(byte[] dst, int dstIndex, int length) {
return (WrappedByteBuf) super.readBytes(dst, dstIndex, length);
}
@Override
public WrappedByteBuf readBytes(ByteBuffer dst) {
return (WrappedByteBuf) super.readBytes(dst);
}
@Override
public WrappedByteBuf readBytes(OutputStream out, int length) throws IOException {
return (WrappedByteBuf) super.readBytes(out, length);
}
@Override
public WrappedByteBuf skipBytes(int length) {
return (WrappedByteBuf) super.skipBytes(length);
}
@Override
public WrappedByteBuf writeBoolean(boolean value) {
return (WrappedByteBuf) super.writeBoolean(value);
}
@Override
public WrappedByteBuf writeByte(int value) {
return (WrappedByteBuf) super.writeByte(value);
}
@Override
public WrappedByteBuf writeShort(int value) {
return (WrappedByteBuf) super.writeShort(value);
}
@Override
public WrappedByteBuf writeMedium(int value) {
return (WrappedByteBuf) super.writeMedium(value);
}
@Override
public WrappedByteBuf writeInt(int value) {
return (WrappedByteBuf) super.writeInt(value);
}
@Override
public WrappedByteBuf writeLong(long value) {
return (WrappedByteBuf) super.writeLong(value);
}
@Override
public WrappedByteBuf writeChar(int value) {
return (WrappedByteBuf) super.writeChar(value);
}
@Override
public WrappedByteBuf writeFloat(float value) {
return (WrappedByteBuf) super.writeFloat(value);
}
@Override
public WrappedByteBuf writeDouble(double value) {
return (WrappedByteBuf) super.writeDouble(value);
}
@Override
public WrappedByteBuf writeBytes(ByteBuf src) {
return (WrappedByteBuf) super.writeBytes(src);
}
@Override
public WrappedByteBuf writeBytes(ByteBuf src, int length) {
return (WrappedByteBuf) super.writeBytes(src, length);
}
@Override
public WrappedByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
return (WrappedByteBuf) super.writeBytes(src, srcIndex, length);
}
@Override
public WrappedByteBuf writeBytes(byte[] src) {
return (WrappedByteBuf) super.writeBytes(src);
}
@Override
public WrappedByteBuf writeBytes(byte[] src, int srcIndex, int length) {
return (WrappedByteBuf) super.writeBytes(src, srcIndex, length);
}
@Override
public WrappedByteBuf writeBytes(ByteBuffer src) {
return (WrappedByteBuf) super.writeBytes(src);
}
@Override
public WrappedByteBuf writeZero(int length) {
return (WrappedByteBuf) super.writeZero(length);
}
}

View File

@ -251,6 +251,11 @@ public interface ByteBuf extends ChannelBuf, Comparable<ByteBuf> {
*/ */
int maxCapacity(); int maxCapacity();
/**
* Returns the {@link ByteBufAllocator} which created this buffer.
*/
ByteBufAllocator alloc();
/** /**
* Returns the <a href="http://en.wikipedia.org/wiki/Endianness">endianness</a> * Returns the <a href="http://en.wikipedia.org/wiki/Endianness">endianness</a>
* of this buffer. * of this buffer.
@ -1831,53 +1836,4 @@ public interface ByteBuf extends ChannelBuf, Comparable<ByteBuf> {
*/ */
@Override @Override
String toString(); String toString();
/**
* Returns an object that exposes unsafe expert-only operations which can lead to unspecified
* behavior.
*/
Unsafe unsafe();
interface Unsafe {
/**
* Returns the internal NIO buffer that is reused for I/O.
*
* @throws UnsupportedOperationException if the buffer has no internal NIO buffer
*/
ByteBuffer nioBuffer();
/**
* Returns the internal NIO buffer array that is reused for I/O.
*
* @throws UnsupportedOperationException if the buffer has no internal NIO buffer array
*/
ByteBuffer[] nioBuffers();
/**
* Returns a new buffer whose type is identical to the callee.
*
* @param initialCapacity the initial capacity of the new buffer
*/
ByteBuf newBuffer(int initialCapacity);
/**
* Similar to {@link ByteBuf#discardReadBytes()} except that this method might discard
* some, all, or none of read bytes depending on its internal implementation to reduce
* overall memory bandwidth consumption at the cost of potentially additional memory
* consumption.
*/
void discardSomeReadBytes();
/**
* Increases the reference count of the buffer.
*/
void acquire();
/**
* Decreases the reference count of the buffer. If decreased to 0, the internal memory
* block of the buffer will be deallocated. The result of accessing a freed buffer is
* unspecified and can even cause JVM crash.
*/
void release();
}
} }

View File

@ -0,0 +1,37 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.buffer;
import java.util.concurrent.TimeUnit;
public interface ByteBufAllocator {
ByteBuf buffer();
ByteBuf buffer(int initialCapacity);
ByteBuf buffer(int initialCapacity, int maxCapacity);
ByteBuf heapBuffer();
ByteBuf heapBuffer(int initialCapacity);
ByteBuf heapBuffer(int initialCapacity, int maxCapacity);
ByteBuf directBuffer();
ByteBuf directBuffer(int initialCapacity);
ByteBuf directBuffer(int initialCapacity, int maxCapacity);
ByteBuf ioBuffer();
void shutdown();
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
}

View File

@ -20,10 +20,4 @@ public interface ChannelBuf {
* The ChannelBufType which will be handled by the ChannelBuf implementation * The ChannelBufType which will be handled by the ChannelBuf implementation
*/ */
ChannelBufType type(); ChannelBufType type();
/**
* Return {@code true} if the ChannelBuf is pooled.
*
*/
boolean isPooled();
} }

View File

@ -39,26 +39,36 @@ import java.util.ListIterator;
*/ */
public class DefaultCompositeByteBuf extends AbstractByteBuf implements CompositeByteBuf { public class DefaultCompositeByteBuf extends AbstractByteBuf implements CompositeByteBuf {
private static final ByteBuffer[] EMPTY_NIOBUFFERS = new ByteBuffer[0];
private final ByteBufAllocator alloc;
private final List<Component> components = new ArrayList<Component>(); private final List<Component> components = new ArrayList<Component>();
private final int maxNumComponents; private final int maxNumComponents;
private final Unsafe unsafe = new CompositeUnsafe();
private Component lastAccessed; private Component lastAccessed;
private int lastAccessedId; private int lastAccessedId;
private boolean freed;
public DefaultCompositeByteBuf(int maxNumComponents) { public DefaultCompositeByteBuf(ByteBufAllocator alloc, int maxNumComponents) {
super(ByteOrder.BIG_ENDIAN, Integer.MAX_VALUE); super(Integer.MAX_VALUE);
if (alloc == null) {
throw new NullPointerException("alloc");
}
this.alloc = alloc;
this.maxNumComponents = maxNumComponents; this.maxNumComponents = maxNumComponents;
} }
public DefaultCompositeByteBuf(int maxNumComponents, ByteBuf... buffers) { public DefaultCompositeByteBuf(ByteBufAllocator alloc, int maxNumComponents, ByteBuf... buffers) {
super(ByteOrder.BIG_ENDIAN, Integer.MAX_VALUE); super(Integer.MAX_VALUE);
if (alloc == null) {
throw new NullPointerException("alloc");
}
if (maxNumComponents < 2) { if (maxNumComponents < 2) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"maxNumComponents: " + maxNumComponents + " (expected: >= 2)"); "maxNumComponents: " + maxNumComponents + " (expected: >= 2)");
} }
this.alloc = alloc;
this.maxNumComponents = maxNumComponents; this.maxNumComponents = maxNumComponents;
addComponents0(0, buffers); addComponents0(0, buffers);
@ -66,14 +76,17 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
setIndex(0, capacity()); setIndex(0, capacity());
} }
public DefaultCompositeByteBuf(int maxNumComponents, Iterable<ByteBuf> buffers) { public DefaultCompositeByteBuf(ByteBufAllocator alloc, int maxNumComponents, Iterable<ByteBuf> buffers) {
super(ByteOrder.BIG_ENDIAN, Integer.MAX_VALUE); super(Integer.MAX_VALUE);
if (alloc == null) {
throw new NullPointerException("alloc");
}
if (maxNumComponents < 2) { if (maxNumComponents < 2) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"maxNumComponents: " + maxNumComponents + " (expected: >= 2)"); "maxNumComponents: " + maxNumComponents + " (expected: >= 2)");
} }
this.alloc = alloc;
this.maxNumComponents = maxNumComponents; this.maxNumComponents = maxNumComponents;
addComponents0(0, buffers); addComponents0(0, buffers);
consolidateIfNeeded(); consolidateIfNeeded();
@ -83,7 +96,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
@Override @Override
public CompositeByteBuf addComponent(ByteBuf buffer) { public CompositeByteBuf addComponent(ByteBuf buffer) {
addComponent0(components.size(), buffer); addComponent0(components.size(), buffer, false);
consolidateIfNeeded(); consolidateIfNeeded();
return this; return this;
} }
@ -104,12 +117,12 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
@Override @Override
public CompositeByteBuf addComponent(int cIndex, ByteBuf buffer) { public CompositeByteBuf addComponent(int cIndex, ByteBuf buffer) {
addComponent0(cIndex, buffer); addComponent0(cIndex, buffer, false);
consolidateIfNeeded(); consolidateIfNeeded();
return this; return this;
} }
private int addComponent0(int cIndex, ByteBuf buffer) { private int addComponent0(int cIndex, ByteBuf buffer, boolean addedBySelf) {
checkComponentIndex(cIndex); checkComponentIndex(cIndex);
if (buffer == null) { if (buffer == null) {
@ -128,7 +141,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
} }
// No need to consolidate - just add a component to the list. // No need to consolidate - just add a component to the list.
Component c = new Component(buffer.order(ByteOrder.BIG_ENDIAN).slice()); Component c = new Component(buffer.order(ByteOrder.BIG_ENDIAN).slice(), addedBySelf);
if (cIndex == components.size()) { if (cIndex == components.size()) {
components.add(c); components.add(c);
if (cIndex == 0) { if (cIndex == 0) {
@ -177,7 +190,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
break; break;
} }
if (b.readable()) { if (b.readable()) {
cIndex = addComponent0(cIndex, b) + 1; cIndex = addComponent0(cIndex, b, false) + 1;
int size = components.size(); int size = components.size();
if (cIndex > size) { if (cIndex > size) {
cIndex = size; cIndex = size;
@ -246,16 +259,17 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
if (numComponents > maxNumComponents) { if (numComponents > maxNumComponents) {
final int capacity = components.get(numComponents - 1).endOffset; final int capacity = components.get(numComponents - 1).endOffset;
ByteBuf consolidated = components.get(numComponents - 1).buf.unsafe().newBuffer(capacity); ByteBuf consolidated = alloc().buffer(capacity);
// We're not using foreach to avoid creating an iterator. // We're not using foreach to avoid creating an iterator.
// noinspection ForLoopReplaceableByForEach // noinspection ForLoopReplaceableByForEach
for (int i = 0; i < numComponents; i ++) { for (int i = 0; i < numComponents; i ++) {
ByteBuf b = components.get(i).buf; Component c = components.get(i);
UnsafeByteBuf b = c.buf;
consolidated.writeBytes(b); consolidated.writeBytes(b);
b.unsafe().release(); c.freeIfNecessary();
} }
Component c = new Component(consolidated); Component c = new Component(consolidated, true);
c.endOffset = c.length; c.endOffset = c.length;
components.clear(); components.clear();
components.add(c); components.add(c);
@ -263,6 +277,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
} }
private void checkComponentIndex(int cIndex) { private void checkComponentIndex(int cIndex) {
assert !freed;
if (cIndex < 0 || cIndex > components.size()) { if (cIndex < 0 || cIndex > components.size()) {
throw new IndexOutOfBoundsException(String.format( throw new IndexOutOfBoundsException(String.format(
"cIndex: %d (expected: >= 0 && <= numComponents(%d))", "cIndex: %d (expected: >= 0 && <= numComponents(%d))",
@ -271,6 +286,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
} }
private void checkComponentIndex(int cIndex, int numComponents) { private void checkComponentIndex(int cIndex, int numComponents) {
assert !freed;
if (cIndex < 0 || cIndex + numComponents > components.size()) { if (cIndex < 0 || cIndex + numComponents > components.size()) {
throw new IndexOutOfBoundsException(String.format( throw new IndexOutOfBoundsException(String.format(
"cIndex: %d, numComponents: %d " + "cIndex: %d, numComponents: %d " +
@ -317,6 +333,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
@Override @Override
public Iterator<ByteBuf> iterator() { public Iterator<ByteBuf> iterator() {
assert !freed;
List<ByteBuf> list = new ArrayList<ByteBuf>(components.size()); List<ByteBuf> list = new ArrayList<ByteBuf>(components.size());
for (Component c: components) { for (Component c: components) {
list.add(c.buf); list.add(c.buf);
@ -413,6 +430,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
@Override @Override
public CompositeByteBuf capacity(int newCapacity) { public CompositeByteBuf capacity(int newCapacity) {
assert !freed;
if (newCapacity < 0 || newCapacity > maxCapacity()) { if (newCapacity < 0 || newCapacity > maxCapacity()) {
throw new IllegalArgumentException("newCapacity: " + newCapacity); throw new IllegalArgumentException("newCapacity: " + newCapacity);
} }
@ -422,13 +440,15 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
final int paddingLength = newCapacity - oldCapacity; final int paddingLength = newCapacity - oldCapacity;
ByteBuf padding; ByteBuf padding;
if (components.isEmpty()) { if (components.isEmpty()) {
padding = new HeapByteBuf(paddingLength, paddingLength); padding = alloc().buffer(paddingLength, paddingLength);
padding.setIndex(0, paddingLength);
addComponent0(0, padding, true);
} else { } else {
Component last = components.get(components.size() - 1); padding = alloc().buffer(paddingLength);
padding = last.buf.unsafe().newBuffer(paddingLength); padding.setIndex(0, paddingLength);
addComponent0(components.size(), padding, true);
consolidateIfNeeded();
} }
padding.setIndex(0, paddingLength);
addComponent(padding);
} else if (newCapacity < oldCapacity) { } else if (newCapacity < oldCapacity) {
int bytesToTrim = oldCapacity - newCapacity; int bytesToTrim = oldCapacity - newCapacity;
for (ListIterator<Component> i = components.listIterator(components.size()); i.hasPrevious();) { for (ListIterator<Component> i = components.listIterator(components.size()); i.hasPrevious();) {
@ -440,10 +460,9 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
} }
// Replace the last component with the trimmed slice. // Replace the last component with the trimmed slice.
Component newC = new Component(c.buf.slice(0, c.length - bytesToTrim)); Component newC = new Component(c.buf.slice(0, c.length - bytesToTrim), c.allocatedBySelf);
newC.offset = c.offset; newC.offset = c.offset;
newC.endOffset = newC.offset + newC.length; newC.endOffset = newC.offset + newC.length;
c.buf.unsafe().release();
i.set(newC); i.set(newC);
break; break;
} }
@ -457,6 +476,16 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
return this; return this;
} }
@Override
public ByteBufAllocator alloc() {
return alloc;
}
@Override
public ByteOrder order() {
return ByteOrder.BIG_ENDIAN;
}
@Override @Override
public int numComponents() { public int numComponents() {
return components.size(); return components.size();
@ -469,6 +498,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
@Override @Override
public int toComponentIndex(int offset) { public int toComponentIndex(int offset) {
assert !freed;
if (offset < 0 || offset >= capacity()) { if (offset < 0 || offset >= capacity()) {
throw new IndexOutOfBoundsException(String.format( throw new IndexOutOfBoundsException(String.format(
"offset: %d (expected: >= 0 && < capacity(%d))", offset, capacity())); "offset: %d (expected: >= 0 && < capacity(%d))", offset, capacity()));
@ -941,7 +971,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
+ (index + length) + ", maximum is " + capacity()); + (index + length) + ", maximum is " + capacity());
} }
ByteBuf dst = unsafe().newBuffer(length); ByteBuf dst = Unpooled.buffer(length);
copyTo(index, length, componentId, dst); copyTo(index, length, componentId, dst);
return dst; return dst;
} }
@ -977,6 +1007,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
} }
private Component findComponent(int offset) { private Component findComponent(int offset) {
assert !freed;
if (offset < 0 || offset >= capacity()) { if (offset < 0 || offset >= capacity()) {
throw new IndexOutOfBoundsException(String.format( throw new IndexOutOfBoundsException(String.format(
"offset: %d (expected: >= 0 && < capacity(%d))", offset, capacity())); "offset: %d (expected: >= 0 && < capacity(%d))", offset, capacity()));
@ -1033,6 +1064,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
} }
private ByteBuffer copiedNioBuffer(int index, int length) { private ByteBuffer copiedNioBuffer(int index, int length) {
assert !freed;
if (components.size() == 1) { if (components.size() == 1) {
return toNioBuffer(components.get(0).buf, index, length); return toNioBuffer(components.get(0).buf, index, length);
} }
@ -1061,7 +1093,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
throw new IndexOutOfBoundsException("index must be >= 0"); throw new IndexOutOfBoundsException("index must be >= 0");
} }
if (length == 0) { if (length == 0) {
return new ByteBuffer[0]; return EMPTY_NIOBUFFERS;
} }
int componentId = toComponentIndex(index); int componentId = toComponentIndex(index);
@ -1092,6 +1124,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
@Override @Override
public CompositeByteBuf consolidate() { public CompositeByteBuf consolidate() {
assert !freed;
final int numComponents = numComponents(); final int numComponents = numComponents();
if (numComponents <= 1) { if (numComponents <= 1) {
return this; return this;
@ -1099,16 +1132,17 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
final Component last = components.get(numComponents - 1); final Component last = components.get(numComponents - 1);
final int capacity = last.endOffset; final int capacity = last.endOffset;
final ByteBuf consolidated = last.buf.unsafe().newBuffer(capacity); final ByteBuf consolidated = alloc().buffer(capacity);
for (int i = 0; i < numComponents; i ++) { for (int i = 0; i < numComponents; i ++) {
ByteBuf b = components.get(i).buf; Component c = components.get(i);
UnsafeByteBuf b = c.buf;
consolidated.writeBytes(b); consolidated.writeBytes(b);
b.unsafe().release(); c.freeIfNecessary();
} }
components.clear(); components.clear();
components.add(new Component(consolidated)); components.add(new Component(consolidated, true));
updateComponentOffsets(0); updateComponentOffsets(0);
return this; return this;
} }
@ -1123,22 +1157,24 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
final int endCIndex = cIndex + numComponents; final int endCIndex = cIndex + numComponents;
final Component last = components.get(endCIndex - 1); final Component last = components.get(endCIndex - 1);
final int capacity = last.endOffset - components.get(cIndex).offset; final int capacity = last.endOffset - components.get(cIndex).offset;
final ByteBuf consolidated = last.buf.unsafe().newBuffer(capacity); final ByteBuf consolidated = alloc().buffer(capacity);
for (int i = cIndex; i < endCIndex; i ++) { for (int i = cIndex; i < endCIndex; i ++) {
ByteBuf b = components.get(i).buf; Component c = components.get(i);
ByteBuf b = c.buf;
consolidated.writeBytes(b); consolidated.writeBytes(b);
b.unsafe().release(); c.freeIfNecessary();
} }
components.subList(cIndex + 1, endCIndex).clear(); components.subList(cIndex + 1, endCIndex).clear();
components.set(cIndex, new Component(consolidated)); components.set(cIndex, new Component(consolidated, true));
updateComponentOffsets(cIndex); updateComponentOffsets(cIndex);
return this; return this;
} }
@Override @Override
public CompositeByteBuf discardReadComponents() { public CompositeByteBuf discardReadComponents() {
assert !freed;
final int readerIndex = readerIndex(); final int readerIndex = readerIndex();
if (readerIndex == 0) { if (readerIndex == 0) {
return this; return this;
@ -1148,7 +1184,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
int writerIndex = writerIndex(); int writerIndex = writerIndex();
if (readerIndex == writerIndex && writerIndex == capacity()) { if (readerIndex == writerIndex && writerIndex == capacity()) {
for (Component c: components) { for (Component c: components) {
c.buf.unsafe().release(); c.freeIfNecessary();
} }
components.clear(); components.clear();
setIndex(0, 0); setIndex(0, 0);
@ -1159,7 +1195,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
// Remove read components. // Remove read components.
int firstComponentId = toComponentIndex(readerIndex); int firstComponentId = toComponentIndex(readerIndex);
for (int i = 0; i < firstComponentId; i ++) { for (int i = 0; i < firstComponentId; i ++) {
components.get(i).buf.unsafe().release(); components.get(i).freeIfNecessary();
} }
components.subList(0, firstComponentId).clear(); components.subList(0, firstComponentId).clear();
@ -1173,6 +1209,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
@Override @Override
public CompositeByteBuf discardReadBytes() { public CompositeByteBuf discardReadBytes() {
assert !freed;
final int readerIndex = readerIndex(); final int readerIndex = readerIndex();
if (readerIndex == 0) { if (readerIndex == 0) {
return this; return this;
@ -1182,7 +1219,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
int writerIndex = writerIndex(); int writerIndex = writerIndex();
if (readerIndex == writerIndex && writerIndex == capacity()) { if (readerIndex == writerIndex && writerIndex == capacity()) {
for (Component c: components) { for (Component c: components) {
c.buf.unsafe().release(); c.freeIfNecessary();
} }
components.clear(); components.clear();
setIndex(0, 0); setIndex(0, 0);
@ -1193,7 +1230,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
// Remove read components. // Remove read components.
int firstComponentId = toComponentIndex(readerIndex); int firstComponentId = toComponentIndex(readerIndex);
for (int i = 0; i < firstComponentId; i ++) { for (int i = 0; i < firstComponentId; i ++) {
components.get(i).buf.unsafe().release(); components.get(i).freeIfNecessary();
} }
components.subList(0, firstComponentId).clear(); components.subList(0, firstComponentId).clear();
@ -1204,8 +1241,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
// new slice would be empty, so remove instead // new slice would be empty, so remove instead
components.remove(0); components.remove(0);
} else { } else {
Component newC = new Component(c.buf.slice(adjustment, c.length - adjustment)); Component newC = new Component(c.buf.slice(adjustment, c.length - adjustment), c.allocatedBySelf);
c.buf.unsafe().release();
components.set(0, newC); components.set(0, newC);
} }
@ -1224,14 +1260,29 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
} }
private static final class Component { private static final class Component {
final ByteBuf buf; final UnsafeByteBuf buf;
final int length; final int length;
final boolean allocatedBySelf;
int offset; int offset;
int endOffset; int endOffset;
Component(ByteBuf buf) { Component(ByteBuf buf, boolean allocatedBySelf) {
this.buf = buf; this.buf = (UnsafeByteBuf) buf;
length = buf.readableBytes(); length = buf.readableBytes();
this.allocatedBySelf = allocatedBySelf;
}
void freeIfNecessary() {
if (!allocatedBySelf) {
return;
}
// Unwrap so that we can free slices, too.
UnsafeByteBuf buf;
for (buf = this.buf; buf.unwrap() != null; buf = (UnsafeByteBuf) buf.unwrap()) {
continue;
}
buf.free(); // We should not get a NPE here. If so, it must be a bug.
} }
} }
@ -1458,68 +1509,47 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
} }
@Override @Override
public Unsafe unsafe() { public ByteBuffer[] nioBuffers() {
return unsafe; return nioBuffers(readerIndex(), readableBytes());
} }
private final class CompositeUnsafe implements Unsafe { @Override
@Override public ByteBuffer internalNioBuffer() {
public ByteBuffer nioBuffer() { if (components.size() == 1) {
if (components.size() == 1) { return components.get(0).buf.internalNioBuffer();
return components.get(0).buf.unsafe().nioBuffer(); }
} throw new UnsupportedOperationException();
throw new UnsupportedOperationException(); }
@Override
public ByteBuffer[] internalNioBuffers() {
ByteBuffer[] nioBuffers = new ByteBuffer[components.size()];
int index = 0;
for (Component component : components) {
nioBuffers[index++] = component.buf.internalNioBuffer();
}
return nioBuffers;
}
@Override
public void discardSomeReadBytes() {
discardReadComponents();
}
@Override
public void free() {
if (freed) {
return;
} }
@Override freed = true;
public ByteBuffer[] nioBuffers() { for (Component c: components) {
ByteBuffer[] nioBuffers = new ByteBuffer[components.size()]; c.freeIfNecessary();
int index = 0;
for (Component component : components) {
nioBuffers[index++] = component.buf.unsafe().nioBuffer();
}
return nioBuffers;
}
@Override
public ByteBuf newBuffer(int initialCapacity) {
CompositeByteBuf buf = new DefaultCompositeByteBuf(maxNumComponents);
buf.addComponent(new HeapByteBuf(new byte[initialCapacity], initialCapacity));
return buf;
}
@Override
public void discardSomeReadBytes() {
discardReadComponents();
}
@Override
public void acquire() {
if (refCnt <= 0) {
throw new IllegalStateException();
}
refCnt ++;
}
@Override
public void release() {
if (refCnt <= 0) {
throw new IllegalStateException();
}
refCnt --;
if (refCnt == 0) {
for (Component c: components) {
c.buf.unsafe().release();
}
components.clear();
lastAccessed = null;
}
} }
} }
@Override @Override
public ByteBuffer[] nioBuffers() { public ByteBuf unwrap() {
return nioBuffers(readerIndex(), readableBytes()); return null;
} }
} }

View File

@ -32,11 +32,6 @@ public class DefaultMessageBuf<T> extends ArrayDeque<T> implements MessageBuf<T>
super(initialCapacity); super(initialCapacity);
} }
@Override
public boolean isPooled() {
return false;
}
@Override @Override
public ChannelBufType type() { public ChannelBufType type() {
return ChannelBufType.MESSAGE; return ChannelBufType.MESSAGE;

View File

@ -19,6 +19,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.GatheringByteChannel; import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel; import java.nio.channels.ScatteringByteChannel;
@ -28,13 +29,12 @@ 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 AbstractWrappedByteBuf { public class DuplicatedByteBuf extends AbstractByteBuf {
private final Unsafe unsafe = new DuplicatedUnsafe(); private final UnsafeByteBuf buffer;
final ByteBuf buffer;
public DuplicatedByteBuf(ByteBuf buffer) { public DuplicatedByteBuf(UnsafeByteBuf buffer) {
super(buffer.order(), buffer.maxCapacity()); super(buffer.maxCapacity());
if (buffer instanceof DuplicatedByteBuf) { if (buffer instanceof DuplicatedByteBuf) {
this.buffer = ((DuplicatedByteBuf) buffer).buffer; this.buffer = ((DuplicatedByteBuf) buffer).buffer;
@ -43,8 +43,6 @@ public class DuplicatedByteBuf extends AbstractWrappedByteBuf {
} }
setIndex(buffer.readerIndex(), buffer.writerIndex()); setIndex(buffer.readerIndex(), buffer.writerIndex());
buffer.unsafe().acquire();
} }
@Override @Override
@ -52,6 +50,16 @@ public class DuplicatedByteBuf extends AbstractWrappedByteBuf {
return buffer; return buffer;
} }
@Override
public ByteBufAllocator alloc() {
return buffer.alloc();
}
@Override
public ByteOrder order() {
return buffer.order();
}
@Override @Override
public boolean isDirect() { public boolean isDirect() {
return buffer.isDirect(); return buffer.isDirect();
@ -63,7 +71,7 @@ public class DuplicatedByteBuf extends AbstractWrappedByteBuf {
} }
@Override @Override
public WrappedByteBuf capacity(int newCapacity) { public ByteBuf capacity(int newCapacity) {
buffer.capacity(newCapacity); buffer.capacity(newCapacity);
return this; return this;
} }
@ -119,73 +127,73 @@ public class DuplicatedByteBuf extends AbstractWrappedByteBuf {
} }
@Override @Override
public WrappedByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
buffer.getBytes(index, dst, dstIndex, length); buffer.getBytes(index, dst, dstIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
buffer.getBytes(index, dst, dstIndex, length); buffer.getBytes(index, dst, dstIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf getBytes(int index, ByteBuffer dst) { public ByteBuf getBytes(int index, ByteBuffer dst) {
buffer.getBytes(index, dst); buffer.getBytes(index, dst);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setByte(int index, int value) { public ByteBuf setByte(int index, int value) {
buffer.setByte(index, value); buffer.setByte(index, value);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setShort(int index, int value) { public ByteBuf setShort(int index, int value) {
buffer.setShort(index, value); buffer.setShort(index, value);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setMedium(int index, int value) { public ByteBuf setMedium(int index, int value) {
buffer.setMedium(index, value); buffer.setMedium(index, value);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setInt(int index, int value) { public ByteBuf setInt(int index, int value) {
buffer.setInt(index, value); buffer.setInt(index, value);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setLong(int index, long value) { public ByteBuf setLong(int index, long value) {
buffer.setLong(index, value); buffer.setLong(index, value);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
buffer.setBytes(index, src, srcIndex, length); buffer.setBytes(index, src, srcIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
buffer.setBytes(index, src, srcIndex, length); buffer.setBytes(index, src, srcIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setBytes(int index, ByteBuffer src) { public ByteBuf setBytes(int index, ByteBuffer src) {
buffer.setBytes(index, src); buffer.setBytes(index, src);
return this; return this;
} }
@Override @Override
public WrappedByteBuf getBytes(int index, OutputStream out, int length) public ByteBuf getBytes(int index, OutputStream out, int length)
throws IOException { throws IOException {
buffer.getBytes(index, out, length); buffer.getBytes(index, out, length);
return this; return this;
@ -230,40 +238,22 @@ public class DuplicatedByteBuf extends AbstractWrappedByteBuf {
} }
@Override @Override
public Unsafe unsafe() { public ByteBuffer internalNioBuffer() {
return unsafe; return buffer.internalNioBuffer();
} }
private final class DuplicatedUnsafe implements Unsafe { @Override
public ByteBuffer[] internalNioBuffers() {
return buffer.internalNioBuffers();
}
@Override @Override
public ByteBuffer nioBuffer() { public void discardSomeReadBytes() {
return buffer.unsafe().nioBuffer(); throw new UnsupportedOperationException();
} }
@Override @Override
public ByteBuffer[] nioBuffers() { public void free() {
return buffer.unsafe().nioBuffers();
}
@Override
public ByteBuf newBuffer(int initialCapacity) {
return buffer.unsafe().newBuffer(initialCapacity);
}
@Override
public void discardSomeReadBytes() {
throw new UnsupportedOperationException();
}
@Override
public void acquire() {
buffer.unsafe().acquire();
}
@Override
public void release() {
buffer.unsafe().release();
}
} }
} }

View File

@ -30,11 +30,6 @@ public class QueueBackedMessageBuf<T> implements MessageBuf<T> {
this.queue = queue; this.queue = queue;
} }
@Override
public boolean isPooled() {
return false;
}
@Override @Override
public ChannelBufType type() { public ChannelBufType type() {
return ChannelBufType.MESSAGE; return ChannelBufType.MESSAGE;

View File

@ -19,6 +19,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ReadOnlyBufferException; import java.nio.ReadOnlyBufferException;
import java.nio.channels.GatheringByteChannel; import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel; import java.nio.channels.ScatteringByteChannel;
@ -28,27 +29,36 @@ 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 AbstractWrappedByteBuf { public class ReadOnlyByteBuf extends AbstractByteBuf {
private final ByteBuf buffer; private final UnsafeByteBuf buffer;
public ReadOnlyByteBuf(UnsafeByteBuf buffer) {
super(buffer.maxCapacity());
if (buffer instanceof ReadOnlyByteBuf) {
buffer = ((ReadOnlyByteBuf) buffer).buffer;
}
public ReadOnlyByteBuf(ByteBuf buffer) {
super(buffer.order(), buffer.maxCapacity());
this.buffer = buffer; this.buffer = buffer;
setIndex(buffer.readerIndex(), buffer.writerIndex()); setIndex(buffer.readerIndex(), buffer.writerIndex());
} }
private ReadOnlyByteBuf(ReadOnlyByteBuf buffer) {
super(buffer.buffer.order(), buffer.maxCapacity());
this.buffer = buffer.buffer;
setIndex(buffer.readerIndex(), buffer.writerIndex());
}
@Override @Override
public ByteBuf unwrap() { public ByteBuf unwrap() {
return buffer; return buffer;
} }
@Override
public ByteBufAllocator alloc() {
return buffer.alloc();
}
@Override
public ByteOrder order() {
return buffer.order();
}
@Override @Override
public boolean isDirect() { public boolean isDirect() {
return buffer.isDirect(); return buffer.isDirect();
@ -70,47 +80,47 @@ public class ReadOnlyByteBuf extends AbstractWrappedByteBuf {
} }
@Override @Override
public WrappedByteBuf discardReadBytes() { public ByteBuf discardReadBytes() {
throw new ReadOnlyBufferException(); throw new ReadOnlyBufferException();
} }
@Override @Override
public WrappedByteBuf setByte(int index, int value) { public ByteBuf setByte(int index, int value) {
throw new ReadOnlyBufferException(); throw new ReadOnlyBufferException();
} }
@Override @Override
public WrappedByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
throw new ReadOnlyBufferException(); throw new ReadOnlyBufferException();
} }
@Override @Override
public WrappedByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
throw new ReadOnlyBufferException(); throw new ReadOnlyBufferException();
} }
@Override @Override
public WrappedByteBuf setBytes(int index, ByteBuffer src) { public ByteBuf setBytes(int index, ByteBuffer src) {
throw new ReadOnlyBufferException(); throw new ReadOnlyBufferException();
} }
@Override @Override
public WrappedByteBuf setShort(int index, int value) { public ByteBuf setShort(int index, int value) {
throw new ReadOnlyBufferException(); throw new ReadOnlyBufferException();
} }
@Override @Override
public WrappedByteBuf setMedium(int index, int value) { public ByteBuf setMedium(int index, int value) {
throw new ReadOnlyBufferException(); throw new ReadOnlyBufferException();
} }
@Override @Override
public WrappedByteBuf setInt(int index, int value) { public ByteBuf setInt(int index, int value) {
throw new ReadOnlyBufferException(); throw new ReadOnlyBufferException();
} }
@Override @Override
public WrappedByteBuf setLong(int index, long value) { public ByteBuf setLong(int index, long value) {
throw new ReadOnlyBufferException(); throw new ReadOnlyBufferException();
} }
@ -133,26 +143,26 @@ public class ReadOnlyByteBuf extends AbstractWrappedByteBuf {
} }
@Override @Override
public WrappedByteBuf getBytes(int index, OutputStream out, int length) public ByteBuf getBytes(int index, OutputStream out, int length)
throws IOException { throws IOException {
buffer.getBytes(index, out, length); buffer.getBytes(index, out, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
buffer.getBytes(index, dst, dstIndex, length); buffer.getBytes(index, dst, dstIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
buffer.getBytes(index, dst, dstIndex, length); buffer.getBytes(index, dst, dstIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf getBytes(int index, ByteBuffer dst) { public ByteBuf getBytes(int index, ByteBuffer dst) {
buffer.getBytes(index, dst); buffer.getBytes(index, dst);
return this; return this;
} }
@ -169,7 +179,7 @@ public class ReadOnlyByteBuf extends AbstractWrappedByteBuf {
@Override @Override
public ByteBuf slice(int index, int length) { public ByteBuf slice(int index, int length) {
return new ReadOnlyByteBuf(buffer.slice(index, length)); return new ReadOnlyByteBuf((UnsafeByteBuf) buffer.slice(index, length));
} }
@Override @Override
@ -223,12 +233,25 @@ public class ReadOnlyByteBuf extends AbstractWrappedByteBuf {
} }
@Override @Override
public WrappedByteBuf capacity(int newCapacity) { public ByteBuf capacity(int newCapacity) {
throw new ReadOnlyBufferException(); throw new ReadOnlyBufferException();
} }
@Override @Override
public Unsafe unsafe() { public ByteBuffer internalNioBuffer() {
return buffer.unsafe(); return buffer.internalNioBuffer();
} }
@Override
public ByteBuffer[] internalNioBuffers() {
return buffer.internalNioBuffers();
}
@Override
public void discardSomeReadBytes() {
throw new UnsupportedOperationException();
}
@Override
public void free() { }
} }

View File

@ -19,6 +19,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.GatheringByteChannel; import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel; import java.nio.channels.ScatteringByteChannel;
@ -29,15 +30,14 @@ 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 AbstractWrappedByteBuf { public class SlicedByteBuf extends AbstractByteBuf {
private final Unsafe unsafe = new SlicedUnsafe(); private final UnsafeByteBuf buffer;
private final ByteBuf buffer;
private final int adjustment; private final int adjustment;
private final int length; private final int length;
public SlicedByteBuf(ByteBuf buffer, int index, int length) { public SlicedByteBuf(UnsafeByteBuf buffer, int index, int length) {
super(buffer.order(), length); super(length);
if (index < 0 || index > buffer.capacity()) { if (index < 0 || index > buffer.capacity()) {
throw new IndexOutOfBoundsException("Invalid index of " + index throw new IndexOutOfBoundsException("Invalid index of " + index
+ ", maximum is " + buffer.capacity()); + ", maximum is " + buffer.capacity());
@ -52,7 +52,7 @@ public class SlicedByteBuf extends AbstractWrappedByteBuf {
this.buffer = ((SlicedByteBuf) buffer).buffer; this.buffer = ((SlicedByteBuf) buffer).buffer;
adjustment = ((SlicedByteBuf) buffer).adjustment + index; adjustment = ((SlicedByteBuf) buffer).adjustment + index;
} else if (buffer instanceof DuplicatedByteBuf) { } else if (buffer instanceof DuplicatedByteBuf) {
this.buffer = ((DuplicatedByteBuf) buffer).buffer; this.buffer = (UnsafeByteBuf) buffer.unwrap();
adjustment = index; adjustment = index;
} else { } else {
this.buffer = buffer; this.buffer = buffer;
@ -61,8 +61,6 @@ public class SlicedByteBuf extends AbstractWrappedByteBuf {
this.length = length; this.length = length;
writerIndex(length); writerIndex(length);
buffer.unsafe().acquire();
} }
@Override @Override
@ -70,6 +68,16 @@ public class SlicedByteBuf extends AbstractWrappedByteBuf {
return buffer; return buffer;
} }
@Override
public ByteBufAllocator alloc() {
return buffer.alloc();
}
@Override
public ByteOrder order() {
return buffer.order();
}
@Override @Override
public boolean isDirect() { public boolean isDirect() {
return buffer.isDirect(); return buffer.isDirect();
@ -81,7 +89,7 @@ public class SlicedByteBuf extends AbstractWrappedByteBuf {
} }
@Override @Override
public WrappedByteBuf capacity(int newCapacity) { public ByteBuf capacity(int newCapacity) {
throw new UnsupportedOperationException("sliced buffer"); throw new UnsupportedOperationException("sliced buffer");
} }
@ -153,84 +161,84 @@ public class SlicedByteBuf extends AbstractWrappedByteBuf {
} }
@Override @Override
public WrappedByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
checkIndex(index, length); checkIndex(index, length);
buffer.getBytes(index + adjustment, dst, dstIndex, length); buffer.getBytes(index + adjustment, dst, dstIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
checkIndex(index, length); checkIndex(index, length);
buffer.getBytes(index + adjustment, dst, dstIndex, length); buffer.getBytes(index + adjustment, dst, dstIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf getBytes(int index, ByteBuffer dst) { public ByteBuf getBytes(int index, ByteBuffer dst) {
checkIndex(index, dst.remaining()); checkIndex(index, dst.remaining());
buffer.getBytes(index + adjustment, dst); buffer.getBytes(index + adjustment, dst);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setByte(int index, int value) { public ByteBuf setByte(int index, int value) {
checkIndex(index); checkIndex(index);
buffer.setByte(index + adjustment, value); buffer.setByte(index + adjustment, value);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setShort(int index, int value) { public ByteBuf setShort(int index, int value) {
checkIndex(index, 2); checkIndex(index, 2);
buffer.setShort(index + adjustment, value); buffer.setShort(index + adjustment, value);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setMedium(int index, int value) { public ByteBuf setMedium(int index, int value) {
checkIndex(index, 3); checkIndex(index, 3);
buffer.setMedium(index + adjustment, value); buffer.setMedium(index + adjustment, value);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setInt(int index, int value) { public ByteBuf setInt(int index, int value) {
checkIndex(index, 4); checkIndex(index, 4);
buffer.setInt(index + adjustment, value); buffer.setInt(index + adjustment, value);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setLong(int index, long value) { public ByteBuf setLong(int index, long value) {
checkIndex(index, 8); checkIndex(index, 8);
buffer.setLong(index + adjustment, value); buffer.setLong(index + adjustment, value);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
checkIndex(index, length); checkIndex(index, length);
buffer.setBytes(index + adjustment, src, srcIndex, length); buffer.setBytes(index + adjustment, src, srcIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
checkIndex(index, length); checkIndex(index, length);
buffer.setBytes(index + adjustment, src, srcIndex, length); buffer.setBytes(index + adjustment, src, srcIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setBytes(int index, ByteBuffer src) { public ByteBuf setBytes(int index, ByteBuffer src) {
checkIndex(index, src.remaining()); checkIndex(index, src.remaining());
buffer.setBytes(index + adjustment, src); buffer.setBytes(index + adjustment, src);
return this; return this;
} }
@Override @Override
public WrappedByteBuf getBytes(int index, OutputStream out, int length) public ByteBuf getBytes(int index, OutputStream out, int length)
throws IOException { throws IOException {
checkIndex(index, length); checkIndex(index, length);
buffer.getBytes(index + adjustment, out, length); buffer.getBytes(index + adjustment, out, length);
@ -302,40 +310,20 @@ public class SlicedByteBuf extends AbstractWrappedByteBuf {
} }
@Override @Override
public Unsafe unsafe() { public ByteBuffer internalNioBuffer() {
return unsafe; return buffer.nioBuffer(adjustment, length);
} }
private final class SlicedUnsafe implements Unsafe { @Override
public ByteBuffer[] internalNioBuffers() {
@Override return buffer.nioBuffers(adjustment, length);
public ByteBuffer nioBuffer() {
return buffer.nioBuffer(adjustment, length);
}
@Override
public ByteBuffer[] nioBuffers() {
return buffer.nioBuffers(adjustment, length);
}
@Override
public ByteBuf newBuffer(int initialCapacity) {
return buffer.unsafe().newBuffer(initialCapacity);
}
@Override
public void discardSomeReadBytes() {
throw new UnsupportedOperationException();
}
@Override
public void acquire() {
buffer.unsafe().acquire();
}
@Override
public void release() {
buffer.unsafe().release();
}
} }
@Override
public void discardSomeReadBytes() {
throw new UnsupportedOperationException();
}
@Override
public void free() { }
} }

View File

@ -24,12 +24,12 @@ import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel; import java.nio.channels.ScatteringByteChannel;
import java.nio.charset.Charset; import java.nio.charset.Charset;
public class SwappedByteBuf implements WrappedByteBuf { public class SwappedByteBuf implements UnsafeByteBuf {
private final ByteBuf buf; private final UnsafeByteBuf buf;
private final ByteOrder order; private final ByteOrder order;
public SwappedByteBuf(ByteBuf buf) { public SwappedByteBuf(UnsafeByteBuf buf) {
if (buf == null) { if (buf == null) {
throw new NullPointerException("buf"); throw new NullPointerException("buf");
} }
@ -63,8 +63,8 @@ public class SwappedByteBuf implements WrappedByteBuf {
} }
@Override @Override
public boolean isPooled() { public ByteBufAllocator alloc() {
return buf.isPooled(); return buf.alloc();
} }
@Override @Override
@ -78,7 +78,7 @@ public class SwappedByteBuf implements WrappedByteBuf {
} }
@Override @Override
public WrappedByteBuf capacity(int newCapacity) { public ByteBuf capacity(int newCapacity) {
buf.capacity(newCapacity); buf.capacity(newCapacity);
return this; return this;
} }
@ -99,7 +99,7 @@ public class SwappedByteBuf implements WrappedByteBuf {
} }
@Override @Override
public WrappedByteBuf readerIndex(int readerIndex) { public ByteBuf readerIndex(int readerIndex) {
buf.readerIndex(readerIndex); buf.readerIndex(readerIndex);
return this; return this;
} }
@ -110,13 +110,13 @@ public class SwappedByteBuf implements WrappedByteBuf {
} }
@Override @Override
public WrappedByteBuf writerIndex(int writerIndex) { public ByteBuf writerIndex(int writerIndex) {
buf.writerIndex(writerIndex); buf.writerIndex(writerIndex);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setIndex(int readerIndex, int writerIndex) { public ByteBuf setIndex(int readerIndex, int writerIndex) {
buf.setIndex(readerIndex, writerIndex); buf.setIndex(readerIndex, writerIndex);
return this; return this;
} }
@ -142,43 +142,43 @@ public class SwappedByteBuf implements WrappedByteBuf {
} }
@Override @Override
public WrappedByteBuf clear() { public ByteBuf clear() {
buf.clear(); buf.clear();
return this; return this;
} }
@Override @Override
public WrappedByteBuf markReaderIndex() { public ByteBuf markReaderIndex() {
buf.markReaderIndex(); buf.markReaderIndex();
return this; return this;
} }
@Override @Override
public WrappedByteBuf resetReaderIndex() { public ByteBuf resetReaderIndex() {
buf.resetReaderIndex(); buf.resetReaderIndex();
return this; return this;
} }
@Override @Override
public WrappedByteBuf markWriterIndex() { public ByteBuf markWriterIndex() {
buf.markWriterIndex(); buf.markWriterIndex();
return this; return this;
} }
@Override @Override
public WrappedByteBuf resetWriterIndex() { public ByteBuf resetWriterIndex() {
buf.resetWriterIndex(); buf.resetWriterIndex();
return this; return this;
} }
@Override @Override
public WrappedByteBuf discardReadBytes() { public ByteBuf discardReadBytes() {
buf.discardReadBytes(); buf.discardReadBytes();
return this; return this;
} }
@Override @Override
public WrappedByteBuf ensureWritableBytes(int writableBytes) { public ByteBuf ensureWritableBytes(int writableBytes) {
buf.ensureWritableBytes(writableBytes); buf.ensureWritableBytes(writableBytes);
return this; return this;
} }
@ -254,43 +254,43 @@ public class SwappedByteBuf implements WrappedByteBuf {
} }
@Override @Override
public WrappedByteBuf getBytes(int index, ByteBuf dst) { public ByteBuf getBytes(int index, ByteBuf dst) {
buf.getBytes(index, dst); buf.getBytes(index, dst);
return this; return this;
} }
@Override @Override
public WrappedByteBuf getBytes(int index, ByteBuf dst, int length) { public ByteBuf getBytes(int index, ByteBuf dst, int length) {
buf.getBytes(index, dst, length); buf.getBytes(index, dst, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
buf.getBytes(index, dst, dstIndex, length); buf.getBytes(index, dst, dstIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf getBytes(int index, byte[] dst) { public ByteBuf getBytes(int index, byte[] dst) {
buf.getBytes(index, dst); buf.getBytes(index, dst);
return this; return this;
} }
@Override @Override
public WrappedByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
buf.getBytes(index, dst, dstIndex, length); buf.getBytes(index, dst, dstIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf getBytes(int index, ByteBuffer dst) { public ByteBuf getBytes(int index, ByteBuffer dst) {
buf.getBytes(index, dst); buf.getBytes(index, dst);
return this; return this;
} }
@Override @Override
public WrappedByteBuf getBytes(int index, OutputStream out, int length) throws IOException { public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
buf.getBytes(index, out, length); buf.getBytes(index, out, length);
return this; return this;
} }
@ -301,91 +301,91 @@ public class SwappedByteBuf implements WrappedByteBuf {
} }
@Override @Override
public WrappedByteBuf setBoolean(int index, boolean value) { public ByteBuf setBoolean(int index, boolean value) {
buf.setBoolean(index, value); buf.setBoolean(index, value);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setByte(int index, int value) { public ByteBuf setByte(int index, int value) {
buf.setByte(index, value); buf.setByte(index, value);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setShort(int index, int value) { public ByteBuf setShort(int index, int value) {
buf.setShort(index, ByteBufUtil.swapShort((short) value)); buf.setShort(index, ByteBufUtil.swapShort((short) value));
return this; return this;
} }
@Override @Override
public WrappedByteBuf setMedium(int index, int value) { public ByteBuf setMedium(int index, int value) {
buf.setMedium(index, ByteBufUtil.swapMedium(value)); buf.setMedium(index, ByteBufUtil.swapMedium(value));
return this; return this;
} }
@Override @Override
public WrappedByteBuf setInt(int index, int value) { public ByteBuf setInt(int index, int value) {
buf.setInt(index, ByteBufUtil.swapInt(value)); buf.setInt(index, ByteBufUtil.swapInt(value));
return this; return this;
} }
@Override @Override
public WrappedByteBuf setLong(int index, long value) { public ByteBuf setLong(int index, long value) {
buf.setLong(index, ByteBufUtil.swapLong(value)); buf.setLong(index, ByteBufUtil.swapLong(value));
return this; return this;
} }
@Override @Override
public WrappedByteBuf setChar(int index, int value) { public ByteBuf setChar(int index, int value) {
setShort(index, value); setShort(index, value);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setFloat(int index, float value) { public ByteBuf setFloat(int index, float value) {
setInt(index, Float.floatToRawIntBits(value)); setInt(index, Float.floatToRawIntBits(value));
return this; return this;
} }
@Override @Override
public WrappedByteBuf setDouble(int index, double value) { public ByteBuf setDouble(int index, double value) {
setLong(index, Double.doubleToRawLongBits(value)); setLong(index, Double.doubleToRawLongBits(value));
return this; return this;
} }
@Override @Override
public WrappedByteBuf setBytes(int index, ByteBuf src) { public ByteBuf setBytes(int index, ByteBuf src) {
buf.setBytes(index, src); buf.setBytes(index, src);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setBytes(int index, ByteBuf src, int length) { public ByteBuf setBytes(int index, ByteBuf src, int length) {
buf.setBytes(index, src, length); buf.setBytes(index, src, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
buf.setBytes(index, src, srcIndex, length); buf.setBytes(index, src, srcIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setBytes(int index, byte[] src) { public ByteBuf setBytes(int index, byte[] src) {
buf.setBytes(index, src); buf.setBytes(index, src);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
buf.setBytes(index, src, srcIndex, length); buf.setBytes(index, src, srcIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf setBytes(int index, ByteBuffer src) { public ByteBuf setBytes(int index, ByteBuffer src) {
buf.setBytes(index, src); buf.setBytes(index, src);
return this; return this;
} }
@ -401,7 +401,7 @@ public class SwappedByteBuf implements WrappedByteBuf {
} }
@Override @Override
public WrappedByteBuf setZero(int index, int length) { public ByteBuf setZero(int index, int length) {
buf.setZero(index, length); buf.setZero(index, length);
return this; return this;
} }
@ -473,7 +473,7 @@ public class SwappedByteBuf implements WrappedByteBuf {
@Override @Override
public ByteBuf readBytes(int length) { public ByteBuf readBytes(int length) {
return buf.readBytes(length); return buf.readBytes(length).order(order());
} }
@Override @Override
@ -482,43 +482,43 @@ public class SwappedByteBuf implements WrappedByteBuf {
} }
@Override @Override
public WrappedByteBuf readBytes(ByteBuf dst) { public ByteBuf readBytes(ByteBuf dst) {
buf.readBytes(dst); buf.readBytes(dst);
return this; return this;
} }
@Override @Override
public WrappedByteBuf readBytes(ByteBuf dst, int length) { public ByteBuf readBytes(ByteBuf dst, int length) {
buf.readBytes(dst, length); buf.readBytes(dst, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf readBytes(ByteBuf dst, int dstIndex, int length) { public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
buf.readBytes(dst, dstIndex, length); buf.readBytes(dst, dstIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf readBytes(byte[] dst) { public ByteBuf readBytes(byte[] dst) {
buf.readBytes(dst); buf.readBytes(dst);
return this; return this;
} }
@Override @Override
public WrappedByteBuf readBytes(byte[] dst, int dstIndex, int length) { public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
buf.readBytes(dst, dstIndex, length); buf.readBytes(dst, dstIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf readBytes(ByteBuffer dst) { public ByteBuf readBytes(ByteBuffer dst) {
buf.readBytes(dst); buf.readBytes(dst);
return this; return this;
} }
@Override @Override
public WrappedByteBuf readBytes(OutputStream out, int length) throws IOException { public ByteBuf readBytes(OutputStream out, int length) throws IOException {
buf.readBytes(out, length); buf.readBytes(out, length);
return this; return this;
} }
@ -529,97 +529,97 @@ public class SwappedByteBuf implements WrappedByteBuf {
} }
@Override @Override
public WrappedByteBuf skipBytes(int length) { public ByteBuf skipBytes(int length) {
buf.skipBytes(length); buf.skipBytes(length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf writeBoolean(boolean value) { public ByteBuf writeBoolean(boolean value) {
buf.writeBoolean(value); buf.writeBoolean(value);
return this; return this;
} }
@Override @Override
public WrappedByteBuf writeByte(int value) { public ByteBuf writeByte(int value) {
buf.writeByte(value); buf.writeByte(value);
return this; return this;
} }
@Override @Override
public WrappedByteBuf writeShort(int value) { public ByteBuf writeShort(int value) {
buf.writeShort(ByteBufUtil.swapShort((short) value)); buf.writeShort(ByteBufUtil.swapShort((short) value));
return this; return this;
} }
@Override @Override
public WrappedByteBuf writeMedium(int value) { public ByteBuf writeMedium(int value) {
buf.writeMedium(ByteBufUtil.swapMedium(value)); buf.writeMedium(ByteBufUtil.swapMedium(value));
return this; return this;
} }
@Override @Override
public WrappedByteBuf writeInt(int value) { public ByteBuf writeInt(int value) {
buf.writeInt(ByteBufUtil.swapInt(value)); buf.writeInt(ByteBufUtil.swapInt(value));
return this; return this;
} }
@Override @Override
public WrappedByteBuf writeLong(long value) { public ByteBuf writeLong(long value) {
buf.writeLong(ByteBufUtil.swapLong(value)); buf.writeLong(ByteBufUtil.swapLong(value));
return this; return this;
} }
@Override @Override
public WrappedByteBuf writeChar(int value) { public ByteBuf writeChar(int value) {
writeShort(value); writeShort(value);
return this; return this;
} }
@Override @Override
public WrappedByteBuf writeFloat(float value) { public ByteBuf writeFloat(float value) {
writeInt(Float.floatToRawIntBits(value)); writeInt(Float.floatToRawIntBits(value));
return this; return this;
} }
@Override @Override
public WrappedByteBuf writeDouble(double value) { public ByteBuf writeDouble(double value) {
writeLong(Double.doubleToRawLongBits(value)); writeLong(Double.doubleToRawLongBits(value));
return this; return this;
} }
@Override @Override
public WrappedByteBuf writeBytes(ByteBuf src) { public ByteBuf writeBytes(ByteBuf src) {
buf.writeBytes(src); buf.writeBytes(src);
return this; return this;
} }
@Override @Override
public WrappedByteBuf writeBytes(ByteBuf src, int length) { public ByteBuf writeBytes(ByteBuf src, int length) {
buf.writeBytes(src, length); buf.writeBytes(src, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf writeBytes(ByteBuf src, int srcIndex, int length) { public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
buf.writeBytes(src, srcIndex, length); buf.writeBytes(src, srcIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf writeBytes(byte[] src) { public ByteBuf writeBytes(byte[] src) {
buf.writeBytes(src); buf.writeBytes(src);
return this; return this;
} }
@Override @Override
public WrappedByteBuf writeBytes(byte[] src, int srcIndex, int length) { public ByteBuf writeBytes(byte[] src, int srcIndex, int length) {
buf.writeBytes(src, srcIndex, length); buf.writeBytes(src, srcIndex, length);
return this; return this;
} }
@Override @Override
public WrappedByteBuf writeBytes(ByteBuffer src) { public ByteBuf writeBytes(ByteBuffer src) {
buf.writeBytes(src); buf.writeBytes(src);
return this; return this;
} }
@ -635,7 +635,7 @@ public class SwappedByteBuf implements WrappedByteBuf {
} }
@Override @Override
public WrappedByteBuf writeZero(int length) { public ByteBuf writeZero(int length) {
buf.writeZero(length); buf.writeZero(length);
return this; return this;
} }
@ -768,11 +768,6 @@ public class SwappedByteBuf implements WrappedByteBuf {
return buf.toString(index, length, charset); return buf.toString(index, length, charset);
} }
@Override
public Unsafe unsafe() {
return buf.unsafe();
}
@Override @Override
public int hashCode() { public int hashCode() {
return buf.hashCode(); return buf.hashCode();
@ -798,4 +793,22 @@ public class SwappedByteBuf implements WrappedByteBuf {
public String toString() { public String toString() {
return "Swapped(" + buf.toString() + ')'; return "Swapped(" + buf.toString() + ')';
} }
@Override
public ByteBuffer internalNioBuffer() {
return buf.internalNioBuffer();
}
@Override
public ByteBuffer[] internalNioBuffers() {
return buf.internalNioBuffers();
}
@Override
public void discardSomeReadBytes() {
buf.discardSomeReadBytes();
}
@Override
public void free() { }
} }

View File

@ -77,6 +77,8 @@ import java.util.Queue;
*/ */
public final class Unpooled { public final class Unpooled {
private static final ByteBufAllocator ALLOC = UnpooledByteBufAllocator.HEAP_BY_DEFAULT;
/** /**
* Big endian byte order. * Big endian byte order.
*/ */
@ -90,15 +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 HeapByteBuf(0, 0) { public static final ByteBuf EMPTY_BUFFER = ALLOC.heapBuffer(0, 0);
@Override
public ByteBuf order(ByteOrder endianness) {
if (endianness == null) {
throw new NullPointerException("endianness");
}
return this;
}
};
public static <T> MessageBuf<T> messageBuffer() { public static <T> MessageBuf<T> messageBuffer() {
return new DefaultMessageBuf<T>(); return new DefaultMessageBuf<T>();
@ -120,7 +114,7 @@ public final class Unpooled {
* expands its capacity boundlessly on demand. * expands its capacity boundlessly on demand.
*/ */
public static ByteBuf buffer() { public static ByteBuf buffer() {
return buffer(256, Integer.MAX_VALUE); return ALLOC.heapBuffer();
} }
/** /**
@ -128,7 +122,7 @@ public final class Unpooled {
* expands its capacity boundlessly on demand. * expands its capacity boundlessly on demand.
*/ */
public static ByteBuf directBuffer() { public static ByteBuf directBuffer() {
return directBuffer(256, Integer.MAX_VALUE); return ALLOC.directBuffer();
} }
/** /**
@ -137,7 +131,7 @@ public final class Unpooled {
* {@code writerIndex} are {@code 0}. * {@code writerIndex} are {@code 0}.
*/ */
public static ByteBuf buffer(int initialCapacity) { public static ByteBuf buffer(int initialCapacity) {
return buffer(initialCapacity, Integer.MAX_VALUE); return ALLOC.heapBuffer(initialCapacity);
} }
/** /**
@ -146,7 +140,7 @@ public final class Unpooled {
* {@code writerIndex} are {@code 0}. * {@code writerIndex} are {@code 0}.
*/ */
public static ByteBuf directBuffer(int initialCapacity) { public static ByteBuf directBuffer(int initialCapacity) {
return directBuffer(initialCapacity, Integer.MAX_VALUE); return ALLOC.directBuffer(initialCapacity);
} }
/** /**
@ -155,10 +149,7 @@ public final class Unpooled {
* {@code writerIndex} are {@code 0}. * {@code writerIndex} are {@code 0}.
*/ */
public static ByteBuf buffer(int initialCapacity, int maxCapacity) { public static ByteBuf buffer(int initialCapacity, int maxCapacity) {
if (initialCapacity == 0 && maxCapacity == 0) { return ALLOC.heapBuffer(initialCapacity, maxCapacity);
return EMPTY_BUFFER;
}
return new HeapByteBuf(initialCapacity, maxCapacity);
} }
/** /**
@ -167,10 +158,7 @@ public final class Unpooled {
* {@code writerIndex} are {@code 0}. * {@code writerIndex} are {@code 0}.
*/ */
public static ByteBuf directBuffer(int initialCapacity, int maxCapacity) { public static ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
if (initialCapacity == 0 && maxCapacity == 0) { return ALLOC.directBuffer(initialCapacity, maxCapacity);
return EMPTY_BUFFER;
}
return new DirectByteBuf(initialCapacity, maxCapacity);
} }
/** /**
@ -182,7 +170,7 @@ public final class Unpooled {
if (array.length == 0) { if (array.length == 0) {
return EMPTY_BUFFER; return EMPTY_BUFFER;
} }
return new HeapByteBuf(array, array.length); return new UnpooledHeapByteBuf(ALLOC, array, array.length);
} }
/** /**
@ -199,7 +187,7 @@ public final class Unpooled {
return wrappedBuffer(array); return wrappedBuffer(array);
} }
return new SlicedByteBuf(wrappedBuffer(array), offset, length); return wrappedBuffer(array).slice(offset, length);
} }
/** /**
@ -217,7 +205,7 @@ public final class Unpooled {
buffer.arrayOffset() + buffer.position(), buffer.arrayOffset() + buffer.position(),
buffer.remaining()).order(buffer.order()); buffer.remaining()).order(buffer.order());
} else { } else {
return new DirectByteBuf(buffer, buffer.remaining()); return new UnpooledDirectByteBuf(ALLOC, buffer, buffer.remaining());
} }
} }
@ -288,7 +276,7 @@ public final class Unpooled {
} }
if (!components.isEmpty()) { if (!components.isEmpty()) {
return new DefaultCompositeByteBuf(maxNumComponents, components); return new DefaultCompositeByteBuf(ALLOC, maxNumComponents, components);
} }
} }
@ -312,7 +300,7 @@ public final class Unpooled {
default: default:
for (ByteBuf b: buffers) { for (ByteBuf b: buffers) {
if (b.readable()) { if (b.readable()) {
return new DefaultCompositeByteBuf(maxNumComponents, buffers); return new DefaultCompositeByteBuf(ALLOC, maxNumComponents, buffers);
} }
} }
} }
@ -346,7 +334,7 @@ public final class Unpooled {
} }
if (!components.isEmpty()) { if (!components.isEmpty()) {
return new DefaultCompositeByteBuf(maxNumComponents, components); return new DefaultCompositeByteBuf(ALLOC, maxNumComponents, components);
} }
} }
@ -364,7 +352,7 @@ public final class Unpooled {
* Returns a new big-endian composite buffer with no components. * Returns a new big-endian composite buffer with no components.
*/ */
public static CompositeByteBuf compositeBuffer(int maxNumComponents) { public static CompositeByteBuf compositeBuffer(int maxNumComponents) {
return new DefaultCompositeByteBuf(maxNumComponents); return new DefaultCompositeByteBuf(ALLOC, maxNumComponents);
} }
/** /**
@ -674,10 +662,7 @@ public final class Unpooled {
* {@code buffer}. * {@code buffer}.
*/ */
public static ByteBuf unmodifiableBuffer(ByteBuf buffer) { public static ByteBuf unmodifiableBuffer(ByteBuf buffer) {
if (buffer instanceof ReadOnlyByteBuf) { return new ReadOnlyByteBuf((UnsafeByteBuf) buffer);
buffer = ((ReadOnlyByteBuf) buffer).unwrap();
}
return new ReadOnlyByteBuf(buffer);
} }
/** /**

View File

@ -0,0 +1,73 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.buffer;
import io.netty.util.internal.DetectionUtil;
import java.util.concurrent.TimeUnit;
/**
* Simplistic {@link ByteBufAllocator} implementation that does not pool anything.
*/
public final class UnpooledByteBufAllocator extends AbstractByteBufAllocator {
public static final UnpooledByteBufAllocator HEAP_BY_DEFAULT = new UnpooledByteBufAllocator(false);
public static final UnpooledByteBufAllocator DIRECT_BY_DEFAULT = new UnpooledByteBufAllocator(true);
private UnpooledByteBufAllocator(boolean directByDefault) {
super(directByDefault);
}
@Override
protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
return new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
}
@Override
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
return new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
}
@Override
public ByteBuf ioBuffer() {
if (DetectionUtil.canFreeDirectBuffer()) {
return directBuffer();
}
return heapBuffer();
}
@Override
public void shutdown() {
throw new IllegalStateException(getClass().getName() + " cannot be shut down.");
}
@Override
public boolean isShutdown() {
return false;
}
@Override
public boolean isTerminated() {
return false;
}
@Override
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
Thread.sleep(unit.toMillis(timeout));
return false;
}
}

View File

@ -33,7 +33,7 @@ import java.nio.channels.ScatteringByteChannel;
* constructor explicitly. * constructor explicitly.
*/ */
@SuppressWarnings("restriction") @SuppressWarnings("restriction")
public class DirectByteBuf extends AbstractByteBuf { public class UnpooledDirectByteBuf extends AbstractByteBuf {
private static final Field CLEANER_FIELD; private static final Field CLEANER_FIELD;
@ -52,6 +52,11 @@ public class DirectByteBuf extends AbstractByteBuf {
} }
private static void freeDirect(ByteBuffer buffer) { private static void freeDirect(ByteBuffer buffer) {
if (CLEANER_FIELD == null) {
// Doomed to wait for GC.
return;
}
Cleaner cleaner; Cleaner cleaner;
try { try {
cleaner = (Cleaner) CLEANER_FIELD.get(buffer); cleaner = (Cleaner) CLEANER_FIELD.get(buffer);
@ -61,12 +66,12 @@ public class DirectByteBuf extends AbstractByteBuf {
} }
} }
private final Unsafe unsafe = new DirectUnsafe(); private final ByteBufAllocator alloc;
private boolean doNotFree;
private ByteBuffer buffer; private ByteBuffer buffer;
private ByteBuffer tmpBuf; private ByteBuffer tmpNioBuf;
private int capacity; private int capacity;
private boolean freed;
private boolean doNotFree;
/** /**
* Creates a new direct buffer. * Creates a new direct buffer.
@ -74,8 +79,11 @@ public class DirectByteBuf extends AbstractByteBuf {
* @param initialCapacity the initial capacity of the underlying direct buffer * @param initialCapacity the initial capacity of the underlying direct buffer
* @param maxCapacity the maximum capacity of the underlying direct buffer * @param maxCapacity the maximum capacity of the underlying direct buffer
*/ */
public DirectByteBuf(int initialCapacity, int maxCapacity) { public UnpooledDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
super(ByteOrder.BIG_ENDIAN, maxCapacity); super(maxCapacity);
if (alloc == null) {
throw new NullPointerException("alloc");
}
if (initialCapacity < 0) { if (initialCapacity < 0) {
throw new IllegalArgumentException("initialCapacity: " + initialCapacity); throw new IllegalArgumentException("initialCapacity: " + initialCapacity);
} }
@ -87,6 +95,7 @@ public class DirectByteBuf extends AbstractByteBuf {
"initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity)); "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
} }
this.alloc = alloc;
setByteBuffer(ByteBuffer.allocateDirect(initialCapacity)); setByteBuffer(ByteBuffer.allocateDirect(initialCapacity));
} }
@ -95,9 +104,11 @@ public class DirectByteBuf extends AbstractByteBuf {
* *
* @param maxCapacity the maximum capacity of the underlying direct buffer * @param maxCapacity the maximum capacity of the underlying direct buffer
*/ */
public DirectByteBuf(ByteBuffer initialBuffer, int maxCapacity) { public UnpooledDirectByteBuf(ByteBufAllocator alloc, ByteBuffer initialBuffer, int maxCapacity) {
super(ByteOrder.BIG_ENDIAN, maxCapacity); super(maxCapacity);
if (alloc == null) {
throw new NullPointerException("alloc");
}
if (initialBuffer == null) { if (initialBuffer == null) {
throw new NullPointerException("initialBuffer"); throw new NullPointerException("initialBuffer");
} }
@ -114,6 +125,7 @@ public class DirectByteBuf extends AbstractByteBuf {
"initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity)); "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
} }
this.alloc = alloc;
doNotFree = true; doNotFree = true;
setByteBuffer(initialBuffer.slice().order(ByteOrder.BIG_ENDIAN)); setByteBuffer(initialBuffer.slice().order(ByteOrder.BIG_ENDIAN));
writerIndex(initialCapacity); writerIndex(initialCapacity);
@ -130,7 +142,7 @@ public class DirectByteBuf extends AbstractByteBuf {
} }
this.buffer = buffer; this.buffer = buffer;
tmpBuf = buffer.duplicate(); tmpNioBuf = null;
capacity = buffer.remaining(); capacity = buffer.remaining();
} }
@ -146,6 +158,7 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf capacity(int newCapacity) { public ByteBuf capacity(int newCapacity) {
assert !freed;
if (newCapacity < 0 || newCapacity > maxCapacity()) { if (newCapacity < 0 || newCapacity > maxCapacity()) {
throw new IllegalArgumentException("newCapacity: " + newCapacity); throw new IllegalArgumentException("newCapacity: " + newCapacity);
} }
@ -181,6 +194,16 @@ public class DirectByteBuf extends AbstractByteBuf {
return this; return this;
} }
@Override
public ByteBufAllocator alloc() {
return alloc;
}
@Override
public ByteOrder order() {
return ByteOrder.BIG_ENDIAN;
}
@Override @Override
public boolean hasArray() { public boolean hasArray() {
return false; return false;
@ -198,34 +221,40 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override @Override
public byte getByte(int index) { public byte getByte(int index) {
assert !freed;
return buffer.get(index); return buffer.get(index);
} }
@Override @Override
public short getShort(int index) { public short getShort(int index) {
assert !freed;
return buffer.getShort(index); return buffer.getShort(index);
} }
@Override @Override
public int getUnsignedMedium(int index) { public int getUnsignedMedium(int index) {
assert !freed;
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) {
assert !freed;
return buffer.getInt(index); return buffer.getInt(index);
} }
@Override @Override
public long getLong(int index) { public long getLong(int index) {
assert !freed;
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) {
if (dst instanceof DirectByteBuf) { assert !freed;
DirectByteBuf bbdst = (DirectByteBuf) dst; if (dst instanceof UnpooledDirectByteBuf) {
ByteBuffer data = bbdst.tmpBuf; UnpooledDirectByteBuf bbdst = (UnpooledDirectByteBuf) dst;
ByteBuffer data = bbdst.internalNioBuffer();
data.clear().position(dstIndex).limit(dstIndex + length); data.clear().position(dstIndex).limit(dstIndex + length);
getBytes(index, data); getBytes(index, data);
} else if (buffer.hasArray()) { } else if (buffer.hasArray()) {
@ -238,6 +267,8 @@ public class DirectByteBuf 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) {
assert !freed;
ByteBuffer tmpBuf = internalNioBuffer();
try { try {
tmpBuf.clear().position(index).limit(index + length); tmpBuf.clear().position(index).limit(index + length);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
@ -250,7 +281,9 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf getBytes(int index, ByteBuffer dst) { public ByteBuf getBytes(int index, ByteBuffer dst) {
assert !freed;
int bytesToCopy = Math.min(capacity() - index, dst.remaining()); int bytesToCopy = Math.min(capacity() - index, dst.remaining());
ByteBuffer tmpBuf = internalNioBuffer();
try { try {
tmpBuf.clear().position(index).limit(index + bytesToCopy); tmpBuf.clear().position(index).limit(index + bytesToCopy);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
@ -263,18 +296,21 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf setByte(int index, int value) { public ByteBuf setByte(int index, int value) {
assert !freed;
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) {
assert !freed;
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) {
assert !freed;
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);
@ -283,21 +319,24 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf setInt(int index, int value) { public ByteBuf setInt(int index, int value) {
assert !freed;
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) {
assert !freed;
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) {
if (src instanceof DirectByteBuf) { assert !freed;
DirectByteBuf bbsrc = (DirectByteBuf) src; if (src instanceof UnpooledDirectByteBuf) {
ByteBuffer data = bbsrc.tmpBuf; UnpooledDirectByteBuf bbsrc = (UnpooledDirectByteBuf) src;
ByteBuffer data = bbsrc.internalNioBuffer();
data.clear().position(srcIndex).limit(srcIndex + length); data.clear().position(srcIndex).limit(srcIndex + length);
setBytes(index, data); setBytes(index, data);
@ -311,6 +350,8 @@ public class DirectByteBuf 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) {
assert !freed;
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);
return this; return this;
@ -318,6 +359,8 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf setBytes(int index, ByteBuffer src) { public ByteBuf setBytes(int index, ByteBuffer src) {
assert !freed;
ByteBuffer tmpBuf = internalNioBuffer();
if (src == tmpBuf) { if (src == tmpBuf) {
src = src.duplicate(); src = src.duplicate();
} }
@ -329,6 +372,7 @@ public class DirectByteBuf 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 {
assert !freed;
if (length == 0) { if (length == 0) {
return this; return this;
} }
@ -337,6 +381,7 @@ public class DirectByteBuf extends AbstractByteBuf {
out.write(buffer.array(), index + buffer.arrayOffset(), length); out.write(buffer.array(), index + buffer.arrayOffset(), length);
} else { } else {
byte[] tmp = new byte[length]; byte[] tmp = new byte[length];
ByteBuffer tmpBuf = internalNioBuffer();
tmpBuf.clear().position(index); tmpBuf.clear().position(index);
tmpBuf.get(tmp); tmpBuf.get(tmp);
out.write(tmp); out.write(tmp);
@ -346,33 +391,38 @@ public class DirectByteBuf 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 {
assert !freed;
if (length == 0) { if (length == 0) {
return 0; return 0;
} }
ByteBuffer tmpBuf = internalNioBuffer();
tmpBuf.clear().position(index).limit(index + length); tmpBuf.clear().position(index).limit(index + length);
return out.write(tmpBuf); return out.write(tmpBuf);
} }
@Override @Override
public int setBytes(int index, InputStream in, int length) throws IOException { public int setBytes(int index, InputStream in, int length) throws IOException {
assert !freed;
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 {
byte[] tmp = new byte[length]; byte[] tmp = new byte[length];
int readBytes = in.read(tmp); int readBytes = in.read(tmp);
tmpBuf.clear().position(index); ByteBuffer tmpNioBuf = internalNioBuffer();
tmpBuf.put(tmp); tmpNioBuf.clear().position(index);
tmpNioBuf.put(tmp);
return readBytes; return readBytes;
} }
} }
@Override @Override
public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
tmpBuf.clear().position(index).limit(index + length); assert !freed;
ByteBuffer tmpNioBuf = internalNioBuffer();
tmpNioBuf.clear().position(index).limit(index + length);
try { try {
return in.read(tmpBuf); return in.read(tmpNioBuf);
} catch (ClosedChannelException e) { } catch (ClosedChannelException e) {
return -1; return -1;
} }
@ -385,10 +435,11 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuffer nioBuffer(int index, int length) { public ByteBuffer nioBuffer(int index, int length) {
assert !freed;
if (index == 0 && length == capacity()) { if (index == 0 && length == capacity()) {
return buffer.duplicate(); return buffer.duplicate();
} else { } else {
return ((ByteBuffer) tmpBuf.clear().position(index).limit(index + length)).slice(); return ((ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length)).slice();
} }
} }
@ -404,9 +455,10 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf copy(int index, int length) { public ByteBuf copy(int index, int length) {
assert !freed;
ByteBuffer src; ByteBuffer src;
try { try {
src = (ByteBuffer) tmpBuf.clear().position(index).limit(index + length); src = (ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw new IndexOutOfBoundsException("Too many bytes to read - Need " + (index + length)); throw new IndexOutOfBoundsException("Too many bytes to read - Need " + (index + length));
} }
@ -416,67 +468,52 @@ public class DirectByteBuf extends AbstractByteBuf {
dst.put(src); dst.put(src);
dst.order(order()); dst.order(order());
dst.clear(); dst.clear();
return new DirectByteBuf(dst, maxCapacity()); return new UnpooledDirectByteBuf(alloc(), dst, maxCapacity());
} }
@Override @Override
public Unsafe unsafe() { public ByteBuffer internalNioBuffer() {
return unsafe; ByteBuffer tmpNioBuf = this.tmpNioBuf;
if (tmpNioBuf == null) {
this.tmpNioBuf = tmpNioBuf = buffer.duplicate();
}
return tmpNioBuf;
} }
private class DirectUnsafe implements Unsafe { @Override
@Override public ByteBuffer[] internalNioBuffers() {
public ByteBuffer nioBuffer() { throw new UnsupportedOperationException();
return tmpBuf; }
@Override
public void discardSomeReadBytes() {
final int readerIndex = readerIndex();
if (readerIndex == writerIndex()) {
discardReadBytes();
return;
} }
@Override if (readerIndex > 0 && readerIndex >= capacity >>> 1) {
public ByteBuffer[] nioBuffers() { discardReadBytes();
throw new UnsupportedOperationException(); }
}
@Override
public void free() {
if (freed) {
return;
} }
@Override freed = true;
public ByteBuf newBuffer(int initialCapacity) { if (doNotFree) {
return new DirectByteBuf(initialCapacity, Math.max(initialCapacity, maxCapacity())); return;
} }
@Override freeDirect(buffer);
public void discardSomeReadBytes() { }
final int readerIndex = readerIndex();
if (readerIndex == writerIndex()) {
discardReadBytes();
return;
}
if (readerIndex > 0 && readerIndex >= capacity >>> 1) { @Override
discardReadBytes(); public ByteBuf unwrap() {
} return null;
}
@Override
public void acquire() {
if (refCnt <= 0) {
throw new IllegalStateException();
}
refCnt ++;
}
@Override
public void release() {
if (refCnt <= 0) {
throw new IllegalStateException();
}
refCnt --;
if (refCnt == 0) {
if (doNotFree) {
doNotFree = false;
} else {
freeDirect(buffer);
}
buffer = null;
tmpBuf = null;
}
}
} }
} }

View File

@ -27,12 +27,12 @@ import java.nio.channels.ScatteringByteChannel;
/** /**
* Big endian Java heap buffer implementation. * Big endian Java heap buffer implementation.
*/ */
public class HeapByteBuf extends AbstractByteBuf { public class UnpooledHeapByteBuf extends AbstractByteBuf {
private final Unsafe unsafe = new HeapUnsafe();
private final ByteBufAllocator alloc;
private byte[] array; private byte[] array;
private ByteBuffer nioBuf; private ByteBuffer tmpNioBuf;
private boolean freed;
/** /**
* Creates a new heap buffer with a newly allocated byte array. * Creates a new heap buffer with a newly allocated byte array.
@ -40,8 +40,8 @@ public class HeapByteBuf extends AbstractByteBuf {
* @param initialCapacity the initial capacity of the underlying byte array * @param initialCapacity the initial capacity of the underlying byte array
* @param maxCapacity the max capacity of the underlying byte array * @param maxCapacity the max capacity of the underlying byte array
*/ */
public HeapByteBuf(int initialCapacity, int maxCapacity) { public UnpooledHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
this(new byte[initialCapacity], 0, 0, maxCapacity); this(alloc, new byte[initialCapacity], 0, 0, maxCapacity);
} }
/** /**
@ -50,12 +50,18 @@ public class HeapByteBuf extends AbstractByteBuf {
* @param initialArray the initial underlying byte array * @param initialArray the initial underlying byte array
* @param maxCapacity the max capacity of the underlying byte array * @param maxCapacity the max capacity of the underlying byte array
*/ */
public HeapByteBuf(byte[] initialArray, int maxCapacity) { public UnpooledHeapByteBuf(ByteBufAllocator alloc, byte[] initialArray, int maxCapacity) {
this(initialArray, 0, initialArray.length, maxCapacity); this(alloc, initialArray, 0, initialArray.length, maxCapacity);
} }
private HeapByteBuf(byte[] initialArray, int readerIndex, int writerIndex, int maxCapacity) { private UnpooledHeapByteBuf(
super(ByteOrder.BIG_ENDIAN, maxCapacity); ByteBufAllocator alloc, byte[] initialArray, int readerIndex, int writerIndex, int maxCapacity) {
super(maxCapacity);
if (alloc == null) {
throw new NullPointerException("alloc");
}
if (initialArray == null) { if (initialArray == null) {
throw new NullPointerException("initialArray"); throw new NullPointerException("initialArray");
} }
@ -64,13 +70,24 @@ public class HeapByteBuf extends AbstractByteBuf {
"initialCapacity(%d) > maxCapacity(%d)", initialArray.length, maxCapacity)); "initialCapacity(%d) > maxCapacity(%d)", initialArray.length, maxCapacity));
} }
this.alloc = alloc;
setArray(initialArray); setArray(initialArray);
setIndex(readerIndex, writerIndex); setIndex(readerIndex, writerIndex);
} }
private void setArray(byte[] initialArray) { private void setArray(byte[] initialArray) {
array = initialArray; array = initialArray;
nioBuf = ByteBuffer.wrap(initialArray); tmpNioBuf = null;
}
@Override
public ByteBufAllocator alloc() {
return alloc;
}
@Override
public ByteOrder order() {
return ByteOrder.BIG_ENDIAN;
} }
@Override @Override
@ -85,6 +102,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf capacity(int newCapacity) { public ByteBuf capacity(int newCapacity) {
assert !freed;
if (newCapacity < 0 || newCapacity > maxCapacity()) { if (newCapacity < 0 || newCapacity > maxCapacity()) {
throw new IllegalArgumentException("newCapacity: " + newCapacity); throw new IllegalArgumentException("newCapacity: " + newCapacity);
} }
@ -118,6 +136,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override @Override
public byte[] array() { public byte[] array() {
assert !freed;
return array; return array;
} }
@ -128,13 +147,15 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override @Override
public byte getByte(int index) { public byte getByte(int index) {
assert !freed;
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) {
if (dst instanceof HeapByteBuf) { assert !freed;
getBytes(index, ((HeapByteBuf) dst).array, dstIndex, length); if (dst instanceof UnpooledHeapByteBuf) {
getBytes(index, ((UnpooledHeapByteBuf) dst).array, dstIndex, length);
} else { } else {
dst.setBytes(dstIndex, array, index, length); dst.setBytes(dstIndex, array, index, length);
} }
@ -143,39 +164,43 @@ public class HeapByteBuf 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) {
assert !freed;
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) {
assert !freed;
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) public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
throws IOException { assert !freed;
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) public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
throws IOException { assert !freed;
return out.write((ByteBuffer) nioBuf.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) {
assert !freed;
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) {
if (src instanceof HeapByteBuf) { assert !freed;
setBytes(index, ((HeapByteBuf) src).array, srcIndex, length); if (src instanceof UnpooledHeapByteBuf) {
setBytes(index, ((UnpooledHeapByteBuf) src).array, srcIndex, length);
} else { } else {
src.getBytes(srcIndex, array, index, length); src.getBytes(srcIndex, array, index, length);
} }
@ -184,25 +209,29 @@ public class HeapByteBuf 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) {
assert !freed;
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) {
assert !freed;
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 {
assert !freed;
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 {
assert !freed;
try { try {
return in.read((ByteBuffer) nioBuf.clear().position(index).limit(index + length)); return in.read((ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length));
} catch (ClosedChannelException e) { } catch (ClosedChannelException e) {
return -1; return -1;
} }
@ -215,6 +244,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuffer nioBuffer(int index, int length) { public ByteBuffer nioBuffer(int index, int length) {
assert !freed;
return ByteBuffer.wrap(array, index, length); return ByteBuffer.wrap(array, index, length);
} }
@ -230,11 +260,13 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override @Override
public short getShort(int index) { public short getShort(int index) {
assert !freed;
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) {
assert !freed;
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;
@ -242,6 +274,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override @Override
public int getInt(int index) { public int getInt(int index) {
assert !freed;
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 |
@ -250,6 +283,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override @Override
public long getLong(int index) { public long getLong(int index) {
assert !freed;
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 |
@ -262,6 +296,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf setShort(int index, int value) { public ByteBuf setShort(int index, int value) {
assert !freed;
array[index] = (byte) (value >>> 8); array[index] = (byte) (value >>> 8);
array[index + 1] = (byte) value; array[index + 1] = (byte) value;
return this; return this;
@ -269,6 +304,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf setMedium(int index, int value) { public ByteBuf setMedium(int index, int value) {
assert !freed;
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;
@ -277,6 +313,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf setInt(int index, int value) { public ByteBuf setInt(int index, int value) {
assert !freed;
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);
@ -286,6 +323,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf setLong(int index, long value) { public ByteBuf setLong(int index, long value) {
assert !freed;
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);
@ -299,6 +337,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override @Override
public ByteBuf copy(int index, int length) { public ByteBuf copy(int index, int length) {
assert !freed;
if (index < 0 || length < 0 || index + length > array.length) { if (index < 0 || length < 0 || index + length > array.length) {
throw new IndexOutOfBoundsException("Too many bytes to copy - Need " throw new IndexOutOfBoundsException("Too many bytes to copy - Need "
+ (index + length) + ", maximum is " + array.length); + (index + length) + ", maximum is " + array.length);
@ -306,61 +345,43 @@ public class HeapByteBuf extends AbstractByteBuf {
byte[] copiedArray = new byte[length]; byte[] copiedArray = new byte[length];
System.arraycopy(array, index, copiedArray, 0, length); System.arraycopy(array, index, copiedArray, 0, length);
return new HeapByteBuf(copiedArray, maxCapacity()); return new UnpooledHeapByteBuf(alloc(), copiedArray, maxCapacity());
} }
@Override @Override
public Unsafe unsafe() { public ByteBuffer internalNioBuffer() {
return unsafe; ByteBuffer tmpNioBuf = this.tmpNioBuf;
if (tmpNioBuf == null) {
this.tmpNioBuf = tmpNioBuf = ByteBuffer.wrap(array);
}
return tmpNioBuf;
} }
private class HeapUnsafe implements Unsafe { @Override
@Override public ByteBuffer[] internalNioBuffers() {
public ByteBuffer nioBuffer() { throw new UnsupportedOperationException();
return nioBuf; }
@Override
public void discardSomeReadBytes() {
final int readerIndex = readerIndex();
if (readerIndex == writerIndex()) {
discardReadBytes();
return;
} }
@Override if (readerIndex > 0 && readerIndex >= capacity() >>> 1) {
public ByteBuffer[] nioBuffers() { discardReadBytes();
throw new UnsupportedOperationException();
} }
}
@Override @Override
public ByteBuf newBuffer(int initialCapacity) { public void free() {
return new HeapByteBuf(initialCapacity, Math.max(initialCapacity, maxCapacity())); freed = true;
} }
@Override @Override
public void discardSomeReadBytes() { public ByteBuf unwrap() {
final int readerIndex = readerIndex(); return null;
if (readerIndex == writerIndex()) {
discardReadBytes();
return;
}
if (readerIndex > 0 && readerIndex >= capacity() >>> 1) {
discardReadBytes();
}
}
@Override
public void acquire() {
if (refCnt <= 0) {
throw new IllegalStateException();
}
refCnt ++;
}
@Override
public void release() {
if (refCnt <= 0) {
throw new IllegalStateException();
}
refCnt --;
if (refCnt == 0) {
array = null;
nioBuf = null;
}
}
} }
} }

View File

@ -0,0 +1,57 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.buffer;
import java.nio.ByteBuffer;
public interface UnsafeByteBuf extends ByteBuf {
/**
* Returns the internal NIO buffer that is reused for I/O.
*
* @throws UnsupportedOperationException if the buffer has no internal NIO buffer
*/
ByteBuffer internalNioBuffer();
/**
* Returns the internal NIO buffer array that is reused for I/O.
*
* @throws UnsupportedOperationException if the buffer has no internal NIO buffer array
*/
ByteBuffer[] internalNioBuffers();
/**
* Similar to {@link ByteBuf#discardReadBytes()} except that this method might discard
* some, all, or none of read bytes depending on its internal implementation to reduce
* overall memory bandwidth consumption at the cost of potentially additional memory
* consumption.
*/
void discardSomeReadBytes();
/**
* Deallocates the internal memory block of this buffer or returns it to the {@link ByteBufAllocator} it came
* from. The result of accessing a released buffer is unspecified and can even cause JVM crash.
*/
void free();
/**
* Return the underlying buffer instance if this buffer is a wrapper.
*
* @return {@code null} if this buffer is not a wrapper
*/
ByteBuf unwrap();
}

View File

@ -1,205 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.buffer;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
/**
* The common interface for buffer wrappers and derived buffers. Most users won't
* need to use this interface. It is used internally in most cases.
*/
public interface WrappedByteBuf extends ByteBuf {
/**
* Returns this buffer's parent that this buffer is wrapping.
*/
ByteBuf unwrap();
@Override
WrappedByteBuf capacity(int newCapacity);
@Override
WrappedByteBuf readerIndex(int readerIndex);
@Override
WrappedByteBuf writerIndex(int writerIndex);
@Override
WrappedByteBuf setIndex(int readerIndex, int writerIndex);
@Override
WrappedByteBuf clear();
@Override
WrappedByteBuf markReaderIndex();
@Override
WrappedByteBuf resetReaderIndex();
@Override
WrappedByteBuf markWriterIndex();
@Override
WrappedByteBuf resetWriterIndex();
@Override
WrappedByteBuf discardReadBytes();
@Override
WrappedByteBuf ensureWritableBytes(int minWritableBytes);
@Override
WrappedByteBuf getBytes(int index, ByteBuf dst);
@Override
WrappedByteBuf getBytes(int index, ByteBuf dst, int length);
@Override
WrappedByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length);
@Override
WrappedByteBuf getBytes(int index, byte[] dst);
@Override
WrappedByteBuf getBytes(int index, byte[] dst, int dstIndex, int length);
@Override
WrappedByteBuf getBytes(int index, ByteBuffer dst);
@Override
WrappedByteBuf getBytes(int index, OutputStream out, int length) throws IOException;
@Override
WrappedByteBuf setBoolean(int index, boolean value);
@Override
WrappedByteBuf setByte(int index, int value);
@Override
WrappedByteBuf setShort(int index, int value);
@Override
WrappedByteBuf setMedium(int index, int value);
@Override
WrappedByteBuf setInt(int index, int value);
@Override
WrappedByteBuf setLong(int index, long value);
@Override
WrappedByteBuf setChar(int index, int value);
@Override
WrappedByteBuf setFloat(int index, float value);
@Override
WrappedByteBuf setDouble(int index, double value);
@Override
WrappedByteBuf setBytes(int index, ByteBuf src);
@Override
WrappedByteBuf setBytes(int index, ByteBuf src, int length);
@Override
WrappedByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length);
@Override
WrappedByteBuf setBytes(int index, byte[] src);
@Override
WrappedByteBuf setBytes(int index, byte[] src, int srcIndex, int length);
@Override
WrappedByteBuf setBytes(int index, ByteBuffer src);
@Override
WrappedByteBuf setZero(int index, int length);
@Override
WrappedByteBuf readBytes(ByteBuf dst);
@Override
WrappedByteBuf readBytes(ByteBuf dst, int length);
@Override
WrappedByteBuf readBytes(ByteBuf dst, int dstIndex, int length);
@Override
WrappedByteBuf readBytes(byte[] dst);
@Override
WrappedByteBuf readBytes(byte[] dst, int dstIndex, int length);
@Override
WrappedByteBuf readBytes(ByteBuffer dst);
@Override
WrappedByteBuf readBytes(OutputStream out, int length) throws IOException;
@Override
WrappedByteBuf skipBytes(int length);
@Override
WrappedByteBuf writeBoolean(boolean value);
@Override
WrappedByteBuf writeByte(int value);
@Override
WrappedByteBuf writeShort(int value);
@Override
WrappedByteBuf writeMedium(int value);
@Override
WrappedByteBuf writeInt(int value);
@Override
WrappedByteBuf writeLong(long value);
@Override
WrappedByteBuf writeChar(int value);
@Override
WrappedByteBuf writeFloat(float value);
@Override
WrappedByteBuf writeDouble(double value);
@Override
WrappedByteBuf writeBytes(ByteBuf src);
@Override
WrappedByteBuf writeBytes(ByteBuf src, int length);
@Override
WrappedByteBuf writeBytes(ByteBuf src, int srcIndex, int length);
@Override
WrappedByteBuf writeBytes(byte[] src);
@Override
WrappedByteBuf writeBytes(byte[] src, int srcIndex, int length);
@Override
WrappedByteBuf writeBytes(ByteBuffer src);
@Override
WrappedByteBuf writeZero(int length);
}

View File

@ -15,10 +15,10 @@
*/ */
package io.netty.buffer; package io.netty.buffer;
import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.*;
/** /**
* Tests big-endian heap channel buffers * Tests big-endian heap channel buffers
*/ */
@ -39,7 +39,12 @@ public class BigEndianHeapChannelBufferTest extends AbstractChannelBufferTest {
} }
@Test(expected = NullPointerException.class) @Test(expected = NullPointerException.class)
public void shouldNotAllowNullInConstructor() { public void shouldNotAllowNullInConstructor1() {
new HeapByteBuf(null, 0); new UnpooledHeapByteBuf(null, new byte[1], 0);
}
@Test(expected = NullPointerException.class)
public void shouldNotAllowNullInConstructor2() {
new UnpooledHeapByteBuf(UnpooledByteBufAllocator.HEAP_BY_DEFAULT, null, 0);
} }
} }

View File

@ -15,10 +15,10 @@
*/ */
package io.netty.buffer; package io.netty.buffer;
import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.*;
/** /**
* Tests duplicated channel buffers * Tests duplicated channel buffers
*/ */
@ -28,7 +28,7 @@ public class DuplicateChannelBufferTest extends AbstractChannelBufferTest {
@Override @Override
protected ByteBuf newBuffer(int length) { protected ByteBuf newBuffer(int length) {
buffer = new DuplicatedByteBuf(Unpooled.buffer(length)); buffer = new DuplicatedByteBuf((UnsafeByteBuf) Unpooled.buffer(length));
assertEquals(0, buffer.writerIndex()); assertEquals(0, buffer.writerIndex());
return buffer; return buffer;
} }

View File

@ -15,9 +15,7 @@
*/ */
package io.netty.buffer; package io.netty.buffer;
import static io.netty.buffer.Unpooled.*; import org.junit.Test;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -26,7 +24,9 @@ import java.nio.ByteBuffer;
import java.nio.channels.GatheringByteChannel; import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel; import java.nio.channels.ScatteringByteChannel;
import org.junit.Test; import static io.netty.buffer.Unpooled.*;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
/** /**
* Tests read-only channel buffers * Tests read-only channel buffers
@ -46,7 +46,7 @@ public class ReadOnlyChannelBufferTest {
@Test @Test
public void testUnwrap() { public void testUnwrap() {
ByteBuf buf = buffer(1); ByteBuf buf = buffer(1);
assertSame(buf, ((WrappedByteBuf) Unpooled.unmodifiableBuffer(buf)).unwrap()); assertSame(buf, ((UnsafeByteBuf) Unpooled.unmodifiableBuffer(buf)).unwrap());
} }
@Test @Test
@ -74,7 +74,7 @@ public class ReadOnlyChannelBufferTest {
@Test @Test
public void shouldForwardReadCallsBlindly() throws Exception { public void shouldForwardReadCallsBlindly() throws Exception {
ByteBuf buf = createStrictMock(ByteBuf.class); ByteBuf buf = createStrictMock(UnsafeByteBuf.class);
expect(buf.order()).andReturn(BIG_ENDIAN).anyTimes(); expect(buf.order()).andReturn(BIG_ENDIAN).anyTimes();
expect(buf.maxCapacity()).andReturn(65536).anyTimes(); expect(buf.maxCapacity()).andReturn(65536).anyTimes();
expect(buf.readerIndex()).andReturn(0).anyTimes(); expect(buf.readerIndex()).andReturn(0).anyTimes();

View File

@ -16,7 +16,6 @@
package io.netty.handler.codec.spdy; package io.netty.handler.codec.spdy;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
@ -64,7 +63,7 @@ public abstract class SpdyOrHttpChooser extends ChannelHandlerAdapter implements
@Override @Override
public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
return Unpooled.buffer(); return ctx.alloc().buffer();
} }
@Override @Override

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.handler.codec.spdy; package io.netty.handler.codec.spdy;
import io.netty.buffer.ChannelBuf;
import io.netty.buffer.MessageBuf; import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
@ -95,6 +96,16 @@ public class SpdySessionHandler
return Unpooled.messageBuffer(); return Unpooled.messageBuffer();
} }
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
// Nothing to free
}
@Override
public void freeOutboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
// Nothing to free
}
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception {
MessageBuf<Object> in = ctx.inboundMessageBuffer(); MessageBuf<Object> in = ctx.inboundMessageBuffer();

View File

@ -16,6 +16,7 @@
package io.netty.handler.codec; package io.netty.handler.codec;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.UnsafeByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundByteHandlerAdapter; import io.netty.channel.ChannelInboundByteHandlerAdapter;
@ -70,7 +71,7 @@ public abstract class ByteToByteDecoder extends ChannelInboundByteHandlerAdapter
} }
} }
in.unsafe().discardSomeReadBytes(); ((UnsafeByteBuf) in).discardSomeReadBytes();
if (out.readableBytes() > oldOutSize) { if (out.readableBytes() > oldOutSize) {
ctx.fireInboundBufferUpdated(); ctx.fireInboundBufferUpdated();
} }

View File

@ -16,6 +16,7 @@
package io.netty.handler.codec; package io.netty.handler.codec;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.UnsafeByteBuf;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundByteHandlerAdapter; import io.netty.channel.ChannelOutboundByteHandlerAdapter;
@ -43,7 +44,7 @@ public abstract class ByteToByteEncoder extends ChannelOutboundByteHandlerAdapte
} }
} }
in.unsafe().discardSomeReadBytes(); ((UnsafeByteBuf) in).discardSomeReadBytes();
ctx.flush(future); ctx.flush(future);
} }

View File

@ -16,12 +16,13 @@
package io.netty.handler.codec; package io.netty.handler.codec;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.ChannelBuf;
import io.netty.buffer.UnsafeByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelHandlerUtil;
import io.netty.channel.ChannelInboundByteHandler; import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelHandlerUtil;
public abstract class ByteToMessageDecoder<O> public abstract class ByteToMessageDecoder<O>
extends ChannelInboundHandlerAdapter implements ChannelInboundByteHandler { extends ChannelInboundHandlerAdapter implements ChannelInboundByteHandler {
@ -36,7 +37,12 @@ public abstract class ByteToMessageDecoder<O>
@Override @Override
public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
return Unpooled.buffer(); return ctx.alloc().buffer();
}
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
((UnsafeByteBuf) buf).free();
} }
@Override @Override
@ -92,7 +98,7 @@ public abstract class ByteToMessageDecoder<O>
break; break;
} }
} catch (Throwable t) { } catch (Throwable t) {
in.unsafe().discardSomeReadBytes(); ((UnsafeByteBuf) in).discardSomeReadBytes();
if (decoded) { if (decoded) {
decoded = false; decoded = false;
@ -107,7 +113,7 @@ public abstract class ByteToMessageDecoder<O>
} }
} }
in.unsafe().discardSomeReadBytes(); ((UnsafeByteBuf) in).discardSomeReadBytes();
if (decoded) { if (decoded) {
ctx.fireInboundBufferUpdated(); ctx.fireInboundBufferUpdated();

View File

@ -16,7 +16,6 @@
package io.netty.handler.codec; package io.netty.handler.codec;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
/** /**
@ -68,7 +67,7 @@ public class FixedLengthFrameDecoder extends ByteToMessageDecoder<Object> {
@Override @Override
public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
if (allocateFullBuffer) { if (allocateFullBuffer) {
return Unpooled.buffer(frameLength); return ctx.alloc().buffer(frameLength);
} else { } else {
return super.newInboundBuffer(ctx); return super.newInboundBuffer(ctx);
} }

View File

@ -16,6 +16,7 @@
package io.netty.handler.codec; package io.netty.handler.codec;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.serialization.ObjectDecoder; import io.netty.handler.codec.serialization.ObjectDecoder;
@ -426,7 +427,7 @@ public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder<Object> {
* is overridden to avoid memory copy. * is overridden to avoid memory copy.
*/ */
protected ByteBuf extractFrame(ByteBuf buffer, int index, int length) { protected ByteBuf extractFrame(ByteBuf buffer, int index, int length) {
ByteBuf frame = buffer.unsafe().newBuffer(length); ByteBuf frame = Unpooled.buffer(length);
frame.writeBytes(buffer, index, length); frame.writeBytes(buffer, index, length);
return frame; return frame;
} }

View File

@ -15,13 +15,14 @@
*/ */
package io.netty.handler.codec; package io.netty.handler.codec;
import io.netty.buffer.ChannelBuf;
import io.netty.buffer.MessageBuf; import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelHandlerUtil;
import io.netty.channel.ChannelInboundMessageHandler; import io.netty.channel.ChannelInboundMessageHandler;
import io.netty.channel.ChannelOutboundMessageHandler; import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.ChannelHandlerUtil;
public abstract class MessageToMessageCodec<INBOUND_IN, INBOUND_OUT, OUTBOUND_IN, OUTBOUND_OUT> public abstract class MessageToMessageCodec<INBOUND_IN, INBOUND_OUT, OUTBOUND_IN, OUTBOUND_OUT>
extends ChannelHandlerAdapter extends ChannelHandlerAdapter
@ -72,6 +73,11 @@ public abstract class MessageToMessageCodec<INBOUND_IN, INBOUND_OUT, OUTBOUND_IN
return decoder.newInboundBuffer(ctx); return decoder.newInboundBuffer(ctx);
} }
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
// Nothing to free
}
@Override @Override
public void inboundBufferUpdated( public void inboundBufferUpdated(
ChannelHandlerContext ctx) throws Exception { ChannelHandlerContext ctx) throws Exception {
@ -83,6 +89,11 @@ public abstract class MessageToMessageCodec<INBOUND_IN, INBOUND_OUT, OUTBOUND_IN
return encoder.newOutboundBuffer(ctx); return encoder.newOutboundBuffer(ctx);
} }
@Override
public void freeOutboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
// Nothing to free
}
@Override @Override
public void flush(ChannelHandlerContext ctx, ChannelFuture future) throws Exception { public void flush(ChannelHandlerContext ctx, ChannelFuture future) throws Exception {
encoder.flush(ctx, future); encoder.flush(ctx, future);

View File

@ -15,12 +15,13 @@
*/ */
package io.netty.handler.codec; package io.netty.handler.codec;
import io.netty.buffer.ChannelBuf;
import io.netty.buffer.MessageBuf; import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelHandlerUtil;
import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInboundMessageHandler; import io.netty.channel.ChannelInboundMessageHandler;
import io.netty.channel.ChannelHandlerUtil;
public abstract class MessageToMessageDecoder<I, O> public abstract class MessageToMessageDecoder<I, O>
extends ChannelInboundHandlerAdapter implements ChannelInboundMessageHandler<I> { extends ChannelInboundHandlerAdapter implements ChannelInboundMessageHandler<I> {
@ -36,6 +37,11 @@ public abstract class MessageToMessageDecoder<I, O>
return Unpooled.messageBuffer(); return Unpooled.messageBuffer();
} }
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
// Nothing to free
}
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) public void inboundBufferUpdated(ChannelHandlerContext ctx)
throws Exception { throws Exception {

View File

@ -16,12 +16,12 @@
package io.netty.handler.codec; package io.netty.handler.codec;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.UnsafeByteBuf;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelHandlerUtil; import io.netty.channel.ChannelHandlerUtil;
import io.netty.channel.ChannelPipeline;
import io.netty.util.internal.Signal; import io.netty.util.internal.Signal;
/** /**
@ -282,8 +282,8 @@ public abstract class ReplayingDecoder<O, S> extends ByteToMessageDecoder<O> {
static final Signal REPLAY = new Signal(ReplayingDecoder.class.getName() + ".REPLAY"); static final Signal REPLAY = new Signal(ReplayingDecoder.class.getName() + ".REPLAY");
private final ByteBuf cumulation = Unpooled.buffer(); private ByteBuf cumulation;
private final ReplayingDecoderBuffer replayable = new ReplayingDecoderBuffer(cumulation); private ReplayingDecoderBuffer replayable;
private S state; private S state;
private int checkpoint = -1; private int checkpoint = -1;
@ -357,6 +357,8 @@ public abstract class ReplayingDecoder<O, S> extends ByteToMessageDecoder<O> {
@Override @Override
public ByteBuf newInboundBuffer( public ByteBuf newInboundBuffer(
ChannelHandlerContext ctx) throws Exception { ChannelHandlerContext ctx) throws Exception {
cumulation = ctx.alloc().buffer();
replayable = new ReplayingDecoderBuffer(cumulation);
return cumulation; return cumulation;
} }
@ -457,7 +459,7 @@ public abstract class ReplayingDecoder<O, S> extends ByteToMessageDecoder<O> {
private void fireInboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) { private void fireInboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) {
final int oldReaderIndex = in.readerIndex(); final int oldReaderIndex = in.readerIndex();
in.unsafe().discardSomeReadBytes(); ((UnsafeByteBuf) in).discardSomeReadBytes();
final int newReaderIndex = in.readerIndex(); final int newReaderIndex = in.readerIndex();
checkpoint -= oldReaderIndex - newReaderIndex; checkpoint -= oldReaderIndex - newReaderIndex;
ctx.fireInboundBufferUpdated(); ctx.fireInboundBufferUpdated();

View File

@ -16,10 +16,12 @@
package io.netty.handler.codec; package io.netty.handler.codec;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufIndexFinder; import io.netty.buffer.ByteBufIndexFinder;
import io.netty.buffer.ChannelBufType; import io.netty.buffer.ChannelBufType;
import io.netty.buffer.SwappedByteBuf; import io.netty.buffer.SwappedByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.buffer.UnsafeByteBuf;
import io.netty.util.internal.Signal; import io.netty.util.internal.Signal;
import java.io.IOException; import java.io.IOException;
@ -31,7 +33,7 @@ import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel; import java.nio.channels.ScatteringByteChannel;
import java.nio.charset.Charset; import java.nio.charset.Charset;
class ReplayingDecoderBuffer implements ByteBuf { class ReplayingDecoderBuffer implements UnsafeByteBuf {
private static final Signal REPLAY = ReplayingDecoder.REPLAY; private static final Signal REPLAY = ReplayingDecoder.REPLAY;
@ -79,8 +81,8 @@ class ReplayingDecoderBuffer implements ByteBuf {
} }
@Override @Override
public boolean isPooled() { public ByteBufAllocator alloc() {
return false; return buffer.alloc();
} }
@Override @Override
@ -849,7 +851,27 @@ class ReplayingDecoderBuffer implements ByteBuf {
} }
@Override @Override
public Unsafe unsafe() { public ByteBuffer internalNioBuffer() {
throw new UnreplayableOperationException();
}
@Override
public ByteBuffer[] internalNioBuffers() {
throw new UnreplayableOperationException();
}
@Override
public void discardSomeReadBytes() {
throw new UnreplayableOperationException();
}
@Override
public void free() {
throw new UnreplayableOperationException();
}
@Override
public ByteBuf unwrap() {
throw new UnreplayableOperationException(); throw new UnreplayableOperationException();
} }
} }

View File

@ -20,6 +20,7 @@
package io.netty.handler.codec.base64; package io.netty.handler.codec.base64;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
/** /**
* Utility class for {@link ByteBuf} that encodes and decodes to and from * Utility class for {@link ByteBuf} that encodes and decodes to and from
@ -115,10 +116,10 @@ public final class Base64 {
} }
int len43 = len * 4 / 3; int len43 = len * 4 / 3;
ByteBuf dest = src.unsafe().newBuffer( ByteBuf dest = Unpooled.buffer(
len43 + len43 +
(len % 3 > 0? 4 : 0) + // Account for padding (len % 3 > 0 ? 4 : 0) + // Account for padding
(breakLines? len43 / MAX_LINE_LENGTH : 0)).order(src.order()); // New lines (breakLines ? len43 / MAX_LINE_LENGTH : 0)).order(src.order()); // New lines
int d = 0; int d = 0;
int e = 0; int e = 0;
int len2 = len - 2; int len2 = len - 2;
@ -219,7 +220,7 @@ public final class Base64 {
byte[] DECODABET = decodabet(dialect); byte[] DECODABET = decodabet(dialect);
int len34 = len * 3 / 4; int len34 = len * 3 / 4;
ByteBuf dest = src.unsafe().newBuffer(len34).order(src.order()); // Upper limit on size of output ByteBuf dest = Unpooled.buffer(len34).order(src.order()); // Upper limit on size of output
int outBuffPosn = 0; int outBuffPosn = 0;
byte[] b4 = new byte[4]; byte[] b4 = new byte[4];

View File

@ -17,6 +17,7 @@ package io.netty.handler.codec.serialization;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufOutputStream; import io.netty.buffer.ByteBufOutputStream;
import io.netty.buffer.UnsafeByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder; import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.Attribute; import io.netty.util.Attribute;
@ -97,7 +98,7 @@ public class CompatibleObjectEncoder extends MessageToByteEncoder<Object> {
oos.reset(); oos.reset();
// Also discard the byproduct to avoid OOM on the sending side. // Also discard the byproduct to avoid OOM on the sending side.
out.unsafe().discardSomeReadBytes(); ((UnsafeByteBuf) out).discardSomeReadBytes();
} }
} }

View File

@ -15,8 +15,12 @@
*/ */
package io.netty.util.internal; package io.netty.util.internal;
import sun.misc.Cleaner;
import java.lang.reflect.Field;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedActionException; import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction; import java.security.PrivilegedExceptionAction;
@ -38,11 +42,11 @@ public final class DetectionUtil {
private static final int JAVA_VERSION = javaVersion0(); private static final int JAVA_VERSION = javaVersion0();
private static final boolean HAS_UNSAFE = hasUnsafe(AtomicInteger.class.getClassLoader()); private static final boolean HAS_UNSAFE = hasUnsafe(AtomicInteger.class.getClassLoader());
private static final boolean CAN_FREE_DIRECT_BUFFER;
private static final boolean IS_WINDOWS; private static final boolean IS_WINDOWS;
private static final boolean IS_ROOT; private static final boolean IS_ROOT;
static { static {
Pattern PERMISSION_DENIED = Pattern.compile(".*permission.*denied.*"); Pattern PERMISSION_DENIED = Pattern.compile(".*permission.*denied.*");
String os = SystemPropertyUtil.get("os.name", "").toLowerCase(Locale.UK); String os = SystemPropertyUtil.get("os.name", "").toLowerCase(Locale.UK);
// windows // windows
@ -82,6 +86,21 @@ public final class DetectionUtil {
} }
IS_ROOT = root; IS_ROOT = root;
boolean canFreeDirectBuffer = false;
try {
ByteBuffer direct = ByteBuffer.allocateDirect(1);
Field cleanerField = direct.getClass().getDeclaredField("cleaner");
cleanerField.setAccessible(true);
Cleaner cleaner = (Cleaner) cleanerField.get(direct);
cleaner.clean();
canFreeDirectBuffer = true;
} catch (Throwable t) {
// Ignore.
}
CAN_FREE_DIRECT_BUFFER = canFreeDirectBuffer;
} }
/** /**
@ -107,6 +126,10 @@ public final class DetectionUtil {
return JAVA_VERSION; return JAVA_VERSION;
} }
public static boolean canFreeDirectBuffer() {
return CAN_FREE_DIRECT_BUFFER;
}
private static boolean hasUnsafe(ClassLoader loader) { private static boolean hasUnsafe(ClassLoader loader) {
boolean noUnsafe = SystemPropertyUtil.getBoolean("io.netty.noUnsafe", false); boolean noUnsafe = SystemPropertyUtil.getBoolean("io.netty.noUnsafe", false);
if (noUnsafe) { if (noUnsafe) {

View File

@ -16,7 +16,8 @@
package io.netty.handler.logging; package io.netty.handler.logging;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.ChannelBuf;
import io.netty.buffer.UnsafeByteBuf;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundByteHandler; import io.netty.channel.ChannelInboundByteHandler;
@ -108,12 +109,22 @@ public class ByteLoggingHandler
} }
@Override @Override
public ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { public ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return Unpooled.buffer(); return ctx.alloc().buffer();
} }
@Override @Override
public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
return Unpooled.buffer(); return ctx.alloc().buffer();
}
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
((UnsafeByteBuf) buf).free();
}
@Override
public void freeOutboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
((UnsafeByteBuf) buf).free();
} }
@Override @Override

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.handler.logging; package io.netty.handler.logging;
import io.netty.buffer.ChannelBuf;
import io.netty.buffer.MessageBuf; import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
@ -57,6 +58,16 @@ public class MessageLoggingHandler
return Unpooled.messageBuffer(); return Unpooled.messageBuffer();
} }
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
// Nothing to free
}
@Override
public void freeOutboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
// Nothing to free
}
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) public void inboundBufferUpdated(ChannelHandlerContext ctx)
throws Exception { throws Exception {

View File

@ -17,7 +17,8 @@ package io.netty.handler.ssl;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil; import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled; import io.netty.buffer.ChannelBuf;
import io.netty.buffer.UnsafeByteBuf;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelFlushFutureNotifier; import io.netty.channel.ChannelFlushFutureNotifier;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
@ -32,6 +33,10 @@ import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory; import io.netty.logging.InternalLoggerFactory;
import io.netty.util.internal.DetectionUtil; import io.netty.util.internal.DetectionUtil;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.Status;
import javax.net.ssl.SSLException;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException; import java.nio.channels.ClosedChannelException;
@ -44,11 +49,6 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.Status;
import javax.net.ssl.SSLException;
/** /**
* Adds <a href="http://en.wikipedia.org/wiki/Transport_Layer_Security">SSL * Adds <a href="http://en.wikipedia.org/wiki/Transport_Layer_Security">SSL
* &middot; TLS</a> and StartTLS support to a {@link Channel}. Please refer * &middot; TLS</a> and StartTLS support to a {@link Channel}. Please refer
@ -376,12 +376,22 @@ public class SslHandler
@Override @Override
public ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { public ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return Unpooled.buffer(); return ctx.alloc().buffer();
} }
@Override @Override
public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
return Unpooled.buffer(); return ctx.alloc().buffer();
}
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
((UnsafeByteBuf) buf).free();
}
@Override
public void freeOutboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
((UnsafeByteBuf) buf).free();
} }
@Override @Override
@ -401,7 +411,7 @@ public class SslHandler
final ByteBuf in = ctx.outboundByteBuffer(); final ByteBuf in = ctx.outboundByteBuffer();
final ByteBuf out = ctx.nextOutboundByteBuffer(); final ByteBuf out = ctx.nextOutboundByteBuffer();
out.unsafe().discardSomeReadBytes(); ((UnsafeByteBuf) out).discardSomeReadBytes();
// Do not encrypt the first write request if this handler is // Do not encrypt the first write request if this handler is
// created with startTLS flag turned on. // created with startTLS flag turned on.
@ -473,7 +483,7 @@ public class SslHandler
setHandshakeFailure(e); setHandshakeFailure(e);
throw e; throw e;
} finally { } finally {
in.unsafe().discardSomeReadBytes(); ((UnsafeByteBuf) in).discardSomeReadBytes();
flush0(ctx, bytesConsumed); flush0(ctx, bytesConsumed);
} }
} }

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.handler.stream; package io.netty.handler.stream;
import io.netty.buffer.ChannelBuf;
import io.netty.buffer.MessageBuf; import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.Channel; import io.netty.channel.Channel;
@ -95,6 +96,11 @@ public class ChunkedWriteHandler
return queue; return queue;
} }
@Override
public void freeOutboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
// Nothing to free
}
private boolean isWritable() { private boolean isWritable() {
return pendingWrites.get() < maxPendingWrites; return pendingWrites.get() < maxPendingWrites;
} }

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.bootstrap; package io.netty.bootstrap;
import io.netty.buffer.ChannelBuf;
import io.netty.buffer.MessageBuf; import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.Channel; import io.netty.channel.Channel;
@ -229,6 +230,11 @@ public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap> {
return Unpooled.messageBuffer(); return Unpooled.messageBuffer();
} }
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
// Nothing to free
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) { public void inboundBufferUpdated(ChannelHandlerContext ctx) {

View File

@ -16,6 +16,7 @@
package io.netty.channel; package io.netty.channel;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.MessageBuf; import io.netty.buffer.MessageBuf;
import io.netty.logging.InternalLogger; import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory; import io.netty.logging.InternalLoggerFactory;
@ -146,6 +147,11 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
return pipeline; return pipeline;
} }
@Override
public ByteBufAllocator alloc() {
return config().getAllocator();
}
@Override @Override
public EventLoop eventLoop() { public EventLoop eventLoop() {
EventLoop eventLoop = this.eventLoop; EventLoop eventLoop = this.eventLoop;

View File

@ -106,7 +106,7 @@ import java.nio.channels.SelectionKey;
* *
* @apiviz.exclude ^io\.netty\.channel\.([a-z]+\.)+[^\.]+Channel$ * @apiviz.exclude ^io\.netty\.channel\.([a-z]+\.)+[^\.]+Channel$
*/ */
public interface Channel extends AttributeMap, ChannelOutboundInvoker, ChannelFutureFactory, Comparable<Channel> { public interface Channel extends AttributeMap, ChannelOutboundInvoker, ChannelPropertyAccess, Comparable<Channel> {
/** /**
* Returns the unique integer ID of this channel. * Returns the unique integer ID of this channel.
@ -131,12 +131,6 @@ public interface Channel extends AttributeMap, ChannelOutboundInvoker, ChannelFu
*/ */
ChannelConfig config(); ChannelConfig config();
/**
* Returns the {@link ChannelPipeline} which handles {@link ChannelEvent}s
* associated with this channel.
*/
ChannelPipeline pipeline();
boolean isOpen(); boolean isOpen();
boolean isRegistered(); boolean isRegistered();
boolean isActive(); boolean isActive();

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.channel; package io.netty.channel;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.socket.SocketChannelConfig; import io.netty.channel.socket.SocketChannelConfig;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -136,4 +137,7 @@ public interface ChannelConfig {
* if the specified value is {@code 0} or less than {@code 0} * if the specified value is {@code 0} or less than {@code 0}
*/ */
void setWriteSpinCount(int writeSpinCount); void setWriteSpinCount(int writeSpinCount);
ByteBufAllocator getAllocator();
ByteBufAllocator setAllocator(ByteBufAllocator bufferPool);
} }

View File

@ -126,7 +126,7 @@ import java.util.Set;
* @apiviz.owns io.netty.channel.ChannelHandler * @apiviz.owns io.netty.channel.ChannelHandler
*/ */
public interface ChannelHandlerContext public interface ChannelHandlerContext
extends AttributeMap, ChannelFutureFactory, extends AttributeMap, ChannelPropertyAccess,
ChannelInboundInvoker, ChannelOutboundInvoker { ChannelInboundInvoker, ChannelOutboundInvoker {
/** /**
@ -134,11 +134,6 @@ public interface ChannelHandlerContext
*/ */
Channel channel(); Channel channel();
/**
* Return the {@link ChannelPipeline} which belongs this {@link ChannelHandlerContext}.
*/
ChannelPipeline pipeline();
/** /**
* The {@link EventExecutor} that is used to dispatch the events. This can also be used to directly * The {@link EventExecutor} that is used to dispatch the events. This can also be used to directly
* submit tasks that get executed in the event loop. For more informations please refer to the * submit tasks that get executed in the event loop. For more informations please refer to the

View File

@ -16,7 +16,8 @@
package io.netty.channel; package io.netty.channel;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.ChannelBuf;
import io.netty.buffer.UnsafeByteBuf;
/** /**
@ -34,7 +35,12 @@ public abstract class ChannelInboundByteHandlerAdapter
*/ */
@Override @Override
public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
return Unpooled.buffer(); return ctx.alloc().buffer();
}
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
((UnsafeByteBuf) buf).free();
} }
@Override @Override
@ -44,7 +50,7 @@ public abstract class ChannelInboundByteHandlerAdapter
inboundBufferUpdated(ctx, in); inboundBufferUpdated(ctx, in);
} finally { } finally {
if (!in.readable()) { if (!in.readable()) {
in.unsafe().discardSomeReadBytes(); ((UnsafeByteBuf) in).discardSomeReadBytes();
} }
} }
} }

View File

@ -25,4 +25,10 @@ public interface ChannelInboundHandler extends ChannelStateHandler {
* Return the {@link ChannelBuf} which will be used for inbound data for the given {@link ChannelHandlerContext}. * Return the {@link ChannelBuf} which will be used for inbound data for the given {@link ChannelHandlerContext}.
*/ */
ChannelBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception; ChannelBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception;
/**
* Invoked when this handler is not going to receive any inbound message anymore and thus it's safe to
* deallocate its inbound buffer.
*/
void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception;
} }

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.channel; package io.netty.channel;
import io.netty.buffer.ChannelBuf;
import io.netty.buffer.MessageBuf; import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
@ -33,6 +34,11 @@ public abstract class ChannelInboundMessageHandlerAdapter<I>
return Unpooled.messageBuffer(); return Unpooled.messageBuffer();
} }
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
// Nothing to free
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public final void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { public final void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception {

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.channel; package io.netty.channel;
import io.netty.buffer.ByteBufAllocator;
import io.netty.util.UniqueName; import io.netty.util.UniqueName;
import java.net.InetAddress; import java.net.InetAddress;
@ -28,6 +29,7 @@ public class ChannelOption<T> extends UniqueName {
private static final ConcurrentMap<String, Boolean> names = new ConcurrentHashMap<String, Boolean>(); private static final ConcurrentMap<String, Boolean> names = new ConcurrentHashMap<String, Boolean>();
public static final ChannelOption<ByteBufAllocator> ALLOCATOR = new ChannelOption<ByteBufAllocator>("ALLOCATOR");
public static final ChannelOption<Integer> CONNECT_TIMEOUT_MILLIS = public static final ChannelOption<Integer> CONNECT_TIMEOUT_MILLIS =
new ChannelOption<Integer>("CONNECT_TIMEOUT_MILLIS"); new ChannelOption<Integer>("CONNECT_TIMEOUT_MILLIS");
public static final ChannelOption<Integer> WRITE_SPIN_COUNT = public static final ChannelOption<Integer> WRITE_SPIN_COUNT =

View File

@ -16,12 +16,18 @@
package io.netty.channel; package io.netty.channel;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.ChannelBuf;
import io.netty.buffer.UnsafeByteBuf;
public abstract class ChannelOutboundByteHandlerAdapter public abstract class ChannelOutboundByteHandlerAdapter
extends ChannelOutboundHandlerAdapter implements ChannelOutboundByteHandler { extends ChannelOutboundHandlerAdapter implements ChannelOutboundByteHandler {
@Override @Override
public ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { public ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return Unpooled.buffer(); return ctx.alloc().buffer();
}
@Override
public void freeOutboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
((UnsafeByteBuf) buf).free();
} }
} }

View File

@ -19,4 +19,10 @@ import io.netty.buffer.ChannelBuf;
public interface ChannelOutboundHandler extends ChannelOperationHandler { public interface ChannelOutboundHandler extends ChannelOperationHandler {
ChannelBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception; ChannelBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception;
/**
* Invoked when this handler is not allowed to send any outbound message anymore and thus it's safe to
* deallocate its outbound buffer.
*/
void freeOutboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception;
} }

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.channel; package io.netty.channel;
import io.netty.buffer.ChannelBuf;
import io.netty.buffer.MessageBuf; import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
@ -24,4 +25,9 @@ public abstract class ChannelOutboundMessageHandlerAdapter<I>
public MessageBuf<I> newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { public MessageBuf<I> newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return Unpooled.messageBuffer(); return Unpooled.messageBuffer();
} }
@Override
public void freeOutboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
// Nothing to free
}
} }

View File

@ -15,11 +15,16 @@
*/ */
package io.netty.channel; package io.netty.channel;
import io.netty.buffer.ByteBufAllocator;
/** /**
* Factory which is responsible to create new {@link ChannelFuture}'s * Provides common methods between {@link Channel} and {@link ChannelHandlerContext}.
*
*/ */
public interface ChannelFutureFactory { interface ChannelPropertyAccess {
ChannelPipeline pipeline();
ByteBufAllocator alloc();
/** /**
* Create a new {@link ChannelFuture} * Create a new {@link ChannelFuture}

View File

@ -68,12 +68,22 @@ public class CombinedChannelHandler
return in.newInboundBuffer(ctx); return in.newInboundBuffer(ctx);
} }
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
in.freeInboundBuffer(ctx, buf);
}
@Override @Override
public ChannelBuf newOutboundBuffer( public ChannelBuf newOutboundBuffer(
ChannelHandlerContext ctx) throws Exception { ChannelHandlerContext ctx) throws Exception {
return out.newOutboundBuffer(ctx); return out.newOutboundBuffer(ctx);
} }
@Override
public void freeOutboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
out.freeOutboundBuffer(ctx, buf);
}
@Override @Override
public void beforeAdd(ChannelHandlerContext ctx) throws Exception { public void beforeAdd(ChannelHandlerContext ctx) throws Exception {
if (in == null) { if (in == null) {

View File

@ -15,6 +15,8 @@
*/ */
package io.netty.channel; package io.netty.channel;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.socket.SocketChannelConfig; import io.netty.channel.socket.SocketChannelConfig;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
@ -28,14 +30,16 @@ import static io.netty.channel.ChannelOption.*;
*/ */
public class DefaultChannelConfig implements ChannelConfig { public class DefaultChannelConfig implements ChannelConfig {
private static final ByteBufAllocator DEFAULT_ALLOCATOR = UnpooledByteBufAllocator.HEAP_BY_DEFAULT;
private static final int DEFAULT_CONNECT_TIMEOUT = 30000; private static final int DEFAULT_CONNECT_TIMEOUT = 30000;
private volatile ByteBufAllocator allocator = DEFAULT_ALLOCATOR;
private volatile int connectTimeoutMillis = DEFAULT_CONNECT_TIMEOUT; private volatile int connectTimeoutMillis = DEFAULT_CONNECT_TIMEOUT;
private volatile int writeSpinCount = 16; private volatile int writeSpinCount = 16;
@Override @Override
public Map<ChannelOption<?>, Object> getOptions() { public Map<ChannelOption<?>, Object> getOptions() {
return getOptions(null, CONNECT_TIMEOUT_MILLIS, WRITE_SPIN_COUNT); return getOptions(null, CONNECT_TIMEOUT_MILLIS, WRITE_SPIN_COUNT, ALLOCATOR);
} }
protected Map<ChannelOption<?>, Object> getOptions( protected Map<ChannelOption<?>, Object> getOptions(
@ -79,6 +83,9 @@ public class DefaultChannelConfig implements ChannelConfig {
if (option == WRITE_SPIN_COUNT) { if (option == WRITE_SPIN_COUNT) {
return (T) Integer.valueOf(getWriteSpinCount()); return (T) Integer.valueOf(getWriteSpinCount());
} }
if (option == ALLOCATOR) {
return (T) getAllocator();
}
return null; return null;
} }
@ -91,6 +98,8 @@ public class DefaultChannelConfig implements ChannelConfig {
setConnectTimeoutMillis((Integer) value); setConnectTimeoutMillis((Integer) value);
} else if (option == WRITE_SPIN_COUNT) { } else if (option == WRITE_SPIN_COUNT) {
setWriteSpinCount((Integer) value); setWriteSpinCount((Integer) value);
} else if (option == ALLOCATOR) {
setAllocator((ByteBufAllocator) value);
} else { } else {
return false; return false;
} }
@ -132,4 +141,19 @@ public class DefaultChannelConfig implements ChannelConfig {
} }
this.writeSpinCount = writeSpinCount; this.writeSpinCount = writeSpinCount;
} }
@Override
public ByteBufAllocator getAllocator() {
return allocator;
}
@Override
public ByteBufAllocator setAllocator(ByteBufAllocator allocator) {
if (allocator == null) {
throw new NullPointerException("allocator");
}
ByteBufAllocator oldAllocator = this.allocator;
this.allocator = allocator;
return oldAllocator;
}
} }

View File

@ -15,11 +15,12 @@
*/ */
package io.netty.channel; package io.netty.channel;
import static io.netty.channel.DefaultChannelPipeline.*;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ChannelBuf; import io.netty.buffer.ChannelBuf;
import io.netty.buffer.MessageBuf; import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.buffer.UnsafeByteBuf;
import io.netty.util.DefaultAttributeMap; import io.netty.util.DefaultAttributeMap;
import java.net.SocketAddress; import java.net.SocketAddress;
@ -34,42 +35,47 @@ import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import static io.netty.channel.DefaultChannelPipeline.*;
final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext { final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext {
private static final EnumSet<ChannelHandlerType> EMPTY_TYPE = EnumSet.noneOf(ChannelHandlerType.class); private static final EnumSet<ChannelHandlerType> EMPTY_TYPE = EnumSet.noneOf(ChannelHandlerType.class);
static final int DIR_INBOUND = 0x00000001; static final int DIR_INBOUND = 1;
static final int DIR_OUTBOUND = 0x80000000; static final int DIR_OUTBOUND = 2;
private static final int FLAG_NEEDS_LAZY_INIT = 4;
volatile DefaultChannelHandlerContext next; volatile DefaultChannelHandlerContext next;
volatile DefaultChannelHandlerContext prev; volatile DefaultChannelHandlerContext prev;
private final Channel channel; private final Channel channel;
private final DefaultChannelPipeline pipeline; private final DefaultChannelPipeline pipeline;
EventExecutor executor; // not thread-safe but OK because it never changes once set.
private final String name; private final String name;
private final Set<ChannelHandlerType> type; private final Set<ChannelHandlerType> type;
final int directions;
private final ChannelHandler handler; private final ChannelHandler handler;
final int flags;
final AtomicBoolean readable = new AtomicBoolean(true);
MessageBuf<Object> inMsgBuf; EventExecutor executor; // not thread-safe but OK because it never changes once set.
ByteBuf inByteBuf;
MessageBuf<Object> outMsgBuf; private MessageBuf<Object> inMsgBuf;
ByteBuf outByteBuf; private UnsafeByteBuf inByteBuf;
private MessageBuf<Object> outMsgBuf;
private UnsafeByteBuf outByteBuf;
// When the two handlers run in a different thread and they are next to each other, // When the two handlers run in a different thread and they are next to each other,
// each other's buffers can be accessed at the same time resulting in a race condition. // each other's buffers can be accessed at the same time resulting in a race condition.
// To avoid such situation, we lazily creates an additional thread-safe buffer called // To avoid such situation, we lazily creates an additional thread-safe buffer called
// 'bridge' so that the two handlers access each other's buffer only via the bridges. // 'bridge' so that the two handlers access each other's buffer only via the bridges.
// The content written into a bridge is flushed into the actual buffer by flushBridge(). // The content written into a bridge is flushed into the actual buffer by flushBridge().
final AtomicReference<MessageBridge> inMsgBridge; private final AtomicReference<MessageBridge> inMsgBridge;
final AtomicReference<MessageBridge> outMsgBridge; AtomicReference<MessageBridge> outMsgBridge;
final AtomicReference<ByteBridge> inByteBridge; private final AtomicReference<ByteBridge> inByteBridge;
final AtomicReference<ByteBridge> outByteBridge; AtomicReference<ByteBridge> outByteBridge;
final AtomicBoolean readable = new AtomicBoolean(true);
// Runnables that calls handlers // Runnables that calls handlers
final Runnable fireChannelRegisteredTask = new Runnable() { private final Runnable fireChannelRegisteredTask = new Runnable() {
@Override @Override
public void run() { public void run() {
DefaultChannelHandlerContext ctx = DefaultChannelHandlerContext.this; DefaultChannelHandlerContext ctx = DefaultChannelHandlerContext.this;
@ -80,7 +86,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
} }
} }
}; };
final Runnable fireChannelUnregisteredTask = new Runnable() { private final Runnable fireChannelUnregisteredTask = new Runnable() {
@Override @Override
public void run() { public void run() {
DefaultChannelHandlerContext ctx = DefaultChannelHandlerContext.this; DefaultChannelHandlerContext ctx = DefaultChannelHandlerContext.this;
@ -91,7 +97,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
} }
} }
}; };
final Runnable fireChannelActiveTask = new Runnable() { private final Runnable fireChannelActiveTask = new Runnable() {
@Override @Override
public void run() { public void run() {
DefaultChannelHandlerContext ctx = DefaultChannelHandlerContext.this; DefaultChannelHandlerContext ctx = DefaultChannelHandlerContext.this;
@ -102,7 +108,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
} }
} }
}; };
final Runnable fireChannelInactiveTask = new Runnable() { private final Runnable fireChannelInactiveTask = new Runnable() {
@Override @Override
public void run() { public void run() {
DefaultChannelHandlerContext ctx = DefaultChannelHandlerContext.this; DefaultChannelHandlerContext ctx = DefaultChannelHandlerContext.this;
@ -113,7 +119,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
} }
} }
}; };
final Runnable curCtxFireInboundBufferUpdatedTask = new Runnable() { private final Runnable curCtxFireInboundBufferUpdatedTask = new Runnable() {
@Override @Override
public void run() { public void run() {
DefaultChannelHandlerContext ctx = DefaultChannelHandlerContext.this; DefaultChannelHandlerContext ctx = DefaultChannelHandlerContext.this;
@ -148,6 +154,55 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
} }
} }
}; };
private final Runnable freeInboundBufferTask = new Runnable() {
@Override
public void run() {
DefaultChannelHandlerContext ctx = DefaultChannelHandlerContext.this;
if (ctx.handler instanceof ChannelInboundHandler) {
ChannelInboundHandler h = (ChannelInboundHandler) ctx.handler;
try {
if (ctx.inByteBuf != null) {
h.freeInboundBuffer(ctx, ctx.inByteBuf);
} else {
h.freeInboundBuffer(ctx, ctx.inMsgBuf);
}
} catch (Throwable t) {
pipeline.notifyHandlerException(t);
}
}
DefaultChannelHandlerContext nextCtx = nextContext(ctx.next, DIR_INBOUND);
if (nextCtx != null) {
nextCtx.callFreeInboundBuffer();
} else {
// Freed all inbound buffers. Free all outbound buffers in a reverse order.
pipeline.firstContext(DIR_OUTBOUND).callFreeOutboundBuffer();
}
}
};
private final Runnable freeOutboundBufferTask = new Runnable() {
@Override
public void run() {
DefaultChannelHandlerContext ctx = DefaultChannelHandlerContext.this;
if (ctx.handler instanceof ChannelOutboundHandler) {
ChannelOutboundHandler h = (ChannelOutboundHandler) ctx.handler;
try {
if (ctx.outByteBuf != null) {
h.freeOutboundBuffer(ctx, ctx.outByteBuf);
} else {
h.freeOutboundBuffer(ctx, ctx.outMsgBuf);
}
} catch (Throwable t) {
pipeline.notifyHandlerException(t);
}
}
DefaultChannelHandlerContext nextCtx = nextContext(ctx.prev, DIR_OUTBOUND);
if (nextCtx != null) {
nextCtx.callFreeOutboundBuffer();
}
}
};
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
DefaultChannelHandlerContext( DefaultChannelHandlerContext(
@ -162,25 +217,25 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
throw new NullPointerException("handler"); throw new NullPointerException("handler");
} }
int flags = 0;
// Determine the type of the specified handler. // Determine the type of the specified handler.
int typeValue = 0;
EnumSet<ChannelHandlerType> type = EMPTY_TYPE.clone(); EnumSet<ChannelHandlerType> type = EMPTY_TYPE.clone();
if (handler instanceof ChannelStateHandler) { if (handler instanceof ChannelStateHandler) {
type.add(ChannelHandlerType.STATE); type.add(ChannelHandlerType.STATE);
typeValue |= DIR_INBOUND; flags |= DIR_INBOUND;
if (handler instanceof ChannelInboundHandler) { if (handler instanceof ChannelInboundHandler) {
type.add(ChannelHandlerType.INBOUND); type.add(ChannelHandlerType.INBOUND);
} }
} }
if (handler instanceof ChannelOperationHandler) { if (handler instanceof ChannelOperationHandler) {
type.add(ChannelHandlerType.OPERATION); type.add(ChannelHandlerType.OPERATION);
typeValue |= DIR_OUTBOUND; flags |= DIR_OUTBOUND;
if (handler instanceof ChannelOutboundHandler) { if (handler instanceof ChannelOutboundHandler) {
type.add(ChannelHandlerType.OUTBOUND); type.add(ChannelHandlerType.OUTBOUND);
} }
} }
this.type = Collections.unmodifiableSet(type); this.type = Collections.unmodifiableSet(type);
directions = typeValue;
this.prev = prev; this.prev = prev;
this.next = next; this.next = next;
@ -217,8 +272,8 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
throw new ChannelPipelineException("A user handler's newInboundBuffer() returned null"); throw new ChannelPipelineException("A user handler's newInboundBuffer() returned null");
} }
if (buf instanceof ByteBuf) { if (buf instanceof UnsafeByteBuf) {
inByteBuf = (ByteBuf) buf; inByteBuf = (UnsafeByteBuf) buf;
inByteBridge = new AtomicReference<ByteBridge>(); inByteBridge = new AtomicReference<ByteBridge>();
inMsgBuf = null; inMsgBuf = null;
inMsgBridge = null; inMsgBridge = null;
@ -238,29 +293,15 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
} }
if (type.contains(ChannelHandlerType.OUTBOUND)) { if (type.contains(ChannelHandlerType.OUTBOUND)) {
ChannelBuf buf; if (prev == null) {
try { // Special case: if pref == null, it means this context for HeadHandler.
buf = ((ChannelOutboundHandler) handler).newOutboundBuffer(this); // HeadHandler is an outbound handler instantiated by the constructor of DefaultChannelPipeline.
} catch (Exception e) { // Because Channel is not really fully initialized at this point, we should not call
throw new ChannelPipelineException("A user handler failed to create a new outbound buffer.", e); // newOutboundBuffer() yet because it will usually lead to NPE.
} // To work around this problem, we lazily initialize the outbound buffer for this special case.
flags |= FLAG_NEEDS_LAZY_INIT;
if (buf == null) {
throw new ChannelPipelineException("A user handler's newOutboundBuffer() returned null");
}
if (buf instanceof ByteBuf) {
outByteBuf = (ByteBuf) buf;
outByteBridge = new AtomicReference<ByteBridge>();
outMsgBuf = null;
outMsgBridge = null;
} else if (buf instanceof MessageBuf) {
outByteBuf = null;
outByteBridge = null;
outMsgBuf = (MessageBuf<Object>) buf;
outMsgBridge = new AtomicReference<MessageBridge>();
} else { } else {
throw new Error(); initOutboundBuffer();
} }
} else { } else {
outByteBuf = null; outByteBuf = null;
@ -268,6 +309,43 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
outMsgBuf = null; outMsgBuf = null;
outMsgBridge = null; outMsgBridge = null;
} }
this.flags = flags;
}
private void lazyInitOutboundBuffer() {
if ((flags & FLAG_NEEDS_LAZY_INIT) != 0) {
if (outByteBuf == null && outMsgBuf == null) {
initOutboundBuffer();
}
}
}
private void initOutboundBuffer() {
ChannelBuf buf;
try {
buf = ((ChannelOutboundHandler) handler).newOutboundBuffer(this);
} catch (Exception e) {
throw new ChannelPipelineException("A user handler failed to create a new outbound buffer.", e);
}
if (buf == null) {
throw new ChannelPipelineException("A user handler's newOutboundBuffer() returned null");
}
if (buf instanceof UnsafeByteBuf) {
outByteBuf = (UnsafeByteBuf) buf;
outByteBridge = new AtomicReference<ByteBridge>();
outMsgBuf = null;
outMsgBridge = null;
} else if (buf instanceof MessageBuf) {
outByteBuf = null;
outByteBridge = null;
outMsgBuf = (MessageBuf<Object>) buf;
outMsgBridge = new AtomicReference<MessageBridge>();
} else {
throw new Error();
}
} }
void fillBridge() { void fillBridge() {
@ -309,6 +387,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
} }
} }
lazyInitOutboundBuffer();
if (outMsgBridge != null) { if (outMsgBridge != null) {
MessageBridge bridge = outMsgBridge.get(); MessageBridge bridge = outMsgBridge.get();
if (bridge != null) { if (bridge != null) {
@ -332,6 +411,11 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
return pipeline; return pipeline;
} }
@Override
public ByteBufAllocator alloc() {
return channel.config().getAllocator();
}
@Override @Override
public EventExecutor executor() { public EventExecutor executor() {
if (executor == null) { if (executor == null) {
@ -405,16 +489,22 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
@Override @Override
public boolean hasOutboundByteBuffer() { public boolean hasOutboundByteBuffer() {
lazyInitOutboundBuffer();
return outByteBuf != null; return outByteBuf != null;
} }
@Override @Override
public boolean hasOutboundMessageBuffer() { public boolean hasOutboundMessageBuffer() {
lazyInitOutboundBuffer();
return outMsgBuf != null; return outMsgBuf != null;
} }
@Override @Override
public ByteBuf outboundByteBuffer() { public ByteBuf outboundByteBuffer() {
if (outMsgBuf == null) {
lazyInitOutboundBuffer();
}
if (outByteBuf == null) { if (outByteBuf == null) {
if (handler instanceof ChannelOutboundHandler) { if (handler instanceof ChannelOutboundHandler) {
throw new NoSuchBufferException(String.format( throw new NoSuchBufferException(String.format(
@ -434,6 +524,10 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> MessageBuf<T> outboundMessageBuffer() { public <T> MessageBuf<T> outboundMessageBuffer() {
if (outMsgBuf == null) {
initOutboundBuffer();
}
if (outMsgBuf == null) { if (outMsgBuf == null) {
if (handler instanceof ChannelOutboundHandler) { if (handler instanceof ChannelOutboundHandler) {
throw new NoSuchBufferException(String.format( throw new NoSuchBufferException(String.format(
@ -470,7 +564,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
* @throws ChannelPipelineException with a {@link Throwable} as a cause, if the task threw another type of * @throws ChannelPipelineException with a {@link Throwable} as a cause, if the task threw another type of
* {@link Throwable}. * {@link Throwable}.
*/ */
<T> T executeOnEventLoop(Callable<T> c) throws Exception { private <T> T executeOnEventLoop(Callable<T> c) throws Exception {
return getFromFuture(executor().submit(c)); return getFromFuture(executor().submit(c));
} }
@ -513,7 +607,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
* @throws ChannelPipelineException with a {@link Throwable} as a cause, if the task threw another type of * @throws ChannelPipelineException with a {@link Throwable} as a cause, if the task threw another type of
* {@link Throwable}. * {@link Throwable}.
*/ */
<T> T getFromFuture(Future<T> future) throws Exception { private static <T> T getFromFuture(Future<T> future) throws Exception {
try { try {
return future.get(); return future.get();
} catch (ExecutionException ex) { } catch (ExecutionException ex) {
@ -547,7 +641,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
* @throws ChannelPipelineException with a {@link Throwable} as a cause, if the task threw another type of * @throws ChannelPipelineException with a {@link Throwable} as a cause, if the task threw another type of
* {@link Throwable}. * {@link Throwable}.
*/ */
void waitForFuture(Future future) { static void waitForFuture(Future<?> future) {
try { try {
future.get(); future.get();
} catch (ExecutionException ex) { } catch (ExecutionException ex) {
@ -585,7 +679,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
ByteBuf currentInboundByteBuf = inboundByteBuffer(); ByteBuf currentInboundByteBuf = inboundByteBuffer();
this.inByteBuf = newInboundByteBuf; inByteBuf = (UnsafeByteBuf) newInboundByteBuf;
return currentInboundByteBuf; return currentInboundByteBuf;
} }
@ -611,7 +705,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
MessageBuf<T> currentInboundMsgBuf = inboundMessageBuffer(); MessageBuf<T> currentInboundMsgBuf = inboundMessageBuffer();
this.inMsgBuf = (MessageBuf<Object>) newInboundMsgBuf; inMsgBuf = (MessageBuf<Object>) newInboundMsgBuf;
return currentInboundMsgBuf; return currentInboundMsgBuf;
} }
@ -636,7 +730,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
ByteBuf currentOutboundByteBuf = outboundByteBuffer(); ByteBuf currentOutboundByteBuf = outboundByteBuffer();
this.outByteBuf = newOutboundByteBuf; outByteBuf = (UnsafeByteBuf) newOutboundByteBuf;
return currentOutboundByteBuf; return currentOutboundByteBuf;
} }
@ -662,7 +756,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
MessageBuf<T> currentOutboundMsgBuf = outboundMessageBuffer(); MessageBuf<T> currentOutboundMsgBuf = outboundMessageBuffer();
this.outMsgBuf = (MessageBuf<Object>) newOutboundMsgBuf; outMsgBuf = (MessageBuf<Object>) newOutboundMsgBuf;
return currentOutboundMsgBuf; return currentOutboundMsgBuf;
} }
@ -696,12 +790,36 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
@Override @Override
public boolean hasNextOutboundByteBuffer() { public boolean hasNextOutboundByteBuffer() {
return DefaultChannelPipeline.hasNextOutboundByteBuffer(prev); DefaultChannelHandlerContext ctx = prev;
for (;;) {
if (ctx == null) {
return false;
}
ctx.lazyInitOutboundBuffer();
if (ctx.outByteBridge != null) {
return true;
}
ctx = ctx.prev;
}
} }
@Override @Override
public boolean hasNextOutboundMessageBuffer() { public boolean hasNextOutboundMessageBuffer() {
return DefaultChannelPipeline.hasNextOutboundMessageBuffer(prev); DefaultChannelHandlerContext ctx = prev;
for (;;) {
if (ctx == null) {
return false;
}
ctx.lazyInitOutboundBuffer();
if (ctx.outMsgBridge != null) {
return true;
}
ctx = ctx.prev;
}
} }
@Override @Override
@ -728,7 +846,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
} else { } else {
ByteBridge bridge = ctx.inByteBridge.get(); ByteBridge bridge = ctx.inByteBridge.get();
if (bridge == null) { if (bridge == null) {
bridge = new ByteBridge(); bridge = new ByteBridge(ctx);
if (!ctx.inByteBridge.compareAndSet(null, bridge)) { if (!ctx.inByteBridge.compareAndSet(null, bridge)) {
bridge = ctx.inByteBridge.get(); bridge = ctx.inByteBridge.get();
} }
@ -779,12 +897,12 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
@Override @Override
public ByteBuf nextOutboundByteBuffer() { public ByteBuf nextOutboundByteBuffer() {
return DefaultChannelPipeline.nextOutboundByteBuffer(prev); return pipeline.nextOutboundByteBuffer(prev);
} }
@Override @Override
public MessageBuf<Object> nextOutboundMessageBuffer() { public MessageBuf<Object> nextOutboundMessageBuffer() {
return DefaultChannelPipeline.nextOutboundMessageBuffer(prev); return pipeline.nextOutboundMessageBuffer(prev);
} }
@Override @Override
@ -876,8 +994,8 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
} else { } else {
logger.warn( logger.warn(
"An exceptionCaught() event was fired, and it reached at the end of the " + "An exceptionCaught() event was fired, and it reached at the end of the " +
"pipeline. It usually means the last inbound handler in the pipeline did not " + "pipeline. It usually means the last inbound handler in the pipeline did not " +
"handle the exception.", cause); "handle the exception.", cause);
} }
} }
@ -1011,6 +1129,25 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
return pipeline.write(prev, message, future); return pipeline.write(prev, message, future);
} }
void callFreeInboundBuffer() {
EventExecutor executor = executor();
if (executor.inEventLoop()) {
freeInboundBufferTask.run();
} else {
executor.execute(freeInboundBufferTask);
}
}
/** Invocation initiated by {@link #freeInboundBufferTask} after freeing all inbound buffers. */
private void callFreeOutboundBuffer() {
EventExecutor executor = executor();
if (executor.inEventLoop()) {
freeOutboundBufferTask.run();
} else {
executor.execute(freeOutboundBufferTask);
}
}
@Override @Override
public ChannelFuture newFuture() { public ChannelFuture newFuture() {
return channel.newFuture(); return channel.newFuture();
@ -1028,9 +1165,10 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
static final class MessageBridge { static final class MessageBridge {
final MessageBuf<Object> msgBuf = Unpooled.messageBuffer(); final MessageBuf<Object> msgBuf = Unpooled.messageBuffer();
final Queue<Object[]> exchangeBuf = new ConcurrentLinkedQueue<Object[]>();
void fill() { private final Queue<Object[]> exchangeBuf = new ConcurrentLinkedQueue<Object[]>();
private void fill() {
if (msgBuf.isEmpty()) { if (msgBuf.isEmpty()) {
return; return;
} }
@ -1039,7 +1177,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
exchangeBuf.add(data); exchangeBuf.add(data);
} }
void flush(MessageBuf<Object> out) { private void flush(MessageBuf<Object> out) {
for (;;) { for (;;) {
Object[] data = exchangeBuf.poll(); Object[] data = exchangeBuf.poll();
if (data == null) { if (data == null) {
@ -1052,26 +1190,48 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
} }
static final class ByteBridge { static final class ByteBridge {
final ByteBuf byteBuf = Unpooled.buffer(); final UnsafeByteBuf byteBuf;
final Queue<ByteBuf> exchangeBuf = new ConcurrentLinkedQueue<ByteBuf>();
void fill() { private final Queue<UnsafeByteBuf> exchangeBuf = new ConcurrentLinkedQueue<UnsafeByteBuf>();
private final ChannelHandlerContext ctx;
ByteBridge(ChannelHandlerContext ctx) {
this.ctx = ctx;
// TODO Choose whether to use heap or direct buffer depending on the context's buffer type.
byteBuf = (UnsafeByteBuf) ctx.alloc().buffer();
}
private void fill() {
if (!byteBuf.readable()) { if (!byteBuf.readable()) {
return; return;
} }
ByteBuf data = byteBuf.readBytes(byteBuf.readableBytes());
byteBuf.discardReadBytes(); int dataLen = byteBuf.readableBytes();
exchangeBuf.add(data); ByteBuf data;
if (byteBuf.isDirect()) {
data = ctx.alloc().directBuffer(dataLen, dataLen);
} else {
data = ctx.alloc().buffer(dataLen, dataLen);
}
byteBuf.readBytes(data);
byteBuf.discardSomeReadBytes();
exchangeBuf.add((UnsafeByteBuf) data);
} }
void flush(ByteBuf out) { private void flush(ByteBuf out) {
for (;;) { for (;;) {
ByteBuf data = exchangeBuf.poll(); UnsafeByteBuf data = exchangeBuf.poll();
if (data == null) { if (data == null) {
break; break;
} }
out.writeBytes(data); try {
out.writeBytes(data);
} finally {
data.free();
}
} }
} }
} }

View File

@ -19,6 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.ChannelBuf; import io.netty.buffer.ChannelBuf;
import io.netty.buffer.MessageBuf; import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.buffer.UnsafeByteBuf;
import io.netty.logging.InternalLogger; import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory; import io.netty.logging.InternalLoggerFactory;
@ -358,7 +359,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
private DefaultChannelHandlerContext remove(final DefaultChannelHandlerContext ctx) { private DefaultChannelHandlerContext remove(final DefaultChannelHandlerContext ctx) {
DefaultChannelHandlerContext context; DefaultChannelHandlerContext context;
Future future; Future<?> future;
synchronized (this) { synchronized (this) {
if (head == tail) { if (head == tail) {
@ -407,7 +408,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
// Run the following 'waiting' code outside of the above synchronized block // Run the following 'waiting' code outside of the above synchronized block
// in order to avoid deadlock // in order to avoid deadlock
context.waitForFuture(future); waitForFuture(future);
return context; return context;
} }
@ -497,9 +498,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
private ChannelHandler replace( private ChannelHandler replace(
final DefaultChannelHandlerContext ctx, final String newName, ChannelHandler newHandler) { final DefaultChannelHandlerContext ctx, final String newName, ChannelHandler newHandler) {
Future future; Future<?> future;
DefaultChannelHandlerContext context;
synchronized (this) { synchronized (this) {
if (ctx == head) { if (ctx == head) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
@ -528,7 +527,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
} }
} }
}); });
context = oldTail;
} }
} else { } else {
@ -555,7 +553,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
} }
} }
}); });
context = newCtx;
} }
} }
} }
@ -563,7 +560,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
// Run the following 'waiting' code outside of the above synchronized block // Run the following 'waiting' code outside of the above synchronized block
// in order to avoid deadlock // in order to avoid deadlock
context.waitForFuture(future); waitForFuture(future);
return ctx.handler(); return ctx.handler();
} }
@ -866,33 +863,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
return nextOutboundByteBuffer(tail); return nextOutboundByteBuffer(tail);
} }
static boolean hasNextOutboundByteBuffer(DefaultChannelHandlerContext ctx) { ByteBuf nextOutboundByteBuffer(DefaultChannelHandlerContext ctx) {
for (;;) {
if (ctx == null) {
return false;
}
if (ctx.outByteBridge != null) {
return true;
}
ctx = ctx.prev;
}
}
static boolean hasNextOutboundMessageBuffer(DefaultChannelHandlerContext ctx) {
for (;;) {
if (ctx == null) {
return false;
}
if (ctx.outMsgBridge != null) {
return true;
}
ctx = ctx.prev;
}
}
static ByteBuf nextOutboundByteBuffer(DefaultChannelHandlerContext ctx) {
final DefaultChannelHandlerContext initialCtx = ctx; final DefaultChannelHandlerContext initialCtx = ctx;
final Thread currentThread = Thread.currentThread(); final Thread currentThread = Thread.currentThread();
for (;;) { for (;;) {
@ -910,13 +881,13 @@ public class DefaultChannelPipeline implements ChannelPipeline {
} }
} }
if (ctx.outByteBuf != null) { if (ctx.hasOutboundByteBuffer()) {
if (ctx.executor().inEventLoop(currentThread)) { if (ctx.executor().inEventLoop(currentThread)) {
return ctx.outByteBuf; return ctx.outboundByteBuffer();
} else { } else {
ByteBridge bridge = ctx.outByteBridge.get(); ByteBridge bridge = ctx.outByteBridge.get();
if (bridge == null) { if (bridge == null) {
bridge = new ByteBridge(); bridge = new ByteBridge(ctx);
if (!ctx.outByteBridge.compareAndSet(null, bridge)) { if (!ctx.outByteBridge.compareAndSet(null, bridge)) {
bridge = ctx.outByteBridge.get(); bridge = ctx.outByteBridge.get();
} }
@ -928,7 +899,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
} }
} }
static MessageBuf<Object> nextOutboundMessageBuffer(DefaultChannelHandlerContext ctx) { MessageBuf<Object> nextOutboundMessageBuffer(DefaultChannelHandlerContext ctx) {
final DefaultChannelHandlerContext initialCtx = ctx; final DefaultChannelHandlerContext initialCtx = ctx;
final Thread currentThread = Thread.currentThread(); final Thread currentThread = Thread.currentThread();
for (;;) { for (;;) {
@ -946,9 +917,9 @@ public class DefaultChannelPipeline implements ChannelPipeline {
} }
} }
if (ctx.outMsgBuf != null) { if (ctx.hasOutboundMessageBuffer()) {
if (ctx.executor().inEventLoop(currentThread)) { if (ctx.executor().inEventLoop(currentThread)) {
return ctx.outMsgBuf; return ctx.outboundMessageBuffer();
} else { } else {
MessageBridge bridge = ctx.outMsgBridge.get(); MessageBridge bridge = ctx.outMsgBridge.get();
if (bridge == null) { if (bridge == null) {
@ -972,6 +943,11 @@ public class DefaultChannelPipeline implements ChannelPipeline {
@Override @Override
public void fireChannelUnregistered() { public void fireChannelUnregistered() {
head.fireChannelUnregistered(); head.fireChannelUnregistered();
// Free all buffers if channel is closed and unregistered.
if (!channel.isOpen()) {
head.callFreeInboundBuffer();
}
} }
@Override @Override
@ -1232,8 +1208,8 @@ public class DefaultChannelPipeline implements ChannelPipeline {
} catch (Throwable t) { } catch (Throwable t) {
notifyHandlerException(t); notifyHandlerException(t);
} finally { } finally {
if (ctx.outByteBuf != null) { if (ctx.hasOutboundByteBuffer()) {
ByteBuf buf = ctx.outByteBuf; ByteBuf buf = ctx.outboundByteBuffer();
if (!buf.readable()) { if (!buf.readable()) {
buf.discardReadBytes(); buf.discardReadBytes();
} }
@ -1289,10 +1265,10 @@ public class DefaultChannelPipeline implements ChannelPipeline {
if (executor.inEventLoop()) { if (executor.inEventLoop()) {
if (msgBuf) { if (msgBuf) {
ctx.outMsgBuf.add(message); ctx.outboundMessageBuffer().add(message);
} else { } else {
ByteBuf buf = (ByteBuf) message; ByteBuf buf = (ByteBuf) message;
ctx.outByteBuf.writeBytes(buf, buf.readerIndex(), buf.readableBytes()); ctx.outboundByteBuffer().writeBytes(buf, buf.readerIndex(), buf.readableBytes());
} }
flush0(ctx, future); flush0(ctx, future);
return future; return future;
@ -1325,12 +1301,12 @@ public class DefaultChannelPipeline implements ChannelPipeline {
} }
} }
private DefaultChannelHandlerContext firstContext(int direction) { DefaultChannelHandlerContext firstContext(int direction) {
assert direction == DIR_INBOUND || direction == DIR_OUTBOUND; assert direction == DIR_INBOUND || direction == DIR_OUTBOUND;
if (direction > 0) { if (direction == DIR_INBOUND) {
return nextContext(head.next, direction); return nextContext(head.next, DIR_INBOUND);
} else { } else { // DIR_OUTBOUND
return nextContext(tail, direction); return nextContext(tail, DIR_OUTBOUND);
} }
} }
@ -1342,15 +1318,15 @@ public class DefaultChannelPipeline implements ChannelPipeline {
} }
DefaultChannelHandlerContext realCtx = ctx; DefaultChannelHandlerContext realCtx = ctx;
if (direction > 0) { if (direction == DIR_INBOUND) {
while ((realCtx.directions & direction) == 0) { while ((realCtx.flags & DIR_INBOUND) == 0) {
realCtx = realCtx.next; realCtx = realCtx.next;
if (realCtx == null) { if (realCtx == null) {
return null; return null;
} }
} }
} else { } else { // DIR_OUTBOUND
while ((realCtx.directions & direction) == 0) { while ((realCtx.flags & DIR_OUTBOUND) == 0) {
realCtx = realCtx.prev; realCtx = realCtx.prev;
if (realCtx == null) { if (realCtx == null) {
return null; return null;
@ -1448,8 +1424,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
public ChannelBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { public ChannelBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
switch (channel.metadata().bufferType()) { switch (channel.metadata().bufferType()) {
case BYTE: case BYTE:
// TODO: Use a direct buffer once buffer pooling is implemented. return ctx.alloc().ioBuffer();
return Unpooled.buffer();
case MESSAGE: case MESSAGE:
return Unpooled.messageBuffer(); return Unpooled.messageBuffer();
default: default:
@ -1457,6 +1432,13 @@ public class DefaultChannelPipeline implements ChannelPipeline {
} }
} }
@Override
public void freeOutboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) {
if (buf instanceof UnsafeByteBuf) {
((UnsafeByteBuf) buf).free();
}
}
@Override @Override
public void beforeAdd(ChannelHandlerContext ctx) throws Exception { public void beforeAdd(ChannelHandlerContext ctx) throws Exception {
// NOOP // NOOP

View File

@ -19,6 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.ChannelBuf; import io.netty.buffer.ChannelBuf;
import io.netty.buffer.MessageBuf; import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.buffer.UnsafeByteBuf;
import io.netty.channel.AbstractChannel; import io.netty.channel.AbstractChannel;
import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelException; import io.netty.channel.ChannelException;
@ -211,6 +212,11 @@ public abstract class AbstractEmbeddedChannel extends AbstractChannel {
return lastInboundMessageBuffer; return lastInboundMessageBuffer;
} }
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
// Nothing to free
}
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception {
// Do nothing. // Do nothing.
@ -235,6 +241,11 @@ public abstract class AbstractEmbeddedChannel extends AbstractChannel {
return lastInboundByteBuffer; return lastInboundByteBuffer;
} }
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
((UnsafeByteBuf) buf).free();
}
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception {
// No nothing // No nothing

View File

@ -17,8 +17,10 @@ package io.netty.channel.local;
import io.netty.bootstrap.ServerBootstrap; import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ChannelBuf;
import io.netty.buffer.MessageBuf; import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.buffer.UnsafeByteBuf;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerAdapter;
@ -349,6 +351,16 @@ public class LocalTransportThreadModelTest {
return Unpooled.messageBuffer(); return Unpooled.messageBuffer();
} }
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
// Nothing to free
}
@Override
public void freeOutboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) {
// Nothing to free
}
@Override @Override
public void inboundBufferUpdated( public void inboundBufferUpdated(
ChannelHandlerContext ctx) throws Exception { ChannelHandlerContext ctx) throws Exception {
@ -393,7 +405,17 @@ public class LocalTransportThreadModelTest {
@Override @Override
public ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { public ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return Unpooled.buffer(); return ctx.alloc().buffer();
}
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
// Nothing to free
}
@Override
public void freeOutboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) {
((UnsafeByteBuf) buf).free();
} }
@Override @Override
@ -440,7 +462,7 @@ public class LocalTransportThreadModelTest {
out.add(msg); out.add(msg);
} }
} }
in.unsafe().discardSomeReadBytes(); ((UnsafeByteBuf) in).discardSomeReadBytes();
if (swallow) { if (swallow) {
future.setSuccess(); future.setSuccess();
} else { } else {
@ -472,7 +494,7 @@ public class LocalTransportThreadModelTest {
@Override @Override
public ByteBuf newInboundBuffer( public ByteBuf newInboundBuffer(
ChannelHandlerContext ctx) throws Exception { ChannelHandlerContext ctx) throws Exception {
return Unpooled.buffer(); return ctx.alloc().buffer();
} }
@Override @Override
@ -481,6 +503,16 @@ public class LocalTransportThreadModelTest {
return Unpooled.messageBuffer(); return Unpooled.messageBuffer();
} }
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
((UnsafeByteBuf) buf).free();
}
@Override
public void freeOutboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) {
// Nothing to free
}
@Override @Override
public void inboundBufferUpdated( public void inboundBufferUpdated(
ChannelHandlerContext ctx) throws Exception { ChannelHandlerContext ctx) throws Exception {
@ -556,6 +588,16 @@ public class LocalTransportThreadModelTest {
return Unpooled.messageBuffer(); return Unpooled.messageBuffer();
} }
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
// Nothing to free
}
@Override
public void freeOutboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) {
// Nothing to free
}
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception {
Thread t = this.t; Thread t = this.t;
@ -632,6 +674,16 @@ public class LocalTransportThreadModelTest {
return Unpooled.messageBuffer(); return Unpooled.messageBuffer();
} }
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
// Nothing to free
}
@Override
public void freeOutboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) {
// Nothing to free
}
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception {
Thread t = this.t; Thread t = this.t;