{"action":"created","comment":{"url":"https://api.github.com/repos/apache/spark/pulls/comments/29215841","id":29215841,"diff_hunk":"@@ -0,0 +1,552 @@\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+\n+package org.apache.spark.unsafe.map;\n+\n+import java.lang.Override;\n+import java.lang.UnsupportedOperationException;\n+import java.util.Iterator;\n+import java.util.LinkedList;\n+import java.util.List;\n+\n+import org.apache.spark.unsafe.*;\n+import org.apache.spark.unsafe.array.ByteArrayMethods;\n+import org.apache.spark.unsafe.array.LongArray;\n+import org.apache.spark.unsafe.bitset.BitSet;\n+import org.apache.spark.unsafe.hash.Murmur3_x86_32;\n+import org.apache.spark.unsafe.memory.*;\n+\n+/**\n+ * An append-only hash map where keys and values are contiguous regions of bytes.\n+ * <p>\n+ * This is backed by a power-of-2-sized hash table, using quadratic probing with triangular numbers,\n+ * which is guaranteed to exhaust the space.\n+ * <p>\n+ * Note that even though we use long for indexing, the map can support up to 2^31 keys because\n+ * we use 32 bit MurmurHash. In either case, if the key cardinality is so high, you should probably\n+ * be using sorting instead of hashing for better cache locality.\n+ * <p>\n+ * This class is not thread safe.\n+ */\n+public final class BytesToBytesMap {\n+\n+  private static final Murmur3_x86_32 HASHER = new Murmur3_x86_32(0);\n+\n+  private static final HashMapGrowthStrategy growthStrategy = HashMapGrowthStrategy.DOUBLING;\n+\n+  private final MemoryManager memoryManager;\n+\n+  /**\n+   * A linked list for tracking all allocated data pages so that we can free all of our memory.\n+   */\n+  private final List<MemoryBlock> dataPages = new LinkedList<MemoryBlock>();\n+\n+  /**\n+   * The data page that will be used to store keys and values for new hashtable entries. When this\n+   * page becomes full, a new page will be allocated and this pointer will change to point to that\n+   * new page.\n+   */\n+  private MemoryBlock currentDataPage = null;\n+\n+  /**\n+   * Offset into `currentDataPage` that points to the location where new data can be inserted into\n+   * the page.\n+   */\n+  private long pageCursor = 0;\n+\n+  /**\n+   * The size of the data pages that hold key and value data. Map entries cannot span multiple\n+   * pages, so this limits the maximum entry size.\n+   */\n+  private static final long PAGE_SIZE_BYTES = 1L << 26; // 64 megabytes\n+\n+  // This choice of page table size and page size means that we can address up to 500 gigabytes\n+  // of memory.\n+\n+  /**\n+   * A single array to store the key and value.\n+   *\n+   * Position {@code 2 * i} in the array is used to track a pointer to the key at index {@code i},\n+   * while position {@code 2 * i + 1} in the array holds key's full 32-bit hashcode.\n+   */\n+  private LongArray longArray;\n+  // TODO: we're wasting 32 bits of space here; we can probably store fewer bits of the hashcode\n+  // and exploit word-alignment to use fewer bits to hold the address.  This might let us store\n+  // only one long per map entry, increasing the chance that this array will fit in cache at the\n+  // expense of maybe performing more lookups if we have hash collisions.  Say that we stored only\n+  // 27 bits of the hashcode and 37 bits of the address.  37 bits is enough to address 1 terabyte\n+  // of RAM given word-alignment.  If we use 13 bits of this for our page table, that gives us a\n+  // maximum page size of 2^24 * 8 = ~134 megabytes per page. This change will require us to store\n+  // full base addresses in the page table for off-heap mode so that we can reconstruct the full\n+  // absolute memory addresses.\n+\n+  /**\n+   * A {@link BitSet} used to track location of the map where the key is set.\n+   * Size of the bitset should be half of the size of the long array.\n+   */\n+  private BitSet bitset;\n+\n+  private final double loadFactor;\n+\n+  /**\n+   * Number of keys defined in the map.\n+   */\n+  private int size;\n+\n+  /**\n+   * The map will be expanded once the number of keys exceeds this threshold.\n+   */\n+  private int growthThreshold;\n+\n+  /**\n+   * Mask for truncating hashcodes so that they do not exceed the long array's size.\n+   */\n+  private int mask;\n+\n+  /**\n+   * Return value of {@link BytesToBytesMap#lookup(Object, long, int)}.\n+   */\n+  private final Location loc;\n+\n+  private final boolean enablePerfMetrics;\n+\n+  private long timeSpentResizingMs = 0;","path":"unsafe/src/main/java/org/apache/spark/unsafe/map/BytesToBytesMap.java","position":127,"original_position":127,"commit_id":"162caf74c15952f6ae0482c1fa74529a0289b039","original_commit_id":"162caf74c15952f6ae0482c1fa74529a0289b039","user":{"login":"rxin","id":323388,"avatar_url":"https://avatars.githubusercontent.com/u/323388?v=3","gravatar_id":"","url":"https://api.github.com/users/rxin","html_url":"https://github.com/rxin","followers_url":"https://api.github.com/users/rxin/followers","following_url":"https://api.github.com/users/rxin/following{/other_user}","gists_url":"https://api.github.com/users/rxin/gists{/gist_id}","starred_url":"https://api.github.com/users/rxin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rxin/subscriptions","organizations_url":"https://api.github.com/users/rxin/orgs","repos_url":"https://api.github.com/users/rxin/repos","events_url":"https://api.github.com/users/rxin/events{/privacy}","received_events_url":"https://api.github.com/users/rxin/received_events","type":"User","site_admin":false},"body":"should be nano sec","created_at":"2015-04-28T05:47:35Z","updated_at":"2015-04-28T05:47:35Z","html_url":"https://github.com/apache/spark/pull/5725#discussion_r29215841","pull_request_url":"https://api.github.com/repos/apache/spark/pulls/5725","_links":{"self":{"href":"https://api.github.com/repos/apache/spark/pulls/comments/29215841"},"html":{"href":"https://github.com/apache/spark/pull/5725#discussion_r29215841"},"pull_request":{"href":"https://api.github.com/repos/apache/spark/pulls/5725"}}},"pull_request":{"url":"https://api.github.com/repos/apache/spark/pulls/5725","id":34196985,"html_url":"https://github.com/apache/spark/pull/5725","diff_url":"https://github.com/apache/spark/pull/5725.diff","patch_url":"https://github.com/apache/spark/pull/5725.patch","issue_url":"https://api.github.com/repos/apache/spark/issues/5725","number":5725,"state":"open","locked":false,"title":"[SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use managed memory for aggregations","user":{"login":"JoshRosen","id":50748,"avatar_url":"https://avatars.githubusercontent.com/u/50748?v=3","gravatar_id":"","url":"https://api.github.com/users/JoshRosen","html_url":"https://github.com/JoshRosen","followers_url":"https://api.github.com/users/JoshRosen/followers","following_url":"https://api.github.com/users/JoshRosen/following{/other_user}","gists_url":"https://api.github.com/users/JoshRosen/gists{/gist_id}","starred_url":"https://api.github.com/users/JoshRosen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JoshRosen/subscriptions","organizations_url":"https://api.github.com/users/JoshRosen/orgs","repos_url":"https://api.github.com/users/JoshRosen/repos","events_url":"https://api.github.com/users/JoshRosen/events{/privacy}","received_events_url":"https://api.github.com/users/JoshRosen/received_events","type":"User","site_admin":false},"body":"This patch adds managed-memory-based aggregation to Spark SQL / DataFrames. Instead of working with Java objects, this new aggregation path uses `sun.misc.Unsafe` to manipulate raw memory.  This reduces the memory footprint for aggregations, resulting in fewer spills, OutOfMemoryErrors, and garbage collection pauses.  As a result, this allows for higher memory utilization.  It can also result in better cache locality since objects will be stored closer together in memory.\r\n\r\nThis feature can be eanbled by setting `spark.sql.unsafe.enabled=true`.  For now, this feature is only supported when codegen is enabled and only supports aggregations for which the grouping columns are primitive numeric types or strings and aggregated values are numeric.\r\n\r\n### Managing memory with sun.misc.Unsafe\r\n\r\nThis patch supports both on- and off-heap managed memory.\r\n\r\n- In on-heap mode, memory addresses are identified by the combination of a base Object and an offset within that object.\r\n- In off-heap mode, memory is addressed directly with 64-bit long addresses.\r\n\r\nTo support both modes, functions that manipulate memory accept both `baseObject` and `baseOffset` fields.  In off-heap mode, we simply pass `null` as `baseObject`.\r\n\r\nWe allocate memory in large chunks, so memory fragmentation and allocation speed are not significant bottlenecks.\r\n\r\nBy default, we use on-heap mode.  To enable off-heap mode, set `spark.unsafe.offHeap=true`.\r\n\r\n### Compact tuple format\r\n\r\nThis patch introduces `UnsafeRow`, a compact row layout.  In this format, each tuple has three parts: a null bit set, fixed length values, and variable-length values:\r\n\r\n![image](https://cloud.githubusercontent.com/assets/50748/7328538/2fdb65ce-ea8b-11e4-9743-6c0f02bb7d1f.png)\r\n\r\n- Rows are always 8-byte word aligned (so their sizes will always be a multiple of 8 bytes)\r\n- The bit set is used for null tracking:\r\n\t- Position _i_ is set if and only if field _i_ is null\r\n\t- The bit set is aligned to an 8-byte word boundary.\r\n- Every field appears as an 8-byte word in the fixed-length values part:\r\n\t- If a field is null, we zero out the values.\r\n\t- If a field is variable-length, the word stores a relative offset (w.r.t. the base of the tuple) that points to the beginning of the field's data in the variable-length part.\r\n- Each variable-length data type can have its own encoding:\r\n\t- For strings, the first word stores the length of the string and is followed by UTF-8 encoded bytes.  If necessary, the end of the string is padded with empty bytes in order to ensure word-alignment.\r\n\r\nFor example, a tuple that consists 3 fields of type (int, string, string), with value (null, “data”, “bricks”) would look like this:\r\n\r\n![image](https://cloud.githubusercontent.com/assets/50748/7328526/1e21959c-ea8b-11e4-9a28-a4350fe4a7b5.png)\r\n\r\nThis format allows us to compare tuples for equality by directly comparing their raw bytes.  This also enables fast hashing of tuples.\r\n\r\n### Hash map for performing aggregations\r\n\r\nThis patch introduces `UnsafeFixedWidthAggregationMap`, a hash map for performing aggregations where the aggregation result columns are fixed-with.  This map's keys and values are `Row` objects. `UnsafeFixedWidthAggregationMap` is implemented on top of `BytesToBytesMap`, an append-only map which supports byte-array keys and values.\r\n\r\n`BytesToBytesMap` stores pointers to key and value tuples.  For each record with a new key, we copy the key and create the aggregation value buffer for that key and put them in a buffer. The hash table then simply stores pointers to the key and value. For each record with an existing key, we simply run the aggregation function to update the values in place.\r\n\r\nThis map is implemented using open hashing with triangular sequence probing.  Each entry stores two words in a long array: the first word stores the address of the key and the second word stores the relative offset from the key tuple to the value tuple, as well as the key's 32-bit hashcode.  By storing the full hashcode, we reduce the number of equality checks that need to be performed to handle position collisions ()since the chance of hashcode collision is much lower than position collision).\r\n\r\n`UnsafeFixedWidthAggregationMap` allows regular Spark SQL `Row` objects to be used when probing the map.  Internally, it encodes these rows into `UnsafeRow` format using `UnsafeRowConverter`.  This conversion has a small overhead that can be eliminated in the future once we use UnsafeRows in other operators.","created_at":"2015-04-27T18:36:58Z","updated_at":"2015-04-28T05:47:35Z","closed_at":null,"merged_at":null,"merge_commit_sha":"edbad774e0949d40674bf39034bbe4fccab7e36c","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/apache/spark/pulls/5725/commits","review_comments_url":"https://api.github.com/repos/apache/spark/pulls/5725/comments","review_comment_url":"https://api.github.com/repos/apache/spark/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/spark/issues/5725/comments","statuses_url":"https://api.github.com/repos/apache/spark/statuses/162caf74c15952f6ae0482c1fa74529a0289b039","head":{"label":"JoshRosen:unsafe","ref":"unsafe","sha":"162caf74c15952f6ae0482c1fa74529a0289b039","user":{"login":"JoshRosen","id":50748,"avatar_url":"https://avatars.githubusercontent.com/u/50748?v=3","gravatar_id":"","url":"https://api.github.com/users/JoshRosen","html_url":"https://github.com/JoshRosen","followers_url":"https://api.github.com/users/JoshRosen/followers","following_url":"https://api.github.com/users/JoshRosen/following{/other_user}","gists_url":"https://api.github.com/users/JoshRosen/gists{/gist_id}","starred_url":"https://api.github.com/users/JoshRosen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JoshRosen/subscriptions","organizations_url":"https://api.github.com/users/JoshRosen/orgs","repos_url":"https://api.github.com/users/JoshRosen/repos","events_url":"https://api.github.com/users/JoshRosen/events{/privacy}","received_events_url":"https://api.github.com/users/JoshRosen/received_events","type":"User","site_admin":false},"repo":{"id":22238710,"name":"spark","full_name":"JoshRosen/spark","owner":{"login":"JoshRosen","id":50748,"avatar_url":"https://avatars.githubusercontent.com/u/50748?v=3","gravatar_id":"","url":"https://api.github.com/users/JoshRosen","html_url":"https://github.com/JoshRosen","followers_url":"https://api.github.com/users/JoshRosen/followers","following_url":"https://api.github.com/users/JoshRosen/following{/other_user}","gists_url":"https://api.github.com/users/JoshRosen/gists{/gist_id}","starred_url":"https://api.github.com/users/JoshRosen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JoshRosen/subscriptions","organizations_url":"https://api.github.com/users/JoshRosen/orgs","repos_url":"https://api.github.com/users/JoshRosen/repos","events_url":"https://api.github.com/users/JoshRosen/events{/privacy}","received_events_url":"https://api.github.com/users/JoshRosen/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/JoshRosen/spark","description":"Mirror of Apache Spark","fork":true,"url":"https://api.github.com/repos/JoshRosen/spark","forks_url":"https://api.github.com/repos/JoshRosen/spark/forks","keys_url":"https://api.github.com/repos/JoshRosen/spark/keys{/key_id}","collaborators_url":"https://api.github.com/repos/JoshRosen/spark/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/JoshRosen/spark/teams","hooks_url":"https://api.github.com/repos/JoshRosen/spark/hooks","issue_events_url":"https://api.github.com/repos/JoshRosen/spark/issues/events{/number}","events_url":"https://api.github.com/repos/JoshRosen/spark/events","assignees_url":"https://api.github.com/repos/JoshRosen/spark/assignees{/user}","branches_url":"https://api.github.com/repos/JoshRosen/spark/branches{/branch}","tags_url":"https://api.github.com/repos/JoshRosen/spark/tags","blobs_url":"https://api.github.com/repos/JoshRosen/spark/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/JoshRosen/spark/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/JoshRosen/spark/git/refs{/sha}","trees_url":"https://api.github.com/repos/JoshRosen/spark/git/trees{/sha}","statuses_url":"https://api.github.com/repos/JoshRosen/spark/statuses/{sha}","languages_url":"https://api.github.com/repos/JoshRosen/spark/languages","stargazers_url":"https://api.github.com/repos/JoshRosen/spark/stargazers","contributors_url":"https://api.github.com/repos/JoshRosen/spark/contributors","subscribers_url":"https://api.github.com/repos/JoshRosen/spark/subscribers","subscription_url":"https://api.github.com/repos/JoshRosen/spark/subscription","commits_url":"https://api.github.com/repos/JoshRosen/spark/commits{/sha}","git_commits_url":"https://api.github.com/repos/JoshRosen/spark/git/commits{/sha}","comments_url":"https://api.github.com/repos/JoshRosen/spark/comments{/number}","issue_comment_url":"https://api.github.com/repos/JoshRosen/spark/issues/comments{/number}","contents_url":"https://api.github.com/repos/JoshRosen/spark/contents/{+path}","compare_url":"https://api.github.com/repos/JoshRosen/spark/compare/{base}...{head}","merges_url":"https://api.github.com/repos/JoshRosen/spark/merges","archive_url":"https://api.github.com/repos/JoshRosen/spark/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/JoshRosen/spark/downloads","issues_url":"https://api.github.com/repos/JoshRosen/spark/issues{/number}","pulls_url":"https://api.github.com/repos/JoshRosen/spark/pulls{/number}","milestones_url":"https://api.github.com/repos/JoshRosen/spark/milestones{/number}","notifications_url":"https://api.github.com/repos/JoshRosen/spark/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/JoshRosen/spark/labels{/name}","releases_url":"https://api.github.com/repos/JoshRosen/spark/releases{/id}","created_at":"2014-07-25T00:47:52Z","updated_at":"2015-04-22T03:24:31Z","pushed_at":"2015-04-28T05:20:35Z","git_url":"git://github.com/JoshRosen/spark.git","ssh_url":"git@github.com:JoshRosen/spark.git","clone_url":"https://github.com/JoshRosen/spark.git","svn_url":"https://github.com/JoshRosen/spark","homepage":null,"size":101148,"stargazers_count":1,"watchers_count":1,"language":"Scala","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":0,"forks":2,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"apache:master","ref":"master","sha":"998aac21f0a0588a70f8cf123ae4080163c612fb","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":17165658,"name":"spark","full_name":"apache/spark","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/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}","created_at":"2014-02-25T08:00:08Z","updated_at":"2015-04-28T04:46:09Z","pushed_at":"2015-04-28T05:22:02Z","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":1551445,"stargazers_count":3773,"watchers_count":3773,"language":"Scala","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":3284,"mirror_url":"git://git.apache.org/spark.git","open_issues_count":306,"forks":3284,"open_issues":306,"watchers":3773,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/spark/pulls/5725"},"html":{"href":"https://github.com/apache/spark/pull/5725"},"issue":{"href":"https://api.github.com/repos/apache/spark/issues/5725"},"comments":{"href":"https://api.github.com/repos/apache/spark/issues/5725/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/spark/pulls/5725/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/spark/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/spark/pulls/5725/commits"},"statuses":{"href":"https://api.github.com/repos/apache/spark/statuses/162caf74c15952f6ae0482c1fa74529a0289b039"}}}}