]> granicus.if.org Git - postgresql/commitdiff
Ensure that we retry rather than erroring out when send() or recv() return
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 16 Jul 2006 18:17:23 +0000 (18:17 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 16 Jul 2006 18:17:23 +0000 (18:17 +0000)
EINTR; the stats code was failing to do this and so were a couple of places
in the postmaster.  The stats code assumed that recv() could not return EINTR
if a preceding select() showed the socket to be read-ready, but this is
demonstrably false with our Windows implementation of recv(), and it may
not be the case on all Unix variants either.  I think this explains the
intermittent stats regression test failures we've been seeing, as well
as reports of stats collector instability under high load on Windows.

Backpatch as far as 8.0.

src/backend/postmaster/pgstat.c
src/backend/postmaster/postmaster.c

index 01ae9c13939238b30a78f68d3c00874a04ed52c7..76d49abeae5dc48f6999985a8f4b45dd9c93df94 100644 (file)
@@ -13,7 +13,7 @@
  *
  *     Copyright (c) 2001-2005, PostgreSQL Global Development Group
  *
- *     $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.111.2.5 2006/06/27 14:01:42 tgl Exp $
+ *     $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.111.2.6 2006/07/16 18:17:23 tgl Exp $
  * ----------
  */
 #include "postgres.h"
@@ -339,8 +339,12 @@ pgstat_init(void)
                 * 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")));
@@ -391,8 +395,11 @@ pgstat_init(void)
 
                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")));
@@ -1431,17 +1438,23 @@ pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype)
 static void
 pgstat_send(void *msg, int len)
 {
+       int                     rc;
+
        if (pgStatSock < 0)
                return;
 
        ((PgStat_MsgHdr *) msg)->m_size = len;
 
+       /* 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
-       if (send(pgStatSock, msg, len, 0) < 0)
+       /* In debug builds, log send failures ... */
+       if (rc < 0)
                elog(LOG, "could not send to statistics collector: %m");
-#else
-       send(pgStatSock, msg, len, 0);
-       /* We deliberately ignore any error from send() */
 #endif
 }
 
@@ -1972,9 +1985,13 @@ pgstat_recvbuffer(void)
                        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
index fb45b89587bd2f5a2fd4675efc1c316b349eb08a..a7858c40989ff484804d5e58a711e802c8a67fbc 100644 (file)
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.475.2.5 2006/05/19 15:15:38 alvherre Exp $
+ *       $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.475.2.6 2006/07/16 18:17:23 tgl Exp $
  *
  * NOTES
  *
@@ -1408,8 +1408,12 @@ ProcessStartupPacket(Port *port, bool SSLdone)
 #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")));
@@ -2545,6 +2549,7 @@ static void
 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",
@@ -2555,7 +2560,11 @@ report_fork_failure_to_client(Port *port, int errnum)
        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);
 }