GitHub PullRequestReviewCommentEvent at 2014-07-04 10:21:01
Repository: elasticsearch
Actor: kimchy
Payload: {"action":"created","comment":{"url":"https://api.github.com/repos/elasticsearch/elasticsearch/pulls/comments/14554615","id":14554615,"diff_hunk":"@@ -128,78 +142,269 @@ public void clusterChanged(ClusterChangedEvent event) {\n             return;\n         }\n \n+        List<ShardId> shardsToDelete = new ArrayList<>();\n         for (IndexRoutingTable indexRoutingTable : event.state().routingTable()) {\n             // Note, closed indices will not have any routing information, so won't be deleted\n             for (IndexShardRoutingTable indexShardRoutingTable : indexRoutingTable) {\n-                ShardId shardId = indexShardRoutingTable.shardId();\n-                // a shard can be deleted if all its copies are active, and its not allocated on this node\n-                boolean shardCanBeDeleted = true;\n-                if (indexShardRoutingTable.size() == 0) {\n-                    // should not really happen, there should always be at least 1 (primary) shard in a\n-                    // shard replication group, in any case, protected from deleting something by mistake\n-                    shardCanBeDeleted = false;\n-                } else {\n-                    for (ShardRouting shardRouting : indexShardRoutingTable) {\n-                        // be conservative here, check on started, not even active\n-                        if (!shardRouting.started()) {\n-                            shardCanBeDeleted = false;\n-                            break;\n-                        }\n+                if (shardCanBeDeleted(event.state(), indexShardRoutingTable)) {\n+                    ShardId shardId = indexShardRoutingTable.shardId();\n+                    IndexService indexService = indicesService.indexService(shardId.getIndex());\n+                    if (indexService == null || !indexService.hasShard(shardId.getId())) {\n+                        shardsToDelete.add(shardId);\n+                    }\n+                }\n+            }\n+        }\n \n-                        // if the allocated or relocation node id doesn't exists in the cluster state or we're not connected to it\n-                        // it may be a stale node, make sure we don't do anything with this until the routing table has properly been\n-                        // rerouted to reflect the fact that the node does not exists\n-                        DiscoveryNode node = event.state().nodes().get(shardRouting.currentNodeId());\n-                        if (node == null || !transportService.nodeConnected(node)) {\n-                            shardCanBeDeleted = false;\n-                            break;\n-                        }\n-                        if (shardRouting.relocatingNodeId() != null) {\n-                            node = event.state().nodes().get(shardRouting.relocatingNodeId());\n-                            if (node == null || !transportService.nodeConnected(node)) {\n-                                shardCanBeDeleted = false;\n-                                break;\n-                            }\n-                        }\n+        if (!shardsToDelete.isEmpty()) {\n+            deleteShardIfExistElseWhere(event.state(), shardsToDelete);\n+        }\n+    }\n \n-                        // check if shard is active on the current node or is getting relocated to the our node\n-                        String localNodeId = clusterService.localNode().id();\n-                        if (localNodeId.equals(shardRouting.currentNodeId()) || localNodeId.equals(shardRouting.relocatingNodeId())) {\n-                            shardCanBeDeleted = false;\n-                            break;\n-                        }\n+    private boolean shardCanBeDeleted(ClusterState state, IndexShardRoutingTable indexShardRoutingTable) {\n+        // a shard can be deleted if all its copies are active, and its not allocated on this node\n+        if (indexShardRoutingTable.size() == 0) {\n+            // should not really happen, there should always be at least 1 (primary) shard in a\n+            // shard replication group, in any case, protected from deleting something by mistake\n+            return false;\n+        }\n+\n+        for (ShardRouting shardRouting : indexShardRoutingTable) {\n+            // be conservative here, check on started, not even active\n+            if (!shardRouting.started()) {\n+                return false;\n+            }\n+\n+            // if the allocated or relocation node id doesn't exists in the cluster state or we're not connected to it\n+            // it may be a stale node, make sure we don't do anything with this until the routing table has properly been\n+            // rerouted to reflect the fact that the node does not exists\n+            DiscoveryNode node = state.nodes().get(shardRouting.currentNodeId());\n+            if (node == null || !transportService.nodeConnected(node)) {\n+                return false;\n+            }\n+            if (shardRouting.relocatingNodeId() != null) {\n+                node = state.nodes().get(shardRouting.relocatingNodeId());\n+                if (node == null || !transportService.nodeConnected(node)) {\n+                    return false;\n+                }\n+            }\n+\n+            // check if shard is active on the current node or is getting relocated to the our node\n+            String localNodeId = clusterService.localNode().id();\n+            if (localNodeId.equals(shardRouting.currentNodeId()) || localNodeId.equals(shardRouting.relocatingNodeId())) {\n+                return false;\n+            }\n+        }\n+\n+        return true;\n+    }\n+\n+    private void deleteShardIfExistElseWhere(ClusterState state, List<ShardId> shardsToDelete) {\n+        shards: for (ShardId shardId : shardsToDelete) {\n+            String indexUUID = state.getMetaData().index(shardId.getIndex()).getUUID();\n+            List<Tuple<DiscoveryNode, ShardActiveRequest>> requests = new ArrayList<>();\n+            IndexShardRoutingTable shardRoutingTable = state.routingTable().index(shardId.getIndex()).shard(shardId.id());\n+            for (ShardRouting shardRouting : shardRoutingTable) {\n+                DiscoveryNode node = state.getNodes().get(shardRouting.currentNodeId());\n+                if (state.nodes().localNode().equals(node)) {\n+                    continue;\n+                }\n+                requests.add(new Tuple<>(node, new ShardActiveRequest(state.getClusterName(), indexUUID, shardId)));\n+            }\n+\n+            for (Tuple<DiscoveryNode, ShardActiveRequest> request : requests) {\n+                // If all nodes have been upgraded to >= 1.3.0 at some point we get back here and have the chance to\n+                // run this api. (when cluster state is then updated)\n+                if (request.v1().getVersion().before(Version.V_1_3_0)) {\n+                    logger.debug(\"Can't invoke shard active api for shard [{}]\", shardId);\n+                    continue shards;\n+                }\n+            }\n+\n+            ShardActiveResponseHandler responseHandler = new ShardActiveResponseHandler(shardId, requests.size());\n+            for (Tuple<DiscoveryNode, ShardActiveRequest> request : requests) {\n+                transportService.submitRequest(request.v1(), ACTION_SHARD_EXISTS, request.v2(), responseHandler);\n+            }\n+        }\n+    }\n+\n+    private class ShardActiveResponseHandler implements TransportResponseHandler<ShardActiveResponse> {\n+\n+        private final ShardId shardId;\n+        private final AtomicInteger awaitingResponses;\n+        private final AtomicInteger activeCopies;\n+\n+        public ShardActiveResponseHandler(ShardId shardId, int expectedResponses) {\n+            this.shardId = shardId;\n+            this.awaitingResponses = new AtomicInteger(expectedResponses);\n+            this.activeCopies = new AtomicInteger();\n+        }\n+\n+        @Override\n+        public ShardActiveResponse newInstance() {\n+            return new ShardActiveResponse();\n+        }\n+\n+        @Override\n+        public void handleResponse(ShardActiveResponse response) {\n+            if (response.shardExists) {\n+                logger.trace(\"[{}] exists on node [{}]\", shardId, response.node);\n+                activeCopies.incrementAndGet();\n+            }\n+\n+            if (awaitingResponses.decrementAndGet() == 0) {\n+                allNodesResponded();\n+            }\n+        }\n+\n+        @Override\n+        public void handleException(TransportException exp) {\n+            logger.debug(\"shards exists request failed for {}\", exp, shardId);\n+            if (awaitingResponses.decrementAndGet() == 0) {\n+                allNodesResponded();\n+            }\n+        }\n+\n+        @Override\n+        public String executor() {\n+            return ThreadPool.Names.GENERIC;\n+        }\n+\n+        private void allNodesResponded() {\n+            if (activeCopies.get() == 0) {\n+                logger.trace(\"not deleting shard [{}], no node holds this shard\", shardId);\n+                return;\n+            }\n+\n+            ClusterState state = clusterService.state();\n+            if (!shardCanBeDeleted(state, state.routingTable().index(shardId.getIndex()).shard(shardId.getId()))) {\n+                logger.trace(\"not deleting shard [{}], pre shard active action check fails now\", shardId);\n+            }","path":"src/main/java/org/elasticsearch/indices/store/IndicesStore.java","position":236,"original_position":236,"commit_id":"b6e4a60a53968849ca4c41a5890403730f0b8192","original_commit_id":"b6e4a60a53968849ca4c41a5890403730f0b8192","user":{"login":"kimchy","id":41300,"avatar_url":"https://avatars.githubusercontent.com/u/41300?","gravatar_id":"fd44bb3c96e34e000c5453a0078900d6","url":"https://api.github.com/users/kimchy","html_url":"https://github.com/kimchy","followers_url":"https://api.github.com/users/kimchy/followers","following_url":"https://api.github.com/users/kimchy/following{/other_user}","gists_url":"https://api.github.com/users/kimchy/gists{/gist_id}","starred_url":"https://api.github.com/users/kimchy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kimchy/subscriptions","organizations_url":"https://api.github.com/users/kimchy/orgs","repos_url":"https://api.github.com/users/kimchy/repos","events_url":"https://api.github.com/users/kimchy/events{/privacy}","received_events_url":"https://api.github.com/users/kimchy/received_events","type":"User","site_admin":false},"body":"there are a few things that might happen here once all the calls:\r\n- the shards might move around: if they did, compared to what we had before, we need to run the same logic with the call to the action again.\r\n- a shard with the same id might get replaced on us locally, remember, we no longer have the protection of this not happening on the cluster state changed listener. I would keep the IndexShard instance around, and see if its still the same as the one we get?","created_at":"2014-07-04T10:21:01Z","updated_at":"2014-07-04T10:21:01Z","html_url":"https://github.com/elasticsearch/elasticsearch/pull/6692#discussion_r14554615","pull_request_url":"https://api.github.com/repos/elasticsearch/elasticsearch/pulls/6692","_links":{"self":{"href":"https://api.github.com/repos/elasticsearch/elasticsearch/pulls/comments/14554615"},"html":{"href":"https://github.com/elasticsearch/elasticsearch/pull/6692#discussion_r14554615"},"pull_request":{"href":"https://api.github.com/repos/elasticsearch/elasticsearch/pulls/6692"}}},"pull_request":{"url":"https://api.github.com/repos/elasticsearch/elasticsearch/pulls/6692","id":17905987,"html_url":"https://github.com/elasticsearch/elasticsearch/pull/6692","diff_url":"https://github.com/elasticsearch/elasticsearch/pull/6692.diff","patch_url":"https://github.com/elasticsearch/elasticsearch/pull/6692.patch","issue_url":"https://api.github.com/repos/elasticsearch/elasticsearch/issues/6692","number":6692,"state":"open","title":"Store: Before deleting shard verify that another node holds an active shard instance","user":{"login":"martijnvg","id":580421,"avatar_url":"https://avatars.githubusercontent.com/u/580421?","gravatar_id":"c572e98b0d86d9f26d5e9cd9ddd99fc7","url":"https://api.github.com/users/martijnvg","html_url":"https://github.com/martijnvg","followers_url":"https://api.github.com/users/martijnvg/followers","following_url":"https://api.github.com/users/martijnvg/following{/other_user}","gists_url":"https://api.github.com/users/martijnvg/gists{/gist_id}","starred_url":"https://api.github.com/users/martijnvg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/martijnvg/subscriptions","organizations_url":"https://api.github.com/users/martijnvg/orgs","repos_url":"https://api.github.com/users/martijnvg/repos","events_url":"https://api.github.com/users/martijnvg/events{/privacy}","received_events_url":"https://api.github.com/users/martijnvg/received_events","type":"User","site_admin":false},"body":"Before removing shard physically from disk verify that another node in the cluster actually holds an active shard instance.","created_at":"2014-07-02T19:13:11Z","updated_at":"2014-07-04T10:21:01Z","closed_at":null,"merged_at":null,"merge_commit_sha":"676eadcf4e5f1f308f05754644e2431f088d5ceb","assignee":{"login":"martijnvg","id":580421,"avatar_url":"https://avatars.githubusercontent.com/u/580421?","gravatar_id":"c572e98b0d86d9f26d5e9cd9ddd99fc7","url":"https://api.github.com/users/martijnvg","html_url":"https://github.com/martijnvg","followers_url":"https://api.github.com/users/martijnvg/followers","following_url":"https://api.github.com/users/martijnvg/following{/other_user}","gists_url":"https://api.github.com/users/martijnvg/gists{/gist_id}","starred_url":"https://api.github.com/users/martijnvg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/martijnvg/subscriptions","organizations_url":"https://api.github.com/users/martijnvg/orgs","repos_url":"https://api.github.com/users/martijnvg/repos","events_url":"https://api.github.com/users/martijnvg/events{/privacy}","received_events_url":"https://api.github.com/users/martijnvg/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/elasticsearch/elasticsearch/pulls/6692/commits","review_comments_url":"https://api.github.com/repos/elasticsearch/elasticsearch/pulls/6692/comments","review_comment_url":"https://api.github.com/repos/elasticsearch/elasticsearch/pulls/comments/{number}","comments_url":"https://api.github.com/repos/elasticsearch/elasticsearch/issues/6692/comments","statuses_url":"https://api.github.com/repos/elasticsearch/elasticsearch/statuses/b6e4a60a53968849ca4c41a5890403730f0b8192","head":{"label":"martijnvg:improvements/shard-exists-elsewhere","ref":"improvements/shard-exists-elsewhere","sha":"b6e4a60a53968849ca4c41a5890403730f0b8192","user":{"login":"martijnvg","id":580421,"avatar_url":"https://avatars.githubusercontent.com/u/580421?","gravatar_id":"c572e98b0d86d9f26d5e9cd9ddd99fc7","url":"https://api.github.com/users/martijnvg","html_url":"https://github.com/martijnvg","followers_url":"https://api.github.com/users/martijnvg/followers","following_url":"https://api.github.com/users/martijnvg/following{/other_user}","gists_url":"https://api.github.com/users/martijnvg/gists{/gist_id}","starred_url":"https://api.github.com/users/martijnvg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/martijnvg/subscriptions","organizations_url":"https://api.github.com/users/martijnvg/orgs","repos_url":"https://api.github.com/users/martijnvg/repos","events_url":"https://api.github.com/users/martijnvg/events{/privacy}","received_events_url":"https://api.github.com/users/martijnvg/received_events","type":"User","site_admin":false},"repo":{"id":3584739,"name":"elasticsearch","full_name":"martijnvg/elasticsearch","owner":{"login":"martijnvg","id":580421,"avatar_url":"https://avatars.githubusercontent.com/u/580421?","gravatar_id":"c572e98b0d86d9f26d5e9cd9ddd99fc7","url":"https://api.github.com/users/martijnvg","html_url":"https://github.com/martijnvg","followers_url":"https://api.github.com/users/martijnvg/followers","following_url":"https://api.github.com/users/martijnvg/following{/other_user}","gists_url":"https://api.github.com/users/martijnvg/gists{/gist_id}","starred_url":"https://api.github.com/users/martijnvg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/martijnvg/subscriptions","organizations_url":"https://api.github.com/users/martijnvg/orgs","repos_url":"https://api.github.com/users/martijnvg/repos","events_url":"https://api.github.com/users/martijnvg/events{/privacy}","received_events_url":"https://api.github.com/users/martijnvg/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/martijnvg/elasticsearch","description":"Open Source, Distributed, RESTful Search Engine with grouping","fork":true,"url":"https://api.github.com/repos/martijnvg/elasticsearch","forks_url":"https://api.github.com/repos/martijnvg/elasticsearch/forks","keys_url":"https://api.github.com/repos/martijnvg/elasticsearch/keys{/key_id}","collaborators_url":"https://api.github.com/repos/martijnvg/elasticsearch/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/martijnvg/elasticsearch/teams","hooks_url":"https://api.github.com/repos/martijnvg/elasticsearch/hooks","issue_events_url":"https://api.github.com/repos/martijnvg/elasticsearch/issues/events{/number}","events_url":"https://api.github.com/repos/martijnvg/elasticsearch/events","assignees_url":"https://api.github.com/repos/martijnvg/elasticsearch/assignees{/user}","branches_url":"https://api.github.com/repos/martijnvg/elasticsearch/branches{/branch}","tags_url":"https://api.github.com/repos/martijnvg/elasticsearch/tags","blobs_url":"https://api.github.com/repos/martijnvg/elasticsearch/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/martijnvg/elasticsearch/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/martijnvg/elasticsearch/git/refs{/sha}","trees_url":"https://api.github.com/repos/martijnvg/elasticsearch/git/trees{/sha}","statuses_url":"https://api.github.com/repos/martijnvg/elasticsearch/statuses/{sha}","languages_url":"https://api.github.com/repos/martijnvg/elasticsearch/languages","stargazers_url":"https://api.github.com/repos/martijnvg/elasticsearch/stargazers","contributors_url":"https://api.github.com/repos/martijnvg/elasticsearch/contributors","subscribers_url":"https://api.github.com/repos/martijnvg/elasticsearch/subscribers","subscription_url":"https://api.github.com/repos/martijnvg/elasticsearch/subscription","commits_url":"https://api.github.com/repos/martijnvg/elasticsearch/commits{/sha}","git_commits_url":"https://api.github.com/repos/martijnvg/elasticsearch/git/commits{/sha}","comments_url":"https://api.github.com/repos/martijnvg/elasticsearch/comments{/number}","issue_comment_url":"https://api.github.com/repos/martijnvg/elasticsearch/issues/comments/{number}","contents_url":"https://api.github.com/repos/martijnvg/elasticsearch/contents/{+path}","compare_url":"https://api.github.com/repos/martijnvg/elasticsearch/compare/{base}...{head}","merges_url":"https://api.github.com/repos/martijnvg/elasticsearch/merges","archive_url":"https://api.github.com/repos/martijnvg/elasticsearch/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/martijnvg/elasticsearch/downloads","issues_url":"https://api.github.com/repos/martijnvg/elasticsearch/issues{/number}","pulls_url":"https://api.github.com/repos/martijnvg/elasticsearch/pulls{/number}","milestones_url":"https://api.github.com/repos/martijnvg/elasticsearch/milestones{/number}","notifications_url":"https://api.github.com/repos/martijnvg/elasticsearch/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/martijnvg/elasticsearch/labels{/name}","releases_url":"https://api.github.com/repos/martijnvg/elasticsearch/releases{/id}","created_at":"2012-02-29T18:56:33Z","updated_at":"2014-06-25T09:07:57Z","pushed_at":"2014-07-03T15:31:12Z","git_url":"git://github.com/martijnvg/elasticsearch.git","ssh_url":"git@github.com:martijnvg/elasticsearch.git","clone_url":"https://github.com/martijnvg/elasticsearch.git","svn_url":"https://github.com/martijnvg/elasticsearch","homepage":"http://elasticsearch.org","size":55711,"stargazers_count":12,"watchers_count":12,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":12,"default_branch":"master"}},"base":{"label":"elasticsearch:master","ref":"master","sha":"8909a77724d239cce805cc1bf84c13850d7a78a3","user":{"login":"elasticsearch","id":141304,"avatar_url":"https://avatars.githubusercontent.com/u/141304?","gravatar_id":"1aecf795625bbc7251068cfbc39800ab","url":"https://api.github.com/users/elasticsearch","html_url":"https://github.com/elasticsearch","followers_url":"https://api.github.com/users/elasticsearch/followers","following_url":"https://api.github.com/users/elasticsearch/following{/other_user}","gists_url":"https://api.github.com/users/elasticsearch/gists{/gist_id}","starred_url":"https://api.github.com/users/elasticsearch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/elasticsearch/subscriptions","organizations_url":"https://api.github.com/users/elasticsearch/orgs","repos_url":"https://api.github.com/users/elasticsearch/repos","events_url":"https://api.github.com/users/elasticsearch/events{/privacy}","received_events_url":"https://api.github.com/users/elasticsearch/received_events","type":"Organization","site_admin":false},"repo":{"id":507775,"name":"elasticsearch","full_name":"elasticsearch/elasticsearch","owner":{"login":"elasticsearch","id":141304,"avatar_url":"https://avatars.githubusercontent.com/u/141304?","gravatar_id":"1aecf795625bbc7251068cfbc39800ab","url":"https://api.github.com/users/elasticsearch","html_url":"https://github.com/elasticsearch","followers_url":"https://api.github.com/users/elasticsearch/followers","following_url":"https://api.github.com/users/elasticsearch/following{/other_user}","gists_url":"https://api.github.com/users/elasticsearch/gists{/gist_id}","starred_url":"https://api.github.com/users/elasticsearch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/elasticsearch/subscriptions","organizations_url":"https://api.github.com/users/elasticsearch/orgs","repos_url":"https://api.github.com/users/elasticsearch/repos","events_url":"https://api.github.com/users/elasticsearch/events{/privacy}","received_events_url":"https://api.github.com/users/elasticsearch/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/elasticsearch/elasticsearch","description":"Open Source, Distributed, RESTful Search Engine","fork":false,"url":"https://api.github.com/repos/elasticsearch/elasticsearch","forks_url":"https://api.github.com/repos/elasticsearch/elasticsearch/forks","keys_url":"https://api.github.com/repos/elasticsearch/elasticsearch/keys{/key_id}","collaborators_url":"https://api.github.com/repos/elasticsearch/elasticsearch/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/elasticsearch/elasticsearch/teams","hooks_url":"https://api.github.com/repos/elasticsearch/elasticsearch/hooks","issue_events_url":"https://api.github.com/repos/elasticsearch/elasticsearch/issues/events{/number}","events_url":"https://api.github.com/repos/elasticsearch/elasticsearch/events","assignees_url":"https://api.github.com/repos/elasticsearch/elasticsearch/assignees{/user}","branches_url":"https://api.github.com/repos/elasticsearch/elasticsearch/branches{/branch}","tags_url":"https://api.github.com/repos/elasticsearch/elasticsearch/tags","blobs_url":"https://api.github.com/repos/elasticsearch/elasticsearch/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/elasticsearch/elasticsearch/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/elasticsearch/elasticsearch/git/refs{/sha}","trees_url":"https://api.github.com/repos/elasticsearch/elasticsearch/git/trees{/sha}","statuses_url":"https://api.github.com/repos/elasticsearch/elasticsearch/statuses/{sha}","languages_url":"https://api.github.com/repos/elasticsearch/elasticsearch/languages","stargazers_url":"https://api.github.com/repos/elasticsearch/elasticsearch/stargazers","contributors_url":"https://api.github.com/repos/elasticsearch/elasticsearch/contributors","subscribers_url":"https://api.github.com/repos/elasticsearch/elasticsearch/subscribers","subscription_url":"https://api.github.com/repos/elasticsearch/elasticsearch/subscription","commits_url":"https://api.github.com/repos/elasticsearch/elasticsearch/commits{/sha}","git_commits_url":"https://api.github.com/repos/elasticsearch/elasticsearch/git/commits{/sha}","comments_url":"https://api.github.com/repos/elasticsearch/elasticsearch/comments{/number}","issue_comment_url":"https://api.github.com/repos/elasticsearch/elasticsearch/issues/comments/{number}","contents_url":"https://api.github.com/repos/elasticsearch/elasticsearch/contents/{+path}","compare_url":"https://api.github.com/repos/elasticsearch/elasticsearch/compare/{base}...{head}","merges_url":"https://api.github.com/repos/elasticsearch/elasticsearch/merges","archive_url":"https://api.github.com/repos/elasticsearch/elasticsearch/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/elasticsearch/elasticsearch/downloads","issues_url":"https://api.github.com/repos/elasticsearch/elasticsearch/issues{/number}","pulls_url":"https://api.github.com/repos/elasticsearch/elasticsearch/pulls{/number}","milestones_url":"https://api.github.com/repos/elasticsearch/elasticsearch/milestones{/number}","notifications_url":"https://api.github.com/repos/elasticsearch/elasticsearch/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/elasticsearch/elasticsearch/labels{/name}","releases_url":"https://api.github.com/repos/elasticsearch/elasticsearch/releases{/id}","created_at":"2010-02-08T13:20:56Z","updated_at":"2014-07-04T09:43:18Z","pushed_at":"2014-07-04T10:19:18Z","git_url":"git://github.com/elasticsearch/elasticsearch.git","ssh_url":"git@github.com:elasticsearch/elasticsearch.git","clone_url":"https://github.com/elasticsearch/elasticsearch.git","svn_url":"https://github.com/elasticsearch/elasticsearch","homepage":"http://elasticsearch.org","size":208469,"stargazers_count":7493,"watchers_count":7493,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":false,"forks_count":2110,"mirror_url":null,"open_issues_count":1079,"forks":2110,"open_issues":1079,"watchers":7493,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/elasticsearch/elasticsearch/pulls/6692"},"html":{"href":"https://github.com/elasticsearch/elasticsearch/pull/6692"},"issue":{"href":"https://api.github.com/repos/elasticsearch/elasticsearch/issues/6692"},"comments":{"href":"https://api.github.com/repos/elasticsearch/elasticsearch/issues/6692/comments"},"review_comments":{"href":"https://api.github.com/repos/elasticsearch/elasticsearch/pulls/6692/comments"},"review_comment":{"href":"https://api.github.com/repos/elasticsearch/elasticsearch/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/elasticsearch/elasticsearch/pulls/6692/commits"},"statuses":{"href":"https://api.github.com/repos/elasticsearch/elasticsearch/statuses/b6e4a60a53968849ca4c41a5890403730f0b8192"}}}}