diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c index 8b3663b3c9d..eaed9fb5a97 100644 --- a/src/backend/executor/execProcnode.c +++ b/src/backend/executor/execProcnode.c @@ -752,6 +752,19 @@ ExecShutdownNode(PlanState *node) planstate_tree_walker(node, ExecShutdownNode, NULL); + /* + * Treat the node as running while we shut it down, but only if it's run + * at least once already. We don't expect much CPU consumption during + * node shutdown, but in the case of Gather or Gather Merge, we may shut + * down workers at this stage. If so, their buffer usage will get + * propagated into pgBufferUsage at this point, and we want to make sure + * that it gets associated with the Gather node. We skip this if the node + * has never been executed, so as to avoid incorrectly making it appear + * that it has. + */ + if (node->instrument && node->instrument->running) + InstrStartNode(node->instrument); + switch (nodeTag(node)) { case T_GatherState: @@ -776,6 +789,10 @@ ExecShutdownNode(PlanState *node) break; } + /* Stop the node if we started it above, reporting 0 tuples. */ + if (node->instrument && node->instrument->running) + InstrStopNode(node->instrument, 0); + return false; } diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c index cdc9c51bd15..4a700b7b30e 100644 --- a/src/backend/executor/nodeGather.c +++ b/src/backend/executor/nodeGather.c @@ -324,7 +324,10 @@ gather_readnext(GatherState *gatherstate) Assert(!tup); --gatherstate->nreaders; if (gatherstate->nreaders == 0) + { + ExecShutdownGatherWorkers(gatherstate); return NULL; + } memmove(&gatherstate->reader[gatherstate->nextreader], &gatherstate->reader[gatherstate->nextreader + 1], sizeof(TupleQueueReader *) diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c index 56d98b4490b..66ea6aa3c35 100644 --- a/src/backend/executor/nodeLimit.c +++ b/src/backend/executor/nodeLimit.c @@ -134,6 +134,8 @@ ExecLimit(PlanState *pstate) node->position - node->offset >= node->count) { node->lstate = LIMIT_WINDOWEND; + /* Allow nodes to release or shut down resources. */ + (void) ExecShutdownNode(outerPlan); return NULL; }