{"action":"created","comment":{"url":"https://api.github.com/repos/apache/kafka/pulls/comments/81061922","pull_request_review_id":2069537,"id":81061922,"diff_hunk":"@@ -292,56 +286,44 @@ class DelayedOperationPurgatory[T <: DelayedOperation](purgatoryName: String,\n    */\n   private class Watchers(val key: Any) {\n \n-    private[this] val operations = new LinkedList[T]()\n+    private[this] var operations = Vector[T]()\n \n-    def watched: Int = operations synchronized operations.size\n+    def watched: Int = synchronized(operations.size)\n \n     // add the element to watch\n     def watch(t: T) {\n-      operations synchronized operations.add(t)\n+      synchronized {\n+        operations = operations :+ t\n+      }\n     }\n \n     // traverse the list and try to complete some watched elements\n     def tryCompleteWatched(): Int = {\n-\n-      var completed = 0\n-      operations synchronized {\n-        val iter = operations.iterator()\n-        while (iter.hasNext) {\n-          val curr = iter.next()\n-          if (curr.isCompleted) {\n-            // another thread has completed this operation, just remove it\n-            iter.remove()\n-          } else if (curr synchronized curr.tryComplete()) {\n-            completed += 1\n-            iter.remove()\n-          }\n-        }\n+      // call tryComplete without holding the lock to avoid potential deadlocks\n+      var completedAlready = 0\n+      var completedNow = 0\n+      for (op <- synchronized(operations)) {\n+        if (op.isCompleted())\n+          completedAlready += 1\n+        else if (op synchronized op.tryComplete())\n+          completedNow += 1\n       }\n \n-      if (operations.size == 0)\n-        removeKeyIfEmpty(key, this)\n+      // purge if there are any completed operations\n+      if (completedAlready + completedNow > 0)\n+        purgeCompleted()\n \n-      completed\n+      completedNow\n     }\n \n     // traverse the list and purge elements that are already completed by others\n     def purgeCompleted(): Int = {\n-      var purged = 0\n-      operations synchronized {\n-        val iter = operations.iterator()\n-        while (iter.hasNext) {\n-          val curr = iter.next()\n-          if (curr.isCompleted) {\n-            iter.remove()\n-            purged += 1\n-          }\n-        }\n+      val purged = synchronized {\n+        val initialSize = operations.size\n+        operations = operations.filterNot(_.isCompleted())\n+        initialSize - operations.size\n       }\n-\n-      if (operations.size == 0)\n-        removeKeyIfEmpty(key, this)\n-\n+      removeKeyIfEmpty(key, this)","path":"core/src/main/scala/kafka/server/DelayedOperation.scala","position":92,"original_position":92,"commit_id":"03e8545e06afe011fcceed1f32bb3424c5d31c6d","original_commit_id":"03e8545e06afe011fcceed1f32bb3424c5d31c6d","user":{"login":"hachikuji","id":12502538,"avatar_url":"https://avatars.githubusercontent.com/u/12502538?v=3","gravatar_id":"","url":"https://api.github.com/users/hachikuji","html_url":"https://github.com/hachikuji","followers_url":"https://api.github.com/users/hachikuji/followers","following_url":"https://api.github.com/users/hachikuji/following{/other_user}","gists_url":"https://api.github.com/users/hachikuji/gists{/gist_id}","starred_url":"https://api.github.com/users/hachikuji/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hachikuji/subscriptions","organizations_url":"https://api.github.com/users/hachikuji/orgs","repos_url":"https://api.github.com/users/hachikuji/repos","events_url":"https://api.github.com/users/hachikuji/events{/privacy}","received_events_url":"https://api.github.com/users/hachikuji/received_events","type":"User","site_admin":false},"body":"I wrote it that way initially, but I removed the check because `removeKeyIfEmpty` already checks if `operations` is empty.","created_at":"2016-09-29T04:05:38Z","updated_at":"2016-09-29T04:05:38Z","html_url":"https://github.com/apache/kafka/pull/1738#discussion_r81061922","pull_request_url":"https://api.github.com/repos/apache/kafka/pulls/1738","_links":{"self":{"href":"https://api.github.com/repos/apache/kafka/pulls/comments/81061922"},"html":{"href":"https://github.com/apache/kafka/pull/1738#discussion_r81061922"},"pull_request":{"href":"https://api.github.com/repos/apache/kafka/pulls/1738"}}},"pull_request":{"url":"https://api.github.com/repos/apache/kafka/pulls/1738","id":81265567,"html_url":"https://github.com/apache/kafka/pull/1738","diff_url":"https://github.com/apache/kafka/pull/1738.diff","patch_url":"https://github.com/apache/kafka/pull/1738.patch","issue_url":"https://api.github.com/repos/apache/kafka/issues/1738","number":1738,"state":"open","locked":false,"title":"KAFKA-3994: Fix deadlock in Watchers by calling tryComplete without the lock","user":{"login":"hachikuji","id":12502538,"avatar_url":"https://avatars.githubusercontent.com/u/12502538?v=3","gravatar_id":"","url":"https://api.github.com/users/hachikuji","html_url":"https://github.com/hachikuji","followers_url":"https://api.github.com/users/hachikuji/followers","following_url":"https://api.github.com/users/hachikuji/following{/other_user}","gists_url":"https://api.github.com/users/hachikuji/gists{/gist_id}","starred_url":"https://api.github.com/users/hachikuji/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hachikuji/subscriptions","organizations_url":"https://api.github.com/users/hachikuji/orgs","repos_url":"https://api.github.com/users/hachikuji/repos","events_url":"https://api.github.com/users/hachikuji/events{/privacy}","received_events_url":"https://api.github.com/users/hachikuji/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-08-15T03:08:40Z","updated_at":"2016-09-29T04:05:38Z","closed_at":null,"merged_at":null,"merge_commit_sha":"ece594ddaa38a0be55d3c43323884f61d5fea746","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/apache/kafka/pulls/1738/commits","review_comments_url":"https://api.github.com/repos/apache/kafka/pulls/1738/comments","review_comment_url":"https://api.github.com/repos/apache/kafka/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/kafka/issues/1738/comments","statuses_url":"https://api.github.com/repos/apache/kafka/statuses/03e8545e06afe011fcceed1f32bb3424c5d31c6d","head":{"label":"hachikuji:KAFKA-3994","ref":"KAFKA-3994","sha":"03e8545e06afe011fcceed1f32bb3424c5d31c6d","user":{"login":"hachikuji","id":12502538,"avatar_url":"https://avatars.githubusercontent.com/u/12502538?v=3","gravatar_id":"","url":"https://api.github.com/users/hachikuji","html_url":"https://github.com/hachikuji","followers_url":"https://api.github.com/users/hachikuji/followers","following_url":"https://api.github.com/users/hachikuji/following{/other_user}","gists_url":"https://api.github.com/users/hachikuji/gists{/gist_id}","starred_url":"https://api.github.com/users/hachikuji/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hachikuji/subscriptions","organizations_url":"https://api.github.com/users/hachikuji/orgs","repos_url":"https://api.github.com/users/hachikuji/repos","events_url":"https://api.github.com/users/hachikuji/events{/privacy}","received_events_url":"https://api.github.com/users/hachikuji/received_events","type":"User","site_admin":false},"repo":{"id":35842084,"name":"kafka","full_name":"hachikuji/kafka","owner":{"login":"hachikuji","id":12502538,"avatar_url":"https://avatars.githubusercontent.com/u/12502538?v=3","gravatar_id":"","url":"https://api.github.com/users/hachikuji","html_url":"https://github.com/hachikuji","followers_url":"https://api.github.com/users/hachikuji/followers","following_url":"https://api.github.com/users/hachikuji/following{/other_user}","gists_url":"https://api.github.com/users/hachikuji/gists{/gist_id}","starred_url":"https://api.github.com/users/hachikuji/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hachikuji/subscriptions","organizations_url":"https://api.github.com/users/hachikuji/orgs","repos_url":"https://api.github.com/users/hachikuji/repos","events_url":"https://api.github.com/users/hachikuji/events{/privacy}","received_events_url":"https://api.github.com/users/hachikuji/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/hachikuji/kafka","description":"Mirror of Apache Kafka","fork":true,"url":"https://api.github.com/repos/hachikuji/kafka","forks_url":"https://api.github.com/repos/hachikuji/kafka/forks","keys_url":"https://api.github.com/repos/hachikuji/kafka/keys{/key_id}","collaborators_url":"https://api.github.com/repos/hachikuji/kafka/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/hachikuji/kafka/teams","hooks_url":"https://api.github.com/repos/hachikuji/kafka/hooks","issue_events_url":"https://api.github.com/repos/hachikuji/kafka/issues/events{/number}","events_url":"https://api.github.com/repos/hachikuji/kafka/events","assignees_url":"https://api.github.com/repos/hachikuji/kafka/assignees{/user}","branches_url":"https://api.github.com/repos/hachikuji/kafka/branches{/branch}","tags_url":"https://api.github.com/repos/hachikuji/kafka/tags","blobs_url":"https://api.github.com/repos/hachikuji/kafka/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/hachikuji/kafka/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/hachikuji/kafka/git/refs{/sha}","trees_url":"https://api.github.com/repos/hachikuji/kafka/git/trees{/sha}","statuses_url":"https://api.github.com/repos/hachikuji/kafka/statuses/{sha}","languages_url":"https://api.github.com/repos/hachikuji/kafka/languages","stargazers_url":"https://api.github.com/repos/hachikuji/kafka/stargazers","contributors_url":"https://api.github.com/repos/hachikuji/kafka/contributors","subscribers_url":"https://api.github.com/repos/hachikuji/kafka/subscribers","subscription_url":"https://api.github.com/repos/hachikuji/kafka/subscription","commits_url":"https://api.github.com/repos/hachikuji/kafka/commits{/sha}","git_commits_url":"https://api.github.com/repos/hachikuji/kafka/git/commits{/sha}","comments_url":"https://api.github.com/repos/hachikuji/kafka/comments{/number}","issue_comment_url":"https://api.github.com/repos/hachikuji/kafka/issues/comments{/number}","contents_url":"https://api.github.com/repos/hachikuji/kafka/contents/{+path}","compare_url":"https://api.github.com/repos/hachikuji/kafka/compare/{base}...{head}","merges_url":"https://api.github.com/repos/hachikuji/kafka/merges","archive_url":"https://api.github.com/repos/hachikuji/kafka/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/hachikuji/kafka/downloads","issues_url":"https://api.github.com/repos/hachikuji/kafka/issues{/number}","pulls_url":"https://api.github.com/repos/hachikuji/kafka/pulls{/number}","milestones_url":"https://api.github.com/repos/hachikuji/kafka/milestones{/number}","notifications_url":"https://api.github.com/repos/hachikuji/kafka/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/hachikuji/kafka/labels{/name}","releases_url":"https://api.github.com/repos/hachikuji/kafka/releases{/id}","deployments_url":"https://api.github.com/repos/hachikuji/kafka/deployments","created_at":"2015-05-18T20:54:26Z","updated_at":"2015-05-18T20:54:28Z","pushed_at":"2016-09-29T02:23:54Z","git_url":"git://github.com/hachikuji/kafka.git","ssh_url":"git@github.com:hachikuji/kafka.git","clone_url":"https://github.com/hachikuji/kafka.git","svn_url":"https://github.com/hachikuji/kafka","homepage":null,"size":34387,"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":"0.8.2"}},"base":{"label":"apache:trunk","ref":"trunk","sha":"3db752a565071c78e4b11eaafa739844fa785b04","user":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"repo":{"id":2211243,"name":"kafka","full_name":"apache/kafka","owner":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apache/kafka","description":"Mirror of Apache Kafka","fork":false,"url":"https://api.github.com/repos/apache/kafka","forks_url":"https://api.github.com/repos/apache/kafka/forks","keys_url":"https://api.github.com/repos/apache/kafka/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/kafka/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/kafka/teams","hooks_url":"https://api.github.com/repos/apache/kafka/hooks","issue_events_url":"https://api.github.com/repos/apache/kafka/issues/events{/number}","events_url":"https://api.github.com/repos/apache/kafka/events","assignees_url":"https://api.github.com/repos/apache/kafka/assignees{/user}","branches_url":"https://api.github.com/repos/apache/kafka/branches{/branch}","tags_url":"https://api.github.com/repos/apache/kafka/tags","blobs_url":"https://api.github.com/repos/apache/kafka/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/kafka/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/kafka/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/kafka/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/kafka/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/kafka/languages","stargazers_url":"https://api.github.com/repos/apache/kafka/stargazers","contributors_url":"https://api.github.com/repos/apache/kafka/contributors","subscribers_url":"https://api.github.com/repos/apache/kafka/subscribers","subscription_url":"https://api.github.com/repos/apache/kafka/subscription","commits_url":"https://api.github.com/repos/apache/kafka/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/kafka/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/kafka/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/kafka/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/kafka/contents/{+path}","compare_url":"https://api.github.com/repos/apache/kafka/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/kafka/merges","archive_url":"https://api.github.com/repos/apache/kafka/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/kafka/downloads","issues_url":"https://api.github.com/repos/apache/kafka/issues{/number}","pulls_url":"https://api.github.com/repos/apache/kafka/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/kafka/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/kafka/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/kafka/labels{/name}","releases_url":"https://api.github.com/repos/apache/kafka/releases{/id}","deployments_url":"https://api.github.com/repos/apache/kafka/deployments","created_at":"2011-08-15T18:06:16Z","updated_at":"2016-09-29T03:42:13Z","pushed_at":"2016-09-29T02:23:54Z","git_url":"git://github.com/apache/kafka.git","ssh_url":"git@github.com:apache/kafka.git","clone_url":"https://github.com/apache/kafka.git","svn_url":"https://github.com/apache/kafka","homepage":null,"size":49694,"stargazers_count":3839,"watchers_count":3839,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":2380,"mirror_url":"git://git.apache.org/kafka.git","open_issues_count":254,"forks":2380,"open_issues":254,"watchers":3839,"default_branch":"trunk"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/kafka/pulls/1738"},"html":{"href":"https://github.com/apache/kafka/pull/1738"},"issue":{"href":"https://api.github.com/repos/apache/kafka/issues/1738"},"comments":{"href":"https://api.github.com/repos/apache/kafka/issues/1738/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/kafka/pulls/1738/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/kafka/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/kafka/pulls/1738/commits"},"statuses":{"href":"https://api.github.com/repos/apache/kafka/statuses/03e8545e06afe011fcceed1f32bb3424c5d31c6d"}}}}
{"actor":{"display_login":"hachikuji"}}