Skip to content

Commit d47cfef

Browse files
committed
Move interrupt checking from ExecProcNode() to executor nodes.
In a followup commit ExecProcNode(), and especially the large switch it contains, will largely be replaced by a function pointer directly to the correct node. The node functions will then get invoked by a thin inline function wrapper. To avoid having to include miscadmin.h in headers - CHECK_FOR_INTERRUPTS() - move the interrupt checks into the individual executor routines. While looking through all executor nodes, I noticed a number of arguably missing interrupt checks, add these too. Author: Andres Freund, Tom Lane Reviewed-By: Tom Lane Discussion: https://postgr.es/m/[email protected]
1 parent 9dea962 commit d47cfef

29 files changed

+104
-10
lines changed

src/backend/executor/execProcnode.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,8 +399,6 @@ ExecProcNode(PlanState *node)
399399
{
400400
TupleTableSlot *result;
401401

402-
CHECK_FOR_INTERRUPTS();
403-
404402
if (node->chgParam != NULL) /* something changed */
405403
ExecReScan(node); /* let ReScan handle this */
406404

src/backend/executor/nodeAgg.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,8 @@ fetch_input_tuple(AggState *aggstate)
677677

678678
if (aggstate->sort_in)
679679
{
680+
/* make sure we check for interrupts in either path through here */
681+
CHECK_FOR_INTERRUPTS();
680682
if (!tuplesort_gettupleslot(aggstate->sort_in, true, false,
681683
aggstate->sort_slot, NULL))
682684
return NULL;
@@ -1414,6 +1416,8 @@ process_ordered_aggregate_multi(AggState *aggstate,
14141416
while (tuplesort_gettupleslot(pertrans->sortstates[aggstate->current_set],
14151417
true, true, slot1, &newAbbrevVal))
14161418
{
1419+
CHECK_FOR_INTERRUPTS();
1420+
14171421
/*
14181422
* Extract the first numTransInputs columns as datums to pass to the
14191423
* transfn. (This will help execTuplesMatch too, so we do it
@@ -2100,6 +2104,8 @@ ExecAgg(AggState *node)
21002104
{
21012105
TupleTableSlot *result = NULL;
21022106

2107+
CHECK_FOR_INTERRUPTS();
2108+
21032109
if (!node->agg_done)
21042110
{
21052111
/* Dispatch based on strategy */
@@ -2563,6 +2569,8 @@ agg_retrieve_hash_table(AggState *aggstate)
25632569
TupleTableSlot *hashslot = perhash->hashslot;
25642570
int i;
25652571

2572+
CHECK_FOR_INTERRUPTS();
2573+
25662574
/*
25672575
* Find the next entry in the hash table
25682576
*/

src/backend/executor/nodeAppend.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959

6060
#include "executor/execdebug.h"
6161
#include "executor/nodeAppend.h"
62+
#include "miscadmin.h"
6263

6364
static bool exec_append_initialize_next(AppendState *appendstate);
6465

@@ -204,6 +205,8 @@ ExecAppend(AppendState *node)
204205
PlanState *subnode;
205206
TupleTableSlot *result;
206207

208+
CHECK_FOR_INTERRUPTS();
209+
207210
/*
208211
* figure out which subplan we are currently processing
209212
*/

src/backend/executor/nodeBitmapHeapscan.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "access/transam.h"
4242
#include "executor/execdebug.h"
4343
#include "executor/nodeBitmapHeapscan.h"
44+
#include "miscadmin.h"
4445
#include "pgstat.h"
4546
#include "storage/bufmgr.h"
4647
#include "storage/predicate.h"
@@ -192,6 +193,8 @@ BitmapHeapNext(BitmapHeapScanState *node)
192193
Page dp;
193194
ItemId lp;
194195

196+
CHECK_FOR_INTERRUPTS();
197+
195198
/*
196199
* Get next page of results if needed
197200
*/

src/backend/executor/nodeCustom.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "executor/nodeCustom.h"
1616
#include "nodes/execnodes.h"
1717
#include "nodes/plannodes.h"
18+
#include "miscadmin.h"
1819
#include "parser/parsetree.h"
1920
#include "utils/hsearch.h"
2021
#include "utils/memutils.h"
@@ -104,6 +105,8 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
104105
TupleTableSlot *
105106
ExecCustomScan(CustomScanState *node)
106107
{
108+
CHECK_FOR_INTERRUPTS();
109+
107110
Assert(node->methods->ExecCustomScan != NULL);
108111
return node->methods->ExecCustomScan(node);
109112
}

src/backend/executor/nodeGather.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ ExecGather(GatherState *node)
128128
TupleTableSlot *slot;
129129
ExprContext *econtext;
130130

131+
CHECK_FOR_INTERRUPTS();
132+
131133
/*
132134
* Initialize the parallel context and workers on first execution. We do
133135
* this on first execution rather than during node initialization, as it
@@ -247,6 +249,8 @@ gather_getnext(GatherState *gatherstate)
247249

248250
while (gatherstate->reader != NULL || gatherstate->need_to_scan_locally)
249251
{
252+
CHECK_FOR_INTERRUPTS();
253+
250254
if (gatherstate->reader != NULL)
251255
{
252256
MemoryContext oldContext;

src/backend/executor/nodeGatherMerge.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ ExecGatherMerge(GatherMergeState *node)
164164
ExprContext *econtext;
165165
int i;
166166

167+
CHECK_FOR_INTERRUPTS();
168+
167169
/*
168170
* As with Gather, we don't launch workers until this node is actually
169171
* executed.
@@ -393,6 +395,8 @@ gather_merge_init(GatherMergeState *gm_state)
393395
reread:
394396
for (i = 0; i < nreaders + 1; i++)
395397
{
398+
CHECK_FOR_INTERRUPTS();
399+
396400
if (!gm_state->gm_tuple_buffers[i].done &&
397401
(TupIsNull(gm_state->gm_slots[i]) ||
398402
gm_state->gm_slots[i]->tts_isempty))

src/backend/executor/nodeGroup.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include "executor/executor.h"
2626
#include "executor/nodeGroup.h"
27+
#include "miscadmin.h"
2728

2829

2930
/*
@@ -40,6 +41,8 @@ ExecGroup(GroupState *node)
4041
TupleTableSlot *firsttupleslot;
4142
TupleTableSlot *outerslot;
4243

44+
CHECK_FOR_INTERRUPTS();
45+
4346
/*
4447
* get state info from node
4548
*/

src/backend/executor/nodeHash.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,9 @@ ExecHashIncreaseNumBuckets(HashJoinTable hashtable)
810810
idx += MAXALIGN(HJTUPLE_OVERHEAD +
811811
HJTUPLE_MINTUPLE(hashTuple)->t_len);
812812
}
813+
814+
/* allow this loop to be cancellable */
815+
CHECK_FOR_INTERRUPTS();
813816
}
814817
}
815818

@@ -1192,6 +1195,9 @@ ExecScanHashTableForUnmatched(HashJoinState *hjstate, ExprContext *econtext)
11921195

11931196
hashTuple = hashTuple->next;
11941197
}
1198+
1199+
/* allow this loop to be cancellable */
1200+
CHECK_FOR_INTERRUPTS();
11951201
}
11961202

11971203
/*

src/backend/executor/nodeHashjoin.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,14 @@ ExecHashJoin(HashJoinState *node)
9292
*/
9393
for (;;)
9494
{
95+
/*
96+
* It's possible to iterate this loop many times before returning a
97+
* tuple, in some pathological cases such as needing to move much of
98+
* the current batch to a later batch. So let's check for interrupts
99+
* each time through.
100+
*/
101+
CHECK_FOR_INTERRUPTS();
102+
95103
switch (node->hj_JoinState)
96104
{
97105
case HJ_BUILD_HASHTABLE:
@@ -246,13 +254,6 @@ ExecHashJoin(HashJoinState *node)
246254

247255
case HJ_SCAN_BUCKET:
248256

249-
/*
250-
* We check for interrupts here because this corresponds to
251-
* where we'd fetch a row from a child plan node in other join
252-
* types.
253-
*/
254-
CHECK_FOR_INTERRUPTS();
255-
256257
/*
257258
* Scan the selected hash bucket for matches to current outer
258259
*/

0 commit comments

Comments
 (0)