]> granicus.if.org Git - postgresql/commitdiff
Don't launch new child processes after we've been told to shut down.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 21 Nov 2012 20:18:38 +0000 (15:18 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 21 Nov 2012 20:19:30 +0000 (15:19 -0500)
Once we've received a shutdown signal (SIGINT or SIGTERM), we should not
launch any more child processes, even if we get signals requesting such.
The normal code path for spawning backends has always understood that,
but the postmaster's infrastructure for hot standby and autovacuum didn't
get the memo.  As reported by Hari Babu in bug #7643, this could lead to
failure to shut down at all in some cases, such as when SIGINT is received
just before the startup process sends PMSIGNAL_RECOVERY_STARTED: we'd
launch a bgwriter and checkpointer, and then those processes would have no
idea that they ought to quit.  Similarly, launching a new autovacuum worker
would result in waiting till it finished before shutting down.

Also, switch the order of the code blocks in reaper() that detect startup
process crash versus shutdown termination.  Once we've sent it a signal,
we should not consider that exit(1) is surprising.  This is just a cosmetic
fix since shutdown occurs correctly anyway, but better not to log a phony
complaint about startup process crash.

Back-patch to 9.0.  Some parts of this might be applicable before that,
but given the lack of prior complaints I'm not going to worry too much
about older branches.

src/backend/postmaster/postmaster.c

index b223feefbab0645667449f643c6c8adee3747ef0..6f93d93fa3f7577fb9157f0bea805c427e3605dd 100644 (file)
@@ -2261,9 +2261,9 @@ pmdie(SIGNAL_ARGS)
                        if (pmState == PM_RECOVERY)
                        {
                                /*
-                                * Only startup, bgwriter, and checkpointer should be active
-                                * in this state; we just signaled the first two, and we don't
-                                * want to kill checkpointer yet.
+                                * Only startup, bgwriter, walreceiver, and/or checkpointer
+                                * should be active in this state; we just signaled the first
+                                * three, and we don't want to kill checkpointer yet.
                                 */
                                pmState = PM_WAIT_BACKENDS;
                        }
@@ -2354,6 +2354,18 @@ reaper(SIGNAL_ARGS)
                {
                        StartupPID = 0;
 
+                       /*
+                        * Startup process exited in response to a shutdown request (or it
+                        * completed normally regardless of the shutdown request).
+                        */
+                       if (Shutdown > NoShutdown &&
+                               (EXIT_STATUS_0(exitstatus) || EXIT_STATUS_1(exitstatus)))
+                       {
+                               pmState = PM_WAIT_BACKENDS;
+                               /* PostmasterStateMachine logic does the rest */
+                               continue;
+                       }
+
                        /*
                         * Unexpected exit of startup process (including FATAL exit)
                         * during PM_STARTUP is treated as catastrophic. There are no
@@ -2368,18 +2380,6 @@ reaper(SIGNAL_ARGS)
                                ExitPostmaster(1);
                        }
 
-                       /*
-                        * Startup process exited in response to a shutdown request (or it
-                        * completed normally regardless of the shutdown request).
-                        */
-                       if (Shutdown > NoShutdown &&
-                               (EXIT_STATUS_0(exitstatus) || EXIT_STATUS_1(exitstatus)))
-                       {
-                               pmState = PM_WAIT_BACKENDS;
-                               /* PostmasterStateMachine logic does the rest */
-                               continue;
-                       }
-
                        /*
                         * After PM_STARTUP, any unexpected exit (including FATAL exit) of
                         * the startup process is catastrophic, so kill other children,
@@ -4283,7 +4283,7 @@ sigusr1_handler(SIGNAL_ARGS)
         * first. We don't want to go back to recovery in that case.
         */
        if (CheckPostmasterSignal(PMSIGNAL_RECOVERY_STARTED) &&
-               pmState == PM_STARTUP)
+               pmState == PM_STARTUP && Shutdown == NoShutdown)
        {
                /* WAL redo has started. We're out of reinitialization. */
                FatalError = false;
@@ -4300,7 +4300,7 @@ sigusr1_handler(SIGNAL_ARGS)
                pmState = PM_RECOVERY;
        }
        if (CheckPostmasterSignal(PMSIGNAL_BEGIN_HOT_STANDBY) &&
-               pmState == PM_RECOVERY)
+               pmState == PM_RECOVERY && Shutdown == NoShutdown)
        {
                /*
                 * Likewise, start other special children as needed.
@@ -4331,7 +4331,8 @@ sigusr1_handler(SIGNAL_ARGS)
                signal_child(SysLoggerPID, SIGUSR1);
        }
 
-       if (CheckPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER))
+       if (CheckPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER) &&
+               Shutdown == NoShutdown)
        {
                /*
                 * Start one iteration of the autovacuum daemon, even if autovacuuming
@@ -4345,7 +4346,8 @@ sigusr1_handler(SIGNAL_ARGS)
                start_autovac_launcher = true;
        }
 
-       if (CheckPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER))
+       if (CheckPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER) &&
+               Shutdown == NoShutdown)
        {
                /* The autovacuum launcher wants us to start a worker process. */
                StartAutovacuumWorker();
@@ -4354,7 +4356,8 @@ sigusr1_handler(SIGNAL_ARGS)
        if (CheckPostmasterSignal(PMSIGNAL_START_WALRECEIVER) &&
                WalReceiverPID == 0 &&
                (pmState == PM_STARTUP || pmState == PM_RECOVERY ||
-                pmState == PM_HOT_STANDBY || pmState == PM_WAIT_READONLY))
+                pmState == PM_HOT_STANDBY || pmState == PM_WAIT_READONLY) &&
+               Shutdown == NoShutdown)
        {
                /* Startup Process wants us to start the walreceiver process. */
                WalReceiverPID = StartWalReceiver();