Move interrupt checking from ExecProcNode() to executor nodes.
authorAndres Freund <andres@anarazel.de>
Wed, 26 Jul 2017 00:37:17 +0000 (17:37 -0700)
committerAndres Freund <andres@anarazel.de>
Sun, 30 Jul 2017 23:06:42 +0000 (16:06 -0700)
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/22833.1490390175@sss.pgh.pa.us

29 files changed:
src/backend/executor/execProcnode.c
src/backend/executor/nodeAgg.c
src/backend/executor/nodeAppend.c
src/backend/executor/nodeBitmapHeapscan.c
src/backend/executor/nodeCustom.c
src/backend/executor/nodeGather.c
src/backend/executor/nodeGatherMerge.c
src/backend/executor/nodeGroup.c
src/backend/executor/nodeHash.c
src/backend/executor/nodeHashjoin.c
src/backend/executor/nodeIndexonlyscan.c
src/backend/executor/nodeIndexscan.c
src/backend/executor/nodeLimit.c
src/backend/executor/nodeLockRows.c
src/backend/executor/nodeMaterial.c
src/backend/executor/nodeMergeAppend.c
src/backend/executor/nodeMergejoin.c
src/backend/executor/nodeModifyTable.c
src/backend/executor/nodeNestloop.c
src/backend/executor/nodeProjectSet.c
src/backend/executor/nodeRecursiveunion.c
src/backend/executor/nodeResult.c
src/backend/executor/nodeSetOp.c
src/backend/executor/nodeSort.c
src/backend/executor/nodeSubplan.c
src/backend/executor/nodeTableFuncscan.c
src/backend/executor/nodeTidscan.c
src/backend/executor/nodeUnique.c
src/backend/executor/nodeWindowAgg.c

