From b00703d869aaf5c0e76f6e8a15adeb1e8b99fbc1 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Thu, 8 Feb 2024 12:58:08 +0200
Subject: [PATCH v10 3/3] Use 0-based indexing for BackendIds

---
 doc/src/sgml/monitoring.sgml                  |  2 +-
 src/backend/access/transam/clog.c             |  2 +-
 src/backend/access/transam/multixact.c        | 19 ++++++++-----------
 src/backend/access/transam/twophase.c         |  4 ++--
 src/backend/access/transam/xlog.c             |  2 +-
 src/backend/commands/async.c                  | 12 ++++++------
 src/backend/postmaster/bgwriter.c             |  2 +-
 src/backend/postmaster/pgarch.c               |  2 +-
 src/backend/postmaster/walsummarizer.c        |  2 +-
 src/backend/storage/buffer/bufmgr.c           |  6 +++---
 src/backend/storage/ipc/procarray.c           | 10 +++++-----
 src/backend/storage/ipc/procsignal.c          |  8 ++++----
 src/backend/storage/ipc/sinvaladt.c           | 19 ++++++++-----------
 src/backend/storage/lmgr/condition_variable.c | 12 ++++++------
 src/backend/storage/lmgr/lwlock.c             |  6 +++---
 src/backend/storage/lmgr/predicate.c          |  2 +-
 src/backend/storage/lmgr/proc.c               |  9 ++-------
 src/backend/utils/activity/backend_status.c   | 12 ++++++------
 src/backend/utils/adt/mcxtfuncs.c             |  2 +-
 src/include/storage/backendid.h               |  6 ++++--
 src/include/storage/proc.h                    | 11 +++--------
 21 files changed, 68 insertions(+), 82 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 5cf9363ac82..adec1b92a31 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -4933,7 +4933,7 @@ description | Waiting for a newly initialized WAL file to reach durable storage
    access functions can be used; these are shown in <xref
    linkend="monitoring-stats-backend-funcs-table"/>.
    These access functions use the session's backend ID number, which is a
-   small positive integer that is distinct from the backend ID of any
+   small non-negative integer that is distinct from the backend ID of any
    concurrent session, although a session's ID can be recycled as soon as
    it exits.  The backend ID is used, among other things, to identify the
    session's temporary schema if it has one.
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 97f7434da34..7b79067efb1 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -425,7 +425,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 {
 	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
-	int			pgprocno = MyProcNumber;
+	int			pgprocno = MyBackendId;
 	uint32		nextidx;
 	uint32		wakeidx;
 
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index febc429f724..f577008f4bd 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -238,9 +238,8 @@ typedef struct MultiXactStateData
 	 * immediately following the MultiXactStateData struct. Each is indexed by
 	 * BackendId.
 	 *
-	 * In both arrays, there's a slot for all normal backends (1..MaxBackends)
-	 * followed by a slot for max_prepared_xacts prepared transactions. Valid
-	 * BackendIds start from 1; element zero of each array is never used.
+	 * In both arrays, there's a slot for all normal backends (0..MaxBackends-1)
+	 * followed by a slot for max_prepared_xacts prepared transactions.
 	 *
 	 * OldestMemberMXactId[k] is the oldest MultiXactId each backend's current
 	 * transaction(s) could possibly be a member of, or InvalidMultiXactId
@@ -284,8 +283,7 @@ typedef struct MultiXactStateData
 } MultiXactStateData;
 
 /*
- * Last element of OldestMemberMXactId and OldestVisibleMXactId arrays.
- * Valid elements are (1..MaxOldestSlot); element 0 is never used.
+ * Size of OldestMemberMXactId and OldestVisibleMXactId arrays.
  */
 #define MaxOldestSlot	(MaxBackends + max_prepared_xacts)
 
@@ -698,7 +696,7 @@ MultiXactIdSetOldestVisible(void)
 		if (oldestMXact < FirstMultiXactId)
 			oldestMXact = FirstMultiXactId;
 
