diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index d89ba3031f9..395e75f768f 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -1741,7 +1741,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) * MyProc->xid/xmin, otherwise GetOldestNonRemovableTransactionId() * might appear to go backwards, which is probably Not Good. */ - LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + LWLockAcquire(ProcArrayLock, LW_SHARED); MyProc->statusFlags |= PROC_IN_VACUUM; if (params->is_wraparound) MyProc->statusFlags |= PROC_VACUUM_FOR_WRAPAROUND; diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c index f1f4df7d70f..4324e326565 100644 --- a/src/backend/replication/logical/logical.c +++ b/src/backend/replication/logical/logical.c @@ -181,7 +181,7 @@ StartupDecodingContext(List *output_plugin_options, */ if (!IsTransactionOrTransactionBlock()) { - LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + LWLockAcquire(ProcArrayLock, LW_SHARED); MyProc->statusFlags |= PROC_IN_LOGICAL_DECODING; ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags; LWLockRelease(ProcArrayLock); diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c index 5ed955ba0bf..9c7cf13d4d9 100644 --- a/src/backend/replication/slot.c +++ b/src/backend/replication/slot.c @@ -527,7 +527,7 @@ ReplicationSlotRelease(void) MyReplicationSlot = NULL; /* might not have been set when we've been a plain slot */ - LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + LWLockAcquire(ProcArrayLock, LW_SHARED); MyProc->statusFlags &= ~PROC_IN_LOGICAL_DECODING; ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags; LWLockRelease(ProcArrayLock); diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index e2cb6e990d1..94edb24b22d 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -662,6 +662,8 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid) /* avoid unnecessarily dirtying shared cachelines */ if (proc->statusFlags & PROC_VACUUM_STATE_MASK) { + /* Only safe to change my own flags with just share lock */ + Assert(proc == MyProc); Assert(!LWLockHeldByMe(ProcArrayLock)); LWLockAcquire(ProcArrayLock, LW_SHARED); Assert(proc->statusFlags == ProcGlobal->statusFlags[proc->pgxactoff]); @@ -682,7 +684,11 @@ ProcArrayEndTransactionInternal(PGPROC *proc, TransactionId latestXid) { size_t pgxactoff = proc->pgxactoff; - Assert(LWLockHeldByMe(ProcArrayLock)); + /* + * Note: we need exclusive lock here because we're going to + * change other processes' PGPROC entries. + */ + Assert(LWLockHeldByMeInMode(ProcArrayLock, LW_EXCLUSIVE)); Assert(TransactionIdIsValid(ProcGlobal->xids[pgxactoff])); Assert(ProcGlobal->xids[pgxactoff] == proc->xid); diff --git a/src/backend/storage/lmgr/deadlock.c b/src/backend/storage/lmgr/deadlock.c index cb7a8f0fd28..f7ed6968ca9 100644 --- a/src/backend/storage/lmgr/deadlock.c +++ b/src/backend/storage/lmgr/deadlock.c @@ -623,7 +623,7 @@ FindLockCycleRecurseMember(PGPROC *checkProc, * because that flag is set at process start and never * reset. There is logic elsewhere to avoid canceling an * autovacuum that is working to prevent XID wraparound - * problems (which needs to read a different vacuumFlag + * problems (which needs to read a different statusFlags * bit), but we don't do that here to avoid grabbing * ProcArrayLock. */ diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 1067f58f51b..00bb244340a 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -98,6 +98,11 @@ typedef enum * The semaphore and lock-activity fields in a prepared-xact PGPROC are unused, * but its myProcLocks[] lists are valid. * + * We allow many fields of this struct to be accessed without locks, such as + * statusFlags or delayChkpt. However, keep in mind that writing mirrored ones + * (see below) requires holding ProcArrayLock or XidGenLock in at least shared + * mode, so that pgxactoff does not change concurrently. + * * Mirrored fields: * * Some fields in PGPROC (see "mirrored in ..." comment) are mirrored into an