index 294ad2cff99adb05d63d52bc5732b081789d6854..20fd9f822ed29277b169e48d8ab0450b1848d8db 100644 (file)
@@ -399,8 +399,6 @@ ExecProcNode(PlanState *node)
 {
    TupleTableSlot *result;
 
-   CHECK_FOR_INTERRUPTS();
-
    if (node->chgParam != NULL) /* something changed */
        ExecReScan(node);       /* let ReScan handle this */
 
index de9a18e71c3b75905e3d19d41499b2f9501b0d48..377916dae75e27b2d099048c5b0a74dfb4f17c1e 100644 (file)
@@ -677,6 +677,8 @@ fetch_input_tuple(AggState *aggstate)
 
    if (aggstate->sort_in)
    {
+       /* make sure we check for interrupts in either path through here */
+       CHECK_FOR_INTERRUPTS();
        if (!tuplesort_gettupleslot(aggstate->sort_in, true, false,
                                    aggstate->sort_slot, NULL))
            return NULL;
@@ -1414,6 +1416,8 @@ process_ordered_aggregate_multi(AggState *aggstate,
    while (tuplesort_gettupleslot(pertrans->sortstates[aggstate->current_set],
                                  true, true, slot1, &newAbbrevVal))
    {
+       CHECK_FOR_INTERRUPTS();
+
        /*
         * Extract the first numTransInputs columns as datums to pass to the
         * transfn.  (This will help execTuplesMatch too, so we do it
@@ -2100,6 +2104,8 @@ ExecAgg(AggState *node)
 {
    TupleTableSlot *result = NULL;
 
+   CHECK_FOR_INTERRUPTS();
+
    if (!node->agg_done)
    {
        /* Dispatch based on strategy */
@@ -2563,6 +2569,8 @@ agg_retrieve_hash_table(AggState *aggstate)
        TupleTableSlot *hashslot = perhash->hashslot;
        int         i;
 
+       CHECK_FOR_INTERRUPTS();
+
        /*
         * Find the next entry in the hash table
         */
index aae5e3fa63c9f6e574121bf76739b5764351b9c7..58045e05e5d28aac5a758d3c8c3f2980f0123da9 100644 (file)
@@ -59,6 +59,7 @@
 
 #include "executor/execdebug.h"
 #include "executor/nodeAppend.h"
+#include "miscadmin.h"
 
 static bool exec_append_initialize_next(AppendState *appendstate);
 
@@ -204,6 +205,8 @@ ExecAppend(AppendState *node)
        PlanState  *subnode;
        TupleTableSlot *result;
 
+       CHECK_FOR_INTERRUPTS();
+
        /*
         * figure out which subplan we are currently processing
         */
index 7e0ba030b7fc019e8804c4a8dd4f1a20edbbf74d..cf109d5049f95d437aec944da0c41a29e147c2f8 100644 (file)
@@ -41,6 +41,7 @@
 #include "access/transam.h"
 #include "executor/execdebug.h"
 #include "executor/nodeBitmapHeapscan.h"
+#include "miscadmin.h"
 #include "pgstat.h"
 #include "storage/bufmgr.h"
 #include "storage/predicate.h"
@@ -192,6 +193,8 @@ BitmapHeapNext(BitmapHeapScanState *node)
        Page        dp;
        ItemId      lp;
 
+       CHECK_FOR_INTERRUPTS();
+
        /*
         * Get next page of results if needed
         */
index 69e27047f1c667182e079347a73ff4ffa1957ec4..fc15974a2d0d98b120375b88f4dd127bdafcfccf 100644 (file)
@@ -15,6 +15,7 @@
 #include "executor/nodeCustom.h"
 #include "nodes/execnodes.h"
 #include "nodes/plannodes.h"
+#include "miscadmin.h"
 #include "parser/parsetree.h"
 #include "utils/hsearch.h"
 #include "utils/memutils.h"
@@ -104,6 +105,8 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
 TupleTableSlot *
 ExecCustomScan(CustomScanState *node)
 {
+   CHECK_FOR_INTERRUPTS();
+
    Assert(node->methods->ExecCustomScan != NULL);
    return node->methods->ExecCustomScan(node);
 }
index f83cd584d7de2a66a1cc942eba087036a9354a6a..5dbe19c056d30737ba0c3ea4866daedb37275384 100644 (file)
@@ -128,6 +128,8 @@ ExecGather(GatherState *node)
    TupleTableSlot *slot;
    ExprContext *econtext;
 
+   CHECK_FOR_INTERRUPTS();
+
    /*
     * Initialize the parallel context and workers on first execution. We do
     * this on first execution rather than during node initialization, as it
@@ -247,6 +249,8 @@ gather_getnext(GatherState *gatherstate)
 
    while (gatherstate->reader != NULL || gatherstate->need_to_scan_locally)
    {
+       CHECK_FOR_INTERRUPTS();
+
        if (gatherstate->reader != NULL)
        {
            MemoryContext oldContext;
index 80ee1fc89b488a7f7b28906fb213b35112acaf90..0aff3798f75ccfb7d4aea28b9c7bd4297d32e8c8 100644 (file)
@@ -164,6 +164,8 @@ ExecGatherMerge(GatherMergeState *node)
    ExprContext *econtext;
    int         i;
 
+   CHECK_FOR_INTERRUPTS();
+
    /*
     * As with Gather, we don't launch workers until this node is actually
     * executed.
@@ -393,6 +395,8 @@ gather_merge_init(GatherMergeState *gm_state)
 reread:
    for (i = 0; i < nreaders + 1; i++)
    {
+       CHECK_FOR_INTERRUPTS();
+
        if (!gm_state->gm_tuple_buffers[i].done &&
            (TupIsNull(gm_state->gm_slots[i]) ||
             gm_state->gm_slots[i]->tts_isempty))
index af9ba4905eb24cc4b2ee80b271348f6ef4f05f21..fc5e0e59bcc1a9dcd1a6f3e38f1736555f74aed5 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "executor/executor.h"
 #include "executor/nodeGroup.h"
+#include "miscadmin.h"
 
 
 /*
@@ -40,6 +41,8 @@ ExecGroup(GroupState *node)
    TupleTableSlot *firsttupleslot;
    TupleTableSlot *outerslot;
 
+   CHECK_FOR_INTERRUPTS();
+
    /*
     * get state info from node
     */
index 075f4ed11c8566d665c8180e8064212e1a9fb7ef..fbeb562489cc1a906e134622096fc15b56842951 100644 (file)
@@ -810,6 +810,9 @@ ExecHashIncreaseNumBuckets(HashJoinTable hashtable)
            idx += MAXALIGN(HJTUPLE_OVERHEAD +
                            HJTUPLE_MINTUPLE(hashTuple)->t_len);
        }
+
+       /* allow this loop to be cancellable */
+       CHECK_FOR_INTERRUPTS();
    }
 }
 
@@ -1192,6 +1195,9 @@ ExecScanHashTableForUnmatched(HashJoinState *hjstate, ExprContext *econtext)
 
            hashTuple = hashTuple->next;
        }
