v8-0002-Show-Bitmap-Heap-Scan-stats-for-non-parallel-awar.patch
text/x-patch
Filename: v8-0002-Show-Bitmap-Heap-Scan-stats-for-non-parallel-awar.patch
Type: text/x-patch
Part: 1
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v8-0002
Subject: Show Bitmap Heap Scan stats for non-parallel-aware workers
| File | + | − |
|---|---|---|
| src/backend/commands/explain.c | 1 | 1 |
| src/backend/executor/execParallel.c | 9 | 9 |
| src/backend/executor/nodeBitmapHeapscan.c | 61 | 25 |
From 6a570e087696479f1be020c13891c8c6242d91e7 Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@vondra.me>
Date: Fri, 3 Apr 2026 14:15:28 +0200
Subject: [PATCH v8 2/5] Show Bitmap Heap Scan stats for non-parallel-aware
workers
Commit 5a1e6df3b84c added information about exact/lossy pages for each
parallel worker. It however works only for parallel-aware scans, not for
other parallel scans. For example scans on the outer side of a parallel
join are not parallel-aware, and so won't report the stats. Similarly,
queries run with debug_parallel_query=regress are not parallel-aware,
which may cause regression failures due to changes in explain output.
Fixed in a way similar to 0fbceae841cb, by invoking functions always,
and only then considering parallel_aware.
Probably needs to be backpatched to 18.
---
src/backend/commands/explain.c | 2 +-
src/backend/executor/execParallel.c | 18 ++---
src/backend/executor/nodeBitmapHeapscan.c | 86 ++++++++++++++++-------
3 files changed, 71 insertions(+), 35 deletions(-)
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index e4b70166b0e..8275bb2af61 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -3949,7 +3949,7 @@ show_tidbitmap_info(BitmapHeapScanState *planstate, ExplainState *es)
}
/* Display stats for each parallel worker */
- if (planstate->pstate != NULL)
+ if (planstate->sinstrument != NULL)
{
for (int n = 0; n < planstate->sinstrument->num_workers; n++)
{
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index 755191b51ef..ce377a774f8 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -290,9 +290,9 @@ ExecParallelEstimate(PlanState *planstate, ExecParallelEstimateContext *e)
e->pcxt);
break;
case T_BitmapHeapScanState:
- if (planstate->plan->parallel_aware)
- ExecBitmapHeapEstimate((BitmapHeapScanState *) planstate,
- e->pcxt);
+ /* even when not parallel-aware, for EXPLAIN ANALYZE */
+ ExecBitmapHeapEstimate((BitmapHeapScanState *) planstate,
+ e->pcxt);
break;
case T_HashJoinState:
if (planstate->plan->parallel_aware)
@@ -522,9 +522,9 @@ ExecParallelInitializeDSM(PlanState *planstate,
d->pcxt);
break;
case T_BitmapHeapScanState:
- if (planstate->plan->parallel_aware)
- ExecBitmapHeapInitializeDSM((BitmapHeapScanState *) planstate,
- d->pcxt);
+ /* even when not parallel-aware, for EXPLAIN ANALYZE */
+ ExecBitmapHeapInitializeDSM((BitmapHeapScanState *) planstate,
+ d->pcxt);
break;
case T_HashJoinState:
if (planstate->plan->parallel_aware)
@@ -1400,9 +1400,9 @@ ExecParallelInitializeWorker(PlanState *planstate, ParallelWorkerContext *pwcxt)
pwcxt);
break;
case T_BitmapHeapScanState:
- if (planstate->plan->parallel_aware)
- ExecBitmapHeapInitializeWorker((BitmapHeapScanState *) planstate,
- pwcxt);
+ /* even when not parallel-aware, for EXPLAIN ANALYZE */
+ ExecBitmapHeapInitializeWorker((BitmapHeapScanState *) planstate,
+ pwcxt);
break;
case T_HashJoinState:
if (planstate->plan->parallel_aware)
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index 73831aed451..0c580365e9c 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -495,9 +495,21 @@ void
ExecBitmapHeapEstimate(BitmapHeapScanState *node,
ParallelContext *pcxt)
{
- Size size;
+ Size size = 0;
+ bool instrument = (node->ss.ps.instrument != NULL);
+ bool parallel_aware = node->ss.ps.plan->parallel_aware;
- size = MAXALIGN(sizeof(ParallelBitmapHeapState));
+ if (!instrument && !parallel_aware)
+ {
+ /* No DSM required by the scan */
+ return;
+ }
+
+ /* parallel state is needed only in parallel-aware scans */
+ if (parallel_aware)
+ {
+ size = MAXALIGN(sizeof(ParallelBitmapHeapState));
+ }
/* account for instrumentation, if required */
if (node->ss.ps.instrument && pcxt->nworkers > 0)
@@ -521,48 +533,61 @@ ExecBitmapHeapInitializeDSM(BitmapHeapScanState *node,
ParallelContext *pcxt)
{
ParallelBitmapHeapState *pstate;
+ bool instrument = node->ss.ps.instrument != NULL;
+ bool parallel_aware = node->ss.ps.plan->parallel_aware;
SharedBitmapHeapInstrumentation *sinstrument = NULL;
- dsa_area *dsa = node->ss.ps.state->es_query_dsa;
char *ptr;
- Size size;
+ Size size = 0;
- /* If there's no DSA, there are no workers; initialize nothing. */
- if (dsa == NULL)
+ if (!instrument && !parallel_aware)
+ {
+ /* No DSM required by the scan */
return;
+ }
- size = MAXALIGN(sizeof(ParallelBitmapHeapState));
- if (node->ss.ps.instrument && pcxt->nworkers > 0)
+ /* parallel state is needed only in parallel-aware scans */
+ if (parallel_aware)
+ {
+ size = MAXALIGN(sizeof(ParallelBitmapHeapState));
+ }
+
+ if (instrument && pcxt->nworkers > 0)
{
size = add_size(size, offsetof(SharedBitmapHeapInstrumentation, sinstrument));
size = add_size(size, mul_size(pcxt->nworkers, sizeof(BitmapHeapScanInstrumentation)));
}
ptr = shm_toc_allocate(pcxt->toc, size);
- pstate = (ParallelBitmapHeapState *) ptr;
- ptr += MAXALIGN(sizeof(ParallelBitmapHeapState));
- if (node->ss.ps.instrument && pcxt->nworkers > 0)
- sinstrument = (SharedBitmapHeapInstrumentation *) ptr;
+ shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, ptr);
+
+ if (parallel_aware)
+ {
+ pstate = (ParallelBitmapHeapState *) ptr;
+ ptr += MAXALIGN(sizeof(ParallelBitmapHeapState));
- pstate->tbmiterator = 0;
+ pstate->tbmiterator = 0;
- /* Initialize the mutex */
- SpinLockInit(&pstate->mutex);
- pstate->state = BM_INITIAL;
+ /* Initialize the mutex */
+ SpinLockInit(&pstate->mutex);
+ pstate->state = BM_INITIAL;
- ConditionVariableInit(&pstate->cv);
+ ConditionVariableInit(&pstate->cv);
- if (sinstrument)
+ node->pstate = pstate;
+ }
+
+ if (instrument && pcxt->nworkers > 0)
{
+ sinstrument = (SharedBitmapHeapInstrumentation *) ptr;
+
sinstrument->num_workers = pcxt->nworkers;
/* ensure any unfilled slots will contain zeroes */
memset(sinstrument->sinstrument, 0,
pcxt->nworkers * sizeof(BitmapHeapScanInstrumentation));
- }
- shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pstate);
- node->pstate = pstate;
- node->sinstrument = sinstrument;
+ node->sinstrument = sinstrument;
+ }
}
/* ----------------------------------------------------------------
@@ -600,16 +625,27 @@ void
ExecBitmapHeapInitializeWorker(BitmapHeapScanState *node,
ParallelWorkerContext *pwcxt)
{
+ bool instrument = node->ss.ps.instrument != NULL;
+ bool parallel_aware = node->ss.ps.plan->parallel_aware;
char *ptr;
+ if (!instrument && !parallel_aware)
+ {
+ /* No DSM required by the scan */
+ return;
+ }
+
Assert(node->ss.ps.state->es_query_dsa != NULL);
ptr = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
- node->pstate = (ParallelBitmapHeapState *) ptr;
- ptr += MAXALIGN(sizeof(ParallelBitmapHeapState));
+ if (parallel_aware)
+ {
+ node->pstate = (ParallelBitmapHeapState *) ptr;
+ ptr += MAXALIGN(sizeof(ParallelBitmapHeapState));
+ }
- if (node->ss.ps.instrument)
+ if (instrument)
node->sinstrument = (SharedBitmapHeapInstrumentation *) ptr;
}
--
2.53.0