{"action":"created","comment":{"url":"https://api.github.com/repos/joey/flume/pulls/comments/23477054","id":23477054,"diff_hunk":"@@ -285,94 +310,222 @@ public Status process() throws EventDeliveryException {\n       if (transaction != null) {\n         try {\n           transaction.rollback();\n+          transaction.close();\n         } catch (Exception ex) {\n-          LOG.error(\"Transaction rollback failed\", ex);\n-          throw Throwables.propagate(ex);\n+          LOG.error(\"Transaction rollback failed: \" + ex.getLocalizedMessage());\n+          LOG.debug(\"Exception follows.\", ex);\n+          // We don't propogate the exception as the original throwable will\n+          // be propogated later.\n+        } finally {\n+          transaction = null;\n         }\n       }\n \n-      // close the writer and remove the its reference\n-      writer.close();\n-      this.writer = null;\n-      this.lastRolledMs = System.currentTimeMillis();\n+      // We don't want to close the writer because that will persist data \n+      // that will be replayed. This will avoid duplicate data.\n+      // This is also no different the the no-op close the writer does if\n+      // it's already in the ERROR state.\n+      try {\n+        rollWriter(false, true);\n+      } catch (EventDeliveryException ex) {\n+        LOG.warn(\"Rolling the writer failed, will retry: \"\n+            + ex.getLocalizedMessage());\n+        LOG.debug(\"Exception follows.\", ex);\n+        // We don't propogate the exception as the original throwable will\n+        // be propogated later.\n+      }\n \n       // handle the exception\n       Throwables.propagateIfInstanceOf(th, Error.class);\n       Throwables.propagateIfInstanceOf(th, EventDeliveryException.class);\n       throw new EventDeliveryException(th);\n-\n-    } finally {\n-      if (transaction != null) {\n-        transaction.close();\n-      }\n     }\n   }\n \n-  private DatasetWriter<GenericRecord> newWriter(\n-    final UserGroupInformation login, final URI uri) {\n-    View<GenericRecord> view = KerberosUtil.runPrivileged(login,\n-      new PrivilegedExceptionAction<Dataset<GenericRecord>>() {\n-        @Override\n-        public Dataset<GenericRecord> run() {\n-          return Datasets.load(uri);\n-        }\n-      });\n-\n-    DatasetDescriptor descriptor = view.getDataset().getDescriptor();\n-    String formatName = descriptor.getFormat().getName();\n-    Preconditions.checkArgument(allowedFormats().contains(formatName),\n-      \"Unsupported format: \" + formatName);\n-\n-    Schema newSchema = descriptor.getSchema();\n-    if (targetSchema == null || !newSchema.equals(targetSchema)) {\n-      this.targetSchema = descriptor.getSchema();\n-      // target dataset schema has changed, invalidate all readers based on it\n-      readers.invalidateAll();\n+  /**\n+   * Parse the event using the entity parser and write the entity to the dataset.\n+   * \n+   * @param event The event to write\n+   * @throws EventDeliveryException An error occurred trying to write to the\n+                                dataset that couldn't or shouldn't be\n+                                handled by the failure newPolicy.\n+   */\n+  @VisibleForTesting\n+  void write(Event event) throws EventDeliveryException {\n+    try {\n+      entity = parser.parse(event, reuseEntity ? entity : null);\n+      bytesParsed += event.getBody().length;\n+\n+      // writeEncoded would be an optimization in some cases, but HBase\n+      // will not support it and partitioned Datasets need to get partition\n+      // info from the entity Object. We may be able to avoid the\n+      // serialization round-trip otherwise.\n+      writer.write(entity);\n+    } catch (NonRecoverableEventException ex) {\n+      policy.handle(event, ex);\n+    } catch (DataFileWriter.AppendWriteException ex) {\n+      policy.handle(event, ex);\n+    } catch (RuntimeException ex) {\n+      Throwables.propagateIfInstanceOf(ex, EventDeliveryException.class);\n+      throw new EventDeliveryException(ex);\n     }\n-\n-    this.reuseDatum = !(\"parquet\".equals(formatName));\n-    this.datasetName = view.getDataset().getName();\n-\n-    return view.newWriter();\n   }\n \n   /**\n-   * Not thread-safe.\n-   *\n-   * @param event\n-   * @param reuse\n-   * @return\n+   * Create a new writer.\n+   * \n+   * This method also re-loads the dataset so updates to the configuration or\n+   * a dataset created after Flume starts will be loaded.\n+   * \n+   * @return The dataset writer\n+   * @throws EventDeliveryException There was an error creating the writer.\n    */\n-  private GenericRecord deserialize(Event event, GenericRecord reuse)\n+  private DatasetWriter<GenericRecord> newWriter()\n       throws EventDeliveryException {\n-    decoder = DecoderFactory.get().binaryDecoder(event.getBody(), decoder);\n-    // no checked exception is thrown in the CacheLoader\n-    DatumReader<GenericRecord> reader = readers.getUnchecked(schema(event));\n     try {\n-      return reader.read(reuse, decoder);\n-    } catch (IOException ex) {\n-      throw new EventDeliveryException(\"Cannot deserialize event\", ex);\n+      View<GenericRecord> view = KerberosUtil.runPrivileged(login,\n+          new PrivilegedExceptionAction<Dataset<GenericRecord>>() {\n+            @Override\n+            public Dataset<GenericRecord> run() {\n+              return Datasets.load(datasetUri);\n+            }\n+          });\n+\n+      DatasetDescriptor descriptor = view.getDataset().getDescriptor();\n+      String formatName = descriptor.getFormat().getName();\n+      Preconditions.checkArgument(allowedFormats().contains(formatName),\n+          \"Unsupported format: \" + formatName);\n+\n+      Schema newSchema = descriptor.getSchema();\n+      if (datasetSchema == null || !newSchema.equals(datasetSchema)) {\n+        this.datasetSchema = descriptor.getSchema();\n+        // dataset schema has changed, create a new parser\n+        parser = parserFactory.newParser(datasetSchema, context);\n+      }\n+\n+      this.reuseEntity = !(\"parquet\".equals(formatName));\n+      // Commit on batch if kite.commitOnBatch is true and the format isn't\n+      // parquet\n+      this.commitOnBatch = context.getBoolean(CONFIG_COMMIT_ON_BATCH,\n+          DEFAULT_COMMIT_ON_BATCH) && !(\"parquet\".equals(formatName));\n+      this.datasetName = view.getDataset().getName();\n+\n+      return view.newWriter();\n+    } catch (DatasetNotFoundException ex) {\n+      throw new EventDeliveryException(\"Dataset \" + datasetUri + \" not found.\"\n+          + \" The dataset must be created before Flume can write to it.\", ex);\n+    } catch (RuntimeException ex) {\n+      throw new EventDeliveryException(\"Error trying to open a new\"\n+          + \" writer for dataset \" + datasetUri + \": \"\n+          + ex.getLocalizedMessage(), ex);\n     }\n   }\n \n-  private static Schema schema(Event event) throws EventDeliveryException {\n-    Map<String, String> headers = event.getHeaders();\n-    String schemaURL = headers.get(\n-        DatasetSinkConstants.AVRO_SCHEMA_URL_HEADER);\n+  /**\n+   * Return true if the sink should roll the writer.\n+   * \n+   * Currently, this is based on time since the last roll.\n+   * \n+   * @return True if and only if the sink should roll the writer\n+   */\n+  private boolean shouldRoll() {\n+    long currentTimeMillis = System.currentTimeMillis();\n+    long elapsedTimeSeconds = TimeUnit.MILLISECONDS.toSeconds(\n+        currentTimeMillis - lastRolledMs);\n+\n+    LOG.debug(\"Current time: {}, lastRolled: {}, diff: {} sec\",\n+        new Object[] {currentTimeMillis, lastRolledMs, elapsedTimeSeconds});\n+\n+    return elapsedTimeSeconds >= rollIntervalS;\n+  }\n+\n+  /**\n+   * Roll the dataset writer. If there's an error during the roll, the\n+   * transaction will be rolled back.\n+   * \n+   * @param closeWriter If true, the current writer is closed\n+   * @param createNewWriter If true, a new writer is created\n+   * @throws EventDeliveryException There was an error during the roll which\n+   *                                means we can't guarantee previously written\n+   *                                records were persisted.\n+   */\n+  @VisibleForTesting\n+  void rollWriter(boolean closeWriter, boolean createNewWriter)\n+      throws EventDeliveryException {\n     try {\n-      if (headers.get(DatasetSinkConstants.AVRO_SCHEMA_URL_HEADER) != null) {\n-        return schemasFromURL.get(schemaURL);\n-      } else {\n-        return schemasFromLiteral.get(\n-            headers.get(DatasetSinkConstants.AVRO_SCHEMA_LITERAL_HEADER));\n+      // close the current writer and get a new one\n+      if (writer != null && closeWriter) {\n+        try {\n+          writer.close();\n+        } catch (DatasetIOException ex) {\n+          throw new EventDeliveryException(\"Check HDFS permissions/health. IO\"\n+              + \" error trying to close the  writer for dataset \" + datasetUri\n+              + \": \" + ex.getLocalizedMessage(), ex);\n+        } catch (DatasetWriterException ex) {\n+          throw new EventDeliveryException(\"Failure moving temp file: \"\n+              + ex.getLocalizedMessage(), ex);\n+        } catch (RuntimeException ex) {\n+          throw new EventDeliveryException(\"Error trying to close the  writer for\"\n+              + \" dataset \" + datasetUri + \": \" + ex.getLocalizedMessage(), ex);\n+        }\n+      }\n+      writer = null;\n+\n+      // commit transaction\n+      if (transaction != null) {\n+        policy.endBatch();\n+        transaction.commit();\n+        transaction.close();\n+        transaction = null;\n+      }\n+\n+      if (createNewWriter) {\n+        writer = newWriter();\n+      }\n+\n+      if (closeWriter) {\n+        // Only log if we closed the old writer\n+        long elapsedTimeSeconds = TimeUnit.MILLISECONDS.toSeconds(\n+            System.currentTimeMillis() - lastRolledMs);\n+        LOG.info(\"Rolled writer for {} after {} seconds and {} bytes parsed\",\n+            new Object[]{datasetUri, elapsedTimeSeconds, bytesParsed});\n+      }\n+    } catch (Exception ex) {\n+      try {\n+        // If the transaction wasn't committed before we got the exception, we\n+        // need to rollback.\n+        if (transaction != null) {\n+          transaction.rollback();\n+          transaction.close();\n+          transaction = null;\n+        }\n+      } catch (RuntimeException rollbackException) {\n+        LOG.error(\"Transaction rollback failed: \"\n+            + rollbackException.getLocalizedMessage());\n+        LOG.debug(\"Exception follows.\", rollbackException);\n       }\n-    } catch (ExecutionException ex) {\n-      throw new EventDeliveryException(\"Cannot get schema\", ex.getCause());\n+\n+      Throwables.propagateIfInstanceOf(ex, EventDeliveryException.class);\n+      throw new EventDeliveryException(\"Failed to roll writer for \" + datasetUri\n+          + \": \" + ex.getLocalizedMessage(), ex);","path":"flume-ng-sinks/flume-dataset-sink/src/main/java/org/apache/flume/sink/kite/DatasetSink.java","position":700,"original_position":700,"commit_id":"c2705578455e849f7f4ce4dc8117bf1bccbbcf32","original_commit_id":"c2705578455e849f7f4ce4dc8117bf1bccbbcf32","user":{"login":"rdblue","id":87915,"avatar_url":"https://avatars.githubusercontent.com/u/87915?v=3","gravatar_id":"","url":"https://api.github.com/users/rdblue","html_url":"https://github.com/rdblue","followers_url":"https://api.github.com/users/rdblue/followers","following_url":"https://api.github.com/users/rdblue/following{/other_user}","gists_url":"https://api.github.com/users/rdblue/gists{/gist_id}","starred_url":"https://api.github.com/users/rdblue/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rdblue/subscriptions","organizations_url":"https://api.github.com/users/rdblue/orgs","repos_url":"https://api.github.com/users/rdblue/repos","events_url":"https://api.github.com/users/rdblue/events{/privacy}","received_events_url":"https://api.github.com/users/rdblue/received_events","type":"User","site_admin":false},"body":"Also don't need to add the localized message here.","created_at":"2015-01-23T20:18:29Z","updated_at":"2015-01-23T20:18:29Z","html_url":"https://github.com/joey/flume/pull/1#discussion_r23477054","pull_request_url":"https://api.github.com/repos/joey/flume/pulls/1","_links":{"self":{"href":"https://api.github.com/repos/joey/flume/pulls/comments/23477054"},"html":{"href":"https://github.com/joey/flume/pull/1#discussion_r23477054"},"pull_request":{"href":"https://api.github.com/repos/joey/flume/pulls/1"}}},"pull_request":{"url":"https://api.github.com/repos/joey/flume/pulls/1","id":27947209,"html_url":"https://github.com/joey/flume/pull/1","diff_url":"https://github.com/joey/flume/pull/1.diff","patch_url":"https://github.com/joey/flume/pull/1.patch","issue_url":"https://api.github.com/repos/joey/flume/issues/1","number":1,"state":"open","locked":false,"title":"Flume 2591 datasetsink 2.0","user":{"login":"joey","id":249392,"avatar_url":"https://avatars.githubusercontent.com/u/249392?v=3","gravatar_id":"","url":"https://api.github.com/users/joey","html_url":"https://github.com/joey","followers_url":"https://api.github.com/users/joey/followers","following_url":"https://api.github.com/users/joey/following{/other_user}","gists_url":"https://api.github.com/users/joey/gists{/gist_id}","starred_url":"https://api.github.com/users/joey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/joey/subscriptions","organizations_url":"https://api.github.com/users/joey/orgs","repos_url":"https://api.github.com/users/joey/repos","events_url":"https://api.github.com/users/joey/events{/privacy}","received_events_url":"https://api.github.com/users/joey/received_events","type":"User","site_admin":false},"body":"","created_at":"2015-01-23T19:10:32Z","updated_at":"2015-01-23T20:18:29Z","closed_at":null,"merged_at":null,"merge_commit_sha":"38f58eebc9cf1f47d230ee5a1e4ae8b866aa1869","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/joey/flume/pulls/1/commits","review_comments_url":"https://api.github.com/repos/joey/flume/pulls/1/comments","review_comment_url":"https://api.github.com/repos/joey/flume/pulls/comments/{number}","comments_url":"https://api.github.com/repos/joey/flume/issues/1/comments","statuses_url":"https://api.github.com/repos/joey/flume/statuses/c2705578455e849f7f4ce4dc8117bf1bccbbcf32","head":{"label":"joey:FLUME-2591-datasetsink-2.0","ref":"FLUME-2591-datasetsink-2.0","sha":"c2705578455e849f7f4ce4dc8117bf1bccbbcf32","user":{"login":"joey","id":249392,"avatar_url":"https://avatars.githubusercontent.com/u/249392?v=3","gravatar_id":"","url":"https://api.github.com/users/joey","html_url":"https://github.com/joey","followers_url":"https://api.github.com/users/joey/followers","following_url":"https://api.github.com/users/joey/following{/other_user}","gists_url":"https://api.github.com/users/joey/gists{/gist_id}","starred_url":"https://api.github.com/users/joey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/joey/subscriptions","organizations_url":"https://api.github.com/users/joey/orgs","repos_url":"https://api.github.com/users/joey/repos","events_url":"https://api.github.com/users/joey/events{/privacy}","received_events_url":"https://api.github.com/users/joey/received_events","type":"User","site_admin":false},"repo":{"id":4204676,"name":"flume","full_name":"joey/flume","owner":{"login":"joey","id":249392,"avatar_url":"https://avatars.githubusercontent.com/u/249392?v=3","gravatar_id":"","url":"https://api.github.com/users/joey","html_url":"https://github.com/joey","followers_url":"https://api.github.com/users/joey/followers","following_url":"https://api.github.com/users/joey/following{/other_user}","gists_url":"https://api.github.com/users/joey/gists{/gist_id}","starred_url":"https://api.github.com/users/joey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/joey/subscriptions","organizations_url":"https://api.github.com/users/joey/orgs","repos_url":"https://api.github.com/users/joey/repos","events_url":"https://api.github.com/users/joey/events{/privacy}","received_events_url":"https://api.github.com/users/joey/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/joey/flume","description":"Mirror of Apache Flume","fork":true,"url":"https://api.github.com/repos/joey/flume","forks_url":"https://api.github.com/repos/joey/flume/forks","keys_url":"https://api.github.com/repos/joey/flume/keys{/key_id}","collaborators_url":"https://api.github.com/repos/joey/flume/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/joey/flume/teams","hooks_url":"https://api.github.com/repos/joey/flume/hooks","issue_events_url":"https://api.github.com/repos/joey/flume/issues/events{/number}","events_url":"https://api.github.com/repos/joey/flume/events","assignees_url":"https://api.github.com/repos/joey/flume/assignees{/user}","branches_url":"https://api.github.com/repos/joey/flume/branches{/branch}","tags_url":"https://api.github.com/repos/joey/flume/tags","blobs_url":"https://api.github.com/repos/joey/flume/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/joey/flume/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/joey/flume/git/refs{/sha}","trees_url":"https://api.github.com/repos/joey/flume/git/trees{/sha}","statuses_url":"https://api.github.com/repos/joey/flume/statuses/{sha}","languages_url":"https://api.github.com/repos/joey/flume/languages","stargazers_url":"https://api.github.com/repos/joey/flume/stargazers","contributors_url":"https://api.github.com/repos/joey/flume/contributors","subscribers_url":"https://api.github.com/repos/joey/flume/subscribers","subscription_url":"https://api.github.com/repos/joey/flume/subscription","commits_url":"https://api.github.com/repos/joey/flume/commits{/sha}","git_commits_url":"https://api.github.com/repos/joey/flume/git/commits{/sha}","comments_url":"https://api.github.com/repos/joey/flume/comments{/number}","issue_comment_url":"https://api.github.com/repos/joey/flume/issues/comments/{number}","contents_url":"https://api.github.com/repos/joey/flume/contents/{+path}","compare_url":"https://api.github.com/repos/joey/flume/compare/{base}...{head}","merges_url":"https://api.github.com/repos/joey/flume/merges","archive_url":"https://api.github.com/repos/joey/flume/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/joey/flume/downloads","issues_url":"https://api.github.com/repos/joey/flume/issues{/number}","pulls_url":"https://api.github.com/repos/joey/flume/pulls{/number}","milestones_url":"https://api.github.com/repos/joey/flume/milestones{/number}","notifications_url":"https://api.github.com/repos/joey/flume/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/joey/flume/labels{/name}","releases_url":"https://api.github.com/repos/joey/flume/releases{/id}","created_at":"2012-05-02T15:49:57Z","updated_at":"2015-01-23T19:08:28Z","pushed_at":"2015-01-23T19:09:41Z","git_url":"git://github.com/joey/flume.git","ssh_url":"git@github.com:joey/flume.git","clone_url":"https://github.com/joey/flume.git","svn_url":"https://github.com/joey/flume","homepage":"","size":39645,"stargazers_count":1,"watchers_count":1,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":1,"default_branch":"trunk"}},"base":{"label":"joey:trunk","ref":"trunk","sha":"82631f811a7c6a4d8e6ec886f80d1a21876947e5","user":{"login":"joey","id":249392,"avatar_url":"https://avatars.githubusercontent.com/u/249392?v=3","gravatar_id":"","url":"https://api.github.com/users/joey","html_url":"https://github.com/joey","followers_url":"https://api.github.com/users/joey/followers","following_url":"https://api.github.com/users/joey/following{/other_user}","gists_url":"https://api.github.com/users/joey/gists{/gist_id}","starred_url":"https://api.github.com/users/joey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/joey/subscriptions","organizations_url":"https://api.github.com/users/joey/orgs","repos_url":"https://api.github.com/users/joey/repos","events_url":"https://api.github.com/users/joey/events{/privacy}","received_events_url":"https://api.github.com/users/joey/received_events","type":"User","site_admin":false},"repo":{"id":4204676,"name":"flume","full_name":"joey/flume","owner":{"login":"joey","id":249392,"avatar_url":"https://avatars.githubusercontent.com/u/249392?v=3","gravatar_id":"","url":"https://api.github.com/users/joey","html_url":"https://github.com/joey","followers_url":"https://api.github.com/users/joey/followers","following_url":"https://api.github.com/users/joey/following{/other_user}","gists_url":"https://api.github.com/users/joey/gists{/gist_id}","starred_url":"https://api.github.com/users/joey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/joey/subscriptions","organizations_url":"https://api.github.com/users/joey/orgs","repos_url":"https://api.github.com/users/joey/repos","events_url":"https://api.github.com/users/joey/events{/privacy}","received_events_url":"https://api.github.com/users/joey/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/joey/flume","description":"Mirror of Apache Flume","fork":true,"url":"https://api.github.com/repos/joey/flume","forks_url":"https://api.github.com/repos/joey/flume/forks","keys_url":"https://api.github.com/repos/joey/flume/keys{/key_id}","collaborators_url":"https://api.github.com/repos/joey/flume/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/joey/flume/teams","hooks_url":"https://api.github.com/repos/joey/flume/hooks","issue_events_url":"https://api.github.com/repos/joey/flume/issues/events{/number}","events_url":"https://api.github.com/repos/joey/flume/events","assignees_url":"https://api.github.com/repos/joey/flume/assignees{/user}","branches_url":"https://api.github.com/repos/joey/flume/branches{/branch}","tags_url":"https://api.github.com/repos/joey/flume/tags","blobs_url":"https://api.github.com/repos/joey/flume/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/joey/flume/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/joey/flume/git/refs{/sha}","trees_url":"https://api.github.com/repos/joey/flume/git/trees{/sha}","statuses_url":"https://api.github.com/repos/joey/flume/statuses/{sha}","languages_url":"https://api.github.com/repos/joey/flume/languages","stargazers_url":"https://api.github.com/repos/joey/flume/stargazers","contributors_url":"https://api.github.com/repos/joey/flume/contributors","subscribers_url":"https://api.github.com/repos/joey/flume/subscribers","subscription_url":"https://api.github.com/repos/joey/flume/subscription","commits_url":"https://api.github.com/repos/joey/flume/commits{/sha}","git_commits_url":"https://api.github.com/repos/joey/flume/git/commits{/sha}","comments_url":"https://api.github.com/repos/joey/flume/comments{/number}","issue_comment_url":"https://api.github.com/repos/joey/flume/issues/comments/{number}","contents_url":"https://api.github.com/repos/joey/flume/contents/{+path}","compare_url":"https://api.github.com/repos/joey/flume/compare/{base}...{head}","merges_url":"https://api.github.com/repos/joey/flume/merges","archive_url":"https://api.github.com/repos/joey/flume/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/joey/flume/downloads","issues_url":"https://api.github.com/repos/joey/flume/issues{/number}","pulls_url":"https://api.github.com/repos/joey/flume/pulls{/number}","milestones_url":"https://api.github.com/repos/joey/flume/milestones{/number}","notifications_url":"https://api.github.com/repos/joey/flume/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/joey/flume/labels{/name}","releases_url":"https://api.github.com/repos/joey/flume/releases{/id}","created_at":"2012-05-02T15:49:57Z","updated_at":"2015-01-23T19:08:28Z","pushed_at":"2015-01-23T19:09:41Z","git_url":"git://github.com/joey/flume.git","ssh_url":"git@github.com:joey/flume.git","clone_url":"https://github.com/joey/flume.git","svn_url":"https://github.com/joey/flume","homepage":"","size":39645,"stargazers_count":1,"watchers_count":1,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":1,"default_branch":"trunk"}},"_links":{"self":{"href":"https://api.github.com/repos/joey/flume/pulls/1"},"html":{"href":"https://github.com/joey/flume/pull/1"},"issue":{"href":"https://api.github.com/repos/joey/flume/issues/1"},"comments":{"href":"https://api.github.com/repos/joey/flume/issues/1/comments"},"review_comments":{"href":"https://api.github.com/repos/joey/flume/pulls/1/comments"},"review_comment":{"href":"https://api.github.com/repos/joey/flume/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/joey/flume/pulls/1/commits"},"statuses":{"href":"https://api.github.com/repos/joey/flume/statuses/c2705578455e849f7f4ce4dc8117bf1bccbbcf32"}}}}