diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 24add74..6845794 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -272,6 +272,7 @@ static StartupStatusEnum StartupStatus = STARTUP_NOT_RUNNING; static int Shutdown = NoShutdown; static bool FatalError = false; /* T if recovering from backend crash */ +static bool ClosedSockets = false; /* T if recovering from backend crash */ /* * We use a simple state machine to control startup, shutdown, and @@ -379,6 +380,7 @@ static void getInstallationPaths(const char *argv0); static void checkDataDir(void); static Port *ConnCreate(int serverFd); static void ConnFree(Port *port); +static void ClosePostmasterSockets(void); static void reset_shared(int port); static void SIGHUP_handler(SIGNAL_ARGS); static void pmdie(SIGNAL_ARGS); @@ -1520,6 +1522,13 @@ DetermineSleepTime(struct timeval * timeout) { TimestampTz next_wakeup = 0; + if (pmState == PM_WAIT_DEAD_END) + { + timeout->tv_sec = 0; + timeout->tv_usec = 100000; + return; + } + /* * Normal case: either there are no background workers at all, or we're in * a shutdown sequence (during which we ignore bgworkers altogether). @@ -1630,6 +1639,8 @@ ServerLoop(void) fd_set rmask; int selres; time_t now; + /* must set timeout each time; some OSes change it! */ + struct timeval timeout; /* * Wait for a connection request to arrive. @@ -1641,32 +1652,25 @@ ServerLoop(void) * If we are in PM_WAIT_DEAD_END state, then we don't want to accept * any new connections, so we don't call select(), and just sleep. */ - memcpy((char *) &rmask, (char *) &readmask, sizeof(fd_set)); - if (pmState == PM_WAIT_DEAD_END) + /* Needs to run with blocked signals! */ + DetermineSleepTime(&timeout); + + PG_SETMASK(&UnBlockSig); + + if (pmState == PM_WAIT_DEAD_END || ClosedSockets) { - PG_SETMASK(&UnBlockSig); - - pg_usleep(100000L); /* 100 msec seems reasonable */ + pg_usleep(timeout.tv_sec * 1000000L + timeout.tv_usec); selres = 0; - - PG_SETMASK(&BlockSig); } else { - /* must set timeout each time; some OSes change it! */ - struct timeval timeout; - - /* Needs to run with blocked signals! */ - DetermineSleepTime(&timeout); - - PG_SETMASK(&UnBlockSig); - + memcpy((char *) &rmask, (char *) &readmask, sizeof(fd_set)); selres = select(nSockets, &rmask, NULL, NULL, &timeout); - - PG_SETMASK(&BlockSig); } + PG_SETMASK(&BlockSig); + /* Now check the select() result */ if (selres < 0) { @@ -2389,6 +2393,26 @@ ConnFree(Port *conn) /* + * ClosePostmasterSockets -- close all the postmaster's listen sockets + */ +static void +ClosePostmasterSockets(void) +{ + int i; + + for (i = 0; i < MAXLISTEN; i++) + { + if (ListenSocket[i] != PGINVALID_SOCKET) + { + StreamClose(ListenSocket[i]); + ListenSocket[i] = PGINVALID_SOCKET; + } + } + + ClosedSockets = true; +} + +/* * ClosePostmasterPorts -- close all the postmaster's open sockets * * This is called during child process startup to release file descriptors @@ -2401,8 +2425,6 @@ ConnFree(Port *conn) void ClosePostmasterPorts(bool am_syslogger) { - int i; - #ifndef WIN32 /* @@ -2418,14 +2440,7 @@ ClosePostmasterPorts(bool am_syslogger) #endif /* Close the listen sockets */ - for (i = 0; i < MAXLISTEN; i++) - { - if (ListenSocket[i] != PGINVALID_SOCKET) - { - StreamClose(ListenSocket[i]); - ListenSocket[i] = PGINVALID_SOCKET; - } - } + ClosePostmasterSockets(); /* If using syslogger, close the read side of the pipe */ if (!am_syslogger) @@ -2674,6 +2689,12 @@ pmdie(SIGNAL_ARGS) sd_notify(0, "STOPPING=1"); #endif + /* + * Close the listen sockets to avoid wasting resources by creating + * dead-end children, so that postmaster stops as fast as possible. + */ + ClosePostmasterSockets(); + TerminateChildren(SIGQUIT); pmState = PM_WAIT_BACKENDS; @@ -3221,6 +3242,15 @@ HandleChildCrash(int pid, int exitstatus, const char *procname) LogChildExit(LOG, procname, pid, exitstatus); ereport(LOG, (errmsg("terminating any other active server processes"))); + + /* + * If the startup process failed, or the user does not want an automatic + * restart after backend crashes, close the listen sockets to avoid wasting + * resources by creating dead-end children, so that postmaster stops as + * fast as possible. + */ + if (StartupStatus == STARTUP_CRASHED || !restart_after_crash) + ClosePostmasterSockets(); } /* Process background workers. */