optimize-repeated-snapshots.patch
application/octet-stream
Filename: optimize-repeated-snapshots.patch
Type: application/octet-stream
Part: 0
Message:
optimizing repeated MVCC snapshots
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
| File | + | − |
|---|---|---|
| src/backend/storage/ipc/procarray.c | 34 | 0 |
| src/include/utils/snapshot.h | 2 | 1 |
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 6ea0a28..cd0b39c 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -51,6 +51,7 @@
#include "access/xact.h"
#include "access/twophase.h"
#include "miscadmin.h"
+#include "storage/barrier.h"
#include "storage/procarray.h"
#include "storage/spin.h"
#include "utils/builtins.h"
@@ -81,6 +82,9 @@ typedef struct ProcArrayStruct
*/
TransactionId lastOverflowedXid;
+ /* Increment on transaction commit/abort. */
+ TransactionId xendcount;
+
/*
* We declare pgprocnos[] as 1 entry because C wants a fixed-size array, but
* actually it is maxProcs entries long.
@@ -223,7 +227,13 @@ CreateSharedProcArray(void)
{
/*
* We're the first - initialize.
+ *
+ * Note: We need to initialize procArray->xfinish to something other
+ * than 0, because we're going to later compare it against the
+ * xendcount of a snapshot to see if anything's changed; and 0 in the
+ * snapshot means it's as-yet uninitialized.
*/
+ procArray->xendcount = 1;
procArray->numProcs = 0;
procArray->maxProcs = PROCARRAY_MAXPROCS;
procArray->maxKnownAssignedXids = TOTAL_MAX_CACHED_SUBXIDS;
@@ -410,6 +420,8 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
latestXid))
ShmemVariableCache->latestCompletedXid = latestXid;
+ procArray->xendcount++;
+
LWLockRelease(ProcArrayLock);
}
else
@@ -1245,6 +1257,27 @@ GetSnapshotData(Snapshot snapshot)
Assert(snapshot != NULL);
/*
+ * If no transactions have committed or aborted since the last time this
+ * function was called on the passed-in snapshot, we can return without
+ * doing anything.
+ *
+ * Memory ordering effects: It's possible that the procArray->xendcount
+ * could be fetched by the CPU prior to entering this function, in which
+ * case we might see an "old" value that matches instead of a "new" value
+ * that doesn't. But that's not much different than if this function had
+ * been called slightly sooner in the first place. Just to be on the safe
+ * side, include a read barrier, so that this fetch won't be done before
+ * all prior fetches have been completed.
+ *
+ * XXX: This is theoretically unsafe if 64-bit reads and writes from shared
+ * memory aren't atomic, but in practice you'd have to be incredibly
+ * unlucky to have a problem.
+ */
+ pg_read_barrier();
+ if (procArray->xendcount == snapshot->xendcount)
+ return snapshot;
+
+ /*
* Allocating space for maxProcs xids is usually overkill; numProcs would
* be sufficient. But it seems better to do the malloc while not holding
* the lock, so we can't look at numProcs. Likewise, we allocate much
@@ -1283,6 +1316,7 @@ GetSnapshotData(Snapshot snapshot)
LWLockAcquire(ProcArrayLock, LW_SHARED);
/* xmax is always latestCompletedXid + 1 */
+ snapshot->xendcount = arrayP->xendcount;
xmax = ShmemVariableCache->latestCompletedXid;
Assert(TransactionIdIsNormal(xmax));
TransactionIdAdvance(xmax);
diff --git a/src/include/utils/snapshot.h b/src/include/utils/snapshot.h
index 93c02fa..d6a3a68 100644
--- a/src/include/utils/snapshot.h
+++ b/src/include/utils/snapshot.h
@@ -44,12 +44,13 @@ typedef struct SnapshotData
* is stored as an optimization to avoid needing to search the XID arrays
* for most tuples.
*/
+ uint64 xendcount; /* when did we take this snapshot? */
TransactionId xmin; /* all XID < xmin are visible to me */
TransactionId xmax; /* all XID >= xmax are invisible to me */
uint32 xcnt; /* # of xact ids in xip[] */
- TransactionId *xip; /* array of xact IDs in progress */
/* note: all ids in xip[] satisfy xmin <= xip[i] < xmax */
int32 subxcnt; /* # of xact ids in subxip[] */
+ TransactionId *xip; /* array of xact IDs in progress */
TransactionId *subxip; /* array of subxact IDs in progress */
bool suboverflowed; /* has the subxip array overflowed? */
bool takenDuringRecovery; /* recovery-shaped snapshot? */