Refactor how some aux processes advertise their ProcNumber

This moves the responsibility of setting the ProcGlobal->walwriterProc
and checkpointerProc fields into InitAuxiliaryProcess. Also switch to
the same pattern to advertise the autovacuum launcher's ProcNumber,
replacing the ad hoc av_launcherpid field in shared memory. This can
easily be extended to other aux processes in the future, if other
processes need to find them.

Switch to pg_atomic_uint32 for the fields. Seems easier to reason
about than volatile pointers. There was some precedence for that, as
were already using pg_atomic_uint32 for the procArrayGroupFirst and
clogGroupFirst fields, which also store ProcNumbers.

Todo: We could also replace WalRecv->procno with this, but that's a
little more code churn so I left that for the future.

Reviewed-by: Andres Freund <andres@anarazel.de>
Discussion: https://www.postgresql.org/message-id/818bafaf-1e77-4c78-8037-d7120878d87c@iki.fi
This commit is contained in:
Heikki Linnakangas 2026-07-08 20:33:36 +03:00
parent ad7877b00a
commit 842169b6c1
6 changed files with 49 additions and 32 deletions

View file

@ -2671,8 +2671,7 @@ XLogSetAsyncXactLSN(XLogRecPtr asyncXactLSN)
if (wakeup)
{
volatile PROC_HDR *procglobal = ProcGlobal;
ProcNumber walwriterProc = procglobal->walwriterProc;
ProcNumber walwriterProc = pg_atomic_read_u32(&ProcGlobal->walwriterProc);
if (walwriterProc != INVALID_PROC_NUMBER)
SetLatch(&GetPGProcByNumber(walwriterProc)->procLatch);

View file

@ -286,7 +286,6 @@ typedef struct AutoVacuumWorkItem
* struct and the array of WorkerInfo structs. This struct keeps:
*
* av_signal set by other processes to indicate various conditions
* av_launcherpid the PID of the autovacuum launcher
* av_freeWorkers the WorkerInfo freelist
* av_runningWorkers the WorkerInfo non-free queue
* av_startingWorker pointer to WorkerInfo currently being started (cleared by
@ -302,7 +301,6 @@ typedef struct AutoVacuumWorkItem
typedef struct
{
sig_atomic_t av_signal[AutoVacNumSignals];
pid_t av_launcherpid;
dclist_head av_freeWorkers;
dlist_head av_runningWorkers;
WorkerInfo av_startingWorker;
@ -602,8 +600,6 @@ AutoVacLauncherMain(const void *startup_data, size_t startup_data_len)
proc_exit(0); /* done */
}
AutoVacuumShmem->av_launcherpid = MyProcPid;
/*
* Create the initial database list. The invariant we want this list to
* keep is that it's ordered by decreasing next_worker. As soon as an
@ -837,8 +833,6 @@ AutoVacLauncherShutdown(void)
{
ereport(DEBUG1,
(errmsg_internal("autovacuum launcher shutting down")));
AutoVacuumShmem->av_launcherpid = 0;
proc_exit(0); /* done */
}
@ -1569,6 +1563,8 @@ AutoVacWorkerMain(const void *startup_data, size_t startup_data_len)
*/
if (AutoVacuumShmem->av_startingWorker != NULL)
{
ProcNumber launcherProc;
MyWorkerInfo = AutoVacuumShmem->av_startingWorker;
dbid = MyWorkerInfo->wi_dboid;
MyWorkerInfo->wi_proc = MyProc;
@ -1587,8 +1583,14 @@ AutoVacWorkerMain(const void *startup_data, size_t startup_data_len)
on_shmem_exit(FreeWorkerInfo, 0);
/* wake up the launcher */
if (AutoVacuumShmem->av_launcherpid != 0)
kill(AutoVacuumShmem->av_launcherpid, SIGUSR2);
launcherProc = pg_atomic_read_u32(&ProcGlobal->avLauncherProc);
if (launcherProc != INVALID_PROC_NUMBER)
{
int pid = GetPGProcByNumber(launcherProc)->pid;
if (pid != 0)
kill(pid, SIGUSR2);
}
}
else
{
@ -3559,7 +3561,6 @@ AutoVacuumShmemInit(void *arg)
{
WorkerInfo worker;
AutoVacuumShmem->av_launcherpid = 0;
dclist_init(&AutoVacuumShmem->av_freeWorkers);
dlist_init(&AutoVacuumShmem->av_runningWorkers);
AutoVacuumShmem->av_startingWorker = NULL;

View file

@ -47,6 +47,7 @@
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "port/atomics.h"
#include "postmaster/auxprocess.h"
#include "postmaster/bgwriter.h"
#include "postmaster/interrupt.h"
@ -358,12 +359,6 @@ CheckpointerMain(const void *startup_data, size_t startup_data_len)
*/
UpdateSharedMemoryConfig();
/*
* Advertise our proc number that backends can use to wake us up while
* we're sleeping.
*/
ProcGlobal->checkpointerProc = MyProcNumber;
/*
* Loop until we've been asked to write the shutdown checkpoint or
* terminate.
@ -1120,7 +1115,7 @@ RequestCheckpoint(int flags)
for (ntries = 0;; ntries++)
{
volatile PROC_HDR *procglobal = ProcGlobal;
ProcNumber checkpointerProc = procglobal->checkpointerProc;
ProcNumber checkpointerProc = pg_atomic_read_u32(&procglobal->checkpointerProc);
if (checkpointerProc == INVALID_PROC_NUMBER)
{
@ -1261,8 +1256,7 @@ ForwardSyncRequest(const FileTag *ftag, SyncRequestType type)
/* ... but not till after we release the lock */
if (too_full)
{
volatile PROC_HDR *procglobal = ProcGlobal;
ProcNumber checkpointerProc = procglobal->checkpointerProc;
ProcNumber checkpointerProc = pg_atomic_read_u32(&ProcGlobal->checkpointerProc);
if (checkpointerProc != INVALID_PROC_NUMBER)
SetLatch(&GetPGProcByNumber(checkpointerProc)->procLatch);
@ -1543,7 +1537,7 @@ void
WakeupCheckpointer(void)
{
volatile PROC_HDR *procglobal = ProcGlobal;
ProcNumber checkpointerProc = procglobal->checkpointerProc;
ProcNumber checkpointerProc = pg_atomic_read_u32(&procglobal->checkpointerProc);
if (checkpointerProc != INVALID_PROC_NUMBER)
SetLatch(&GetPGProcByNumber(checkpointerProc)->procLatch);

View file

@ -206,12 +206,6 @@ WalWriterMain(const void *startup_data, size_t startup_data_len)
hibernating = false;
SetWalWriterSleeping(false);
/*
* Advertise our proc number that backends can use to wake us up while
* we're sleeping.
*/
ProcGlobal->walwriterProc = MyProcNumber;
/*
* Loop forever
*/

View file

@ -240,8 +240,9 @@ ProcGlobalShmemInit(void *arg)
dlist_init(&ProcGlobal->bgworkerFreeProcs);
dlist_init(&ProcGlobal->walsenderFreeProcs);
ProcGlobal->startupBufferPinWaitBufId = -1;
ProcGlobal->walwriterProc = INVALID_PROC_NUMBER;
ProcGlobal->checkpointerProc = INVALID_PROC_NUMBER;
pg_atomic_init_u32(&ProcGlobal->avLauncherProc, INVALID_PROC_NUMBER);
pg_atomic_init_u32(&ProcGlobal->walwriterProc, INVALID_PROC_NUMBER);
pg_atomic_init_u32(&ProcGlobal->checkpointerProc, INVALID_PROC_NUMBER);
pg_atomic_init_u32(&ProcGlobal->procArrayGroupFirst, INVALID_PROC_NUMBER);
pg_atomic_init_u32(&ProcGlobal->clogGroupFirst, INVALID_PROC_NUMBER);
@ -724,6 +725,14 @@ InitAuxiliaryProcess(void)
*/
PGSemaphoreReset(MyProc->sem);
/* Some aux processes are also advertised in ProcGlobal */
if (MyBackendType == B_AUTOVAC_LAUNCHER)
pg_atomic_write_u32(&ProcGlobal->avLauncherProc, MyProcNumber);
if (MyBackendType == B_WAL_WRITER)
pg_atomic_write_u32(&ProcGlobal->walwriterProc, MyProcNumber);
if (MyBackendType == B_CHECKPOINTER)
pg_atomic_write_u32(&ProcGlobal->checkpointerProc, MyProcNumber);
/*
* Arrange to clean up at process exit.
*/
@ -1101,6 +1110,25 @@ AuxiliaryProcKill(int code, Datum arg)
SwitchBackToLocalLatch();
pgstat_reset_wait_event_storage();
/*
* If this was one of the aux processes advertised in ProcGlobal, clear it
*/
if (MyBackendType == B_AUTOVAC_LAUNCHER)
{
Assert(pg_atomic_read_u32(&ProcGlobal->avLauncherProc) == MyProcNumber);
pg_atomic_write_u32(&ProcGlobal->avLauncherProc, INVALID_PROC_NUMBER);
}
if (MyBackendType == B_WAL_WRITER)
{
Assert(pg_atomic_read_u32(&ProcGlobal->walwriterProc) == MyProcNumber);
pg_atomic_write_u32(&ProcGlobal->walwriterProc, INVALID_PROC_NUMBER);
}
if (MyBackendType == B_CHECKPOINTER)
{
Assert(pg_atomic_read_u32(&ProcGlobal->checkpointerProc) == MyProcNumber);
pg_atomic_write_u32(&ProcGlobal->checkpointerProc, INVALID_PROC_NUMBER);
}
proc = MyProc;
MyProc = NULL;
MyProcNumber = INVALID_PROC_NUMBER;

View file

@ -488,11 +488,12 @@ typedef struct PROC_HDR
pg_atomic_uint32 clogGroupFirst;
/*
* Current slot numbers of some auxiliary processes. There can be only one
* Current proc numbers of some auxiliary processes. There can be only one
* of each of these running at a time.
*/
ProcNumber walwriterProc;
ProcNumber checkpointerProc;
pg_atomic_uint32 avLauncherProc;
pg_atomic_uint32 walwriterProc;
pg_atomic_uint32 checkpointerProc;
/* Current shared estimate of appropriate spins_per_delay value */
int spins_per_delay;