Skip to content

Commit 3354f85

Browse files
committed
Consolidate postmaster code to launch background processes
Much of the code in process_pm_child_exit() to launch replacement processes when one exits or when progressing to next postmaster state was unnecessary, because the ServerLoop will launch any missing background processes anyway. Remove the redundant code and let ServerLoop handle it. In ServerLoop, move the code to launch all the processes to a new subroutine, to group it all together. Reviewed-by: Thomas Munro <thomas.munro@gmail.com> Discussion: https://www.postgresql.org/message-id/8f2118b9-79e3-4af7-b2c9-bd5818193ca4@iki.fi
1 parent 4eb5089 commit 3354f85

File tree

1 file changed

+122
-157
lines changed

1 file changed

+122
-157
lines changed

src/backend/postmaster/postmaster.c

Lines changed: 122 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -417,26 +417,12 @@ static void TerminateChildren(int signal);
417417

418418
static int CountChildren(int target);
419419
static Backend *assign_backendlist_entry(void);
420+
static void LaunchMissingBackgroundProcesses(void);
420421
static void maybe_start_bgworkers(void);
421422
static bool CreateOptsFile(int argc, char *argv[], char *fullprogname);
422423
static pid_t StartChildProcess(BackendType type);
423424
static void StartAutovacuumWorker(void);
424-
static void MaybeStartWalReceiver(void);
425-
static void MaybeStartWalSummarizer(void);
426425
static void InitPostmasterDeathWatchHandle(void);
427-
static void MaybeStartSlotSyncWorker(void);
428-
429-
/*
430-
* Archiver is allowed to start up at the current postmaster state?
431-
*
432-
* If WAL archiving is enabled always, we are allowed to start archiver
433-
* even during recovery.
434-
*/
435-
#define PgArchStartupAllowed() \
436-
(((XLogArchivingActive() && pmState == PM_RUN) || \
437-
(XLogArchivingAlways() && \
438-
(pmState == PM_RECOVERY || pmState == PM_HOT_STANDBY))) && \
439-
PgArchCanRestart())
440426

441427
#ifdef WIN32
442428
#define WNOHANG 0 /* ignored, so any integer value will do */
@@ -1670,53 +1656,11 @@ ServerLoop(void)
16701656
}
16711657
}
16721658

1673-
/* If we have lost the log collector, try to start a new one */
1674-
if (SysLoggerPID == 0 && Logging_collector)
1675-
SysLoggerPID = SysLogger_Start();
1676-
1677-
/*
1678-
* If no background writer process is running, and we are not in a
1679-
* state that prevents it, start one. It doesn't matter if this
1680-
* fails, we'll just try again later. Likewise for the checkpointer.
1681-
*/
1682-
if (pmState == PM_RUN || pmState == PM_RECOVERY ||
1683-
pmState == PM_HOT_STANDBY || pmState == PM_STARTUP)
1684-
{
1685-
if (CheckpointerPID == 0)
1686-
CheckpointerPID = StartChildProcess(B_CHECKPOINTER);
1687-
if (BgWriterPID == 0)
1688-
BgWriterPID = StartChildProcess(B_BG_WRITER);
1689-
}
1690-
16911659
/*
1692-
* Likewise, if we have lost the walwriter process, try to start a new
1693-
* one. But this is needed only in normal operation (else we cannot
1694-
* be writing any new WAL).
1660+
* If we need to launch any background processes after changing state
1661+
* or because some exited, do so now.
16951662
*/
1696-
if (WalWriterPID == 0 && pmState == PM_RUN)
1697-
WalWriterPID = StartChildProcess(B_WAL_WRITER);
1698-
1699-
/*
1700-
* If we have lost the autovacuum launcher, try to start a new one. We
1701-
* don't want autovacuum to run in binary upgrade mode because
1702-
* autovacuum might update relfrozenxid for empty tables before the
1703-
* physical files are put in place.
1704-
*/
1705-
if (!IsBinaryUpgrade && AutoVacPID == 0 &&
1706-
(AutoVacuumingActive() || start_autovac_launcher) &&
1707-
pmState == PM_RUN)
1708-
{
1709-
AutoVacPID = StartChildProcess(B_AUTOVAC_LAUNCHER);
1710-
if (AutoVacPID != 0)
1711-
start_autovac_launcher = false; /* signal processed */
1712-
}
1713-
1714-
/* If we have lost the archiver, try to start a new one. */
1715-
if (PgArchPID == 0 && PgArchStartupAllowed())
1716-
PgArchPID = StartChildProcess(B_ARCHIVER);
1717-
1718-
/* If we need to start a slot sync worker, try to do that now */
1719-
MaybeStartSlotSyncWorker();
1663+
LaunchMissingBackgroundProcesses();
17201664

