{"action":"opened","number":5389,"pull_request":{"url":"https://api.github.com/repos/playframework/playframework/pulls/5389","id":53530324,"html_url":"https://github.com/playframework/playframework/pull/5389","diff_url":"https://github.com/playframework/playframework/pull/5389.diff","patch_url":"https://github.com/playframework/playframework/pull/5389.patch","issue_url":"https://api.github.com/repos/playframework/playframework/issues/5389","number":5389,"state":"open","locked":false,"title":"Add optimized Headers implementation for Netty","user":{"login":"richdougherty","id":14750,"avatar_url":"https://avatars.githubusercontent.com/u/14750?v=3","gravatar_id":"","url":"https://api.github.com/users/richdougherty","html_url":"https://github.com/richdougherty","followers_url":"https://api.github.com/users/richdougherty/followers","following_url":"https://api.github.com/users/richdougherty/following{/other_user}","gists_url":"https://api.github.com/users/richdougherty/gists{/gist_id}","starred_url":"https://api.github.com/users/richdougherty/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/richdougherty/subscriptions","organizations_url":"https://api.github.com/users/richdougherty/orgs","repos_url":"https://api.github.com/users/richdougherty/repos","events_url":"https://api.github.com/users/richdougherty/events{/privacy}","received_events_url":"https://api.github.com/users/richdougherty/received_events","type":"User","site_admin":false},"body":"This change improves performance by about 5% on a simple benchmark.\r\n\r\nThe standard Play `Headers` implementation is slow. `Headers` are stored as a sequence of string pairs. Accessing a single header value involves converting the pairs into a `Map` of headers and sequences of values then converting the sequence to an `Option`.\r\n\r\nWe can improve performance on each request by introducing a new `Headers` implementation that wraps the Netty headers data structure and delegates calls directly to Netty where possible. This saves a lot of work in the common case of reading header values because Netty has a fast implementation for these cases.\r\n\r\nNot all header methods have equivalent Netty header methods. For example, if you try to modify the headers by adding a new header value, the implementation will converting the Netty headers into a sequence of strings and then add the new header, just like the standard implementation. However, for most requests we will now be able to avoid this conversion and use the fast Netty headers instead.\r\n\r\nUnfortunately add a new implementation of `Headers` I wasn't able to just subclass the `Headers` class. That would have been straightforward, but unfortunately the `Headers` class has a public constructor that is commonly used for constructing `Headers`. This public constructor means that the `Headers` class needs to continue to support the current sequence of strings data structure.\r\n\r\nInstead of subclassing `Headers`, I've added a private abstract class called `HeadersImpl` that contains all the same methods as `Headers`. The `Headers` class now delegates to an internal `HeadersImpl` to do all of its work.\r\n\r\nThis `HeadersImpl` has two private subclasses: one that handles headers in the normal way, as a sequence of pairs, and another that wraps Netty headers.\r\n\r\nBy adding the `HeadersImpl` class and its subclasses we can continue to support the public constructor in `Headers`. When that constructor is called we construct a normal `HeadersImpl`, but we can now also construct other types of `HeadersImpl` too, such as the one that wraps Netty headers.\r\n\r\nI've deprecated the public constructor in `Headers` so we will be able to remove it in in Play 2.6. When the public constructor is removed, we can merge the `HeadersImpl` class back into the Headers class and the two `HeadersImpl` subclasses can become subclasses of Headers.","created_at":"2015-12-14T06:56:23Z","updated_at":"2015-12-14T06:56:23Z","closed_at":null,"merged_at":null,"merge_commit_sha":null,"assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/playframework/playframework/pulls/5389/commits","review_comments_url":"https://api.github.com/repos/playframework/playframework/pulls/5389/comments","review_comment_url":"https://api.github.com/repos/playframework/playframework/pulls/comments{/number}","comments_url":"https://api.github.com/repos/playframework/playframework/issues/5389/comments","statuses_url":"https://api.github.com/repos/playframework/playframework/statuses/698b36c85bbf412f76d61c5a2409b8681bebb7c6","head":{"label":"richdougherty:netty-header-performance","ref":"netty-header-performance","sha":"698b36c85bbf412f76d61c5a2409b8681bebb7c6","user":{"login":"richdougherty","id":14750,"avatar_url":"https://avatars.githubusercontent.com/u/14750?v=3","gravatar_id":"","url":"https://api.github.com/users/richdougherty","html_url":"https://github.com/richdougherty","followers_url":"https://api.github.com/users/richdougherty/followers","following_url":"https://api.github.com/users/richdougherty/following{/other_user}","gists_url":"https://api.github.com/users/richdougherty/gists{/gist_id}","starred_url":"https://api.github.com/users/richdougherty/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/richdougherty/subscriptions","organizations_url":"https://api.github.com/users/richdougherty/orgs","repos_url":"https://api.github.com/users/richdougherty/repos","events_url":"https://api.github.com/users/richdougherty/events{/privacy}","received_events_url":"https://api.github.com/users/richdougherty/received_events","type":"User","site_admin":false},"repo":{"id":8997972,"name":"playframework","full_name":"richdougherty/playframework","owner":{"login":"richdougherty","id":14750,"avatar_url":"https://avatars.githubusercontent.com/u/14750?v=3","gravatar_id":"","url":"https://api.github.com/users/richdougherty","html_url":"https://github.com/richdougherty","followers_url":"https://api.github.com/users/richdougherty/followers","following_url":"https://api.github.com/users/richdougherty/following{/other_user}","gists_url":"https://api.github.com/users/richdougherty/gists{/gist_id}","starred_url":"https://api.github.com/users/richdougherty/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/richdougherty/subscriptions","organizations_url":"https://api.github.com/users/richdougherty/orgs","repos_url":"https://api.github.com/users/richdougherty/repos","events_url":"https://api.github.com/users/richdougherty/events{/privacy}","received_events_url":"https://api.github.com/users/richdougherty/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/richdougherty/playframework","description":"Play Framework","fork":true,"url":"https://api.github.com/repos/richdougherty/playframework","forks_url":"https://api.github.com/repos/richdougherty/playframework/forks","keys_url":"https://api.github.com/repos/richdougherty/playframework/keys{/key_id}","collaborators_url":"https://api.github.com/repos/richdougherty/playframework/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/richdougherty/playframework/teams","hooks_url":"https://api.github.com/repos/richdougherty/playframework/hooks","issue_events_url":"https://api.github.com/repos/richdougherty/playframework/issues/events{/number}","events_url":"https://api.github.com/repos/richdougherty/playframework/events","assignees_url":"https://api.github.com/repos/richdougherty/playframework/assignees{/user}","branches_url":"https://api.github.com/repos/richdougherty/playframework/branches{/branch}","tags_url":"https://api.github.com/repos/richdougherty/playframework/tags","blobs_url":"https://api.github.com/repos/richdougherty/playframework/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/richdougherty/playframework/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/richdougherty/playframework/git/refs{/sha}","trees_url":"https://api.github.com/repos/richdougherty/playframework/git/trees{/sha}","statuses_url":"https://api.github.com/repos/richdougherty/playframework/statuses/{sha}","languages_url":"https://api.github.com/repos/richdougherty/playframework/languages","stargazers_url":"https://api.github.com/repos/richdougherty/playframework/stargazers","contributors_url":"https://api.github.com/repos/richdougherty/playframework/contributors","subscribers_url":"https://api.github.com/repos/richdougherty/playframework/subscribers","subscription_url":"https://api.github.com/repos/richdougherty/playframework/subscription","commits_url":"https://api.github.com/repos/richdougherty/playframework/commits{/sha}","git_commits_url":"https://api.github.com/repos/richdougherty/playframework/git/commits{/sha}","comments_url":"https://api.github.com/repos/richdougherty/playframework/comments{/number}","issue_comment_url":"https://api.github.com/repos/richdougherty/playframework/issues/comments{/number}","contents_url":"https://api.github.com/repos/richdougherty/playframework/contents/{+path}","compare_url":"https://api.github.com/repos/richdougherty/playframework/compare/{base}...{head}","merges_url":"https://api.github.com/repos/richdougherty/playframework/merges","archive_url":"https://api.github.com/repos/richdougherty/playframework/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/richdougherty/playframework/downloads","issues_url":"https://api.github.com/repos/richdougherty/playframework/issues{/number}","pulls_url":"https://api.github.com/repos/richdougherty/playframework/pulls{/number}","milestones_url":"https://api.github.com/repos/richdougherty/playframework/milestones{/number}","notifications_url":"https://api.github.com/repos/richdougherty/playframework/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/richdougherty/playframework/labels{/name}","releases_url":"https://api.github.com/repos/richdougherty/playframework/releases{/id}","created_at":"2013-03-25T03:20:47Z","updated_at":"2015-04-30T04:45:17Z","pushed_at":"2015-12-14T06:53:29Z","git_url":"git://github.com/richdougherty/playframework.git","ssh_url":"git@github.com:richdougherty/playframework.git","clone_url":"https://github.com/richdougherty/playframework.git","svn_url":"https://github.com/richdougherty/playframework","homepage":"http://www.playframework.org/","size":77087,"stargazers_count":0,"watchers_count":0,"language":"Scala","has_issues":false,"has_downloads":true,"has_wiki":false,"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":"playframework:master","ref":"master","sha":"879597660cbdb7cfb6609d45b8024650df856c5d","user":{"login":"playframework","id":319107,"avatar_url":"https://avatars.githubusercontent.com/u/319107?v=3","gravatar_id":"","url":"https://api.github.com/users/playframework","html_url":"https://github.com/playframework","followers_url":"https://api.github.com/users/playframework/followers","following_url":"https://api.github.com/users/playframework/following{/other_user}","gists_url":"https://api.github.com/users/playframework/gists{/gist_id}","starred_url":"https://api.github.com/users/playframework/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/playframework/subscriptions","organizations_url":"https://api.github.com/users/playframework/orgs","repos_url":"https://api.github.com/users/playframework/repos","events_url":"https://api.github.com/users/playframework/events{/privacy}","received_events_url":"https://api.github.com/users/playframework/received_events","type":"Organization","site_admin":false},"repo":{"id":2340549,"name":"playframework","full_name":"playframework/playframework","owner":{"login":"playframework","id":319107,"avatar_url":"https://avatars.githubusercontent.com/u/319107?v=3","gravatar_id":"","url":"https://api.github.com/users/playframework","html_url":"https://github.com/playframework","followers_url":"https://api.github.com/users/playframework/followers","following_url":"https://api.github.com/users/playframework/following{/other_user}","gists_url":"https://api.github.com/users/playframework/gists{/gist_id}","starred_url":"https://api.github.com/users/playframework/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/playframework/subscriptions","organizations_url":"https://api.github.com/users/playframework/orgs","repos_url":"https://api.github.com/users/playframework/repos","events_url":"https://api.github.com/users/playframework/events{/privacy}","received_events_url":"https://api.github.com/users/playframework/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/playframework/playframework","description":"Play Framework","fork":false,"url":"https://api.github.com/repos/playframework/playframework","forks_url":"https://api.github.com/repos/playframework/playframework/forks","keys_url":"https://api.github.com/repos/playframework/playframework/keys{/key_id}","collaborators_url":"https://api.github.com/repos/playframework/playframework/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/playframework/playframework/teams","hooks_url":"https://api.github.com/repos/playframework/playframework/hooks","issue_events_url":"https://api.github.com/repos/playframework/playframework/issues/events{/number}","events_url":"https://api.github.com/repos/playframework/playframework/events","assignees_url":"https://api.github.com/repos/playframework/playframework/assignees{/user}","branches_url":"https://api.github.com/repos/playframework/playframework/branches{/branch}","tags_url":"https://api.github.com/repos/playframework/playframework/tags","blobs_url":"https://api.github.com/repos/playframework/playframework/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/playframework/playframework/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/playframework/playframework/git/refs{/sha}","trees_url":"https://api.github.com/repos/playframework/playframework/git/trees{/sha}","statuses_url":"https://api.github.com/repos/playframework/playframework/statuses/{sha}","languages_url":"https://api.github.com/repos/playframework/playframework/languages","stargazers_url":"https://api.github.com/repos/playframework/playframework/stargazers","contributors_url":"https://api.github.com/repos/playframework/playframework/contributors","subscribers_url":"https://api.github.com/repos/playframework/playframework/subscribers","subscription_url":"https://api.github.com/repos/playframework/playframework/subscription","commits_url":"https://api.github.com/repos/playframework/playframework/commits{/sha}","git_commits_url":"https://api.github.com/repos/playframework/playframework/git/commits{/sha}","comments_url":"https://api.github.com/repos/playframework/playframework/comments{/number}","issue_comment_url":"https://api.github.com/repos/playframework/playframework/issues/comments{/number}","contents_url":"https://api.github.com/repos/playframework/playframework/contents/{+path}","compare_url":"https://api.github.com/repos/playframework/playframework/compare/{base}...{head}","merges_url":"https://api.github.com/repos/playframework/playframework/merges","archive_url":"https://api.github.com/repos/playframework/playframework/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/playframework/playframework/downloads","issues_url":"https://api.github.com/repos/playframework/playframework/issues{/number}","pulls_url":"https://api.github.com/repos/playframework/playframework/pulls{/number}","milestones_url":"https://api.github.com/repos/playframework/playframework/milestones{/number}","notifications_url":"https://api.github.com/repos/playframework/playframework/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/playframework/playframework/labels{/name}","releases_url":"https://api.github.com/repos/playframework/playframework/releases{/id}","created_at":"2011-09-07T09:24:08Z","updated_at":"2015-12-13T15:11:25Z","pushed_at":"2015-12-14T05:24:44Z","git_url":"git://github.com/playframework/playframework.git","ssh_url":"git@github.com:playframework/playframework.git","clone_url":"https://github.com/playframework/playframework.git","svn_url":"https://github.com/playframework/playframework","homepage":"http://www.playframework.com/","size":84014,"stargazers_count":7176,"watchers_count":7176,"language":"Scala","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":2539,"mirror_url":null,"open_issues_count":329,"forks":2539,"open_issues":329,"watchers":7176,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/playframework/playframework/pulls/5389"},"html":{"href":"https://github.com/playframework/playframework/pull/5389"},"issue":{"href":"https://api.github.com/repos/playframework/playframework/issues/5389"},"comments":{"href":"https://api.github.com/repos/playframework/playframework/issues/5389/comments"},"review_comments":{"href":"https://api.github.com/repos/playframework/playframework/pulls/5389/comments"},"review_comment":{"href":"https://api.github.com/repos/playframework/playframework/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/playframework/playframework/pulls/5389/commits"},"statuses":{"href":"https://api.github.com/repos/playframework/playframework/statuses/698b36c85bbf412f76d61c5a2409b8681bebb7c6"}},"merged":false,"mergeable":null,"mergeable_state":"unknown","merged_by":null,"comments":0,"review_comments":0,"commits":1,"additions":299,"deletions":30,"changed_files":9}}