aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/access/transam/transam.c13
-rw-r--r--src/backend/storage/ipc/procarray.c12
-rw-r--r--src/backend/utils/adt/xid8funcs.c30
3 files changed, 32 insertions, 23 deletions
diff --git a/src/backend/access/transam/transam.c b/src/backend/access/transam/transam.c
index 1ba4bbead55..e9e0ef79c1b 100644
--- a/src/backend/access/transam/transam.c
+++ b/src/backend/access/transam/transam.c
@@ -226,10 +226,15 @@ TransactionIdDidAbort(TransactionId transactionId)
*
* This does NOT look into pg_xact but merely probes our local cache
* (and so it's not named TransactionIdDidComplete, which would be the
- * appropriate name for a function that worked that way). The intended
- * use is just to short-circuit TransactionIdIsInProgress calls when doing
- * repeated heapam_visibility.c checks for the same XID. If this isn't
- * extremely fast then it will be counterproductive.
+ * appropriate name for a function that worked that way).
+ *
+ * NB: This is unused, and will be removed in v15. This was used to
+ * short-circuit TransactionIdIsInProgress, but that was wrong for a
+ * transaction that was known to be marked as committed in CLOG but not
+ * yet removed from the proc array. This is kept in backbranches just in
+ * case it is still used by extensions. However, extensions doing
+ * something similar to tuple visibility checks should also be careful to
+ * check the proc array first!
*
* Note:
* Assumes transaction identifier is valid.
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 33a890736a5..755f842d6a7 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -263,6 +263,11 @@ static ProcArrayStruct *procArray;
static PGPROC *allProcs;
/*
+ * Cache to reduce overhead of repeated calls to TransactionIdIsInProgress()
+ */
+static TransactionId cachedXidIsNotInProgress = InvalidTransactionId;
+
+/*
* Bookkeeping for tracking emulated transactions in recovery
*/
static TransactionId *KnownAssignedXids;
@@ -1404,7 +1409,7 @@ TransactionIdIsInProgress(TransactionId xid)
* already known to be completed, we can fall out without any access to
* shared memory.
*/
- if (TransactionIdIsKnownCompleted(xid))
+ if (TransactionIdEquals(cachedXidIsNotInProgress, xid))
{
xc_by_known_xact_inc();
return false;
@@ -1562,6 +1567,7 @@ TransactionIdIsInProgress(TransactionId xid)
if (nxids == 0)
{
xc_no_overflow_inc();
+ cachedXidIsNotInProgress = xid;
return false;
}
@@ -1576,7 +1582,10 @@ TransactionIdIsInProgress(TransactionId xid)
xc_slow_answer_inc();
if (TransactionIdDidAbort(xid))
+ {
+ cachedXidIsNotInProgress = xid;
return false;
+ }
/*
* It isn't aborted, so check whether the transaction tree it belongs to
@@ -1594,6 +1603,7 @@ TransactionIdIsInProgress(TransactionId xid)
}
}
+ cachedXidIsNotInProgress = xid;
return false;
}
diff --git a/src/backend/utils/adt/xid8funcs.c b/src/backend/utils/adt/xid8funcs.c
index cc2b4ac7979..d0e236ee3cc 100644
--- a/src/backend/utils/adt/xid8funcs.c
+++ b/src/backend/utils/adt/xid8funcs.c
@@ -36,6 +36,7 @@
#include "miscadmin.h"
#include "postmaster/postmaster.h"
#include "storage/lwlock.h"
+#include "storage/procarray.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/snapmgr.h"
@@ -677,29 +678,22 @@ pg_xact_status(PG_FUNCTION_ARGS)
{
Assert(TransactionIdIsValid(xid));
- if (TransactionIdIsCurrentTransactionId(xid))
+ /*
+ * Like when doing visiblity checks on a row, check whether the
+ * transaction is still in progress before looking into the CLOG.
+ * Otherwise we would incorrectly return "committed" for a transaction
+ * that is committing and has already updated the CLOG, but hasn't
+ * removed its XID from the proc array yet. (See comment on that race
+ * condition at the top of heapam_visibility.c)
+ */
+ if (TransactionIdIsInProgress(xid))
status = "in progress";
else if (TransactionIdDidCommit(xid))
status = "committed";
- else if (TransactionIdDidAbort(xid))
- status = "aborted";
else
{
- /*
- * The xact is not marked as either committed or aborted in clog.
- *
- * It could be a transaction that ended without updating clog or
- * writing an abort record due to a crash. We can safely assume
- * it's aborted if it isn't committed and is older than our
- * snapshot xmin.
- *
- * Otherwise it must be in-progress (or have been at the time we
- * checked commit/abort status).
- */
- if (TransactionIdPrecedes(xid, GetActiveSnapshot()->xmin))
- status = "aborted";
- else
- status = "in progress";
+ /* it must have aborted or crashed */
+ status = "aborted";
}
}
else