aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/storage/ipc/standby.c29
-rw-r--r--src/backend/storage/lmgr/lock.c29
-rw-r--r--src/include/storage/standby.h1
3 files changed, 43 insertions, 16 deletions
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index 82da9261566..5e0d1d067e5 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -953,14 +953,6 @@ LogAccessExclusiveLock(Oid dbOid, Oid relOid)
{
xl_standby_lock xlrec;
- /*
- * Ensure that a TransactionId has been assigned to this transaction. We
- * don't actually need the xid yet but if we don't do this then
- * RecordTransactionCommit() and RecordTransactionAbort() will optimise
- * away the transaction completion record which recovery relies upon to
- * release locks. It's a hack, but for a corner case not worth adding code
- * for into the main commit path.
- */
xlrec.xid = GetTopTransactionId();
/*
@@ -973,3 +965,24 @@ LogAccessExclusiveLock(Oid dbOid, Oid relOid)
LogAccessExclusiveLocks(1, &xlrec);
}
+
+/*
+ * Prepare to log an AccessExclusiveLock, for use during LockAcquire()
+ */
+void
+LogAccessExclusiveLockPrepare(void)
+{
+ /*
+ * Ensure that a TransactionId has been assigned to this transaction,
+ * for two reasons, both related to lock release on the standby.
+ * First, we must assign an xid so that RecordTransactionCommit() and
+ * RecordTransactionAbort() do not optimise away the transaction
+ * completion record which recovery relies upon to release locks. It's
+ * a hack, but for a corner case not worth adding code for into the
+ * main commit path. Second, must must assign an xid before the lock
+ * is recorded in shared memory, otherwise a concurrently executing
+ * GetRunningTransactionLocks() might see a lock associated with an
+ * InvalidTransactionId which we later assert cannot happen.
+ */
+ (void) GetTopTransactionId();
+}
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 45cfbc07102..e7cf1cd7ad0 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -499,6 +499,7 @@ LockAcquireExtended(const LOCKTAG *locktag,
int partition;
LWLockId partitionLock;
int status;
+ bool log_lock = false;
if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
elog(ERROR, "unrecognized lock method: %d", lockmethodid);
@@ -580,6 +581,24 @@ LockAcquireExtended(const LOCKTAG *locktag,
}
/*
+ * Emit a WAL record if acquisition of this lock needs to be replayed in a
+ * standby server. Only AccessExclusiveLocks can conflict with lock types
+ * that read-only transactions can acquire in a standby server.
+ *
+ * Make sure this definition matches the one in GetRunningTransactionLocks().
+ *
+ * First we prepare to log, then after lock acquired we issue log record.
+ */
+ if (lockmode >= AccessExclusiveLock &&
+ locktag->locktag_type == LOCKTAG_RELATION &&
+ !RecoveryInProgress() &&
+ XLogStandbyInfoActive())
+ {
+ LogAccessExclusiveLockPrepare();
+ log_lock = true;
+ }
+
+ /*
* Otherwise we've got to mess with the shared lock table.
*/
hashcode = locallock->hashcode;
@@ -868,15 +887,9 @@ LockAcquireExtended(const LOCKTAG *locktag,
/*
* Emit a WAL record if acquisition of this lock need to be replayed in a
- * standby server. Only AccessExclusiveLocks can conflict with lock types
- * that read-only transactions can acquire in a standby server.
- *
- * Make sure this definition matches the one GetRunningTransactionLocks().
+ * standby server.
*/
- if (lockmode >= AccessExclusiveLock &&
- locktag->locktag_type == LOCKTAG_RELATION &&
- !RecoveryInProgress() &&
- XLogStandbyInfoActive())
+ if (log_lock)
{
/*
* Decode the locktag back to the original values, to avoid sending
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index 553415c2d3a..dec1d713233 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -109,6 +109,7 @@ typedef struct RunningTransactionsData
typedef RunningTransactionsData *RunningTransactions;
extern void LogAccessExclusiveLock(Oid dbOid, Oid relOid);
+extern void LogAccessExclusiveLockPrepare(void);
extern void LogStandbySnapshot(TransactionId *oldestActiveXid, TransactionId *nextXid);