Commit dcfff74f authored by Alvaro Herrera's avatar Alvaro Herrera

Restore lock level to update statusFlags

Reverts 27838981 (some comments are kept).  Per discussion, it does
not seem safe to relax the lock level used for this; in order for it to
be safe, there would have to be memory barriers between the point we set
the flag and the point we set the trasaction Xid, which perhaps would
not be so bad; but there would also have to be barriers at the readers'
side, which from a performance perspective might be bad.

Now maybe this analysis is wrong and it *is* safe for some reason, but
proof of that is not trivial.

Discussion: https://postgr.es/m/20201118190928.vnztes7c2sldu43a@alap3.anarazel.de
parent 9fbc3f31
...@@ -1712,13 +1712,6 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) ...@@ -1712,13 +1712,6 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
/* Begin a transaction for vacuuming this relation */ /* Begin a transaction for vacuuming this relation */
StartTransactionCommand(); StartTransactionCommand();
/*
* Need to acquire a snapshot to prevent pg_subtrans from being truncated,
* cutoff xids in local memory wrapping around, and to have updated xmin
* horizons.
*/
PushActiveSnapshot(GetTransactionSnapshot());
if (!(params->options & VACOPT_FULL)) if (!(params->options & VACOPT_FULL))
{ {
/* /*
...@@ -1739,9 +1732,11 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) ...@@ -1739,9 +1732,11 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
* Note: these flags remain set until CommitTransaction or * Note: these flags remain set until CommitTransaction or
* AbortTransaction. We don't want to clear them until we reset * AbortTransaction. We don't want to clear them until we reset
* MyProc->xid/xmin, otherwise GetOldestNonRemovableTransactionId() * MyProc->xid/xmin, otherwise GetOldestNonRemovableTransactionId()
* might appear to go backwards, which is probably Not Good. * might appear to go backwards, which is probably Not Good. (We also
* set PROC_IN_VACUUM *before* taking our own snapshot, so that our
* xmin doesn't become visible ahead of setting the flag.)
*/ */
LWLockAcquire(ProcArrayLock, LW_SHARED); LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
MyProc->statusFlags |= PROC_IN_VACUUM; MyProc->statusFlags |= PROC_IN_VACUUM;
if (params->is_wraparound) if (params->is_wraparound)
MyProc->statusFlags |= PROC_VACUUM_FOR_WRAPAROUND; MyProc->statusFlags |= PROC_VACUUM_FOR_WRAPAROUND;
...@@ -1749,6 +1744,13 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) ...@@ -1749,6 +1744,13 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
LWLockRelease(ProcArrayLock); LWLockRelease(ProcArrayLock);
} }
/*
* Need to acquire a snapshot to prevent pg_subtrans from being truncated,
* cutoff xids in local memory wrapping around, and to have updated xmin
* horizons.
*/
PushActiveSnapshot(GetTransactionSnapshot());
/* /*
* Check for user-requested abort. Note we want this to be inside a * Check for user-requested abort. Note we want this to be inside a
* transaction, so xact.c doesn't issue useless WARNING. * transaction, so xact.c doesn't issue useless WARNING.
......
...@@ -181,7 +181,7 @@ StartupDecodingContext(List *output_plugin_options, ...@@ -181,7 +181,7 @@ StartupDecodingContext(List *output_plugin_options,
*/ */
if (!IsTransactionOrTransactionBlock()) if (!IsTransactionOrTransactionBlock())
{ {
LWLockAcquire(ProcArrayLock, LW_SHARED); LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
MyProc->statusFlags |= PROC_IN_LOGICAL_DECODING; MyProc->statusFlags |= PROC_IN_LOGICAL_DECODING;
ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags; ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags;
LWLockRelease(ProcArrayLock); LWLockRelease(ProcArrayLock);
......
...@@ -662,10 +662,8 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid) ...@@ -662,10 +662,8 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
/* avoid unnecessarily dirtying shared cachelines */ /* avoid unnecessarily dirtying shared cachelines */
if (proc->statusFlags & PROC_VACUUM_STATE_MASK) if (proc->statusFlags & PROC_VACUUM_STATE_MASK)
{ {
/* Only safe to change my own flags with just share lock */
Assert(proc == MyProc);
Assert(!LWLockHeldByMe(ProcArrayLock)); Assert(!LWLockHeldByMe(ProcArrayLock));
LWLockAcquire(ProcArrayLock, LW_SHARED); LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
Assert(proc->statusFlags == ProcGlobal->statusFlags[proc->pgxactoff]); Assert(proc->statusFlags == ProcGlobal->statusFlags[proc->pgxactoff]);
proc->statusFlags &= ~PROC_VACUUM_STATE_MASK; proc->statusFlags &= ~PROC_VACUUM_STATE_MASK;
ProcGlobal->statusFlags[proc->pgxactoff] = proc->statusFlags; ProcGlobal->statusFlags[proc->pgxactoff] = proc->statusFlags;
...@@ -685,8 +683,8 @@ ProcArrayEndTransactionInternal(PGPROC *proc, TransactionId latestXid) ...@@ -685,8 +683,8 @@ ProcArrayEndTransactionInternal(PGPROC *proc, TransactionId latestXid)
size_t pgxactoff = proc->pgxactoff; size_t pgxactoff = proc->pgxactoff;
/* /*
* Note: we need exclusive lock here because we're going to * Note: we need exclusive lock here because we're going to change other
* change other processes' PGPROC entries. * processes' PGPROC entries.
*/ */
Assert(LWLockHeldByMeInMode(ProcArrayLock, LW_EXCLUSIVE)); Assert(LWLockHeldByMeInMode(ProcArrayLock, LW_EXCLUSIVE));
Assert(TransactionIdIsValid(ProcGlobal->xids[pgxactoff])); Assert(TransactionIdIsValid(ProcGlobal->xids[pgxactoff]));
......
...@@ -102,9 +102,9 @@ typedef enum ...@@ -102,9 +102,9 @@ typedef enum
* but its myProcLocks[] lists are valid. * but its myProcLocks[] lists are valid.
* *
* We allow many fields of this struct to be accessed without locks, such as * 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 * delayChkpt and isBackgroundWorker. However, keep in mind that writing
* (see below) requires holding ProcArrayLock or XidGenLock in at least shared * mirrored ones (see below) requires holding ProcArrayLock or XidGenLock in
* mode, so that pgxactoff does not change concurrently. * at least shared mode, so that pgxactoff does not change concurrently.
* *
* Mirrored fields: * Mirrored fields:
* *
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment