From e96373aae58f0e12a4c1845d5c10d94729a01b52 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 16 Jul 2006 18:17:14 +0000 Subject: [PATCH] Ensure that we retry rather than erroring out when send() or recv() return 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 | 27 ++++++++++++++++++++++----- src/backend/postmaster/postmaster.c | 13 +++++++++++-- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index ac51d2bab7..c971c06704 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -13,7 +13,7 @@ * * Copyright (c) 2001-2006, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.135 2006/07/14 14:52:22 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.136 2006/07/16 18:17:14 tgl Exp $ * ---------- */ #include "postgres.h" @@ -323,8 +323,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"))); @@ -375,8 +379,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"))); @@ -1533,17 +1540,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 } @@ -1718,9 +1731,13 @@ PgstatCollectorMain(int argc, char *argv[]) len = recv(pgStatSock, (char *) &msg, 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 diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index aa0f4e3418..6c8cf982ce 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.494 2006/07/15 15:47:17 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.495 2006/07/16 18:17:14 tgl Exp $ * * NOTES * @@ -1374,8 +1374,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"))); @@ -2524,6 +2528,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", @@ -2534,7 +2539,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); } -- 2.40.0