static void pgstat_recvbuffer(void);
static void pgstat_exit(SIGNAL_ARGS);
static void pgstat_die(SIGNAL_ARGS);
+static void pgstat_beshutdown_hook(int code, Datum arg);
static int pgstat_add_backend(PgStat_MsgHdr *msg);
static void pgstat_sub_backend(int procpid);
* packet filtering rules prevent it).
*/
test_byte = TESTBYTEVAL;
+
+retry1:
if (send(pgStatSock, &test_byte, 1, 0) != 1)
{
+ if (errno == EINTR)
+ goto retry1; /* if interrupted, just retry */
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not send test message on socket for statistics collector: %m")));
test_byte++; /* just make sure variable is changed */
+retry2:
if (recv(pgStatSock, &test_byte, 1, 0) != 1)
{
+ if (errno == EINTR)
+ goto retry2; /* if interrupted, just retry */
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not receive test message on socket for statistics collector: %m")));
* messages will be discarded; backends won't block waiting to send
* messages to the collector.
*/
- if (!set_noblock(pgStatSock))
+ if (!pg_set_noblock(pgStatSock))
{
ereport(LOG,
(errcode_for_socket_access(),
pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_BESTART);
pgstat_send(&msg, sizeof(msg));
+
+ /*
+ * Set up a process-exit hook to ensure we flush the last batch of
+ * statistics to the collector.
+ */
+ on_proc_exit(pgstat_beshutdown_hook, 0);
+}
+
+/*
+ * Flush any remaining statistics counts out to the collector at process
+ * exit. Without this, operations triggered during backend exit (such as
+ * temp table deletions) won't be counted. This is an on_proc_exit hook,
+ * not on_shmem_exit, so that everything interesting must have happened
+ * already.
+ */
+static void
+pgstat_beshutdown_hook(int code, Datum arg)
+{
+ pgstat_report_tabstat();
}
static void
pgstat_send(void *msg, int len)
{
+ int rc;
+
if (pgStatSock < 0)
return;
((PgStat_MsgHdr *) msg)->m_size = len;
- send(pgStatSock, msg, len, 0);
- /* We deliberately ignore any error from send() */
+ /* We'll retry after EINTR, but ignore all other failures */
+ do
+ {
+ rc = send(pgStatSock, msg, len, 0);
+ } while (rc < 0 && errno == EINTR);
+
+#ifdef USE_ASSERT_CHECKING
+ /* In debug builds, log send failures ... */
+ if (rc < 0)
+ elog(LOG, "could not send to statistics collector: %m");
+#endif
}
* Set the write pipe to nonblock mode, so that we cannot block when
* the collector falls behind.
*/
- if (!set_noblock(writePipe))
+ if (!pg_set_noblock(writePipe))
ereport(ERROR,
(errcode_for_socket_access(),
errmsg("could not set statistics collector pipe to nonblocking mode: %m")));
len = recv(pgStatSock, (char *) &input_buffer,
sizeof(PgStat_Msg), 0);
if (len < 0)
+ {
+ if (errno == EINTR)
+ continue;
ereport(ERROR,
(errcode_for_socket_access(),
errmsg("could not read statistics message: %m")));
+ }
/*
* We ignore messages that are smaller than our common header
#else
SSLok = 'N'; /* No support for SSL */
#endif
+
+retry1:
if (send(port->sock, &SSLok, 1, 0) != 1)
{
+ if (errno == EINTR)
+ goto retry1; /* if interrupted, just retry */
ereport(COMMERROR,
(errcode_for_socket_access(),
errmsg("failed to send SSL negotiation response: %m")));
report_fork_failure_to_client(Port *port, int errnum)
{
char buffer[1000];
+ int rc;
/* Format the error message packet (always V2 protocol) */
snprintf(buffer, sizeof(buffer), "E%s%s\n",
if (!pg_set_noblock(port->sock))
return;
- send(port->sock, buffer, strlen(buffer) + 1, 0);
+ /* We'll retry after EINTR, but ignore all other failures */
+ do
+ {
+ rc = send(port->sock, buffer, strlen(buffer) + 1, 0);
+ } while (rc < 0 && errno == EINTR);
}