Make XactLockTableWait() and ConditionalXactLockTableWait() interruptable more.
authorFujii Masao <fujii@postgresql.org>
Fri, 30 May 2025 15:08:40 +0000 (00:08 +0900)
committerFujii Masao <fujii@postgresql.org>
Fri, 30 May 2025 15:08:40 +0000 (00:08 +0900)
Previously, XactLockTableWait() and ConditionalXactLockTableWait() could enter
a non-interruptible loop when they successfully acquired a lock on a transaction
but the transaction still appeared to be running. Since this loop continued
until the transaction completed, it could result in long, uninterruptible waits.

Although this scenario is generally unlikely since XactLockTableWait() and
ConditionalXactLockTableWait() can basically acquire a transaction lock
only when the transaction is not running, it can occur in a hot standby.
In such cases, the transaction may still appear active due to
the KnownAssignedXids list, even while no lock on the transaction exists.
For example, this situation can happen when creating a logical replication
slot on a standby.

The cause of the non-interruptible loop was the absence of CHECK_FOR_INTERRUPTS()
within it. This commit adds CHECK_FOR_INTERRUPTS() to the loop in both functions,
ensuring they can be interrupted safely.

Back-patch to all supported branches.

Author: Kevin K Biju <kevinkbiju@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/CAM45KeELdjhS-rGuvN=ZLJ_asvZACucZ9LZWVzH7bGcD12DDwg@mail.gmail.com
Backpatch-through: 13

src/backend/storage/lmgr/lmgr.c

index f50962983c37b8f24f974c043b19426b7d39c8c0..3f6bf70bd3c24fc5f694a17dacd26d01533bd7bc 100644 (file)
@@ -717,7 +717,10 @@ XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid,
         * through, to avoid slowing down the normal case.)
         */
        if (!first)
+       {
+           CHECK_FOR_INTERRUPTS();
            pg_usleep(1000L);
+       }
        first = false;
        xid = SubTransGetTopmostTransaction(xid);
    }
@@ -757,7 +760,10 @@ ConditionalXactLockTableWait(TransactionId xid, bool logLockFailure)
 
        /* See XactLockTableWait about this case */
        if (!first)
+       {
+           CHECK_FOR_INTERRUPTS();
            pg_usleep(1000L);
+       }
        first = false;
        xid = SubTransGetTopmostTransaction(xid);
    }