diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 60d29a2089a..0edd7f1dc7f 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -3811,12 +3811,8 @@ PostmasterStateMachine(void) * dead_end children left. There shouldn't be any regular backends * left by now anyway; what we're really waiting for is walsenders and * archiver. - * - * Walreceiver should normally be dead by now, but not when a fast - * shutdown is performed during recovery. */ - if (PgArchPID == 0 && CountChildren(BACKEND_TYPE_ALL) == 0 && - WalReceiverPID == 0) + if (PgArchPID == 0 && CountChildren(BACKEND_TYPE_ALL) == 0) { pmState = PM_WAIT_DEAD_END; } @@ -5213,16 +5209,25 @@ sigusr1_handler(SIGNAL_ARGS) MaybeStartWalReceiver(); } - if (CheckPostmasterSignal(PMSIGNAL_ADVANCE_STATE_MACHINE) && - (pmState == PM_WAIT_BACKUP || pmState == PM_WAIT_BACKENDS)) + /* + * Try to advance postmaster's state machine, if a child requests it. + * + * Be careful about the order of this action relative to sigusr1_handler's + * other actions. Generally, this should be after other actions, in case + * they have effects PostmasterStateMachine would need to know about. + * However, we should do it before the CheckPromoteSignal step, which + * cannot have any (immediate) effect on the state machine, but does + * depend on what state we're in now. + */ + if (CheckPostmasterSignal(PMSIGNAL_ADVANCE_STATE_MACHINE)) { - /* Advance postmaster's state machine */ PostmasterStateMachine(); } - if (CheckPromoteSignal() && StartupPID != 0 && + if (StartupPID != 0 && (pmState == PM_STARTUP || pmState == PM_RECOVERY || - pmState == PM_HOT_STANDBY || pmState == PM_WAIT_READONLY)) + pmState == PM_HOT_STANDBY || pmState == PM_WAIT_READONLY) && + CheckPromoteSignal()) { /* Tell startup process to finish recovery */ signal_child(StartupPID, SIGUSR2); @@ -5518,6 +5523,14 @@ StartAutovacuumWorker(void) /* * MaybeStartWalReceiver * Start the WAL receiver process, if not running and our state allows. + * + * Note: if WalReceiverPID is already nonzero, it might seem that we should + * clear WalReceiverRequested. However, there's a race condition if the + * walreceiver terminates and the startup process immediately requests a new + * one: it's quite possible to get the signal for the request before reaping + * the dead walreceiver process. Better to risk launching an extra + * walreceiver than to miss launching one we need. (The walreceiver code + * has logic to recognize that it should go away if not needed.) */ static void MaybeStartWalReceiver(void) @@ -5528,7 +5541,9 @@ MaybeStartWalReceiver(void) Shutdown == NoShutdown) { WalReceiverPID = StartWalReceiver(); - WalReceiverRequested = false; + if (WalReceiverPID != 0) + WalReceiverRequested = false; + /* else leave the flag set, so we'll try again later */ } }