{"action":"created","comment":{"url":"https://api.github.com/repos/apache/accumulo/pulls/comments/174579228","pull_request_review_id":103961648,"id":174579228,"diff_hunk":"@@ -0,0 +1,356 @@\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.fate.util;\n+\n+import static java.util.concurrent.TimeUnit.MILLISECONDS;\n+import static java.util.concurrent.TimeUnit.NANOSECONDS;\n+\n+import java.util.concurrent.TimeUnit;\n+\n+import org.slf4j.Logger;\n+import org.slf4j.LoggerFactory;\n+\n+import com.google.common.annotations.VisibleForTesting;\n+import com.google.common.base.Preconditions;\n+\n+/**\n+ * Encapsulates the retrying implementation for some operation. Provides bounded retry attempts with a bounded, linear backoff.\n+ */\n+public class Retry {\n+  private static final Logger log = LoggerFactory.getLogger(Retry.class);\n+\n+  private long maxRetries; // not final for testing\n+  private long waitIncrement; // not final for testing\n+  private long maxWait; // not final for testing\n+  private final long logIntervalNanoSec;\n+\n+  private long retriesDone;\n+  private long currentWait;\n+\n+  private boolean hasNeverLogged;\n+  private long lastRetryLog;\n+\n+  /**\n+   * @param maxRetries\n+   *          Maximum times to retry or MAX_RETRY_DISABLED if no maximum\n+   * @param startWait\n+   *          The amount of time (ms) to wait for the initial retry\n+   * @param maxWait\n+   *          The maximum wait (ms)\n+   * @param waitIncrement\n+   *          The amount of time (ms) to increment next wait time by\n+   * @param logInterval\n+   *          The amount of time (ms) between logging retries\n+   */\n+  private Retry(long maxRetries, long startWait, long waitIncrement, long maxWait, long logInterval) {\n+    this.maxRetries = maxRetries;\n+    this.maxWait = maxWait;\n+    this.waitIncrement = waitIncrement;\n+    this.retriesDone = 0;\n+    this.currentWait = startWait;\n+    this.logIntervalNanoSec = MILLISECONDS.toNanos(logInterval);\n+    this.hasNeverLogged = true;\n+    this.lastRetryLog = -1;\n+  }\n+\n+  // Visible for testing\n+  @VisibleForTesting\n+  long getMaxRetries() {\n+    return maxRetries;\n+  }\n+\n+  // Visible for testing\n+  @VisibleForTesting\n+  long getCurrentWait() {\n+    return currentWait;\n+  }\n+\n+  // Visible for testing\n+  @VisibleForTesting\n+  long getWaitIncrement() {\n+    return waitIncrement;\n+  }\n+\n+  // Visible for testing\n+  @VisibleForTesting\n+  long getMaxWait() {\n+    return maxWait;\n+  }\n+\n+  // Visible for testing\n+  @VisibleForTesting\n+  void setMaxRetries(long maxRetries) {\n+    this.maxRetries = maxRetries;\n+  }\n+\n+  // Visible for testing\n+  @VisibleForTesting\n+  void setStartWait(long startWait) {\n+    this.currentWait = startWait;\n+  }\n+\n+  // Visible for testing\n+  @VisibleForTesting\n+  void setWaitIncrement(long waitIncrement) {\n+    this.waitIncrement = waitIncrement;\n+  }\n+\n+  // Visible for testing\n+  @VisibleForTesting\n+  void setMaxWait(long maxWait) {\n+    this.maxWait = maxWait;\n+  }\n+\n+  public boolean hasInfiniteRetries() {\n+    return maxRetries < 0;\n+  }\n+\n+  public long getLogInterval() {\n+    return NANOSECONDS.toMillis(logIntervalNanoSec);\n+  }\n+\n+  public boolean canRetry() {\n+    return hasInfiniteRetries() || (retriesDone < maxRetries);\n+  }\n+\n+  public void useRetry() {\n+    if (!canRetry()) {\n+      throw new IllegalStateException(\"No retries left\");\n+    }\n+\n+    retriesDone++;\n+  }\n+\n+  public boolean hasRetried() {\n+    return retriesDone > 0;\n+  }\n+\n+  public long retriesCompleted() {\n+    return retriesDone;\n+  }\n+\n+  public void waitForNextAttempt() throws InterruptedException {\n+    log.debug(\"Sleeping for {}ms before retrying operation\", currentWait);\n+    sleep(currentWait);\n+    currentWait = Math.min(maxWait, currentWait + waitIncrement);\n+  }\n+\n+  protected void sleep(long wait) throws InterruptedException {\n+    Thread.sleep(wait);\n+  }\n+\n+  public void logRetry(Logger log, String message, Throwable t) {\n+    // log the first time as debug, and then after every logInterval as a warning\n+    long now = System.nanoTime();\n+    if (lastRetryLog < 0) {\n+      if (log.isDebugEnabled()) {\n+        log.debug(getMessage(message, t));\n+      }\n+      lastRetryLog = now;\n+    } else if ((now - lastRetryLog) > logIntervalNanoSec) {\n+      log.warn(getMessage(message), t);\n+      lastRetryLog = now;\n+    } else {\n+      if (log.isTraceEnabled()) {\n+        log.trace(getMessage(message, t));\n+      }\n+    }\n+  }\n+\n+  public void logRetry(Logger log, String message) {\n+    // log the first time as debug, and then after every logInterval as a warning\n+    long now = System.nanoTime();\n+    if (hasNeverLogged) {\n+      if (log.isDebugEnabled()) {\n+        log.debug(getMessage(message));\n+      }\n+      hasNeverLogged = false;\n+      lastRetryLog = now;\n+    } else if ((now - lastRetryLog) > logIntervalNanoSec) {\n+      log.warn(getMessage(message));\n+      lastRetryLog = now;\n+    } else {\n+      if (log.isTraceEnabled()) {\n+        log.trace(getMessage(message));\n+      }\n+    }\n+  }\n+\n+  private String getMessage(String message) {\n+    return message + \", retrying attempt \" + (retriesDone + 1) + \" (suppressing retry messages for \" + getLogInterval() + \"ms)\";\n+  }\n+\n+  private String getMessage(String message, Throwable t) {\n+    return message + \":\" + t + \", retrying attempt \" + (retriesDone + 1) + \" (suppressing retry messages for \" + getLogInterval() + \"ms)\";\n+  }\n+\n+  public interface NeedsRetries {\n+    /**\n+     * @return this builder with the maximum number of retries set to unlimited\n+     */\n+    NeedsRetryDelay infiniteRetries();\n+\n+    /**\n+     * @param max\n+     *          the maximum number of retries to set\n+     * @return this builder with the maximum number of retries set to the provided value\n+     */\n+    NeedsRetryDelay maxRetries(long max);\n+  }\n+\n+  public interface NeedsRetryDelay {\n+    /**\n+     * @param duration\n+     *          the amount of time to wait before the first retry; input is converted to milliseconds, rounded down to the nearest\n+     * @return this builder with the initial wait period set\n+     */\n+    NeedsTimeIncrement retryAfter(long duration, TimeUnit unit);\n+  }\n+\n+  public interface NeedsTimeIncrement {\n+    /**\n+     * @param duration\n+     *          the amount of additional time to add before each subsequent retry; input is converted to milliseconds, rounded down to the nearest\n+     * @return this builder with the increment amount set\n+     */\n+    NeedsMaxWait incrementBy(long duration, TimeUnit unit);\n+  }\n+\n+  public interface NeedsMaxWait {\n+    /**\n+     * @param duration\n+     *          the maximum amount of time to which the waiting period between retries can be incremented; input is converted to milliseconds, rounded down to\n+     *          the nearest\n+     * @return this builder with a maximum time limit set\n+     */\n+    NeedsLogInterval maxWait(long duration, TimeUnit unit);\n+  }\n+\n+  public interface NeedsLogInterval {\n+    /**\n+     * @param duration\n+     *          the minimum time interval between logging that a retry is occurring; input is converted to milliseconds, rounded down to the nearest\n+     * @return this builder with a logging interval set\n+     */\n+    BuilderDone logInterval(long duration, TimeUnit unit);\n+  }\n+\n+  public interface BuilderDone {\n+    /**\n+     * Create a RetryFactory from this builder which can be used to create many Retry objects with the same settings.\n+     *\n+     * @return this builder as a factory; intermediate references to this builder cannot be used to change options after this has been called\n+     */\n+    RetryFactory createFactory();\n+\n+    /**\n+     * Create a single Retry object with the currently configured builder settings.\n+     *\n+     * @return a retry object from this builder's settings\n+     */\n+    Retry createRetry();\n+  }\n+\n+  public interface RetryFactory {\n+    /**\n+     * Create a single Retry object from this factory's settings.\n+     *\n+     * @return a retry object from this factory's settings\n+     */\n+    Retry createRetry();\n+  }\n+\n+  public static NeedsRetries builder() {\n+    return new RetryFactoryBuilder();\n+  }\n+\n+  private static class RetryFactoryBuilder implements NeedsRetries, NeedsRetryDelay, NeedsTimeIncrement, NeedsMaxWait, NeedsLogInterval, BuilderDone,\n+      RetryFactory {\n+\n+    private boolean modifiable = true;\n+    private long maxRetries;\n+    private long initialWait;\n+    private long maxWait;\n+    private long waitIncrement;\n+    private long logInterval;\n+\n+    RetryFactoryBuilder() {}\n+\n+    private void checkState() {\n+      Preconditions.checkState(modifiable, \"Cannot modify this builder once 'createFactory()' has been called\");\n+    }\n+\n+    @Override\n+    public NeedsRetryDelay infiniteRetries() {\n+      checkState();\n+      this.maxRetries = -1;\n+      return this;\n+    }\n+\n+    @Override\n+    public NeedsRetryDelay maxRetries(long max) {\n+      checkState();\n+      Preconditions.checkArgument(max >= 0, \"Maximum number of retries must not be negative\");\n+      this.maxRetries = max;\n+      return this;\n+    }\n+\n+    @Override\n+    public NeedsTimeIncrement retryAfter(long duration, TimeUnit unit) {\n+      checkState();\n+      this.initialWait = unit.toMillis(duration);\n+      Preconditions.checkArgument(initialWait >= 0, \"Initial waiting period must not be negative\");\n+      return this;\n+    }\n+\n+    @Override\n+    public NeedsMaxWait incrementBy(long duration, TimeUnit unit) {\n+      checkState();\n+      this.waitIncrement = unit.toMillis(duration);\n+      Preconditions.checkArgument(waitIncrement >= 0, \"Amount of time to increment the wait between each retry must not be negative\");\n+      return this;\n+    }\n+\n+    @Override\n+    public NeedsLogInterval maxWait(long duration, TimeUnit unit) {\n+      checkState();\n+      this.maxWait = unit.toMillis(duration);\n+      Preconditions.checkArgument(maxWait >= initialWait, \"Maximum wait between retries must not be less than the initial delay\");\n+      return this;\n+    }\n+\n+    @Override\n+    public BuilderDone logInterval(long duration, TimeUnit unit) {\n+      checkState();\n+      this.logInterval = unit.toMillis(duration);\n+      Preconditions.checkArgument(logInterval >= 0, \"The amount of time between logging retries must not be negative\");\n+      return this;\n+    }\n+\n+    @Override\n+    public RetryFactory createFactory() {\n+      this.modifiable = false;\n+      return this;\n+    }\n+\n+    @Override\n+    public Retry createRetry() {\n+      return new Retry(maxRetries, initialWait, waitIncrement, maxWait, logInterval);","path":"fate/src/main/java/org/apache/accumulo/fate/util/Retry.java","position":352,"original_position":352,"commit_id":"a1528ef34b688c6e83a56b9eb3190aff65db35a7","original_commit_id":"a1528ef34b688c6e83a56b9eb3190aff65db35a7","user":{"login":"ctubbsii","id":1280725,"avatar_url":"https://avatars3.githubusercontent.com/u/1280725?v=4","gravatar_id":"","url":"https://api.github.com/users/ctubbsii","html_url":"https://github.com/ctubbsii","followers_url":"https://api.github.com/users/ctubbsii/followers","following_url":"https://api.github.com/users/ctubbsii/following{/other_user}","gists_url":"https://api.github.com/users/ctubbsii/gists{/gist_id}","starred_url":"https://api.github.com/users/ctubbsii/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ctubbsii/subscriptions","organizations_url":"https://api.github.com/users/ctubbsii/orgs","repos_url":"https://api.github.com/users/ctubbsii/repos","events_url":"https://api.github.com/users/ctubbsii/events{/privacy}","received_events_url":"https://api.github.com/users/ctubbsii/received_events","type":"User","site_admin":false},"body":"It does.","created_at":"2018-03-14T19:11:09Z","updated_at":"2018-03-14T19:11:09Z","html_url":"https://github.com/apache/accumulo/pull/399#discussion_r174579228","pull_request_url":"https://api.github.com/repos/apache/accumulo/pulls/399","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/apache/accumulo/pulls/comments/174579228"},"html":{"href":"https://github.com/apache/accumulo/pull/399#discussion_r174579228"},"pull_request":{"href":"https://api.github.com/repos/apache/accumulo/pulls/399"}},"in_reply_to_id":174567481},"pull_request":{"url":"https://api.github.com/repos/apache/accumulo/pulls/399","id":175024476,"html_url":"https://github.com/apache/accumulo/pull/399","diff_url":"https://github.com/apache/accumulo/pull/399.diff","patch_url":"https://github.com/apache/accumulo/pull/399.patch","issue_url":"https://api.github.com/repos/apache/accumulo/issues/399","number":399,"state":"open","locked":false,"title":"ACCUMULO-4847 Fix Retry utility's API","user":{"login":"ctubbsii","id":1280725,"avatar_url":"https://avatars3.githubusercontent.com/u/1280725?v=4","gravatar_id":"","url":"https://api.github.com/users/ctubbsii","html_url":"https://github.com/ctubbsii","followers_url":"https://api.github.com/users/ctubbsii/followers","following_url":"https://api.github.com/users/ctubbsii/following{/other_user}","gists_url":"https://api.github.com/users/ctubbsii/gists{/gist_id}","starred_url":"https://api.github.com/users/ctubbsii/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ctubbsii/subscriptions","organizations_url":"https://api.github.com/users/ctubbsii/orgs","repos_url":"https://api.github.com/users/ctubbsii/repos","events_url":"https://api.github.com/users/ctubbsii/events{/privacy}","received_events_url":"https://api.github.com/users/ctubbsii/received_events","type":"User","site_admin":false},"body":"Create a builder API for Retry and RetryFactory, so that the parameters\r\n(which all have the same type) cannot be easily confused for one another\r\nand cause \"sleep-until-heat-death-of-the-universe\" bugs.\r\n\r\nAlso fix a minor bug which is caused by the assumption that nanoTime is\r\nalways positive. It is normal for nanoTime to be negative, only the\r\ndifferences between two times is guaranteed to be positive.","created_at":"2018-03-14T17:08:19Z","updated_at":"2018-03-14T19:11:09Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5379f52ea02f2ffdfcfe142947f17cd0dbfa49ce","assignee":{"login":"ctubbsii","id":1280725,"avatar_url":"https://avatars3.githubusercontent.com/u/1280725?v=4","gravatar_id":"","url":"https://api.github.com/users/ctubbsii","html_url":"https://github.com/ctubbsii","followers_url":"https://api.github.com/users/ctubbsii/followers","following_url":"https://api.github.com/users/ctubbsii/following{/other_user}","gists_url":"https://api.github.com/users/ctubbsii/gists{/gist_id}","starred_url":"https://api.github.com/users/ctubbsii/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ctubbsii/subscriptions","organizations_url":"https://api.github.com/users/ctubbsii/orgs","repos_url":"https://api.github.com/users/ctubbsii/repos","events_url":"https://api.github.com/users/ctubbsii/events{/privacy}","received_events_url":"https://api.github.com/users/ctubbsii/received_events","type":"User","site_admin":false},"assignees":[{"login":"ctubbsii","id":1280725,"avatar_url":"https://avatars3.githubusercontent.com/u/1280725?v=4","gravatar_id":"","url":"https://api.github.com/users/ctubbsii","html_url":"https://github.com/ctubbsii","followers_url":"https://api.github.com/users/ctubbsii/followers","following_url":"https://api.github.com/users/ctubbsii/following{/other_user}","gists_url":"https://api.github.com/users/ctubbsii/gists{/gist_id}","starred_url":"https://api.github.com/users/ctubbsii/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ctubbsii/subscriptions","organizations_url":"https://api.github.com/users/ctubbsii/orgs","repos_url":"https://api.github.com/users/ctubbsii/repos","events_url":"https://api.github.com/users/ctubbsii/events{/privacy}","received_events_url":"https://api.github.com/users/ctubbsii/received_events","type":"User","site_admin":false}],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/apache/accumulo/pulls/399/commits","review_comments_url":"https://api.github.com/repos/apache/accumulo/pulls/399/comments","review_comment_url":"https://api.github.com/repos/apache/accumulo/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/accumulo/issues/399/comments","statuses_url":"https://api.github.com/repos/apache/accumulo/statuses/a1528ef34b688c6e83a56b9eb3190aff65db35a7","head":{"label":"ctubbsii:1.7-retry-fixes-stuck-locator","ref":"1.7-retry-fixes-stuck-locator","sha":"a1528ef34b688c6e83a56b9eb3190aff65db35a7","user":{"login":"ctubbsii","id":1280725,"avatar_url":"https://avatars3.githubusercontent.com/u/1280725?v=4","gravatar_id":"","url":"https://api.github.com/users/ctubbsii","html_url":"https://github.com/ctubbsii","followers_url":"https://api.github.com/users/ctubbsii/followers","following_url":"https://api.github.com/users/ctubbsii/following{/other_user}","gists_url":"https://api.github.com/users/ctubbsii/gists{/gist_id}","starred_url":"https://api.github.com/users/ctubbsii/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ctubbsii/subscriptions","organizations_url":"https://api.github.com/users/ctubbsii/orgs","repos_url":"https://api.github.com/users/ctubbsii/repos","events_url":"https://api.github.com/users/ctubbsii/events{/privacy}","received_events_url":"https://api.github.com/users/ctubbsii/received_events","type":"User","site_admin":false},"repo":{"id":9703694,"name":"accumulo","full_name":"ctubbsii/accumulo","owner":{"login":"ctubbsii","id":1280725,"avatar_url":"https://avatars3.githubusercontent.com/u/1280725?v=4","gravatar_id":"","url":"https://api.github.com/users/ctubbsii","html_url":"https://github.com/ctubbsii","followers_url":"https://api.github.com/users/ctubbsii/followers","following_url":"https://api.github.com/users/ctubbsii/following{/other_user}","gists_url":"https://api.github.com/users/ctubbsii/gists{/gist_id}","starred_url":"https://api.github.com/users/ctubbsii/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ctubbsii/subscriptions","organizations_url":"https://api.github.com/users/ctubbsii/orgs","repos_url":"https://api.github.com/users/ctubbsii/repos","events_url":"https://api.github.com/users/ctubbsii/events{/privacy}","received_events_url":"https://api.github.com/users/ctubbsii/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/ctubbsii/accumulo","description":"Mirror of Apache Accumulo","fork":true,"url":"https://api.github.com/repos/ctubbsii/accumulo","forks_url":"https://api.github.com/repos/ctubbsii/accumulo/forks","keys_url":"https://api.github.com/repos/ctubbsii/accumulo/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ctubbsii/accumulo/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ctubbsii/accumulo/teams","hooks_url":"https://api.github.com/repos/ctubbsii/accumulo/hooks","issue_events_url":"https://api.github.com/repos/ctubbsii/accumulo/issues/events{/number}","events_url":"https://api.github.com/repos/ctubbsii/accumulo/events","assignees_url":"https://api.github.com/repos/ctubbsii/accumulo/assignees{/user}","branches_url":"https://api.github.com/repos/ctubbsii/accumulo/branches{/branch}","tags_url":"https://api.github.com/repos/ctubbsii/accumulo/tags","blobs_url":"https://api.github.com/repos/ctubbsii/accumulo/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ctubbsii/accumulo/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ctubbsii/accumulo/git/refs{/sha}","trees_url":"https://api.github.com/repos/ctubbsii/accumulo/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ctubbsii/accumulo/statuses/{sha}","languages_url":"https://api.github.com/repos/ctubbsii/accumulo/languages","stargazers_url":"https://api.github.com/repos/ctubbsii/accumulo/stargazers","contributors_url":"https://api.github.com/repos/ctubbsii/accumulo/contributors","subscribers_url":"https://api.github.com/repos/ctubbsii/accumulo/subscribers","subscription_url":"https://api.github.com/repos/ctubbsii/accumulo/subscription","commits_url":"https://api.github.com/repos/ctubbsii/accumulo/commits{/sha}","git_commits_url":"https://api.github.com/repos/ctubbsii/accumulo/git/commits{/sha}","comments_url":"https://api.github.com/repos/ctubbsii/accumulo/comments{/number}","issue_comment_url":"https://api.github.com/repos/ctubbsii/accumulo/issues/comments{/number}","contents_url":"https://api.github.com/repos/ctubbsii/accumulo/contents/{+path}","compare_url":"https://api.github.com/repos/ctubbsii/accumulo/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ctubbsii/accumulo/merges","archive_url":"https://api.github.com/repos/ctubbsii/accumulo/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ctubbsii/accumulo/downloads","issues_url":"https://api.github.com/repos/ctubbsii/accumulo/issues{/number}","pulls_url":"https://api.github.com/repos/ctubbsii/accumulo/pulls{/number}","milestones_url":"https://api.github.com/repos/ctubbsii/accumulo/milestones{/number}","notifications_url":"https://api.github.com/repos/ctubbsii/accumulo/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ctubbsii/accumulo/labels{/name}","releases_url":"https://api.github.com/repos/ctubbsii/accumulo/releases{/id}","deployments_url":"https://api.github.com/repos/ctubbsii/accumulo/deployments","created_at":"2013-04-26T20:31:50Z","updated_at":"2017-07-11T19:04:13Z","pushed_at":"2018-03-14T17:11:04Z","git_url":"git://github.com/ctubbsii/accumulo.git","ssh_url":"git@github.com:ctubbsii/accumulo.git","clone_url":"https://github.com/ctubbsii/accumulo.git","svn_url":"https://github.com/ctubbsii/accumulo","homepage":"https://accumulo.apache.org","size":56363,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0"},"forks":1,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"apache:1.7","ref":"1.7","sha":"68f70d5d557ad9ceec8acfb509906dbc19a0cf15","user":{"login":"apache","id":47359,"avatar_url":"https://avatars0.githubusercontent.com/u/47359?v=4","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://avatars0.githubusercontent.com/u/47359?v=4","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":"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":"2018-03-11T06:32:06Z","pushed_at":"2018-03-14T17:11:05Z","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":"https://accumulo.apache.org","size":59095,"stargazers_count":355,"watchers_count":355,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":197,"mirror_url":null,"archived":false,"open_issues_count":10,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0"},"forks":197,"open_issues":10,"watchers":355,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/accumulo/pulls/399"},"html":{"href":"https://github.com/apache/accumulo/pull/399"},"issue":{"href":"https://api.github.com/repos/apache/accumulo/issues/399"},"comments":{"href":"https://api.github.com/repos/apache/accumulo/issues/399/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/accumulo/pulls/399/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/accumulo/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/accumulo/pulls/399/commits"},"statuses":{"href":"https://api.github.com/repos/apache/accumulo/statuses/a1528ef34b688c6e83a56b9eb3190aff65db35a7"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"ctubbsii"}}