{"action":"created","comment":{"url":"https://api.github.com/repos/citusdata/citus/pulls/comments/82492554","pull_request_review_id":3399751,"id":82492554,"diff_hunk":"@@ -0,0 +1,541 @@\n+/*-------------------------------------------------------------------------\n+ *\n+ * connection_management.c\n+ *   Central management of connections and their life-cycle\n+ *\n+ * Copyright (c) 2016, Citus Data, Inc.\n+ *\n+ *-------------------------------------------------------------------------\n+ */\n+\n+#include \"postgres.h\"\n+\n+#ifdef HAVE_POLL_H\n+#include <poll.h>\n+#endif\n+\n+#include \"libpq-fe.h\"\n+\n+#include \"miscadmin.h\"\n+\n+#include \"access/hash.h\"\n+#include \"commands/dbcommands.h\"\n+#include \"distributed/connection_management.h\"\n+#include \"distributed/metadata_cache.h\"\n+#include \"distributed/hash_helpers.h\"\n+#include \"mb/pg_wchar.h\"\n+#include \"utils/hsearch.h\"\n+#include \"utils/memutils.h\"\n+\n+\n+HTAB *ConnectionHash = NULL;\n+MemoryContext ConnectionContext = NULL;\n+\n+static uint32 ConnectionHashHash(const void *key, Size keysize);\n+static int ConnectionHashCompare(const void *a, const void *b, Size keysize);\n+static MultiConnection * StartConnectionEstablishment(ConnectionHashKey *key);\n+\n+\n+/*\n+ * Initialize per-backend connection management infrastructure.\n+ */\n+void\n+InitializeConnectionManagement(void)\n+{\n+\tHASHCTL info;\n+\tuint32 hashFlags = 0;\n+\n+\n+\t/*\n+\t * Create a single context for connection and transaction related memory\n+\t * management. Doing so, instead of allocating in TopMemoryContext, makes\n+\t * it easier to associate used memory.\n+\t */\n+\tConnectionContext = AllocSetContextCreate(TopMemoryContext, \"Connection Context\",\n+\t\t\t\t\t\t\t\t\t\t\t  ALLOCSET_DEFAULT_MINSIZE,\n+\t\t\t\t\t\t\t\t\t\t\t  ALLOCSET_DEFAULT_INITSIZE,\n+\t\t\t\t\t\t\t\t\t\t\t  ALLOCSET_DEFAULT_MAXSIZE);\n+\n+\t/* create (host,port,user,database) -> [connection] hash */\n+\tmemset(&info, 0, sizeof(info));\n+\tinfo.keysize = sizeof(ConnectionHashKey);\n+\tinfo.entrysize = sizeof(ConnectionHashEntry);\n+\tinfo.hash = ConnectionHashHash;\n+\tinfo.match = ConnectionHashCompare;\n+\tinfo.hcxt = ConnectionContext;\n+\thashFlags = (HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT | HASH_COMPARE);\n+\n+\tConnectionHash = hash_create(\"citus connection cache (host,port,user,database)\",\n+\t\t\t\t\t\t\t\t 64, &info, hashFlags);\n+}\n+\n+\n+/*\n+ * Perform connection management activity after the end of a transaction. Both\n+ * COMMIT and ABORT paths are handled here.\n+ *\n+ * This is called by Citus' global transaction callback.\n+ */\n+void\n+AtEOXact_Connections(bool isCommit)\n+{\n+\tHASH_SEQ_STATUS status;\n+\tConnectionHashEntry *entry;\n+\n+\t/*\n+\t * Close all remote connections if necessary anymore (i.e. not session\n+\t * lifetime), or if in a failed state.\n+\t */\n+\thash_seq_init(&status, ConnectionHash);\n+\twhile ((entry = (ConnectionHashEntry *) hash_seq_search(&status)) != 0)\n+\t{\n+\t\tListCell *previousCell = NULL;\n+\t\tListCell *nextCell = NULL;\n+\t\tListCell *connectionCell = NULL;\n+\n+\t\t/*\n+\t\t * Have to iterate \"manually\", to be able to delete connections in the\n+\t\t * middle of the list.\n+\t\t */\n+\t\tfor (connectionCell = list_head(entry->connections);\n+\t\t\t connectionCell != NULL;\n+\t\t\t connectionCell = nextCell)\n+\t\t{\n+\t\t\tMultiConnection *connection = (MultiConnection *) lfirst(connectionCell);\n+\n+\t\t\tnextCell = lnext(connectionCell);\n+\n+\t\t\t/*\n+\t\t\t * To avoid code leaking connections we warn if connections are\n+\t\t\t * still claimed exclusively. We can only do so if the transaction\n+\t\t\t * committed, as it's normal that code didn't have chance to clean\n+\t\t\t * up after errors.\n+\t\t\t */\n+\t\t\tif (isCommit && connection->claimedExclusively)\n+\t\t\t{\n+\t\t\t\tereport(WARNING,\n+\t\t\t\t\t\t(errmsg(\"connection claimed exclusively at transaction commit\")));\n+\t\t\t}\n+\n+\t\t\t/*\n+\t\t\t * Only let a connection life longer than a single transaction if\n+\t\t\t * instructed to do so by the caller. We also skip doing so if\n+\t\t\t * it's in a state that wouldn't allow us to run queries again.\n+\t\t\t */\n+\t\t\tif (!connection->sessionLifespan ||\n+\t\t\t\tPQstatus(connection->conn) != CONNECTION_OK ||\n+\t\t\t\tPQtransactionStatus(connection->conn) != PQTRANS_IDLE)\n+\t\t\t{\n+\t\t\t\tPQfinish(connection->conn);\n+\t\t\t\tconnection->conn = NULL;\n+\n+\t\t\t\tentry->connections =\n+\t\t\t\t\tlist_delete_cell(entry->connections, connectionCell, previousCell);\n+\n+\t\t\t\tpfree(connection);\n+\t\t\t}\n+\t\t\telse\n+\t\t\t{\n+\t\t\t\t/* reset per-transaction state */\n+\t\t\t\tconnection->activeInTransaction = false;\n+\n+\t\t\t\tUnclaimConnection(connection);\n+\n+\t\t\t\tpreviousCell = connectionCell;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/*\n+\t\t * NB: We leave the hash entry in place, even if there's no individual\n+\t\t * connections in it anymore. There seems no benefit in deleting it,\n+\t\t * and it'll save a bit of work in the next transaction.\n+\t\t */\n+\t}\n+}\n+\n+\n+/*\n+ * GetNodeConnection() establishes a connection to remote node, using default\n+ * user and database.\n+ *\n+ * See StartNodeUserDatabaseConnection for details.\n+ */\n+MultiConnection *\n+GetNodeConnection(uint32 flags, const char *hostname, int32 port)\n+{\n+\treturn GetNodeUserDatabaseConnection(flags, hostname, port, NULL, NULL);\n+}\n+\n+\n+/*\n+ * StartNodeConnection initiate a connection to remote node, using default\n+ * user and database.\n+ *\n+ * See StartNodeUserDatabaseConnection for details.\n+ */\n+MultiConnection *\n+StartNodeConnection(uint32 flags, const char *hostname, int32 port)\n+{\n+\treturn StartNodeUserDatabaseConnection(flags, hostname, port, NULL, NULL);\n+}\n+\n+\n+/*\n+ * GetNodeUserDatabaseConnection establishes connection to remote node.\n+ *\n+ * See StartNodeUserDatabaseConnection for details.\n+ */\n+MultiConnection *\n+GetNodeUserDatabaseConnection(uint32 flags, const char *hostname, int32 port, const\n+\t\t\t\t\t\t\t  char *user, const char *database)\n+{\n+\tMultiConnection *connection;\n+\n+\tconnection = StartNodeUserDatabaseConnection(flags, hostname, port, user, database);\n+\n+\tFinishConnectionEstablishment(connection);\n+\n+\treturn connection;\n+}\n+\n+\n+/*\n+ * StartNodeUserDatabaseConnection() initiates a connection to a remote node.\n+ *\n+ * If user or database are NULL, the current session's defaults are used. The\n+ * following flags influence connection establishment behaviour:\n+ * - NEW_CONNECTION - it is permitted to establish a new connection\n+ * - CACHED_CONNECTION - it is permitted to re-use an established connection\n+ * - SESSION_LIFESPAN - the connection should persist after transaction end\n+ * - FOR_DML - only meaningful for placement associated connections\n+ * - FOR_DDL - only meaningful for placement associated connections\n+ * - CRITICAL_CONNECTION - transaction failures on this connection fail the entire\n+ *   coordinated transaction\n+ *\n+ * The returned connection has only been initiated, not fully\n+ * established. That's useful to allow parallel connection establishment. If\n+ * that's not desired use the Get* variant.\n+ */\n+MultiConnection *\n+StartNodeUserDatabaseConnection(uint32 flags, const char *hostname, int32 port, const\n+\t\t\t\t\t\t\t\tchar *user, const char *database)\n+{\n+\tConnectionHashKey key;\n+\tConnectionHashEntry *entry = NULL;\n+\tMultiConnection *connection;\n+\tMemoryContext oldContext;\n+\tbool found;\n+\n+\tstrlcpy(key.hostname, hostname, MAX_NODE_LENGTH);\n+\tkey.port = port;\n+\tif (user)\n+\t{\n+\t\tstrlcpy(key.user, user, NAMEDATALEN);\n+\t}\n+\telse\n+\t{\n+\t\tstrlcpy(key.user, CurrentUserName(), NAMEDATALEN);\n+\t}\n+\tif (database)\n+\t{\n+\t\tstrlcpy(key.database, database, NAMEDATALEN);\n+\t}\n+\telse\n+\t{\n+\t\tstrlcpy(key.database, get_database_name(MyDatabaseId), NAMEDATALEN);\n+\t}\n+\n+\tif (CurrentCoordinatedTransactionState == COORD_TRANS_NONE)\n+\t{\n+\t\tCurrentCoordinatedTransactionState = COORD_TRANS_IDLE;\n+\t}\n+\n+\t/*\n+\t * Lookup relevant hash entry. We always enter. If only a cached\n+\t * connection is desired, and there's none, we'll simply leave the\n+\t * connection list empty.\n+\t */\n+\n+\tentry = hash_search(ConnectionHash, &key, HASH_ENTER, &found);\n+\tif (!found)\n+\t{\n+\t\tentry->connections = NIL;\n+\t}\n+\n+\tif (flags & CACHED_CONNECTION)\n+\t{\n+\t\tListCell *connectionCell = NULL;\n+\n+\t\t/* check connection cache for a connection that's not already in use */\n+\t\tforeach(connectionCell, entry->connections)\n+\t\t{\n+\t\t\tconnection = (MultiConnection *) lfirst(connectionCell);\n+\n+\t\t\t/* don't return claimed connections */\n+\t\t\tif (!connection->claimedExclusively)\n+\t\t\t{\n+\t\t\t\tif (flags & SESSION_LIFESPAN)\n+\t\t\t\t{\n+\t\t\t\t\tconnection->sessionLifespan = true;\n+\t\t\t\t}\n+\t\t\t\tconnection->activeInTransaction = true;\n+\n+\t\t\t\t/*\n+\t\t\t\t * Check whether we're right now allowed to open new\n+\t\t\t\t * connections. A cached connection counts as new if it hasn't\n+\t\t\t\t * been used in this transaction.\n+\t\t\t\t *\n+\t\t\t\t * FIXME: This should be removed soon, once all connections go\n+\t\t\t\t * through this API.\n+\t\t\t\t */\n+\t\t\t\tif (!connection->activeInTransaction &&\n+\t\t\t\t\tXactModificationLevel > XACT_MODIFICATION_DATA)\n+\t\t\t\t{\n+\t\t\t\t\tereport(ERROR, (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),\n+\t\t\t\t\t\t\t\t\terrmsg(\"cannot open new connections after the first \"\n+\t\t\t\t\t\t\t\t\t\t   \"modification command within a transaction\")));\n+\t\t\t\t}\n+\n+\t\t\t\treturn connection;\n+\t\t\t}\n+\n+\t\t\t/*\n+\t\t\t * One could argue for erroring out when the connection is in a\n+\t\t\t * failed state. But that'd be a bad idea for two reasons:\n+\t\t\t *\n+\t\t\t * 1) Generally starting a connection might fail, after calling\n+\t\t\t *    this function, so calling code needs to handle that anyway.\n+\t\t\t * 2) This might be used in code that transparently handles\n+\t\t\t *    connection failure.\n+\t\t\t */\n+\t\t}\n+\n+\t\t/* no connection available, done if a new connection isn't desirable */\n+\t\tif (!(flags & NEW_CONNECTION))\n+\t\t{\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+\n+\t/*\n+\t * Check whether we're right now allowed to open new connections.\n+\t *\n+\t * FIXME: This should be removed soon, once all connections go through\n+\t * this API.\n+\t */\n+\tif (XactModificationLevel > XACT_MODIFICATION_DATA)\n+\t{\n+\t\tereport(ERROR, (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),\n+\t\t\t\t\t\terrmsg(\"cannot open new connections after the first modification \"\n+\t\t\t\t\t\t\t   \"command within a transaction\")));\n+\t}\n+\n+\t/*\n+\t * Either no caching desired, or no pre-established, non-claimed,\n+\t * connection present. Initiate connection establishment.\n+\t */\n+\tconnection = StartConnectionEstablishment(&key);\n+\n+\toldContext = MemoryContextSwitchTo(ConnectionContext);\n+\tentry->connections = lappend(entry->connections, connection);\n+\tMemoryContextSwitchTo(oldContext);\n+\n+\tif (flags & SESSION_LIFESPAN)\n+\t{\n+\t\tconnection->sessionLifespan = true;","path":"src/backend/distributed/utils/connection_management.c","position":345,"original_position":345,"commit_id":"3929e322b531fbeed3854d5d57735458ffb3a8e4","original_commit_id":"3929e322b531fbeed3854d5d57735458ffb3a8e4","user":{"login":"anarazel","id":1598211,"avatar_url":"https://avatars.githubusercontent.com/u/1598211?v=3","gravatar_id":"","url":"https://api.github.com/users/anarazel","html_url":"https://github.com/anarazel","followers_url":"https://api.github.com/users/anarazel/followers","following_url":"https://api.github.com/users/anarazel/following{/other_user}","gists_url":"https://api.github.com/users/anarazel/gists{/gist_id}","starred_url":"https://api.github.com/users/anarazel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/anarazel/subscriptions","organizations_url":"https://api.github.com/users/anarazel/orgs","repos_url":"https://api.github.com/users/anarazel/repos","events_url":"https://api.github.com/users/anarazel/events{/privacy}","received_events_url":"https://api.github.com/users/anarazel/received_events","type":"User","site_admin":false},"body":"I very much disagree. It's completely caller specific whether connections should be session lifespan. DDL should pretty much never (DROP TABLE;), others sometimes (COPY when flag specified), others always. There's no way to magically specify this.","created_at":"2016-10-08T01:44:16Z","updated_at":"2016-10-08T01:44:16Z","html_url":"https://github.com/citusdata/citus/pull/863#discussion_r82492554","pull_request_url":"https://api.github.com/repos/citusdata/citus/pulls/863","_links":{"self":{"href":"https://api.github.com/repos/citusdata/citus/pulls/comments/82492554"},"html":{"href":"https://github.com/citusdata/citus/pull/863#discussion_r82492554"},"pull_request":{"href":"https://api.github.com/repos/citusdata/citus/pulls/863"}}},"pull_request":{"url":"https://api.github.com/repos/citusdata/citus/pulls/863","id":88527457,"html_url":"https://github.com/citusdata/citus/pull/863","diff_url":"https://github.com/citusdata/citus/pull/863.diff","patch_url":"https://github.com/citusdata/citus/pull/863.patch","issue_url":"https://api.github.com/repos/citusdata/citus/issues/863","number":863,"state":"open","locked":false,"title":"Connection Lifecycle Management Infrastructure","user":{"login":"anarazel","id":1598211,"avatar_url":"https://avatars.githubusercontent.com/u/1598211?v=3","gravatar_id":"","url":"https://api.github.com/users/anarazel","html_url":"https://github.com/anarazel","followers_url":"https://api.github.com/users/anarazel/followers","following_url":"https://api.github.com/users/anarazel/following{/other_user}","gists_url":"https://api.github.com/users/anarazel/gists{/gist_id}","starred_url":"https://api.github.com/users/anarazel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/anarazel/subscriptions","organizations_url":"https://api.github.com/users/anarazel/orgs","repos_url":"https://api.github.com/users/anarazel/repos","events_url":"https://api.github.com/users/anarazel/events{/privacy}","received_events_url":"https://api.github.com/users/anarazel/received_events","type":"User","site_admin":false},"body":"Subset of #775, for easier review.","created_at":"2016-10-08T00:46:04Z","updated_at":"2016-10-08T01:44:16Z","closed_at":null,"merged_at":null,"merge_commit_sha":"aee9a3b506c7c3c1425c979dfc2a16996f94fba2","assignee":{"login":"marcocitus","id":7127240,"avatar_url":"https://avatars.githubusercontent.com/u/7127240?v=3","gravatar_id":"","url":"https://api.github.com/users/marcocitus","html_url":"https://github.com/marcocitus","followers_url":"https://api.github.com/users/marcocitus/followers","following_url":"https://api.github.com/users/marcocitus/following{/other_user}","gists_url":"https://api.github.com/users/marcocitus/gists{/gist_id}","starred_url":"https://api.github.com/users/marcocitus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/marcocitus/subscriptions","organizations_url":"https://api.github.com/users/marcocitus/orgs","repos_url":"https://api.github.com/users/marcocitus/repos","events_url":"https://api.github.com/users/marcocitus/events{/privacy}","received_events_url":"https://api.github.com/users/marcocitus/received_events","type":"User","site_admin":false},"assignees":[{"login":"marcocitus","id":7127240,"avatar_url":"https://avatars.githubusercontent.com/u/7127240?v=3","gravatar_id":"","url":"https://api.github.com/users/marcocitus","html_url":"https://github.com/marcocitus","followers_url":"https://api.github.com/users/marcocitus/followers","following_url":"https://api.github.com/users/marcocitus/following{/other_user}","gists_url":"https://api.github.com/users/marcocitus/gists{/gist_id}","starred_url":"https://api.github.com/users/marcocitus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/marcocitus/subscriptions","organizations_url":"https://api.github.com/users/marcocitus/orgs","repos_url":"https://api.github.com/users/marcocitus/repos","events_url":"https://api.github.com/users/marcocitus/events{/privacy}","received_events_url":"https://api.github.com/users/marcocitus/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/citusdata/citus/pulls/863/commits","review_comments_url":"https://api.github.com/repos/citusdata/citus/pulls/863/comments","review_comment_url":"https://api.github.com/repos/citusdata/citus/pulls/comments{/number}","comments_url":"https://api.github.com/repos/citusdata/citus/issues/863/comments","statuses_url":"https://api.github.com/repos/citusdata/citus/statuses/3929e322b531fbeed3854d5d57735458ffb3a8e4","head":{"label":"citusdata:feature/connection-lifecycle","ref":"feature/connection-lifecycle","sha":"3929e322b531fbeed3854d5d57735458ffb3a8e4","user":{"login":"citusdata","id":2545424,"avatar_url":"https://avatars.githubusercontent.com/u/2545424?v=3","gravatar_id":"","url":"https://api.github.com/users/citusdata","html_url":"https://github.com/citusdata","followers_url":"https://api.github.com/users/citusdata/followers","following_url":"https://api.github.com/users/citusdata/following{/other_user}","gists_url":"https://api.github.com/users/citusdata/gists{/gist_id}","starred_url":"https://api.github.com/users/citusdata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/citusdata/subscriptions","organizations_url":"https://api.github.com/users/citusdata/orgs","repos_url":"https://api.github.com/users/citusdata/repos","events_url":"https://api.github.com/users/citusdata/events{/privacy}","received_events_url":"https://api.github.com/users/citusdata/received_events","type":"Organization","site_admin":false},"repo":{"id":50874442,"name":"citus","full_name":"citusdata/citus","owner":{"login":"citusdata","id":2545424,"avatar_url":"https://avatars.githubusercontent.com/u/2545424?v=3","gravatar_id":"","url":"https://api.github.com/users/citusdata","html_url":"https://github.com/citusdata","followers_url":"https://api.github.com/users/citusdata/followers","following_url":"https://api.github.com/users/citusdata/following{/other_user}","gists_url":"https://api.github.com/users/citusdata/gists{/gist_id}","starred_url":"https://api.github.com/users/citusdata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/citusdata/subscriptions","organizations_url":"https://api.github.com/users/citusdata/orgs","repos_url":"https://api.github.com/users/citusdata/repos","events_url":"https://api.github.com/users/citusdata/events{/privacy}","received_events_url":"https://api.github.com/users/citusdata/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/citusdata/citus","description":"Scalable PostgreSQL for real-time workloads","fork":false,"url":"https://api.github.com/repos/citusdata/citus","forks_url":"https://api.github.com/repos/citusdata/citus/forks","keys_url":"https://api.github.com/repos/citusdata/citus/keys{/key_id}","collaborators_url":"https://api.github.com/repos/citusdata/citus/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/citusdata/citus/teams","hooks_url":"https://api.github.com/repos/citusdata/citus/hooks","issue_events_url":"https://api.github.com/repos/citusdata/citus/issues/events{/number}","events_url":"https://api.github.com/repos/citusdata/citus/events","assignees_url":"https://api.github.com/repos/citusdata/citus/assignees{/user}","branches_url":"https://api.github.com/repos/citusdata/citus/branches{/branch}","tags_url":"https://api.github.com/repos/citusdata/citus/tags","blobs_url":"https://api.github.com/repos/citusdata/citus/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/citusdata/citus/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/citusdata/citus/git/refs{/sha}","trees_url":"https://api.github.com/repos/citusdata/citus/git/trees{/sha}","statuses_url":"https://api.github.com/repos/citusdata/citus/statuses/{sha}","languages_url":"https://api.github.com/repos/citusdata/citus/languages","stargazers_url":"https://api.github.com/repos/citusdata/citus/stargazers","contributors_url":"https://api.github.com/repos/citusdata/citus/contributors","subscribers_url":"https://api.github.com/repos/citusdata/citus/subscribers","subscription_url":"https://api.github.com/repos/citusdata/citus/subscription","commits_url":"https://api.github.com/repos/citusdata/citus/commits{/sha}","git_commits_url":"https://api.github.com/repos/citusdata/citus/git/commits{/sha}","comments_url":"https://api.github.com/repos/citusdata/citus/comments{/number}","issue_comment_url":"https://api.github.com/repos/citusdata/citus/issues/comments{/number}","contents_url":"https://api.github.com/repos/citusdata/citus/contents/{+path}","compare_url":"https://api.github.com/repos/citusdata/citus/compare/{base}...{head}","merges_url":"https://api.github.com/repos/citusdata/citus/merges","archive_url":"https://api.github.com/repos/citusdata/citus/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/citusdata/citus/downloads","issues_url":"https://api.github.com/repos/citusdata/citus/issues{/number}","pulls_url":"https://api.github.com/repos/citusdata/citus/pulls{/number}","milestones_url":"https://api.github.com/repos/citusdata/citus/milestones{/number}","notifications_url":"https://api.github.com/repos/citusdata/citus/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/citusdata/citus/labels{/name}","releases_url":"https://api.github.com/repos/citusdata/citus/releases{/id}","deployments_url":"https://api.github.com/repos/citusdata/citus/deployments","created_at":"2016-02-01T21:58:39Z","updated_at":"2016-10-07T18:24:45Z","pushed_at":"2016-10-08T00:46:38Z","git_url":"git://github.com/citusdata/citus.git","ssh_url":"git@github.com:citusdata/citus.git","clone_url":"https://github.com/citusdata/citus.git","svn_url":"https://github.com/citusdata/citus","homepage":"https://www.citusdata.com","size":4043,"stargazers_count":1627,"watchers_count":1627,"language":"C","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":111,"mirror_url":null,"open_issues_count":400,"forks":111,"open_issues":400,"watchers":1627,"default_branch":"master"}},"base":{"label":"citusdata:master","ref":"master","sha":"76d86e1ac922e38ebf541b23015347980df7109d","user":{"login":"citusdata","id":2545424,"avatar_url":"https://avatars.githubusercontent.com/u/2545424?v=3","gravatar_id":"","url":"https://api.github.com/users/citusdata","html_url":"https://github.com/citusdata","followers_url":"https://api.github.com/users/citusdata/followers","following_url":"https://api.github.com/users/citusdata/following{/other_user}","gists_url":"https://api.github.com/users/citusdata/gists{/gist_id}","starred_url":"https://api.github.com/users/citusdata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/citusdata/subscriptions","organizations_url":"https://api.github.com/users/citusdata/orgs","repos_url":"https://api.github.com/users/citusdata/repos","events_url":"https://api.github.com/users/citusdata/events{/privacy}","received_events_url":"https://api.github.com/users/citusdata/received_events","type":"Organization","site_admin":false},"repo":{"id":50874442,"name":"citus","full_name":"citusdata/citus","owner":{"login":"citusdata","id":2545424,"avatar_url":"https://avatars.githubusercontent.com/u/2545424?v=3","gravatar_id":"","url":"https://api.github.com/users/citusdata","html_url":"https://github.com/citusdata","followers_url":"https://api.github.com/users/citusdata/followers","following_url":"https://api.github.com/users/citusdata/following{/other_user}","gists_url":"https://api.github.com/users/citusdata/gists{/gist_id}","starred_url":"https://api.github.com/users/citusdata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/citusdata/subscriptions","organizations_url":"https://api.github.com/users/citusdata/orgs","repos_url":"https://api.github.com/users/citusdata/repos","events_url":"https://api.github.com/users/citusdata/events{/privacy}","received_events_url":"https://api.github.com/users/citusdata/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/citusdata/citus","description":"Scalable PostgreSQL for real-time workloads","fork":false,"url":"https://api.github.com/repos/citusdata/citus","forks_url":"https://api.github.com/repos/citusdata/citus/forks","keys_url":"https://api.github.com/repos/citusdata/citus/keys{/key_id}","collaborators_url":"https://api.github.com/repos/citusdata/citus/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/citusdata/citus/teams","hooks_url":"https://api.github.com/repos/citusdata/citus/hooks","issue_events_url":"https://api.github.com/repos/citusdata/citus/issues/events{/number}","events_url":"https://api.github.com/repos/citusdata/citus/events","assignees_url":"https://api.github.com/repos/citusdata/citus/assignees{/user}","branches_url":"https://api.github.com/repos/citusdata/citus/branches{/branch}","tags_url":"https://api.github.com/repos/citusdata/citus/tags","blobs_url":"https://api.github.com/repos/citusdata/citus/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/citusdata/citus/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/citusdata/citus/git/refs{/sha}","trees_url":"https://api.github.com/repos/citusdata/citus/git/trees{/sha}","statuses_url":"https://api.github.com/repos/citusdata/citus/statuses/{sha}","languages_url":"https://api.github.com/repos/citusdata/citus/languages","stargazers_url":"https://api.github.com/repos/citusdata/citus/stargazers","contributors_url":"https://api.github.com/repos/citusdata/citus/contributors","subscribers_url":"https://api.github.com/repos/citusdata/citus/subscribers","subscription_url":"https://api.github.com/repos/citusdata/citus/subscription","commits_url":"https://api.github.com/repos/citusdata/citus/commits{/sha}","git_commits_url":"https://api.github.com/repos/citusdata/citus/git/commits{/sha}","comments_url":"https://api.github.com/repos/citusdata/citus/comments{/number}","issue_comment_url":"https://api.github.com/repos/citusdata/citus/issues/comments{/number}","contents_url":"https://api.github.com/repos/citusdata/citus/contents/{+path}","compare_url":"https://api.github.com/repos/citusdata/citus/compare/{base}...{head}","merges_url":"https://api.github.com/repos/citusdata/citus/merges","archive_url":"https://api.github.com/repos/citusdata/citus/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/citusdata/citus/downloads","issues_url":"https://api.github.com/repos/citusdata/citus/issues{/number}","pulls_url":"https://api.github.com/repos/citusdata/citus/pulls{/number}","milestones_url":"https://api.github.com/repos/citusdata/citus/milestones{/number}","notifications_url":"https://api.github.com/repos/citusdata/citus/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/citusdata/citus/labels{/name}","releases_url":"https://api.github.com/repos/citusdata/citus/releases{/id}","deployments_url":"https://api.github.com/repos/citusdata/citus/deployments","created_at":"2016-02-01T21:58:39Z","updated_at":"2016-10-07T18:24:45Z","pushed_at":"2016-10-08T00:46:38Z","git_url":"git://github.com/citusdata/citus.git","ssh_url":"git@github.com:citusdata/citus.git","clone_url":"https://github.com/citusdata/citus.git","svn_url":"https://github.com/citusdata/citus","homepage":"https://www.citusdata.com","size":4043,"stargazers_count":1627,"watchers_count":1627,"language":"C","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":111,"mirror_url":null,"open_issues_count":400,"forks":111,"open_issues":400,"watchers":1627,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/citusdata/citus/pulls/863"},"html":{"href":"https://github.com/citusdata/citus/pull/863"},"issue":{"href":"https://api.github.com/repos/citusdata/citus/issues/863"},"comments":{"href":"https://api.github.com/repos/citusdata/citus/issues/863/comments"},"review_comments":{"href":"https://api.github.com/repos/citusdata/citus/pulls/863/comments"},"review_comment":{"href":"https://api.github.com/repos/citusdata/citus/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/citusdata/citus/pulls/863/commits"},"statuses":{"href":"https://api.github.com/repos/citusdata/citus/statuses/3929e322b531fbeed3854d5d57735458ffb3a8e4"}}}}
{"actor":{"display_login":"anarazel"}}