From d9c3c943653740d1df44385c3cd658ed67bb4fb2 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Thu, 15 Jan 2026 18:02:25 +0200 Subject: [PATCH] Wake up autovacuum launcher from postmaster when a worker exits When an autovacuum worker exits, the launcher needs to be notified with SIGUSR2, so that it can rebalance and possibly launch a new worker. The launcher must be notified only after the worker has finished ProcKill(), so that the worker slot is available for a new worker. Before this commit, the autovacuum worker was responsible for that, which required a slightly complicated dance to pass the launcher's PID from FreeWorkerInfo() to ProcKill() in a global variable. Simplify that by moving the responsibility of the signaling to the postmaster. The postmaster was already doing it when it failed to fork a worker process, so it seems logical to make it responsible for notifying the launcher on worker exit too. That's also how the notification on background worker exit is done. Reviewed-by: Nathan Bossart Reviewed-by: Masahiko Sawada Reviewed-by: li carol Discussion: https://www.postgresql.org/message-id/a5e27d25-c7e7-45d5-9bac-a17c8f462def@iki.fi --- src/backend/postmaster/autovacuum.c | 22 ---------------------- src/backend/postmaster/postmaster.c | 8 ++++++++ src/backend/storage/lmgr/proc.c | 4 ---- src/include/postmaster/autovacuum.h | 3 --- 4 files changed, 8 insertions(+), 29 deletions(-) diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 3e507d23cc9..22379de1e31 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -323,9 +323,6 @@ avl_dbase *avl_dbase_array; /* Pointer to my own WorkerInfo, valid on each worker */ static WorkerInfo MyWorkerInfo = NULL; -/* PID of launcher, valid only in worker while shutting down */ -int AutovacuumLauncherPid = 0; - static Oid do_start_worker(void); static void ProcessAutoVacLauncherInterrupts(void); pg_noreturn static void AutoVacLauncherShutdown(void); @@ -1604,11 +1601,6 @@ AutoVacWorkerMain(const void *startup_data, size_t startup_data_len) do_autovacuum(); } - /* - * The launcher will be notified of my death in ProcKill, *if* we managed - * to get a worker slot at all - */ - /* All done, go away */ proc_exit(0); } @@ -1623,20 +1615,6 @@ FreeWorkerInfo(int code, Datum arg) { LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE); - /* - * Wake the launcher up so that he can launch a new worker immediately - * if required. We only save the launcher's PID in local memory here; - * the actual signal will be sent when the PGPROC is recycled. Note - * that we always do this, so that the launcher can rebalance the cost - * limit setting of the remaining workers. - * - * We somewhat ignore the risk that the launcher changes its PID - * between us reading it and the actual kill; we expect ProcKill to be - * called shortly after us, and we assume that PIDs are not reused too - * quickly after a process exits. - */ - AutovacuumLauncherPid = AutoVacuumShmem->av_launcherpid; - dlist_delete(&MyWorkerInfo->wi_links); MyWorkerInfo->wi_dboid = InvalidOid; MyWorkerInfo->wi_tableoid = InvalidOid; diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 921d73226d6..d6133bfebc6 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -2664,6 +2664,14 @@ CleanupBackend(PMChild *bp, if (bp_bgworker_notify) BackgroundWorkerStopNotifications(bp_pid); + /* + * If it was an autovacuum worker, wake up the launcher so that it can + * immediately launch a new worker or rebalance to cost limit setting of + * the remaining workers. + */ + if (bp_bkend_type == B_AUTOVAC_WORKER && AutoVacLauncherPMChild != NULL) + signal_child(AutoVacLauncherPMChild, SIGUSR2); + /* * If it was a background worker, also update its RegisteredBgWorker * entry. diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 66274029c74..063826ae576 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -1035,10 +1035,6 @@ ProcKill(int code, Datum arg) ProcGlobal->spins_per_delay = update_spins_per_delay(ProcGlobal->spins_per_delay); SpinLockRelease(ProcStructLock); - - /* wake autovac launcher if needed -- see comments in FreeWorkerInfo */ - if (AutovacuumLauncherPid != 0) - kill(AutovacuumLauncherPid, SIGUSR2); } /* diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h index e43067d0260..5aa0f3a8ac1 100644 --- a/src/include/postmaster/autovacuum.h +++ b/src/include/postmaster/autovacuum.h @@ -44,9 +44,6 @@ extern PGDLLIMPORT int autovacuum_multixact_freeze_max_age; extern PGDLLIMPORT double autovacuum_vac_cost_delay; extern PGDLLIMPORT int autovacuum_vac_cost_limit; -/* autovacuum launcher PID, only valid when worker is shutting down */ -extern PGDLLIMPORT int AutovacuumLauncherPid; - extern PGDLLIMPORT int Log_autovacuum_min_duration; extern PGDLLIMPORT int Log_autoanalyze_min_duration;