1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-19 13:42:17 +03:00

Replace BackendIds with 0-based ProcNumbers

Now that BackendId was just another index into the proc array, it was
redundant with the 0-based proc numbers used in other places. Replace
all usage of backend IDs with proc numbers.

The only place where the term "backend id" remains is in a few pgstat
functions that expose backend IDs at the SQL level. Those IDs are now
in fact 0-based ProcNumbers too, but the documentation still calls
them "backend ids". That term still seems appropriate to describe what
the numbers are, so I let it be.

One user-visible effect is that pg_temp_0 is now a valid temp schema
name, for backend with ProcNumber 0.

Reviewed-by: Andres Freund
Discussion: https://www.postgresql.org/message-id/8171f1aa-496f-46a6-afc3-c46fe7a9b407@iki.fi
This commit is contained in:
Heikki Linnakangas
2024-03-03 19:38:22 +02:00
parent ab355e3a88
commit 024c521117
71 changed files with 571 additions and 579 deletions

View File

@@ -818,9 +818,9 @@ ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid)
* If the list was not empty, the leader will clear our XID. It is
* impossible to have followers without a leader because the first process
* that has added itself to the list will always have nextidx as
* INVALID_PGPROCNO.
* INVALID_PROC_NUMBER.
*/
if (nextidx != INVALID_PGPROCNO)
if (nextidx != INVALID_PROC_NUMBER)
{
int extraWaits = 0;
@@ -836,7 +836,7 @@ ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid)
}
pgstat_report_wait_end();
Assert(pg_atomic_read_u32(&proc->procArrayGroupNext) == INVALID_PGPROCNO);
Assert(pg_atomic_read_u32(&proc->procArrayGroupNext) == INVALID_PROC_NUMBER);
/* Fix semaphore count for any absorbed wakeups */
while (extraWaits-- > 0)
@@ -853,13 +853,13 @@ ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid)
* to pop elements one at a time could lead to an ABA problem.
*/
nextidx = pg_atomic_exchange_u32(&procglobal->procArrayGroupFirst,
INVALID_PGPROCNO);
INVALID_PROC_NUMBER);
/* Remember head of list so we can perform wakeups after dropping lock. */
wakeidx = nextidx;
/* Walk the list and clear all XIDs. */
while (nextidx != INVALID_PGPROCNO)
while (nextidx != INVALID_PROC_NUMBER)
{
PGPROC *nextproc = &allProcs[nextidx];
@@ -879,12 +879,12 @@ ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid)
* up are probably much slower than the simple memory writes we did while
* holding the lock.
*/
while (wakeidx != INVALID_PGPROCNO)
while (wakeidx != INVALID_PROC_NUMBER)
{
PGPROC *nextproc = &allProcs[wakeidx];
wakeidx = pg_atomic_read_u32(&nextproc->procArrayGroupNext);
pg_atomic_write_u32(&nextproc->procArrayGroupNext, INVALID_PGPROCNO);
pg_atomic_write_u32(&nextproc->procArrayGroupNext, INVALID_PROC_NUMBER);
/* ensure all previous writes are visible before follower continues. */
pg_write_barrier();
@@ -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++)
@@ -2553,7 +2553,7 @@ ProcArrayInstallImportedXmin(TransactionId xmin,
continue;
/* We are only interested in the specific virtual transaction. */
if (proc->vxid.backendId != sourcevxid->backendId)
if (proc->vxid.procNumber != sourcevxid->procNumber)
continue;
if (proc->vxid.lxid != sourcevxid->localTransactionId)
continue;
@@ -3105,20 +3105,20 @@ HaveVirtualXIDsDelayingChkpt(VirtualTransactionId *vxids, int nvxids, int type)
}
/*
* BackendIdGetProc -- get a backend's PGPROC given its backend ID
* ProcNumberGetProc -- get a backend's PGPROC given its proc number
*
* The result may be out of date arbitrarily quickly, so the caller
* must be careful about how this information is used. NULL is
* returned if the backend is not active.
*/
PGPROC *
BackendIdGetProc(int backendID)
ProcNumberGetProc(ProcNumber procNumber)
{
PGPROC *result;
if (backendID < 1 || backendID > ProcGlobal->allProcCount)
if (procNumber < 0 || procNumber >= ProcGlobal->allProcCount)
return NULL;
result = GetPGProcByBackendId(backendID);
result = GetPGProcByNumber(procNumber);
if (result->pid == 0)
return NULL;
@@ -3127,15 +3127,15 @@ BackendIdGetProc(int backendID)
}
/*
* BackendIdGetTransactionIds -- get a backend's transaction status
* ProcNumberGetTransactionIds -- get a backend's transaction status
*
* Get the xid, xmin, nsubxid and overflow status of the backend. The
* result may be out of date arbitrarily quickly, so the caller must be
* careful about how this information is used.
*/
void
BackendIdGetTransactionIds(int backendID, TransactionId *xid,
TransactionId *xmin, int *nsubxid, bool *overflowed)
ProcNumberGetTransactionIds(ProcNumber procNumber, TransactionId *xid,
TransactionId *xmin, int *nsubxid, bool *overflowed)
{
PGPROC *proc;
@@ -3144,9 +3144,9 @@ BackendIdGetTransactionIds(int backendID, TransactionId *xid,
*nsubxid = 0;
*overflowed = false;
if (backendID < 1 || backendID > ProcGlobal->allProcCount)
if (procNumber < 0 || procNumber >= ProcGlobal->allProcCount)
return;
proc = GetPGProcByBackendId(backendID);
proc = GetPGProcByNumber(procNumber);
/* Need to lock out additions/removals of backends */
LWLockAcquire(ProcArrayLock, LW_SHARED);
@@ -3453,7 +3453,7 @@ GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
LWLockRelease(ProcArrayLock);
/* add the terminator */
vxids[count].backendId = InvalidBackendId;
vxids[count].procNumber = INVALID_PROC_NUMBER;
vxids[count].localTransactionId = InvalidLocalTransactionId;
return vxids;
@@ -3488,7 +3488,7 @@ SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode,
GET_VXID_FROM_PGPROC(procvxid, *proc);
if (procvxid.backendId == vxid.backendId &&
if (procvxid.procNumber == vxid.procNumber &&
procvxid.localTransactionId == vxid.localTransactionId)
{
proc->recoveryConflictPending = conflictPending;
@@ -3499,7 +3499,7 @@ SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode,
* Kill the pid if it's still here. If not, that's what we
* wanted so ignore any errors.
*/
(void) SendProcSignal(pid, sigmode, vxid.backendId);
(void) SendProcSignal(pid, sigmode, vxid.procNumber);
}
break;
}
@@ -3662,7 +3662,7 @@ CancelDBBackends(Oid databaseid, ProcSignalReason sigmode, bool conflictPending)
* Kill the pid if it's still here. If not, that's what we
* wanted so ignore any errors.
*/
(void) SendProcSignal(pid, sigmode, procvxid.backendId);
(void) SendProcSignal(pid, sigmode, procvxid.procNumber);
}
}
}

