Acquire ProcArrayLock exclusively in ProcArrayClearTransaction.
authorAndres Freund <andres@anarazel.de>
Thu, 20 Aug 2020 01:19:52 +0000 (18:19 -0700)
committerAndres Freund <andres@anarazel.de>
Thu, 20 Aug 2020 01:24:33 +0000 (18:24 -0700)
This corrects an oversight by me in 20729324078, which made
ProcArrayClearTransaction() increment xactCompletionCount. That requires an
exclusive lock, obviously.

There's other approaches that avoid the exclusive acquisition, but given that a
2PC commit is fairly heavyweight, it doesn't seem worth doing so. I've not been
able to measure a performance difference, unsurprisingly.  I did add a
comment documenting that we could do so, should it ever become a bottleneck.

Reported-By: Tom Lane <tgl@sss.pgh.pa.us>
Author: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/1355915.1597794204@sss.pgh.pa.us

src/backend/storage/ipc/procarray.c

index 51f8099cad2ca43d7be1c5b5f66426d282fdbcb1..60b7a5db8e07a6edd8d94b55a041080f98d7e4a8 100644 (file)
@@ -840,13 +840,20 @@ ProcArrayClearTransaction(PGPROC *proc)
        size_t          pgxactoff;
 
        /*
-        * We can skip locking ProcArrayLock exclusively here, because this action
-        * does not actually change anyone's view of the set of running XIDs: our
-        * entry is duplicate with the gxact that has already been inserted into
-        * the ProcArray. But need it in shared mode for pgproc->pgxactoff to stay
-        * the same.
+        * Currently we need to lock ProcArrayLock exclusively here, as we
+        * increment xactCompletionCount below. We also need it at least in shared
+        * mode for pgproc->pgxactoff to stay the same below.
+        *
+        * We could however, as this action does not actually change anyone's view
+        * of the set of running XIDs (our entry is duplicate with the gxact that
+        * has already been inserted into the ProcArray), lower the lock level to
+        * shared if we were to make xactCompletionCount an atomic variable. But
+        * that doesn't seem worth it currently, as a 2PC commit is heavyweight
+        * enough for this not to be the bottleneck.  If it ever becomes a
+        * bottleneck it may also be worth considering to combine this with the
+        * subsequent ProcArrayRemove()
         */
-       LWLockAcquire(ProcArrayLock, LW_SHARED);
+       LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
 
        pgxactoff = proc->pgxactoff;