Subject: Preferred use of macro GetPGProcByNumber

From: "Maksim.Melnikov" <[email-masked]>
Date: Fri, 12 Sep 2025 15:39:09 +0300

Hello hackers,
I've noticed some places where elements of ProcGlobal->allProcs are 
addressed directly via arr index.
But in proc.h macros GetPGProcByNumber exist, that was added to get proc 
objects by index,
so I suggest minor refactoring 'ProcGlobal->allProcs[index]' -> 
'GetPGProcByNumber(index)'.
Please, see attached patch, branched from rev 6ede13d1b5f.

Best regards
Melnikov Maksim
From f03b596e8fd3fa80f86843babb1704fae4032480 Mon Sep 17 00:00:00 2001
From: Maksim Melnikov <[email-masked]>
Date: Fri, 12 Sep 2025 15:17:39 +0300
Subject: [PATCH v1] Preferred use of macro GetPGProcByNumber.

Minor refactoring, using of GetPGProcByNumber(index) macros
instead of ProcGlobal->allProcs[index].
---
 src/backend/access/transam/clog.c      |  4 +-
 src/backend/postmaster/pgarch.c        |  2 +-
 src/backend/postmaster/walsummarizer.c |  2 +-
 src/backend/storage/buffer/freelist.c  |  2 +-
 src/backend/storage/ipc/procarray.c    | 64 ++++++++++++--------------
 src/backend/storage/lmgr/lock.c        |  6 +--
 src/backend/storage/lmgr/proc.c        |  2 +-
 7 files changed, 39 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index e80fbe109cf..bbdcce39990 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -574,7 +574,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	/* Walk the list and update the status of all XIDs. */
 	while (nextidx != INVALID_PROC_NUMBER)
 	{
-		PGPROC	   *nextproc = &ProcGlobal->allProcs[nextidx];
+		PGPROC	   *nextproc = GetPGProcByNumber(nextidx);
 		int64		thispageno = nextproc->clogGroupMemberPage;
 
 		/*
@@ -633,7 +633,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 */
 	while (wakeidx != INVALID_PROC_NUMBER)
 	{
-		PGPROC	   *wakeproc = &ProcGlobal->allProcs[wakeidx];
+		PGPROC	   *wakeproc = GetPGProcByNumber(wakeidx);
 
 		wakeidx = pg_atomic_read_u32(&wakeproc->clogGroupNext);
 		pg_atomic_write_u32(&wakeproc->clogGroupNext, INVALID_PROC_NUMBER);
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 78e39e5f866..a35895babeb 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -289,7 +289,7 @@ PgArchWakeup(void)
 	 * be relaunched shortly and will start archiving.
 	 */
 	if (arch_pgprocno != INVALID_PROC_NUMBER)
-		SetLatch(&ProcGlobal->allProcs[arch_pgprocno].procLatch);
+		SetLatch(&GetPGProcByNumber(arch_pgprocno)->procLatch);
 }

diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c
index e1f142f20c7..69461ea9a79 100644
--- a/src/backend/postmaster/walsummarizer.c
+++ b/src/backend/postmaster/walsummarizer.c
@@ -649,7 +649,7 @@ WakeupWalSummarizer(void)
 	LWLockRelease(WALSummarizerLock);
 
 	if (pgprocno != INVALID_PROC_NUMBER)
-		SetLatch(&ProcGlobal->allProcs[pgprocno].procLatch);
+		SetLatch(&GetPGProcByNumber(pgprocno)->procLatch);
 }
 
 /*
diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c
index 01909be0272..2fbd254e4bc 100644
--- a/src/backend/storage/buffer/freelist.c
+++ b/src/backend/storage/buffer/freelist.c
@@ -239,7 +239,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r
 		 * actually fine because procLatch isn't ever freed, so we just can
 		 * potentially set the wrong process' (or no process') latch.
 		 */