View File

@@ -43,10 +43,10 @@
* observe it only once.)
*
* Each process that wants to receive signals registers its process ID
* in the ProcSignalSlots array. The array is indexed by backend ID to make
* in the ProcSignalSlots array. The array is indexed by ProcNumber to make
* slot allocation simple, and to avoid having to search the array when you
* know the backend ID of the process you're signaling. (We do support
* signaling without backend ID, but it's a bit less efficient.)
* know the ProcNumber of the process you're signaling. (We do support
* signaling without ProcNumber, but it's a bit less efficient.)
*
* The flags are actually declared as "volatile sig_atomic_t" for maximum
* portability. This should ensure that loads and stores of the flag
@@ -83,7 +83,7 @@ typedef struct
} ProcSignalHeader;
/*
* We reserve a slot for each possible BackendId, plus one for each
* We reserve a slot for each possible ProcNumber, plus one for each
* possible auxiliary process type. (This scheme assumes there is not
* more than one of any auxiliary process type at a time.)
*/
@@ -161,16 +161,16 @@ ProcSignalInit(void)
ProcSignalSlot *slot;
uint64 barrier_generation;
if (MyBackendId <= 0)
elog(ERROR, "MyBackendId not set");
if (MyBackendId > NumProcSignalSlots)
elog(ERROR, "unexpected MyBackendId %d in ProcSignalInit (max %d)", MyBackendId, NumProcSignalSlots);
slot = &ProcSignal->psh_slot[MyBackendId - 1];
if (MyProcNumber < 0)
elog(ERROR, "MyProcNumber not set");
if (MyProcNumber >= NumProcSignalSlots)
elog(ERROR, "unexpected MyProcNumber %d in ProcSignalInit (max %d)", MyProcNumber, NumProcSignalSlots);
slot = &ProcSignal->psh_slot[MyProcNumber];
/* sanity check */
if (slot->pss_pid != 0)
elog(LOG, "process %d taking over ProcSignal slot %d, but it's not empty",
MyProcPid, MyBackendId - 1);
MyProcPid, MyProcNumber);
/* Clear out any leftover signal reasons */
MemSet(slot->pss_signalFlags, 0, NUM_PROCSIGNALS * sizeof(sig_atomic_t));
@@ -218,6 +218,7 @@ CleanupProcSignalState(int status, Datum arg)
* won't try to access it after it's no longer ours (and perhaps even
* after we've unmapped the shared memory segment).
*/
Assert(MyProcSignalSlot != NULL);
MyProcSignalSlot = NULL;
/* sanity check */
@@ -246,7 +247,7 @@ CleanupProcSignalState(int status, Datum arg)
* SendProcSignal
* Send a signal to a Postgres process
*
* Providing backendId is optional, but it will speed up the operation.
* Providing procNumber is optional, but it will speed up the operation.
*
* On success (a signal was sent), zero is returned.
* On error, -1 is returned, and errno is set (typically to ESRCH or EPERM).
@@ -254,13 +255,13 @@ CleanupProcSignalState(int status, Datum arg)
* Not to be confused with ProcSendSignal
*/
int
SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
{
volatile ProcSignalSlot *slot;
if (backendId != InvalidBackendId)
if (procNumber != INVALID_PROC_NUMBER)
{
slot = &ProcSignal->psh_slot[backendId - 1];
slot = &ProcSignal->psh_slot[procNumber];
/*
* Note: Since there's no locking, it's possible that the target
@@ -281,10 +282,11 @@ SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
else
{
/*
* BackendId not provided, so search the array using pid. We search
* Pronumber not provided, so search the array using pid. We search
* the array back to front so as to reduce search overhead. Passing
* InvalidBackendId means that the target is most likely an auxiliary
* process, which will have a slot near the end of the array.
* INVALID_PROC_NUMBER means that the target is most likely an
* auxiliary process, which will have a slot near the end of the
* array.
*/
int i;

View File

@@ -19,9 +19,9 @@
#include "access/transam.h"
#include "miscadmin.h"
#include "storage/backendid.h"
#include "storage/ipc.h"
#include "storage/proc.h"
#include "storage/procnumber.h"
#include "storage/procsignal.h"
#include "storage/shmem.h"
#include "storage/sinvaladt.h"
@@ -155,8 +155,8 @@ typedef struct ProcState
/*
* Next LocalTransactionId to use for each idle backend slot. We keep
* this here because it is indexed by BackendId and it is convenient to
* copy the value to and from local memory when MyBackendId is set. It's
* this here because it is indexed by ProcNumber and it is convenient to
* copy the value to and from local memory when MyProcNumber is set. It's
* meaningless in an active ProcState entry.
*/
LocalTransactionId nextLXID;
@@ -197,7 +197,7 @@ typedef struct SISeg
} SISeg;
/*
* We reserve a slot for each possible BackendId, plus one for each
* We reserve a slot for each possible ProcNumber, plus one for each
* possible auxiliary process type. (This scheme assumes there is not
* more than one of any auxiliary process type at a time.)
*/
@@ -274,15 +274,13 @@ SharedInvalBackendInit(bool sendOnly)
ProcState *stateP;
pid_t oldPid;
SISeg *segP = shmInvalBuffer;
int pgprocno;
if (MyBackendId <= 0)
elog(ERROR, "MyBackendId not set");
if (MyBackendId > NumProcStateSlots)
elog(PANIC, "unexpected MyBackendId %d in SharedInvalBackendInit (max %d)",
MyBackendId, NumProcStateSlots);
pgprocno = MyBackendId - 1;
stateP = &segP->procState[pgprocno];
if (MyProcNumber < 0)
elog(ERROR, "MyProcNumber not set");
if (MyProcNumber >= NumProcStateSlots)
elog(PANIC, "unexpected MyProcNumber %d in SharedInvalBackendInit (max %d)",
MyProcNumber, NumProcStateSlots);
stateP = &segP->procState[MyProcNumber];
/*
* This can run in parallel with read operations, but not with write
@@ -296,10 +294,10 @@ SharedInvalBackendInit(bool sendOnly)
{
LWLockRelease(SInvalWriteLock);
elog(ERROR, "sinval slot for backend %d is already in use by process %d",
MyBackendId, (int) oldPid);
MyProcNumber, (int) oldPid);
}
shmInvalBuffer->pgprocnos[shmInvalBuffer->numProcs++] = pgprocno;
shmInvalBuffer->pgprocnos[shmInvalBuffer->numProcs++] = MyProcNumber;
/* Fetch next local transaction ID into local memory */
nextLocalTransactionId = stateP->nextLXID;
@@ -331,16 +329,15 @@ 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[MyProcNumber];
/* Update next local transaction ID for next holder of this backendID */
/* Update next local transaction ID for next holder of this proc number */
stateP->nextLXID = nextLocalTransactionId;
/* Mark myself inactive */
@@ -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] == MyProcNumber)
{
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[MyProcNumber];
/*
* Before starting to take locks, do a quick, unlocked test to see whether
@@ -668,13 +665,13 @@ SICleanupQueue(bool callerHasWriteLock, int minFree)
if (needSig)
{
pid_t his_pid = needSig->procPid;
BackendId his_backendId = (needSig - &segP->procState[0]) + 1;
ProcNumber his_procNumber = (needSig - &segP->procState[0]);
needSig->signaled = true;
LWLockRelease(SInvalReadLock);
LWLockRelease(SInvalWriteLock);
elog(DEBUG4, "sending sinval catchup signal to PID %d", (int) his_pid);
SendProcSignal(his_pid, PROCSIG_CATCHUP_INTERRUPT, his_backendId);
SendProcSignal(his_pid, PROCSIG_CATCHUP_INTERRUPT, his_procNumber);
if (callerHasWriteLock)
LWLockAcquire(SInvalWriteLock, LW_EXCLUSIVE);
}
@@ -693,11 +690,11 @@ SICleanupQueue(bool callerHasWriteLock, int minFree)
* We split VirtualTransactionIds into two parts so that it is possible
* to allocate a new one without any contention for shared memory, except
* for a bit of additional overhead during backend startup/shutdown.
* The high-order part of a VirtualTransactionId is a BackendId, and the
* The high-order part of a VirtualTransactionId is a ProcNumber, and the
* low-order part is a LocalTransactionId, which we assign from a local
* counter. To avoid the risk of a VirtualTransactionId being reused
* within a short interval, successive procs occupying the same backend ID
* slot should use a consecutive sequence of local IDs, which is implemented
* within a short interval, successive procs occupying the same PGPROC slot
* should use a consecutive sequence of local IDs, which is implemented
* by copying nextLocalTransactionId as seen above.
*/
LocalTransactionId

View File

@@ -137,8 +137,8 @@ InitRecoveryTransactionEnvironment(void)
* are held by vxids and row level locks are held by xids. All queries
* hold AccessShareLocks so never block while we write or lock new rows.
*/
MyProc->vxid.backendId = MyBackendId;
vxid.backendId = MyBackendId;
MyProc->vxid.procNumber = MyProcNumber;
vxid.procNumber = MyProcNumber;
vxid.localTransactionId = GetNextLocalTransactionId();
VirtualXactLockTableInsert(vxid);
@@ -300,7 +300,7 @@ LogRecoveryConflict(ProcSignalReason reason, TimestampTz wait_start,
vxids = wait_list;
while (VirtualTransactionIdIsValid(*vxids))
{
PGPROC *proc = BackendIdGetProc(vxids->backendId);
PGPROC *proc = ProcNumberGetProc(vxids->procNumber);
/* proc can be NULL if the target backend is not active */
if (proc)