{"action":"created","comment":{"url":"https://api.github.com/repos/apache/accumulo/pulls/comments/59384715","id":59384715,"diff_hunk":"@@ -0,0 +1,334 @@\n+/*\n+ * Licensed to the Apache Software Foundation (ASF) under one or more\n+ * contributor license agreements.  See the NOTICE file distributed with\n+ * this work for additional information regarding copyright ownership.\n+ * The ASF licenses this file to You under the Apache License, Version 2.0\n+ * (the \"License\"); you may not use this file except in compliance with\n+ * the License.  You may obtain a copy of the License at\n+ *\n+ *     http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+package org.apache.accumulo.server.master.balancer;\n+\n+import java.net.InetAddress;\n+import java.net.UnknownHostException;\n+import java.util.ArrayList;\n+import java.util.Collections;\n+import java.util.HashMap;\n+import java.util.List;\n+import java.util.Map;\n+import java.util.Map.Entry;\n+import java.util.Set;\n+import java.util.SortedMap;\n+import java.util.TreeMap;\n+import java.util.regex.Pattern;\n+\n+import org.apache.accumulo.core.client.admin.TableOperations;\n+import org.apache.accumulo.core.conf.AccumuloConfiguration;\n+import org.apache.accumulo.core.conf.Property;\n+import org.apache.accumulo.core.data.impl.KeyExtent;\n+import org.apache.accumulo.core.master.thrift.TabletServerStatus;\n+import org.apache.accumulo.core.tabletserver.thrift.TabletStats;\n+import org.apache.accumulo.server.conf.ServerConfiguration;\n+import org.apache.accumulo.server.master.state.TServerInstance;\n+import org.apache.accumulo.server.master.state.TabletMigration;\n+import org.apache.thrift.TException;\n+import org.slf4j.Logger;\n+import org.slf4j.LoggerFactory;\n+\n+/**\n+ * This balancer will create pools of tablet servers by grouping tablet servers that match a regex into the same pool and calling the balancer set on the table\n+ * to balance within the set of matching tablet servers. All tablet servers that do not match a regex are grouped into a default pool.<br>\n+ * Regex properties for this balancer are specified as:<br>\n+ * <b>table.custom.balancer.host.regex.&lt;tablename&gt;=&lt;regex&gt;</b><br>\n+ * Periodically (default 5m) this balancer will check to see if a tablet server is hosting tablets that it should not be according to the regex configuration.\n+ * If this occurs then the offending tablets will be reassigned. This would cover the case where the configuration is changed and the master is restarted while\n+ * the tablet servers are up. To change the out of bounds check time period, set the following property:<br>\n+ * <b>table.custom.balancer.host.regex.oob.period=5m</b><br>\n+ * Periodically (default 5m) this balancer will regroup the set of current tablet servers into pools based on regexes applied to the tserver host names. This\n+ * would cover the case of tservers dying or coming online. To change the host pool check time period, set the following property: <br>\n+ * <b>table.custom.balancer.host.regex.pool.check=5m</b><br>\n+ * Regex matching can be based on either the host name (default) or host ip address. To set this balancer to match the regular expressions to the tablet server\n+ * IP address, then set the following property:<br>\n+ * <b>table.custom.balancer.host.regex.is.ip=true</b>\n+ *\n+ */\n+public class HostRegexTableLoadBalancer extends TableLoadBalancer {\n+\n+  private static final Logger LOG = LoggerFactory.getLogger(HostRegexTableLoadBalancer.class);\n+  public static final String HOST_BALANCER_PREFIX = Property.TABLE_ARBITRARY_PROP_PREFIX.getKey() + \"balancer.host.regex.\";\n+  public static final String HOST_BALANCER_OOB_CHECK = Property.TABLE_ARBITRARY_PROP_PREFIX.getKey() + \"balancer.host.regex.oob.period\";\n+  private static final String HOST_BALANCER_OOB_DEFAULT = \"5m\";\n+  public static final String HOST_BALANCER_POOL_RECHECK_KEY = Property.TABLE_ARBITRARY_PROP_PREFIX.getKey() + \"balancer.host.regex.pool.check\";\n+  private static final String HOST_BALANCER_POOL_RECHECK_DEFAULT = \"5m\";\n+  public static final String HOST_BALANCER_REGEX_USING_IPS = Property.TABLE_ARBITRARY_PROP_PREFIX.getKey() + \"balancer.host.regex.is.ip\";\n+  protected static final String DEFAULT_POOL = \"HostTableLoadBalancer.ALL\";\n+\n+  protected long oobCheckMillis = AccumuloConfiguration.getTimeInMillis(HOST_BALANCER_OOB_DEFAULT);\n+  protected long poolRecheckMillis = AccumuloConfiguration.getTimeInMillis(HOST_BALANCER_POOL_RECHECK_DEFAULT);\n+\n+  private Map<String,String> tableIdToTableName = null;\n+  private Map<String,Pattern> poolNameToRegexPattern = null;\n+  private volatile long lastOOBCheck = System.currentTimeMillis();\n+  private volatile long lastPoolRecheck = 0;\n+  private boolean isIpBasedRegex = false;\n+  private Map<String,SortedMap<TServerInstance,TabletServerStatus>> pools = new HashMap<String,SortedMap<TServerInstance,TabletServerStatus>>();\n+\n+  /**\n+   * Group the set of current tservers by pool name. Tservers that don't match a regex are put into a default pool.\n+   *\n+   * @param current\n+   *          map of current tservers\n+   * @return current servers grouped by pool name, if not a match it is put into a default pool.\n+   */\n+  protected synchronized Map<String,SortedMap<TServerInstance,TabletServerStatus>> splitCurrentByRegex(SortedMap<TServerInstance,TabletServerStatus> current) {\n+    if ((System.currentTimeMillis() - lastPoolRecheck) > poolRecheckMillis) {\n+      LOG.debug(\"Performing pool recheck - regrouping tablet servers into pools based on regex\");\n+      Map<String,SortedMap<TServerInstance,TabletServerStatus>> newPools = new HashMap<String,SortedMap<TServerInstance,TabletServerStatus>>();\n+      for (Entry<TServerInstance,TabletServerStatus> e : current.entrySet()) {\n+        List<String> poolNames = getPoolNamesForHost(e.getKey().host());\n+        for (String pool : poolNames) {\n+          SortedMap<TServerInstance,TabletServerStatus> np = newPools.get(pool);\n+          if (null == np) {\n+            np = new TreeMap<TServerInstance,TabletServerStatus>(current.comparator());\n+            newPools.put(pool, np);\n+          }\n+          np.put(e.getKey(), e.getValue());\n+        }\n+      }\n+      pools = newPools;\n+      this.lastPoolRecheck = System.currentTimeMillis();\n+    }\n+    return pools;\n+  }\n+\n+  /**\n+   * Matches host against the regexes and returns the matching pool names\n+   *\n+   * @param host\n+   *          tablet server host\n+   * @return pool names, will return default pool if host matches more no regex\n+   */\n+  protected List<String> getPoolNamesForHost(String host) {\n+    String test = host;\n+    if (!isIpBasedRegex) {\n+      try {\n+        test = getNameFromIp(host);\n+      } catch (UnknownHostException e1) {\n+        LOG.error(\"Unable to determine host name for IP: \" + host + \", setting to default pool\", e1);\n+        return Collections.singletonList(DEFAULT_POOL);\n+      }\n+    }\n+    List<String> pools = new ArrayList<>();\n+    for (Entry<String,Pattern> e : poolNameToRegexPattern.entrySet()) {\n+      if (e.getValue().matcher(test).matches()) {\n+        pools.add(e.getKey());\n+      }\n+    }\n+    if (pools.size() == 0) {\n+      pools.add(DEFAULT_POOL);\n+    }\n+    return pools;\n+  }\n+\n+  protected String getNameFromIp(String hostIp) throws UnknownHostException {\n+    return InetAddress.getByName(hostIp).getHostName();\n+  }\n+\n+  /**\n+   * Matches table name against pool names, returns matching pool name or DEFAULT_POOL.\n+   *\n+   * @param tableName\n+   *          name of table\n+   * @return tablet server pool name (table name or DEFAULT_POOL)\n+   */\n+  protected String getPoolNameForTable(String tableName) {\n+    if (null == tableName) {\n+      return DEFAULT_POOL;\n+    }\n+    return poolNameToRegexPattern.containsKey(tableName) ? tableName : DEFAULT_POOL;\n+  }\n+\n+  /**\n+   * Parse configuration and extract properties\n+   *\n+   * @param conf\n+   *          server configuration\n+   */\n+  protected void parseConfiguration(ServerConfiguration conf) {\n+    tableIdToTableName = new HashMap<>();\n+    poolNameToRegexPattern = new HashMap<>();\n+    for (Entry<String,String> table : getTableOperations().tableIdMap().entrySet()) {\n+      tableIdToTableName.put(table.getValue(), table.getKey());\n+      Map<String,String> customProps = conf.getTableConfiguration(table.getValue()).getAllPropertiesWithPrefix(Property.TABLE_ARBITRARY_PROP_PREFIX);\n+      if (null != customProps && customProps.size() > 0) {\n+        for (Entry<String,String> customProp : customProps.entrySet()) {\n+          if (customProp.getKey().startsWith(HOST_BALANCER_PREFIX)) {\n+            String tableName = customProp.getKey().substring(HOST_BALANCER_PREFIX.length());\n+            String regex = customProp.getValue();\n+            poolNameToRegexPattern.put(tableName, Pattern.compile(regex));\n+          }\n+        }\n+      }\n+    }\n+    String oobProperty = conf.getConfiguration().get(HOST_BALANCER_OOB_CHECK);\n+    if (null != oobProperty) {\n+      oobCheckMillis = AccumuloConfiguration.getTimeInMillis(oobProperty);\n+    }\n+    String poolRecheckProperty = conf.getConfiguration().get(HOST_BALANCER_POOL_RECHECK_KEY);\n+    if (null != poolRecheckProperty) {\n+      poolRecheckMillis = AccumuloConfiguration.getTimeInMillis(poolRecheckProperty);\n+    }\n+    String ipBased = conf.getConfiguration().get(HOST_BALANCER_REGEX_USING_IPS);\n+    if (null != ipBased) {\n+      isIpBasedRegex = Boolean.parseBoolean(ipBased);\n+    }\n+  }\n+\n+  public Map<String,String> getTableIdToTableName() {\n+    return tableIdToTableName;\n+  }\n+\n+  public Map<String,Pattern> getPoolNameToRegexPattern() {\n+    return poolNameToRegexPattern;\n+  }\n+\n+  public long getOobCheckMillis() {\n+    return oobCheckMillis;\n+  }\n+\n+  public long getPoolRecheckMillis() {\n+    return poolRecheckMillis;\n+  }\n+\n+  public boolean isIpBasedRegex() {\n+    return isIpBasedRegex;\n+  }\n+\n+  @Override\n+  public void init(ServerConfiguration conf) {\n+    super.init(conf);\n+    parseConfiguration(conf);\n+  }\n+\n+  @Override\n+  public void getAssignments(SortedMap<TServerInstance,TabletServerStatus> current, Map<KeyExtent,TServerInstance> unassigned,\n+      Map<KeyExtent,TServerInstance> assignments) {\n+\n+    Map<String,SortedMap<TServerInstance,TabletServerStatus>> pools = splitCurrentByRegex(current);\n+    // group the unassigned into tables\n+    Map<String,Map<KeyExtent,TServerInstance>> groupedUnassigned = new HashMap<String,Map<KeyExtent,TServerInstance>>();\n+    for (Entry<KeyExtent,TServerInstance> e : unassigned.entrySet()) {\n+      Map<KeyExtent,TServerInstance> tableUnassigned = groupedUnassigned.get(e.getKey().getTableId());\n+      if (tableUnassigned == null) {\n+        tableUnassigned = new HashMap<KeyExtent,TServerInstance>();\n+        groupedUnassigned.put(e.getKey().getTableId(), tableUnassigned);\n+      }\n+      tableUnassigned.put(e.getKey(), e.getValue());\n+    }\n+    // Send a view of the current servers to the tables tablet balancer\n+    for (Entry<String,Map<KeyExtent,TServerInstance>> e : groupedUnassigned.entrySet()) {\n+      Map<KeyExtent,TServerInstance> newAssignments = new HashMap<KeyExtent,TServerInstance>();\n+      String tableName = tableIdToTableName.get(e.getKey());\n+      String poolName = getPoolNameForTable(tableName);\n+      SortedMap<TServerInstance,TabletServerStatus> currentView = pools.get(poolName);\n+      if (null == currentView || currentView.size() == 0) {\n+        LOG.warn(\"No tablet servers online for table {}, assigning within default pool\", tableName);\n+        currentView = pools.get(DEFAULT_POOL);\n+        if (null == currentView) {\n+          LOG.error(\"No tablet servers exist in the default pool, unable to assign tablets for table {}\", tableName);","path":"server/base/src/main/java/org/apache/accumulo/server/master/balancer/HostRegexTableLoadBalancer.java","position":245,"original_position":245,"commit_id":"9bef8b6c1ef488dcbd6cdcdca13c087e4b17ecb0","original_commit_id":"9bef8b6c1ef488dcbd6cdcdca13c087e4b17ecb0","user":{"login":"joshelser","id":67863,"avatar_url":"https://avatars.githubusercontent.com/u/67863?v=3","gravatar_id":"","url":"https://api.github.com/users/joshelser","html_url":"https://github.com/joshelser","followers_url":"https://api.github.com/users/joshelser/followers","following_url":"https://api.github.com/users/joshelser/following{/other_user}","gists_url":"https://api.github.com/users/joshelser/gists{/gist_id}","starred_url":"https://api.github.com/users/joshelser/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/joshelser/subscriptions","organizations_url":"https://api.github.com/users/joshelser/orgs","repos_url":"https://api.github.com/users/joshelser/repos","events_url":"https://api.github.com/users/joshelser/events{/privacy}","received_events_url":"https://api.github.com/users/joshelser/received_events","type":"User","site_admin":false},"body":"Findbugs caught a bug here. You're likely missing a `continue`?. When `null == currentView`, you'll fall through and call `keySet()` on it.","created_at":"2016-04-12T14:24:28Z","updated_at":"2016-04-12T14:24:28Z","html_url":"https://github.com/apache/accumulo/pull/83#discussion_r59384715","pull_request_url":"https://api.github.com/repos/apache/accumulo/pulls/83","_links":{"self":{"href":"https://api.github.com/repos/apache/accumulo/pulls/comments/59384715"},"html":{"href":"https://github.com/apache/accumulo/pull/83#discussion_r59384715"},"pull_request":{"href":"https://api.github.com/repos/apache/accumulo/pulls/83"}}},"pull_request":{"url":"https://api.github.com/repos/apache/accumulo/pulls/83","id":64476411,"html_url":"https://github.com/apache/accumulo/pull/83","diff_url":"https://github.com/apache/accumulo/pull/83.diff","patch_url":"https://github.com/apache/accumulo/pull/83.patch","issue_url":"https://api.github.com/repos/apache/accumulo/issues/83","number":83,"state":"open","locked":false,"title":"ACCUMULO-4173: Host Regex Table Load Balancer","user":{"login":"dlmarion","id":567911,"avatar_url":"https://avatars.githubusercontent.com/u/567911?v=3","gravatar_id":"","url":"https://api.github.com/users/dlmarion","html_url":"https://github.com/dlmarion","followers_url":"https://api.github.com/users/dlmarion/followers","following_url":"https://api.github.com/users/dlmarion/following{/other_user}","gists_url":"https://api.github.com/users/dlmarion/gists{/gist_id}","starred_url":"https://api.github.com/users/dlmarion/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dlmarion/subscriptions","organizations_url":"https://api.github.com/users/dlmarion/orgs","repos_url":"https://api.github.com/users/dlmarion/repos","events_url":"https://api.github.com/users/dlmarion/events{/privacy}","received_events_url":"https://api.github.com/users/dlmarion/received_events","type":"User","site_admin":false},"body":"A table load balancer that passes a subset of the tserver hosts to the configured tablet balancer for a table. Tservers that do not match any regex are part of a default pool. Tables with configured regex (or those that are in error) are balanced within the default pool of tservers.","created_at":"2016-03-29T14:40:41Z","updated_at":"2016-04-12T14:24:28Z","closed_at":null,"merged_at":null,"merge_commit_sha":"9186a1437ee4799afbf56375d57c0b9ba6f1e96e","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/apache/accumulo/pulls/83/commits","review_comments_url":"https://api.github.com/repos/apache/accumulo/pulls/83/comments","review_comment_url":"https://api.github.com/repos/apache/accumulo/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/accumulo/issues/83/comments","statuses_url":"https://api.github.com/repos/apache/accumulo/statuses/9bef8b6c1ef488dcbd6cdcdca13c087e4b17ecb0","head":{"label":"apache:ACCUMULO-4173","ref":"ACCUMULO-4173","sha":"9bef8b6c1ef488dcbd6cdcdca13c087e4b17ecb0","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":2524488,"name":"accumulo","full_name":"apache/accumulo","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/accumulo","description":"Mirror of Apache Accumulo","fork":false,"url":"https://api.github.com/repos/apache/accumulo","forks_url":"https://api.github.com/repos/apache/accumulo/forks","keys_url":"https://api.github.com/repos/apache/accumulo/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/accumulo/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/accumulo/teams","hooks_url":"https://api.github.com/repos/apache/accumulo/hooks","issue_events_url":"https://api.github.com/repos/apache/accumulo/issues/events{/number}","events_url":"https://api.github.com/repos/apache/accumulo/events","assignees_url":"https://api.github.com/repos/apache/accumulo/assignees{/user}","branches_url":"https://api.github.com/repos/apache/accumulo/branches{/branch}","tags_url":"https://api.github.com/repos/apache/accumulo/tags","blobs_url":"https://api.github.com/repos/apache/accumulo/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/accumulo/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/accumulo/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/accumulo/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/accumulo/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/accumulo/languages","stargazers_url":"https://api.github.com/repos/apache/accumulo/stargazers","contributors_url":"https://api.github.com/repos/apache/accumulo/contributors","subscribers_url":"https://api.github.com/repos/apache/accumulo/subscribers","subscription_url":"https://api.github.com/repos/apache/accumulo/subscription","commits_url":"https://api.github.com/repos/apache/accumulo/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/accumulo/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/accumulo/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/accumulo/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/accumulo/contents/{+path}","compare_url":"https://api.github.com/repos/apache/accumulo/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/accumulo/merges","archive_url":"https://api.github.com/repos/apache/accumulo/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/accumulo/downloads","issues_url":"https://api.github.com/repos/apache/accumulo/issues{/number}","pulls_url":"https://api.github.com/repos/apache/accumulo/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/accumulo/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/accumulo/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/accumulo/labels{/name}","releases_url":"https://api.github.com/repos/apache/accumulo/releases{/id}","deployments_url":"https://api.github.com/repos/apache/accumulo/deployments","created_at":"2011-10-06T07:00:09Z","updated_at":"2016-04-03T21:53:59Z","pushed_at":"2016-04-12T13:58:31Z","git_url":"git://github.com/apache/accumulo.git","ssh_url":"git@github.com:apache/accumulo.git","clone_url":"https://github.com/apache/accumulo.git","svn_url":"https://github.com/apache/accumulo","homepage":"","size":64000,"stargazers_count":214,"watchers_count":214,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":117,"mirror_url":"git://git.apache.org/accumulo.git","open_issues_count":3,"forks":117,"open_issues":3,"watchers":214,"default_branch":"master"}},"base":{"label":"apache:master","ref":"master","sha":"25b99c258be3768d144338548d1f14aeed4b8767","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":2524488,"name":"accumulo","full_name":"apache/accumulo","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/accumulo","description":"Mirror of Apache Accumulo","fork":false,"url":"https://api.github.com/repos/apache/accumulo","forks_url":"https://api.github.com/repos/apache/accumulo/forks","keys_url":"https://api.github.com/repos/apache/accumulo/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/accumulo/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/accumulo/teams","hooks_url":"https://api.github.com/repos/apache/accumulo/hooks","issue_events_url":"https://api.github.com/repos/apache/accumulo/issues/events{/number}","events_url":"https://api.github.com/repos/apache/accumulo/events","assignees_url":"https://api.github.com/repos/apache/accumulo/assignees{/user}","branches_url":"https://api.github.com/repos/apache/accumulo/branches{/branch}","tags_url":"https://api.github.com/repos/apache/accumulo/tags","blobs_url":"https://api.github.com/repos/apache/accumulo/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/accumulo/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/accumulo/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/accumulo/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/accumulo/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/accumulo/languages","stargazers_url":"https://api.github.com/repos/apache/accumulo/stargazers","contributors_url":"https://api.github.com/repos/apache/accumulo/contributors","subscribers_url":"https://api.github.com/repos/apache/accumulo/subscribers","subscription_url":"https://api.github.com/repos/apache/accumulo/subscription","commits_url":"https://api.github.com/repos/apache/accumulo/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/accumulo/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/accumulo/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/accumulo/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/accumulo/contents/{+path}","compare_url":"https://api.github.com/repos/apache/accumulo/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/accumulo/merges","archive_url":"https://api.github.com/repos/apache/accumulo/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/accumulo/downloads","issues_url":"https://api.github.com/repos/apache/accumulo/issues{/number}","pulls_url":"https://api.github.com/repos/apache/accumulo/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/accumulo/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/accumulo/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/accumulo/labels{/name}","releases_url":"https://api.github.com/repos/apache/accumulo/releases{/id}","deployments_url":"https://api.github.com/repos/apache/accumulo/deployments","created_at":"2011-10-06T07:00:09Z","updated_at":"2016-04-03T21:53:59Z","pushed_at":"2016-04-12T13:58:31Z","git_url":"git://github.com/apache/accumulo.git","ssh_url":"git@github.com:apache/accumulo.git","clone_url":"https://github.com/apache/accumulo.git","svn_url":"https://github.com/apache/accumulo","homepage":"","size":64000,"stargazers_count":214,"watchers_count":214,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":117,"mirror_url":"git://git.apache.org/accumulo.git","open_issues_count":3,"forks":117,"open_issues":3,"watchers":214,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/accumulo/pulls/83"},"html":{"href":"https://github.com/apache/accumulo/pull/83"},"issue":{"href":"https://api.github.com/repos/apache/accumulo/issues/83"},"comments":{"href":"https://api.github.com/repos/apache/accumulo/issues/83/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/accumulo/pulls/83/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/accumulo/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/accumulo/pulls/83/commits"},"statuses":{"href":"https://api.github.com/repos/apache/accumulo/statuses/9bef8b6c1ef488dcbd6cdcdca13c087e4b17ecb0"}}}}