Optimize HttpContentEncoder to do less memory copies as those are not needed

This commit is contained in:
Norman Maurer 2013-07-05 06:38:25 +02:00
parent d900f8c21d
commit 9f0f653588

View File

@ -17,7 +17,6 @@ package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufHolder; import io.netty.buffer.ByteBufHolder;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageList; import io.netty.channel.MessageList;
import io.netty.channel.embedded.EmbeddedChannel; import io.netty.channel.embedded.EmbeddedChannel;
@ -163,9 +162,8 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
} }
case AWAIT_CONTENT: { case AWAIT_CONTENT: {
ensureContent(msg); ensureContent(msg);
HttpContent[] encoded = encodeContent((HttpContent) msg); encodeContent((HttpContent) msg, out);
out.add(encoded); if (msg instanceof LastHttpContent) {
if (encoded[encoded.length - 1] instanceof LastHttpContent) {
state = State.AWAIT_HEADERS; state = State.AWAIT_HEADERS;
} }
break; break;
@ -198,31 +196,18 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
} }
} }
private HttpContent[] encodeContent(HttpContent c) { private void encodeContent(HttpContent c, MessageList<Object> out) {
ByteBuf newContent = Unpooled.buffer();
ByteBuf content = c.content(); ByteBuf content = c.content();
encode(content, newContent); encode(content, out);
if (c instanceof LastHttpContent) { if (c instanceof LastHttpContent) {
ByteBuf lastProduct = Unpooled.buffer(); finishEncode(out);
finishEncode(lastProduct);
// Generate an additional chunk if the decoder produced // Generate an additional chunk if the decoder produced
// the last product on closure, // the last product on closure,
if (lastProduct.isReadable()) { out.add(LastHttpContent.EMPTY_LAST_CONTENT);
if (newContent.isReadable()) {
return new HttpContent[] {
new DefaultHttpContent(newContent), new DefaultLastHttpContent(lastProduct)};
} else {
return new HttpContent[] { new DefaultLastHttpContent(lastProduct) };
}
} else {
return new HttpContent[] { new DefaultLastHttpContent(newContent) };
}
} }
return new HttpContent[] { new DefaultHttpContent(newContent) };
} }
/** /**
@ -271,30 +256,26 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
} }
} }
private void encode(ByteBuf in, ByteBuf out) { private void encode(ByteBuf in, MessageList<Object> out) {
// call retain here as it will call release after its written to the channel // call retain here as it will call release after its written to the channel
encoder.writeOutbound(in.retain()); encoder.writeOutbound(in.retain());
fetchEncoderOutput(out); fetchEncoderOutput(out);
} }
private void finishEncode(ByteBuf out) { private void finishEncode(MessageList<Object> out) {
if (encoder.finish()) { if (encoder.finish()) {
fetchEncoderOutput(out); fetchEncoderOutput(out);
} }
encoder = null; encoder = null;
} }
private void fetchEncoderOutput(ByteBuf out) { private void fetchEncoderOutput(MessageList<Object> out) {
for (;;) { for (;;) {
ByteBuf buf = (ByteBuf) encoder.readOutbound(); ByteBuf buf = (ByteBuf) encoder.readOutbound();
if (buf == null) { if (buf == null) {
break; break;
} }
out.writeBytes(buf); out.add(new DefaultHttpContent(buf));
// Need to release the buffer after write it
// See https://github.com/netty/netty/issues/1524
buf.release();
} }
} }