diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 4308128..76f8cff 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -1468,6 +1468,9 @@ GetSnapshotData(Snapshot snapshot) snapshot->curcid = GetCurrentCommandId(false); + /* Initialise the single xid cache for this snapshot */ + snapshot->xid_in_snapshot = InvalidTransactionId; + /* * This is a new snapshot, so set both refcounts are zero, and mark it as * not copied in persistent memory. diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c index 24384b4..68413bd 100644 --- a/src/backend/utils/time/tqual.c +++ b/src/backend/utils/time/tqual.c @@ -1532,6 +1532,25 @@ XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot) return true; /* + * If we've seen this xid last time then we use our cached knowledge + * to allow a fast path out. + * + * When XidInMVCCSnapshot is called repeatedly in a transaction it + * is usually because we're viewing the results of large transactions. + * Typically there will be just one big concurrent transaction and so + * its very fast to just remember that and be done. Lots of short + * transactions don't cause problems because their xids quickly go + * above the snapshot's xmax and get ignore before we get here. + * + * XXX If there were more big concurrent transactions then it would make + * sense to remember a list of xids and an LRU scheme. For long lists it + * would make better sense to sort the snapshot xids. Both of those + * ideas have much more complex code and diminishing returns. + */ + if (TransactionIdEquals(xid, snapshot->xid_in_snapshot)) + return true; + + /* * Snapshot information is stored slightly differently in snapshots taken * during recovery. */ @@ -1552,7 +1571,10 @@ XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot) for (j = 0; j < snapshot->subxcnt; j++) { if (TransactionIdEquals(xid, snapshot->subxip[j])) + { + snapshot->xid_in_snapshot = xid; return true; + } } /* not there, fall through to search xip[] */ @@ -1574,7 +1596,10 @@ XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot) for (i = 0; i < snapshot->xcnt; i++) { if (TransactionIdEquals(xid, snapshot->xip[i])) + { + snapshot->xid_in_snapshot = xid; return true; + } } } else @@ -1610,7 +1635,10 @@ XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot) for (j = 0; j < snapshot->subxcnt; j++) { if (TransactionIdEquals(xid, snapshot->subxip[j])) + { + snapshot->xid_in_snapshot = xid; return true; + } } } diff --git a/src/include/utils/snapshot.h b/src/include/utils/snapshot.h index e747191..605895e 100644 --- a/src/include/utils/snapshot.h +++ b/src/include/utils/snapshot.h @@ -56,6 +56,12 @@ typedef struct SnapshotData bool copied; /* false if it's a static snapshot */ /* + * Single transaction cache. Keep track of common xid so we can respond + * quickly when we keep seeing an xid while we use this snapshot. + */ + TransactionId xid_in_snapshot; + + /* * note: all ids in subxip[] are >= xmin, but we don't bother filtering * out any that are >= xmax */