17211665
/* If we need to signal the autovacuum launcher, do so now */
17221666
if (avlauncher_needs_signal)
@@ -1726,17 +1670,6 @@ ServerLoop(void)
17261670
kill(AutoVacPID, SIGUSR2);
17271671
}
17281672

1729-
/* If we need to start a WAL receiver, try to do that now */
1730-
if (WalReceiverRequested)
1731-
MaybeStartWalReceiver();
1732-
1733-
/* If we need to start a WAL summarizer, try to do that now */
1734-
MaybeStartWalSummarizer();
1735-
1736-
/* Get other worker processes running, if needed */
1737-
if (StartWorkerNeeded || HaveCrashedWorker)
1738-
maybe_start_bgworkers();
1739-
17401673
#ifdef HAVE_PTHREAD_IS_THREADED_NP
17411674

17421675
/*
@@ -2386,23 +2319,11 @@ process_pm_child_exit(void)
23862319
connsAllowed = true;
23872320

23882321
/*
2389-
* Crank up any background tasks that we didn't start earlier
2390-
* already. It doesn't matter if any of these fail, we'll just
2391-
* try again later.
2322+
* At the next iteration of the postmaster's main loop, we will
2323+
* crank up the background tasks like the autovacuum launcher and
2324+
* background workers that were not started earlier already.
23922325
*/
2393-
if (CheckpointerPID == 0)
2394-
CheckpointerPID = StartChildProcess(B_CHECKPOINTER);
2395-
if (BgWriterPID == 0)
2396-
BgWriterPID = StartChildProcess(B_BG_WRITER);
2397-
if (WalWriterPID == 0)
2398-
WalWriterPID = StartChildProcess(B_WAL_WRITER);
2399-
MaybeStartWalSummarizer();
2400-
if (!IsBinaryUpgrade && AutoVacuumingActive() && AutoVacPID == 0)
2401-
AutoVacPID = StartChildProcess(B_AUTOVAC_LAUNCHER);
2402-
if (PgArchStartupAllowed() && PgArchPID == 0)
2403-
PgArchPID = StartChildProcess(B_ARCHIVER);
2404-
MaybeStartSlotSyncWorker();
2405-
maybe_start_bgworkers();
2326+
StartWorkerNeeded = true;
24062327

24072328
/* at this point we are really open for business */
24082329
ereport(LOG,
@@ -2541,20 +2462,15 @@ process_pm_child_exit(void)
25412462
/*
25422463
* Was it the archiver? If exit status is zero (normal) or one (FATAL
25432464
* exit), we assume everything is all right just like normal backends
2544-
* and just try to restart a new one so that we immediately retry
2545-
* archiving remaining files. (If fail, we'll try again in future
2546-
* cycles of the postmaster's main loop.) Unless we were waiting for
2547-
* it to shut down; don't restart it in that case, and
2548-
* PostmasterStateMachine() will advance to the next shutdown step.
2465+
* and just try to start a new one on the next cycle of the
2466+
* postmaster's main loop, to retry archiving remaining files.
25492467
*/
25502468
if (pid == PgArchPID)
25512469
{
25522470
PgArchPID = 0;
25532471
if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_1(exitstatus))
25542472
HandleChildCrash(pid, exitstatus,
25552473
_("archiver process"));
2556-
if (PgArchStartupAllowed())
2557-
PgArchPID = StartChildProcess(B_ARCHIVER);
25582474
continue;
25592475
}
25602476

@@ -3207,6 +3123,118 @@ PostmasterStateMachine(void)
32073123
}
32083124
}
32093125

