(arrayP->numProcs - index) * sizeof(*arrayP->pgprocnos));
memmove(&ProcGlobal->xids[index + 1], &ProcGlobal->xids[index],
(arrayP->numProcs - index) * sizeof(*ProcGlobal->xids));
+ memmove(&ProcGlobal->nsubxids[index + 1], &ProcGlobal->nsubxids[index],
+ (arrayP->numProcs - index) * sizeof(*ProcGlobal->nsubxids));
memmove(&ProcGlobal->vacuumFlags[index + 1], &ProcGlobal->vacuumFlags[index],
(arrayP->numProcs - index) * sizeof(*ProcGlobal->vacuumFlags));
arrayP->pgprocnos[index] = proc->pgprocno;
ProcGlobal->xids[index] = proc->xidCopy;
+ ProcGlobal->nsubxids[index] = proc->nsubxidsCopy;
ProcGlobal->vacuumFlags[index] = proc->vacuumFlagsCopy;
arrayP->numProcs++;
MaintainLatestCompletedXid(latestXid);
ProcGlobal->xids[proc->pgxactoff] = 0;
+ ProcGlobal->nsubxids[proc->pgxactoff] = 0;
}
else
{
}
Assert(TransactionIdIsValid(ProcGlobal->xids[proc->pgxactoff] == 0));
+ Assert(TransactionIdIsValid(ProcGlobal->nsubxids[proc->pgxactoff] == 0));
ProcGlobal->vacuumFlags[proc->pgxactoff] = 0;
for (index = 0; index < arrayP->numProcs; index++)
(arrayP->numProcs - index - 1) * sizeof(*arrayP->pgprocnos));
memmove(&ProcGlobal->xids[index], &ProcGlobal->xids[index + 1],
(arrayP->numProcs - index - 1) * sizeof(*ProcGlobal->xids));
+ memmove(&ProcGlobal->nsubxids[index], &ProcGlobal->nsubxids[index + 1],
+ (arrayP->numProcs - index - 1) * sizeof(*ProcGlobal->nsubxids));
memmove(&ProcGlobal->vacuumFlags[index], &ProcGlobal->vacuumFlags[index + 1],
(arrayP->numProcs - index - 1) * sizeof(*ProcGlobal->vacuumFlags));
* estimate of global xmin, but that's OK.
*/
Assert(!TransactionIdIsValid(proc->xidCopy));
+ Assert(proc->nsubxidsCopy == 0);
proc->lxid = InvalidLocalTransactionId;
proc->xmin = InvalidTransactionId;
proc->delayChkpt = false; /* be sure this is cleared in abort */
proc->recoveryConflictPending = false;
- Assert(pgxact->nxids == 0);
- Assert(pgxact->overflowed == false);
-
/* must be cleared with xid/xmin: */
/* avoid unnecessarily dirtying shared cachelines */
if (proc->vacuumFlagsCopy & PROC_VACUUM_STATE_MASK)
}
/* Clear the subtransaction-XID cache too while holding the lock */
- pgxact->nxids = 0;
- pgxact->overflowed = false;
+ Assert(ProcGlobal->nsubxids[pgxactoff] == proc->nsubxidsCopy);
+ if (proc->nsubxidsCopy != 0)
+ {
+ ProcGlobal->nsubxids[pgxactoff] = 0;
+ proc->nsubxidsCopy = 0;
+ }
/* Also advance global latestCompletedXid while holding the lock */
MaintainLatestCompletedXid(latestXid);
void
ProcArrayClearTransaction(PGPROC *proc)
{
- PGXACT *pgxact = &allPgXact[proc->pgprocno];
size_t pgxactoff;
/*
Assert(!proc->delayChkpt);
/* Clear the subtransaction-XID cache too */
- pgxact->nxids = 0;
- pgxact->overflowed = false;
+ Assert(ProcGlobal->nsubxids[pgxactoff] == proc->nsubxidsCopy);
+ if (proc->nsubxidsCopy != 0)
+ {
+ ProcGlobal->nsubxids[pgxactoff] = 0;
+ proc->nsubxidsCopy = 0;
+ }
LWLockRelease(ProcArrayLock);
}
{
static TransactionId *xids = NULL;
static TransactionId *other_xids;
+ static int8 *other_nsubxids;
int nxids = 0;
ProcArrayStruct *arrayP = procArray;
TransactionId topxid;
/* No shortcuts, gotta grovel through the array */
other_xids = ProcGlobal->xids;
+ other_nsubxids = ProcGlobal->nsubxids;
for (i = 0; i < arrayP->numProcs; i++)
{
int pgprocno = arrayP->pgprocnos[i];
PGPROC *proc = &allProcs[pgprocno];
- PGXACT *pgxact = &allPgXact[pgprocno];
TransactionId pxid;
int pxids;
/*
* Step 2: check the cached child-Xids arrays
*/
- pxids = pgxact->nxids;
+ pxids = other_nsubxids[i];
pg_read_barrier(); /* pairs with barrier in GetNewTransactionId() */
for (j = pxids - 1; j >= 0; j--)
{
* we hold ProcArrayLock. So we can't miss an Xid that we need to
* worry about.)
*/
- if (pgxact->overflowed)
+ if (proc->nsubxidsCopy == -1)
xids[nxids++] = pxid;
}
{
size_t numProcs = arrayP->numProcs;
TransactionId *xip = snapshot->xip;
+ int8 *allnsubxids = ProcGlobal->nsubxids;
int workspace_count = 0;
uint8 *allVacuumFlags = ProcGlobal->vacuumFlags;
{
int pgxactoff = snapshot_workspace_off[i];
TransactionId xid = snapshot_workspace_xid[i];
- int pgprocno = arrayP->pgprocnos[pgxactoff];
- PGXACT *pgxact = &allPgXact[pgprocno];
- uint8 vacuumFlags = allVacuumFlags[pgxactoff];
+ uint8 vacuumFlags = allVacuumFlags[pgxactoff];
int nsubxids;
Assert(allProcs[arrayP->pgprocnos[pgxactoff]].pgxactoff == pgxactoff);
if (suboverflowed)
continue;
- nsubxids = pgxact->nxids;
+ nsubxids = allnsubxids[pgxactoff];
- if (pgxact->overflowed)
+ if (nsubxids == -1)
{
suboverflowed = true;
continue;
*/
for (index = 0; index < arrayP->numProcs; index++)
{
- int pgprocno = arrayP->pgprocnos[index];
- PGXACT *pgxact = &allPgXact[pgprocno];
TransactionId xid;
/* Fetch xid just once - see GetNewTransactionId */
if (TransactionIdPrecedes(xid, oldestRunningXid))
oldestRunningXid = xid;
- if (pgxact->overflowed)
+ if (ProcGlobal->nsubxids[index] == -1)
suboverflowed = true;
/*
*/
if (!suboverflowed)
{
+ int8 *other_nsubxids = ProcGlobal->nsubxids;
+
for (index = 0; index < arrayP->numProcs; index++)
{
int pgprocno = arrayP->pgprocnos[index];
PGPROC *proc = &allProcs[pgprocno];
- PGXACT *pgxact = &allPgXact[pgprocno];
- int nxids;
+ int nsubxids;
/*
* Save subtransaction XIDs. Other backends can't add or remove
* entries while we're holding XidGenLock.
*/
- nxids = pgxact->nxids;
- if (nxids > 0)
+ nsubxids = other_nsubxids[index];
+ if (nsubxids > 0)
{
/* barrier not really required, as XidGenLock is held, but ... */
pg_read_barrier(); /* pairs with GetNewTransactionId */
memcpy(&xids[count], (void *) proc->subxids.xids,
- nxids * sizeof(TransactionId));
- count += nxids;
- subcount += nxids;
+ nsubxids * sizeof(TransactionId));
+ count += nsubxids;
+ subcount += nsubxids;
/*
* Top-level XID of a transaction is always less than any of
}
-#define XidCacheRemove(i) \
- do { \
- MyProc->subxids.xids[i] = MyProc->subxids.xids[MyPgXact->nxids - 1]; \
- pg_write_barrier(); \
- MyPgXact->nxids--; \
- } while (0)
-
/*
* XidCacheRemoveRunningXids
*
{
int i,
j;
+ int8 *pnsubxids;
Assert(TransactionIdIsValid(xid));
*/
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+ pnsubxids = &ProcGlobal->nsubxids[MyProc->pgxactoff];
+
/*
* Under normal circumstances xid and xids[] will be in increasing order,
* as will be the entries in subxids. Scan backwards to avoid O(N^2)
{
TransactionId anxid = xids[i];
- for (j = MyPgXact->nxids - 1; j >= 0; j--)
+ for (j = *pnsubxids - 1; j >= 0; j--)
{
if (TransactionIdEquals(MyProc->subxids.xids[j], anxid))
{
- XidCacheRemove(j);
+ MyProc->subxids.xids[j] = MyProc->subxids.xids[*pnsubxids - 1];
+ pg_write_barrier();
+ (*pnsubxids)--;
break;
}
}
* error during AbortSubTransaction. So instead of Assert, emit a
* debug warning.
*/
- if (j < 0 && !MyPgXact->overflowed)
+ if (j < 0 && MyProc->nsubxidsCopy != -1)
elog(WARNING, "did not find subXID %u in MyProc", anxid);
}
- for (j = MyPgXact->nxids - 1; j >= 0; j--)
+ for (j = *pnsubxids - 1; j >= 0; j--)
{
if (TransactionIdEquals(MyProc->subxids.xids[j], xid))
{
- XidCacheRemove(j);
+ MyProc->subxids.xids[j] = MyProc->subxids.xids[*pnsubxids - 1];
+ pg_write_barrier();
+ (*pnsubxids)--;
break;
}
}
/* Ordinarily we should have found it, unless the cache has overflowed */
- if (j < 0 && !MyPgXact->overflowed)
+ if (j < 0 && MyProc->nsubxidsCopy != -1)
elog(WARNING, "did not find subXID %u in MyProc", xid);
+ MyProc->nsubxidsCopy = *pnsubxids;
+
/* Also advance global latestCompletedXid while holding the lock */
if (TransactionIdPrecedes(XidFromFullTransactionId(ShmemVariableCache->latestCompletedFullXid),
latestXid))