Subject: pgsql: Refactor how some aux processes advertise their ProcNumber

From: Heikki Linnakangas <[email-masked]>
Date: Wed, 08 Jul 2026 17:43:01 +0000

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 <[email-masked]>
Discussion: https://www.postgresql.org/message-id/[email-masked]

Branch
------
master

Details
-------
https://git.postgresql.org/pg/commitdiff/842169b6c110f48c9f7a2dc29d0cedcc97c2ff29

Modified Files
--------------
src/backend/access/transam/xlog.c     |  3 +--
src/backend/postmaster/autovacuum.c   | 19 ++++++++++---------
src/backend/postmaster/checkpointer.c | 14 ++++----------
src/backend/postmaster/walwriter.c    |  6 ------
src/backend/storage/lmgr/proc.c       | 32 ++++++++++++++++++++++++++++++--
src/include/storage/proc.h            |  7 ++++---
6 files changed, 49 insertions(+), 32 deletions(-)

---

From: Thom Brown <[email-masked]>
Date: Wed, 8 Jul 2026 22:57:00 +0100

> https://git.postgresql.org/pg/commitdiff/842169b6c110f48c9f7a2dc29d0cedcc97c2ff29

@@ -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);

I'm looking for the places this gets called from. I can only see
auxprocess.c which the launcher doesn't go through. The same question
for similar code in AuxiliaryProcKill().

Thom

---

From: Fujii Masao <[email-masked]>
Date: Thu, 9 Jul 2026 09:57:27 +0900

> for similar code in AuxiliaryProcKill().

You're right. The autovacuum launcher does not go through
AuxiliaryProcessMainCommon(), so it never calls
InitAuxiliaryProcess(). Instead, it initializes its PGPROC with
InitProcess().

As a result, the avLauncherProc assignment added to
InitAuxiliaryProcess() is never executed for the launcher, and the
corresponding cleanup in AuxiliaryProcKill() is never reached either.

It seems we should move the avLauncherProc set/clear operations to
InitProcess()/ProcKill() path, as in the attached patch.

Regards,

-- 
Fujii Masao

---

From: Nathan Bossart <[email-masked]>
Date: Wed, 8 Jul 2026 22:10:55 -0500

> clogGroupFirst fields, which also store ProcNumbers.

Since removing volatile qualifiers is on my mind, I noticed that this patch
makes it possible to remove two more.  Patch attached.

-- 
nathan
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index a09d4097d51..f6351f1eb10 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -1114,8 +1114,7 @@ RequestCheckpoint(int flags)
 #define MAX_SIGNAL_TRIES 600	/* max wait 60.0 sec */
 	for (ntries = 0;; ntries++)
 	{
-		volatile PROC_HDR *procglobal = ProcGlobal;
-		ProcNumber	checkpointerProc = pg_atomic_read_u32(&procglobal->checkpointerProc);
+		ProcNumber	checkpointerProc = pg_atomic_read_u32(&ProcGlobal->checkpointerProc);
 
 		if (checkpointerProc == INVALID_PROC_NUMBER)
 		{
@@ -1536,8 +1535,7 @@ FirstCallSinceLastCheckpoint(void)
 void
 WakeupCheckpointer(void)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
-	ProcNumber	checkpointerProc = pg_atomic_read_u32(&procglobal->checkpointerProc);
+	ProcNumber	checkpointerProc = pg_atomic_read_u32(&ProcGlobal->checkpointerProc);
 
 	if (checkpointerProc != INVALID_PROC_NUMBER)
 		SetLatch(&GetPGProcByNumber(checkpointerProc)->procLatch);

---

From: Thom Brown <[email-masked]>
Date: Thu, 9 Jul 2026 12:09:23 +0100

> makes it possible to remove two more.  Patch attached.

+1

---

From: Heikki Linnakangas <[email-masked]>
Date: Thu, 9 Jul 2026 15:17:53 +0300

> corresponding cleanup in AuxiliaryProcKill() is never reached either.

Huh, you're right. That raises some questions:

Why is the autovacuum launcher not an aux process? I guess it's because 
it needs to acquire a heavy-weight lock in order to read the list of 
databases.

How come none of the tests failed? I guess the path to wake up the 
launcher isn't critical for correctness, it just makes autovacuum slower 
to react.

> InitProcess()/ProcKill() path, as in the attached patch.
Thanks! Committed that, and also Nathan's volatile removal.

- Heikki

---

From: Fujii Masao <[email-masked]>
Date: Thu, 9 Jul 2026 21:34:50 +0900

> it needs to acquire a heavy-weight lock in order to read the list of

That seems to be one of the reasons, based on the comment about auxiliary
processes in miscadmin.h:

-------------------------
* Auxiliary processes. These have PGPROC entries, but they are not
* attached to any particular database, and cannot run transactions or
* even take heavyweight locks. There can be only one of each of these
* running at a time, except for IO workers.
-------------------------

Regards,

-- 
Fujii Masao

---

From: Álvaro Herrera <[email-masked]>
Date: Thu, 9 Jul 2026 14:36:04 +0200

On 2026-Jul-09, Heikki Linnakangas wrote:

> Why is the autovacuum launcher not an aux process? I guess it's because it
> needs to acquire a heavy-weight lock in order to read the list of databases.

Because it scans pg_database.

commit 00e6a16d01683762c2f34eb4909fc739093ab3bf
Author:     Tom Lane <[email-masked]> []
AuthorDate: Mon Aug 31 19:41:00 2009 +0000
CommitDate: Mon Aug 31 19:41:00 2009 +0000

    Change the autovacuum launcher to read pg_database directly, rather than
    via the "flat files" facility.  This requires making it enough like a backend
    to be able to run transactions; it's no longer an "auxiliary process" but
    more like the autovacuum worker processes.  Also, its signal handling has
    to be brought into line with backends/workers.  In particular, since it
    now has to handle procsignal.c processing, the special autovac-launcher-only
    signal conditions are moved to SIGUSR2.
    
    Alvaro, with some cleanup from Tom

-- 
Álvaro Herrera               48°01'N 7°57'E  —  https://www.EnterpriseDB.com/
"If you want to have good ideas, you must have many ideas.  Most of them
will be wrong, and what you have to learn is which ones to throw away."
                                                         (Linus Pauling)