summaryrefslogtreecommitdiff
path: root/src/backend/utils/time/snapmgr.c
diff options
context:
space:
mode:
authorAndres Freund2019-01-22 01:03:15 +0000
committerAndres Freund2019-01-22 01:06:41 +0000
commitb7eda3e0e33402a7727253e6f307ca96b92eb23d (patch)
tree0878213217c64dcde36233ef0609e0c9d2d3c945 /src/backend/utils/time/snapmgr.c
parent63746189b23815415cacc715fdc4f6b991f1a5e7 (diff)
Move generic snapshot related code from tqual.h to snapmgr.h.
The code in tqual.c is largely heap specific. Due to the upcoming pluggable storage work, it therefore makes sense to move it into access/heap/ (as the file's header notes, the tqual name isn't very good). But the various statically allocated snapshot and snapshot initialization functions are now (see previous commit) generic and do not depend on functions declared in tqual.h anymore. Therefore move. Also move XidInMVCCSnapshot as that's useful for future AMs, and already used outside of tqual.c. Author: Andres Freund Discussion: https://postgr.es/m/[email protected]
Diffstat (limited to 'src/backend/utils/time/snapmgr.c')
-rw-r--r--src/backend/utils/time/snapmgr.c126
1 files changed, 125 insertions, 1 deletions
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index d47d2b3ef7a..6e02585e10e 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -48,6 +48,7 @@
#include <sys/stat.h>
#include <unistd.h>
+#include "access/subtrans.h"
#include "access/transam.h"
#include "access/xact.h"
#include "access/xlog.h"
@@ -66,7 +67,6 @@
#include "utils/resowner_private.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
-#include "utils/tqual.h"
/*
@@ -144,6 +144,8 @@ static volatile OldSnapshotControlData *oldSnapshotControl;
static SnapshotData CurrentSnapshotData = {SNAPSHOT_MVCC};
static SnapshotData SecondarySnapshotData = {SNAPSHOT_MVCC};
SnapshotData CatalogSnapshotData = {SNAPSHOT_MVCC};
+SnapshotData SnapshotSelfData = {SNAPSHOT_SELF};
+SnapshotData SnapshotAnyData = {SNAPSHOT_ANY};
/* Pointers to valid snapshots */
static Snapshot CurrentSnapshot = NULL;
@@ -2192,3 +2194,125 @@ RestoreTransactionSnapshot(Snapshot snapshot, void *master_pgproc)
{
SetTransactionSnapshot(snapshot, NULL, InvalidPid, master_pgproc);
}
+
+/*
+ * XidInMVCCSnapshot
+ * Is the given XID still-in-progress according to the snapshot?
+ *
+ * Note: GetSnapshotData never stores either top xid or subxids of our own
+ * backend into a snapshot, so these xids will not be reported as "running"
+ * by this function. This is OK for current uses, because we always check
+ * TransactionIdIsCurrentTransactionId first, except when it's known the
+ * XID could not be ours anyway.
+ */
+bool
+XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
+{
+ uint32 i;
+
+ /*
+ * Make a quick range check to eliminate most XIDs without looking at the
+ * xip arrays. Note that this is OK even if we convert a subxact XID to
+ * its parent below, because a subxact with XID < xmin has surely also got
+ * a parent with XID < xmin, while one with XID >= xmax must belong to a
+ * parent that was not yet committed at the time of this snapshot.
+ */
+
+ /* Any xid < xmin is not in-progress */
+ if (TransactionIdPrecedes(xid, snapshot->xmin))
+ return false;
+ /* Any xid >= xmax is in-progress */
+ if (TransactionIdFollowsOrEquals(xid, snapshot->xmax))
+ return true;
+
+ /*
+ * Snapshot information is stored slightly differently in snapshots taken
+ * during recovery.
+ */
+ if (!snapshot->takenDuringRecovery)
+ {
+ /*
+ * If the snapshot contains full subxact data, the fastest way to
+ * check things is just to compare the given XID against both subxact
+ * XIDs and top-level XIDs. If the snapshot overflowed, we have to
+ * use pg_subtrans to convert a subxact XID to its parent XID, but
+ * then we need only look at top-level XIDs not subxacts.
+ */
+ if (!snapshot->suboverflowed)
+ {
+ /* we have full data, so search subxip */
+ int32 j;
+
+ for (j = 0; j < snapshot->subxcnt; j++)
+ {
+ if (TransactionIdEquals(xid, snapshot->subxip[j]))
+ return true;
+ }
+
+ /* not there, fall through to search xip[] */
+ }
+ else
+ {
+ /*
+ * Snapshot overflowed, so convert xid to top-level. This is safe
+ * because we eliminated too-old XIDs above.
+ */
+ xid = SubTransGetTopmostTransaction(xid);
+
+ /*
+ * If xid was indeed a subxact, we might now have an xid < xmin,
+ * so recheck to avoid an array scan. No point in rechecking
+ * xmax.
+ */
+ if (TransactionIdPrecedes(xid, snapshot->xmin))
+ return false;
+ }
+
+ for (i = 0; i < snapshot->xcnt; i++)
+ {
+ if (TransactionIdEquals(xid, snapshot->xip[i]))
+ return true;
+ }
+ }
+ else
+ {
+ int32 j;
+
+ /*
+ * In recovery we store all xids in the subxact array because it is by
+ * far the bigger array, and we mostly don't know which xids are
+ * top-level and which are subxacts. The xip array is empty.
+ *
+ * We start by searching subtrans, if we overflowed.
+ */
+ if (snapshot->suboverflowed)
+ {
+ /*
+ * Snapshot overflowed, so convert xid to top-level. This is safe
+ * because we eliminated too-old XIDs above.
+ */
+ xid = SubTransGetTopmostTransaction(xid);
+
+ /*
+ * If xid was indeed a subxact, we might now have an xid < xmin,
+ * so recheck to avoid an array scan. No point in rechecking
+ * xmax.
+ */
+ if (TransactionIdPrecedes(xid, snapshot->xmin))
+ return false;
+ }
+
+ /*
+ * We now have either a top-level xid higher than xmin or an
+ * indeterminate xid. We don't know whether it's top level or subxact
+ * but it doesn't matter. If it's present, the xid is visible.
+ */
+ for (j = 0; j < snapshot->subxcnt; j++)
+ {
+ if (TransactionIdEquals(xid, snapshot->subxip[j]))
+ return true;
+ }
+ }
+
+ return false;
+}