shared-snapshot-v2.patch
application/octet-stream
Filename: shared-snapshot-v2.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v2
| File | + | − |
|---|---|---|
| src/backend/access/transam/varsup.c | 4 | 0 |
| src/backend/storage/ipc/procarray.c | 156 | 81 |
| src/backend/storage/lmgr/proc.c | 6 | 0 |
| src/include/storage/procarray.h | 1 | 0 |
| src/include/storage/proc.h | 12 | 0 |
diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c
index 555bb13..f53051d 100644
--- a/src/backend/access/transam/varsup.c
+++ b/src/backend/access/transam/varsup.c
@@ -224,6 +224,10 @@ GetNewTransactionId(bool isSubXact)
else
myproc->subxids.overflowed = true;
}
+
+ /*
+ * XXX Do we need to invalidate the shared snapshot ?
+ */
}
LWLockRelease(XidGenLock);
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index e7593fa..91bd26d 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -158,6 +158,8 @@ static int KnownAssignedXidsGetAndSetXmin(TransactionId *xarray,
TransactionId xmax);
static TransactionId KnownAssignedXidsGetOldestXmin(void);
static void KnownAssignedXidsDisplay(int trace_level);
+static void SetSharedSnapshot(Snapshot snapshot, TransactionId globalxmin);
+static bool GetSharedSnapshot(Snapshot snapshot, TransactionId *globalxmin);
/*
* Report shared-memory space needed by CreateSharedProcArray.
@@ -379,6 +381,7 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
latestXid))
ShmemVariableCache->latestCompletedXid = latestXid;
+ ResetSharedSnapshot();
LWLockRelease(ProcArrayLock);
}
else
@@ -1111,6 +1114,60 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum)
return result;
}
+static bool
+GetSharedSnapshot(Snapshot snapshot, TransactionId *globalxmin)
+{
+ volatile PROC_HDR *procglobal = ProcGlobal;
+
+ if (!procglobal->sn_isvalid)
+ return false;
+
+ snapshot->xmin = procglobal->sn_xmin;
+ snapshot->xmax = procglobal->sn_xmax;
+
+ snapshot->xcnt = procglobal->sn_xcnt;
+ if (snapshot->xcnt)
+ memcpy(snapshot->xip, procglobal->sn_xip, snapshot->xcnt);
+
+ snapshot->subxcnt = procglobal->sn_subxcnt;
+ if (snapshot->subxcnt)
+ memcpy(snapshot->subxip, procglobal->sn_subxip, snapshot->subxcnt);
+
+ snapshot->suboverflowed = procglobal->sn_suboverflowed;
+ *globalxmin = procglobal->sn_globalxmin;
+
+ return true;
+}
+
+static void
+SetSharedSnapshot(Snapshot snapshot, TransactionId globalxmin)
+{
+ volatile PROC_HDR *procglobal = ProcGlobal;
+
+ procglobal->sn_xmin = snapshot->xmin;
+ procglobal->sn_xmax = snapshot->xmax;
+
+ procglobal->sn_xcnt = snapshot->xcnt;
+ if (snapshot->xcnt)
+ memcpy(procglobal->sn_xip, snapshot->xip, snapshot->xcnt);
+
+ procglobal->sn_subxcnt = snapshot->subxcnt;
+ if (snapshot->subxcnt)
+ memcpy(procglobal->sn_subxip, snapshot->subxip, snapshot->subxcnt);
+
+ procglobal->sn_suboverflowed = snapshot->suboverflowed;
+
+ procglobal->sn_isvalid = true;
+ procglobal->sn_globalxmin = globalxmin;
+}
+
+void
+ResetSharedSnapshot()
+{
+ volatile PROC_HDR *procglobal = ProcGlobal;
+ procglobal->sn_isvalid = false;
+}
+
/*
* GetSnapshotData -- returns information about running transactions.
*
@@ -1216,83 +1273,101 @@ GetSnapshotData(Snapshot snapshot)
if (!snapshot->takenDuringRecovery)
{
- /*
- * Spin over procArray checking xid, xmin, and subxids. The goal is
- * to gather all active xids, find the lowest xmin, and try to record
- * subxids. During recovery no xids will be assigned, so all normal
- * backends can be ignored, nor are there any VACUUMs running. All
- * prepared transaction xids are held in KnownAssignedXids, so these
- * will be seen without needing to loop through procs here.
- */
- for (index = 0; index < arrayP->numProcs; index++)
+ if (!GetSharedSnapshot(snapshot, &globalxmin))
{
- volatile PGPROC *proc = arrayP->procs[index];
- TransactionId xid;
-
- /* Ignore procs running LAZY VACUUM */
- if (proc->vacuumFlags & PROC_IN_VACUUM)
- continue;
-
- /* Update globalxmin to be the smallest valid xmin */
- xid = proc->xmin; /* fetch just once */
- if (TransactionIdIsNormal(xid) &&
- TransactionIdPrecedes(xid, globalxmin))
- globalxmin = xid;
-
- /* Fetch xid just once - see GetNewTransactionId */
- xid = proc->xid;
-
/*
- * If the transaction has been assigned an xid < xmax we add it to
- * the snapshot, and update xmin if necessary. There's no need to
- * store XIDs >= xmax, since we'll treat them as running anyway.
- * We don't bother to examine their subxids either.
- *
- * We don't include our own XID (if any) in the snapshot, but we
- * must include it into xmin.
+ * Spin over procArray checking xid, xmin, and subxids. The goal is
+ * to gather all active xids, find the lowest xmin, and try to record
+ * subxids. During recovery no xids will be assigned, so all normal
+ * backends can be ignored, nor are there any VACUUMs running. All
+ * prepared transaction xids are held in KnownAssignedXids, so these
+ * will be seen without needing to loop through procs here.
*/
- if (TransactionIdIsNormal(xid))
+ for (index = 0; index < arrayP->numProcs; index++)
{
- if (TransactionIdFollowsOrEquals(xid, xmax))
+ volatile PGPROC *proc = arrayP->procs[index];
+ TransactionId xid;
+
+ /* Ignore procs running LAZY VACUUM */
+ if (proc->vacuumFlags & PROC_IN_VACUUM)
continue;
- if (proc != MyProc)
- snapshot->xip[count++] = xid;
- if (TransactionIdPrecedes(xid, xmin))
- xmin = xid;
- }
- /*
- * Save subtransaction XIDs if possible (if we've already
- * overflowed, there's no point). Note that the subxact XIDs must
- * be later than their parent, so no need to check them against
- * xmin. We could filter against xmax, but it seems better not to
- * do that much work while holding the ProcArrayLock.
- *
- * The other backend can add more subxids concurrently, but cannot
- * remove any. Hence it's important to fetch nxids just once.
- * Should be safe to use memcpy, though. (We needn't worry about
- * missing any xids added concurrently, because they must postdate
- * xmax.)
- *
- * Again, our own XIDs are not included in the snapshot.
- */
- if (!suboverflowed && proc != MyProc)
- {
- if (proc->subxids.overflowed)
- suboverflowed = true;
- else
+ /* Update globalxmin to be the smallest valid xmin */
+ xid = proc->xmin; /* fetch just once */
+ if (TransactionIdIsNormal(xid) &&
+ TransactionIdPrecedes(xid, globalxmin))
+ globalxmin = xid;
+
+ /* Fetch xid just once - see GetNewTransactionId */
+ xid = proc->xid;
+
+ /*
+ * If the transaction has been assigned an xid < xmax we add it to
+ * the snapshot, and update xmin if necessary. There's no need to
+ * store XIDs >= xmax, since we'll treat them as running anyway.
+ * We don't bother to examine their subxids either.
+ *
+ * We don't include our own XID (if any) in the snapshot, but we
+ * must include it into xmin.
+ */
+ if (TransactionIdIsNormal(xid))
{
- int nxids = proc->subxids.nxids;
+ if (TransactionIdFollowsOrEquals(xid, xmax))
+ continue;
+ if (proc != MyProc)
+ snapshot->xip[count++] = xid;
+ if (TransactionIdPrecedes(xid, xmin))
+ xmin = xid;
+ }
- if (nxids > 0)
+ /*
+ * Save subtransaction XIDs if possible (if we've already
+ * overflowed, there's no point). Note that the subxact XIDs must
+ * be later than their parent, so no need to check them against
+ * xmin. We could filter against xmax, but it seems better not to
+ * do that much work while holding the ProcArrayLock.
+ *
+ * The other backend can add more subxids concurrently, but cannot
+ * remove any. Hence it's important to fetch nxids just once.
+ * Should be safe to use memcpy, though. (We needn't worry about
+ * missing any xids added concurrently, because they must postdate
+ * xmax.)
+ *
+ * Again, our own XIDs are not included in the snapshot.
+ */
+ if (!suboverflowed && proc != MyProc)
+ {
+ if (proc->subxids.overflowed)
+ suboverflowed = true;
+ else
{
- memcpy(snapshot->subxip + subcount,
- (void *) proc->subxids.xids,
- nxids * sizeof(TransactionId));
- subcount += nxids;
+ int nxids = proc->subxids.nxids;
+
+ if (nxids > 0)
+ {
+ memcpy(snapshot->subxip + subcount,
+ (void *) proc->subxids.xids,
+ nxids * sizeof(TransactionId));
+ subcount += nxids;
+ }
}
}
}
+
+ snapshot->xmin = xmin;
+ snapshot->xmax = xmax;
+ snapshot->xcnt = count;
+ snapshot->subxcnt = subcount;
+ snapshot->suboverflowed = suboverflowed;
+
+ /*
+ * Update globalxmin to include actual process xids. This is a slightly
+ * different way of computing it than GetOldestXmin uses, but should give
+ * the same result.
+ */
+ if (TransactionIdPrecedes(snapshot->xmin, globalxmin))
+ globalxmin = snapshot->xmin;
+ SetSharedSnapshot(snapshot, globalxmin);
}
}
else
@@ -1325,32 +1400,32 @@ GetSnapshotData(Snapshot snapshot)
if (TransactionIdPrecedesOrEquals(xmin, procArray->lastOverflowedXid))
suboverflowed = true;
+
+ snapshot->xmin = xmin;
+ snapshot->xmax = xmax;
+ snapshot->xcnt = count;
+ snapshot->subxcnt = subcount;
+ snapshot->suboverflowed = suboverflowed;
+
+ /*
+ * Update globalxmin to include actual process xids. This is a slightly
+ * different way of computing it than GetOldestXmin uses, but should give
+ * the same result.
+ */
+ if (TransactionIdPrecedes(snapshot->xmin, globalxmin))
+ globalxmin = snapshot->xmin;
}
if (!TransactionIdIsValid(MyProc->xmin))
- MyProc->xmin = TransactionXmin = xmin;
+ MyProc->xmin = TransactionXmin = snapshot->xmin;
LWLockRelease(ProcArrayLock);
- /*
- * Update globalxmin to include actual process xids. This is a slightly
- * different way of computing it than GetOldestXmin uses, but should give
- * the same result.
- */
- if (TransactionIdPrecedes(xmin, globalxmin))
- globalxmin = xmin;
-
/* Update global variables too */
RecentGlobalXmin = globalxmin - vacuum_defer_cleanup_age;
if (!TransactionIdIsNormal(RecentGlobalXmin))
RecentGlobalXmin = FirstNormalTransactionId;
- RecentXmin = xmin;
-
- snapshot->xmin = xmin;
- snapshot->xmax = xmax;
- snapshot->xcnt = count;
- snapshot->subxcnt = subcount;
- snapshot->suboverflowed = suboverflowed;
+ RecentXmin = snapshot->xmin;
snapshot->curcid = GetCurrentCommandId(false);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index f4091ec..0d82561 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -109,6 +109,9 @@ ProcGlobalShmemSize(void)
size = add_size(size, mul_size(NUM_AUXILIARY_PROCS, sizeof(PGPROC)));
/* MyProcs, including autovacuum workers and launcher */
size = add_size(size, mul_size(MaxBackends, sizeof(PGPROC)));
+ /* Shared snapshot xip/subxip array */
+ size = add_size(size, mul_size(2 * MaxBackends, sizeof (TransactionId)));
+ size = add_size(size, mul_size(2 * NUM_AUXILIARY_PROCS, sizeof (TransactionId)));
/* ProcStructLock */
size = add_size(size, sizeof(slock_t));
@@ -229,6 +232,9 @@ InitProcGlobal(void)
*/
AuxiliaryProcs = &procs[MaxBackends];
+ ProcGlobal->sn_xip = (TransactionId *) ShmemAlloc(sizeof (TransactionId) * (MaxBackends + NUM_AUXILIARY_PROCS));
+ ProcGlobal->sn_subxip = (TransactionId *) ShmemAlloc(sizeof (TransactionId) * (MaxBackends + NUM_AUXILIARY_PROCS));
+
/* Create ProcStructLock spinlock, too */
ProcStructLock = (slock_t *) ShmemAlloc(sizeof(slock_t));
SpinLockInit(ProcStructLock);
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 8b09b2a..5831f5a 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -183,6 +183,18 @@ typedef struct PROC_HDR
int startupProcPid;
/* Buffer id of the buffer that Startup process waits for pin on, or -1 */
int startupBufferPinWaitBufId;
+
+ /* Shared snapshot information */
+ bool sn_isvalid; /* is shared snapshot still valid ? */
+ TransactionId sn_xmin; /* all XID < xmin are visible to me */
+ TransactionId sn_xmax; /* all XID >= xmax are invisible to me */
+ uint32 sn_xcnt; /* # of xact ids in xip[] */
+ TransactionId *sn_xip; /* array of xact IDs in progress */
+ /* note: all ids in xip[] satisfy xmin <= xip[i] < xmax */
+ int32 sn_subxcnt; /* # of xact ids in subxip[] */
+ TransactionId *sn_subxip; /* array of subxact IDs in progress */
+ bool sn_suboverflowed; /* has the subxip array overflowed? */
+ TransactionId sn_globalxmin;
} PROC_HDR;
extern PROC_HDR *ProcGlobal;
diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h
index 3c20fc4..ac0211b 100644
--- a/src/include/storage/procarray.h
+++ b/src/include/storage/procarray.h
@@ -70,5 +70,6 @@ extern bool CountOtherDBBackends(Oid databaseId,
extern void XidCacheRemoveRunningXids(TransactionId xid,
int nxids, const TransactionId *xids,
TransactionId latestXid);
+extern void ResetSharedSnapshot(void);
#endif /* PROCARRAY_H */