diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 85261379b1..b147f6482c 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -1132,7 +1132,7 @@ relation_open(Oid relationId, LOCKMODE lockmode) /* Make note that we've accessed a temporary relation */ if (RelationUsesLocalBuffers(r)) - MyXactAccessedTempRel = true; + MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPREL; pgstat_initstats(r); @@ -1178,7 +1178,7 @@ try_relation_open(Oid relationId, LOCKMODE lockmode) /* Make note that we've accessed a temporary relation */ if (RelationUsesLocalBuffers(r)) - MyXactAccessedTempRel = true; + MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPREL; pgstat_initstats(r); diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index f09941d0ec..4b4999fd7b 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -2065,11 +2065,15 @@ RecordTransactionCommitPrepared(TransactionId xid, /* See notes in RecordTransactionCommit */ MyPgXact->delayChkpt = true; - /* Emit the XLOG commit record */ + /* + * Emit the XLOG commit record. Note that we mark 2PC commits as potentially + * having AccessExclusiveLocks since we don't know whether or not they do. + */ recptr = XactLogCommitRecord(committs, nchildren, children, nrels, rels, ninvalmsgs, invalmsgs, initfileinval, false, + MyXactFlags | XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK, xid); @@ -2146,10 +2150,14 @@ RecordTransactionAbortPrepared(TransactionId xid, START_CRIT_SECTION(); - /* Emit the XLOG abort record */ + /* + * Emit the XLOG commit record. Note that we mark 2PC aborts as potentially + * having AccessExclusiveLocks since we don't know whether or not they do. + */ recptr = XactLogAbortRecord(GetCurrentTimestamp(), nchildren, children, nrels, rels, + MyXactFlags | XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK, xid); /* Always flush, since we're about to remove the 2PC state file */ diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 02e0779f32..c8751c697d 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -109,12 +109,13 @@ int nParallelCurrentXids = 0; TransactionId *ParallelCurrentXids; /* - * MyXactAccessedTempRel is set when a temporary relation is accessed. - * We don't allow PREPARE TRANSACTION in that case. (This is global - * so that it can be set from heapam.c.) + * Miscellaneous flag bits to record events which occur on the top level + * transaction. These flags are only persisted in MyXactFlags and are intended + * so we remember to do certain things later on in the transaction. This is + * globally accessible, so can be set from anywhere in the code that requires + * recording flags. */ -bool MyXactAccessedTempRel = false; - +int MyXactFlags; /* * transaction states - transaction state from server perspective @@ -1231,6 +1232,7 @@ RecordTransactionCommit(void) nchildren, children, nrels, rels, nmsgs, invalMessages, RelcacheInitFileInval, forceSyncCommit, + MyXactFlags, InvalidTransactionId /* plain commit */ ); if (replorigin) @@ -1583,7 +1585,7 @@ RecordTransactionAbort(bool isSubXact) XactLogAbortRecord(xact_time, nchildren, children, nrels, rels, - InvalidTransactionId); + MyXactFlags, InvalidTransactionId); /* * Report the latest async abort LSN, so that the WAL writer knows to @@ -1845,7 +1847,7 @@ StartTransaction(void) XactDeferrable = DefaultXactDeferrable; XactIsoLevel = DefaultXactIsoLevel; forceSyncCommit = false; - MyXactAccessedTempRel = false; + MyXactFlags = 0; /* * reinitialize within-transaction counters @@ -2260,7 +2262,7 @@ PrepareTransaction(void) * cases, such as a temp table created and dropped all within the * transaction. That seems to require much more bookkeeping though. */ - if (MyXactAccessedTempRel) + if ((MyXactFlags & XACT_FLAGS_ACCESSEDTEMPREL)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot PREPARE a transaction that has operated on temporary tables"))); @@ -5108,7 +5110,7 @@ XactLogCommitRecord(TimestampTz commit_time, int nrels, RelFileNode *rels, int nmsgs, SharedInvalidationMessage *msgs, bool relcacheInval, bool forceSync, - TransactionId twophase_xid) + int xactflags, TransactionId twophase_xid) { xl_xact_commit xlrec; xl_xact_xinfo xl_xinfo; @@ -5139,6 +5141,8 @@ XactLogCommitRecord(TimestampTz commit_time, xl_xinfo.xinfo |= XACT_COMPLETION_UPDATE_RELCACHE_FILE; if (forceSyncCommit) xl_xinfo.xinfo |= XACT_COMPLETION_FORCE_SYNC_COMMIT; + if ((xactflags & XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK)) + xl_xinfo.xinfo |= XACT_XINFO_HAS_AE_LOCKS; /* * Check if the caller would like to ask standbys for immediate feedback @@ -5251,7 +5255,7 @@ XLogRecPtr XactLogAbortRecord(TimestampTz abort_time, int nsubxacts, TransactionId *subxacts, int nrels, RelFileNode *rels, - TransactionId twophase_xid) + int xactflags, TransactionId twophase_xid) { xl_xact_abort xlrec; xl_xact_xinfo xl_xinfo; @@ -5276,6 +5280,9 @@ XactLogAbortRecord(TimestampTz abort_time, xlrec.xact_time = abort_time; + if ((xactflags & XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK)) + xl_xinfo.xinfo |= XACT_XINFO_HAS_AE_LOCKS; + if (nsubxacts > 0) { xl_xinfo.xinfo |= XACT_XINFO_HAS_SUBXACTS; @@ -5427,7 +5434,8 @@ xact_redo_commit(xl_xact_parsed_commit *parsed, * via their top-level xid only, so no need to provide subxact list, * which will save time when replaying commits. */ - StandbyReleaseLockTree(xid, 0, NULL); + if (parsed->xinfo & XACT_XINFO_HAS_AE_LOCKS) + StandbyReleaseLockTree(xid, 0, NULL); } if (parsed->xinfo & XACT_XINFO_HAS_ORIGIN) @@ -5563,7 +5571,8 @@ xact_redo_abort(xl_xact_parsed_abort *parsed, TransactionId xid) /* * Release locks, if any. There are no invalidations to send. */ - StandbyReleaseLockTree(xid, parsed->nsubxacts, parsed->subxacts); + if (parsed->xinfo & XACT_XINFO_HAS_AE_LOCKS) + StandbyReleaseLockTree(xid, parsed->nsubxacts, parsed->subxacts); } /* Make sure files supposed to be dropped are dropped */ diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 86329e5f9f..3b28e8c34f 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -12471,7 +12471,7 @@ PreCommit_on_commit_actions(void) * relations, we can skip truncating ON COMMIT DELETE ROWS * tables, as they must still be empty. */ - if (MyXactAccessedTempRel) + if ((MyXactFlags & XACT_FLAGS_ACCESSEDTEMPREL)) oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid); break; case ONCOMMIT_DROP: diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index 6259070722..7be8fd4a78 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -1063,6 +1063,7 @@ LogAccessExclusiveLock(Oid dbOid, Oid relOid) xlrec.relOid = relOid; LogAccessExclusiveLocks(1, &xlrec); + MyXactFlags |= XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK; } /* diff --git a/src/include/access/xact.h b/src/include/access/xact.h index e7d11913d1..5b37c05842 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -71,8 +71,27 @@ typedef enum /* Synchronous commit level */ extern int synchronous_commit; -/* Kluge for 2PC support */ -extern bool MyXactAccessedTempRel; +/* + * Miscellaneous flag bits to record events which occur on the top level + * transaction. These flags are only persisted in MyXactFlags and are intended + * so we remember to do certain things later in the transaction. This is + * globally accessible, so can be set from anywhere in the code which requires + * recording flags. + */ +extern int MyXactFlags; + +/* + * XACT_FLAGS_ACCESSEDTEMPREL - set when a temporary relation is accessed. We + * don't allow PREPARE TRANSACTION in that case. + */ +#define XACT_FLAGS_ACCESSEDTEMPREL (1U << 0) + +/* + * XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK - records whether the top level xact + * logged any Access Exclusive Locks. + */ +#define XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK (1U << 1) + /* * start- and end-of-transaction callbacks for dynamically loaded modules @@ -137,6 +156,7 @@ typedef void (*SubXactCallback) (SubXactEvent event, SubTransactionId mySubid, #define XACT_XINFO_HAS_INVALS (1U << 3) #define XACT_XINFO_HAS_TWOPHASE (1U << 4) #define XACT_XINFO_HAS_ORIGIN (1U << 5) +#define XACT_XINFO_HAS_AE_LOCKS (1U << 6) /* * Also stored in xinfo, these indicating a variety of additional actions that @@ -364,12 +384,13 @@ extern XLogRecPtr XactLogCommitRecord(TimestampTz commit_time, int nrels, RelFileNode *rels, int nmsgs, SharedInvalidationMessage *msgs, bool relcacheInval, bool forceSync, + int xactflags, TransactionId twophase_xid); extern XLogRecPtr XactLogAbortRecord(TimestampTz abort_time, int nsubxacts, TransactionId *subxacts, int nrels, RelFileNode *rels, - TransactionId twophase_xid); + int xactflags, TransactionId twophase_xid); extern void xact_redo(XLogReaderState *record); /* xactdesc.c */