static void LogChildExit(int lev, const char *procname,
int pid, int exitstatus);
static void PostmasterStateMachine(void);
+static void UpdatePMState(PMState newState);
static void ExitPostmaster(int status) pg_attribute_noreturn();
static int ServerLoop(void);
StartupPMChild = StartChildProcess(B_STARTUP);
Assert(StartupPMChild != NULL);
StartupStatus = STARTUP_RUNNING;
- pmState = PM_STARTUP;
+ UpdatePMState(PM_STARTUP);
/* Some workers may be scheduled to start now */
maybe_start_bgworkers();
else if (pmState == PM_STARTUP || pmState == PM_RECOVERY)
{
/* There should be no clients, so proceed to stop children */
- pmState = PM_STOP_BACKENDS;
+ UpdatePMState(PM_STOP_BACKENDS);
}
/*
if (pmState == PM_STARTUP || pmState == PM_RECOVERY)
{
/* Just shut down background processes silently */
- pmState = PM_STOP_BACKENDS;
+ UpdatePMState(PM_STOP_BACKENDS);
}
else if (pmState == PM_RUN ||
pmState == PM_HOT_STANDBY)
/* Report that we're about to zap live client sessions */
ereport(LOG,
(errmsg("aborting any active transactions")));
- pmState = PM_STOP_BACKENDS;
+ UpdatePMState(PM_STOP_BACKENDS);
}
/*
/* (note we don't apply send_abort_for_crash here) */
SetQuitSignalReason(PMQUIT_FOR_STOP);
TerminateChildren(SIGQUIT);
- pmState = PM_WAIT_BACKENDS;
+ UpdatePMState(PM_WAIT_BACKENDS);
/* set stopwatch for them to die */
AbortStartTime = time(NULL);
(EXIT_STATUS_0(exitstatus) || EXIT_STATUS_1(exitstatus)))
{
StartupStatus = STARTUP_NOT_RUNNING;
- pmState = PM_WAIT_BACKENDS;
+ UpdatePMState(PM_WAIT_BACKENDS);
/* PostmasterStateMachine logic does the rest */
continue;
}
StartupStatus = STARTUP_NOT_RUNNING;
Shutdown = Max(Shutdown, SmartShutdown);
TerminateChildren(SIGTERM);
- pmState = PM_WAIT_BACKENDS;
+ UpdatePMState(PM_WAIT_BACKENDS);
/* PostmasterStateMachine logic does the rest */
continue;
}
{
StartupStatus = STARTUP_NOT_RUNNING;
if (pmState == PM_STARTUP)
- pmState = PM_WAIT_BACKENDS;
+ UpdatePMState(PM_WAIT_BACKENDS);
}
else
StartupStatus = STARTUP_CRASHED;
FatalError = false;
AbortStartTime = 0;
ReachedNormalRunning = true;
- pmState = PM_RUN;
+ UpdatePMState(PM_RUN);
connsAllowed = true;
/*
*/
SignalChildren(SIGUSR2, btmask(B_WAL_SENDER));
- pmState = PM_SHUTDOWN_2;
+ UpdatePMState(PM_SHUTDOWN_2);
}
else
{
pmState == PM_RUN ||
pmState == PM_STOP_BACKENDS ||
pmState == PM_SHUTDOWN)
- pmState = PM_WAIT_BACKENDS;
+ UpdatePMState(PM_WAIT_BACKENDS);
/*
* .. and if this doesn't happen quickly enough, now the clock is ticking
* Then we're ready to stop other children.
*/
if (CountChildren(btmask(B_BACKEND)) == 0)
- pmState = PM_STOP_BACKENDS;
+ UpdatePMState(PM_STOP_BACKENDS);
}
}
SignalChildren(SIGTERM, targetMask);
- pmState = PM_WAIT_BACKENDS;
+ UpdatePMState(PM_WAIT_BACKENDS);
}
/* Are any of the target processes still running? */
/*
* Stop any dead-end children and stop creating new ones.
*/
- pmState = PM_WAIT_DEAD_END;
+ UpdatePMState(PM_WAIT_DEAD_END);
ConfigurePostmasterWaitSet(false);
SignalChildren(SIGQUIT, btmask(B_DEAD_END_BACKEND));
if (CheckpointerPMChild != NULL)
{
signal_child(CheckpointerPMChild, SIGUSR2);
- pmState = PM_SHUTDOWN;
+ UpdatePMState(PM_SHUTDOWN);
}
else
{
* for checkpointer fork failure.
*/
FatalError = true;
- pmState = PM_WAIT_DEAD_END;
+ UpdatePMState(PM_WAIT_DEAD_END);
ConfigurePostmasterWaitSet(false);
/* Kill the walsenders and archiver too */
*/
if (CountChildren(btmask_all_except2(B_LOGGER, B_DEAD_END_BACKEND)) == 0)
{
- pmState = PM_WAIT_DEAD_END;
+ UpdatePMState(PM_WAIT_DEAD_END);
ConfigurePostmasterWaitSet(false);
SignalChildren(SIGTERM, btmask_all_except(B_LOGGER));
}
Assert(AutoVacLauncherPMChild == NULL);
Assert(SlotSyncWorkerPMChild == NULL);
/* syslogger is not considered here */
- pmState = PM_NO_CHILDREN;
+ UpdatePMState(PM_NO_CHILDREN);
}
}
StartupPMChild = StartChildProcess(B_STARTUP);
Assert(StartupPMChild != NULL);
StartupStatus = STARTUP_RUNNING;
- pmState = PM_STARTUP;
+ UpdatePMState(PM_STARTUP);
/* crash recovery started, reset SIGKILL flag */
AbortStartTime = 0;
}
}
+static const char *
+pmstate_name(PMState state)
+{
+#define PM_TOSTR_CASE(sym) case sym: return #sym
+ switch (state)
+ {
+ PM_TOSTR_CASE(PM_INIT);
+ PM_TOSTR_CASE(PM_STARTUP);
+ PM_TOSTR_CASE(PM_RECOVERY);
+ PM_TOSTR_CASE(PM_HOT_STANDBY);
+ PM_TOSTR_CASE(PM_RUN);
+ PM_TOSTR_CASE(PM_STOP_BACKENDS);
+ PM_TOSTR_CASE(PM_WAIT_BACKENDS);
+ PM_TOSTR_CASE(PM_SHUTDOWN);
+ PM_TOSTR_CASE(PM_SHUTDOWN_2);
+ PM_TOSTR_CASE(PM_WAIT_DEAD_END);
+ PM_TOSTR_CASE(PM_NO_CHILDREN);
+ }
+#undef PM_TOSTR_CASE
+
+ pg_unreachable();
+ return ""; /* silence compiler */
+}
+
+/*
+ * Simple wrapper for updating pmState. The main reason to have this wrapper
+ * is that it makes it easy to log all state transitions.
+ */
+static void
+UpdatePMState(PMState newState)
+{
+ elog(DEBUG1, "updating PMState from %s to %s",
+ pmstate_name(pmState), pmstate_name(newState));
+ pmState = newState;
+}
+
/*
* Launch background processes after state change, or relaunch after an
* existing process has exited.
#endif
}
- pmState = PM_RECOVERY;
+ UpdatePMState(PM_RECOVERY);
}
if (CheckPostmasterSignal(PMSIGNAL_BEGIN_HOT_STANDBY) &&
sd_notify(0, "READY=1");
#endif
- pmState = PM_HOT_STANDBY;
+ UpdatePMState(PM_HOT_STANDBY);
connsAllowed = true;
/* Some workers may be scheduled to start now */