-		SetLatch(&ProcGlobal->allProcs[bgwprocno].procLatch);
+		SetLatch(&GetPGProcByNumber(bgwprocno)->procLatch);
 	}
 
 	/*
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 200f72c6e25..d3b9680b562 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -268,8 +268,6 @@ typedef enum KAXCompressReason
 
 static ProcArrayStruct *procArray;
 
-static PGPROC *allProcs;
-
 /*
  * Cache to reduce overhead of repeated calls to TransactionIdIsInProgress()
  */
@@ -444,8 +442,6 @@ ProcArrayShmemInit(void)
 		TransamVariables->xactCompletionCount = 1;
 	}
 
-	allProcs = ProcGlobal->allProcs;
-
 	/* Create or attach to the KnownAssignedXids arrays too, if needed */
 	if (EnableHotStandby)
 	{
@@ -502,7 +498,7 @@ ProcArrayAdd(PGPROC *proc)
 		int			this_procno = arrayP->pgprocnos[index];
 
 		Assert(this_procno >= 0 && this_procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
-		Assert(allProcs[this_procno].pgxactoff == index);
+		Assert(GetPGProcByNumber(this_procno)->pgxactoff == index);
 
 		/* If we have found our right position in the array, break */
 		if (this_procno > pgprocno)
@@ -538,9 +534,9 @@ ProcArrayAdd(PGPROC *proc)
 		int			procno = arrayP->pgprocnos[index];
 
 		Assert(procno >= 0 && procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
-		Assert(allProcs[procno].pgxactoff == index - 1);
+		Assert(GetPGProcByNumber(procno)->pgxactoff == index - 1);
 
-		allProcs[procno].pgxactoff = index;
+		GetPGProcByNumber(procno)->pgxactoff = index;
 	}
 
 	/*
@@ -581,7 +577,7 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid)
 	myoff = proc->pgxactoff;
 
 	Assert(myoff >= 0 && myoff < arrayP->numProcs);
-	Assert(ProcGlobal->allProcs[arrayP->pgprocnos[myoff]].pgxactoff == myoff);
+	Assert(GetPGProcByNumber(arrayP->pgprocnos[myoff])->pgxactoff == myoff);
 
 	if (TransactionIdIsValid(latestXid))
 	{
@@ -636,9 +632,9 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid)
 		int			procno = arrayP->pgprocnos[index];
 
 		Assert(procno >= 0 && procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
-		Assert(allProcs[procno].pgxactoff - 1 == index);
+		Assert(GetPGProcByNumber(procno)->pgxactoff - 1 == index);
 
-		allProcs[procno].pgxactoff = index;
+		GetPGProcByNumber(procno)->pgxactoff = index;
 	}
 
 	/*
@@ -860,7 +856,7 @@ ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid)
 	/* Walk the list and clear all XIDs. */
 	while (nextidx != INVALID_PROC_NUMBER)
 	{
-		PGPROC	   *nextproc = &allProcs[nextidx];
+		PGPROC	   *nextproc = GetPGProcByNumber(nextidx);
 
 		ProcArrayEndTransactionInternal(nextproc, nextproc->procArrayGroupMemberXid);
 
@@ -880,7 +876,7 @@ ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid)
 	 */
 	while (wakeidx != INVALID_PROC_NUMBER)
 	{
-		PGPROC	   *nextproc = &allProcs[wakeidx];
+		PGPROC	   *nextproc = GetPGProcByNumber(wakeidx);
 
 		wakeidx = pg_atomic_read_u32(&nextproc->procArrayGroupNext);
 		pg_atomic_write_u32(&nextproc->procArrayGroupNext, INVALID_PROC_NUMBER);
@@ -1526,7 +1522,7 @@ TransactionIdIsInProgress(TransactionId xid)
 		pxids = other_subxidstates[pgxactoff].count;
 		pg_read_barrier();		/* pairs with barrier in GetNewTransactionId() */
 		pgprocno = arrayP->pgprocnos[pgxactoff];
-		proc = &allProcs[pgprocno];
+		proc = GetPGProcByNumber(pgprocno);
 		for (j = pxids - 1; j >= 0; j--)
 		{
 			/* Fetch xid just once - see GetNewTransactionId */
@@ -1740,7 +1736,7 @@ ComputeXidHorizons(ComputeXidHorizonsResult *h)
 	for (int index = 0; index < arrayP->numProcs; index++)
 	{
 		int			pgprocno = arrayP->pgprocnos[index];
-		PGPROC	   *proc = &allProcs[pgprocno];
+		PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 		int8		statusFlags = ProcGlobal->statusFlags[index];
 		TransactionId xid;
 		TransactionId xmin;
@@ -2224,7 +2220,7 @@ GetSnapshotData(Snapshot snapshot)
 			TransactionId xid = UINT32_ACCESS_ONCE(other_xids[pgxactoff]);
 			uint8		statusFlags;
 
-			Assert(allProcs[arrayP->pgprocnos[pgxactoff]].pgxactoff == pgxactoff);
+			Assert(GetPGProcByNumber(arrayP->pgprocnos[pgxactoff])->pgxactoff == pgxactoff);
 
 			/*
 			 * If the transaction has no XID assigned, we can skip it; it
@@ -2298,7 +2294,7 @@ GetSnapshotData(Snapshot snapshot)
 					if (nsubxids > 0)
 					{
 						int			pgprocno = pgprocnos[pgxactoff];
-						PGPROC	   *proc = &allProcs[pgprocno];
+						PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 
 						pg_read_barrier();	/* pairs with GetNewTransactionId */
 
@@ -2499,7 +2495,7 @@ ProcArrayInstallImportedXmin(TransactionId xmin,
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
 		int			pgprocno = arrayP->pgprocnos[index];
-		PGPROC	   *proc = &allProcs[pgprocno];
+		PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 		int			statusFlags = ProcGlobal->statusFlags[index];
 		TransactionId xid;
 
@@ -2725,7 +2721,7 @@ GetRunningTransactionData(void)
 		if (TransactionIdPrecedes(xid, oldestDatabaseRunningXid))
 		{
 			int			pgprocno = arrayP->pgprocnos[index];
-			PGPROC	   *proc = &allProcs[pgprocno];
+			PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 
 			if (proc->databaseId == MyDatabaseId)
 				oldestDatabaseRunningXid = xid;
@@ -2756,7 +2752,7 @@ GetRunningTransactionData(void)
 		for (index = 0; index < arrayP->numProcs; index++)
 		{
 			int			pgprocno = arrayP->pgprocnos[index];
-			PGPROC	   *proc = &allProcs[pgprocno];
+			PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 			int			nsubxids;
 
 			/*
@@ -2858,7 +2854,7 @@ GetOldestActiveTransactionId(bool inCommitOnly, bool allDbs)
 	{
 		TransactionId xid;
 		int			pgprocno = arrayP->pgprocnos[index];
-		PGPROC	   *proc = &allProcs[pgprocno];
+		PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 
 		/* Fetch xid just once - see GetNewTransactionId */
 		xid = UINT32_ACCESS_ONCE(other_xids[index]);
@@ -3020,7 +3016,7 @@ GetVirtualXIDsDelayingChkpt(int *nvxids, int type)
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
 		int			pgprocno = arrayP->pgprocnos[index];
-		PGPROC	   *proc = &allProcs[pgprocno];
+		PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 
 		if ((proc->delayChkptFlags & type) != 0)
 		{
@@ -3061,7 +3057,7 @@ HaveVirtualXIDsDelayingChkpt(VirtualTransactionId *vxids, int nvxids, int type)
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
 		int			pgprocno = arrayP->pgprocnos[index];
-		PGPROC	   *proc = &allProcs[pgprocno];
+		PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 		VirtualTransactionId vxid;
 
 		GET_VXID_FROM_PGPROC(vxid, *proc);
@@ -3189,7 +3185,7 @@ BackendPidGetProcWithLock(int pid)
 
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
-		PGPROC	   *proc = &allProcs[arrayP->pgprocnos[index]];
+		PGPROC	   *proc = GetPGProcByNumber(arrayP->pgprocnos[index]);
 
 		if (proc->pid == pid)
 		{
@@ -3232,7 +3228,7 @@ BackendXidGetPid(TransactionId xid)
 		if (other_xids[index] == xid)
 		{
 			int			pgprocno = arrayP->pgprocnos[index];
-			PGPROC	   *proc = &allProcs[pgprocno];
+			PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 
 			result = proc->pid;
 			break;
@@ -3301,7 +3297,7 @@ GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0,
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
 		int			pgprocno = arrayP->pgprocnos[index];
-		PGPROC	   *proc = &allProcs[pgprocno];
+		PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 		uint8		statusFlags = ProcGlobal->statusFlags[index];
 
 		if (proc == MyProc)
@@ -3403,7 +3399,7 @@ GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
 		int			pgprocno = arrayP->pgprocnos[index];
-		PGPROC	   *proc = &allProcs[pgprocno];
+		PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 
 		/* Exclude prepared transactions */
 		if (proc->pid == 0)
@@ -3468,7 +3464,7 @@ SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode,
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
 		int			pgprocno = arrayP->pgprocnos[index];
-		PGPROC	   *proc = &allProcs[pgprocno];
+		PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 		VirtualTransactionId procvxid;
 
 		GET_VXID_FROM_PGPROC(procvxid, *proc);
@@ -3523,7 +3519,7 @@ MinimumActiveBackends(int min)
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
 		int			pgprocno = arrayP->pgprocnos[index];
-		PGPROC	   *proc = &allProcs[pgprocno];
+		PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 
 		/*
 		 * Since we're not holding a lock, need to be prepared to deal with
@@ -3569,7 +3565,7 @@ CountDBBackends(Oid databaseid)
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
 		int			pgprocno = arrayP->pgprocnos[index];
-		PGPROC	   *proc = &allProcs[pgprocno];
+		PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 
 		if (proc->pid == 0)
 			continue;			/* do not count prepared xacts */
@@ -3598,7 +3594,7 @@ CountDBConnections(Oid databaseid)
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
 		int			pgprocno = arrayP->pgprocnos[index];
-		PGPROC	   *proc = &allProcs[pgprocno];
+		PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 
 		if (proc->pid == 0)
 			continue;			/* do not count prepared xacts */
@@ -3629,7 +3625,7 @@ CancelDBBackends(Oid databaseid, ProcSignalReason sigmode, bool conflictPending)
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
 		int			pgprocno = arrayP->pgprocnos[index];
-		PGPROC	   *proc = &allProcs[pgprocno];
+		PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 
 		if (databaseid == InvalidOid || proc->databaseId == databaseid)
 		{
@@ -3670,7 +3666,7 @@ CountUserBackends(Oid roleid)
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
 		int			pgprocno = arrayP->pgprocnos[index];
-		PGPROC	   *proc = &allProcs[pgprocno];
+		PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 
 		if (proc->pid == 0)
 			continue;			/* do not count prepared xacts */
@@ -3733,7 +3729,7 @@ CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared)
 		for (index = 0; index < arrayP->numProcs; index++)
 		{
 			int			pgprocno = arrayP->pgprocnos[index];
-			PGPROC	   *proc = &allProcs[pgprocno];
+			PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 			uint8		statusFlags = ProcGlobal->statusFlags[index];
 
 			if (proc->databaseId != databaseId)
@@ -3799,7 +3795,7 @@ TerminateOtherDBBackends(Oid databaseId)
 	for (i = 0; i < procArray->numProcs; i++)
 	{
 		int			pgprocno = arrayP->pgprocnos[i];
-		PGPROC	   *proc = &allProcs[pgprocno];
+		PGPROC	   *proc = GetPGProcByNumber(pgprocno);
 
 		if (proc->databaseId != databaseId)
 			continue;
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 4cc7f645c31..9441df9556a 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -2876,7 +2876,7 @@ FastPathTransferRelationLocks(LockMethod lockMethodTable, const LOCKTAG *locktag
 	 */
 	for (i = 0; i < ProcGlobal->allProcCount; i++)
 	{
-		PGPROC	   *proc = &ProcGlobal->allProcs[i];
+		PGPROC	   *proc = GetPGProcByNumber(i);
 		uint32		j;
 
 		LWLockAcquire(&proc->fpInfoLock, LW_EXCLUSIVE);
@@ -3135,7 +3135,7 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
 		 */
 		for (i = 0; i < ProcGlobal->allProcCount; i++)
 		{
-			PGPROC	   *proc = &ProcGlobal->allProcs[i];
+			PGPROC	   *proc = GetPGProcByNumber(i);
 			uint32		j;
 
 			/* A backend never blocks itself */
@@ -3822,7 +3822,7 @@ GetLockStatusData(void)
 	 */
 	for (i = 0; i < ProcGlobal->allProcCount; ++i)
 	{
-		PGPROC	   *proc = &ProcGlobal->allProcs[i];
+		PGPROC	   *proc = GetPGProcByNumber(i);
 
 		/* Skip backends with pid=0, as they don't hold fast-path locks */
 		if (proc->pid == 0)
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index e9ef0fbfe32..6d46a3f3740 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -1988,7 +1988,7 @@ ProcSendSignal(ProcNumber procNumber)
 	if (procNumber < 0 || procNumber >= ProcGlobal->allProcCount)
 		elog(ERROR, "procNumber out of range");
 
-	SetLatch(&ProcGlobal->allProcs[procNumber].procLatch);
+	SetLatch(&GetPGProcByNumber(procNumber)->procLatch);
 }
 
 /*
-- 
2.43.0

---

From: Chao Li <[email-masked]>
Date: Mon, 15 Sep 2025 10:06:33 +0800

> On Sep 12, 2025, at 20:39, Maksim.Melnikov <[email-masked]> wrote:
> 
> Hello hackers,
> I've noticed some places where elements of ProcGlobal->allProcs are addressed directly via arr index.
> But in proc.h macros GetPGProcByNumber exist, that was added to get proc objects by index,
> so I suggest minor refactoring 'ProcGlobal->allProcs[index]' -> 'GetPGProcByNumber(index)'.
> <v1-0001-Preferred-use-of-macro-GetPGProcByNumber.patch>

For the replacements in procarray.c, there may have slight performance difference. The current version stores dereferenced “allProcs” in a local static variable, which is faster than using the macro because the macro need to dereference “allProcs” from the “ProcGlobal” every time when it is called.

In other files, they are just simple direct replacements, so they should be fine.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

---

From: "Maksim.Melnikov" <[email-masked]>
Date: Tue, 16 Sep 2025 11:05:58 +0300

Thanks for your comment,  I've attached patch version without 
procarray.c changes.

Best regards

Melnikov Maksim
From a7112592352756a4b41789ab7f73cd546ac7633b Mon Sep 17 00:00:00 2001
From: Maksim Melnikov <[email-masked]>
Date: Fri, 12 Sep 2025 15:17:39 +0300
Subject: [PATCH v2] Preferred use of macro GetPGProcByNumber.

Minor refactoring, using of GetPGProcByNumber(index) macros
instead of ProcGlobal->allProcs[index].
---
 src/backend/access/transam/clog.c      | 4 ++--
 src/backend/postmaster/pgarch.c        | 2 +-
 src/backend/postmaster/walsummarizer.c | 2 +-
 src/backend/storage/buffer/freelist.c  | 2 +-
 src/backend/storage/lmgr/lock.c        | 6 +++---
 src/backend/storage/lmgr/proc.c        | 2 +-
 6 files changed, 9 insertions(+), 9 deletions(-)

 		/*

 
 
 /*
 
 	/*

 

 /*
-- 
2.43.0

---

From: Chao Li <[email-masked]>
Date: Tue, 16 Sep 2025 16:19:23 +0800

> On Sep 16, 2025, at 16:05, Maksim.Melnikov <[email-masked]> wrote:
> 
> Thanks for your comment,  I've attached patch version without procarray.c changes.
> 
> 
> Best regards
> 
> Melnikov Maksim
> <v2-0001-Preferred-use-of-macro-GetPGProcByNumber.patch>

V2 LGMT.

Best regards,