-		for (i = 1; i <= MaxOldestSlot; i++)
+		for (i = 0; i < MaxOldestSlot; i++)
 		{
 			MultiXactId thisoldest = OldestMemberMXactId[i];
 
@@ -1828,9 +1826,9 @@ MultiXactShmemSize(void)
 {
 	Size		size;
 
-	/* We need 2*MaxOldestSlot + 1 perBackendXactIds[] entries */
+	/* We need 2*MaxOldestSlot perBackendXactIds[] entries */
 #define SHARED_MULTIXACT_STATE_SIZE \
-	add_size(offsetof(MultiXactStateData, perBackendXactIds) + sizeof(MultiXactId), \
+	add_size(offsetof(MultiXactStateData, perBackendXactIds), \
 			 mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
 
 	size = SHARED_MULTIXACT_STATE_SIZE;
@@ -1880,8 +1878,7 @@ MultiXactShmemInit(void)
 		Assert(found);
 
 	/*
-	 * Set up array pointers.  Note that perBackendXactIds[0] is wasted space
-	 * since we only use indexes 1..MaxOldestSlot in each array.
+	 * Set up array pointers.
 	 */
 	OldestMemberMXactId = MultiXactState->perBackendXactIds;
 	OldestVisibleMXactId = OldestMemberMXactId + MaxOldestSlot;
@@ -2533,7 +2530,7 @@ GetOldestMultiXactId(void)
 		nextMXact = FirstMultiXactId;
 
 	oldestMXact = nextMXact;
-	for (i = 1; i <= MaxOldestSlot; i++)
+	for (i = 0; i < MaxOldestSlot; i++)
 	{
 		MultiXactId thisoldest;
 
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 5c282002900..709353d4056 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -895,7 +895,7 @@ TwoPhaseGetXidByVirtualXID(VirtualTransactionId vxid,
  *		Get the dummy backend ID for prepared transaction specified by XID
  *
  * Dummy backend IDs are similar to real backend IDs of real backends.
- * They start at MaxBackends + 1, and are unique across all currently active
+ * They start at MaxBackends, and are unique across all currently active
  * real backends and prepared transactions.  If lock_held is set to true,
  * TwoPhaseStateLock will not be taken, so the caller had better hold it.
  */
@@ -904,7 +904,7 @@ TwoPhaseGetDummyBackendId(TransactionId xid, bool lock_held)
 {
 	GlobalTransaction gxact = TwoPhaseGetGXact(xid, lock_held);
 
-	return gxact->pgprocno + 1;
+	return gxact->pgprocno;
 }
 
 /*
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 1e4abbca8be..e401684f82f 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -1379,7 +1379,7 @@ WALInsertLockAcquire(void)
 	static int	lockToTry = -1;
 
 	if (lockToTry == -1)
-		lockToTry = MyProcNumber % NUM_XLOGINSERT_LOCKS;
+		lockToTry = MyBackendId % NUM_XLOGINSERT_LOCKS;
 	MyLockNo = lockToTry;
 
 	/*
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 8b24b222931..5aa893c9141 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -1094,7 +1094,7 @@ Exec_ListenPreCommit(void)
 	head = QUEUE_HEAD;
 	max = QUEUE_TAIL;
 	prevListener = InvalidBackendId;
-	for (BackendId i = QUEUE_FIRST_LISTENER; i > 0; i = QUEUE_NEXT_LISTENER(i))
+	for (BackendId i = QUEUE_FIRST_LISTENER; i != InvalidBackendId; i = QUEUE_NEXT_LISTENER(i))
 	{
 		if (QUEUE_BACKEND_DBOID(i) == MyDatabaseId)
 			max = QUEUE_POS_MAX(max, QUEUE_BACKEND_POS(i));
@@ -1106,7 +1106,7 @@ Exec_ListenPreCommit(void)
 	QUEUE_BACKEND_PID(MyBackendId) = MyProcPid;
 	QUEUE_BACKEND_DBOID(MyBackendId) = MyDatabaseId;
 	/* Insert backend into list of listeners at correct position */
-	if (prevListener > 0)
+	if (prevListener != InvalidBackendId)
 	{
 		QUEUE_NEXT_LISTENER(MyBackendId) = QUEUE_NEXT_LISTENER(prevListener);
 		QUEUE_NEXT_LISTENER(prevListener) = MyBackendId;
@@ -1253,7 +1253,7 @@ asyncQueueUnregister(void)
 		QUEUE_FIRST_LISTENER = QUEUE_NEXT_LISTENER(MyBackendId);
 	else
 	{
-		for (BackendId i = QUEUE_FIRST_LISTENER; i > 0; i = QUEUE_NEXT_LISTENER(i))
+		for (BackendId i = QUEUE_FIRST_LISTENER; i != InvalidBackendId; i = QUEUE_NEXT_LISTENER(i))
 		{
 			if (QUEUE_NEXT_LISTENER(i) == MyBackendId)
 			{
@@ -1533,7 +1533,7 @@ asyncQueueFillWarning(void)
 		QueuePosition min = QUEUE_HEAD;
 		int32		minPid = InvalidPid;
 
-		for (BackendId i = QUEUE_FIRST_LISTENER; i > 0; i = QUEUE_NEXT_LISTENER(i))
+		for (BackendId i = QUEUE_FIRST_LISTENER; i != InvalidBackendId; i = QUEUE_NEXT_LISTENER(i))
 		{
 			Assert(QUEUE_BACKEND_PID(i) != InvalidPid);
 			min = QUEUE_POS_MIN(min, QUEUE_BACKEND_POS(i));
@@ -1589,7 +1589,7 @@ SignalBackends(void)
 	count = 0;
 
 	LWLockAcquire(NotifyQueueLock, LW_EXCLUSIVE);
-	for (BackendId i = QUEUE_FIRST_LISTENER; i > 0; i = QUEUE_NEXT_LISTENER(i))
+	for (BackendId i = QUEUE_FIRST_LISTENER; i != InvalidBackendId; i = QUEUE_NEXT_LISTENER(i))
 	{
 		int32		pid = QUEUE_BACKEND_PID(i);
 		QueuePosition pos;
@@ -2126,7 +2126,7 @@ asyncQueueAdvanceTail(void)
 	 */
 	LWLockAcquire(NotifyQueueLock, LW_EXCLUSIVE);
 	min = QUEUE_HEAD;
-	for (BackendId i = QUEUE_FIRST_LISTENER; i > 0; i = QUEUE_NEXT_LISTENER(i))
+	for (BackendId i = QUEUE_FIRST_LISTENER; i != InvalidBackendId; i = QUEUE_NEXT_LISTENER(i))
 	{
 		Assert(QUEUE_BACKEND_PID(i) != InvalidPid);
 		min = QUEUE_POS_MIN(min, QUEUE_BACKEND_POS(i));
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index 6364b16261f..6cef901045d 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -326,7 +326,7 @@ BackgroundWriterMain(void)
 		if (rc == WL_TIMEOUT && can_hibernate && prev_hibernate)
 		{
 			/* Ask for notification at next buffer allocation */
-			StrategyNotifyBgWriter(MyProcNumber);
+			StrategyNotifyBgWriter(MyBackendId);
 			/* Sleep ... */
 			(void) WaitLatch(MyLatch,
 							 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 2aa3e9890a2..213c9669fda 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -242,7 +242,7 @@ PgArchiverMain(void)
 	 * Advertise our pgprocno so that backends can use our latch to wake us up
 	 * while we're sleeping.
 	 */
-	PgArch->pgprocno = MyProcNumber;
+	PgArch->pgprocno = MyBackendId;
 
 	/* Create workspace for pgarch_readyXlog() */
 	arch_files = palloc(sizeof(struct arch_files_state));
diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c
index 5d61d1517e8..71560e8b808 100644
--- a/src/backend/postmaster/walsummarizer.c
+++ b/src/backend/postmaster/walsummarizer.c
@@ -248,7 +248,7 @@ WalSummarizerMain(void)
 	/* Advertise ourselves. */
 	on_shmem_exit(WalSummarizerShutdown, (Datum) 0);
 	LWLockAcquire(WALSummarizerLock, LW_EXCLUSIVE);
-	WalSummarizerCtl->summarizer_pgprocno = MyProcNumber;
+	WalSummarizerCtl->summarizer_pgprocno = MyBackendId;
 	LWLockRelease(WALSummarizerLock);
 
 	/* Create and switch to a memory context that we can reset on error. */
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 87a31745864..bb9da98c9f5 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -4780,7 +4780,7 @@ UnlockBuffers(void)
 		 * got a cancel/die interrupt before getting the signal.
 		 */
 		if ((buf_state & BM_PIN_COUNT_WAITER) != 0 &&
-			buf->wait_backend_pgprocno == MyProcNumber)
+			buf->wait_backend_pgprocno == MyBackendId)
 			buf_state &= ~BM_PIN_COUNT_WAITER;
 
 		UnlockBufHdr(buf, buf_state);
@@ -4930,7 +4930,7 @@ LockBufferForCleanup(Buffer buffer)
 			LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
 			elog(ERROR, "multiple backends attempting to wait for pincount 1");
 		}
-		bufHdr->wait_backend_pgprocno = MyProcNumber;
+		bufHdr->wait_backend_pgprocno = MyBackendId;
 		PinCountWaitBuf = bufHdr;
 		buf_state |= BM_PIN_COUNT_WAITER;
 		UnlockBufHdr(bufHdr, buf_state);
@@ -4994,7 +4994,7 @@ LockBufferForCleanup(Buffer buffer)
 		 */
 		buf_state = LockBufHdr(bufHdr);
 		if ((buf_state & BM_PIN_COUNT_WAITER) != 0 &&
-			bufHdr->wait_backend_pgprocno == MyProcNumber)
+			bufHdr->wait_backend_pgprocno == MyBackendId)
 			buf_state &= ~BM_PIN_COUNT_WAITER;
 		UnlockBufHdr(bufHdr, buf_state);
 
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index d96606ebba5..7ed08d95355 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -2538,7 +2538,7 @@ ProcArrayInstallImportedXmin(TransactionId xmin,
 
 	/*
 	 * Find the PGPROC entry of the source transaction. (This could use
-	 * GetPGProcByBackendId(), unless it's a prepared xact.  But this isn't
+	 * GetPGProcByNumber(), unless it's a prepared xact.  But this isn't
 	 * performance critical.)
 	 */
 	for (index = 0; index < arrayP->numProcs; index++)
@@ -3116,9 +3116,9 @@ BackendIdGetProc(int backendID)
 {
 	PGPROC	   *result;
 
-	if (backendID < 1 || backendID > ProcGlobal->allProcCount)
+	if (backendID < 0 || backendID >= ProcGlobal->allProcCount)
 		return NULL;
-	result = GetPGProcByBackendId(backendID);
+	result = GetPGProcByNumber(backendID);
 
 	if (result->pid == 0)
 		return NULL;
@@ -3144,9 +3144,9 @@ BackendIdGetTransactionIds(int backendID, TransactionId *xid,
 	*nsubxid = 0;
 	*overflowed = false;
 
-	if (backendID < 1 || backendID > ProcGlobal->allProcCount)
+	if (backendID < 0 || backendID >= ProcGlobal->allProcCount)
 		return;
-	proc = GetPGProcByBackendId(backendID);
+	proc = GetPGProcByNumber(backendID);
 
 	/* Need to lock out additions/removals of backends */
 	LWLockAcquire(ProcArrayLock, LW_SHARED);
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index d1d5bf0c152..0bf577b8bc0 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -161,11 +161,11 @@ ProcSignalInit(void)
 	ProcSignalSlot *slot;
 	uint64		barrier_generation;
 
-	if (MyBackendId <= 0)
+	if (MyBackendId < 0)
 		elog(ERROR, "MyBackendId not set");
-	if (MyBackendId > NumProcSignalSlots)
+	if (MyBackendId >= NumProcSignalSlots)
 		elog(ERROR, "unexpected MyBackendId %d in ProcSignalInit (max %d)", MyBackendId, NumProcSignalSlots);
-	slot = &ProcSignal->psh_slot[MyBackendId - 1];
+	slot = &ProcSignal->psh_slot[MyBackendId];
 
 	/* sanity check */
 	if (slot->pss_pid != 0)
@@ -260,7 +260,7 @@ SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
 
 	if (backendId != InvalidBackendId)
 	{
-		slot = &ProcSignal->psh_slot[backendId - 1];
+		slot = &ProcSignal->psh_slot[backendId];
 
 		/*
 		 * Note: Since there's no locking, it's possible that the target
diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c
index f624bfc7d78..f3ef3eb1ab0 100644
--- a/src/backend/storage/ipc/sinvaladt.c
+++ b/src/backend/storage/ipc/sinvaladt.c
@@ -274,15 +274,13 @@ SharedInvalBackendInit(bool sendOnly)
 	ProcState  *stateP;
 	pid_t		oldPid;
 	SISeg	   *segP = shmInvalBuffer;
-	int			pgprocno;
 
-	if (MyBackendId <= 0)
+	if (MyBackendId < 0)
 		elog(ERROR, "MyBackendId not set");
-	if (MyBackendId > NumProcStateSlots)
+	if (MyBackendId >= NumProcStateSlots)
 		elog(PANIC, "unexpected MyBackendId %d in SharedInvalBackendInit (max %d)",
 			 MyBackendId, NumProcStateSlots);
-	pgprocno = MyBackendId - 1;
-	stateP = &segP->procState[pgprocno];
+	stateP = &segP->procState[MyBackendId];
 
 	/*
 	 * This can run in parallel with read operations, but not with write
@@ -299,7 +297,7 @@ SharedInvalBackendInit(bool sendOnly)
 			 MyBackendId, (int) oldPid);
 	}
 
-	shmInvalBuffer->pgprocnos[shmInvalBuffer->numProcs++] = pgprocno;
+	shmInvalBuffer->pgprocnos[shmInvalBuffer->numProcs++] = MyBackendId;
 
 	/* Fetch next local transaction ID into local memory */
 	nextLocalTransactionId = stateP->nextLXID;
@@ -331,14 +329,13 @@ CleanupInvalidationState(int status, Datum arg)
 {
 	SISeg	   *segP = (SISeg *) DatumGetPointer(arg);
 	ProcState  *stateP;
-	int			pgprocno = MyBackendId - 1;
 	int			i;
 
 	Assert(PointerIsValid(segP));
 
 	LWLockAcquire(SInvalWriteLock, LW_EXCLUSIVE);
 
-	stateP = &segP->procState[pgprocno];
+	stateP = &segP->procState[MyBackendId];
 
 	/* Update next local transaction ID for next holder of this backendID */
 	stateP->nextLXID = nextLocalTransactionId;
@@ -351,7 +348,7 @@ CleanupInvalidationState(int status, Datum arg)
 
 	for (i = segP->numProcs - 1; i >= 0; i--)
 	{
-		if (segP->pgprocnos[i] == pgprocno)
+		if (segP->pgprocnos[i] == MyBackendId)
 		{
 			if (i != segP->numProcs - 1)
 				segP->pgprocnos[i] = segP->pgprocnos[segP->numProcs - 1];
@@ -481,7 +478,7 @@ SIGetDataEntries(SharedInvalidationMessage *data, int datasize)
 	int			n;
 
 	segP = shmInvalBuffer;
-	stateP = &segP->procState[MyBackendId - 1];
+	stateP = &segP->procState[MyBackendId];
 
 	/*
 	 * Before starting to take locks, do a quick, unlocked test to see whether
@@ -668,7 +665,7 @@ SICleanupQueue(bool callerHasWriteLock, int minFree)
 	if (needSig)
 	{
 		pid_t		his_pid = needSig->procPid;
-		BackendId	his_backendId = (needSig - &segP->procState[0]) + 1;
+		BackendId	his_backendId = (needSig - &segP->procState[0]);
 
 		needSig->signaled = true;
 		LWLockRelease(SInvalReadLock);
diff --git a/src/backend/storage/lmgr/condition_variable.c b/src/backend/storage/lmgr/condition_variable.c
index 10fdae19dcc..daff1368c1f 100644
--- a/src/backend/storage/lmgr/condition_variable.c
+++ b/src/backend/storage/lmgr/condition_variable.c
@@ -57,7 +57,7 @@ ConditionVariableInit(ConditionVariable *cv)
 void
 ConditionVariablePrepareToSleep(ConditionVariable *cv)
 {
-	int			pgprocno = MyProcNumber;
+	int			pgprocno = MyBackendId;
 
 	/*
 	 * If some other sleep is already prepared, cancel it; this is necessary
@@ -181,10 +181,10 @@ ConditionVariableTimedSleep(ConditionVariable *cv, long timeout,
 		 * guarantee not to return spuriously, we'll avoid this obvious case.
 		 */
 		SpinLockAcquire(&cv->mutex);
-		if (!proclist_contains(&cv->wakeup, MyProcNumber, cvWaitLink))
+		if (!proclist_contains(&cv->wakeup, MyBackendId, cvWaitLink))
 		{
 			done = true;
-			proclist_push_tail(&cv->wakeup, MyProcNumber, cvWaitLink);
+			proclist_push_tail(&cv->wakeup, MyBackendId, cvWaitLink);
 		}
 		SpinLockRelease(&cv->mutex);
 
@@ -236,8 +236,8 @@ ConditionVariableCancelSleep(void)
 		return false;
 
 	SpinLockAcquire(&cv->mutex);
-	if (proclist_contains(&cv->wakeup, MyProcNumber, cvWaitLink))
-		proclist_delete(&cv->wakeup, MyProcNumber, cvWaitLink);
+	if (proclist_contains(&cv->wakeup, MyBackendId, cvWaitLink))
+		proclist_delete(&cv->wakeup, MyBackendId, cvWaitLink);
 	else
 		signaled = true;
 	SpinLockRelease(&cv->mutex);
@@ -281,7 +281,7 @@ ConditionVariableSignal(ConditionVariable *cv)
 void
 ConditionVariableBroadcast(ConditionVariable *cv)
 {
-	int			pgprocno = MyProcNumber;
+	int			pgprocno = MyBackendId;
 	PGPROC	   *proc = NULL;
 	bool		have_sentinel = false;
 
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 997857679ed..291ac8d58f8 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -1056,9 +1056,9 @@ LWLockQueueSelf(LWLock *lock, LWLockMode mode)
 
 	/* LW_WAIT_UNTIL_FREE waiters are always at the front of the queue */
 	if (mode == LW_WAIT_UNTIL_FREE)
-		proclist_push_head(&lock->waiters, MyProcNumber, lwWaitLink);
+		proclist_push_head(&lock->waiters, MyBackendId, lwWaitLink);
 	else
-		proclist_push_tail(&lock->waiters, MyProcNumber, lwWaitLink);
+		proclist_push_tail(&lock->waiters, MyBackendId, lwWaitLink);
 
 	/* Can release the mutex now */
 	LWLockWaitListUnlock(lock);
@@ -1097,7 +1097,7 @@ LWLockDequeueSelf(LWLock *lock)
 	 */
 	on_waitlist = MyProc->lwWaiting == LW_WS_WAITING;
 	if (on_waitlist)
-		proclist_delete(&lock->waiters, MyProcNumber, lwWaitLink);
+		proclist_delete(&lock->waiters, MyBackendId, lwWaitLink);
 
 	if (proclist_is_empty(&lock->waiters) &&
 		(pg_atomic_read_u32(&lock->state) & LW_FLAG_HAS_WAITERS) != 0)
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index d62060d58c8..d3dec91a68d 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -1830,7 +1830,7 @@ GetSerializableTransactionSnapshotInt(Snapshot snapshot,
 	sxact->finishedBefore = InvalidTransactionId;
 	sxact->xmin = snapshot->xmin;
 	sxact->pid = MyProcPid;
-	sxact->pgprocno = MyProcNumber;
+	sxact->pgprocno = MyBackendId;
 	dlist_init(&sxact->predicateLocks);
 	dlist_node_init(&sxact->finishedLink);
 	sxact->flags = 0;
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 4226e41d80c..402ab53a061 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -64,7 +64,6 @@ bool		log_lock_waits = false;
 
 /* Pointer to this process's PGPROC struct, if any */
 PGPROC	   *MyProc = NULL;
-int			MyProcNumber = INVALID_PGPROCNO;
 
 /*
  * This spinlock protects the freelist of recycled PGPROC structures.
@@ -352,8 +351,7 @@ InitProcess(void)
 				(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
 				 errmsg("sorry, too many clients already")));
 	}
-	MyProcNumber = GetNumberFromPGProc(MyProc);
-	MyBackendId = GetBackendIdFromPGProc(MyProc);
+	MyBackendId = GetNumberFromPGProc(MyProc);
 
 	/*
 	 * Cross-check that the PGPROC is of the type we expect; if this were not
@@ -566,8 +564,7 @@ InitAuxiliaryProcess(void)
 	SpinLockRelease(ProcStructLock);
 
 	MyProc = auxproc;
-	MyProcNumber = GetNumberFromPGProc(MyProc);
-	MyBackendId = GetBackendIdFromPGProc(MyProc);
+	MyBackendId = GetNumberFromPGProc(MyProc);
 
 	/*
 	 * Initialize all fields of MyProc, except for those previously
@@ -910,7 +907,6 @@ ProcKill(int code, Datum arg)
 
 	proc = MyProc;
 	MyProc = NULL;
-	MyProcNumber = INVALID_PGPROCNO;
 	MyBackendId = InvalidBackendId;
 	DisownLatch(&proc->procLatch);
 
@@ -988,7 +984,6 @@ AuxiliaryProcKill(int code, Datum arg)
 
 	proc = MyProc;
 	MyProc = NULL;
-	MyProcNumber = INVALID_PGPROCNO;
 	MyBackendId = InvalidBackendId;
 	DisownLatch(&proc->procLatch);
 
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index 3d3f7b06723..8a4a9cd219b 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -249,8 +249,8 @@ pgstat_beinit(void)
 {
 	/* Initialize MyBEEntry */
 	Assert(MyBackendId != InvalidBackendId);
-	Assert(MyBackendId >= 1 && MyBackendId <= NumBackendStatSlots);
-	MyBEEntry = &BackendStatusArray[MyBackendId - 1];
+	Assert(MyBackendId >= 0 && MyBackendId < NumBackendStatSlots);
+	MyBEEntry = &BackendStatusArray[MyBackendId];
 
 	/* Set up a process-exit hook to clean up */
 	on_shmem_exit(pgstat_beshutdown_hook, 0);
@@ -721,7 +721,7 @@ pgstat_read_current_status(void)
 #ifdef ENABLE_GSS
 	PgBackendGSSStatus *localgssstatus;
 #endif
-	int			i;
+	int			backendId;
 
 	if (localBackendStatusTable)
 		return;					/* already done */
@@ -764,7 +764,7 @@ pgstat_read_current_status(void)
 
 	beentry = BackendStatusArray;
 	localentry = localtable;
-	for (i = 1; i <= NumBackendStatSlots; i++)
+	for (backendId = 0; backendId < NumBackendStatSlots; backendId++)
 	{
 		/*
 		 * Follow the protocol of retrying if st_changecount changes while we
@@ -835,8 +835,8 @@ pgstat_read_current_status(void)
 			 * is in order by backend_id.  pgstat_get_beentry_by_backend_id()
 			 * depends on that.
 			 */
-			localentry->backend_id = i;
-			BackendIdGetTransactionIds(i,
+			localentry->backend_id = backendId;
+			BackendIdGetTransactionIds(backendId,
 									   &localentry->backend_xid,
 									   &localentry->backend_xmin,
 									   &localentry->backend_subxact_count,
diff --git a/src/backend/utils/adt/mcxtfuncs.c b/src/backend/utils/adt/mcxtfuncs.c
index a7267dc15d1..a3239ab126b 100644
--- a/src/backend/utils/adt/mcxtfuncs.c
+++ b/src/backend/utils/adt/mcxtfuncs.c
@@ -176,7 +176,7 @@ pg_log_backend_memory_contexts(PG_FUNCTION_ARGS)
 	}
 
 	if (proc != NULL)
-		backendId = GetBackendIdFromPGProc(proc);
+		backendId = GetNumberFromPGProc(proc);
 	if (SendProcSignal(pid, PROCSIG_LOG_MEMORY_CONTEXT, backendId) < 0)
 	{
 		/* Again, just a warning to allow loops */
diff --git a/src/include/storage/backendid.h b/src/include/storage/backendid.h
index 01387723f79..de242e2c039 100644
--- a/src/include/storage/backendid.h
+++ b/src/include/storage/backendid.h
@@ -19,8 +19,10 @@
  * assigned at backend startup after authentication.  Note that a backend ID
  * can be reused for a different backend immediately after a backend exits.
  *
- * Backend IDs are assigned starting from 1. For historical reasons, BackendId
- * 0 is unused, but InvalidBackendId is defined as -1.
+ * Backend IDs are assigned starting from 0.  A backend ID is also an index
+ * into the proc array, and is synonymous with "proc numbers" used in other
+ * parts of the code.  (Before version 17, backend IDs were assigned
+ * separately from proc numbers, and started from 1.)
  */
 typedef int BackendId;
 
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index d1e50380b7c..eca0a5809e1 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -199,7 +199,7 @@ struct PGPROC
 	 */
 	struct {
 		BackendId	backendId;		/* For regular backends, equal to
-									 * GetBackendIdFromPGProc(proc).  For
+									 * GetNumberFromPGProc(proc).  For
 									 * prepared xacts, ID of the original
 									 * backend that processed the
 									 * transaction. For unused PGPROC entries,
@@ -317,7 +317,6 @@ struct PGPROC
 
 
 extern PGDLLIMPORT PGPROC *MyProc;
-extern PGDLLIMPORT int MyProcNumber;	/* same as GetNumberFromPGProc(MyProc) */
 
 /*
  * There is one ProcGlobal struct for the whole database cluster.
@@ -422,15 +421,11 @@ extern PGDLLIMPORT PROC_HDR *ProcGlobal;
 extern PGDLLIMPORT PGPROC *PreparedXactProcs;
 
 /*
- * Accessors for getting PGPROC given a pgprocno or BackendId, and vice versa.
- *
- * For historical reasons, some code uses 0-based "proc numbers", while other
- * code uses 1-based backend IDs.
+ * Accessors for getting PGPROC given a pgprocno (or BackendId which is the
+ * same thing since version 17) and vice versa.
  */
 #define GetPGProcByNumber(n) (&ProcGlobal->allProcs[(n)])
 #define GetNumberFromPGProc(proc) ((proc) - &ProcGlobal->allProcs[0])
-#define GetPGProcByBackendId(n) (&ProcGlobal->allProcs[(n) - 1])
-#define GetBackendIdFromPGProc(proc) (GetNumberFromPGProc(proc) + 1)
 
 /*
  * We set aside some extra PGPROC structures for auxiliary processes,
-- 
2.39.2

