]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Handle interrupts while waiting on Append's async subplans
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Wed, 12 Mar 2025 18:53:09 +0000 (20:53 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Wed, 12 Mar 2025 18:53:16 +0000 (20:53 +0200)
We did not wake up on interrupts while waiting on async events on an
async-capable append node. For example, if you tried to cancel the
query, nothing would happen until one of the async subplans becomes
readable. To fix, add WL_LATCH_SET to the WaitEventSet.

Backpatch down to v14 where async Append execution was introduced.

Discussion: https://www.postgresql.org/message-id/37a40570-f558-40d3-b5ea-5c2079b3b30b@iki.fi

src/backend/executor/nodeAppend.c

index ca0f54d676f4a67d5cac42524bd149e62b9eacf5..6d5bee668c4373d77818fd84e55af583630b2db7 100644 (file)
@@ -1016,7 +1016,7 @@ ExecAppendAsyncRequest(AppendState *node, TupleTableSlot **result)
 static void
 ExecAppendAsyncEventWait(AppendState *node)
 {
-       int                     nevents = node->as_nasyncplans + 1;
+       int                     nevents = node->as_nasyncplans + 2;
        long            timeout = node->as_syncdone ? -1 : 0;
        WaitEvent       occurred_event[EVENT_BUFFER_SIZE];
        int                     noccurred;
@@ -1041,8 +1041,8 @@ ExecAppendAsyncEventWait(AppendState *node)
        }
 
        /*
-        * No need for further processing if there are no configured events other
-        * than the postmaster death event.
+        * No need for further processing if none of the subplans configured any
+        * events.
         */
        if (GetNumRegisteredWaitEvents(node->as_eventset) == 1)
        {
@@ -1051,6 +1051,21 @@ ExecAppendAsyncEventWait(AppendState *node)
                return;
        }
 
+       /*
+        * Add the process latch to the set, so that we wake up to process the
+        * standard interrupts with CHECK_FOR_INTERRUPTS().
+        *
+        * NOTE: For historical reasons, it's important that this is added to the
+        * WaitEventSet after the ExecAsyncConfigureWait() calls.  Namely,
+        * postgres_fdw calls "GetNumRegisteredWaitEvents(set) == 1" to check if
+        * any other events are in the set.  That's a poor design, it's
+        * questionable for postgres_fdw to be doing that in the first place, but
+        * we cannot change it now.  The pattern has possibly been copied to other
+        * extensions too.
+        */
+       AddWaitEventToSet(node->as_eventset, WL_LATCH_SET, PGINVALID_SOCKET,
+                                         MyLatch, NULL);
+
        /* Return at most EVENT_BUFFER_SIZE events in one call. */
        if (nevents > EVENT_BUFFER_SIZE)
                nevents = EVENT_BUFFER_SIZE;
@@ -1092,6 +1107,13 @@ ExecAppendAsyncEventWait(AppendState *node)
                                ExecAsyncNotify(areq);
                        }
                }
+
+               /* Handle standard interrupts */
+               if ((w->events & WL_LATCH_SET) != 0)
+               {
+                       ResetLatch(MyLatch);
+                       CHECK_FOR_INTERRUPTS();
+               }
        }
 }