Fix race condition in transaction timeout TAP tests
authorAlexander Korotkov <akorotkov@postgresql.org>
Fri, 15 Mar 2024 12:31:25 +0000 (14:31 +0200)
committerAlexander Korotkov <akorotkov@postgresql.org>
Fri, 15 Mar 2024 12:38:22 +0000 (14:38 +0200)
The interruption handler within the injection point can get stuck in an
infinite loop while handling transaction timeout. To avoid this situation
we reset the timeout flag before invoking the injection point.

Author: Alexander Korotkov
Reviewed-by: Andrey Borodin
Discussion: https://postgr.es/m/ZfPchPC6oNN71X2J%40paquier.xyz

src/backend/tcop/postgres.c

index 7ac623019bc31cef84ed7663e38d37bcd5090d89..fd4199a098366472bc6d3dffdce29903595e576b 100644 (file)
@@ -3409,8 +3409,10 @@ ProcessInterrupts(void)
        /*
         * If the GUC has been reset to zero, ignore the signal.  This is
         * important because the GUC update itself won't disable any pending
-        * interrupt.
+        * interrupt.  We need to unset the flag before the injection point,
+        * otherwise we could loop in interrupts checking.
         */
+       IdleInTransactionSessionTimeoutPending = false;
        if (IdleInTransactionSessionTimeout > 0)
        {
            INJECTION_POINT("idle-in-transaction-session-timeout");
@@ -3418,13 +3420,12 @@ ProcessInterrupts(void)
                    (errcode(ERRCODE_IDLE_IN_TRANSACTION_SESSION_TIMEOUT),
                     errmsg("terminating connection due to idle-in-transaction timeout")));
        }
-       else
-           IdleInTransactionSessionTimeoutPending = false;
    }
 
    if (TransactionTimeoutPending)
    {
        /* As above, ignore the signal if the GUC has been reset to zero. */
+       TransactionTimeoutPending = false;
        if (TransactionTimeout > 0)
        {
            INJECTION_POINT("transaction-timeout");
@@ -3432,13 +3433,12 @@ ProcessInterrupts(void)
                    (errcode(ERRCODE_TRANSACTION_TIMEOUT),
                     errmsg("terminating connection due to transaction timeout")));
        }
-       else
-           TransactionTimeoutPending = false;
    }
 
    if (IdleSessionTimeoutPending)
    {
        /* As above, ignore the signal if the GUC has been reset to zero. */
+       IdleSessionTimeoutPending = false;
        if (IdleSessionTimeout > 0)
        {
            INJECTION_POINT("idle-session-timeout");
@@ -3446,8 +3446,6 @@ ProcessInterrupts(void)
                    (errcode(ERRCODE_IDLE_SESSION_TIMEOUT),
                     errmsg("terminating connection due to idle-session timeout")));
        }
-       else
-           IdleSessionTimeoutPending = false;
    }
 
    /*