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;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
@ -337,7 +338,7 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder {
private final CoalescingBufferQueue queue;
private int dataSize;
public FlowControlledData(Http2Stream stream, ByteBuf buf, int padding, boolean endOfStream,
FlowControlledData(Http2Stream stream, ByteBuf buf, int padding, boolean endOfStream,
ChannelPromise promise) {
super(stream, padding, endOfStream, promise);
queue = new CoalescingBufferQueue(promise.channel());
@ -361,9 +362,19 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder {
@Override
public void write(ChannelHandlerContext ctx, int allowedBytes) {
int queuedData = queue.readableBytes();
if (!endOfStream && (queuedData == 0 || allowedBytes == 0)) {
// Nothing to write and we don't have to force a write because of EOS.
return;
if (!endOfStream) {
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;
}
if (allowedBytes == 0) {
return;
}
}
// Determine how much data to write.
@ -408,7 +419,7 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder {
private final short weight;
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) {
super(stream, padding, endOfStream, promise);
this.headers = headers;
@ -457,7 +468,7 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder {
protected boolean endOfStream;
protected int padding;
public FlowControlledBase(final Http2Stream stream, int padding, boolean endOfStream,
protected FlowControlledBase(final Http2Stream stream, int padding, boolean endOfStream,
final ChannelPromise promise) {
if (padding < 0) {
throw new IllegalArgumentException("padding must be >= 0");