From d2fb076bec06dafd6922669eed826191c01fa9c6 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Wed, 12 Mar 2025 20:53:09 +0200 Subject: [PATCH] Handle interrupts while waiting on Append's async subplans 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 | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c index 241b3aaa146..e48a547e237 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -1020,7 +1020,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; @@ -1047,13 +1047,28 @@ ExecAppendAsyncEventWait(AppendState *node) } /* - * If there are no configured events other than the postmaster death - * event, we don't need to wait or poll. + * No need for further processing if none of the subplans configured + * any events. */ if (GetNumRegisteredWaitEvents(node->as_eventset) == 1) noccurred = 0; else { + /* + * 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; @@ -1102,6 +1117,13 @@ ExecAppendAsyncEventWait(AppendState *node) ExecAsyncNotify(areq); } } + + /* Handle standard interrupts */ + if ((w->events & WL_LATCH_SET) != 0) + { + ResetLatch(MyLatch); + CHECK_FOR_INTERRUPTS(); + } } } -- 2.39.5