{"action":"created","comment":{"url":"https://api.github.com/repos/facebook/rocksdb/pulls/comments/86465177","pull_request_review_id":7124524,"id":86465177,"diff_hunk":"@@ -529,63 +587,123 @@ InlineSkipList<Comparator>::AllocateNode(size_t key_size, int height) {\n }\n \n template <class Comparator>\n-void InlineSkipList<Comparator>::Insert(const char* key) {\n-  // InsertConcurrently often can't maintain the prev_ invariants, so\n-  // it just sets prev_height_ to zero, letting us know that we should\n-  // ignore it.  A relaxed load suffices here because write thread\n-  // synchronization separates Insert calls from InsertConcurrently calls.\n-  auto prev_height = prev_height_.load(std::memory_order_relaxed);\n-\n-  // fast path for sequential insertion\n-  if (prev_height > 0 && !KeyIsAfterNode(key, prev_[0]->NoBarrier_Next(0)) &&\n-      (prev_[0] == head_ || KeyIsAfterNode(key, prev_[0]))) {\n-    assert(prev_[0] != head_ || (prev_height == 1 && GetMaxHeight() == 1));\n-\n-    // Outside of this method prev_[1..max_height_] is the predecessor\n-    // of prev_[0], and prev_height_ refers to prev_[0].  Inside Insert\n-    // prev_[0..max_height - 1] is the predecessor of key.  Switch from\n-    // the external state to the internal\n-    for (int i = 1; i < prev_height; i++) {\n-      prev_[i] = prev_[0];\n-    }\n-  } else {\n-    // TODO(opt): we could use a NoBarrier predecessor search as an\n-    // optimization for architectures where memory_order_acquire needs\n-    // a synchronization instruction.  Doesn't matter on x86\n-    FindLessThan(key, prev_);\n+typename InlineSkipList<Comparator>::InsertHint*\n+InlineSkipList<Comparator>::AllocateInsertHint() {\n+  InsertHint* hint = reinterpret_cast<InsertHint*>(allocator_->AllocateAligned(\n+      sizeof(InsertHint) + sizeof(Node*) * (kMaxHeight_)));\n+  hint->last_height = 0;\n+  hint->prev_height = 1;\n+  for (int i = 0; i < kMaxHeight_; i++) {\n+    hint->prev[i] = head_;\n   }\n+  return hint;\n+}\n \n-  // Our data structure does not allow duplicate insertion\n-  assert(prev_[0]->Next(0) == nullptr || !Equal(key, prev_[0]->Next(0)->Key()));\n-\n+template <class Comparator>\n+typename InlineSkipList<Comparator>::Node*\n+InlineSkipList<Comparator>::GetNodeForInsert(const char* key, int* height) {\n   // Find the Node that we placed before the key in AllocateKey\n   Node* x = reinterpret_cast<Node*>(const_cast<char*>(key)) - 1;\n-  int height = x->UnstashHeight();\n-  assert(height >= 1 && height <= kMaxHeight_);\n-\n-  if (height > GetMaxHeight()) {\n-    for (int i = GetMaxHeight(); i < height; i++) {\n-      prev_[i] = head_;\n-    }\n+  assert(height != nullptr);\n+  *height = x->UnstashHeight();\n+  assert(*height >= 1 && *height <= kMaxHeight_);\n \n+  if (*height > GetMaxHeight()) {\n     // It is ok to mutate max_height_ without any synchronization\n     // with concurrent readers.  A concurrent reader that observes\n     // the new value of max_height_ will see either the old value of\n     // new level pointers from head_ (nullptr), or a new value set in\n     // the loop below.  In the former case the reader will\n     // immediately drop to the next level since nullptr sorts after all\n     // keys.  In the latter case the reader will use the new node.\n-    max_height_.store(height, std::memory_order_relaxed);\n+    max_height_.store(*height, std::memory_order_relaxed);\n+  }\n+\n+  return x;\n+}\n+\n+template <class Comparator>\n+void InlineSkipList<Comparator>::Insert(const char* key) {\n+  int height = 0;\n+  Node* x = GetNodeForInsert(key, &height);\n+\n+  // InsertConcurrently often can't maintain the prev_ invariants, so\n+  // it just sets prev_height_ to zero, letting us know that we should\n+  // ignore it.  A relaxed load suffices here because write thread\n+  // synchronization separates Insert calls from InsertConcurrently calls.\n+\n+  // Outside of this method prev_[1..max_height_] is the predecessor\n+  // of prev_[0], and prev_height_ refers to prev_[0].  Inside Insert\n+  // prev_[0..max_height - 1] is the predecessor of key.  Switch from\n+  // the external state to the internal\n+\n+  bool hint_valid = hint_valid_.exchange(true, std::memory_order_relaxed);\n+  if (!hint_valid || !KeyIsAfterNode(key, hint_->Last()) ||\n+      KeyIsAfterNode(key, hint_->Last()->NoBarrier_Next(0))) {\n+    // TODO(opt): we could use a NoBarrier predecessor search as an\n+    // optimization for architectures where memory_order_acquire needs\n+    // a synchronization instruction.  Doesn't matter on x86\n+    FindLessThan(key, hint_->prev);\n+    hint_->last_height = 0;\n   }\n \n-  for (int i = 0; i < height; i++) {\n-    // NoBarrier_SetNext() suffices since we will add a barrier when\n-    // we publish a pointer to \"x\" in prev[i].\n-    x->NoBarrier_SetNext(i, prev_[i]->NoBarrier_Next(i));\n-    prev_[i]->SetNext(i, x);\n+  // Our data structure does not allow duplicate insertion\n+  assert(hint_->prev[0]->Next(0) == nullptr ||\n+      !Equal(key, hint_->prev[0]->Next(0)->Key()));\n+\n+  hint_->PushLast(x, height);\n+}\n+\n+template <class Comparator>\n+void InlineSkipList<Comparator>::InsertWithHint(\n+    const char* key, InsertHint** hint_ptr) {\n+  hint_valid_.store(false, std::memory_order_relaxed);","path":"db/inlineskiplist.h","position":284,"original_position":284,"commit_id":"b8a277428bbcab59ca23db19b8739f9593c3b74e","original_commit_id":"b8a277428bbcab59ca23db19b8739f9593c3b74e","user":{"login":"siying","id":5334567,"avatar_url":"https://avatars.githubusercontent.com/u/5334567?v=3","gravatar_id":"","url":"https://api.github.com/users/siying","html_url":"https://github.com/siying","followers_url":"https://api.github.com/users/siying/followers","following_url":"https://api.github.com/users/siying/following{/other_user}","gists_url":"https://api.github.com/users/siying/gists{/gist_id}","starred_url":"https://api.github.com/users/siying/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/siying/subscriptions","organizations_url":"https://api.github.com/users/siying/orgs","repos_url":"https://api.github.com/users/siying/repos","events_url":"https://api.github.com/users/siying/events{/privacy}","received_events_url":"https://api.github.com/users/siying/received_events","type":"User","site_admin":false},"body":"Why?","created_at":"2016-11-03T23:30:06Z","updated_at":"2016-11-03T23:55:56Z","html_url":"https://github.com/facebook/rocksdb/pull/1449#discussion_r86465177","pull_request_url":"https://api.github.com/repos/facebook/rocksdb/pulls/1449","_links":{"self":{"href":"https://api.github.com/repos/facebook/rocksdb/pulls/comments/86465177"},"html":{"href":"https://github.com/facebook/rocksdb/pull/1449#discussion_r86465177"},"pull_request":{"href":"https://api.github.com/repos/facebook/rocksdb/pulls/1449"}}},"pull_request":{"url":"https://api.github.com/repos/facebook/rocksdb/pulls/1449","id":91688429,"html_url":"https://github.com/facebook/rocksdb/pull/1449","diff_url":"https://github.com/facebook/rocksdb/pull/1449.diff","patch_url":"https://github.com/facebook/rocksdb/pull/1449.patch","issue_url":"https://api.github.com/repos/facebook/rocksdb/issues/1449","number":1449,"state":"open","locked":false,"title":"Optimize sequential insert into memtable - Part 2: Implementation","user":{"login":"yiwu-arbug","id":2606959,"avatar_url":"https://avatars.githubusercontent.com/u/2606959?v=3","gravatar_id":"","url":"https://api.github.com/users/yiwu-arbug","html_url":"https://github.com/yiwu-arbug","followers_url":"https://api.github.com/users/yiwu-arbug/followers","following_url":"https://api.github.com/users/yiwu-arbug/following{/other_user}","gists_url":"https://api.github.com/users/yiwu-arbug/gists{/gist_id}","starred_url":"https://api.github.com/users/yiwu-arbug/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yiwu-arbug/subscriptions","organizations_url":"https://api.github.com/users/yiwu-arbug/orgs","repos_url":"https://api.github.com/users/yiwu-arbug/repos","events_url":"https://api.github.com/users/yiwu-arbug/events{/privacy}","received_events_url":"https://api.github.com/users/yiwu-arbug/received_events","type":"User","site_admin":false},"body":"Summary:\r\nSee #1419 for the interface part.\r\n\r\nImplement a insert hint into skip-list to hint insert position. This is\r\nto optimize for the write workload where there are multiple stream of\r\nsequential writes. For example, there is a stream of keys of a1, a2,\r\na3... but also b1, b2, b2... Each stream are not neccessary strictly\r\nsequential, but can get reorder a little bit. User can specify a prefix\r\nextractor and the `SkipListRep` can thus maintan a hint for each of the\r\nstream for fast insert into memtable.\r\n\r\nWe assume that all keys using the same hint are consecutive in the\r\nskiplist, and no other keys will be insert between them (this is true\r\nsince we group keys by prefixes).  A hint is basically a prev pointer to\r\nthe largest key inserted with the same hint. Since we don't want to\r\nupdate all the other hints when we insert into skip-list, we maintain a\r\nweaker form of prev pointer. Let H be the maximum height previously\r\ninserted for the hint, and K being the largest key:\r\n* prev[0] == K,\r\n* prev[i + 1] < prev[i]\r\n* for i < H, prev[i]->Next(i) == K,\r\n* for i >= H, prev[i]->Next(i) <= K.\r\nActually for levels above H, prev[i] is a cache of prev pointer. Before\r\nusing them (if needed) we need to check if they are still valid, or\r\nrecompute them. To insert a key K1 of height H1, there are several cases:\r\n1. if K1 > K, insert K1 after K and update the hint.\r\n2. if K1 < K, find the smallest i with i >= H1 and prev[i] < K1, and\r\nthen binary search from prev[i] on level i.\r\n\r\nI don't have strict proof of how many key comparisons we will do. But\r\nsuppose each key in each of the stream can be reordered up to w\r\npositions, where w is a small constant. We will likely to do a binary\r\nsearch starting from level of max(w, h1), where h1 is the height of the\r\nnew key. Thus number of comparison should likely to be O(log(w) + avg_height)\r\n= O(1).\r\n\r\nI ran a benchmark to insert 5M keys into a memtable, with w = 5. Value\r\nsize is 10. The result:\r\n                without hint            with hint\r\n  #streams      us/op   # key compare   us/op   # key comparison\r\n  1             ~0.8    ~140M           ~0.40   ~29M\r\n  10            ~1.1    ~190M           ~0.41   ~29M\r\n  10000         ~1.9    ~190M           ~0.64   ~32M\r\n\r\nThere's still small room for improve. I'll tune the code a little bit\r\nand update inline comments, tests and benchmarks soon.\r\n\r\nTest Plan:\r\nwill update test.","created_at":"2016-10-31T20:53:09Z","updated_at":"2016-11-03T23:55:56Z","closed_at":null,"merged_at":null,"merge_commit_sha":"d4d206f0941887bffb97e82d9cfcb9621590c998","assignee":{"login":"siying","id":5334567,"avatar_url":"https://avatars.githubusercontent.com/u/5334567?v=3","gravatar_id":"","url":"https://api.github.com/users/siying","html_url":"https://github.com/siying","followers_url":"https://api.github.com/users/siying/followers","following_url":"https://api.github.com/users/siying/following{/other_user}","gists_url":"https://api.github.com/users/siying/gists{/gist_id}","starred_url":"https://api.github.com/users/siying/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/siying/subscriptions","organizations_url":"https://api.github.com/users/siying/orgs","repos_url":"https://api.github.com/users/siying/repos","events_url":"https://api.github.com/users/siying/events{/privacy}","received_events_url":"https://api.github.com/users/siying/received_events","type":"User","site_admin":false},"assignees":[{"login":"siying","id":5334567,"avatar_url":"https://avatars.githubusercontent.com/u/5334567?v=3","gravatar_id":"","url":"https://api.github.com/users/siying","html_url":"https://github.com/siying","followers_url":"https://api.github.com/users/siying/followers","following_url":"https://api.github.com/users/siying/following{/other_user}","gists_url":"https://api.github.com/users/siying/gists{/gist_id}","starred_url":"https://api.github.com/users/siying/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/siying/subscriptions","organizations_url":"https://api.github.com/users/siying/orgs","repos_url":"https://api.github.com/users/siying/repos","events_url":"https://api.github.com/users/siying/events{/privacy}","received_events_url":"https://api.github.com/users/siying/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/facebook/rocksdb/pulls/1449/commits","review_comments_url":"https://api.github.com/repos/facebook/rocksdb/pulls/1449/comments","review_comment_url":"https://api.github.com/repos/facebook/rocksdb/pulls/comments{/number}","comments_url":"https://api.github.com/repos/facebook/rocksdb/issues/1449/comments","statuses_url":"https://api.github.com/repos/facebook/rocksdb/statuses/b8a277428bbcab59ca23db19b8739f9593c3b74e","head":{"label":"yiwu-arbug:insert_hint","ref":"insert_hint","sha":"b8a277428bbcab59ca23db19b8739f9593c3b74e","user":{"login":"yiwu-arbug","id":2606959,"avatar_url":"https://avatars.githubusercontent.com/u/2606959?v=3","gravatar_id":"","url":"https://api.github.com/users/yiwu-arbug","html_url":"https://github.com/yiwu-arbug","followers_url":"https://api.github.com/users/yiwu-arbug/followers","following_url":"https://api.github.com/users/yiwu-arbug/following{/other_user}","gists_url":"https://api.github.com/users/yiwu-arbug/gists{/gist_id}","starred_url":"https://api.github.com/users/yiwu-arbug/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yiwu-arbug/subscriptions","organizations_url":"https://api.github.com/users/yiwu-arbug/orgs","repos_url":"https://api.github.com/users/yiwu-arbug/repos","events_url":"https://api.github.com/users/yiwu-arbug/events{/privacy}","received_events_url":"https://api.github.com/users/yiwu-arbug/received_events","type":"User","site_admin":false},"repo":{"id":68760384,"name":"rocksdb","full_name":"yiwu-arbug/rocksdb","owner":{"login":"yiwu-arbug","id":2606959,"avatar_url":"https://avatars.githubusercontent.com/u/2606959?v=3","gravatar_id":"","url":"https://api.github.com/users/yiwu-arbug","html_url":"https://github.com/yiwu-arbug","followers_url":"https://api.github.com/users/yiwu-arbug/followers","following_url":"https://api.github.com/users/yiwu-arbug/following{/other_user}","gists_url":"https://api.github.com/users/yiwu-arbug/gists{/gist_id}","starred_url":"https://api.github.com/users/yiwu-arbug/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yiwu-arbug/subscriptions","organizations_url":"https://api.github.com/users/yiwu-arbug/orgs","repos_url":"https://api.github.com/users/yiwu-arbug/repos","events_url":"https://api.github.com/users/yiwu-arbug/events{/privacy}","received_events_url":"https://api.github.com/users/yiwu-arbug/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/yiwu-arbug/rocksdb","description":"A library that provides an embeddable, persistent key-value store for fast storage.","fork":true,"url":"https://api.github.com/repos/yiwu-arbug/rocksdb","forks_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/forks","keys_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/keys{/key_id}","collaborators_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/teams","hooks_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/hooks","issue_events_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/issues/events{/number}","events_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/events","assignees_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/assignees{/user}","branches_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/branches{/branch}","tags_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/tags","blobs_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/git/refs{/sha}","trees_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/git/trees{/sha}","statuses_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/statuses/{sha}","languages_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/languages","stargazers_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/stargazers","contributors_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/contributors","subscribers_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/subscribers","subscription_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/subscription","commits_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/commits{/sha}","git_commits_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/git/commits{/sha}","comments_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/comments{/number}","issue_comment_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/issues/comments{/number}","contents_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/contents/{+path}","compare_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/compare/{base}...{head}","merges_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/merges","archive_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/downloads","issues_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/issues{/number}","pulls_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/pulls{/number}","milestones_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/milestones{/number}","notifications_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/labels{/name}","releases_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/releases{/id}","deployments_url":"https://api.github.com/repos/yiwu-arbug/rocksdb/deployments","created_at":"2016-09-20T23:06:58Z","updated_at":"2016-09-20T23:07:03Z","pushed_at":"2016-11-02T22:52:28Z","git_url":"git://github.com/yiwu-arbug/rocksdb.git","ssh_url":"git@github.com:yiwu-arbug/rocksdb.git","clone_url":"https://github.com/yiwu-arbug/rocksdb.git","svn_url":"https://github.com/yiwu-arbug/rocksdb","homepage":"http://rocksdb.org","size":46591,"stargazers_count":0,"watchers_count":0,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"facebook:master","ref":"master","sha":"6a4faee5cd75e2abe9d61cb7c7c39361c85ece52","user":{"login":"facebook","id":69631,"avatar_url":"https://avatars.githubusercontent.com/u/69631?v=3","gravatar_id":"","url":"https://api.github.com/users/facebook","html_url":"https://github.com/facebook","followers_url":"https://api.github.com/users/facebook/followers","following_url":"https://api.github.com/users/facebook/following{/other_user}","gists_url":"https://api.github.com/users/facebook/gists{/gist_id}","starred_url":"https://api.github.com/users/facebook/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/facebook/subscriptions","organizations_url":"https://api.github.com/users/facebook/orgs","repos_url":"https://api.github.com/users/facebook/repos","events_url":"https://api.github.com/users/facebook/events{/privacy}","received_events_url":"https://api.github.com/users/facebook/received_events","type":"Organization","site_admin":false},"repo":{"id":6934395,"name":"rocksdb","full_name":"facebook/rocksdb","owner":{"login":"facebook","id":69631,"avatar_url":"https://avatars.githubusercontent.com/u/69631?v=3","gravatar_id":"","url":"https://api.github.com/users/facebook","html_url":"https://github.com/facebook","followers_url":"https://api.github.com/users/facebook/followers","following_url":"https://api.github.com/users/facebook/following{/other_user}","gists_url":"https://api.github.com/users/facebook/gists{/gist_id}","starred_url":"https://api.github.com/users/facebook/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/facebook/subscriptions","organizations_url":"https://api.github.com/users/facebook/orgs","repos_url":"https://api.github.com/users/facebook/repos","events_url":"https://api.github.com/users/facebook/events{/privacy}","received_events_url":"https://api.github.com/users/facebook/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/facebook/rocksdb","description":"A library that provides an embeddable, persistent key-value store for fast storage.","fork":false,"url":"https://api.github.com/repos/facebook/rocksdb","forks_url":"https://api.github.com/repos/facebook/rocksdb/forks","keys_url":"https://api.github.com/repos/facebook/rocksdb/keys{/key_id}","collaborators_url":"https://api.github.com/repos/facebook/rocksdb/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/facebook/rocksdb/teams","hooks_url":"https://api.github.com/repos/facebook/rocksdb/hooks","issue_events_url":"https://api.github.com/repos/facebook/rocksdb/issues/events{/number}","events_url":"https://api.github.com/repos/facebook/rocksdb/events","assignees_url":"https://api.github.com/repos/facebook/rocksdb/assignees{/user}","branches_url":"https://api.github.com/repos/facebook/rocksdb/branches{/branch}","tags_url":"https://api.github.com/repos/facebook/rocksdb/tags","blobs_url":"https://api.github.com/repos/facebook/rocksdb/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/facebook/rocksdb/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/facebook/rocksdb/git/refs{/sha}","trees_url":"https://api.github.com/repos/facebook/rocksdb/git/trees{/sha}","statuses_url":"https://api.github.com/repos/facebook/rocksdb/statuses/{sha}","languages_url":"https://api.github.com/repos/facebook/rocksdb/languages","stargazers_url":"https://api.github.com/repos/facebook/rocksdb/stargazers","contributors_url":"https://api.github.com/repos/facebook/rocksdb/contributors","subscribers_url":"https://api.github.com/repos/facebook/rocksdb/subscribers","subscription_url":"https://api.github.com/repos/facebook/rocksdb/subscription","commits_url":"https://api.github.com/repos/facebook/rocksdb/commits{/sha}","git_commits_url":"https://api.github.com/repos/facebook/rocksdb/git/commits{/sha}","comments_url":"https://api.github.com/repos/facebook/rocksdb/comments{/number}","issue_comment_url":"https://api.github.com/repos/facebook/rocksdb/issues/comments{/number}","contents_url":"https://api.github.com/repos/facebook/rocksdb/contents/{+path}","compare_url":"https://api.github.com/repos/facebook/rocksdb/compare/{base}...{head}","merges_url":"https://api.github.com/repos/facebook/rocksdb/merges","archive_url":"https://api.github.com/repos/facebook/rocksdb/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/facebook/rocksdb/downloads","issues_url":"https://api.github.com/repos/facebook/rocksdb/issues{/number}","pulls_url":"https://api.github.com/repos/facebook/rocksdb/pulls{/number}","milestones_url":"https://api.github.com/repos/facebook/rocksdb/milestones{/number}","notifications_url":"https://api.github.com/repos/facebook/rocksdb/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/facebook/rocksdb/labels{/name}","releases_url":"https://api.github.com/repos/facebook/rocksdb/releases{/id}","deployments_url":"https://api.github.com/repos/facebook/rocksdb/deployments","created_at":"2012-11-30T06:16:18Z","updated_at":"2016-11-03T23:16:00Z","pushed_at":"2016-11-03T23:25:25Z","git_url":"git://github.com/facebook/rocksdb.git","ssh_url":"git@github.com:facebook/rocksdb.git","clone_url":"https://github.com/facebook/rocksdb.git","svn_url":"https://github.com/facebook/rocksdb","homepage":"http://rocksdb.org","size":129343,"stargazers_count":6364,"watchers_count":6364,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":1320,"mirror_url":null,"open_issues_count":284,"forks":1320,"open_issues":284,"watchers":6364,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/facebook/rocksdb/pulls/1449"},"html":{"href":"https://github.com/facebook/rocksdb/pull/1449"},"issue":{"href":"https://api.github.com/repos/facebook/rocksdb/issues/1449"},"comments":{"href":"https://api.github.com/repos/facebook/rocksdb/issues/1449/comments"},"review_comments":{"href":"https://api.github.com/repos/facebook/rocksdb/pulls/1449/comments"},"review_comment":{"href":"https://api.github.com/repos/facebook/rocksdb/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/facebook/rocksdb/pulls/1449/commits"},"statuses":{"href":"https://api.github.com/repos/facebook/rocksdb/statuses/b8a277428bbcab59ca23db19b8739f9593c3b74e"}}}}
{"actor":{"display_login":"siying"}}