{"action":"created","comment":{"url":"https://api.github.com/repos/apache/spark/pulls/comments/147573486","pull_request_review_id":72690182,"id":147573486,"diff_hunk":"@@ -17,47 +17,168 @@\n \n package org.apache.spark.unsafe.memory;\n \n-import javax.annotation.Nullable;\n-\n import org.apache.spark.unsafe.Platform;\n \n+import javax.annotation.Nullable;\n+\n /**\n- * A consecutive block of memory, starting at a {@link MemoryLocation} with a fixed size.\n+ * A declaration of interfaces of MemoryBlock classes .\n  */\n-public class MemoryBlock extends MemoryLocation {\n+public abstract class MemoryBlock {\n+  @Nullable\n+  protected final Object obj;\n \n-  private final long length;\n+  protected final long offset;\n+\n+  protected final long length;\n \n   /**\n    * Optional page number; used when this MemoryBlock represents a page allocated by a\n-   * TaskMemoryManager. This field is public so that it can be modified by the TaskMemoryManager,\n-   * which lives in a different package.\n+   * TaskMemoryManager. This field can be updated using setPageNumber method so that\n+   * this can be modified by the TaskMemoryManager, which lives in a different package.\n    */\n-  public int pageNumber = -1;\n+  private int pageNumber = -1;\n \n   public MemoryBlock(@Nullable Object obj, long offset, long length) {\n-    super(obj, offset);\n+    this.obj = obj;\n+    this.offset = offset;\n     this.length = length;\n   }\n \n+  public MemoryBlock() {\n+    this(null, 0, 0);\n+  }\n+\n+  public final Object getBaseObject() {\n+    return obj;\n+  }\n+\n+  public final long getBaseOffset() {\n+    return offset;\n+  }\n+\n   /**\n    * Returns the size of the memory block.\n    */\n-  public long size() {\n+  public final long size() {\n     return length;\n   }\n \n-  /**\n-   * Creates a memory block pointing to the memory used by the long array.\n-   */\n-  public static MemoryBlock fromLongArray(final long[] array) {\n-    return new MemoryBlock(array, Platform.LONG_ARRAY_OFFSET, array.length * 8L);\n+  public final void setPageNumber(int pageNum) {\n+    pageNumber = pageNum;\n+  }\n+\n+  public final int getPageNumber() {\n+    return pageNumber;\n   }\n \n   /**\n    * Fills the memory block with the specified byte value.\n    */\n-  public void fill(byte value) {\n+  public final void fill(byte value) {\n     Platform.setMemory(obj, offset, length, value);\n   }\n+\n+  /**\n+   * Instantiate the same type of MemoryBlock with new offset and size\n+   */\n+  public abstract MemoryBlock allocate(long offset, long size);\n+\n+\n+  public abstract int getInt(long offset);\n+\n+  public abstract void putInt(long offset, int value);\n+\n+  public abstract boolean getBoolean(long offset);\n+\n+  public abstract void putBoolean(long offset, boolean value);\n+\n+  public abstract byte getByte(long offset);\n+\n+  public abstract void putByte(long offset, byte value);\n+\n+  public abstract short getShort(long offset);\n+\n+  public abstract void putShort(long offset, short value);\n+\n+  public abstract long getLong(long offset);\n+\n+  public abstract void putLong(long offset, long value);\n+\n+  public abstract float getFloat(long offset);\n+\n+  public abstract void putFloat(long offset, float value);\n+\n+  public abstract double getDouble(long offset);\n+\n+  public abstract void putDouble(long offset, double value);\n+\n+  public abstract Object getObjectVolatile(long offset);\n+\n+  public abstract void putObjectVolatile(long offset, Object value);\n+\n+  public static final void copyMemory(","path":"common/unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryBlock.java","position":120,"original_position":120,"commit_id":"6e8d5b820c83517d0340d748959b855229e664a7","original_commit_id":"6e8d5b820c83517d0340d748959b855229e664a7","user":{"login":"kiszk","id":1315079,"avatar_url":"https://avatars2.githubusercontent.com/u/1315079?v=4","gravatar_id":"","url":"https://api.github.com/users/kiszk","html_url":"https://github.com/kiszk","followers_url":"https://api.github.com/users/kiszk/followers","following_url":"https://api.github.com/users/kiszk/following{/other_user}","gists_url":"https://api.github.com/users/kiszk/gists{/gist_id}","starred_url":"https://api.github.com/users/kiszk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kiszk/subscriptions","organizations_url":"https://api.github.com/users/kiszk/orgs","repos_url":"https://api.github.com/users/kiszk/repos","events_url":"https://api.github.com/users/kiszk/events{/privacy}","received_events_url":"https://api.github.com/users/kiszk/received_events","type":"User","site_admin":false},"body":"`copyMemory` has two kinds of arguments: `src` and `dst`.  \r\nIf we make them non-static method, it is not easy to understand whether `this` is `src` or `dst`. If we keep method name `MemoryBlock.copy`, I think that it is good to keep current form (it is common in `memcpy`).\r\n\r\nOr, can we prepare two methods `MemoryBlock.copyFrom(srcOffset, dst...)` and `MemoryBlock.copyTo(src..., dstOffset)`.\r\n\r\n@cloud-fan What do you think?\r\n","created_at":"2017-10-29T08:13:29Z","updated_at":"2017-10-29T08:13:29Z","html_url":"https://github.com/apache/spark/pull/19222#discussion_r147573486","pull_request_url":"https://api.github.com/repos/apache/spark/pulls/19222","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/apache/spark/pulls/comments/147573486"},"html":{"href":"https://github.com/apache/spark/pull/19222#discussion_r147573486"},"pull_request":{"href":"https://api.github.com/repos/apache/spark/pulls/19222"}},"in_reply_to_id":147565937},"pull_request":{"url":"https://api.github.com/repos/apache/spark/pulls/19222","id":140892682,"html_url":"https://github.com/apache/spark/pull/19222","diff_url":"https://github.com/apache/spark/pull/19222.diff","patch_url":"https://github.com/apache/spark/pull/19222.patch","issue_url":"https://api.github.com/repos/apache/spark/issues/19222","number":19222,"state":"open","locked":false,"title":"[SPARK-10399][CORE][SQL] Introduce multiple MemoryBlocks to choose several types of memory block","user":{"login":"kiszk","id":1315079,"avatar_url":"https://avatars2.githubusercontent.com/u/1315079?v=4","gravatar_id":"","url":"https://api.github.com/users/kiszk","html_url":"https://github.com/kiszk","followers_url":"https://api.github.com/users/kiszk/followers","following_url":"https://api.github.com/users/kiszk/following{/other_user}","gists_url":"https://api.github.com/users/kiszk/gists{/gist_id}","starred_url":"https://api.github.com/users/kiszk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kiszk/subscriptions","organizations_url":"https://api.github.com/users/kiszk/orgs","repos_url":"https://api.github.com/users/kiszk/repos","events_url":"https://api.github.com/users/kiszk/events{/privacy}","received_events_url":"https://api.github.com/users/kiszk/received_events","type":"User","site_admin":false},"body":"## What changes were proposed in this pull request?\r\n\r\nThis PR allows us to use one of several types of `MemoryBlock`, such as byte array, int array, long array, or `java.nio.DirectByteBuffer`. To use `java.nio.DirectByteBuffer` allows to have off heap memory which is automatically deallocated by JVM. `MemoryBlock`  class has primitive accessors like `Platform.getInt()`, `Platform.putint()`, or `Platform.copyMemory()`. \r\n\r\nThis PR uses `MemoryBlock` for `OffHeapColumnVector`, `UTF8String`, and other places. This PR can improve performance of operations involving memory accesses (e.g. `UTF8String.trim`) by 1.8x.\r\n\r\nFor now, this PR does not use `MemoryBlock` for `BufferHolder` based on @cloud-fan's [suggestion](https://github.com/apache/spark/pull/11494#issuecomment-309694290).\r\n\r\nSince this PR is a successor of #11494, close #11494. Many codes were ported from #11494. Many efforts were put here. I think this PR should credit to @yzotov.\r\n\r\n\r\nThis PR can achieve **1.1-1.4x performance improvements** for  operations in `UTF8String` or `Murmur3_x86_32`. Other operations are almost comparable performances.\r\n\r\nWithout this PR\r\n```\r\nOpenJDK 64-Bit Server VM 1.8.0_121-8u121-b13-0ubuntu1.16.04.2-b13 on Linux 4.4.0-22-generic\r\nIntel(R) Xeon(R) CPU E5-2667 v3 @ 3.20GHz\r\nOpenJDK 64-Bit Server VM 1.8.0_121-8u121-b13-0ubuntu1.16.04.2-b13 on Linux 4.4.0-22-generic\r\nIntel(R) Xeon(R) CPU E5-2667 v3 @ 3.20GHz\r\nHash byte arrays with length 268435487:  Best/Avg Time(ms)    Rate(M/s)   Per Row(ns)   Relative\r\n------------------------------------------------------------------------------------------------\r\nMurmur3_x86_32                                 526 /  536          0.0   131399881.5       1.0X\r\n\r\nUTF8String benchmark:                    Best/Avg Time(ms)    Rate(M/s)   Per Row(ns)   Relative\r\n------------------------------------------------------------------------------------------------\r\nhashCode                                       525 /  552       1022.6           1.0       1.0X\r\nsubstring                                      414 /  423       1298.0           0.8       1.3X\r\n```\r\n\r\nWith this PR\r\n```\r\nOpenJDK 64-Bit Server VM 1.8.0_121-8u121-b13-0ubuntu1.16.04.2-b13 on Linux 4.4.0-22-generic\r\nIntel(R) Xeon(R) CPU E5-2667 v3 @ 3.20GHz\r\nHash byte arrays with length 268435487:  Best/Avg Time(ms)    Rate(M/s)   Per Row(ns)   Relative\r\n------------------------------------------------------------------------------------------------\r\nMurmur3_x86_32                                 474 /  488          0.0   118552232.0       1.0X\r\n\r\nUTF8String benchmark:                    Best/Avg Time(ms)    Rate(M/s)   Per Row(ns)   Relative\r\n------------------------------------------------------------------------------------------------\r\nhashCode                                       476 /  480       1127.3           0.9       1.0X\r\nsubstring                                      287 /  291       1869.9           0.5       1.7X\r\n```\r\n\r\nBenchmark program\r\n```\r\ntest(\"benchmark Murmur3_x86_32\") {\r\n  val length = 8192 * 32768 + 31\r\n  val seed = 42L\r\n  val iters = 1 << 2\r\n  val random = new Random(seed)\r\n  val arrays = Array.fill[MemoryBlock](numArrays) {\r\n    val bytes = new Array[Byte](length)\r\n    random.nextBytes(bytes)\r\n    new ByteArrayMemoryBlock(bytes, Platform.BYTE_ARRAY_OFFSET, length)\r\n  }\r\n                                                                \r\n  val benchmark = new Benchmark(\"Hash byte arrays with length \" + length,\r\n    iters * numArrays, minNumIters = 20) \r\n  benchmark.addCase(\"HiveHasher\") { _: Int =>\r\n    var sum = 0L\r\n    for (_ <- 0L until iters) {\r\n      sum += HiveHasher.hashUnsafeBytesBlock(\r\n        arrays(i), Platform.BYTE_ARRAY_OFFSET, length)\r\n    }\r\n  }\r\n  benchmark.run()   \r\n}\r\n\r\ntest(\"benchmark UTF8String\") {\r\n  val N = 512 * 1024 * 1024\r\n  val iters = 2\r\n  val benchmark = new Benchmark(\"UTF8String benchmark\", N, minNumIters = 20)\r\n  val str0 = new java.io.StringWriter() { { for (i <- 0 until N) { write(\" \") } } }.toString\r\n  val s0 = UTF8String.fromString(str0)\r\n  benchmark.addCase(\"hashCode\") { _: Int =>\r\n    var h: Int = 0\r\n    for (_ <- 0L until iters) { h += s0.hashCode }\r\n  }\r\n  benchmark.addCase(\"substring\") { _: Int =>\r\n    var s: UTF8String = null\r\n    for (_ <- 0L until iters) { s = s0.substring(N / 2 - 5, N / 2 + 5) }\r\n  }\r\n  benchmark.run()\r\n}\r\n```\r\n\r\n## How was this patch tested?\r\n\r\nAdded `UnsafeMemoryAllocator`\r\n","created_at":"2017-09-13T18:05:08Z","updated_at":"2017-10-29T08:13:29Z","closed_at":null,"merged_at":null,"merge_commit_sha":"51672a3f964f51505610abd558db76f03c5cd2f2","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/apache/spark/pulls/19222/commits","review_comments_url":"https://api.github.com/repos/apache/spark/pulls/19222/comments","review_comment_url":"https://api.github.com/repos/apache/spark/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/spark/issues/19222/comments","statuses_url":"https://api.github.com/repos/apache/spark/statuses/6e8d5b820c83517d0340d748959b855229e664a7","head":{"label":"kiszk:SPARK-10399","ref":"SPARK-10399","sha":"6e8d5b820c83517d0340d748959b855229e664a7","user":{"login":"kiszk","id":1315079,"avatar_url":"https://avatars2.githubusercontent.com/u/1315079?v=4","gravatar_id":"","url":"https://api.github.com/users/kiszk","html_url":"https://github.com/kiszk","followers_url":"https://api.github.com/users/kiszk/followers","following_url":"https://api.github.com/users/kiszk/following{/other_user}","gists_url":"https://api.github.com/users/kiszk/gists{/gist_id}","starred_url":"https://api.github.com/users/kiszk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kiszk/subscriptions","organizations_url":"https://api.github.com/users/kiszk/orgs","repos_url":"https://api.github.com/users/kiszk/repos","events_url":"https://api.github.com/users/kiszk/events{/privacy}","received_events_url":"https://api.github.com/users/kiszk/received_events","type":"User","site_admin":false},"repo":{"id":45008789,"name":"spark","full_name":"kiszk/spark","owner":{"login":"kiszk","id":1315079,"avatar_url":"https://avatars2.githubusercontent.com/u/1315079?v=4","gravatar_id":"","url":"https://api.github.com/users/kiszk","html_url":"https://github.com/kiszk","followers_url":"https://api.github.com/users/kiszk/followers","following_url":"https://api.github.com/users/kiszk/following{/other_user}","gists_url":"https://api.github.com/users/kiszk/gists{/gist_id}","starred_url":"https://api.github.com/users/kiszk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kiszk/subscriptions","organizations_url":"https://api.github.com/users/kiszk/orgs","repos_url":"https://api.github.com/users/kiszk/repos","events_url":"https://api.github.com/users/kiszk/events{/privacy}","received_events_url":"https://api.github.com/users/kiszk/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/kiszk/spark","description":"Mirror of Apache Spark","fork":true,"url":"https://api.github.com/repos/kiszk/spark","forks_url":"https://api.github.com/repos/kiszk/spark/forks","keys_url":"https://api.github.com/repos/kiszk/spark/keys{/key_id}","collaborators_url":"https://api.github.com/repos/kiszk/spark/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/kiszk/spark/teams","hooks_url":"https://api.github.com/repos/kiszk/spark/hooks","issue_events_url":"https://api.github.com/repos/kiszk/spark/issues/events{/number}","events_url":"https://api.github.com/repos/kiszk/spark/events","assignees_url":"https://api.github.com/repos/kiszk/spark/assignees{/user}","branches_url":"https://api.github.com/repos/kiszk/spark/branches{/branch}","tags_url":"https://api.github.com/repos/kiszk/spark/tags","blobs_url":"https://api.github.com/repos/kiszk/spark/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/kiszk/spark/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/kiszk/spark/git/refs{/sha}","trees_url":"https://api.github.com/repos/kiszk/spark/git/trees{/sha}","statuses_url":"https://api.github.com/repos/kiszk/spark/statuses/{sha}","languages_url":"https://api.github.com/repos/kiszk/spark/languages","stargazers_url":"https://api.github.com/repos/kiszk/spark/stargazers","contributors_url":"https://api.github.com/repos/kiszk/spark/contributors","subscribers_url":"https://api.github.com/repos/kiszk/spark/subscribers","subscription_url":"https://api.github.com/repos/kiszk/spark/subscription","commits_url":"https://api.github.com/repos/kiszk/spark/commits{/sha}","git_commits_url":"https://api.github.com/repos/kiszk/spark/git/commits{/sha}","comments_url":"https://api.github.com/repos/kiszk/spark/comments{/number}","issue_comment_url":"https://api.github.com/repos/kiszk/spark/issues/comments{/number}","contents_url":"https://api.github.com/repos/kiszk/spark/contents/{+path}","compare_url":"https://api.github.com/repos/kiszk/spark/compare/{base}...{head}","merges_url":"https://api.github.com/repos/kiszk/spark/merges","archive_url":"https://api.github.com/repos/kiszk/spark/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/kiszk/spark/downloads","issues_url":"https://api.github.com/repos/kiszk/spark/issues{/number}","pulls_url":"https://api.github.com/repos/kiszk/spark/pulls{/number}","milestones_url":"https://api.github.com/repos/kiszk/spark/milestones{/number}","notifications_url":"https://api.github.com/repos/kiszk/spark/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/kiszk/spark/labels{/name}","releases_url":"https://api.github.com/repos/kiszk/spark/releases{/id}","deployments_url":"https://api.github.com/repos/kiszk/spark/deployments","created_at":"2015-10-27T01:25:07Z","updated_at":"2017-09-24T18:21:56Z","pushed_at":"2017-10-29T03:29:11Z","git_url":"git://github.com/kiszk/spark.git","ssh_url":"git@github.com:kiszk/spark.git","clone_url":"https://github.com/kiszk/spark.git","svn_url":"https://github.com/kiszk/spark","homepage":null,"size":258392,"stargazers_count":1,"watchers_count":1,"language":"Scala","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":1,"default_branch":"master"}},"base":{"label":"apache:master","ref":"master","sha":"bd4eb9ce57da7bacff69d9ed958c94f349b7e6fb","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":17165658,"name":"spark","full_name":"apache/spark","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/spark","description":"Mirror of Apache Spark","fork":false,"url":"https://api.github.com/repos/apache/spark","forks_url":"https://api.github.com/repos/apache/spark/forks","keys_url":"https://api.github.com/repos/apache/spark/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/spark/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/spark/teams","hooks_url":"https://api.github.com/repos/apache/spark/hooks","issue_events_url":"https://api.github.com/repos/apache/spark/issues/events{/number}","events_url":"https://api.github.com/repos/apache/spark/events","assignees_url":"https://api.github.com/repos/apache/spark/assignees{/user}","branches_url":"https://api.github.com/repos/apache/spark/branches{/branch}","tags_url":"https://api.github.com/repos/apache/spark/tags","blobs_url":"https://api.github.com/repos/apache/spark/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/spark/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/spark/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/spark/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/spark/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/spark/languages","stargazers_url":"https://api.github.com/repos/apache/spark/stargazers","contributors_url":"https://api.github.com/repos/apache/spark/contributors","subscribers_url":"https://api.github.com/repos/apache/spark/subscribers","subscription_url":"https://api.github.com/repos/apache/spark/subscription","commits_url":"https://api.github.com/repos/apache/spark/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/spark/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/spark/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/spark/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/spark/contents/{+path}","compare_url":"https://api.github.com/repos/apache/spark/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/spark/merges","archive_url":"https://api.github.com/repos/apache/spark/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/spark/downloads","issues_url":"https://api.github.com/repos/apache/spark/issues{/number}","pulls_url":"https://api.github.com/repos/apache/spark/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/spark/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/spark/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/spark/labels{/name}","releases_url":"https://api.github.com/repos/apache/spark/releases{/id}","deployments_url":"https://api.github.com/repos/apache/spark/deployments","created_at":"2014-02-25T08:00:08Z","updated_at":"2017-10-29T04:23:27Z","pushed_at":"2017-10-29T07:52:12Z","git_url":"git://github.com/apache/spark.git","ssh_url":"git@github.com:apache/spark.git","clone_url":"https://github.com/apache/spark.git","svn_url":"https://github.com/apache/spark","homepage":null,"size":265166,"stargazers_count":14831,"watchers_count":14831,"language":"Scala","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":13845,"mirror_url":"git://git.apache.org/spark.git","archived":false,"open_issues_count":387,"forks":13845,"open_issues":387,"watchers":14831,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/spark/pulls/19222"},"html":{"href":"https://github.com/apache/spark/pull/19222"},"issue":{"href":"https://api.github.com/repos/apache/spark/issues/19222"},"comments":{"href":"https://api.github.com/repos/apache/spark/issues/19222/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/spark/pulls/19222/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/spark/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/spark/pulls/19222/commits"},"statuses":{"href":"https://api.github.com/repos/apache/spark/statuses/6e8d5b820c83517d0340d748959b855229e664a7"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"kiszk"}}