+
+       /* allow this loop to be cancellable */
+       CHECK_FOR_INTERRUPTS();
    }
 
    /*
index 668ed871e19f835037bd7b14b7f2db0c8ccd06b5..252960c81c5990f116e34ea8d33bb136efad4f9b 100644 (file)
@@ -92,6 +92,14 @@ ExecHashJoin(HashJoinState *node)
     */
    for (;;)
    {
+       /*
+        * It's possible to iterate this loop many times before returning a
+        * tuple, in some pathological cases such as needing to move much of
+        * the current batch to a later batch.  So let's check for interrupts
+        * each time through.
+        */
+       CHECK_FOR_INTERRUPTS();
+
        switch (node->hj_JoinState)
        {
            case HJ_BUILD_HASHTABLE:
@@ -246,13 +254,6 @@ ExecHashJoin(HashJoinState *node)
 
            case HJ_SCAN_BUCKET:
 
-               /*
-                * We check for interrupts here because this corresponds to
-                * where we'd fetch a row from a child plan node in other join
-                * types.
-                */
-               CHECK_FOR_INTERRUPTS();
-
                /*
                 * Scan the selected hash bucket for matches to current outer
                 */
index 890e54416a528e287111080c8941ec19d8533d54..e2000764a4646dee16e8d9e3ca979b7f9c0f5678 100644 (file)
@@ -34,6 +34,7 @@
 #include "executor/execdebug.h"
 #include "executor/nodeIndexonlyscan.h"
 #include "executor/nodeIndexscan.h"
+#include "miscadmin.h"
 #include "storage/bufmgr.h"
 #include "storage/predicate.h"
 #include "utils/memutils.h"
@@ -117,6 +118,8 @@ IndexOnlyNext(IndexOnlyScanState *node)
    {
        HeapTuple   tuple = NULL;
 
+       CHECK_FOR_INTERRUPTS();
+
        /*
         * We can skip the heap fetch if the TID references a heap page on
         * which all tuples are known visible to everybody.  In any case,
index 75b10115f5281c25b3e37537e9c4dec54a1b8fbd..6704ede9955dd981e9974f1bab0a3cc572725686 100644 (file)
@@ -34,6 +34,7 @@
 #include "executor/execdebug.h"
 #include "executor/nodeIndexscan.h"
 #include "lib/pairingheap.h"
+#include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "utils/array.h"
@@ -131,6 +132,8 @@ IndexNext(IndexScanState *node)
     */
    while ((tuple = index_getnext(scandesc, direction)) != NULL)
    {
+       CHECK_FOR_INTERRUPTS();
+
        /*
         * Store the scanned tuple in the scan tuple slot of the scan state.
         * Note: we pass 'false' because tuples returned by amgetnext are
@@ -233,6 +236,8 @@ IndexNextWithReorder(IndexScanState *node)
 
    for (;;)
    {
+       CHECK_FOR_INTERRUPTS();
+
        /*
         * Check the reorder queue first.  If the topmost tuple in the queue
         * has an ORDER BY value smaller than (or equal to) the value last
@@ -299,6 +304,8 @@ next_indextuple:
            {
                /* Fails recheck, so drop it and loop back for another */
                InstrCountFiltered2(node, 1);
+               /* allow this loop to be cancellable */
+               CHECK_FOR_INTERRUPTS();
                goto next_indextuple;
            }
        }
index abd060d75f49bcd6b5773e79cd32a419fba13251..2ed3523257ff7eca13fe2abdff06531ff7a346ef 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "executor/executor.h"
 #include "executor/nodeLimit.h"
+#include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 
 static void recompute_limits(LimitState *node);
@@ -43,6 +44,8 @@ ExecLimit(LimitState *node)
    TupleTableSlot *slot;
    PlanState  *outerPlan;
 
+   CHECK_FOR_INTERRUPTS();
+
    /*
     * get information from the node
     */
index f519794cf3a358a0ad0c125a6228e2f88d1b83bb..dd4e2c5f2f118f0b30e930b31ab5a41f8085b27a 100644 (file)
@@ -26,6 +26,7 @@
 #include "executor/executor.h"
 #include "executor/nodeLockRows.h"
 #include "foreign/fdwapi.h"
+#include "miscadmin.h"
 #include "storage/bufmgr.h"
 #include "utils/rel.h"
 #include "utils/tqual.h"
@@ -44,6 +45,8 @@ ExecLockRows(LockRowsState *node)
    bool        epq_needed;
    ListCell   *lc;
 
+   CHECK_FOR_INTERRUPTS();
+
    /*
     * get information from the node
     */
index 32b7269cdafd78eb368e785db591e751b88e8158..3342949590920af44aff777b55927e8567de2cde 100644 (file)
@@ -45,6 +45,8 @@ ExecMaterial(MaterialState *node)
    bool        eof_tuplestore;
    TupleTableSlot *slot;
 
+   CHECK_FOR_INTERRUPTS();
+
    /*
     * get state info from node
     */
index fef83dbdbd314f276ef6b428127b82d96f212fc4..d41def13506caaf0a7a32544bc942e967e2c2698 100644 (file)
@@ -40,8 +40,8 @@
 
 #include "executor/execdebug.h"
 #include "executor/nodeMergeAppend.h"
-
 #include "lib/binaryheap.h"
+#include "miscadmin.h"
 
 /*
  * We have one slot for each item in the heap array.  We use SlotNumber
@@ -175,6 +175,8 @@ ExecMergeAppend(MergeAppendState *node)
    TupleTableSlot *result;
    SlotNumber  i;
 
+   CHECK_FOR_INTERRUPTS();
+
    if (!node->ms_initialized)
    {
        /*
index 6a145ee33a2a6f3494256da576ab4e24572ff293..324b61b8c0c2645fb51284483f5c33ca36bf68ef 100644 (file)
@@ -95,6 +95,7 @@
 #include "access/nbtree.h"
 #include "executor/execdebug.h"
 #include "executor/nodeMergejoin.h"
+#include "miscadmin.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 
@@ -610,6 +611,8 @@ ExecMergeJoin(MergeJoinState *node)
    bool        doFillOuter;
    bool        doFillInner;
 
+   CHECK_FOR_INTERRUPTS();
+
    /*
     * get information from node
     */
index 77ba15dd9005c620eac160651de3d3f5c134b79c..637a582e1ccd5042f6f5d0815b50e6c43013adbf 100644 (file)
@@ -1551,6 +1551,8 @@ ExecModifyTable(ModifyTableState *node)
    HeapTupleData oldtupdata;
    HeapTuple   oldtuple;
 
+   CHECK_FOR_INTERRUPTS();
+
    /*
     * This should NOT get called during EvalPlanQual; we should have passed a
     * subplan tree to EvalPlanQual, instead.  Use a runtime test not just
index 0065fe601ecb67fa98f86ec5a4d5ded3cb07c942..bedc374ef05ed1fad914a4d26aab6d439b38ba75 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "executor/execdebug.h"
 #include "executor/nodeNestloop.h"
+#include "miscadmin.h"
 #include "utils/memutils.h"
 
 
@@ -69,6 +70,8 @@ ExecNestLoop(NestLoopState *node)
    ExprContext *econtext;
    ListCell   *lc;
 
+   CHECK_FOR_INTERRUPTS();
+
    /*
     * get information from the node
     */
index 01048cc8268e0b59239e2a60163f90d7f8ba8327..3b69c7adeea64bf3d69cdc2ee39eab08d8220fd5 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "executor/executor.h"
 #include "executor/nodeProjectSet.h"
+#include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/memutils.h"
 
@@ -46,6 +47,8 @@ ExecProjectSet(ProjectSetState *node)
    PlanState  *outerPlan;
    ExprContext *econtext;
 
+   CHECK_FOR_INTERRUPTS();
+
    econtext = node->ps.ps_ExprContext;
 
    /*
index fc1c00d68f3c86f5f023bc4d71c56d3e59950151..2802fffa2b6ab36c97be8dcc6e3761484b8c8852 100644 (file)
@@ -75,6 +75,8 @@ ExecRecursiveUnion(RecursiveUnionState *node)
    TupleTableSlot *slot;
    bool        isnew;
 
+   CHECK_FOR_INTERRUPTS();
+
    /* 1. Evaluate non-recursive term */
    if (!node->recursing)
    {
index a753a53419183cefebf5c3e0ed9fe6a9f8e8ac37..f007f46784fe0ca39e14a506f0360cabc32a9bb5 100644 (file)
@@ -47,6 +47,7 @@
 
 #include "executor/executor.h"
 #include "executor/nodeResult.h"
+#include "miscadmin.h"
 #include "utils/memutils.h"
 
 
@@ -70,6 +71,8 @@ ExecResult(ResultState *node)
    PlanState  *outerPlan;
    ExprContext *econtext;
 
+   CHECK_FOR_INTERRUPTS();
+
    econtext = node->ps.ps_ExprContext;
 
    /*
index 9c7812e519a3a012773398da520d06dfe6d0087c..56c5643f175d6125671a5023ae84dd460599bece 100644 (file)
@@ -47,6 +47,7 @@
 #include "access/htup_details.h"
 #include "executor/executor.h"
 #include "executor/nodeSetOp.h"
+#include "miscadmin.h"
 #include "utils/memutils.h"
 
 
@@ -185,6 +186,8 @@ ExecSetOp(SetOpState *node)
    SetOp      *plannode = (SetOp *) node->ps.plan;
    TupleTableSlot *resultTupleSlot = node->ps.ps_ResultTupleSlot;
 
+   CHECK_FOR_INTERRUPTS();
+
    /*
     * If the previously-returned tuple needs to be returned more than once,
     * keep returning it.
@@ -428,6 +431,8 @@ setop_retrieve_hash_table(SetOpState *setopstate)
     */
    while (!setopstate->setop_done)
    {
+       CHECK_FOR_INTERRUPTS();
+
        /*
         * Find the next entry in the hash table
         */
index 924b458df87f602904cb993824c1c8f0773de978..799a4e92042f35cf943a5f2d802181055936e18e 100644 (file)
@@ -43,6 +43,8 @@ ExecSort(SortState *node)
    Tuplesortstate *tuplesortstate;
    TupleTableSlot *slot;
 
+   CHECK_FOR_INTERRUPTS();
+
    /*
     * get state info from node
     */
index e8fa4c8547ce36d2a4f602ff7fa18581362f8ad5..fe10e809dfb8859fea0da273f22d5b7df130f11a 100644 (file)
@@ -33,6 +33,7 @@
 #include "executor/executor.h"
 #include "executor/nodeSubplan.h"
 #include "nodes/makefuncs.h"
+#include "miscadmin.h"
 #include "optimizer/clauses.h"
 #include "utils/array.h"
 #include "utils/lsyscache.h"
@@ -65,6 +66,8 @@ ExecSubPlan(SubPlanState *node,
 {
    SubPlan    *subplan = node->subplan;
 
+   CHECK_FOR_INTERRUPTS();
+
    /* Set non-null as default */
    *isNull = false;
 
@@ -618,6 +621,8 @@ findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
    InitTupleHashIterator(hashtable, &hashiter);
    while ((entry = ScanTupleHashTable(hashtable, &hashiter)) != NULL)
    {
+       CHECK_FOR_INTERRUPTS();
+
        ExecStoreMinimalTuple(entry->firstTuple, hashtable->tableslot, false);
        if (!execTuplesUnequal(slot, hashtable->tableslot,
                               numCols, keyColIdx,
index bb016ec8f602899c275a47c8efec17d59ebe4dfe..2859363fe2c95fbfabe4923fc72901b2a8b1c127 100644 (file)
@@ -440,6 +440,8 @@ tfuncLoadRows(TableFuncScanState *tstate, ExprContext *econtext)
        ListCell   *cell = list_head(tstate->coldefexprs);
        int         colno;
 
+       CHECK_FOR_INTERRUPTS();
+
        ExecClearTuple(tstate->ss.ss_ScanTupleSlot);
 
        /*
index 96af2d21d9dfb7cf22fb20bda9a96bcc062d5891..c122473bdf882df598c7deb8609a66f0d912c328 100644 (file)
@@ -26,6 +26,7 @@
 #include "catalog/pg_type.h"
 #include "executor/execdebug.h"
 #include "executor/nodeTidscan.h"
+#include "miscadmin.h"
 #include "optimizer/clauses.h"
 #include "storage/bufmgr.h"
 #include "utils/array.h"
@@ -400,6 +401,8 @@ TidNext(TidScanState *node)
            node->tss_TidPtr--;
        else
            node->tss_TidPtr++;
+
+       CHECK_FOR_INTERRUPTS();
    }
 
    /*
index 28cc1e90f8fdda662840ac60505fb88484dfab88..db78c88368b70b959dbf0b157b05b03897b89313 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "executor/executor.h"
 #include "executor/nodeUnique.h"
+#include "miscadmin.h"
 #include "utils/memutils.h"
 
 
@@ -50,6 +51,8 @@ ExecUnique(UniqueState *node)
    TupleTableSlot *slot;
    PlanState  *outerPlan;
 
+   CHECK_FOR_INTERRUPTS();
+
    /*
     * get information from the node
     */
index 8f13fe0c7324f4a631aa8549b1a8105a627b86bb..9da35ac506bd2e0fcfcdc5af2292dd545e585ad7 100644 (file)
@@ -1594,6 +1594,8 @@ ExecWindowAgg(WindowAggState *winstate)
    int         i;
    int         numfuncs;
 
+   CHECK_FOR_INTERRUPTS();
+
    if (winstate->all_done)
        return NULL;
 
@@ -2371,6 +2373,9 @@ window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
    WindowAggState *winstate = winobj->winstate;
    MemoryContext oldcontext;
 
+   /* often called repeatedly in a row */
+   CHECK_FOR_INTERRUPTS();
+
    /* Don't allow passing -1 to spool_tuples here */
    if (pos < 0)
        return false;