{"action":"created","comment":{"url":"https://api.github.com/repos/bloomberg/comdb2/pulls/comments/129602549","pull_request_review_id":52393672,"id":129602549,"diff_hunk":"@@ -0,0 +1,523 @@\n+#include \"comdb2ar.h\"\n+\n+#include \"increment.h\"\n+#include \"glue.h\"\n+#include \"db_wrap.h\"\n+#include \"serialiseerror.h\"\n+#include \"error.h\"\n+#include \"tar_header.h\"\n+#include \"riia.h\"\n+\n+#include <sys/stat.h>\n+#include <fstream>\n+#include <cstring>\n+#include <sstream>\n+#include <iostream>\n+#include <cassert>\n+\n+#include <vector>\n+#include <set>\n+#include <map>\n+#include <utility>\n+#include <fcntl.h>\n+#include <unistd.h>\n+\n+bool is_not_incr_file(std::string filename){\n+    return((filename.substr(filename.length() - 5) != \".incr\") &&\n+            (filename.substr(filename.length() - 4) != \".sha\"));\n+}\n+\n+// Read the SHA file to get the fingerprint of the previous increment\n+std::string get_sha_fingerprint(std::string filename, std::string incr_path) {\n+    std::string filepath = incr_path + \"/\" + filename;\n+    std::ifstream ifs (filepath, std::ifstream::in);\n+\n+    char sha_buffer[40];\n+    ifs.read(&sha_buffer[0], 40);\n+\n+    std::clog << \"Found previous fingerprint as \" << std::string(sha_buffer) << std::endl;\n+\n+    return std::string(sha_buffer);\n+}\n+\n+// Read from STDIN a serialised text file with the SHA fingerprint\n+std::string read_serialised_sha_file() {\n+    char fingerprint[40];\n+\n+    size_t bufsize = 4096;\n+    uint8_t *buf;\n+#if defined _HP_SOURCE || defined _SUN_SOURCE\n+    buf = (uint8_t*) memalign(512, bufsize);\n+#else\n+    if (posix_memalign((void**) &buf, 512, bufsize))\n+        throw Error(\"Failed to allocate output buffer\");\n+#endif\n+    RIIA_malloc free_guard(buf);\n+\n+    if(readall(0, &fingerprint[0], 40) != 40){\n+        std::ostringstream ss;\n+        ss << \"Could not read sha fingerprint file\";\n+        throw Error(ss);\n+    }\n+\n+    // Read and discard the null padding\n+    unsigned long long nblocks = (40 + 511ULL) >> 9;\n+    unsigned long long padding_bytes = (nblocks << 9) - 40;\n+    if(padding_bytes) {\n+        if(readall(0, &buf[0], padding_bytes) != padding_bytes) {\n+            std::ostringstream ss;\n+\n+            ss << \"Error reading padding after in SHA file\";\n+            throw Error(ss);\n+        }\n+    }\n+\n+    std::clog << \"Read SHA as: \" << std::string(fingerprint, 40) << std::endl;\n+    return std::string(fingerprint, 40);\n+}\n+\n+// Determine whether the file has changed, ie if the page's current LSN + Checksum\n+// is the same as it is in the .incr diff file\n+bool assert_cksum_lsn(uint8_t *new_pagep, uint8_t *old_pagep, size_t pagesize) {\n+    uint32_t new_lsn_file = LSN(new_pagep).file;\n+    uint32_t new_lsn_offs = LSN(new_pagep).offset;\n+    bool verify_ret;\n+    uint32_t new_cksum;\n+    verify_checksum(new_pagep, pagesize, false, false, &verify_ret, &new_cksum);\n+\n+    uint8_t cmp_arr[12];\n+    for (int i = 0; i < 4; ++i){\n+        cmp_arr[i] = ((uint8_t *) &new_lsn_file)[i];\n+        cmp_arr[4 + i] = ((uint8_t *) &new_lsn_offs)[i];\n+        cmp_arr[8 + i] = ((uint8_t *) &new_cksum)[i];\n+    }\n+\n+    return (memcmp(cmp_arr, old_pagep, 12) != 0);\n+}\n+\n+// Compare the page with the diff file to determine whether it has changed - driver\n+// For each file, populate pages with the page numbers fo the changed pages\n+// populate data_size with the total amount of data that needs to be serialised\n+// Returns true if any part of the file needs to be serialised\n+bool compare_checksum(\n+    FileInfo file,\n+    const std::string& incr_path,\n+    std::vector<uint32_t>& pages,\n+    ssize_t *data_size,\n+    std::set<std::string>& incr_files\n+) {\n+    std::string filename = file.get_filename();\n+    std::string incr_file_name = incr_path + \"/\" + filename + \".incr\";\n+\n+    // Keep a set of all .incr diff files to determine if there are any remaining at the end\n+    // Any remaining .incr files indiciate deleted files\n+    std::set<std::string>::iterator it = incr_files.find(filename + \".incr\");\n+    if(it == incr_files.end()){\n+        std::ostringstream ss;\n+        ss << \"new incr file found mid backup of file: \" << filename << std::endl;\n+        throw SerialiseError(filename, ss.str());\n+    } else {\n+        incr_files.erase(it);\n+    }\n+\n+    struct stat sb;\n+    bool ret = false;\n+\n+    int flags = O_RDONLY | O_LARGEFILE;\n+    int new_fd = open(file.get_filepath().c_str(), flags);\n+    int old_fd = open(incr_file_name.c_str(), O_RDWR);\n+\n+    struct stat new_st;\n+    if(fstat(new_fd, &new_st) == -1) {\n+        std::ostringstream ss;\n+        ss << \"cannot stat file: \" << std::strerror(errno);\n+        throw SerialiseError(filename, ss.str());\n+    }\n+\n+    // For a new file, make pages empty (upon returning, an empty pages list\n+    // denotes a new file) and mark the size as the full size\n+    if(stat(incr_file_name.c_str(), &sb) != 0) {\n+        std::clog << \"New File: \" << filename << std::endl;\n+        *data_size = new_st.st_size;\n+        return true;\n+    // For returning files, go through each page and compare with the diff files\n+    } else {\n+\n+        size_t pagesize = file.get_pagesize();\n+        if(pagesize == 0) {\n+            pagesize = 4096;\n+        }\n+\n+        uint8_t *new_pagebuf = NULL;\n+        uint8_t old_pagebuf[12];\n+        bool file_expanded = false;\n+\n+#if ! defined  ( _SUN_SOURCE ) && ! defined ( _HP_SOURCE )\n+        posix_memalign((void**) &new_pagebuf, 512, pagesize);\n+#else\n+        new_pagebuf = (uint8_t*) memalign(512, pagesize);\n+#endif\n+\n+        size_t original_size = new_st.st_size;\n+        off_t bytesleft = new_st.st_size;\n+\n+        while(bytesleft >= pagesize) {\n+            ssize_t new_bytesread = read(new_fd, &new_pagebuf[0], pagesize);\n+\n+            if(new_bytesread <= 0) {\n+                std::ostringstream ss;\n+                ss << \"read error after \" << new_bytesread << \" bytes\";\n+                throw SerialiseError(filename, ss.str());\n+            }\n+\n+            // File has expamded by a reasonable amount, so add all remaining pages\n+            if(file_expanded) {\n+                pages.push_back(PGNO(new_pagebuf));\n+                *data_size += pagesize;\n+                continue;\n+            }\n+\n+            ssize_t old_bytesread = read(old_fd, &old_pagebuf[0], 12);\n+\n+            if(old_bytesread < 0){\n+                std::ostringstream ss;\n+                ss << \"read error after \" << new_bytesread << \" bytes\";\n+                throw SerialiseError(filename, ss.str());\n+            }\n+\n+            if(old_bytesread == 0) {\n+                // If the size has more than multiplied by a factor of 10, just treat it as a new file\n+                if ((float) bytesleft / (float) original_size > .9) {\n+                    pages.clear();\n+                    return true;\n+                // otherwise just add the remaining pages\n+                } else {\n+                    file_expanded = true;\n+                }\n+                break;\n+            }\n+\n+            // If a diff has been selected in a page, keep track of that page\n+            if (assert_cksum_lsn(new_pagebuf, old_pagebuf, pagesize)) {\n+                pages.push_back(PGNO(new_pagebuf));\n+                *data_size += pagesize;\n+                ret = true;\n+            }\n+\n+            bytesleft -= pagesize;\n+        }\n+\n+        if(new_pagebuf) free(new_pagebuf);\n+    }\n+    return ret;\n+}\n+\n+ssize_t serialise_incr_file(\n+    const FileInfo& file,\n+    std::vector<uint32_t> pages,\n+    std::string incr_path\n+)\n+// For a file with changed pages, go through each changed page and serialise it\n+{\n+    const std::string& filename = file.get_filename();\n+    const std::string& filepath = file.get_filepath();\n+\n+    int flags;\n+    bool skip_iomap = false;\n+    std::ostringstream ss;\n+\n+    // Ensure large file support\n+    assert(sizeof(off_t) == 8);\n+\n+    struct stat st;\n+    if(stat(filepath.c_str(), &st) == -1) {\n+        ss << \"cannot stat file: \" << std::strerror(errno);\n+        throw SerialiseError(filename, ss.str());\n+    }\n+\n+    size_t pagesize = file.get_pagesize();\n+    if(pagesize == 0) {\n+        pagesize = 4096;\n+    }\n+\n+    std::ifstream ifs (filepath, std::ifstream::in | std::ifstream::binary);\n+\n+    char *char_pagebuf = NULL;\n+    uint8_t *pagebuf = NULL;\n+\n+#if ! defined  ( _SUN_SOURCE ) && ! defined ( _HP_SOURCE )\n+    posix_memalign((void**) &char_pagebuf, 512, pagesize);\n+    posix_memalign((void**) &pagebuf, 512, pagesize);\n+#else\n+    char_pagebuf = (char*) memalign(512, pagesize);\n+    pagebuf = (uint8_t*) memalign(512, pagesize);\n+#endif\n+\n+    ssize_t total_read = 0;\n+    ssize_t total_written = 0;\n+\n+    std::string incrFilename = incr_path + \"/\" + filename + \".incr\";\n+\n+    std::ofstream incrFile(incrFilename, std::ofstream::out |\n+                            std::ofstream::in | std::ofstream::binary);\n+\n+    for(std::vector<uint32_t>::iterator\n+            it = pages.begin();\n+            it != pages.end();\n+            ++it){\n+\n+        ifs.seekg(pagesize * *it, ifs.beg);\n+        ifs.read(&char_pagebuf[0], pagesize);\n+        ssize_t bytes_read = ifs.gcount();\n+        if(bytes_read < pagesize) {\n+            std::ostringstream ss;\n+            ss << \"read error\";\n+            throw SerialiseError(filename, ss.str());\n+        }\n+\n+        std::memcpy(pagebuf, char_pagebuf, pagesize);\n+\n+        uint32_t cksum;\n+        bool cksum_verified;\n+        verify_checksum(pagebuf, pagesize, false, false,\n+                            &cksum_verified, &cksum);\n+        if(!cksum_verified){\n+            std::ostringstream ss;\n+            ss << \"serialise_file:page failed checksum verification\";\n+            throw SerialiseError(filename, ss.str());\n+        }\n+\n+        // Update the diff .incr file\n+        incrFile.seekp(12 * *it, incrFile.beg);\n+        PAGE * pagep = (PAGE *) pagebuf;\n+\n+        incrFile.write((char *) &(LSN(pagep).file), 4);\n+        incrFile.write((char *) &(LSN(pagep).offset), 4);\n+        incrFile.write((char *) &cksum, 4);\n+\n+        ssize_t bytes_written = writeall(1, pagebuf, pagesize);\n+        if(bytes_written != pagesize){\n+            std::ostringstream ss;\n+            ss << \"error writing text data: \" << std::strerror(errno);\n+            throw SerialiseError(filename, ss.str());\n+        }\n+\n+        total_read += bytes_read;\n+        total_written += bytes_written;\n+        if(total_written != total_read){\n+            std::ostringstream ss;\n+            ss << \"different amounts written and read. wrote \" << total_written\n+                << \" bytes and read \" << total_read << \" bytes \"\n+                << std::strerror(errno);\n+            throw SerialiseError(filename, ss.str());\n+        }\n+    }\n+\n+    if (pagebuf)\n+        free(pagebuf);\n+\n+    std::clog << \"a \" << filename << \" pages=[\";\n+    for(size_t i = 0; i < pages.size(); ++i){\n+        std::clog << pages[i];\n+        if(i != pages.size() - 1){\n+            std::clog << \" \";\n+        } else {\n+            std::clog << \"] \";\n+        }\n+    }\n+    std::clog << \"pagesize=\" << pagesize << std::endl;\n+\n+    return total_read;\n+}\n+\n+// Get the datetime as a string YYYYMMDDHHMMSS\n+std::string getDTString() {\n+    time_t rawtime;\n+    struct tm *timeinfo;\n+    char buffer[80];\n+\n+    time(&rawtime);\n+    timeinfo = localtime(&rawtime);\n+\n+    strftime(buffer, sizeof(buffer), \"%Y%m%d%I%M%S\", timeinfo);\n+    std::string str(buffer);\n+\n+    return str;\n+}\n+\n+void incr_deserialise_database(\n+    const std::string& lrldestdir,\n+    const std::string& datadestdir,\n+    const std::string& dbname,\n+    std::set<std::string>& table_set,\n+    std::string& sha_fingerprint,\n+    unsigned percent_full,\n+    bool force_mode,\n+    bool& is_disk_full,\n+    const std::string& incr_path,\n+    bool keep_all_logs","path":"tools/comdb2ar/increment.cpp","position":358,"original_position":358,"commit_id":"cfef95bf7b3c63e75ff59638efd6cb56c01def23","original_commit_id":"cfef95bf7b3c63e75ff59638efd6cb56c01def23","user":{"login":"markhannum","id":16245330,"avatar_url":"https://avatars2.githubusercontent.com/u/16245330?v=4","gravatar_id":"","url":"https://api.github.com/users/markhannum","html_url":"https://github.com/markhannum","followers_url":"https://api.github.com/users/markhannum/followers","following_url":"https://api.github.com/users/markhannum/following{/other_user}","gists_url":"https://api.github.com/users/markhannum/gists{/gist_id}","starred_url":"https://api.github.com/users/markhannum/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/markhannum/subscriptions","organizations_url":"https://api.github.com/users/markhannum/orgs","repos_url":"https://api.github.com/users/markhannum/repos","events_url":"https://api.github.com/users/markhannum/events{/privacy}","received_events_url":"https://api.github.com/users/markhannum/received_events","type":"User","site_admin":false},"body":"I think we discussed this one - we should never keep all logs from all the increments: full-recovery will never work if there are holes in the logstream.  Keep only the logfiles from the last increment.","created_at":"2017-07-26T15:14:42Z","updated_at":"2017-07-26T15:14:42Z","html_url":"https://github.com/bloomberg/comdb2/pull/265#discussion_r129602549","pull_request_url":"https://api.github.com/repos/bloomberg/comdb2/pulls/265","_links":{"self":{"href":"https://api.github.com/repos/bloomberg/comdb2/pulls/comments/129602549"},"html":{"href":"https://github.com/bloomberg/comdb2/pull/265#discussion_r129602549"},"pull_request":{"href":"https://api.github.com/repos/bloomberg/comdb2/pulls/265"}}},"pull_request":{"url":"https://api.github.com/repos/bloomberg/comdb2/pulls/265","id":132090883,"html_url":"https://github.com/bloomberg/comdb2/pull/265","diff_url":"https://github.com/bloomberg/comdb2/pull/265.diff","patch_url":"https://github.com/bloomberg/comdb2/pull/265.patch","issue_url":"https://api.github.com/repos/bloomberg/comdb2/issues/265","number":265,"state":"open","locked":false,"title":"Incremental backup","user":{"login":"dennis-wei","id":14832482,"avatar_url":"https://avatars3.githubusercontent.com/u/14832482?v=4","gravatar_id":"","url":"https://api.github.com/users/dennis-wei","html_url":"https://github.com/dennis-wei","followers_url":"https://api.github.com/users/dennis-wei/followers","following_url":"https://api.github.com/users/dennis-wei/following{/other_user}","gists_url":"https://api.github.com/users/dennis-wei/gists{/gist_id}","starred_url":"https://api.github.com/users/dennis-wei/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dennis-wei/subscriptions","organizations_url":"https://api.github.com/users/dennis-wei/orgs","repos_url":"https://api.github.com/users/dennis-wei/repos","events_url":"https://api.github.com/users/dennis-wei/events{/privacy}","received_events_url":"https://api.github.com/users/dennis-wei/received_events","type":"User","site_admin":false},"body":"Implemented incremental backups as an option in comdb2ar","created_at":"2017-07-24T16:24:44Z","updated_at":"2017-07-26T15:14:42Z","closed_at":null,"merged_at":null,"merge_commit_sha":"972a6a1f2ec3456e6e8fc387c34e62a74d6e7277","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/bloomberg/comdb2/pulls/265/commits","review_comments_url":"https://api.github.com/repos/bloomberg/comdb2/pulls/265/comments","review_comment_url":"https://api.github.com/repos/bloomberg/comdb2/pulls/comments{/number}","comments_url":"https://api.github.com/repos/bloomberg/comdb2/issues/265/comments","statuses_url":"https://api.github.com/repos/bloomberg/comdb2/statuses/cfef95bf7b3c63e75ff59638efd6cb56c01def23","head":{"label":"dennis-wei:finalise-incr","ref":"finalise-incr","sha":"cfef95bf7b3c63e75ff59638efd6cb56c01def23","user":{"login":"dennis-wei","id":14832482,"avatar_url":"https://avatars3.githubusercontent.com/u/14832482?v=4","gravatar_id":"","url":"https://api.github.com/users/dennis-wei","html_url":"https://github.com/dennis-wei","followers_url":"https://api.github.com/users/dennis-wei/followers","following_url":"https://api.github.com/users/dennis-wei/following{/other_user}","gists_url":"https://api.github.com/users/dennis-wei/gists{/gist_id}","starred_url":"https://api.github.com/users/dennis-wei/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dennis-wei/subscriptions","organizations_url":"https://api.github.com/users/dennis-wei/orgs","repos_url":"https://api.github.com/users/dennis-wei/repos","events_url":"https://api.github.com/users/dennis-wei/events{/privacy}","received_events_url":"https://api.github.com/users/dennis-wei/received_events","type":"User","site_admin":false},"repo":{"id":94027794,"name":"comdb2","full_name":"dennis-wei/comdb2","owner":{"login":"dennis-wei","id":14832482,"avatar_url":"https://avatars3.githubusercontent.com/u/14832482?v=4","gravatar_id":"","url":"https://api.github.com/users/dennis-wei","html_url":"https://github.com/dennis-wei","followers_url":"https://api.github.com/users/dennis-wei/followers","following_url":"https://api.github.com/users/dennis-wei/following{/other_user}","gists_url":"https://api.github.com/users/dennis-wei/gists{/gist_id}","starred_url":"https://api.github.com/users/dennis-wei/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dennis-wei/subscriptions","organizations_url":"https://api.github.com/users/dennis-wei/orgs","repos_url":"https://api.github.com/users/dennis-wei/repos","events_url":"https://api.github.com/users/dennis-wei/events{/privacy}","received_events_url":"https://api.github.com/users/dennis-wei/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/dennis-wei/comdb2","description":"Bloomberg's distributed RDBMS","fork":true,"url":"https://api.github.com/repos/dennis-wei/comdb2","forks_url":"https://api.github.com/repos/dennis-wei/comdb2/forks","keys_url":"https://api.github.com/repos/dennis-wei/comdb2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dennis-wei/comdb2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dennis-wei/comdb2/teams","hooks_url":"https://api.github.com/repos/dennis-wei/comdb2/hooks","issue_events_url":"https://api.github.com/repos/dennis-wei/comdb2/issues/events{/number}","events_url":"https://api.github.com/repos/dennis-wei/comdb2/events","assignees_url":"https://api.github.com/repos/dennis-wei/comdb2/assignees{/user}","branches_url":"https://api.github.com/repos/dennis-wei/comdb2/branches{/branch}","tags_url":"https://api.github.com/repos/dennis-wei/comdb2/tags","blobs_url":"https://api.github.com/repos/dennis-wei/comdb2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dennis-wei/comdb2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dennis-wei/comdb2/git/refs{/sha}","trees_url":"https://api.github.com/repos/dennis-wei/comdb2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dennis-wei/comdb2/statuses/{sha}","languages_url":"https://api.github.com/repos/dennis-wei/comdb2/languages","stargazers_url":"https://api.github.com/repos/dennis-wei/comdb2/stargazers","contributors_url":"https://api.github.com/repos/dennis-wei/comdb2/contributors","subscribers_url":"https://api.github.com/repos/dennis-wei/comdb2/subscribers","subscription_url":"https://api.github.com/repos/dennis-wei/comdb2/subscription","commits_url":"https://api.github.com/repos/dennis-wei/comdb2/commits{/sha}","git_commits_url":"https://api.github.com/repos/dennis-wei/comdb2/git/commits{/sha}","comments_url":"https://api.github.com/repos/dennis-wei/comdb2/comments{/number}","issue_comment_url":"https://api.github.com/repos/dennis-wei/comdb2/issues/comments{/number}","contents_url":"https://api.github.com/repos/dennis-wei/comdb2/contents/{+path}","compare_url":"https://api.github.com/repos/dennis-wei/comdb2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dennis-wei/comdb2/merges","archive_url":"https://api.github.com/repos/dennis-wei/comdb2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dennis-wei/comdb2/downloads","issues_url":"https://api.github.com/repos/dennis-wei/comdb2/issues{/number}","pulls_url":"https://api.github.com/repos/dennis-wei/comdb2/pulls{/number}","milestones_url":"https://api.github.com/repos/dennis-wei/comdb2/milestones{/number}","notifications_url":"https://api.github.com/repos/dennis-wei/comdb2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dennis-wei/comdb2/labels{/name}","releases_url":"https://api.github.com/repos/dennis-wei/comdb2/releases{/id}","deployments_url":"https://api.github.com/repos/dennis-wei/comdb2/deployments","created_at":"2017-06-11T19:44:49Z","updated_at":"2017-06-11T19:44:58Z","pushed_at":"2017-07-26T14:16:21Z","git_url":"git://github.com/dennis-wei/comdb2.git","ssh_url":"git@github.com:dennis-wei/comdb2.git","clone_url":"https://github.com/dennis-wei/comdb2.git","svn_url":"https://github.com/dennis-wei/comdb2","homepage":"","size":15913,"stargazers_count":0,"watchers_count":0,"language":"C","has_issues":false,"has_projects":true,"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":"bloomberg:master","ref":"master","sha":"de0c7b94ef943918ea8376afa9dc5512fa519cf9","user":{"login":"bloomberg","id":1416818,"avatar_url":"https://avatars2.githubusercontent.com/u/1416818?v=4","gravatar_id":"","url":"https://api.github.com/users/bloomberg","html_url":"https://github.com/bloomberg","followers_url":"https://api.github.com/users/bloomberg/followers","following_url":"https://api.github.com/users/bloomberg/following{/other_user}","gists_url":"https://api.github.com/users/bloomberg/gists{/gist_id}","starred_url":"https://api.github.com/users/bloomberg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bloomberg/subscriptions","organizations_url":"https://api.github.com/users/bloomberg/orgs","repos_url":"https://api.github.com/users/bloomberg/repos","events_url":"https://api.github.com/users/bloomberg/events{/privacy}","received_events_url":"https://api.github.com/users/bloomberg/received_events","type":"Organization","site_admin":false},"repo":{"id":91593042,"name":"comdb2","full_name":"bloomberg/comdb2","owner":{"login":"bloomberg","id":1416818,"avatar_url":"https://avatars2.githubusercontent.com/u/1416818?v=4","gravatar_id":"","url":"https://api.github.com/users/bloomberg","html_url":"https://github.com/bloomberg","followers_url":"https://api.github.com/users/bloomberg/followers","following_url":"https://api.github.com/users/bloomberg/following{/other_user}","gists_url":"https://api.github.com/users/bloomberg/gists{/gist_id}","starred_url":"https://api.github.com/users/bloomberg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bloomberg/subscriptions","organizations_url":"https://api.github.com/users/bloomberg/orgs","repos_url":"https://api.github.com/users/bloomberg/repos","events_url":"https://api.github.com/users/bloomberg/events{/privacy}","received_events_url":"https://api.github.com/users/bloomberg/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/bloomberg/comdb2","description":"Bloomberg's distributed RDBMS","fork":false,"url":"https://api.github.com/repos/bloomberg/comdb2","forks_url":"https://api.github.com/repos/bloomberg/comdb2/forks","keys_url":"https://api.github.com/repos/bloomberg/comdb2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/bloomberg/comdb2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/bloomberg/comdb2/teams","hooks_url":"https://api.github.com/repos/bloomberg/comdb2/hooks","issue_events_url":"https://api.github.com/repos/bloomberg/comdb2/issues/events{/number}","events_url":"https://api.github.com/repos/bloomberg/comdb2/events","assignees_url":"https://api.github.com/repos/bloomberg/comdb2/assignees{/user}","branches_url":"https://api.github.com/repos/bloomberg/comdb2/branches{/branch}","tags_url":"https://api.github.com/repos/bloomberg/comdb2/tags","blobs_url":"https://api.github.com/repos/bloomberg/comdb2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/bloomberg/comdb2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/bloomberg/comdb2/git/refs{/sha}","trees_url":"https://api.github.com/repos/bloomberg/comdb2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/bloomberg/comdb2/statuses/{sha}","languages_url":"https://api.github.com/repos/bloomberg/comdb2/languages","stargazers_url":"https://api.github.com/repos/bloomberg/comdb2/stargazers","contributors_url":"https://api.github.com/repos/bloomberg/comdb2/contributors","subscribers_url":"https://api.github.com/repos/bloomberg/comdb2/subscribers","subscription_url":"https://api.github.com/repos/bloomberg/comdb2/subscription","commits_url":"https://api.github.com/repos/bloomberg/comdb2/commits{/sha}","git_commits_url":"https://api.github.com/repos/bloomberg/comdb2/git/commits{/sha}","comments_url":"https://api.github.com/repos/bloomberg/comdb2/comments{/number}","issue_comment_url":"https://api.github.com/repos/bloomberg/comdb2/issues/comments{/number}","contents_url":"https://api.github.com/repos/bloomberg/comdb2/contents/{+path}","compare_url":"https://api.github.com/repos/bloomberg/comdb2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/bloomberg/comdb2/merges","archive_url":"https://api.github.com/repos/bloomberg/comdb2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/bloomberg/comdb2/downloads","issues_url":"https://api.github.com/repos/bloomberg/comdb2/issues{/number}","pulls_url":"https://api.github.com/repos/bloomberg/comdb2/pulls{/number}","milestones_url":"https://api.github.com/repos/bloomberg/comdb2/milestones{/number}","notifications_url":"https://api.github.com/repos/bloomberg/comdb2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/bloomberg/comdb2/labels{/name}","releases_url":"https://api.github.com/repos/bloomberg/comdb2/releases{/id}","deployments_url":"https://api.github.com/repos/bloomberg/comdb2/deployments","created_at":"2017-05-17T15:39:23Z","updated_at":"2017-07-25T07:35:54Z","pushed_at":"2017-07-26T14:16:22Z","git_url":"git://github.com/bloomberg/comdb2.git","ssh_url":"git@github.com:bloomberg/comdb2.git","clone_url":"https://github.com/bloomberg/comdb2.git","svn_url":"https://github.com/bloomberg/comdb2","homepage":"","size":15937,"stargazers_count":636,"watchers_count":636,"language":"C","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":66,"mirror_url":null,"open_issues_count":21,"forks":66,"open_issues":21,"watchers":636,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/bloomberg/comdb2/pulls/265"},"html":{"href":"https://github.com/bloomberg/comdb2/pull/265"},"issue":{"href":"https://api.github.com/repos/bloomberg/comdb2/issues/265"},"comments":{"href":"https://api.github.com/repos/bloomberg/comdb2/issues/265/comments"},"review_comments":{"href":"https://api.github.com/repos/bloomberg/comdb2/pulls/265/comments"},"review_comment":{"href":"https://api.github.com/repos/bloomberg/comdb2/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/bloomberg/comdb2/pulls/265/commits"},"statuses":{"href":"https://api.github.com/repos/bloomberg/comdb2/statuses/cfef95bf7b3c63e75ff59638efd6cb56c01def23"}}}}
{"actor":{"display_login":"markhannum"}}