Fulfill the write promise of empty HTTP/2 DATA frames sooner

Motivation:

DefaultHttp2ConnectionEncoder.FlowControlledData.write() does not
complete the write promise of empty HTTP/2 DATA frames until either a
non-DATA frame, a non-empty DATA frame or a DATA frame with endOfStream
set. This makes the write promise of the empty DATA frame is notified
much later than it could be.

Modifications:

- Notify the write promise of the empty DATA frames immediately is the
  queue contains empty DATA frames only

Result:

The write promise of an empty DATA frame is notified sooner.
This commit is contained in:
Trustin Lee 2016-08-24 19:25:59 +09:00
parent acb40a87c3
commit 5b46cf25c1

View File

@ -15,6 +15,7 @@
package io.netty.handler.codec.http2; package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
@ -337,7 +338,7 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder {
private final CoalescingBufferQueue queue; private final CoalescingBufferQueue queue;
private int dataSize; private int dataSize;
public FlowControlledData(Http2Stream stream, ByteBuf buf, int padding, boolean endOfStream, FlowControlledData(Http2Stream stream, ByteBuf buf, int padding, boolean endOfStream,
ChannelPromise promise) { ChannelPromise promise) {
super(stream, padding, endOfStream, promise); super(stream, padding, endOfStream, promise);
queue = new CoalescingBufferQueue(promise.channel()); queue = new CoalescingBufferQueue(promise.channel());
@ -361,11 +362,21 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder {
@Override @Override
public void write(ChannelHandlerContext ctx, int allowedBytes) { public void write(ChannelHandlerContext ctx, int allowedBytes) {
int queuedData = queue.readableBytes(); int queuedData = queue.readableBytes();
if (!endOfStream && (queuedData == 0 || allowedBytes == 0)) { if (!endOfStream) {
// Nothing to write and we don't have to force a write because of EOS. if (queuedData == 0) {
// There's no need to write any data frames because there are only empty data frames in the queue
// and it is not end of stream yet. Just complete their promises by writing an empty buffer.
ChannelPromise writePromise = ctx.newPromise().addListener(this);
queue.remove(0, writePromise).release();
ctx.write(Unpooled.EMPTY_BUFFER, writePromise);
return; return;
} }
if (allowedBytes == 0) {
return;
}
}
// Determine how much data to write. // Determine how much data to write.
int writeableData = min(queuedData, allowedBytes); int writeableData = min(queuedData, allowedBytes);
ChannelPromise writePromise = ctx.newPromise().addListener(this); ChannelPromise writePromise = ctx.newPromise().addListener(this);
@ -408,7 +419,7 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder {
private final short weight; private final short weight;
private final boolean exclusive; private final boolean exclusive;
public FlowControlledHeaders(Http2Stream stream, Http2Headers headers, int streamDependency, short weight, FlowControlledHeaders(Http2Stream stream, Http2Headers headers, int streamDependency, short weight,
boolean exclusive, int padding, boolean endOfStream, ChannelPromise promise) { boolean exclusive, int padding, boolean endOfStream, ChannelPromise promise) {
super(stream, padding, endOfStream, promise); super(stream, padding, endOfStream, promise);
this.headers = headers; this.headers = headers;
@ -457,7 +468,7 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder {
protected boolean endOfStream; protected boolean endOfStream;
protected int padding; protected int padding;
public FlowControlledBase(final Http2Stream stream, int padding, boolean endOfStream, protected FlowControlledBase(final Http2Stream stream, int padding, boolean endOfStream,
final ChannelPromise promise) { final ChannelPromise promise) {
if (padding < 0) { if (padding < 0) {
throw new IllegalArgumentException("padding must be >= 0"); throw new IllegalArgumentException("padding must be >= 0");