3126+
/*
3127+
* Launch background processes after state change, or relaunch after an
3128+
* existing process has exited.
3129+
*
3130+
* Check the current pmState and the status of any background processes. If
3131+
* there are any background processes missing that should be running in the
3132+
* current state, but are not, launch them.
3133+
*/
3134+
static void
3135+
LaunchMissingBackgroundProcesses(void)
3136+
{
3137+
/* Syslogger is active in all states */
3138+
if (SysLoggerPID == 0 && Logging_collector)
3139+
SysLoggerPID = SysLogger_Start();
3140+
3141+
/*
3142+
* The checkpointer and the background writer are active from the start,
3143+
* until shutdown is initiated.
3144+
*
3145+
* (If the checkpointer is not running when we enter the the PM_SHUTDOWN
3146+
* state, it is launched one more time to perform the shutdown checkpoint.
3147+
* That's done in PostmasterStateMachine(), not here.)
3148+
*/
3149+
if (pmState == PM_RUN || pmState == PM_RECOVERY ||
3150+
pmState == PM_HOT_STANDBY || pmState == PM_STARTUP)
3151+
{
3152+
if (CheckpointerPID == 0)
3153+
CheckpointerPID = StartChildProcess(B_CHECKPOINTER);
3154+
if (BgWriterPID == 0)
3155+
BgWriterPID = StartChildProcess(B_BG_WRITER);
3156+
}
3157+
3158+
/*
3159+
* WAL writer is needed only in normal operation (else we cannot be
3160+
* writing any new WAL).
3161+
*/
3162+
if (WalWriterPID == 0 && pmState == PM_RUN)
3163+
WalWriterPID = StartChildProcess(B_WAL_WRITER);
3164+
3165+
/*
3166+
* We don't want autovacuum to run in binary upgrade mode because
3167+
* autovacuum might update relfrozenxid for empty tables before the
3168+
* physical files are put in place.
3169+
*/
3170+
if (!IsBinaryUpgrade && AutoVacPID == 0 &&
3171+
(AutoVacuumingActive() || start_autovac_launcher) &&
3172+
pmState == PM_RUN)
3173+
{
3174+
AutoVacPID = StartChildProcess(B_AUTOVAC_LAUNCHER);
3175+
if (AutoVacPID != 0)
3176+
start_autovac_launcher = false; /* signal processed */
3177+
}
3178+
3179+
/*
3180+
* If WAL archiving is enabled always, we are allowed to start archiver
3181+
* even during recovery.
3182+
*/
3183+
if (PgArchPID == 0 &&
3184+
((XLogArchivingActive() && pmState == PM_RUN) ||
3185+
(XLogArchivingAlways() && (pmState == PM_RECOVERY || pmState == PM_HOT_STANDBY))) &&
3186+
PgArchCanRestart())
3187+
PgArchPID = StartChildProcess(B_ARCHIVER);
3188+
3189+
/*
3190+
* If we need to start a slot sync worker, try to do that now
3191+
*
3192+
* We allow to start the slot sync worker when we are on a hot standby,
3193+
* fast or immediate shutdown is not in progress, slot sync parameters are
3194+
* configured correctly, and it is the first time of worker's launch, or
3195+
* enough time has passed since the worker was launched last.
3196+
*/
3197+
if (SlotSyncWorkerPID == 0 && pmState == PM_HOT_STANDBY &&
3198+
Shutdown <= SmartShutdown && sync_replication_slots &&
3199+
ValidateSlotSyncParams(LOG) && SlotSyncWorkerCanRestart())
3200+
SlotSyncWorkerPID = StartChildProcess(B_SLOTSYNC_WORKER);
3201+
3202+
/*
3203+
* If we need to start a WAL receiver, try to do that now
3204+
*
3205+
* Note: if WalReceiverPID is already nonzero, it might seem that we
3206+
* should clear WalReceiverRequested. However, there's a race condition
3207+
* if the walreceiver terminates and the startup process immediately
3208+
* requests a new one: it's quite possible to get the signal for the
3209+
* request before reaping the dead walreceiver process. Better to risk
3210+
* launching an extra walreceiver than to miss launching one we need. (The
3211+
* walreceiver code has logic to recognize that it should go away if not
3212+
* needed.)
3213+
*/
3214+
if (WalReceiverRequested)
3215+
{
3216+
if (WalReceiverPID == 0 &&
3217+
(pmState == PM_STARTUP || pmState == PM_RECOVERY ||
3218+
pmState == PM_HOT_STANDBY) &&
3219+
Shutdown <= SmartShutdown)
3220+
{
3221+
WalReceiverPID = StartChildProcess(B_WAL_RECEIVER);
3222+
if (WalReceiverPID != 0)
3223+
WalReceiverRequested = false;
3224+
/* else leave the flag set, so we'll try again later */
3225+
}
3226+
}
3227+
3228+
/* If we need to start a WAL summarizer, try to do that now */
3229+
if (summarize_wal && WalSummarizerPID == 0 &&
3230+
(pmState == PM_RUN || pmState == PM_HOT_STANDBY) &&
3231+
Shutdown <= SmartShutdown)
3232+
WalSummarizerPID = StartChildProcess(B_WAL_SUMMARIZER);
3233+
3234+
/* Get other worker processes running, if needed */
3235+
if (StartWorkerNeeded || HaveCrashedWorker)
3236+
maybe_start_bgworkers();
3237+
}
32103238

