1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-29 10:41:53 +03:00

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
This commit is contained in:
Heikki Linnakangas
2025-03-12 20:53:09 +02:00
parent ae0be2f0bd
commit d4d34c08c7

View File

@ -1007,7 +1007,7 @@ ExecAppendAsyncRequest(AppendState *node, TupleTableSlot **result)
static void static void
ExecAppendAsyncEventWait(AppendState *node) ExecAppendAsyncEventWait(AppendState *node)
{ {
int nevents = node->as_nasyncplans + 1; int nevents = node->as_nasyncplans + 2;
long timeout = node->as_syncdone ? -1 : 0; long timeout = node->as_syncdone ? -1 : 0;
WaitEvent occurred_event[EVENT_BUFFER_SIZE]; WaitEvent occurred_event[EVENT_BUFFER_SIZE];
int noccurred; int noccurred;
@ -1034,13 +1034,28 @@ ExecAppendAsyncEventWait(AppendState *node)
} }
/* /*
* If there are no configured events other than the postmaster death * No need for further processing if none of the subplans configured
* event, we don't need to wait or poll. * any events.
*/ */
if (GetNumRegisteredWaitEvents(node->as_eventset) == 1) if (GetNumRegisteredWaitEvents(node->as_eventset) == 1)
noccurred = 0; noccurred = 0;
else 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. */ /* Return at most EVENT_BUFFER_SIZE events in one call. */
if (nevents > EVENT_BUFFER_SIZE) if (nevents > EVENT_BUFFER_SIZE)
nevents = EVENT_BUFFER_SIZE; nevents = EVENT_BUFFER_SIZE;
@ -1089,6 +1104,13 @@ ExecAppendAsyncEventWait(AppendState *node)
ExecAsyncNotify(areq); ExecAsyncNotify(areq);
} }
} }
/* Handle standard interrupts */
if ((w->events & WL_LATCH_SET) != 0)
{
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
}
} }
} }