From 8edd8c77c88e75822334ccb8376d2c151d6e5615 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Fri, 24 Jan 2025 17:00:10 -0500 Subject: [PATCH] postmaster: Move code to switch into FatalError state into function There are two places switching to FatalError mode, behaving somewhat differently. An upcoming commit will introduce a third. That doesn't seem seem like a good idea. This commit just moves the FatalError related code from HandleChildCrash() into its own function, a subsequent commit will evolve the state machine change to be suitable for other callers. Reviewed-by: Bertrand Drouvot Discussion: https://postgr.es/m/kgng5nrvnlv335evmsuvpnh354rw7qyazl73kdysev2cr2v5zu@m3cfzxicm5kp --- src/backend/postmaster/postmaster.c | 76 ++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 24 deletions(-) diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index a24c0385fe6..a92fe4240b2 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -2673,6 +2673,55 @@ CleanupBackend(PMChild *bp, LogChildExit(DEBUG2, procname, bp_pid, exitstatus); } +/* + * Transition into FatalError state, in response to something bad having + * happened. Commonly the caller will have logged the reason for entering + * FatalError state. + * + * This should only be called when not already in FatalError or + * ImmediateShutdown state. + */ +static void +HandleFatalError(QuitSignalReason reason, bool consider_sigabrt) +{ + int sigtosend; + + Assert(!FatalError); + Assert(Shutdown != ImmediateShutdown); + + SetQuitSignalReason(reason); + + if (consider_sigabrt && send_abort_for_crash) + sigtosend = SIGABRT; + else + sigtosend = SIGQUIT; + + /* + * Signal all other child processes to exit. + * + * We could exclude dead-end children here, but at least when sending + * SIGABRT it seems better to include them. + */ + TerminateChildren(sigtosend); + + FatalError = true; + + /* We now transit into a state of waiting for children to die */ + if (pmState == PM_RECOVERY || + pmState == PM_HOT_STANDBY || + pmState == PM_RUN || + pmState == PM_STOP_BACKENDS || + pmState == PM_WAIT_XLOG_SHUTDOWN) + UpdatePMState(PM_WAIT_BACKENDS); + + /* + * .. and if this doesn't happen quickly enough, now the clock is ticking + * for us to kill them without mercy. + */ + if (AbortStartTime == 0) + AbortStartTime = time(NULL); +} + /* * HandleChildCrash -- cleanup after failed backend, bgwriter, checkpointer, * walwriter, autovacuum, archiver, slot sync worker, or background worker. @@ -2698,33 +2747,12 @@ HandleChildCrash(int pid, int exitstatus, const char *procname) LogChildExit(LOG, procname, pid, exitstatus); ereport(LOG, (errmsg("terminating any other active server processes"))); - SetQuitSignalReason(PMQUIT_FOR_CRASH); /* - * Signal all other child processes to exit. The crashed process has - * already been removed from ActiveChildList. - * - * We could exclude dead-end children here, but at least when sending - * SIGABRT it seems better to include them. + * Switch into error state. The crashed process has already been removed + * from ActiveChildList. */ - TerminateChildren(send_abort_for_crash ? SIGABRT : SIGQUIT); - - FatalError = true; - - /* We now transit into a state of waiting for children to die */ - if (pmState == PM_RECOVERY || - pmState == PM_HOT_STANDBY || - pmState == PM_RUN || - pmState == PM_STOP_BACKENDS || - pmState == PM_WAIT_XLOG_SHUTDOWN) - UpdatePMState(PM_WAIT_BACKENDS); - - /* - * .. and if this doesn't happen quickly enough, now the clock is ticking - * for us to kill them without mercy. - */ - if (AbortStartTime == 0) - AbortStartTime = time(NULL); + HandleFatalError(PMQUIT_FOR_CRASH, true); } /*