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.
*/
public abstract class AbstractByteBuf implements ByteBuf {
private final SwappedByteBuf swappedBuf;
private final ByteOrder order;
private final int maxCapacity;
public abstract class AbstractByteBuf implements UnsafeByteBuf {
private int readerIndex;
private int writerIndex;
private int markedReaderIndex;
private int markedWriterIndex;
int refCnt = 1;
private final int maxCapacity;
protected AbstractByteBuf(ByteOrder endianness, int maxCapacity) {
if (endianness == null) {
throw new NullPointerException("endianness");
}
private SwappedByteBuf swappedBuf;
protected AbstractByteBuf(int maxCapacity) {
if (maxCapacity < 0) {
throw new IllegalArgumentException("maxCapacity: " + maxCapacity + " (expected: >= 0)");
}
order = endianness;
swappedBuf = new SwappedByteBuf(this);
this.maxCapacity = maxCapacity;
}
@Override
public boolean isPooled() {
return false;
}
@Override
public ChannelBufType type() {
return ChannelBufType.BYTE;
@ -266,19 +254,19 @@ public abstract class AbstractByteBuf implements ByteBuf {
return Math.min(newCapacity, maxCapacity);
}
@Override
public final ByteOrder order() {
return order;
}
@Override
public ByteBuf order(ByteOrder endianness) {
if (endianness == null) {
throw new NullPointerException("endianness");
}
if (endianness == order()) {
if (endianness == order() || capacity() == 0) {
return this;
}
SwappedByteBuf swappedBuf = this.swappedBuf;
if (swappedBuf == null) {
this.swappedBuf = swappedBuf = new SwappedByteBuf(this);
}
return swappedBuf;
}
@ -521,7 +509,9 @@ public abstract class AbstractByteBuf implements ByteBuf {
if (length == 0) {
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);
readerIndex += length;
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();
/**
* Returns the {@link ByteBufAllocator} which created this buffer.
*/
ByteBufAllocator alloc();
/**
* Returns the <a href="http://en.wikipedia.org/wiki/Endianness">endianness</a>
* of this buffer.
@ -1831,53 +1836,4 @@ public interface ByteBuf extends ChannelBuf, Comparable<ByteBuf> {
*/
@Override
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
*/
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 {
private static final ByteBuffer[] EMPTY_NIOBUFFERS = new ByteBuffer[0];
private final ByteBufAllocator alloc;
private final List<Component> components = new ArrayList<Component>();
private final int maxNumComponents;
private final Unsafe unsafe = new CompositeUnsafe();
private Component lastAccessed;
private int lastAccessedId;
private boolean freed;
public DefaultCompositeByteBuf(int maxNumComponents) {
super(ByteOrder.BIG_ENDIAN, Integer.MAX_VALUE);
public DefaultCompositeByteBuf(ByteBufAllocator alloc, int maxNumComponents) {
super(Integer.MAX_VALUE);
if (alloc == null) {
throw new NullPointerException("alloc");
}
this.alloc = alloc;
this.maxNumComponents = maxNumComponents;
}
public DefaultCompositeByteBuf(int maxNumComponents, ByteBuf... buffers) {
super(ByteOrder.BIG_ENDIAN, Integer.MAX_VALUE);
public DefaultCompositeByteBuf(ByteBufAllocator alloc, int maxNumComponents, ByteBuf... buffers) {
super(Integer.MAX_VALUE);
if (alloc == null) {
throw new NullPointerException("alloc");
}
if (maxNumComponents < 2) {
throw new IllegalArgumentException(
"maxNumComponents: " + maxNumComponents + " (expected: >= 2)");
}
this.alloc = alloc;
this.maxNumComponents = maxNumComponents;
addComponents0(0, buffers);
@ -66,14 +76,17 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
setIndex(0, capacity());
}
public DefaultCompositeByteBuf(int maxNumComponents, Iterable<ByteBuf> buffers) {
super(ByteOrder.BIG_ENDIAN, Integer.MAX_VALUE);
public DefaultCompositeByteBuf(ByteBufAllocator alloc, int maxNumComponents, Iterable<ByteBuf> buffers) {
super(Integer.MAX_VALUE);
if (alloc == null) {
throw new NullPointerException("alloc");
}
if (maxNumComponents < 2) {
throw new IllegalArgumentException(
"maxNumComponents: " + maxNumComponents + " (expected: >= 2)");
}
this.alloc = alloc;
this.maxNumComponents = maxNumComponents;
addComponents0(0, buffers);
consolidateIfNeeded();
@ -83,7 +96,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
@Override
public CompositeByteBuf addComponent(ByteBuf buffer) {
addComponent0(components.size(), buffer);
addComponent0(components.size(), buffer, false);
consolidateIfNeeded();
return this;
}
@ -104,12 +117,12 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
@Override
public CompositeByteBuf addComponent(int cIndex, ByteBuf buffer) {
addComponent0(cIndex, buffer);
addComponent0(cIndex, buffer, false);
consolidateIfNeeded();
return this;
}
private int addComponent0(int cIndex, ByteBuf buffer) {
private int addComponent0(int cIndex, ByteBuf buffer, boolean addedBySelf) {
checkComponentIndex(cIndex);
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.
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()) {
components.add(c);
if (cIndex == 0) {
@ -177,7 +190,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
break;
}
if (b.readable()) {
cIndex = addComponent0(cIndex, b) + 1;
cIndex = addComponent0(cIndex, b, false) + 1;
int size = components.size();
if (cIndex > size) {
cIndex = size;
@ -246,16 +259,17 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
if (numComponents > maxNumComponents) {
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.
// noinspection ForLoopReplaceableByForEach
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);
b.unsafe().release();
c.freeIfNecessary();
}
Component c = new Component(consolidated);
Component c = new Component(consolidated, true);
c.endOffset = c.length;
components.clear();
components.add(c);
@ -263,6 +277,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
}
private void checkComponentIndex(int cIndex) {
assert !freed;
if (cIndex < 0 || cIndex > components.size()) {
throw new IndexOutOfBoundsException(String.format(
"cIndex: %d (expected: >= 0 && <= numComponents(%d))",
@ -271,6 +286,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
}
private void checkComponentIndex(int cIndex, int numComponents) {
assert !freed;
if (cIndex < 0 || cIndex + numComponents > components.size()) {
throw new IndexOutOfBoundsException(String.format(
"cIndex: %d, numComponents: %d " +
@ -317,6 +333,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
@Override
public Iterator<ByteBuf> iterator() {
assert !freed;
List<ByteBuf> list = new ArrayList<ByteBuf>(components.size());
for (Component c: components) {
list.add(c.buf);
@ -413,6 +430,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
@Override
public CompositeByteBuf capacity(int newCapacity) {
assert !freed;
if (newCapacity < 0 || newCapacity > maxCapacity()) {
throw new IllegalArgumentException("newCapacity: " + newCapacity);
}
@ -422,13 +440,15 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
final int paddingLength = newCapacity - oldCapacity;
ByteBuf padding;
if (components.isEmpty()) {
padding = new HeapByteBuf(paddingLength, paddingLength);
padding = alloc().buffer(paddingLength, paddingLength);
padding.setIndex(0, paddingLength);
addComponent0(0, padding, true);
} else {
Component last = components.get(components.size() - 1);
padding = last.buf.unsafe().newBuffer(paddingLength);
padding = alloc().buffer(paddingLength);
padding.setIndex(0, paddingLength);
addComponent0(components.size(), padding, true);
consolidateIfNeeded();
}
padding.setIndex(0, paddingLength);
addComponent(padding);
} else if (newCapacity < oldCapacity) {
int bytesToTrim = oldCapacity - newCapacity;
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.
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.endOffset = newC.offset + newC.length;
c.buf.unsafe().release();
i.set(newC);
break;
}
@ -457,6 +476,16 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
return this;
}
@Override
public ByteBufAllocator alloc() {
return alloc;
}
@Override
public ByteOrder order() {
return ByteOrder.BIG_ENDIAN;
}
@Override
public int numComponents() {
return components.size();
@ -469,6 +498,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
@Override
public int toComponentIndex(int offset) {
assert !freed;
if (offset < 0 || offset >= capacity()) {
throw new IndexOutOfBoundsException(String.format(
"offset: %d (expected: >= 0 && < capacity(%d))", offset, capacity()));
@ -941,7 +971,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
+ (index + length) + ", maximum is " + capacity());
}
ByteBuf dst = unsafe().newBuffer(length);
ByteBuf dst = Unpooled.buffer(length);
copyTo(index, length, componentId, dst);
return dst;
}
@ -977,6 +1007,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
}
private Component findComponent(int offset) {
assert !freed;
if (offset < 0 || offset >= capacity()) {
throw new IndexOutOfBoundsException(String.format(
"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) {
assert !freed;
if (components.size() == 1) {
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");
}
if (length == 0) {
return new ByteBuffer[0];
return EMPTY_NIOBUFFERS;
}
int componentId = toComponentIndex(index);
@ -1092,6 +1124,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
@Override
public CompositeByteBuf consolidate() {
assert !freed;
final int numComponents = numComponents();
if (numComponents <= 1) {
return this;
@ -1099,16 +1132,17 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
final Component last = components.get(numComponents - 1);
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 ++) {
ByteBuf b = components.get(i).buf;
Component c = components.get(i);
UnsafeByteBuf b = c.buf;
consolidated.writeBytes(b);
b.unsafe().release();
}
c.freeIfNecessary();
}
components.clear();
components.add(new Component(consolidated));
components.add(new Component(consolidated, true));
updateComponentOffsets(0);
return this;
}
@ -1123,22 +1157,24 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
final int endCIndex = cIndex + numComponents;
final Component last = components.get(endCIndex - 1);
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 ++) {
ByteBuf b = components.get(i).buf;
Component c = components.get(i);
ByteBuf b = c.buf;
consolidated.writeBytes(b);
b.unsafe().release();
c.freeIfNecessary();
}
components.subList(cIndex + 1, endCIndex).clear();
components.set(cIndex, new Component(consolidated));
components.set(cIndex, new Component(consolidated, true));
updateComponentOffsets(cIndex);
return this;
}
@Override
public CompositeByteBuf discardReadComponents() {
assert !freed;
final int readerIndex = readerIndex();
if (readerIndex == 0) {
return this;
@ -1148,7 +1184,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
int writerIndex = writerIndex();
if (readerIndex == writerIndex && writerIndex == capacity()) {
for (Component c: components) {
c.buf.unsafe().release();
c.freeIfNecessary();
}
components.clear();
setIndex(0, 0);
@ -1159,7 +1195,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
// Remove read components.
int firstComponentId = toComponentIndex(readerIndex);
for (int i = 0; i < firstComponentId; i ++) {
components.get(i).buf.unsafe().release();
components.get(i).freeIfNecessary();
}
components.subList(0, firstComponentId).clear();
@ -1173,6 +1209,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
@Override
public CompositeByteBuf discardReadBytes() {
assert !freed;
final int readerIndex = readerIndex();
if (readerIndex == 0) {
return this;
@ -1182,7 +1219,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
int writerIndex = writerIndex();
if (readerIndex == writerIndex && writerIndex == capacity()) {
for (Component c: components) {
c.buf.unsafe().release();
c.freeIfNecessary();
}
components.clear();
setIndex(0, 0);
@ -1193,7 +1230,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
// Remove read components.
int firstComponentId = toComponentIndex(readerIndex);
for (int i = 0; i < firstComponentId; i ++) {
components.get(i).buf.unsafe().release();
components.get(i).freeIfNecessary();
}
components.subList(0, firstComponentId).clear();
@ -1204,8 +1241,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
// new slice would be empty, so remove instead
components.remove(0);
} else {
Component newC = new Component(c.buf.slice(adjustment, c.length - adjustment));
c.buf.unsafe().release();
Component newC = new Component(c.buf.slice(adjustment, c.length - adjustment), c.allocatedBySelf);
components.set(0, newC);
}
@ -1224,14 +1260,29 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
}
private static final class Component {
final ByteBuf buf;
final UnsafeByteBuf buf;
final int length;
final boolean allocatedBySelf;
int offset;
int endOffset;
Component(ByteBuf buf) {
this.buf = buf;
Component(ByteBuf buf, boolean allocatedBySelf) {
this.buf = (UnsafeByteBuf) buf;
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
public Unsafe unsafe() {
return unsafe;
public ByteBuffer[] nioBuffers() {
return nioBuffers(readerIndex(), readableBytes());
}
private final class CompositeUnsafe implements Unsafe {
@Override
public ByteBuffer nioBuffer() {
if (components.size() == 1) {
return components.get(0).buf.unsafe().nioBuffer();
}
throw new UnsupportedOperationException();
@Override
public ByteBuffer internalNioBuffer() {
if (components.size() == 1) {
return components.get(0).buf.internalNioBuffer();
}
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
public ByteBuffer[] nioBuffers() {
ByteBuffer[] nioBuffers = new ByteBuffer[components.size()];
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;
}
freed = true;
for (Component c: components) {
c.freeIfNecessary();
}
}
@Override
public ByteBuffer[] nioBuffers() {
return nioBuffers(readerIndex(), readableBytes());
public ByteBuf unwrap() {
return null;
}
}

View File

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

View File

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

View File

@ -19,6 +19,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ReadOnlyBufferException;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
@ -28,27 +29,36 @@ import java.nio.channels.ScatteringByteChannel;
* recommended to use {@link Unpooled#unmodifiableBuffer(ByteBuf)}
* 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;
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
public ByteBuf unwrap() {
return buffer;
}
@Override
public ByteBufAllocator alloc() {
return buffer.alloc();
}
@Override
public ByteOrder order() {
return buffer.order();
}
@Override
public boolean isDirect() {
return buffer.isDirect();
@ -70,47 +80,47 @@ public class ReadOnlyByteBuf extends AbstractWrappedByteBuf {
}
@Override
public WrappedByteBuf discardReadBytes() {
public ByteBuf discardReadBytes() {
throw new ReadOnlyBufferException();
}
@Override
public WrappedByteBuf setByte(int index, int value) {
public ByteBuf setByte(int index, int value) {
throw new ReadOnlyBufferException();
}
@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();
}
@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();
}
@Override
public WrappedByteBuf setBytes(int index, ByteBuffer src) {
public ByteBuf setBytes(int index, ByteBuffer src) {
throw new ReadOnlyBufferException();
}
@Override
public WrappedByteBuf setShort(int index, int value) {
public ByteBuf setShort(int index, int value) {
throw new ReadOnlyBufferException();
}
@Override
public WrappedByteBuf setMedium(int index, int value) {
public ByteBuf setMedium(int index, int value) {
throw new ReadOnlyBufferException();
}
@Override
public WrappedByteBuf setInt(int index, int value) {
public ByteBuf setInt(int index, int value) {
throw new ReadOnlyBufferException();
}
@Override
public WrappedByteBuf setLong(int index, long value) {
public ByteBuf setLong(int index, long value) {
throw new ReadOnlyBufferException();
}
@ -133,26 +143,26 @@ public class ReadOnlyByteBuf extends AbstractWrappedByteBuf {
}
@Override
public WrappedByteBuf getBytes(int index, OutputStream out, int length)
public ByteBuf getBytes(int index, OutputStream out, int length)
throws IOException {
buffer.getBytes(index, out, length);
return this;
}
@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);
return this;
}
@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);
return this;
}
@Override
public WrappedByteBuf getBytes(int index, ByteBuffer dst) {
public ByteBuf getBytes(int index, ByteBuffer dst) {
buffer.getBytes(index, dst);
return this;
}
@ -169,7 +179,7 @@ public class ReadOnlyByteBuf extends AbstractWrappedByteBuf {
@Override
public ByteBuf slice(int index, int length) {
return new ReadOnlyByteBuf(buffer.slice(index, length));
return new ReadOnlyByteBuf((UnsafeByteBuf) buffer.slice(index, length));
}
@Override
@ -223,12 +233,25 @@ public class ReadOnlyByteBuf extends AbstractWrappedByteBuf {
}
@Override
public WrappedByteBuf capacity(int newCapacity) {
public ByteBuf capacity(int newCapacity) {
throw new ReadOnlyBufferException();
}
@Override
public Unsafe unsafe() {
return buffer.unsafe();
public ByteBuffer internalNioBuffer() {
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.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
@ -29,15 +30,14 @@ import java.nio.channels.ScatteringByteChannel;
* {@link ByteBuf#slice(int, int)} instead of calling the constructor
* explicitly.
*/
public class SlicedByteBuf extends AbstractWrappedByteBuf {
public class SlicedByteBuf extends AbstractByteBuf {
private final Unsafe unsafe = new SlicedUnsafe();
private final ByteBuf buffer;
private final UnsafeByteBuf buffer;
private final int adjustment;
private final int length;
public SlicedByteBuf(ByteBuf buffer, int index, int length) {
super(buffer.order(), length);
public SlicedByteBuf(UnsafeByteBuf buffer, int index, int length) {
super(length);
if (index < 0 || index > buffer.capacity()) {
throw new IndexOutOfBoundsException("Invalid index of " + index
+ ", maximum is " + buffer.capacity());
@ -52,7 +52,7 @@ public class SlicedByteBuf extends AbstractWrappedByteBuf {
this.buffer = ((SlicedByteBuf) buffer).buffer;
adjustment = ((SlicedByteBuf) buffer).adjustment + index;
} else if (buffer instanceof DuplicatedByteBuf) {
this.buffer = ((DuplicatedByteBuf) buffer).buffer;
this.buffer = (UnsafeByteBuf) buffer.unwrap();
adjustment = index;
} else {
this.buffer = buffer;
@ -61,8 +61,6 @@ public class SlicedByteBuf extends AbstractWrappedByteBuf {
this.length = length;
writerIndex(length);
buffer.unsafe().acquire();
}
@Override
@ -70,6 +68,16 @@ public class SlicedByteBuf extends AbstractWrappedByteBuf {
return buffer;
}
@Override
public ByteBufAllocator alloc() {
return buffer.alloc();
}
@Override
public ByteOrder order() {
return buffer.order();
}
@Override
public boolean isDirect() {
return buffer.isDirect();
@ -81,7 +89,7 @@ public class SlicedByteBuf extends AbstractWrappedByteBuf {
}
@Override
public WrappedByteBuf capacity(int newCapacity) {
public ByteBuf capacity(int newCapacity) {
throw new UnsupportedOperationException("sliced buffer");
}
@ -153,84 +161,84 @@ public class SlicedByteBuf extends AbstractWrappedByteBuf {
}
@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);
buffer.getBytes(index + adjustment, dst, dstIndex, length);
return this;
}
@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);
buffer.getBytes(index + adjustment, dst, dstIndex, length);
return this;
}
@Override
public WrappedByteBuf getBytes(int index, ByteBuffer dst) {
public ByteBuf getBytes(int index, ByteBuffer dst) {
checkIndex(index, dst.remaining());
buffer.getBytes(index + adjustment, dst);
return this;
}
@Override
public WrappedByteBuf setByte(int index, int value) {
public ByteBuf setByte(int index, int value) {
checkIndex(index);
buffer.setByte(index + adjustment, value);
return this;
}
@Override
public WrappedByteBuf setShort(int index, int value) {
public ByteBuf setShort(int index, int value) {
checkIndex(index, 2);
buffer.setShort(index + adjustment, value);
return this;
}
@Override
public WrappedByteBuf setMedium(int index, int value) {
public ByteBuf setMedium(int index, int value) {
checkIndex(index, 3);
buffer.setMedium(index + adjustment, value);
return this;
}
@Override
public WrappedByteBuf setInt(int index, int value) {
public ByteBuf setInt(int index, int value) {
checkIndex(index, 4);
buffer.setInt(index + adjustment, value);
return this;
}
@Override
public WrappedByteBuf setLong(int index, long value) {
public ByteBuf setLong(int index, long value) {
checkIndex(index, 8);
buffer.setLong(index + adjustment, value);
return this;
}
@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);
buffer.setBytes(index + adjustment, src, srcIndex, length);
return this;
}
@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);
buffer.setBytes(index + adjustment, src, srcIndex, length);
return this;
}
@Override
public WrappedByteBuf setBytes(int index, ByteBuffer src) {
public ByteBuf setBytes(int index, ByteBuffer src) {
checkIndex(index, src.remaining());
buffer.setBytes(index + adjustment, src);
return this;
}
@Override
public WrappedByteBuf getBytes(int index, OutputStream out, int length)
public ByteBuf getBytes(int index, OutputStream out, int length)
throws IOException {
checkIndex(index, length);
buffer.getBytes(index + adjustment, out, length);
@ -302,40 +310,20 @@ public class SlicedByteBuf extends AbstractWrappedByteBuf {
}
@Override
public Unsafe unsafe() {
return unsafe;
public ByteBuffer internalNioBuffer() {
return buffer.nioBuffer(adjustment, length);
}
private final class SlicedUnsafe implements Unsafe {
@Override
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 ByteBuffer[] internalNioBuffers() {
return buffer.nioBuffers(adjustment, length);
}
@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.charset.Charset;
public class SwappedByteBuf implements WrappedByteBuf {
public class SwappedByteBuf implements UnsafeByteBuf {
private final ByteBuf buf;
private final UnsafeByteBuf buf;
private final ByteOrder order;
public SwappedByteBuf(ByteBuf buf) {
public SwappedByteBuf(UnsafeByteBuf buf) {
if (buf == null) {
throw new NullPointerException("buf");
}
@ -63,8 +63,8 @@ public class SwappedByteBuf implements WrappedByteBuf {
}
@Override
public boolean isPooled() {
return buf.isPooled();
public ByteBufAllocator alloc() {
return buf.alloc();
}
@Override
@ -78,7 +78,7 @@ public class SwappedByteBuf implements WrappedByteBuf {
}
@Override
public WrappedByteBuf capacity(int newCapacity) {
public ByteBuf capacity(int newCapacity) {
buf.capacity(newCapacity);
return this;
}
@ -99,7 +99,7 @@ public class SwappedByteBuf implements WrappedByteBuf {
}
@Override
public WrappedByteBuf readerIndex(int readerIndex) {
public ByteBuf readerIndex(int readerIndex) {
buf.readerIndex(readerIndex);
return this;
}
@ -110,13 +110,13 @@ public class SwappedByteBuf implements WrappedByteBuf {
}
@Override
public WrappedByteBuf writerIndex(int writerIndex) {
public ByteBuf writerIndex(int writerIndex) {
buf.writerIndex(writerIndex);
return this;
}
@Override
public WrappedByteBuf setIndex(int readerIndex, int writerIndex) {
public ByteBuf setIndex(int readerIndex, int writerIndex) {
buf.setIndex(readerIndex, writerIndex);
return this;
}
@ -142,43 +142,43 @@ public class SwappedByteBuf implements WrappedByteBuf {
}
@Override
public WrappedByteBuf clear() {
public ByteBuf clear() {
buf.clear();
return this;
}
@Override
public WrappedByteBuf markReaderIndex() {
public ByteBuf markReaderIndex() {
buf.markReaderIndex();
return this;
}
@Override
public WrappedByteBuf resetReaderIndex() {
public ByteBuf resetReaderIndex() {
buf.resetReaderIndex();
return this;
}
@Override
public WrappedByteBuf markWriterIndex() {
public ByteBuf markWriterIndex() {
buf.markWriterIndex();
return this;
}
@Override
public WrappedByteBuf resetWriterIndex() {
public ByteBuf resetWriterIndex() {
buf.resetWriterIndex();
return this;
}
@Override
public WrappedByteBuf discardReadBytes() {
public ByteBuf discardReadBytes() {
buf.discardReadBytes();
return this;
}
@Override
public WrappedByteBuf ensureWritableBytes(int writableBytes) {
public ByteBuf ensureWritableBytes(int writableBytes) {
buf.ensureWritableBytes(writableBytes);
return this;
}
@ -254,43 +254,43 @@ public class SwappedByteBuf implements WrappedByteBuf {
}
@Override
public WrappedByteBuf getBytes(int index, ByteBuf dst) {
public ByteBuf getBytes(int index, ByteBuf dst) {
buf.getBytes(index, dst);
return this;
}
@Override
public WrappedByteBuf getBytes(int index, ByteBuf dst, int length) {
public ByteBuf getBytes(int index, ByteBuf dst, int length) {
buf.getBytes(index, dst, length);
return this;
}
@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);
return this;
}
@Override
public WrappedByteBuf getBytes(int index, byte[] dst) {
public ByteBuf getBytes(int index, byte[] dst) {
buf.getBytes(index, dst);
return this;
}
@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);
return this;
}
@Override
public WrappedByteBuf getBytes(int index, ByteBuffer dst) {
public ByteBuf getBytes(int index, ByteBuffer dst) {
buf.getBytes(index, dst);
return this;
}
@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);
return this;
}
@ -301,91 +301,91 @@ public class SwappedByteBuf implements WrappedByteBuf {
}
@Override
public WrappedByteBuf setBoolean(int index, boolean value) {
public ByteBuf setBoolean(int index, boolean value) {
buf.setBoolean(index, value);
return this;
}
@Override
public WrappedByteBuf setByte(int index, int value) {
public ByteBuf setByte(int index, int value) {
buf.setByte(index, value);
return this;
}
@Override
public WrappedByteBuf setShort(int index, int value) {
public ByteBuf setShort(int index, int value) {
buf.setShort(index, ByteBufUtil.swapShort((short) value));
return this;
}
@Override
public WrappedByteBuf setMedium(int index, int value) {
public ByteBuf setMedium(int index, int value) {
buf.setMedium(index, ByteBufUtil.swapMedium(value));
return this;
}
@Override
public WrappedByteBuf setInt(int index, int value) {
public ByteBuf setInt(int index, int value) {
buf.setInt(index, ByteBufUtil.swapInt(value));
return this;
}
@Override
public WrappedByteBuf setLong(int index, long value) {
public ByteBuf setLong(int index, long value) {
buf.setLong(index, ByteBufUtil.swapLong(value));
return this;
}
@Override
public WrappedByteBuf setChar(int index, int value) {
public ByteBuf setChar(int index, int value) {
setShort(index, value);
return this;
}
@Override
public WrappedByteBuf setFloat(int index, float value) {
public ByteBuf setFloat(int index, float value) {
setInt(index, Float.floatToRawIntBits(value));
return this;
}
@Override
public WrappedByteBuf setDouble(int index, double value) {
public ByteBuf setDouble(int index, double value) {
setLong(index, Double.doubleToRawLongBits(value));
return this;
}
@Override
public WrappedByteBuf setBytes(int index, ByteBuf src) {
public ByteBuf setBytes(int index, ByteBuf src) {
buf.setBytes(index, src);
return this;
}
@Override
public WrappedByteBuf setBytes(int index, ByteBuf src, int length) {
public ByteBuf setBytes(int index, ByteBuf src, int length) {
buf.setBytes(index, src, length);
return this;
}
@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);
return this;
}
@Override
public WrappedByteBuf setBytes(int index, byte[] src) {
public ByteBuf setBytes(int index, byte[] src) {
buf.setBytes(index, src);
return this;
}
@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);
return this;
}
@Override
public WrappedByteBuf setBytes(int index, ByteBuffer src) {
public ByteBuf setBytes(int index, ByteBuffer src) {
buf.setBytes(index, src);
return this;
}
@ -401,7 +401,7 @@ public class SwappedByteBuf implements WrappedByteBuf {
}
@Override
public WrappedByteBuf setZero(int index, int length) {
public ByteBuf setZero(int index, int length) {
buf.setZero(index, length);
return this;
}
@ -473,7 +473,7 @@ public class SwappedByteBuf implements WrappedByteBuf {
@Override
public ByteBuf readBytes(int length) {
return buf.readBytes(length);
return buf.readBytes(length).order(order());
}
@Override
@ -482,43 +482,43 @@ public class SwappedByteBuf implements WrappedByteBuf {
}
@Override
public WrappedByteBuf readBytes(ByteBuf dst) {
public ByteBuf readBytes(ByteBuf dst) {
buf.readBytes(dst);
return this;
}
@Override
public WrappedByteBuf readBytes(ByteBuf dst, int length) {
public ByteBuf readBytes(ByteBuf dst, int length) {
buf.readBytes(dst, length);
return this;
}
@Override
public WrappedByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
buf.readBytes(dst, dstIndex, length);
return this;
}
@Override
public WrappedByteBuf readBytes(byte[] dst) {
public ByteBuf readBytes(byte[] dst) {
buf.readBytes(dst);
return this;
}
@Override
public WrappedByteBuf readBytes(byte[] dst, int dstIndex, int length) {
public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
buf.readBytes(dst, dstIndex, length);
return this;
}
@Override
public WrappedByteBuf readBytes(ByteBuffer dst) {
public ByteBuf readBytes(ByteBuffer dst) {
buf.readBytes(dst);
return this;
}
@Override
public WrappedByteBuf readBytes(OutputStream out, int length) throws IOException {
public ByteBuf readBytes(OutputStream out, int length) throws IOException {
buf.readBytes(out, length);
return this;
}
@ -529,97 +529,97 @@ public class SwappedByteBuf implements WrappedByteBuf {
}
@Override
public WrappedByteBuf skipBytes(int length) {
public ByteBuf skipBytes(int length) {
buf.skipBytes(length);
return this;
}
@Override
public WrappedByteBuf writeBoolean(boolean value) {
public ByteBuf writeBoolean(boolean value) {
buf.writeBoolean(value);
return this;
}
@Override
public WrappedByteBuf writeByte(int value) {
public ByteBuf writeByte(int value) {
buf.writeByte(value);
return this;
}
@Override
public WrappedByteBuf writeShort(int value) {
public ByteBuf writeShort(int value) {
buf.writeShort(ByteBufUtil.swapShort((short) value));
return this;
}
@Override
public WrappedByteBuf writeMedium(int value) {
public ByteBuf writeMedium(int value) {
buf.writeMedium(ByteBufUtil.swapMedium(value));
return this;
}
@Override
public WrappedByteBuf writeInt(int value) {
public ByteBuf writeInt(int value) {
buf.writeInt(ByteBufUtil.swapInt(value));
return this;
}
@Override
public WrappedByteBuf writeLong(long value) {
public ByteBuf writeLong(long value) {
buf.writeLong(ByteBufUtil.swapLong(value));
return this;
}
@Override
public WrappedByteBuf writeChar(int value) {
public ByteBuf writeChar(int value) {
writeShort(value);
return this;
}
@Override
public WrappedByteBuf writeFloat(float value) {
public ByteBuf writeFloat(float value) {
writeInt(Float.floatToRawIntBits(value));
return this;
}
@Override
public WrappedByteBuf writeDouble(double value) {
public ByteBuf writeDouble(double value) {
writeLong(Double.doubleToRawLongBits(value));
return this;
}
@Override
public WrappedByteBuf writeBytes(ByteBuf src) {
public ByteBuf writeBytes(ByteBuf src) {
buf.writeBytes(src);
return this;
}
@Override
public WrappedByteBuf writeBytes(ByteBuf src, int length) {
public ByteBuf writeBytes(ByteBuf src, int length) {
buf.writeBytes(src, length);
return this;
}
@Override
public WrappedByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
buf.writeBytes(src, srcIndex, length);
return this;
}
@Override
public WrappedByteBuf writeBytes(byte[] src) {
public ByteBuf writeBytes(byte[] src) {
buf.writeBytes(src);
return this;
}
@Override
public WrappedByteBuf writeBytes(byte[] src, int srcIndex, int length) {
public ByteBuf writeBytes(byte[] src, int srcIndex, int length) {
buf.writeBytes(src, srcIndex, length);
return this;
}
@Override
public WrappedByteBuf writeBytes(ByteBuffer src) {
public ByteBuf writeBytes(ByteBuffer src) {
buf.writeBytes(src);
return this;
}
@ -635,7 +635,7 @@ public class SwappedByteBuf implements WrappedByteBuf {
}
@Override
public WrappedByteBuf writeZero(int length) {
public ByteBuf writeZero(int length) {
buf.writeZero(length);
return this;
}
@ -768,11 +768,6 @@ public class SwappedByteBuf implements WrappedByteBuf {
return buf.toString(index, length, charset);
}
@Override
public Unsafe unsafe() {
return buf.unsafe();
}
@Override
public int hashCode() {
return buf.hashCode();
@ -798,4 +793,22 @@ public class SwappedByteBuf implements WrappedByteBuf {
public String 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 {
private static final ByteBufAllocator ALLOC = UnpooledByteBufAllocator.HEAP_BY_DEFAULT;
/**
* Big endian byte order.
*/
@ -90,15 +92,7 @@ public final class Unpooled {
/**
* A buffer whose capacity is {@code 0}.
*/
public static final ByteBuf EMPTY_BUFFER = new HeapByteBuf(0, 0) {
@Override
public ByteBuf order(ByteOrder endianness) {
if (endianness == null) {
throw new NullPointerException("endianness");
}
return this;
}
};
public static final ByteBuf EMPTY_BUFFER = ALLOC.heapBuffer(0, 0);
public static <T> MessageBuf<T> messageBuffer() {
return new DefaultMessageBuf<T>();
@ -120,7 +114,7 @@ public final class Unpooled {
* expands its capacity boundlessly on demand.
*/
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.
*/
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}.
*/
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}.
*/
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}.
*/
public static ByteBuf buffer(int initialCapacity, int maxCapacity) {
if (initialCapacity == 0 && maxCapacity == 0) {
return EMPTY_BUFFER;
}
return new HeapByteBuf(initialCapacity, maxCapacity);
return ALLOC.heapBuffer(initialCapacity, maxCapacity);
}
/**
@ -167,10 +158,7 @@ public final class Unpooled {
* {@code writerIndex} are {@code 0}.
*/
public static ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
if (initialCapacity == 0 && maxCapacity == 0) {
return EMPTY_BUFFER;
}
return new DirectByteBuf(initialCapacity, maxCapacity);
return ALLOC.directBuffer(initialCapacity, maxCapacity);
}
/**
@ -182,7 +170,7 @@ public final class Unpooled {
if (array.length == 0) {
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 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.remaining()).order(buffer.order());
} 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()) {
return new DefaultCompositeByteBuf(maxNumComponents, components);
return new DefaultCompositeByteBuf(ALLOC, maxNumComponents, components);
}
}
@ -312,7 +300,7 @@ public final class Unpooled {
default:
for (ByteBuf b: buffers) {
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()) {
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.
*/
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}.
*/
public static ByteBuf unmodifiableBuffer(ByteBuf buffer) {
if (buffer instanceof ReadOnlyByteBuf) {
buffer = ((ReadOnlyByteBuf) buffer).unwrap();
}
return new ReadOnlyByteBuf(buffer);
return new ReadOnlyByteBuf((UnsafeByteBuf) 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.
*/
@SuppressWarnings("restriction")
public class DirectByteBuf extends AbstractByteBuf {
public class UnpooledDirectByteBuf extends AbstractByteBuf {
private static final Field CLEANER_FIELD;
@ -52,6 +52,11 @@ public class DirectByteBuf extends AbstractByteBuf {
}
private static void freeDirect(ByteBuffer buffer) {
if (CLEANER_FIELD == null) {
// Doomed to wait for GC.
return;
}
Cleaner cleaner;
try {
cleaner = (Cleaner) CLEANER_FIELD.get(buffer);
@ -61,12 +66,12 @@ public class DirectByteBuf extends AbstractByteBuf {
}
}
private final Unsafe unsafe = new DirectUnsafe();
private boolean doNotFree;
private final ByteBufAllocator alloc;
private ByteBuffer buffer;
private ByteBuffer tmpBuf;
private ByteBuffer tmpNioBuf;
private int capacity;
private boolean freed;
private boolean doNotFree;
/**
* 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 maxCapacity the maximum capacity of the underlying direct buffer
*/
public DirectByteBuf(int initialCapacity, int maxCapacity) {
super(ByteOrder.BIG_ENDIAN, maxCapacity);
public UnpooledDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
super(maxCapacity);
if (alloc == null) {
throw new NullPointerException("alloc");
}
if (initialCapacity < 0) {
throw new IllegalArgumentException("initialCapacity: " + initialCapacity);
}
@ -87,6 +95,7 @@ public class DirectByteBuf extends AbstractByteBuf {
"initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
}
this.alloc = alloc;
setByteBuffer(ByteBuffer.allocateDirect(initialCapacity));
}
@ -95,9 +104,11 @@ public class DirectByteBuf extends AbstractByteBuf {
*
* @param maxCapacity the maximum capacity of the underlying direct buffer
*/
public DirectByteBuf(ByteBuffer initialBuffer, int maxCapacity) {
super(ByteOrder.BIG_ENDIAN, maxCapacity);
public UnpooledDirectByteBuf(ByteBufAllocator alloc, ByteBuffer initialBuffer, int maxCapacity) {
super(maxCapacity);
if (alloc == null) {
throw new NullPointerException("alloc");
}
if (initialBuffer == null) {
throw new NullPointerException("initialBuffer");
}
@ -114,6 +125,7 @@ public class DirectByteBuf extends AbstractByteBuf {
"initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
}
this.alloc = alloc;
doNotFree = true;
setByteBuffer(initialBuffer.slice().order(ByteOrder.BIG_ENDIAN));
writerIndex(initialCapacity);
@ -130,7 +142,7 @@ public class DirectByteBuf extends AbstractByteBuf {
}
this.buffer = buffer;
tmpBuf = buffer.duplicate();
tmpNioBuf = null;
capacity = buffer.remaining();
}
@ -146,6 +158,7 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override
public ByteBuf capacity(int newCapacity) {
assert !freed;
if (newCapacity < 0 || newCapacity > maxCapacity()) {
throw new IllegalArgumentException("newCapacity: " + newCapacity);
}
@ -181,6 +194,16 @@ public class DirectByteBuf extends AbstractByteBuf {
return this;
}
@Override
public ByteBufAllocator alloc() {
return alloc;
}
@Override
public ByteOrder order() {
return ByteOrder.BIG_ENDIAN;
}
@Override
public boolean hasArray() {
return false;
@ -198,34 +221,40 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override
public byte getByte(int index) {
assert !freed;
return buffer.get(index);
}
@Override
public short getShort(int index) {
assert !freed;
return buffer.getShort(index);
}
@Override
public int getUnsignedMedium(int index) {
assert !freed;
return (getByte(index) & 0xff) << 16 | (getByte(index + 1) & 0xff) << 8 | getByte(index + 2) & 0xff;
}
@Override
public int getInt(int index) {
assert !freed;
return buffer.getInt(index);
}
@Override
public long getLong(int index) {
assert !freed;
return buffer.getLong(index);
}
@Override
public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
if (dst instanceof DirectByteBuf) {
DirectByteBuf bbdst = (DirectByteBuf) dst;
ByteBuffer data = bbdst.tmpBuf;
assert !freed;
if (dst instanceof UnpooledDirectByteBuf) {
UnpooledDirectByteBuf bbdst = (UnpooledDirectByteBuf) dst;
ByteBuffer data = bbdst.internalNioBuffer();
data.clear().position(dstIndex).limit(dstIndex + length);
getBytes(index, data);
} else if (buffer.hasArray()) {
@ -238,6 +267,8 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override
public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
assert !freed;
ByteBuffer tmpBuf = internalNioBuffer();
try {
tmpBuf.clear().position(index).limit(index + length);
} catch (IllegalArgumentException e) {
@ -250,7 +281,9 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override
public ByteBuf getBytes(int index, ByteBuffer dst) {
assert !freed;
int bytesToCopy = Math.min(capacity() - index, dst.remaining());
ByteBuffer tmpBuf = internalNioBuffer();
try {
tmpBuf.clear().position(index).limit(index + bytesToCopy);
} catch (IllegalArgumentException e) {
@ -263,18 +296,21 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override
public ByteBuf setByte(int index, int value) {
assert !freed;
buffer.put(index, (byte) value);
return this;
}
@Override
public ByteBuf setShort(int index, int value) {
assert !freed;
buffer.putShort(index, (short) value);
return this;
}
@Override
public ByteBuf setMedium(int index, int value) {
assert !freed;
setByte(index, (byte) (value >>> 16));
setByte(index + 1, (byte) (value >>> 8));
setByte(index + 2, (byte) value);
@ -283,21 +319,24 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override
public ByteBuf setInt(int index, int value) {
assert !freed;
buffer.putInt(index, value);
return this;
}
@Override
public ByteBuf setLong(int index, long value) {
assert !freed;
buffer.putLong(index, value);
return this;
}
@Override
public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
if (src instanceof DirectByteBuf) {
DirectByteBuf bbsrc = (DirectByteBuf) src;
ByteBuffer data = bbsrc.tmpBuf;
assert !freed;
if (src instanceof UnpooledDirectByteBuf) {
UnpooledDirectByteBuf bbsrc = (UnpooledDirectByteBuf) src;
ByteBuffer data = bbsrc.internalNioBuffer();
data.clear().position(srcIndex).limit(srcIndex + length);
setBytes(index, data);
@ -311,6 +350,8 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
assert !freed;
ByteBuffer tmpBuf = internalNioBuffer();
tmpBuf.clear().position(index).limit(index + length);
tmpBuf.put(src, srcIndex, length);
return this;
@ -318,6 +359,8 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override
public ByteBuf setBytes(int index, ByteBuffer src) {
assert !freed;
ByteBuffer tmpBuf = internalNioBuffer();
if (src == tmpBuf) {
src = src.duplicate();
}
@ -329,6 +372,7 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override
public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
assert !freed;
if (length == 0) {
return this;
}
@ -337,6 +381,7 @@ public class DirectByteBuf extends AbstractByteBuf {
out.write(buffer.array(), index + buffer.arrayOffset(), length);
} else {
byte[] tmp = new byte[length];
ByteBuffer tmpBuf = internalNioBuffer();
tmpBuf.clear().position(index);
tmpBuf.get(tmp);
out.write(tmp);
@ -346,33 +391,38 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override
public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
assert !freed;
if (length == 0) {
return 0;
}
ByteBuffer tmpBuf = internalNioBuffer();
tmpBuf.clear().position(index).limit(index + length);
return out.write(tmpBuf);
}
@Override
public int setBytes(int index, InputStream in, int length) throws IOException {
assert !freed;
if (buffer.hasArray()) {
return in.read(buffer.array(), buffer.arrayOffset() + index, length);
} else {
byte[] tmp = new byte[length];
int readBytes = in.read(tmp);
tmpBuf.clear().position(index);
tmpBuf.put(tmp);
ByteBuffer tmpNioBuf = internalNioBuffer();
tmpNioBuf.clear().position(index);
tmpNioBuf.put(tmp);
return readBytes;
}
}
@Override
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 {
return in.read(tmpBuf);
return in.read(tmpNioBuf);
} catch (ClosedChannelException e) {
return -1;
}
@ -385,10 +435,11 @@ public class DirectByteBuf extends AbstractByteBuf {
@Override
public ByteBuffer nioBuffer(int index, int length) {
assert !freed;
if (index == 0 && length == capacity()) {
return buffer.duplicate();
} 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
public ByteBuf copy(int index, int length) {
assert !freed;
ByteBuffer src;
try {
src = (ByteBuffer) tmpBuf.clear().position(index).limit(index + length);
src = (ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length);
} catch (IllegalArgumentException e) {
throw new IndexOutOfBoundsException("Too many bytes to read - Need " + (index + length));
}
@ -416,67 +468,52 @@ public class DirectByteBuf extends AbstractByteBuf {
dst.put(src);
dst.order(order());
dst.clear();
return new DirectByteBuf(dst, maxCapacity());
return new UnpooledDirectByteBuf(alloc(), dst, maxCapacity());
}
@Override
public Unsafe unsafe() {
return unsafe;
public ByteBuffer internalNioBuffer() {
ByteBuffer tmpNioBuf = this.tmpNioBuf;
if (tmpNioBuf == null) {
this.tmpNioBuf = tmpNioBuf = buffer.duplicate();
}
return tmpNioBuf;
}
private class DirectUnsafe implements Unsafe {
@Override
public ByteBuffer nioBuffer() {
return tmpBuf;
@Override
public ByteBuffer[] internalNioBuffers() {
throw new UnsupportedOperationException();
}
@Override
public void discardSomeReadBytes() {
final int readerIndex = readerIndex();
if (readerIndex == writerIndex()) {
discardReadBytes();
return;
}
@Override
public ByteBuffer[] nioBuffers() {
throw new UnsupportedOperationException();
if (readerIndex > 0 && readerIndex >= capacity >>> 1) {
discardReadBytes();
}
}
@Override
public void free() {
if (freed) {
return;
}
@Override
public ByteBuf newBuffer(int initialCapacity) {
return new DirectByteBuf(initialCapacity, Math.max(initialCapacity, maxCapacity()));
freed = true;
if (doNotFree) {
return;
}
@Override
public void discardSomeReadBytes() {
final int readerIndex = readerIndex();
if (readerIndex == writerIndex()) {
discardReadBytes();
return;
}
freeDirect(buffer);
}
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) {
if (doNotFree) {
doNotFree = false;
} else {
freeDirect(buffer);
}
buffer = null;
tmpBuf = null;
}
}
@Override
public ByteBuf unwrap() {
return null;
}
}

View File

@ -27,12 +27,12 @@ import java.nio.channels.ScatteringByteChannel;
/**
* Big endian Java heap buffer implementation.
*/
public class HeapByteBuf extends AbstractByteBuf {
private final Unsafe unsafe = new HeapUnsafe();
public class UnpooledHeapByteBuf extends AbstractByteBuf {
private final ByteBufAllocator alloc;
private byte[] array;
private ByteBuffer nioBuf;
private ByteBuffer tmpNioBuf;
private boolean freed;
/**
* 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 maxCapacity the max capacity of the underlying byte array
*/
public HeapByteBuf(int initialCapacity, int maxCapacity) {
this(new byte[initialCapacity], 0, 0, maxCapacity);
public UnpooledHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int 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 maxCapacity the max capacity of the underlying byte array
*/
public HeapByteBuf(byte[] initialArray, int maxCapacity) {
this(initialArray, 0, initialArray.length, maxCapacity);
public UnpooledHeapByteBuf(ByteBufAllocator alloc, byte[] initialArray, int maxCapacity) {
this(alloc, initialArray, 0, initialArray.length, maxCapacity);
}
private HeapByteBuf(byte[] initialArray, int readerIndex, int writerIndex, int maxCapacity) {
super(ByteOrder.BIG_ENDIAN, maxCapacity);
private UnpooledHeapByteBuf(
ByteBufAllocator alloc, byte[] initialArray, int readerIndex, int writerIndex, int maxCapacity) {
super(maxCapacity);
if (alloc == null) {
throw new NullPointerException("alloc");
}
if (initialArray == null) {
throw new NullPointerException("initialArray");
}
@ -64,13 +70,24 @@ public class HeapByteBuf extends AbstractByteBuf {
"initialCapacity(%d) > maxCapacity(%d)", initialArray.length, maxCapacity));
}
this.alloc = alloc;
setArray(initialArray);
setIndex(readerIndex, writerIndex);
}
private void setArray(byte[] initialArray) {
array = initialArray;
nioBuf = ByteBuffer.wrap(initialArray);
tmpNioBuf = null;
}
@Override
public ByteBufAllocator alloc() {
return alloc;
}
@Override
public ByteOrder order() {
return ByteOrder.BIG_ENDIAN;
}
@Override
@ -85,6 +102,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override
public ByteBuf capacity(int newCapacity) {
assert !freed;
if (newCapacity < 0 || newCapacity > maxCapacity()) {
throw new IllegalArgumentException("newCapacity: " + newCapacity);
}
@ -118,6 +136,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override
public byte[] array() {
assert !freed;
return array;
}
@ -128,13 +147,15 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override
public byte getByte(int index) {
assert !freed;
return array[index];
}
@Override
public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
if (dst instanceof HeapByteBuf) {
getBytes(index, ((HeapByteBuf) dst).array, dstIndex, length);
assert !freed;
if (dst instanceof UnpooledHeapByteBuf) {
getBytes(index, ((UnpooledHeapByteBuf) dst).array, dstIndex, length);
} else {
dst.setBytes(dstIndex, array, index, length);
}
@ -143,39 +164,43 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override
public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
assert !freed;
System.arraycopy(array, index, dst, dstIndex, length);
return this;
}
@Override
public ByteBuf getBytes(int index, ByteBuffer dst) {
assert !freed;
dst.put(array, index, Math.min(capacity() - index, dst.remaining()));
return this;
}
@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;
out.write(array, index, length);
return this;
}
@Override
public int getBytes(int index, GatheringByteChannel out, int length)
throws IOException {
return out.write((ByteBuffer) nioBuf.clear().position(index).limit(index + length));
public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
assert !freed;
return out.write((ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length));
}
@Override
public ByteBuf setByte(int index, int value) {
assert !freed;
array[index] = (byte) value;
return this;
}
@Override
public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
if (src instanceof HeapByteBuf) {
setBytes(index, ((HeapByteBuf) src).array, srcIndex, length);
assert !freed;
if (src instanceof UnpooledHeapByteBuf) {
setBytes(index, ((UnpooledHeapByteBuf) src).array, srcIndex, length);
} else {
src.getBytes(srcIndex, array, index, length);
}
@ -184,25 +209,29 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
assert !freed;
System.arraycopy(src, srcIndex, array, index, length);
return this;
}
@Override
public ByteBuf setBytes(int index, ByteBuffer src) {
assert !freed;
src.get(array, index, src.remaining());
return this;
}
@Override
public int setBytes(int index, InputStream in, int length) throws IOException {
assert !freed;
return in.read(array, index, length);
}
@Override
public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
assert !freed;
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) {
return -1;
}
@ -215,6 +244,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override
public ByteBuffer nioBuffer(int index, int length) {
assert !freed;
return ByteBuffer.wrap(array, index, length);
}
@ -230,11 +260,13 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override
public short getShort(int index) {
assert !freed;
return (short) (array[index] << 8 | array[index + 1] & 0xFF);
}
@Override
public int getUnsignedMedium(int index) {
assert !freed;
return (array[index] & 0xff) << 16 |
(array[index + 1] & 0xff) << 8 |
array[index + 2] & 0xff;
@ -242,6 +274,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override
public int getInt(int index) {
assert !freed;
return (array[index] & 0xff) << 24 |
(array[index + 1] & 0xff) << 16 |
(array[index + 2] & 0xff) << 8 |
@ -250,6 +283,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override
public long getLong(int index) {
assert !freed;
return ((long) array[index] & 0xff) << 56 |
((long) array[index + 1] & 0xff) << 48 |
((long) array[index + 2] & 0xff) << 40 |
@ -262,6 +296,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override
public ByteBuf setShort(int index, int value) {
assert !freed;
array[index] = (byte) (value >>> 8);
array[index + 1] = (byte) value;
return this;
@ -269,6 +304,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override
public ByteBuf setMedium(int index, int value) {
assert !freed;
array[index] = (byte) (value >>> 16);
array[index + 1] = (byte) (value >>> 8);
array[index + 2] = (byte) value;
@ -277,6 +313,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override
public ByteBuf setInt(int index, int value) {
assert !freed;
array[index] = (byte) (value >>> 24);
array[index + 1] = (byte) (value >>> 16);
array[index + 2] = (byte) (value >>> 8);
@ -286,6 +323,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override
public ByteBuf setLong(int index, long value) {
assert !freed;
array[index] = (byte) (value >>> 56);
array[index + 1] = (byte) (value >>> 48);
array[index + 2] = (byte) (value >>> 40);
@ -299,6 +337,7 @@ public class HeapByteBuf extends AbstractByteBuf {
@Override
public ByteBuf copy(int index, int length) {
assert !freed;
if (index < 0 || length < 0 || index + length > array.length) {
throw new IndexOutOfBoundsException("Too many bytes to copy - Need "
+ (index + length) + ", maximum is " + array.length);
@ -306,61 +345,43 @@ public class HeapByteBuf extends AbstractByteBuf {
byte[] copiedArray = new byte[length];
System.arraycopy(array, index, copiedArray, 0, length);
return new HeapByteBuf(copiedArray, maxCapacity());
return new UnpooledHeapByteBuf(alloc(), copiedArray, maxCapacity());
}
@Override
public Unsafe unsafe() {
return unsafe;
public ByteBuffer internalNioBuffer() {
ByteBuffer tmpNioBuf = this.tmpNioBuf;
if (tmpNioBuf == null) {
this.tmpNioBuf = tmpNioBuf = ByteBuffer.wrap(array);
}
return tmpNioBuf;
}
private class HeapUnsafe implements Unsafe {
@Override
public ByteBuffer nioBuffer() {
return nioBuf;
@Override
public ByteBuffer[] internalNioBuffers() {
throw new UnsupportedOperationException();
}
@Override
public void discardSomeReadBytes() {
final int readerIndex = readerIndex();
if (readerIndex == writerIndex()) {
discardReadBytes();
return;
}
@Override
public ByteBuffer[] nioBuffers() {
throw new UnsupportedOperationException();
if (readerIndex > 0 && readerIndex >= capacity() >>> 1) {
discardReadBytes();
}
}
@Override
public ByteBuf newBuffer(int initialCapacity) {
return new HeapByteBuf(initialCapacity, Math.max(initialCapacity, maxCapacity()));
}
@Override
public void free() {
freed = true;
}
@Override
public void discardSomeReadBytes() {
final int readerIndex = readerIndex();
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;
}
}
@Override
public ByteBuf unwrap() {
return 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;
import static org.junit.Assert.*;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Tests big-endian heap channel buffers
*/
@ -39,7 +39,12 @@ public class BigEndianHeapChannelBufferTest extends AbstractChannelBufferTest {
}
@Test(expected = NullPointerException.class)
public void shouldNotAllowNullInConstructor() {
new HeapByteBuf(null, 0);
public void shouldNotAllowNullInConstructor1() {
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;
import static org.junit.Assert.*;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Tests duplicated channel buffers
*/
@ -28,7 +28,7 @@ public class DuplicateChannelBufferTest extends AbstractChannelBufferTest {
@Override
protected ByteBuf newBuffer(int length) {
buffer = new DuplicatedByteBuf(Unpooled.buffer(length));
buffer = new DuplicatedByteBuf((UnsafeByteBuf) Unpooled.buffer(length));
assertEquals(0, buffer.writerIndex());
return buffer;
}

View File

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

View File

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

View File

@ -15,6 +15,7 @@
*/
package io.netty.handler.codec.spdy;
import io.netty.buffer.ChannelBuf;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
@ -95,6 +96,16 @@ public class SpdySessionHandler
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
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception {
MessageBuf<Object> in = ctx.inboundMessageBuffer();

View File

@ -16,6 +16,7 @@
package io.netty.handler.codec;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.UnsafeByteBuf;
import io.netty.channel.ChannelHandlerContext;
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) {
ctx.fireInboundBufferUpdated();
}

View File

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

View File

@ -16,12 +16,13 @@
package io.netty.handler.codec;
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.ChannelHandlerUtil;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelHandlerUtil;
public abstract class ByteToMessageDecoder<O>
extends ChannelInboundHandlerAdapter implements ChannelInboundByteHandler {
@ -36,7 +37,12 @@ public abstract class ByteToMessageDecoder<O>
@Override
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
@ -92,7 +98,7 @@ public abstract class ByteToMessageDecoder<O>
break;
}
} catch (Throwable t) {
in.unsafe().discardSomeReadBytes();
((UnsafeByteBuf) in).discardSomeReadBytes();
if (decoded) {
decoded = false;
@ -107,7 +113,7 @@ public abstract class ByteToMessageDecoder<O>
}
}
in.unsafe().discardSomeReadBytes();
((UnsafeByteBuf) in).discardSomeReadBytes();
if (decoded) {
ctx.fireInboundBufferUpdated();

View File

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

View File

@ -16,6 +16,7 @@
package io.netty.handler.codec;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.serialization.ObjectDecoder;
@ -426,7 +427,7 @@ public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder<Object> {
* is overridden to avoid memory copy.
*/
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);
return frame;
}

View File

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

View File

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

View File

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

View File

@ -16,10 +16,12 @@
package io.netty.handler.codec;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufIndexFinder;
import io.netty.buffer.ChannelBufType;
import io.netty.buffer.SwappedByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.buffer.UnsafeByteBuf;
import io.netty.util.internal.Signal;
import java.io.IOException;
@ -31,7 +33,7 @@ import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.nio.charset.Charset;
class ReplayingDecoderBuffer implements ByteBuf {
class ReplayingDecoderBuffer implements UnsafeByteBuf {
private static final Signal REPLAY = ReplayingDecoder.REPLAY;
@ -79,8 +81,8 @@ class ReplayingDecoderBuffer implements ByteBuf {
}
@Override
public boolean isPooled() {
return false;
public ByteBufAllocator alloc() {
return buffer.alloc();
}
@Override
@ -849,7 +851,27 @@ class ReplayingDecoderBuffer implements ByteBuf {
}
@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();
}
}

View File

@ -20,6 +20,7 @@
package io.netty.handler.codec.base64;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
/**
* 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;
ByteBuf dest = src.unsafe().newBuffer(
ByteBuf dest = Unpooled.buffer(
len43 +
(len % 3 > 0? 4 : 0) + // Account for padding
(breakLines? len43 / MAX_LINE_LENGTH : 0)).order(src.order()); // New lines
(len % 3 > 0 ? 4 : 0) + // Account for padding
(breakLines ? len43 / MAX_LINE_LENGTH : 0)).order(src.order()); // New lines
int d = 0;
int e = 0;
int len2 = len - 2;
@ -219,7 +220,7 @@ public final class Base64 {
byte[] DECODABET = decodabet(dialect);
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;
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.ByteBufOutputStream;
import io.netty.buffer.UnsafeByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.Attribute;
@ -97,7 +98,7 @@ public class CompatibleObjectEncoder extends MessageToByteEncoder<Object> {
oos.reset();
// 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;
import sun.misc.Cleaner;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
@ -38,11 +42,11 @@ public final class DetectionUtil {
private static final int JAVA_VERSION = javaVersion0();
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_ROOT;
static {
Pattern PERMISSION_DENIED = Pattern.compile(".*permission.*denied.*");
String os = SystemPropertyUtil.get("os.name", "").toLowerCase(Locale.UK);
// windows
@ -82,6 +86,21 @@ public final class DetectionUtil {
}
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;
}
public static boolean canFreeDirectBuffer() {
return CAN_FREE_DIRECT_BUFFER;
}
private static boolean hasUnsafe(ClassLoader loader) {
boolean noUnsafe = SystemPropertyUtil.getBoolean("io.netty.noUnsafe", false);
if (noUnsafe) {

View File

@ -16,7 +16,8 @@
package io.netty.handler.logging;
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.ChannelHandlerContext;
import io.netty.channel.ChannelInboundByteHandler;
@ -108,12 +109,22 @@ public class ByteLoggingHandler
}
@Override
public ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return Unpooled.buffer();
return ctx.alloc().buffer();
}
@Override
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

View File

@ -15,6 +15,7 @@
*/
package io.netty.handler.logging;
import io.netty.buffer.ChannelBuf;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
@ -57,6 +58,16 @@ public class MessageLoggingHandler
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
public void inboundBufferUpdated(ChannelHandlerContext ctx)
throws Exception {

View File

@ -17,7 +17,8 @@ package io.netty.handler.ssl;
import io.netty.buffer.ByteBuf;
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.ChannelFlushFutureNotifier;
import io.netty.channel.ChannelFuture;
@ -32,6 +33,10 @@ import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory;
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.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
@ -44,11 +49,6 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
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
* &middot; TLS</a> and StartTLS support to a {@link Channel}. Please refer
@ -376,12 +376,22 @@ public class SslHandler
@Override
public ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return Unpooled.buffer();
return ctx.alloc().buffer();
}
@Override
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
@ -401,7 +411,7 @@ public class SslHandler
final ByteBuf in = ctx.outboundByteBuffer();
final ByteBuf out = ctx.nextOutboundByteBuffer();
out.unsafe().discardSomeReadBytes();
((UnsafeByteBuf) out).discardSomeReadBytes();
// Do not encrypt the first write request if this handler is
// created with startTLS flag turned on.
@ -473,7 +483,7 @@ public class SslHandler
setHandshakeFailure(e);
throw e;
} finally {
in.unsafe().discardSomeReadBytes();
((UnsafeByteBuf) in).discardSomeReadBytes();
flush0(ctx, bytesConsumed);
}
}

View File

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

View File

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

View File

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

View File

@ -106,7 +106,7 @@ import java.nio.channels.SelectionKey;
*
* @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.
@ -131,12 +131,6 @@ public interface Channel extends AttributeMap, ChannelOutboundInvoker, ChannelFu
*/
ChannelConfig config();
/**
* Returns the {@link ChannelPipeline} which handles {@link ChannelEvent}s
* associated with this channel.
*/
ChannelPipeline pipeline();
boolean isOpen();
boolean isRegistered();
boolean isActive();

View File

@ -15,6 +15,7 @@
*/
package io.netty.channel;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.socket.SocketChannelConfig;
import java.nio.ByteBuffer;
@ -136,4 +137,7 @@ public interface ChannelConfig {
* if the specified value is {@code 0} or less than {@code 0}
*/
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
*/
public interface ChannelHandlerContext
extends AttributeMap, ChannelFutureFactory,
extends AttributeMap, ChannelPropertyAccess,
ChannelInboundInvoker, ChannelOutboundInvoker {
/**
@ -134,11 +134,6 @@ public interface ChannelHandlerContext
*/
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
* 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;
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
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
@ -44,7 +50,7 @@ public abstract class ChannelInboundByteHandlerAdapter
inboundBufferUpdated(ctx, in);
} finally {
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}.
*/
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;
import io.netty.buffer.ChannelBuf;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled;
@ -33,6 +34,11 @@ public abstract class ChannelInboundMessageHandlerAdapter<I>
return Unpooled.messageBuffer();
}
@Override
public void freeInboundBuffer(ChannelHandlerContext ctx, ChannelBuf buf) throws Exception {
// Nothing to free
}
@SuppressWarnings("unchecked")
@Override
public final void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception {

View File

@ -15,6 +15,7 @@
*/
package io.netty.channel;
import io.netty.buffer.ByteBufAllocator;
import io.netty.util.UniqueName;
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>();
public static final ChannelOption<ByteBufAllocator> ALLOCATOR = new ChannelOption<ByteBufAllocator>("ALLOCATOR");
public static final ChannelOption<Integer> CONNECT_TIMEOUT_MILLIS =
new ChannelOption<Integer>("CONNECT_TIMEOUT_MILLIS");
public static final ChannelOption<Integer> WRITE_SPIN_COUNT =

View File

@ -16,12 +16,18 @@
package io.netty.channel;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.buffer.ChannelBuf;
import io.netty.buffer.UnsafeByteBuf;
public abstract class ChannelOutboundByteHandlerAdapter
extends ChannelOutboundHandlerAdapter implements ChannelOutboundByteHandler {
@Override
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 {
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;
import io.netty.buffer.ChannelBuf;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled;
@ -24,4 +25,9 @@ public abstract class ChannelOutboundMessageHandlerAdapter<I>
public MessageBuf<I> newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
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;
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}

View File

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

View File

@ -15,6 +15,8 @@
*/
package io.netty.channel;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.socket.SocketChannelConfig;
import java.util.IdentityHashMap;
@ -28,14 +30,16 @@ import static io.netty.channel.ChannelOption.*;
*/
public class DefaultChannelConfig implements ChannelConfig {
private static final ByteBufAllocator DEFAULT_ALLOCATOR = UnpooledByteBufAllocator.HEAP_BY_DEFAULT;
private static final int DEFAULT_CONNECT_TIMEOUT = 30000;
private volatile ByteBufAllocator allocator = DEFAULT_ALLOCATOR;
private volatile int connectTimeoutMillis = DEFAULT_CONNECT_TIMEOUT;
private volatile int writeSpinCount = 16;
@Override
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(
@ -79,6 +83,9 @@ public class DefaultChannelConfig implements ChannelConfig {
if (option == WRITE_SPIN_COUNT) {
return (T) Integer.valueOf(getWriteSpinCount());
}
if (option == ALLOCATOR) {
return (T) getAllocator();
}
return null;
}
@ -91,6 +98,8 @@ public class DefaultChannelConfig implements ChannelConfig {
setConnectTimeoutMillis((Integer) value);
} else if (option == WRITE_SPIN_COUNT) {
setWriteSpinCount((Integer) value);
} else if (option == ALLOCATOR) {
setAllocator((ByteBufAllocator) value);
} else {
return false;
}
@ -132,4 +141,19 @@ public class DefaultChannelConfig implements ChannelConfig {
}
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;
import static io.netty.channel.DefaultChannelPipeline.*;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ChannelBuf;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled;
import io.netty.buffer.UnsafeByteBuf;
import io.netty.util.DefaultAttributeMap;
import java.net.SocketAddress;
@ -34,42 +35,47 @@ import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import static io.netty.channel.DefaultChannelPipeline.*;
final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext {
private static final EnumSet<ChannelHandlerType> EMPTY_TYPE = EnumSet.noneOf(ChannelHandlerType.class);
static final int DIR_INBOUND = 0x00000001;
static final int DIR_OUTBOUND = 0x80000000;
static final int DIR_INBOUND = 1;
static final int DIR_OUTBOUND = 2;
private static final int FLAG_NEEDS_LAZY_INIT = 4;
volatile DefaultChannelHandlerContext next;
volatile DefaultChannelHandlerContext prev;
private final Channel channel;
private final DefaultChannelPipeline pipeline;
EventExecutor executor; // not thread-safe but OK because it never changes once set.
private final String name;
private final Set<ChannelHandlerType> type;
final int directions;
private final ChannelHandler handler;
final int flags;
final AtomicBoolean readable = new AtomicBoolean(true);
MessageBuf<Object> inMsgBuf;
ByteBuf inByteBuf;
MessageBuf<Object> outMsgBuf;
ByteBuf outByteBuf;
EventExecutor executor; // not thread-safe but OK because it never changes once set.
private MessageBuf<Object> inMsgBuf;
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,
// 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
// '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().
final AtomicReference<MessageBridge> inMsgBridge;
final AtomicReference<MessageBridge> outMsgBridge;
final AtomicReference<ByteBridge> inByteBridge;
final AtomicReference<ByteBridge> outByteBridge;
final AtomicBoolean readable = new AtomicBoolean(true);
private final AtomicReference<MessageBridge> inMsgBridge;
AtomicReference<MessageBridge> outMsgBridge;
private final AtomicReference<ByteBridge> inByteBridge;
AtomicReference<ByteBridge> outByteBridge;
// Runnables that calls handlers
final Runnable fireChannelRegisteredTask = new Runnable() {
private final Runnable fireChannelRegisteredTask = new Runnable() {
@Override
public void run() {
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
public void run() {
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
public void run() {
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
public void run() {
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
public void run() {
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")
DefaultChannelHandlerContext(
@ -162,25 +217,25 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
throw new NullPointerException("handler");
}
int flags = 0;
// Determine the type of the specified handler.
int typeValue = 0;
EnumSet<ChannelHandlerType> type = EMPTY_TYPE.clone();
if (handler instanceof ChannelStateHandler) {
type.add(ChannelHandlerType.STATE);
typeValue |= DIR_INBOUND;
flags |= DIR_INBOUND;
if (handler instanceof ChannelInboundHandler) {
type.add(ChannelHandlerType.INBOUND);
}
}
if (handler instanceof ChannelOperationHandler) {
type.add(ChannelHandlerType.OPERATION);
typeValue |= DIR_OUTBOUND;
flags |= DIR_OUTBOUND;
if (handler instanceof ChannelOutboundHandler) {
type.add(ChannelHandlerType.OUTBOUND);
}
}
this.type = Collections.unmodifiableSet(type);
directions = typeValue;
this.prev = prev;
this.next = next;
@ -217,8 +272,8 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
throw new ChannelPipelineException("A user handler's newInboundBuffer() returned null");
}
if (buf instanceof ByteBuf) {
inByteBuf = (ByteBuf) buf;
if (buf instanceof UnsafeByteBuf) {
inByteBuf = (UnsafeByteBuf) buf;
inByteBridge = new AtomicReference<ByteBridge>();
inMsgBuf = null;
inMsgBridge = null;
@ -238,29 +293,15 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
}
if (type.contains(ChannelHandlerType.OUTBOUND)) {
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 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>();
if (prev == null) {
// Special case: if pref == null, it means this context for HeadHandler.
// HeadHandler is an outbound handler instantiated by the constructor of DefaultChannelPipeline.
// Because Channel is not really fully initialized at this point, we should not call
// 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;
} else {
throw new Error();
initOutboundBuffer();
}
} else {
outByteBuf = null;
@ -268,6 +309,43 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
outMsgBuf = 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() {
@ -309,6 +387,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
}
}
lazyInitOutboundBuffer();
if (outMsgBridge != null) {
MessageBridge bridge = outMsgBridge.get();
if (bridge != null) {
@ -332,6 +411,11 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
return pipeline;
}
@Override
public ByteBufAllocator alloc() {
return channel.config().getAllocator();
}
@Override
public EventExecutor executor() {
if (executor == null) {
@ -405,16 +489,22 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
@Override
public boolean hasOutboundByteBuffer() {
lazyInitOutboundBuffer();
return outByteBuf != null;
}
@Override
public boolean hasOutboundMessageBuffer() {
lazyInitOutboundBuffer();
return outMsgBuf != null;
}
@Override
public ByteBuf outboundByteBuffer() {
if (outMsgBuf == null) {
lazyInitOutboundBuffer();
}
if (outByteBuf == null) {
if (handler instanceof ChannelOutboundHandler) {
throw new NoSuchBufferException(String.format(
@ -434,6 +524,10 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
@Override
@SuppressWarnings("unchecked")
public <T> MessageBuf<T> outboundMessageBuffer() {
if (outMsgBuf == null) {
initOutboundBuffer();
}
if (outMsgBuf == null) {
if (handler instanceof ChannelOutboundHandler) {
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
* {@link Throwable}.
*/
<T> T executeOnEventLoop(Callable<T> c) throws Exception {
private <T> T executeOnEventLoop(Callable<T> c) throws Exception {
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
* {@link Throwable}.
*/
<T> T getFromFuture(Future<T> future) throws Exception {
private static <T> T getFromFuture(Future<T> future) throws Exception {
try {
return future.get();
} 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
* {@link Throwable}.
*/
void waitForFuture(Future future) {
static void waitForFuture(Future<?> future) {
try {
future.get();
} catch (ExecutionException ex) {
@ -585,7 +679,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
ByteBuf currentInboundByteBuf = inboundByteBuffer();
this.inByteBuf = newInboundByteBuf;
inByteBuf = (UnsafeByteBuf) newInboundByteBuf;
return currentInboundByteBuf;
}
@ -611,7 +705,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
MessageBuf<T> currentInboundMsgBuf = inboundMessageBuffer();
this.inMsgBuf = (MessageBuf<Object>) newInboundMsgBuf;
inMsgBuf = (MessageBuf<Object>) newInboundMsgBuf;
return currentInboundMsgBuf;
}
@ -636,7 +730,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
ByteBuf currentOutboundByteBuf = outboundByteBuffer();
this.outByteBuf = newOutboundByteBuf;
outByteBuf = (UnsafeByteBuf) newOutboundByteBuf;
return currentOutboundByteBuf;
}
@ -662,7 +756,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
MessageBuf<T> currentOutboundMsgBuf = outboundMessageBuffer();
this.outMsgBuf = (MessageBuf<Object>) newOutboundMsgBuf;
outMsgBuf = (MessageBuf<Object>) newOutboundMsgBuf;
return currentOutboundMsgBuf;
}
@ -696,12 +790,36 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
@Override
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
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
@ -728,7 +846,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
} else {
ByteBridge bridge = ctx.inByteBridge.get();
if (bridge == null) {
bridge = new ByteBridge();
bridge = new ByteBridge(ctx);
if (!ctx.inByteBridge.compareAndSet(null, bridge)) {
bridge = ctx.inByteBridge.get();
}
@ -779,12 +897,12 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
@Override
public ByteBuf nextOutboundByteBuffer() {
return DefaultChannelPipeline.nextOutboundByteBuffer(prev);
return pipeline.nextOutboundByteBuffer(prev);
}
@Override
public MessageBuf<Object> nextOutboundMessageBuffer() {
return DefaultChannelPipeline.nextOutboundMessageBuffer(prev);
return pipeline.nextOutboundMessageBuffer(prev);
}
@Override
@ -876,8 +994,8 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
} else {
logger.warn(
"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 " +
"handle the exception.", cause);
"pipeline. It usually means the last inbound handler in the pipeline did not " +
"handle the exception.", cause);
}
}
@ -1011,6 +1129,25 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
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
public ChannelFuture newFuture() {
return channel.newFuture();
@ -1028,9 +1165,10 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
static final class MessageBridge {
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()) {
return;
}
@ -1039,7 +1177,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
exchangeBuf.add(data);
}
void flush(MessageBuf<Object> out) {
private void flush(MessageBuf<Object> out) {
for (;;) {
Object[] data = exchangeBuf.poll();
if (data == null) {
@ -1052,26 +1190,48 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
}
static final class ByteBridge {
final ByteBuf byteBuf = Unpooled.buffer();
final Queue<ByteBuf> exchangeBuf = new ConcurrentLinkedQueue<ByteBuf>();
final UnsafeByteBuf 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()) {
return;
}
ByteBuf data = byteBuf.readBytes(byteBuf.readableBytes());
byteBuf.discardReadBytes();
exchangeBuf.add(data);
int dataLen = byteBuf.readableBytes();
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 (;;) {
ByteBuf data = exchangeBuf.poll();
UnsafeByteBuf data = exchangeBuf.poll();
if (data == null) {
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.MessageBuf;
import io.netty.buffer.Unpooled;
import io.netty.buffer.UnsafeByteBuf;
import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory;
@ -358,7 +359,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
private DefaultChannelHandlerContext remove(final DefaultChannelHandlerContext ctx) {
DefaultChannelHandlerContext context;
Future future;
Future<?> future;
synchronized (this) {
if (head == tail) {
@ -407,7 +408,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
// Run the following 'waiting' code outside of the above synchronized block
// in order to avoid deadlock
context.waitForFuture(future);
waitForFuture(future);
return context;
}
@ -497,9 +498,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
private ChannelHandler replace(
final DefaultChannelHandlerContext ctx, final String newName, ChannelHandler newHandler) {
Future future;
DefaultChannelHandlerContext context;
Future<?> future;
synchronized (this) {
if (ctx == head) {
throw new IllegalArgumentException();
@ -528,7 +527,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
}
}
});
context = oldTail;
}
} 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
// in order to avoid deadlock
context.waitForFuture(future);
waitForFuture(future);
return ctx.handler();
}
@ -866,33 +863,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
return nextOutboundByteBuffer(tail);
}
static boolean hasNextOutboundByteBuffer(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) {
ByteBuf nextOutboundByteBuffer(DefaultChannelHandlerContext ctx) {
final DefaultChannelHandlerContext initialCtx = ctx;
final Thread currentThread = Thread.currentThread();
for (;;) {
@ -910,13 +881,13 @@ public class DefaultChannelPipeline implements ChannelPipeline {
}
}
if (ctx.outByteBuf != null) {
if (ctx.hasOutboundByteBuffer()) {
if (ctx.executor().inEventLoop(currentThread)) {
return ctx.outByteBuf;
return ctx.outboundByteBuffer();
} else {
ByteBridge bridge = ctx.outByteBridge.get();
if (bridge == null) {
bridge = new ByteBridge();
bridge = new ByteBridge(ctx);
if (!ctx.outByteBridge.compareAndSet(null, bridge)) {
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 Thread currentThread = Thread.currentThread();
for (;;) {
@ -946,9 +917,9 @@ public class DefaultChannelPipeline implements ChannelPipeline {
}
}
if (ctx.outMsgBuf != null) {
if (ctx.hasOutboundMessageBuffer()) {
if (ctx.executor().inEventLoop(currentThread)) {
return ctx.outMsgBuf;
return ctx.outboundMessageBuffer();
} else {
MessageBridge bridge = ctx.outMsgBridge.get();
if (bridge == null) {
@ -972,6 +943,11 @@ public class DefaultChannelPipeline implements ChannelPipeline {
@Override
public void fireChannelUnregistered() {
head.fireChannelUnregistered();
// Free all buffers if channel is closed and unregistered.
if (!channel.isOpen()) {
head.callFreeInboundBuffer();
}
}
@Override
@ -1232,8 +1208,8 @@ public class DefaultChannelPipeline implements ChannelPipeline {
} catch (Throwable t) {
notifyHandlerException(t);
} finally {
if (ctx.outByteBuf != null) {
ByteBuf buf = ctx.outByteBuf;
if (ctx.hasOutboundByteBuffer()) {
ByteBuf buf = ctx.outboundByteBuffer();
if (!buf.readable()) {
buf.discardReadBytes();
}
@ -1289,10 +1265,10 @@ public class DefaultChannelPipeline implements ChannelPipeline {
if (executor.inEventLoop()) {
if (msgBuf) {
ctx.outMsgBuf.add(message);
ctx.outboundMessageBuffer().add(message);
} else {
ByteBuf buf = (ByteBuf) message;
ctx.outByteBuf.writeBytes(buf, buf.readerIndex(), buf.readableBytes());
ctx.outboundByteBuffer().writeBytes(buf, buf.readerIndex(), buf.readableBytes());
}
flush0(ctx, 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;
if (direction > 0) {
return nextContext(head.next, direction);
} else {
return nextContext(tail, direction);
if (direction == DIR_INBOUND) {
return nextContext(head.next, DIR_INBOUND);
} else { // DIR_OUTBOUND
return nextContext(tail, DIR_OUTBOUND);
}
}
@ -1342,15 +1318,15 @@ public class DefaultChannelPipeline implements ChannelPipeline {
}
DefaultChannelHandlerContext realCtx = ctx;
if (direction > 0) {
while ((realCtx.directions & direction) == 0) {
if (direction == DIR_INBOUND) {
while ((realCtx.flags & DIR_INBOUND) == 0) {
realCtx = realCtx.next;
if (realCtx == null) {
return null;
}
}
} else {
while ((realCtx.directions & direction) == 0) {
} else { // DIR_OUTBOUND
while ((realCtx.flags & DIR_OUTBOUND) == 0) {
realCtx = realCtx.prev;
if (realCtx == null) {
return null;
@ -1448,8 +1424,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
public ChannelBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
switch (channel.metadata().bufferType()) {
case BYTE:
// TODO: Use a direct buffer once buffer pooling is implemented.
return Unpooled.buffer();
return ctx.alloc().ioBuffer();
case MESSAGE:
return Unpooled.messageBuffer();
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
public void beforeAdd(ChannelHandlerContext ctx) throws Exception {
// NOOP

View File

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

View File

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