32113239
/*
32123240
* Send a signal to a postmaster child process
@@ -3558,9 +3586,6 @@ process_pm_pmsignal(void)
35583586
StartWorkerNeeded = true;
35593587
}
35603588

3561-
if (StartWorkerNeeded || HaveCrashedWorker)
3562-
maybe_start_bgworkers();
3563-
35643589
/* Tell syslogger to rotate logfile if requested */
35653590
if (SysLoggerPID != 0)
35663591
{
@@ -3600,9 +3625,7 @@ process_pm_pmsignal(void)
36003625
if (CheckPostmasterSignal(PMSIGNAL_START_WALRECEIVER))
36013626
{
36023627
/* Startup Process wants us to start the walreceiver process. */
3603-
/* Start immediately if possible, else remember request for later. */
36043628
WalReceiverRequested = true;
3605-
MaybeStartWalReceiver();
36063629
}
36073630

36083631
/*
@@ -3796,64 +3819,6 @@ StartAutovacuumWorker(void)
37963819
}
37973820
}
37983821

3799-
/*
3800-
* MaybeStartWalReceiver
3801-
* Start the WAL receiver process, if not running and our state allows.
3802-
*
3803-
* Note: if WalReceiverPID is already nonzero, it might seem that we should
3804-
* clear WalReceiverRequested. However, there's a race condition if the
3805-
* walreceiver terminates and the startup process immediately requests a new
3806-
* one: it's quite possible to get the signal for the request before reaping
3807-
* the dead walreceiver process. Better to risk launching an extra
3808-
* walreceiver than to miss launching one we need. (The walreceiver code
3809-
* has logic to recognize that it should go away if not needed.)
3810-
*/
3811-
static void
3812-
MaybeStartWalReceiver(void)
3813-
{
3814-
if (WalReceiverPID == 0 &&
3815-
(pmState == PM_STARTUP || pmState == PM_RECOVERY ||
3816-
pmState == PM_HOT_STANDBY) &&
3817-
Shutdown <= SmartShutdown)
3818-
{
3819-
WalReceiverPID = StartChildProcess(B_WAL_RECEIVER);
3820-
if (WalReceiverPID != 0)
3821-
WalReceiverRequested = false;
3822-
/* else leave the flag set, so we'll try again later */
3823-
}
3824-
}
3825-
3826-
/*
3827-
* MaybeStartWalSummarizer
3828-
* Start the WAL summarizer process, if not running and our state allows.
3829-
*/
3830-
static void
3831-
MaybeStartWalSummarizer(void)
3832-
{
3833-
if (summarize_wal && WalSummarizerPID == 0 &&
3834-
(pmState == PM_RUN || pmState == PM_HOT_STANDBY) &&
3835-
Shutdown <= SmartShutdown)
3836-
WalSummarizerPID = StartChildProcess(B_WAL_SUMMARIZER);
3837-
}
3838-
3839-
3840-
/*
3841-
* MaybeStartSlotSyncWorker
3842-
* Start the slot sync worker, if not running and our state allows.
3843-
*
3844-
* We allow to start the slot sync worker when we are on a hot standby,
3845-
* fast or immediate shutdown is not in progress, slot sync parameters
3846-
* are configured correctly, and it is the first time of worker's launch,
3847-
* or enough time has passed since the worker was launched last.
3848-
*/
3849-
static void
3850-
MaybeStartSlotSyncWorker(void)
3851-
{
3852-
if (SlotSyncWorkerPID == 0 && pmState == PM_HOT_STANDBY &&
3853-
Shutdown <= SmartShutdown && sync_replication_slots &&
3854-
ValidateSlotSyncParams(LOG) && SlotSyncWorkerCanRestart())
3855-
SlotSyncWorkerPID = StartChildProcess(B_SLOTSYNC_WORKER);
3856-
}
38573822

38583823
/*
38593824
* Create the opts file

0 commit comments

Comments
 (0)