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
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);
* 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
typedef struct
{
sig_atomic_t av_signal[AutoVacNumSignals];
- pid_t av_launcherpid;
dclist_head av_freeWorkers;
dlist_head av_runningWorkers;
WorkerInfo av_startingWorker;
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
{
ereport(DEBUG1,
(errmsg_internal("autovacuum launcher shutting down")));
- AutoVacuumShmem->av_launcherpid = 0;
-
proc_exit(0); /* done */
}
*/
if (AutoVacuumShmem->av_startingWorker != NULL)
{
+ ProcNumber launcherProc;
+
MyWorkerInfo = AutoVacuumShmem->av_startingWorker;
dbid = MyWorkerInfo->wi_dboid;
MyWorkerInfo->wi_proc = MyProc;
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
{
{
WorkerInfo worker;
- AutoVacuumShmem->av_launcherpid = 0;
dclist_init(&AutoVacuumShmem->av_freeWorkers);
dlist_init(&AutoVacuumShmem->av_runningWorkers);
AutoVacuumShmem->av_startingWorker = NULL;
#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"
*/
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.
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)
{
/* ... 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);
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);
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
*/
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);
*/
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.
*/
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;
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;