void PgNotifyTransferEvents(Pg_ConnectionId * connid) { PGnotify *notify; while ((notify = PQnotifies(connid->conn)) != NULL) { NotifyEvent *event = (NotifyEvent *) ckalloc(sizeof(NotifyEvent)); event->header.proc = Pg_Notify_EventProc; event->notify = notify; event->connid = connid; Tcl_QueueEvent((Tcl_Event *) event, TCL_QUEUE_TAIL); } /* * This is also a good place to check for unexpected closure of the * connection (ie, backend crash), in which case we must shut down the * notify event source to keep Tcl from trying to select() on the now- * closed socket descriptor. But don't kill on-connection-loss * events; in fact, register one. */ if (PQsocket(connid->conn) < 0) PgConnLossTransferEvents(connid); }
void conn_notifies_process(connectionObject *self) { PGnotify *pgn = NULL; PyObject *notify = NULL; PyObject *pid = NULL, *channel = NULL, *payload = NULL; PyObject *tmp = NULL; static PyObject *append; if (!append) { if (!(append = Text_FromUTF8("append"))) { goto error; } } while ((pgn = PQnotifies(self->pgconn)) != NULL) { Dprintf("conn_notifies_process: got NOTIFY from pid %d, msg = %s", (int) pgn->be_pid, pgn->relname); if (!(pid = PyInt_FromLong((long)pgn->be_pid))) { goto error; } if (!(channel = conn_text_from_chars(self, pgn->relname))) { goto error; } if (!(payload = conn_text_from_chars(self, pgn->extra))) { goto error; } if (!(notify = PyObject_CallFunctionObjArgs((PyObject *)¬ifyType, pid, channel, payload, NULL))) { goto error; } Py_DECREF(pid); pid = NULL; Py_DECREF(channel); channel = NULL; Py_DECREF(payload); payload = NULL; if (!(tmp = PyObject_CallMethodObjArgs( self->notifies, append, notify, NULL))) { goto error; } Py_DECREF(tmp); tmp = NULL; Py_DECREF(notify); notify = NULL; PQfreemem(pgn); pgn = NULL; } return; /* no error */ error: if (pgn) { PQfreemem(pgn); } Py_XDECREF(tmp); Py_XDECREF(notify); Py_XDECREF(pid); Py_XDECREF(channel); Py_XDECREF(payload); /* TODO: callers currently don't expect an error from us */ PyErr_Clear(); }
/* * PrintNotifications: check for asynchronous notifications, and print them out */ static void PrintNotifications(void) { PGnotify *notify; while ((notify = PQnotifies(pset.db))) { fprintf(pset.queryFout, gettext("Asynchronous notification \"%s\" received from server process with PID %d.\n"), notify->relname, notify->be_pid); fflush(pset.queryFout); PQfreemem(notify); } }
pgNotification *pgConn::GetNotification() { pgNotify *notify; notify = PQnotifies(conn); if (!notify) return NULL; pgNotification *ret = new pgNotification; ret->name = wxString(notify->relname, *conv); ret->pid = notify->be_pid; ret->data = wxString(notify->extra, *conv); return ret; }
CAMLprim value PQnotifies_stub(value v_conn) { CAMLparam1(v_conn); CAMLlocal1(v_str); PGnotify *noti = PQnotifies(get_conn(v_conn)); if (noti) { value v_pair; v_str = make_string(noti->relname); v_pair = caml_alloc_small(2, 0); Field(v_pair, 0) = v_str; Field(v_pair, 1) = Val_int(noti->be_pid); PQfreemem(noti); CAMLreturn(make_some(v_pair)); } else CAMLreturn(v_None); }
/* * PrintNotifications: check for asynchronous notifications, and print them out */ static void PrintNotifications(void) { PGnotify *notify; while ((notify = PQnotifies(pset.db))) { /* for backward compatibility, only show payload if nonempty */ if (notify->extra[0]) fprintf(pset.queryFout, _("Asynchronous notification \"%s\" with payload \"%s\" received from server process with PID %d.\n"), notify->relname, notify->extra, notify->be_pid); else fprintf(pset.queryFout, _("Asynchronous notification \"%s\" received from server process with PID %d.\n"), notify->relname, notify->be_pid); fflush(pset.queryFout); PQfreemem(notify); } }
void PGDatabase::GetNotify(pgdb_monitor_callback pmc, void* param) { PGnotify *notify; struct pgdb_monitor_result pmr; while (true) { /* * Sleep until something happens on the connection. We use select(2) * to wait for input, but you could also use poll() or similar * facilities. */ int sock; fd_set input_mask; sock = PQsocket(m_pConnect); if (sock < 0) break; /* shouldn't happen */ FD_ZERO(&input_mask); FD_SET(sock, &input_mask); if (select(sock + 1, &input_mask, NULL, NULL, NULL) < 0) { fprintf(stderr, "select() failed: %s\n", strerror(errno)); } /* Now check for input */ PQconsumeInput(m_pConnect); while ((notify = PQnotifies(m_pConnect)) != NULL) { memset(pmr.tablename, 0 , MAXTABLENAMELEN); memset(pmr.opvalues, 0 , MAXOPVALUELEN); memcpy(pmr.tablename, notify->relname, strlen(notify->relname)); memcpy(pmr.opvalues, notify->extra, strlen(notify->extra)); pmc(&pmr,param); PQfreemem(notify); } } }
char *pl_read(PGconn *conn) { // Sleep until something happens on the connection. We use select(2) //to wait for input, but you could also use poll() or similar // facilities. int sock; fd_set input_mask; PGnotify *notify; char *not_name; sock = PQsocket(conn); if (sock < 0) { fprintf(stderr, "shouldn't happen: sock < 0"); exit_nicely(conn); } FD_ZERO(&input_mask); FD_SET(sock, &input_mask); try_again: if (select(sock + 1, &input_mask, NULL, NULL, NULL) < 0) { fprintf(stderr, "select() failed: %s\n", strerror(errno)); exit_nicely(conn); } // Now check for input PQconsumeInput(conn); if ((notify = PQnotifies(conn)) != NULL) { fprintf(stderr, "ASYNC NOTIFY of '%s' received from backend pid %d\n", notify->relname, notify->be_pid); not_name = (char *)malloc((strlen(notify->relname) + 1) * sizeof(char)); strcpy(not_name, notify->relname); PQfreemem(notify); return not_name; } else { goto try_again; } }
/* * call-seq: * conn.get_notify() -> ary or nil * conn.get_notify() { |rel,pid,msg| .... } -> obj * * Returns a notifier. If there is no unprocessed notifier, it returns +nil+. */ VALUE pgconn_get_notify( VALUE self) { struct pgconn_data *c; PGnotify *notify; VALUE rel, pid, ext; VALUE ret; Data_Get_Struct( self, struct pgconn_data, c); if (PQconsumeInput( c->conn) == 0) pg_raise_connexec( c); notify = PQnotifies( c->conn); if (notify == NULL) return Qnil; rel = pgconn_mkstring( c, notify->relname); pid = INT2FIX( notify->be_pid), ext = pgconn_mkstring( c, notify->extra); ret = rb_ary_new3( 3, rel, pid, ext); PQfreemem( notify); return rb_block_given_p() ? rb_yield( ret) : ret; }
LispObj * Lisp_PQnotifies(LispBuiltin *builtin) /* pq-notifies connection */ { LispObj *result, *code, *cod = COD; PGconn *conn; PGnotify *notifies; LispObj *connection; connection = ARGUMENT(0); if (!CHECKO(connection, PGconn_t)) LispDestroy("%s: cannot convert %s to PGconn*", STRFUN(builtin), STROBJ(connection)); conn = (PGconn*)(connection->data.opaque.data); if ((notifies = PQnotifies(conn)) == NULL) return (NIL); GCDisable(); code = CONS(ATOM("MAKE-PG-NOTIFY"), CONS(KEYWORD("RELNAME"), CONS(STRING(notifies->relname), CONS(KEYWORD("BE-PID"), CONS(REAL(notifies->be_pid), NIL))))); COD = CONS(code, COD); GCEnable(); result = EVAL(code); COD = cod; free(notifies); return (result); }
/* ---------- * slon_localListenThread * * Listen for events on the local database connection. This means, * events generated by the local node only. * ---------- */ void * localListenThread_main(/* @unused@ */ void *dummy) { SlonConn *conn; SlonDString query1; PGconn *dbconn; PGresult *res; int ntuples; int tupno; PGnotify *notification; char restart_notify[256]; int restart_request; int poll_sleep = 0; int node_lock_obtained=0; slon_log(SLON_INFO, "localListenThread: thread starts\n"); /* * Connect to the local database */ if ((conn = slon_connectdb(rtcfg_conninfo, "local_listen")) == NULL) slon_retry(); dbconn = conn->dbconn; /* * Initialize local data */ dstring_init(&query1); sprintf(restart_notify, "_%s_Restart", rtcfg_cluster_name); /* * Listen for local events */ (void) slon_mkquery(&query1, "listen \"_%s_Restart\"; ", rtcfg_cluster_name); res = PQexec(dbconn, dstring_data(&query1)); if (PQresultStatus(res) != PGRES_COMMAND_OK) { slon_log(SLON_FATAL, "localListenThread: \"%s\" - %s\n", dstring_data(&query1), PQresultErrorMessage(res)); PQclear(res); dstring_free(&query1); pthread_mutex_lock(&slon_wait_listen_lock); slon_listen_started=0; pthread_cond_signal(&slon_wait_listen_cond); pthread_mutex_unlock(&slon_wait_listen_lock); slon_retry(); } PQclear(res); /* * Check that we are the only slon daemon connected. */ #define NODELOCKERROR "ERROR: duplicate key violates unique constraint \"sl_nodelock-pkey\"" (void) slon_mkquery(&query1, "select %s.cleanupNodelock(); " "insert into %s.sl_nodelock values (" " %d, 0, \"pg_catalog\".pg_backend_pid()); ", rtcfg_namespace, rtcfg_namespace, rtcfg_nodeid); while(!node_lock_obtained) { res = PQexec(dbconn, dstring_data(&query1)); if (PQresultStatus(res) != PGRES_COMMAND_OK) { slon_log(SLON_FATAL, "localListenThread: \"%s\" - %s\n", dstring_data(&query1), PQresultErrorMessage(res)); if (strncmp(NODELOCKERROR, PQresultErrorMessage(res), strlen(NODELOCKERROR)) == 0) { slon_log(SLON_FATAL, "Do you already have a slon running against this node?\n"); slon_log(SLON_FATAL, "Or perhaps a residual idle backend connection from a dead slon?\n"); PQclear(res); if(worker_restarted) { sleep(5); continue; } else { dstring_free(&query1); pthread_mutex_lock(&slon_wait_listen_lock); slon_listen_started=0; pthread_cond_signal(&slon_wait_listen_cond); pthread_mutex_unlock(&slon_wait_listen_lock); slon_abort(); } } PQclear(res); dstring_free(&query1); slon_abort(); } PQclear(res); node_lock_obtained=1; } /* * Flag the main thread that the coast is clear and he can launch all * other threads. */ pthread_mutex_lock(&slon_wait_listen_lock); slon_listen_started=1; pthread_cond_signal(&slon_wait_listen_cond); pthread_mutex_unlock(&slon_wait_listen_lock); /* * Process all events, then wait for notification and repeat until * shutdown time has arrived. */ while (true) { /* * Start the transaction */ res = PQexec(dbconn, "start transaction; " "set transaction isolation level serializable;"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { slon_log(SLON_FATAL, "localListenThread: cannot start transaction - %s\n", PQresultErrorMessage(res)); PQclear(res); dstring_free(&query1); slon_retry(); break; } PQclear(res); /* * Drain notifications. */ (void) PQconsumeInput(dbconn); restart_request = false; while ((notification = PQnotifies(dbconn)) != NULL) { if (strcmp(restart_notify, notification->relname) == 0) restart_request = true; (void) PQfreemem(notification); } if (restart_request) { slon_log(SLON_INFO, "localListenThread: got restart notification\n"); #ifndef WIN32 slon_restart(); #else /* XXX */ /* Win32 defer to service manager to restart for now */ slon_restart(); #endif } /* * Query the database for new local events */ (void) slon_mkquery(&query1, "select ev_seqno, ev_timestamp, " " 'dummy', 'dummy', 'dummy', " " ev_type, " " ev_data1, ev_data2, ev_data3, ev_data4, " " ev_data5, ev_data6, ev_data7, ev_data8 " "from %s.sl_event " "where ev_origin = '%d' " " and ev_seqno > '%s' " "order by ev_seqno", rtcfg_namespace, rtcfg_nodeid, rtcfg_lastevent); res = PQexec(dbconn, dstring_data(&query1)); if (PQresultStatus(res) != PGRES_TUPLES_OK) { slon_log(SLON_FATAL, "localListenThread: \"%s\" - %s\n", dstring_data(&query1), PQresultErrorMessage(res)); PQclear(res); dstring_free(&query1); slon_retry(); break; } ntuples = PQntuples(res); for (tupno = 0; tupno < ntuples; tupno++) { char *ev_type; /* * Remember the event sequence number for confirmation */ strcpy(rtcfg_lastevent, PQgetvalue(res, tupno, 0)); /* * Get the event type and process configuration events */ ev_type = PQgetvalue(res, tupno, 5); slon_log(SLON_DEBUG2, "localListenThread: " "Received event %d,%s %s\n", rtcfg_nodeid, PQgetvalue(res, tupno, 0), ev_type); if (strcmp(ev_type, "SYNC") == 0) { /* * SYNC - nothing to do */ } else if (strcmp(ev_type, "STORE_NODE") == 0) { /* * STORE_NODE */ int no_id; char *no_comment; no_id = (int)strtol(PQgetvalue(res, tupno, 6), NULL, 10); no_comment = PQgetvalue(res, tupno, 7); if (no_id != rtcfg_nodeid) rtcfg_storeNode(no_id, no_comment); rtcfg_reloadListen(dbconn); } else if (strcmp(ev_type, "ENABLE_NODE") == 0) { /* * ENABLE_NODE */ int no_id; no_id = (int)strtol(PQgetvalue(res, tupno, 6), NULL, 10); if (no_id != rtcfg_nodeid) rtcfg_enableNode(no_id); rtcfg_reloadListen(dbconn); } else if (strcmp(ev_type, "DROP_NODE") == 0) { /* * DROP_NODE */ int no_id; char notify_query[256]; PGresult *notify_res; no_id = (int)strtol(PQgetvalue(res, tupno, 6), NULL, 10); /* * Deactivate the node in the runtime configuration */ rtcfg_disableNode(no_id); /* * And cause the replication daemon to restart to get rid of * it. */ snprintf(notify_query, sizeof(notify_query), "notify \"_%s_Restart\";", rtcfg_cluster_name); notify_res = PQexec(dbconn, notify_query); if (PQresultStatus(notify_res) != PGRES_COMMAND_OK) { slon_log(SLON_FATAL, "localListenThread: \"%s\" %s\n", notify_query, PQresultErrorMessage(notify_res)); PQclear(notify_res); slon_restart(); } PQclear(notify_res); rtcfg_reloadListen(dbconn); } else if (strcmp(ev_type, "CLONE_NODE") == 0) { /* * CLONE_NODE */ int no_id; int no_provider; char *no_comment; no_id = (int)strtol(PQgetvalue(res, tupno, 6), NULL, 10); no_provider = (int)strtol(PQgetvalue(res, tupno, 7), NULL, 10); no_comment = PQgetvalue(res, tupno, 8); rtcfg_storeNode(no_id, no_comment); } else if (strcmp(ev_type, "STORE_PATH") == 0) { /* * STORE_PATH */ int pa_server; int pa_client; char *pa_conninfo; int pa_connretry; pa_server = (int)strtol(PQgetvalue(res, tupno, 6), NULL, 10); pa_client = (int)strtol(PQgetvalue(res, tupno, 7), NULL, 10); pa_conninfo = PQgetvalue(res, tupno, 8); pa_connretry = (int)strtol(PQgetvalue(res, tupno, 9), NULL, 10); if (pa_client == rtcfg_nodeid) rtcfg_storePath(pa_server, pa_conninfo, pa_connretry); rtcfg_reloadListen(dbconn); } else if (strcmp(ev_type, "DROP_PATH") == 0) { /* * DROP_PATH */ int pa_server; int pa_client; pa_server = (int)strtol(PQgetvalue(res, tupno, 6), NULL, 10); pa_client = (int)strtol(PQgetvalue(res, tupno, 7), NULL, 10); if (pa_client == rtcfg_nodeid) rtcfg_dropPath(pa_server); rtcfg_reloadListen(dbconn); } else if (strcmp(ev_type, "STORE_LISTEN") == 0) { /* * STORE_LISTEN */ int li_origin; int li_provider; int li_receiver; li_origin = (int)strtol(PQgetvalue(res, tupno, 6), NULL, 10); li_provider = (int)strtol(PQgetvalue(res, tupno, 7), NULL, 10); li_receiver = (int)strtol(PQgetvalue(res, tupno, 8), NULL, 10); if (li_receiver == rtcfg_nodeid) rtcfg_storeListen(li_origin, li_provider); } else if (strcmp(ev_type, "DROP_LISTEN") == 0) { /* * DROP_LISTEN */ int li_origin; int li_provider; int li_receiver; li_origin = (int)strtol(PQgetvalue(res, tupno, 6), NULL, 10); li_provider = (int)strtol(PQgetvalue(res, tupno, 7), NULL, 10); li_receiver = (int)strtol(PQgetvalue(res, tupno, 8), NULL, 10); if (li_receiver == rtcfg_nodeid) rtcfg_dropListen(li_origin, li_provider); } else if (strcmp(ev_type, "STORE_SET") == 0) { /* * STORE_SET */ int set_id; int set_origin; char *set_comment; set_id = (int)strtol(PQgetvalue(res, tupno, 6), NULL, 10); set_origin = (int)strtol(PQgetvalue(res, tupno, 7), NULL, 10); set_comment = PQgetvalue(res, tupno, 8); rtcfg_storeSet(set_id, set_origin, set_comment); } else if (strcmp(ev_type, "DROP_SET") == 0) { /* * DROP_SET */ int set_id; set_id = (int)strtol(PQgetvalue(res, tupno, 6), NULL, 10); rtcfg_dropSet(set_id); } else if (strcmp(ev_type, "MERGE_SET") == 0) { /* * MERGE_SET */ int set_id; int add_id; set_id = (int)strtol(PQgetvalue(res, tupno, 6), NULL, 10); add_id = (int)strtol(PQgetvalue(res, tupno, 7), NULL, 10); rtcfg_dropSet(add_id); } else if (strcmp(ev_type, "SET_ADD_TABLE") == 0) { /* * SET_ADD_TABLE */ /* * Nothing to do ATM ... we don't support adding tables to * subscribed sets and table information is not maintained in * the runtime configuration. */ } else if (strcmp(ev_type, "SET_ADD_SEQUENCE") == 0) { /* * SET_ADD_SEQUENCE */ /* * Nothing to do ATM ... we don't support adding sequences to * subscribed sets and table information is not maintained in * the runtime configuration. */ } else if (strcmp(ev_type, "SET_DROP_TABLE") == 0) { /* * SET_DROP_TABLE */ /* * Nothing to do ATM ... table information is not maintained * in the runtime configuration. */ } else if (strcmp(ev_type, "SET_DROP_SEQUENCE") == 0) { /* * SET_DROP_SEQUENCE */ /* * Nothing to do ATM ... table information is not maintained * in the runtime configuration. */ } else if (strcmp(ev_type, "SET_MOVE_TABLE") == 0) { /* * SET_MOVE_TABLE */ /* * Nothing to do ATM ... table information is not maintained * in the runtime configuration. */ } else if (strcmp(ev_type, "SET_MOVE_SEQUENCE") == 0) { /* * SET_MOVE_SEQUENCE */ /* * Nothing to do ATM ... table information is not maintained * in the runtime configuration. */ } else if (strcmp(ev_type, "ADJUST_SEQ") == 0) { /* * ADJUST_SEQ */ } else if (strcmp(ev_type, "STORE_TRIGGER") == 0) { /* * STORE_TRIGGER */ /* * Nothing to do ATM */ } else if (strcmp(ev_type, "DROP_TRIGGER") == 0) { /* * DROP_TRIGGER */ /* * Nothing to do ATM */ } else if (strcmp(ev_type, "MOVE_SET") == 0) { /* * MOVE_SET */ int set_id; int old_origin; int new_origin; PGresult *res2; SlonDString query2; int sub_provider; set_id = (int)strtol(PQgetvalue(res, tupno, 6), NULL, 10); old_origin = (int)strtol(PQgetvalue(res, tupno, 7), NULL, 10); new_origin = (int)strtol(PQgetvalue(res, tupno, 8), NULL, 10); /* * We have been the old origin of the set, so according to the * rules we must have a provider now. */ dstring_init(&query2); (void) slon_mkquery(&query2, "select sub_provider from %s.sl_subscribe " " where sub_receiver = %d and sub_set = %d", rtcfg_namespace, rtcfg_nodeid, set_id); res2 = PQexec(dbconn, dstring_data(&query2)); if (PQresultStatus(res2) != PGRES_TUPLES_OK) { slon_log(SLON_FATAL, "localListenThread: \"%s\" %s\n", dstring_data(&query2), PQresultErrorMessage(res2)); dstring_free(&query2); PQclear(res2); slon_retry(); } if (PQntuples(res2) != 1) { slon_log(SLON_FATAL, "localListenThread: MOVE_SET " "but no provider found for set %d\n", set_id); dstring_free(&query2); PQclear(res2); slon_retry(); } sub_provider = (int)strtol(PQgetvalue(res2, 0, 0), NULL, 10); PQclear(res2); dstring_free(&query2); rtcfg_moveSet(set_id, old_origin, new_origin, sub_provider); rtcfg_reloadListen(dbconn); } else if (strcmp(ev_type, "FAILOVER_SET") == 0) { /* * FAILOVER_SET */ /* * Nothing to do. The stored procedure will restart this * daemon anyway. */ } else if (strcmp(ev_type, "SUBSCRIBE_SET") == 0) { /* * SUBSCRIBE_SET */ int sub_set; int sub_provider; int sub_receiver; char *sub_forward; sub_set = (int)strtol(PQgetvalue(res, tupno, 6), NULL, 10); sub_provider = (int)strtol(PQgetvalue(res, tupno, 7), NULL, 10); sub_receiver = (int)strtol(PQgetvalue(res, tupno, 8), NULL, 10); sub_forward = PQgetvalue(res, tupno, 9); if (sub_receiver == rtcfg_nodeid) rtcfg_storeSubscribe(sub_set, sub_provider, sub_forward); rtcfg_reloadListen(dbconn); } else if (strcmp(ev_type, "ENABLE_SUBSCRIPTION") == 0) { /* * ENABLE_SUBSCRIPTION */ int sub_set; int sub_provider; int sub_receiver; char *sub_forward; sub_set = (int)strtol(PQgetvalue(res, tupno, 6), NULL, 10); sub_provider = (int)strtol(PQgetvalue(res, tupno, 7), NULL, 10); sub_receiver = (int)strtol(PQgetvalue(res, tupno, 8), NULL, 10); sub_forward = PQgetvalue(res, tupno, 9); if (sub_receiver == rtcfg_nodeid) rtcfg_enableSubscription(sub_set, sub_provider, sub_forward); rtcfg_reloadListen(dbconn); } else if (strcmp(ev_type, "UNSUBSCRIBE_SET") == 0) { /* * UNSUBSCRIBE_SET */ int sub_set; int sub_receiver; sub_set = (int)strtol(PQgetvalue(res, tupno, 6), NULL, 10); sub_receiver = (int)strtol(PQgetvalue(res, tupno, 7), NULL, 10); if (sub_receiver == rtcfg_nodeid) rtcfg_unsubscribeSet(sub_set); rtcfg_reloadListen(dbconn); } else if (strcmp(ev_type, "DDL_SCRIPT") == 0) { /* * DDL_SCRIPT */ /* * Nothing to do ATM */ } else if (strcmp(ev_type, "ACCEPT_SET") == 0) { /* * ACCEPT_SET */ /* * Nothing to do locally */ slon_log(SLON_DEBUG1, "localListenThread: ACCEPT_SET\n"); rtcfg_reloadListen(dbconn); } else { slon_log(SLON_FATAL, "localListenThread: event %s: Unknown event type: %s\n", rtcfg_lastevent, ev_type); slon_abort(); } } PQclear(res); /* * If there were events, commit the transaction. */ if (ntuples > 0) { poll_sleep = 0; /* drop polling time back to 0... */ res = PQexec(dbconn, "commit transaction"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { slon_log(SLON_FATAL, "localListenThread: \"%s\" - %s\n", dstring_data(&query1), PQresultErrorMessage(res)); PQclear(res); dstring_free(&query1); slon_retry(); break; } PQclear(res); } else { /* * No database events received. Rollback instead. */ /* Increase the amount of time to sleep, to a max of sync_interval_timeout */ poll_sleep += sync_interval; if (poll_sleep > sync_interval_timeout) { poll_sleep = sync_interval_timeout; } res = PQexec(dbconn, "rollback transaction;"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { slon_log(SLON_FATAL, "localListenThread: \"rollback transaction;\" - %s\n", PQresultErrorMessage(res)); PQclear(res); slon_retry(); break; } PQclear(res); } /* * Wait for notify or for timeout */ if (sched_wait_time(conn, SCHED_WAIT_SOCK_READ, poll_sleep) != SCHED_STATUS_OK) break; } /* * The scheduler asked us to shutdown. Free memory and close the DB * connection. */ dstring_free(&query1); slon_disconnectdb(conn); #ifdef SLON_MEMDEBUG conn = NULL; #endif slon_log(SLON_INFO, "localListenThread: thread done\n"); pthread_exit(NULL); }
int main(int argc, char **argv) { const char *conninfo; PGconn *conn; PGresult *res; PGnotify *notify; int nnotifies; /* * If the user supplies a parameter on the command line, use it as the * conninfo string; otherwise default to setting dbname=postgres and using * environment variables or defaults for all other connection parameters. */ if (argc > 1) conninfo = argv[1]; else conninfo = "dbname = postgres"; /* Make a connection to the database */ conn = PQconnectdb(conninfo); /* Check to see that the backend connection was successfully made */ if (PQstatus(conn) != CONNECTION_OK) { fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn)); exit_nicely(conn); } /* * Issue LISTEN command to enable notifications from the rule's NOTIFY. */ res = PQexec(conn, "LISTEN TBL2"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "LISTEN command failed: %s", PQerrorMessage(conn)); PQclear(res); exit_nicely(conn); } /* * should PQclear PGresult whenever it is no longer needed to avoid memory * leaks */ PQclear(res); /* Quit after four notifies are received. */ nnotifies = 0; while (nnotifies < 4) { /* * Sleep until something happens on the connection. We use select(2) * to wait for input, but you could also use poll() or similar * facilities. */ int sock; fd_set input_mask; sock = PQsocket(conn); if (sock < 0) break; /* shouldn't happen */ FD_ZERO(&input_mask); FD_SET(sock, &input_mask); if (select(sock + 1, &input_mask, NULL, NULL, NULL) < 0) { fprintf(stderr, "select() failed: %s\n", strerror(errno)); exit_nicely(conn); } /* Now check for input */ PQconsumeInput(conn); while ((notify = PQnotifies(conn)) != NULL) { fprintf(stderr, "ASYNC NOTIFY of '%s' received from backend pid %d\n", notify->relname, notify->be_pid); PQfreemem(notify); nnotifies++; } } fprintf(stderr, "Done.\n"); /* close the connection to the database and cleanup */ PQfinish(conn); return 0; }
int hb_main(const char* conninfo) { PGconn *conn; PGresult *res; PGnotify *notify; int nnotifies; int checked; int result; char number[5]; char notify_buf[1024]; srand((unsigned)time(NULL)); /* Make a connection to the database */ conn = PQconnectdb(conninfo); /* Check to see that the backend connection was successfully made */ if (PQstatus(conn) != CONNECTION_OK) { elog(WARNING, "Connection to database failed: %s", PQerrorMessage(conn)); exit_nicely(conn); } /* * Issue LISTEN command to enable notifications from the rule's NOTIFY. */ res = PQexec(conn, "LISTEN HB_SV"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { elog(WARNING, "LISTEN command failed: %s", PQerrorMessage(conn)); PQclear(res); exit_nicely(conn); } /* * should PQclear PGresult whenever it is no longer needed to avoid memory * leaks */ PQclear(res); /* Set Secret Number */ memset(number, 0x00, 5); create_random_number(number); elog(LOG , "hb_worker: set secret number=%s\n", number); /* Quit after four notifies are received. */ nnotifies = 0; while (1) { /* * Sleep until something happens on the connection. We use select(2) * to wait for input, but you could also use poll() or similar * facilities. */ int sock; fd_set input_mask; sock = PQsocket(conn); if (sock < 0) break; /* shouldn't happen */ FD_ZERO(&input_mask); FD_SET(sock, &input_mask); if (select(sock + 1, &input_mask, NULL, NULL, NULL) < 0) { elog(WARNING, "select() failed: %s\n", strerror(errno)); exit_nicely(conn); } /* Now check for input */ PQconsumeInput(conn); while ((notify = PQnotifies(conn)) != NULL) { checked = check_number(notify->extra); switch (checked) { case NUMBER_COMMAND: result = compare_numbers(number, notify->extra); if (GET_HITS(result) == 4) { // Notify Game Clear, and Set new number. elog(LOG, "hb_worker: NOTIFY HB_CL,'4 Hit! Conguratulatoins!, next new game.'\n"); strcpy(notify_buf, "NOTIFY HB_CL,'4 Hit! Conguratulatoins!, next new game.'"); PQexec(conn, notify_buf); create_random_number(number); elog(LOG, "hb_worker: set secret number=%s\n", number); } else { // Notify Hit&blow elog(LOG, "NOTIFY HB_CL,'%d Hit / %d Blow.'", GET_HITS(result), GET_BLOWS(result)); sprintf(notify_buf, "NOTIFY HB_CL,'%d Hit / %d Blow.'", GET_HITS(result), GET_BLOWS(result)); PQexec(conn, notify_buf); } break; case START_COMMAND: // Set New number. elog(LOG, "hb_worker: Set New number."); create_random_number(number); break; case QUIT_COMMAND: // nop break; case INVALID_COMMAND: default: // NOTIFY error status sprintf(notify_buf, "NOTIFY HB_CL,'Invalid data.(%s)'", notify->extra); PQexec(conn, notify_buf); break; } PQfreemem(notify); nnotifies++; } } elog(LOG, "Done.\n"); /* close the connection to the database and cleanup */ PQfinish(conn); return 0; }
bool EpollPostgresql::epollEvent(const uint32_t &events) { if(conn==NULL) { std::cerr << "epollEvent() conn==NULL" << std::endl; return false; } const ConnStatusType &connStatusType=PQstatus(conn); if(connStatusType!=CONNECTION_OK) { if(connStatusType==CONNECTION_MADE) { started=true; std::cout << "Connexion CONNECTION_MADE" << std::endl; } else if(connStatusType==CONNECTION_STARTED) { started=true; std::cout << "Connexion CONNECTION_STARTED" << std::endl; } else if(connStatusType==CONNECTION_AWAITING_RESPONSE) std::cout << "Connexion CONNECTION_AWAITING_RESPONSE" << std::endl; else { if(connStatusType==CONNECTION_BAD) { started=false; std::cerr << "Connexion not ok: CONNECTION_BAD" << std::endl; //return false; } else if(connStatusType==CONNECTION_AUTH_OK) std::cerr << "Connexion not ok: CONNECTION_AUTH_OK" << std::endl; else if(connStatusType==CONNECTION_SETENV) std::cerr << "Connexion not ok: CONNECTION_SETENV" << std::endl; else if(connStatusType==CONNECTION_SSL_STARTUP) std::cerr << "Connexion not ok: CONNECTION_SSL_STARTUP" << std::endl; else if(connStatusType==CONNECTION_NEEDED) std::cerr << "Connexion not ok: CONNECTION_NEEDED" << std::endl; else std::cerr << "Connexion not ok: " << connStatusType << std::endl; } } if(connStatusType!=CONNECTION_BAD) { const PostgresPollingStatusType &postgresPollingStatusType=PQconnectPoll(conn); if(postgresPollingStatusType==PGRES_POLLING_FAILED) { std::cerr << "Connexion status: PGRES_POLLING_FAILED" << std::endl; return false; } } if(events & EPOLLIN) { const int PQconsumeInputVar=PQconsumeInput(conn); PGnotify *notify; while((notify = PQnotifies(conn)) != NULL) { std::cerr << "ASYNC NOTIFY of '" << notify->relname << "' received from backend PID " << notify->be_pid << std::endl; PQfreemem(notify); } if(/*PQisBusy(conn)==0, produce blocking, when server is unbusy this this never call*/true) { if(result!=NULL) clear(); tuleIndex=-1; ntuples=0; result=PQgetResult(conn); if(result==NULL) std::cerr << "query async send failed: " << errorMessage() << ", PQgetResult(conn) have returned NULL" << std::endl; else { auto end = std::chrono::high_resolution_clock::now(); std::chrono::duration<double, std::milli> elapsed = end-start; const uint32_t &ms=elapsed.count(); if(ms>5000) { if(queriesList.empty()) std::cerr << "query too slow, take " << ms << "ms" << std::endl; else std::cerr << queriesList.front().query << ": query too slow, take " << ms << "ms" << std::endl; } #ifdef DEBUG_MESSAGE_CLIENT_SQL else { if(queriesList.empty()) std::cout << "query take " << ms << "ms" << std::endl; else std::cout << queriesList.front().query << ": query take " << ms << "ms" << std::endl; } #endif start = std::chrono::high_resolution_clock::now(); while(result!=NULL) { const ExecStatusType &execStatusType=PQresultStatus(result); if(execStatusType!=PGRES_TUPLES_OK && execStatusType!=PGRES_COMMAND_OK) { #ifdef DEBUG_MESSAGE_CLIENT_SQL std::cerr << simplifiedstrCoPG << ", "; #endif if(queriesList.empty()) std::cerr << "Query to database failed: " << errorMessage() << std::endl; else std::cerr << "Query to database failed: " << errorMessage() << queriesList.front().query << std::endl; abort();//prevent continue running to prevent data corruption tuleIndex=0; } else ntuples=PQntuples(result); if(!queue.empty()) { CallBack callback=queue.front(); if(callback.method!=NULL) callback.method(callback.object); queue.erase(queue.cbegin()); } if(result!=NULL) clear(); if(!queriesList.empty()) queriesList.erase(queriesList.cbegin()); if(!queriesList.empty()) if(!sendNextQuery()) return false; result=PQgetResult(conn); } } } else std::cout << "PostgreSQL events with EPOLLIN: PQisBusy: " << std::to_string(PQconsumeInputVar) << std::endl; } if(events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR)) { started=false; if(events == EPOLLRDHUP) { std::cerr << "Database disconnected, try reconnect: " << errorMessage() << std::endl; syncDisconnect(); conn=NULL; syncReconnect(); } } return true; }