[#1907] LengthFieldPrepender should better extend MessageToMessageEncoder for less memory copies

This commit is contained in:
Norman Maurer 2013-10-11 06:38:18 +02:00 committed by Trustin Lee
parent 2d96b32155
commit 573b54a93d
2 changed files with 31 additions and 16 deletions

View File

@ -19,6 +19,8 @@ import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import java.util.List;
/**
* An encoder that prepends the length of the message. The length value is
@ -47,7 +49,7 @@ import io.netty.channel.ChannelHandlerContext;
* </pre>
*/
@Sharable
public class LengthFieldPrepender extends MessageToByteEncoder<ByteBuf> {
public class LengthFieldPrepender extends MessageToMessageEncoder<ByteBuf> {
private final int lengthFieldLength;
private final boolean lengthIncludesLengthFieldLength;
@ -128,7 +130,7 @@ public class LengthFieldPrepender extends MessageToByteEncoder<ByteBuf> {
}
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
int length = msg.readableBytes() + lengthAdjustment;
if (lengthIncludesLengthFieldLength) {
length += lengthFieldLength;
@ -145,32 +147,31 @@ public class LengthFieldPrepender extends MessageToByteEncoder<ByteBuf> {
throw new IllegalArgumentException(
"length does not fit into a byte: " + length);
}
out.writeByte((byte) length);
out.add(ctx.alloc().buffer(1).writeByte((byte) length));
break;
case 2:
if (length >= 65536) {
throw new IllegalArgumentException(
"length does not fit into a short integer: " + length);
}
out.writeShort((short) length);
out.add(ctx.alloc().buffer(2).writeShort((short) length));
break;
case 3:
if (length >= 16777216) {
throw new IllegalArgumentException(
"length does not fit into a medium integer: " + length);
}
out.writeMedium(length);
out.add(ctx.alloc().buffer(3).writeMedium(length));
break;
case 4:
out.writeInt(length);
out.add(ctx.alloc().buffer(4).writeInt(length));
break;
case 8:
out.writeLong(length);
out.add(ctx.alloc().buffer(8).writeLong(length));
break;
default:
throw new Error("should not reach here");
}
out.writeBytes(msg, msg.readerIndex(), msg.readableBytes());
out.add(msg.retain());
}
}

View File

@ -24,7 +24,6 @@ import org.junit.Before;
import org.junit.Test;
import static io.netty.buffer.Unpooled.*;
import static org.hamcrest.core.Is.*;
import static org.junit.Assert.*;
public class LengthFieldPrependerTest {
@ -40,8 +39,13 @@ public class LengthFieldPrependerTest {
public void testPrependLength() throws Exception {
final EmbeddedChannel ch = new EmbeddedChannel(new LengthFieldPrepender(4));
ch.writeOutbound(msg);
final ByteBuf buf = (ByteBuf) ch.readOutbound();
assertThat(buf, is(wrappedBuffer(new byte[]{0, 0, 0, 1, 'A'})));
ByteBuf buf = (ByteBuf) ch.readOutbound();
assertEquals(4, buf.readableBytes());
assertEquals(msg.readableBytes(), buf.readInt());
buf.release();
buf = (ByteBuf) ch.readOutbound();
assertSame(buf, msg);
buf.release();
}
@ -49,8 +53,13 @@ public class LengthFieldPrependerTest {
public void testPrependLengthIncludesLengthFieldLength() throws Exception {
final EmbeddedChannel ch = new EmbeddedChannel(new LengthFieldPrepender(4, true));
ch.writeOutbound(msg);
final ByteBuf buf = (ByteBuf) ch.readOutbound();
assertThat(buf, is(wrappedBuffer(new byte[]{0, 0, 0, 5, 'A'})));
ByteBuf buf = (ByteBuf) ch.readOutbound();
assertEquals(4, buf.readableBytes());
assertEquals(5, buf.readInt());
buf.release();
buf = (ByteBuf) ch.readOutbound();
assertSame(buf, msg);
buf.release();
}
@ -58,8 +67,13 @@ public class LengthFieldPrependerTest {
public void testPrependAdjustedLength() throws Exception {
final EmbeddedChannel ch = new EmbeddedChannel(new LengthFieldPrepender(4, -1));
ch.writeOutbound(msg);
final ByteBuf buf = (ByteBuf) ch.readOutbound();
assertThat(buf, is(wrappedBuffer(new byte[]{0, 0, 0, 0, 'A'})));
ByteBuf buf = (ByteBuf) ch.readOutbound();
assertEquals(4, buf.readableBytes());
assertEquals(msg.readableBytes() - 1, buf.readInt());
buf.release();
buf = (ByteBuf) ch.readOutbound();
assertSame(buf, msg);
buf.release();
}