diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 42a89fc5dc..085bd1e407 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -446,6 +446,7 @@ ProcArrayAdd(PGPROC *proc) { ProcArrayStruct *arrayP = procArray; int index; + int movecount; /* See ProcGlobal comment explaining why both locks are held */ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); @@ -474,33 +475,48 @@ ProcArrayAdd(PGPROC *proc) */ for (index = 0; index < arrayP->numProcs; index++) { - /* - * If we are the first PGPROC or if we have found our right position - * in the array, break - */ - if ((arrayP->pgprocnos[index] == -1) || (arrayP->pgprocnos[index] > proc->pgprocno)) + int procno PG_USED_FOR_ASSERTS_ONLY = arrayP->pgprocnos[index]; + + Assert(procno >= 0 && procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS)); + Assert(allProcs[procno].pgxactoff == index); + + /* If we have found our right position in the array, break */ + if (arrayP->pgprocnos[index] > proc->pgprocno) break; } - memmove(&arrayP->pgprocnos[index + 1], &arrayP->pgprocnos[index], - (arrayP->numProcs - index) * sizeof(*arrayP->pgprocnos)); - memmove(&ProcGlobal->xids[index + 1], &ProcGlobal->xids[index], - (arrayP->numProcs - index) * sizeof(*ProcGlobal->xids)); - memmove(&ProcGlobal->subxidStates[index + 1], &ProcGlobal->subxidStates[index], - (arrayP->numProcs - index) * sizeof(*ProcGlobal->subxidStates)); - memmove(&ProcGlobal->statusFlags[index + 1], &ProcGlobal->statusFlags[index], - (arrayP->numProcs - index) * sizeof(*ProcGlobal->statusFlags)); + movecount = arrayP->numProcs - index; + memmove(&arrayP->pgprocnos[index + 1], + &arrayP->pgprocnos[index], + movecount * sizeof(*arrayP->pgprocnos)); + memmove(&ProcGlobal->xids[index + 1], + &ProcGlobal->xids[index], + movecount * sizeof(*ProcGlobal->xids)); + memmove(&ProcGlobal->subxidStates[index + 1], + &ProcGlobal->subxidStates[index], + movecount * sizeof(*ProcGlobal->subxidStates)); + memmove(&ProcGlobal->statusFlags[index + 1], + &ProcGlobal->statusFlags[index], + movecount * sizeof(*ProcGlobal->statusFlags)); arrayP->pgprocnos[index] = proc->pgprocno; + proc->pgxactoff = index; ProcGlobal->xids[index] = proc->xid; ProcGlobal->subxidStates[index] = proc->subxidStatus; ProcGlobal->statusFlags[index] = proc->statusFlags; arrayP->numProcs++; + /* adjust pgxactoff for all following PGPROCs */ + index++; for (; index < arrayP->numProcs; index++) { - allProcs[arrayP->pgprocnos[index]].pgxactoff = index; + int procno = arrayP->pgprocnos[index]; + + Assert(procno >= 0 && procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS)); + Assert(allProcs[procno].pgxactoff == index - 1); + + allProcs[procno].pgxactoff = index; } /* @@ -525,7 +541,8 @@ void ProcArrayRemove(PGPROC *proc, TransactionId latestXid) { ProcArrayStruct *arrayP = procArray; - int index; + int myoff; + int movecount; #ifdef XIDCACHE_DEBUG /* dump stats at backend shutdown, but not prepared-xact end */ @@ -537,11 +554,14 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid) LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); LWLockAcquire(XidGenLock, LW_EXCLUSIVE); - Assert(ProcGlobal->allProcs[arrayP->pgprocnos[proc->pgxactoff]].pgxactoff == proc->pgxactoff); + myoff = proc->pgxactoff; + + Assert(myoff >= 0 && myoff < arrayP->numProcs); + Assert(ProcGlobal->allProcs[arrayP->pgprocnos[myoff]].pgxactoff == myoff); if (TransactionIdIsValid(latestXid)) { - Assert(TransactionIdIsValid(ProcGlobal->xids[proc->pgxactoff])); + Assert(TransactionIdIsValid(ProcGlobal->xids[myoff])); /* Advance global latestCompletedXid while holding the lock */ MaintainLatestCompletedXid(latestXid); @@ -549,57 +569,60 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid) /* Same with xactCompletionCount */ ShmemVariableCache->xactCompletionCount++; - ProcGlobal->xids[proc->pgxactoff] = 0; - ProcGlobal->subxidStates[proc->pgxactoff].overflowed = false; - ProcGlobal->subxidStates[proc->pgxactoff].count = 0; + ProcGlobal->xids[myoff] = InvalidTransactionId; + ProcGlobal->subxidStates[myoff].overflowed = false; + ProcGlobal->subxidStates[myoff].count = 0; } else { /* Shouldn't be trying to remove a live transaction here */ - Assert(!TransactionIdIsValid(ProcGlobal->xids[proc->pgxactoff])); + Assert(!TransactionIdIsValid(ProcGlobal->xids[myoff])); } - Assert(TransactionIdIsValid(ProcGlobal->xids[proc->pgxactoff] == 0)); - Assert(TransactionIdIsValid(ProcGlobal->subxidStates[proc->pgxactoff].count == 0)); - Assert(TransactionIdIsValid(ProcGlobal->subxidStates[proc->pgxactoff].overflowed == false)); - ProcGlobal->statusFlags[proc->pgxactoff] = 0; + Assert(!TransactionIdIsValid(ProcGlobal->xids[myoff])); + Assert(ProcGlobal->subxidStates[myoff].count == 0); + Assert(ProcGlobal->subxidStates[myoff].overflowed == false); - for (index = 0; index < arrayP->numProcs; index++) + ProcGlobal->statusFlags[myoff] = 0; + + /* Keep the PGPROC array sorted. See notes above */ + movecount = arrayP->numProcs - myoff - 1; + memmove(&arrayP->pgprocnos[myoff], + &arrayP->pgprocnos[myoff + 1], + movecount * sizeof(*arrayP->pgprocnos)); + memmove(&ProcGlobal->xids[myoff], + &ProcGlobal->xids[myoff + 1], + movecount * sizeof(*ProcGlobal->xids)); + memmove(&ProcGlobal->subxidStates[myoff], + &ProcGlobal->subxidStates[myoff + 1], + movecount * sizeof(*ProcGlobal->subxidStates)); + memmove(&ProcGlobal->statusFlags[myoff], + &ProcGlobal->statusFlags[myoff + 1], + movecount * sizeof(*ProcGlobal->statusFlags)); + + arrayP->pgprocnos[arrayP->numProcs - 1] = -1; /* for debugging */ + arrayP->numProcs--; + + /* + * Adjust pgxactoff of following procs for removed PGPROC (note that + * numProcs already has been decremented). + */ + for (int index = myoff; index < arrayP->numProcs; index++) { - if (arrayP->pgprocnos[index] == proc->pgprocno) - { - /* Keep the PGPROC array sorted. See notes above */ - memmove(&arrayP->pgprocnos[index], &arrayP->pgprocnos[index + 1], - (arrayP->numProcs - index - 1) * sizeof(*arrayP->pgprocnos)); - memmove(&ProcGlobal->xids[index], &ProcGlobal->xids[index + 1], - (arrayP->numProcs - index - 1) * sizeof(*ProcGlobal->xids)); - memmove(&ProcGlobal->subxidStates[index], &ProcGlobal->subxidStates[index + 1], - (arrayP->numProcs - index - 1) * sizeof(*ProcGlobal->subxidStates)); - memmove(&ProcGlobal->statusFlags[index], &ProcGlobal->statusFlags[index + 1], - (arrayP->numProcs - index - 1) * sizeof(*ProcGlobal->statusFlags)); + int procno = arrayP->pgprocnos[index]; - arrayP->pgprocnos[arrayP->numProcs - 1] = -1; /* for debugging */ - arrayP->numProcs--; + Assert(procno >= 0 && procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS)); + Assert(allProcs[procno].pgxactoff - 1 == index); - /* adjust for removed PGPROC */ - for (; index < arrayP->numProcs; index++) - allProcs[arrayP->pgprocnos[index]].pgxactoff--; - - /* - * Release in reversed acquisition order, to reduce frequency of - * having to wait for XidGenLock while holding ProcArrayLock. - */ - LWLockRelease(XidGenLock); - LWLockRelease(ProcArrayLock); - return; - } + allProcs[procno].pgxactoff = index; } - /* Oops */ + /* + * Release in reversed acquisition order, to reduce frequency of having to + * wait for XidGenLock while holding ProcArrayLock. + */ LWLockRelease(XidGenLock); LWLockRelease(ProcArrayLock); - - elog(LOG, "failed to find proc %p in ProcArray", proc); }