From 22f16e52bf0fe9b445573a750eb28dfcbb929518 Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Mon, 23 Jun 2014 07:01:05 +0200 Subject: [PATCH] MessageToByteEncoder always starts with ByteBuf that use initalCapacity == 0 Motivation: MessageToByteEncoder always starts with ByteBuf that use initalCapacity == 0 when preferDirect is used. This is really wasteful in terms of performance as every first write into the buffer will cause an expand of the buffer itself. Modifications: - Change ByteBufAllocator.ioBuffer() use the same default initialCapacity as heapBuffer() and directBuffer() - Add new allocateBuffer method to MessageToByteEncoder that allow the user to do some smarter allocation based on the message that will be encoded. Result: Less expanding of buffer and more flexibilty when allocate the buffer for encoding. --- .../buffer/AbstractByteBufAllocator.java | 4 ++-- .../io/netty/buffer/ByteBufAllocator.java | 2 +- .../handler/codec/MessageToByteEncoder.java | 19 ++++++++++++++----- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/buffer/src/main/java/io/netty/buffer/AbstractByteBufAllocator.java b/buffer/src/main/java/io/netty/buffer/AbstractByteBufAllocator.java index 4d39bc29ee..34e5d2c6dd 100644 --- a/buffer/src/main/java/io/netty/buffer/AbstractByteBufAllocator.java +++ b/buffer/src/main/java/io/netty/buffer/AbstractByteBufAllocator.java @@ -96,9 +96,9 @@ public abstract class AbstractByteBufAllocator implements ByteBufAllocator { @Override public ByteBuf ioBuffer() { if (PlatformDependent.hasUnsafe()) { - return directBuffer(0); + return directBuffer(DEFAULT_INITIAL_CAPACITY); } - return heapBuffer(0); + return heapBuffer(DEFAULT_INITIAL_CAPACITY); } @Override diff --git a/buffer/src/main/java/io/netty/buffer/ByteBufAllocator.java b/buffer/src/main/java/io/netty/buffer/ByteBufAllocator.java index e1778020b2..ca7df32ce0 100644 --- a/buffer/src/main/java/io/netty/buffer/ByteBufAllocator.java +++ b/buffer/src/main/java/io/netty/buffer/ByteBufAllocator.java @@ -43,7 +43,7 @@ public interface ByteBufAllocator { ByteBuf buffer(int initialCapacity, int maxCapacity); /** - * Allocate a {@link ByteBuf} whose initial capacity is 0, preferably a direct buffer which is suitable for I/O. + * Allocate a {@link ByteBuf}, preferably a direct buffer which is suitable for I/O. */ ByteBuf ioBuffer(); diff --git a/codec/src/main/java/io/netty/handler/codec/MessageToByteEncoder.java b/codec/src/main/java/io/netty/handler/codec/MessageToByteEncoder.java index f6c506b237..0aab4247c2 100644 --- a/codec/src/main/java/io/netty/handler/codec/MessageToByteEncoder.java +++ b/codec/src/main/java/io/netty/handler/codec/MessageToByteEncoder.java @@ -102,11 +102,7 @@ public abstract class MessageToByteEncoder extends ChannelOutboundHandlerAdap if (acceptOutboundMessage(msg)) { @SuppressWarnings("unchecked") I cast = (I) msg; - if (preferDirect) { - buf = ctx.alloc().ioBuffer(); - } else { - buf = ctx.alloc().heapBuffer(); - } + buf = allocateBuffer(ctx, cast, preferDirect); try { encode(ctx, cast, buf); } finally { @@ -134,6 +130,19 @@ public abstract class MessageToByteEncoder extends ChannelOutboundHandlerAdap } } + /** + * Allocate a {@link ByteBuf} which will be used as argument of {@link #encode(ChannelHandlerContext, I, ByteBuf)}. + * Sub-classes may override this method to returna {@link ByteBuf} with a perfect matching {@code initialCapacity}. + */ + protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, @SuppressWarnings("unused") I msg, + boolean preferDirect) throws Exception { + if (preferDirect) { + return ctx.alloc().ioBuffer(); + } else { + return ctx.alloc().heapBuffer(); + } + } + /** * Encode a message into a {@link ByteBuf}. This method will be called for each written message that can be handled * by this encoder.