[#1907] LengthFieldPrepender should better extend MessageToMessageEncoder for less memory copies
This commit is contained in:
parent
2d96b32155
commit
573b54a93d
@ -19,6 +19,8 @@ import io.netty.buffer.ByteBuf;
|
|||||||
import io.netty.channel.ChannelHandler.Sharable;
|
import io.netty.channel.ChannelHandler.Sharable;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An encoder that prepends the length of the message. The length value is
|
* An encoder that prepends the length of the message. The length value is
|
||||||
@ -47,7 +49,7 @@ import io.netty.channel.ChannelHandlerContext;
|
|||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
@Sharable
|
@Sharable
|
||||||
public class LengthFieldPrepender extends MessageToByteEncoder<ByteBuf> {
|
public class LengthFieldPrepender extends MessageToMessageEncoder<ByteBuf> {
|
||||||
|
|
||||||
private final int lengthFieldLength;
|
private final int lengthFieldLength;
|
||||||
private final boolean lengthIncludesLengthFieldLength;
|
private final boolean lengthIncludesLengthFieldLength;
|
||||||
@ -128,7 +130,7 @@ public class LengthFieldPrepender extends MessageToByteEncoder<ByteBuf> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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;
|
int length = msg.readableBytes() + lengthAdjustment;
|
||||||
if (lengthIncludesLengthFieldLength) {
|
if (lengthIncludesLengthFieldLength) {
|
||||||
length += lengthFieldLength;
|
length += lengthFieldLength;
|
||||||
@ -145,32 +147,31 @@ public class LengthFieldPrepender extends MessageToByteEncoder<ByteBuf> {
|
|||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"length does not fit into a byte: " + length);
|
"length does not fit into a byte: " + length);
|
||||||
}
|
}
|
||||||
out.writeByte((byte) length);
|
out.add(ctx.alloc().buffer(1).writeByte((byte) length));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (length >= 65536) {
|
if (length >= 65536) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"length does not fit into a short integer: " + length);
|
"length does not fit into a short integer: " + length);
|
||||||
}
|
}
|
||||||
out.writeShort((short) length);
|
out.add(ctx.alloc().buffer(2).writeShort((short) length));
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (length >= 16777216) {
|
if (length >= 16777216) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"length does not fit into a medium integer: " + length);
|
"length does not fit into a medium integer: " + length);
|
||||||
}
|
}
|
||||||
out.writeMedium(length);
|
out.add(ctx.alloc().buffer(3).writeMedium(length));
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
out.writeInt(length);
|
out.add(ctx.alloc().buffer(4).writeInt(length));
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
out.writeLong(length);
|
out.add(ctx.alloc().buffer(8).writeLong(length));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error("should not reach here");
|
throw new Error("should not reach here");
|
||||||
}
|
}
|
||||||
|
out.add(msg.retain());
|
||||||
out.writeBytes(msg, msg.readerIndex(), msg.readableBytes());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static io.netty.buffer.Unpooled.*;
|
import static io.netty.buffer.Unpooled.*;
|
||||||
import static org.hamcrest.core.Is.*;
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class LengthFieldPrependerTest {
|
public class LengthFieldPrependerTest {
|
||||||
@ -40,8 +39,13 @@ public class LengthFieldPrependerTest {
|
|||||||
public void testPrependLength() throws Exception {
|
public void testPrependLength() throws Exception {
|
||||||
final EmbeddedChannel ch = new EmbeddedChannel(new LengthFieldPrepender(4));
|
final EmbeddedChannel ch = new EmbeddedChannel(new LengthFieldPrepender(4));
|
||||||
ch.writeOutbound(msg);
|
ch.writeOutbound(msg);
|
||||||
final ByteBuf buf = (ByteBuf) ch.readOutbound();
|
ByteBuf buf = (ByteBuf) ch.readOutbound();
|
||||||
assertThat(buf, is(wrappedBuffer(new byte[]{0, 0, 0, 1, 'A'})));
|
assertEquals(4, buf.readableBytes());
|
||||||
|
assertEquals(msg.readableBytes(), buf.readInt());
|
||||||
|
buf.release();
|
||||||
|
|
||||||
|
buf = (ByteBuf) ch.readOutbound();
|
||||||
|
assertSame(buf, msg);
|
||||||
buf.release();
|
buf.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,8 +53,13 @@ public class LengthFieldPrependerTest {
|
|||||||
public void testPrependLengthIncludesLengthFieldLength() throws Exception {
|
public void testPrependLengthIncludesLengthFieldLength() throws Exception {
|
||||||
final EmbeddedChannel ch = new EmbeddedChannel(new LengthFieldPrepender(4, true));
|
final EmbeddedChannel ch = new EmbeddedChannel(new LengthFieldPrepender(4, true));
|
||||||
ch.writeOutbound(msg);
|
ch.writeOutbound(msg);
|
||||||
final ByteBuf buf = (ByteBuf) ch.readOutbound();
|
ByteBuf buf = (ByteBuf) ch.readOutbound();
|
||||||
assertThat(buf, is(wrappedBuffer(new byte[]{0, 0, 0, 5, 'A'})));
|
assertEquals(4, buf.readableBytes());
|
||||||
|
assertEquals(5, buf.readInt());
|
||||||
|
buf.release();
|
||||||
|
|
||||||
|
buf = (ByteBuf) ch.readOutbound();
|
||||||
|
assertSame(buf, msg);
|
||||||
buf.release();
|
buf.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,8 +67,13 @@ public class LengthFieldPrependerTest {
|
|||||||
public void testPrependAdjustedLength() throws Exception {
|
public void testPrependAdjustedLength() throws Exception {
|
||||||
final EmbeddedChannel ch = new EmbeddedChannel(new LengthFieldPrepender(4, -1));
|
final EmbeddedChannel ch = new EmbeddedChannel(new LengthFieldPrepender(4, -1));
|
||||||
ch.writeOutbound(msg);
|
ch.writeOutbound(msg);
|
||||||
final ByteBuf buf = (ByteBuf) ch.readOutbound();
|
ByteBuf buf = (ByteBuf) ch.readOutbound();
|
||||||
assertThat(buf, is(wrappedBuffer(new byte[]{0, 0, 0, 0, 'A'})));
|
assertEquals(4, buf.readableBytes());
|
||||||
|
assertEquals(msg.readableBytes() - 1, buf.readInt());
|
||||||
|
buf.release();
|
||||||
|
|
||||||
|
buf = (ByteBuf) ch.readOutbound();
|
||||||
|
assertSame(buf, msg);
|
||||||
buf.release();
|
buf.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user