{"action":"created","issue":{"url":"https://api.github.com/repos/aspnet/KestrelHttpServer/issues/562","labels_url":"https://api.github.com/repos/aspnet/KestrelHttpServer/issues/562/labels{/name}","comments_url":"https://api.github.com/repos/aspnet/KestrelHttpServer/issues/562/comments","events_url":"https://api.github.com/repos/aspnet/KestrelHttpServer/issues/562/events","html_url":"https://github.com/aspnet/KestrelHttpServer/pull/562","id":125542849,"number":562,"title":"Make all write operations atomic","user":{"login":"halter73","id":54385,"avatar_url":"https://avatars.githubusercontent.com/u/54385?v=3","gravatar_id":"","url":"https://api.github.com/users/halter73","html_url":"https://github.com/halter73","followers_url":"https://api.github.com/users/halter73/followers","following_url":"https://api.github.com/users/halter73/following{/other_user}","gists_url":"https://api.github.com/users/halter73/gists{/gist_id}","starred_url":"https://api.github.com/users/halter73/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/halter73/subscriptions","organizations_url":"https://api.github.com/users/halter73/orgs","repos_url":"https://api.github.com/users/halter73/repos","events_url":"https://api.github.com/users/halter73/events{/privacy}","received_events_url":"https://api.github.com/users/halter73/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/aspnet/KestrelHttpServer/labels/cla-already-signed","name":"cla-already-signed","color":"009800"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":4,"created_at":"2016-01-08T04:48:04Z","updated_at":"2016-01-08T06:05:37Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/aspnet/KestrelHttpServer/pulls/562","html_url":"https://github.com/aspnet/KestrelHttpServer/pull/562","diff_url":"https://github.com/aspnet/KestrelHttpServer/pull/562.diff","patch_url":"https://github.com/aspnet/KestrelHttpServer/pull/562.patch"},"body":"This PR ensures that simultaneous calls to `SocketOutput.WriteAsync` won't result in a corrupted write.\r\n\r\nThis was mainly achieved by moving the `CopyFrom` call inside of `SocketOutput.WriteAsync` inside of the `_contenxtLock`. I also moved chunking down a layer inside of `SocketOutput`, so it could be protected by the same lock.\r\n\r\nI tested this change using both the plaintext benchmark and a modified LargeResponseSample that used small chunking, and in both cases the performance was nearly identical <1% to dev.\r\n\r\nWhen I first tried only moving `CopyFrom` inside of the lock, I saw performance degradation of a few percent. I was able to remedy this by using `Monitor.TryEnter` to avoid stalling libuv threads."},"comment":{"url":"https://api.github.com/repos/aspnet/KestrelHttpServer/issues/comments/169905710","html_url":"https://github.com/aspnet/KestrelHttpServer/pull/562#issuecomment-169905710","issue_url":"https://api.github.com/repos/aspnet/KestrelHttpServer/issues/562","id":169905710,"user":{"login":"benaadams","id":1142958,"avatar_url":"https://avatars.githubusercontent.com/u/1142958?v=3","gravatar_id":"","url":"https://api.github.com/users/benaadams","html_url":"https://github.com/benaadams","followers_url":"https://api.github.com/users/benaadams/followers","following_url":"https://api.github.com/users/benaadams/following{/other_user}","gists_url":"https://api.github.com/users/benaadams/gists{/gist_id}","starred_url":"https://api.github.com/users/benaadams/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/benaadams/subscriptions","organizations_url":"https://api.github.com/users/benaadams/orgs","repos_url":"https://api.github.com/users/benaadams/repos","events_url":"https://api.github.com/users/benaadams/events{/privacy}","received_events_url":"https://api.github.com/users/benaadams/received_events","type":"User","site_admin":false},"created_at":"2016-01-08T06:05:37Z","updated_at":"2016-01-08T06:05:37Z","body":"The question is what's better?\r\n```\r\nvar t1 = file1.CopyToAsync(Body.Response);\r\nvar t2 = file2.CopyToAsync(Body.Response);\r\nawait Task.WhenAll(t1, t2);\r\n```\r\nCurrent - unknown output, unknown state (I'd suggest this is bad)\r\nThis change - right byte count output; unknown interleaving, good state\r\nAlternative - exception thrown to user code, good state"}}