diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2RemoteFlowController.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2RemoteFlowController.java index 12feeceb80..04e4b19241 100644 --- a/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2RemoteFlowController.java +++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2RemoteFlowController.java @@ -235,8 +235,10 @@ public class DefaultHttp2RemoteFlowController implements Http2RemoteFlowControll } /** - * This will allocate bytes by stream weight and priority for the entire tree rooted at {@code parent}, but does - * not write any bytes. + * This will allocate bytes by stream weight and priority for the entire tree rooted at {@code parent}, but does not + * write any bytes. The connection window is generally distributed amongst siblings according to their weight, + * however we need to ensure that the entire connection window is used (assuming streams have >= connection window + * bytes to send) and we may need some sort of rounding to accomplish this. * * @param parent The parent of the tree. * @param connectionWindow The connection window this is available for use at this point in the tree. @@ -282,7 +284,10 @@ public class DefaultHttp2RemoteFlowController implements Http2RemoteFlowControll int weight = child.weight(); double weightRatio = weight / (double) totalWeight; - int bytesForTree = Math.min(nextConnectionWindow, (int) Math.ceil(connectionWindow * weightRatio)); + // In order to make progress toward the connection window due to possible rounding errors, we make sure + // that each stream (with data to send) is given at least 1 byte toward the connection window. + int connectionWindowChunk = Math.max(1, (int) (connectionWindow * weightRatio)); + int bytesForTree = Math.min(nextConnectionWindow, connectionWindowChunk); int bytesForChild = Math.min(state.streamableBytes(), bytesForTree); if (bytesForChild > 0) {