{"action":"created","comment":{"url":"https://api.github.com/repos/netty/netty/pulls/comments/33883496","id":33883496,"diff_hunk":"@@ -307,38 +338,87 @@ private Http2Stream requireStream(int streamId) {\n         return stream;\n     }\n \n-    /**\n-     * Wrap a DATA frame so it can be written subject to flow-control. Note that this implementation assumes it\n-     * only writes padding once for the entire payload as opposed to writing it once per-frame. This makes the\n-     * {@link #size} calculation deterministic thereby greatly simplifying the implementation.\n-     * <p>\n-     * If frame-splitting is required to fit within max-frame-size and flow-control constraints we ensure that\n-     * the passed promise is not completed until last frame write.\n-     * </p>\n-     */\n-    private final class FlowControlledData extends FlowControlledBase {\n-        private ByteBuf data;\n-        private int size;\n-\n-        private FlowControlledData(ChannelHandlerContext ctx, Http2Stream stream, ByteBuf buf, int padding,\n-                                    boolean endOfStream, ChannelPromise promise) {\n-            super(ctx, stream, padding, endOfStream, promise);\n-            this.data = buf;\n-            size = data.readableBytes() + padding;\n+    private final class FlowControlledFileRegion extends FlowControlledData<FileRegion> {\n+        \n+        private FlowControlledFileRegion(ChannelHandlerContext ctx, Http2Stream stream,\n+                FileRegion data, int padding, boolean endOfStream, ChannelPromise promise) {\n+            super(ctx, stream, data, (int) data.count(), padding, endOfStream, promise);\n         }\n \n         @Override\n-        public int size() {\n-            return size;\n+        public void write(int allowedBytes) {\n+            int bytesWritten = 0;\n+            if (data == null || (allowedBytes == 0 && size != 0)) {\n+                // No point writing an empty DATA frame, wait for a bigger allowance.\n+                return;\n+            }\n+            try {\n+                int maxFrameSize = frameWriter().configuration().frameSizePolicy().maxFrameSize();\n+                do {\n+                    int allowedFrameSize = Math.min(maxFrameSize, allowedBytes - bytesWritten);\n+                    if (data == null) {\n+                        // write padding only\n+                        int writeablePadding = Math.min(allowedFrameSize, padding);\n+                        padding -= writeablePadding;\n+                        bytesWritten += writeablePadding;\n+                        ChannelPromise writePromise;\n+                        if (size == bytesWritten && !promise.isVoid()) {\n+                            // Can use the original promise if it's the last write\n+                            writePromise = promise;\n+                        } else {\n+                            // Create a new promise and listen to it for failure\n+                            writePromise = ctx.newPromise();\n+                            writePromise.addListener(this);\n+                        }\n+                        frameWriter()\n+                                .writeData(ctx, stream.id(), Unpooled.EMPTY_BUFFER,\n+                                        writeablePadding, size == bytesWritten && endOfStream,\n+                                        writePromise);\n+                        return;\n+                    }\n+                    FileRegion toWrite;\n+                    int writeableData = (int) data.count();\n+                    if (writeableData > allowedFrameSize) {\n+                        FileRegion[] regions = data.split(allowedFrameSize);\n+                        toWrite = regions[0];\n+                        data = regions[1];\n+                    } else {\n+                        toWrite = data;\n+                        data = null;\n+                    }\n+                    int writeablePadding = Math.min(allowedFrameSize - writeableData, padding);\n+                    padding -= writeablePadding;\n+                    bytesWritten += writeableData + writeablePadding;\n+                    ChannelPromise writePromise;\n+                    if (size == bytesWritten && !promise.isVoid()) {\n+                        // Can use the original promise if it's the last write\n+                        writePromise = promise;\n+                    } else {\n+                        // Create a new promise and listen to it for failure\n+                        writePromise = ctx.newPromise();\n+                        writePromise.addListener(this);\n+                    }\n+                    frameWriter().writeData(ctx, stream.id(), toWrite, writeablePadding,\n+                            size == bytesWritten && endOfStream, writePromise);\n+                } while (size != bytesWritten && allowedBytes > bytesWritten);\n+            } finally {\n+                size -= bytesWritten;\n+            }\n         }\n \n         @Override\n-        public void error(Throwable cause) {\n-            ReferenceCountUtil.safeRelease(data);\n-            lifecycleManager.onException(ctx, cause);\n-            data = null;\n-            size = 0;\n-            promise.tryFailure(cause);\n+        public boolean merge(FlowControlled next) {\n+            return false;","path":"codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2ConnectionEncoder.java","position":149,"original_position":149,"commit_id":"757ec877590d3f70cf5f17c78d391213fbb1601c","original_commit_id":"757ec877590d3f70cf5f17c78d391213fbb1601c","user":{"login":"Apache9","id":4958168,"avatar_url":"https://avatars.githubusercontent.com/u/4958168?v=3","gravatar_id":"","url":"https://api.github.com/users/Apache9","html_url":"https://github.com/Apache9","followers_url":"https://api.github.com/users/Apache9/followers","following_url":"https://api.github.com/users/Apache9/following{/other_user}","gists_url":"https://api.github.com/users/Apache9/gists{/gist_id}","starred_url":"https://api.github.com/users/Apache9/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Apache9/subscriptions","organizations_url":"https://api.github.com/users/Apache9/orgs","repos_url":"https://api.github.com/users/Apache9/repos","events_url":"https://api.github.com/users/Apache9/events{/privacy}","received_events_url":"https://api.github.com/users/Apache9/received_events","type":"User","site_admin":false},"body":"Yes, can do it later.","created_at":"2015-07-04T00:39:17Z","updated_at":"2015-07-04T00:39:17Z","html_url":"https://github.com/netty/netty/pull/3928#discussion_r33883496","pull_request_url":"https://api.github.com/repos/netty/netty/pulls/3928","_links":{"self":{"href":"https://api.github.com/repos/netty/netty/pulls/comments/33883496"},"html":{"href":"https://github.com/netty/netty/pull/3928#discussion_r33883496"},"pull_request":{"href":"https://api.github.com/repos/netty/netty/pulls/3928"}}},"pull_request":{"url":"https://api.github.com/repos/netty/netty/pulls/3928","id":39145010,"html_url":"https://github.com/netty/netty/pull/3928","diff_url":"https://github.com/netty/netty/pull/3928.diff","patch_url":"https://github.com/netty/netty/pull/3928.patch","issue_url":"https://api.github.com/repos/netty/netty/issues/3928","number":3928,"state":"open","locked":false,"title":"FileRegion support in HTTP/2","user":{"login":"Apache9","id":4958168,"avatar_url":"https://avatars.githubusercontent.com/u/4958168?v=3","gravatar_id":"","url":"https://api.github.com/users/Apache9","html_url":"https://github.com/Apache9","followers_url":"https://api.github.com/users/Apache9/followers","following_url":"https://api.github.com/users/Apache9/following{/other_user}","gists_url":"https://api.github.com/users/Apache9/gists{/gist_id}","starred_url":"https://api.github.com/users/Apache9/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Apache9/subscriptions","organizations_url":"https://api.github.com/users/Apache9/orgs","repos_url":"https://api.github.com/users/Apache9/repos","events_url":"https://api.github.com/users/Apache9/events{/privacy}","received_events_url":"https://api.github.com/users/Apache9/received_events","type":"User","site_admin":false},"body":"POC of #3927.","created_at":"2015-07-03T04:18:58Z","updated_at":"2015-07-04T00:39:17Z","closed_at":null,"merged_at":null,"merge_commit_sha":"2cf6eac8df09d6fc22af3f2f96c0964944b70d9e","assignee":{"login":"Scottmitch","id":7562868,"avatar_url":"https://avatars.githubusercontent.com/u/7562868?v=3","gravatar_id":"","url":"https://api.github.com/users/Scottmitch","html_url":"https://github.com/Scottmitch","followers_url":"https://api.github.com/users/Scottmitch/followers","following_url":"https://api.github.com/users/Scottmitch/following{/other_user}","gists_url":"https://api.github.com/users/Scottmitch/gists{/gist_id}","starred_url":"https://api.github.com/users/Scottmitch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Scottmitch/subscriptions","organizations_url":"https://api.github.com/users/Scottmitch/orgs","repos_url":"https://api.github.com/users/Scottmitch/repos","events_url":"https://api.github.com/users/Scottmitch/events{/privacy}","received_events_url":"https://api.github.com/users/Scottmitch/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/netty/netty/milestones/117","html_url":"https://github.com/netty/netty/milestones/4.1.0.Beta6","labels_url":"https://api.github.com/repos/netty/netty/milestones/117/labels","id":1100817,"number":117,"title":"4.1.0.Beta6","description":"","creator":{"login":"normanmaurer","id":439362,"avatar_url":"https://avatars.githubusercontent.com/u/439362?v=3","gravatar_id":"","url":"https://api.github.com/users/normanmaurer","html_url":"https://github.com/normanmaurer","followers_url":"https://api.github.com/users/normanmaurer/followers","following_url":"https://api.github.com/users/normanmaurer/following{/other_user}","gists_url":"https://api.github.com/users/normanmaurer/gists{/gist_id}","starred_url":"https://api.github.com/users/normanmaurer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/normanmaurer/subscriptions","organizations_url":"https://api.github.com/users/normanmaurer/orgs","repos_url":"https://api.github.com/users/normanmaurer/repos","events_url":"https://api.github.com/users/normanmaurer/events{/privacy}","received_events_url":"https://api.github.com/users/normanmaurer/received_events","type":"User","site_admin":false},"open_issues":67,"closed_issues":36,"state":"open","created_at":"2015-05-07T19:29:09Z","updated_at":"2015-07-03T17:24:31Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/netty/netty/pulls/3928/commits","review_comments_url":"https://api.github.com/repos/netty/netty/pulls/3928/comments","review_comment_url":"https://api.github.com/repos/netty/netty/pulls/comments{/number}","comments_url":"https://api.github.com/repos/netty/netty/issues/3928/comments","statuses_url":"https://api.github.com/repos/netty/netty/statuses/757ec877590d3f70cf5f17c78d391213fbb1601c","head":{"label":"Apache9:NETTY-3927","ref":"NETTY-3927","sha":"757ec877590d3f70cf5f17c78d391213fbb1601c","user":{"login":"Apache9","id":4958168,"avatar_url":"https://avatars.githubusercontent.com/u/4958168?v=3","gravatar_id":"","url":"https://api.github.com/users/Apache9","html_url":"https://github.com/Apache9","followers_url":"https://api.github.com/users/Apache9/followers","following_url":"https://api.github.com/users/Apache9/following{/other_user}","gists_url":"https://api.github.com/users/Apache9/gists{/gist_id}","starred_url":"https://api.github.com/users/Apache9/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Apache9/subscriptions","organizations_url":"https://api.github.com/users/Apache9/orgs","repos_url":"https://api.github.com/users/Apache9/repos","events_url":"https://api.github.com/users/Apache9/events{/privacy}","received_events_url":"https://api.github.com/users/Apache9/received_events","type":"User","site_admin":false},"repo":{"id":37699053,"name":"netty","full_name":"Apache9/netty","owner":{"login":"Apache9","id":4958168,"avatar_url":"https://avatars.githubusercontent.com/u/4958168?v=3","gravatar_id":"","url":"https://api.github.com/users/Apache9","html_url":"https://github.com/Apache9","followers_url":"https://api.github.com/users/Apache9/followers","following_url":"https://api.github.com/users/Apache9/following{/other_user}","gists_url":"https://api.github.com/users/Apache9/gists{/gist_id}","starred_url":"https://api.github.com/users/Apache9/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Apache9/subscriptions","organizations_url":"https://api.github.com/users/Apache9/orgs","repos_url":"https://api.github.com/users/Apache9/repos","events_url":"https://api.github.com/users/Apache9/events{/privacy}","received_events_url":"https://api.github.com/users/Apache9/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Apache9/netty","description":"Netty project - an event-driven asynchronous network application framework","fork":true,"url":"https://api.github.com/repos/Apache9/netty","forks_url":"https://api.github.com/repos/Apache9/netty/forks","keys_url":"https://api.github.com/repos/Apache9/netty/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Apache9/netty/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Apache9/netty/teams","hooks_url":"https://api.github.com/repos/Apache9/netty/hooks","issue_events_url":"https://api.github.com/repos/Apache9/netty/issues/events{/number}","events_url":"https://api.github.com/repos/Apache9/netty/events","assignees_url":"https://api.github.com/repos/Apache9/netty/assignees{/user}","branches_url":"https://api.github.com/repos/Apache9/netty/branches{/branch}","tags_url":"https://api.github.com/repos/Apache9/netty/tags","blobs_url":"https://api.github.com/repos/Apache9/netty/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Apache9/netty/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Apache9/netty/git/refs{/sha}","trees_url":"https://api.github.com/repos/Apache9/netty/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Apache9/netty/statuses/{sha}","languages_url":"https://api.github.com/repos/Apache9/netty/languages","stargazers_url":"https://api.github.com/repos/Apache9/netty/stargazers","contributors_url":"https://api.github.com/repos/Apache9/netty/contributors","subscribers_url":"https://api.github.com/repos/Apache9/netty/subscribers","subscription_url":"https://api.github.com/repos/Apache9/netty/subscription","commits_url":"https://api.github.com/repos/Apache9/netty/commits{/sha}","git_commits_url":"https://api.github.com/repos/Apache9/netty/git/commits{/sha}","comments_url":"https://api.github.com/repos/Apache9/netty/comments{/number}","issue_comment_url":"https://api.github.com/repos/Apache9/netty/issues/comments{/number}","contents_url":"https://api.github.com/repos/Apache9/netty/contents/{+path}","compare_url":"https://api.github.com/repos/Apache9/netty/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Apache9/netty/merges","archive_url":"https://api.github.com/repos/Apache9/netty/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Apache9/netty/downloads","issues_url":"https://api.github.com/repos/Apache9/netty/issues{/number}","pulls_url":"https://api.github.com/repos/Apache9/netty/pulls{/number}","milestones_url":"https://api.github.com/repos/Apache9/netty/milestones{/number}","notifications_url":"https://api.github.com/repos/Apache9/netty/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Apache9/netty/labels{/name}","releases_url":"https://api.github.com/repos/Apache9/netty/releases{/id}","created_at":"2015-06-19T03:16:05Z","updated_at":"2015-06-19T03:16:13Z","pushed_at":"2015-07-03T10:51:18Z","git_url":"git://github.com/Apache9/netty.git","ssh_url":"git@github.com:Apache9/netty.git","clone_url":"https://github.com/Apache9/netty.git","svn_url":"https://github.com/Apache9/netty","homepage":"http://netty.io/","size":43544,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"netty:master","ref":"master","sha":"c15aa42d3201f9183ee9f2d89b32f6e808dc953e","user":{"login":"netty","id":473791,"avatar_url":"https://avatars.githubusercontent.com/u/473791?v=3","gravatar_id":"","url":"https://api.github.com/users/netty","html_url":"https://github.com/netty","followers_url":"https://api.github.com/users/netty/followers","following_url":"https://api.github.com/users/netty/following{/other_user}","gists_url":"https://api.github.com/users/netty/gists{/gist_id}","starred_url":"https://api.github.com/users/netty/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/netty/subscriptions","organizations_url":"https://api.github.com/users/netty/orgs","repos_url":"https://api.github.com/users/netty/repos","events_url":"https://api.github.com/users/netty/events{/privacy}","received_events_url":"https://api.github.com/users/netty/received_events","type":"Organization","site_admin":false},"repo":{"id":1064563,"name":"netty","full_name":"netty/netty","owner":{"login":"netty","id":473791,"avatar_url":"https://avatars.githubusercontent.com/u/473791?v=3","gravatar_id":"","url":"https://api.github.com/users/netty","html_url":"https://github.com/netty","followers_url":"https://api.github.com/users/netty/followers","following_url":"https://api.github.com/users/netty/following{/other_user}","gists_url":"https://api.github.com/users/netty/gists{/gist_id}","starred_url":"https://api.github.com/users/netty/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/netty/subscriptions","organizations_url":"https://api.github.com/users/netty/orgs","repos_url":"https://api.github.com/users/netty/repos","events_url":"https://api.github.com/users/netty/events{/privacy}","received_events_url":"https://api.github.com/users/netty/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/netty/netty","description":"Netty project - an event-driven asynchronous network application framework","fork":false,"url":"https://api.github.com/repos/netty/netty","forks_url":"https://api.github.com/repos/netty/netty/forks","keys_url":"https://api.github.com/repos/netty/netty/keys{/key_id}","collaborators_url":"https://api.github.com/repos/netty/netty/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/netty/netty/teams","hooks_url":"https://api.github.com/repos/netty/netty/hooks","issue_events_url":"https://api.github.com/repos/netty/netty/issues/events{/number}","events_url":"https://api.github.com/repos/netty/netty/events","assignees_url":"https://api.github.com/repos/netty/netty/assignees{/user}","branches_url":"https://api.github.com/repos/netty/netty/branches{/branch}","tags_url":"https://api.github.com/repos/netty/netty/tags","blobs_url":"https://api.github.com/repos/netty/netty/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/netty/netty/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/netty/netty/git/refs{/sha}","trees_url":"https://api.github.com/repos/netty/netty/git/trees{/sha}","statuses_url":"https://api.github.com/repos/netty/netty/statuses/{sha}","languages_url":"https://api.github.com/repos/netty/netty/languages","stargazers_url":"https://api.github.com/repos/netty/netty/stargazers","contributors_url":"https://api.github.com/repos/netty/netty/contributors","subscribers_url":"https://api.github.com/repos/netty/netty/subscribers","subscription_url":"https://api.github.com/repos/netty/netty/subscription","commits_url":"https://api.github.com/repos/netty/netty/commits{/sha}","git_commits_url":"https://api.github.com/repos/netty/netty/git/commits{/sha}","comments_url":"https://api.github.com/repos/netty/netty/comments{/number}","issue_comment_url":"https://api.github.com/repos/netty/netty/issues/comments{/number}","contents_url":"https://api.github.com/repos/netty/netty/contents/{+path}","compare_url":"https://api.github.com/repos/netty/netty/compare/{base}...{head}","merges_url":"https://api.github.com/repos/netty/netty/merges","archive_url":"https://api.github.com/repos/netty/netty/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/netty/netty/downloads","issues_url":"https://api.github.com/repos/netty/netty/issues{/number}","pulls_url":"https://api.github.com/repos/netty/netty/pulls{/number}","milestones_url":"https://api.github.com/repos/netty/netty/milestones{/number}","notifications_url":"https://api.github.com/repos/netty/netty/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/netty/netty/labels{/name}","releases_url":"https://api.github.com/repos/netty/netty/releases{/id}","created_at":"2010-11-09T09:22:21Z","updated_at":"2015-07-03T10:03:46Z","pushed_at":"2015-07-03T12:28:46Z","git_url":"git://github.com/netty/netty.git","ssh_url":"git@github.com:netty/netty.git","clone_url":"https://github.com/netty/netty.git","svn_url":"https://github.com/netty/netty","homepage":"http://netty.io/","size":129327,"stargazers_count":4856,"watchers_count":4856,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2413,"mirror_url":null,"open_issues_count":299,"forks":2413,"open_issues":299,"watchers":4856,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/netty/netty/pulls/3928"},"html":{"href":"https://github.com/netty/netty/pull/3928"},"issue":{"href":"https://api.github.com/repos/netty/netty/issues/3928"},"comments":{"href":"https://api.github.com/repos/netty/netty/issues/3928/comments"},"review_comments":{"href":"https://api.github.com/repos/netty/netty/pulls/3928/comments"},"review_comment":{"href":"https://api.github.com/repos/netty/netty/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/netty/netty/pulls/3928/commits"},"statuses":{"href":"https://api.github.com/repos/netty/netty/statuses/757ec877590d3f70cf5f17c78d391213fbb1601c"}}}}