From f026fbf059f2d9d7c8f1f52e9210018d38d795d8 Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Sun, 22 Mar 2026 13:20:29 -0400 Subject: [PATCH] Make IndexScanInstrumentation a pointer in executor scan nodes. Change the IndexScanInstrumentation fields in IndexScanState, IndexOnlyScanState, and BitmapIndexScanState from inline structs to pointers. This avoids additional space overhead whenever new fields are added to IndexScanInstrumentation in the future, at least in the common case where the instrumentation isn't used (i.e. when the executor node isn't being run through an EXPLAIN ANALYZE). Preparation for an upcoming patch series that will add index prefetching. The new slot-based interface that will enable index prefetching necessitates that we add at least one more field to IndexScanInstrumentation (to count heap fetches during index-only scans). Author: Peter Geoghegan Reviewed-By: Andres Freund Discussion: https://postgr.es/m/CAH2-Wz=g=JTSyDB4UtB5su2ZcvsS7VbP+ZMvvaG6ABoCb+s8Lw@mail.gmail.com --- src/backend/commands/explain.c | 6 +++--- src/backend/executor/nodeBitmapIndexscan.c | 8 ++++++-- src/backend/executor/nodeIndexonlyscan.c | 12 ++++++++---- src/backend/executor/nodeIndexscan.c | 14 +++++++++----- src/include/nodes/execnodes.h | 6 +++--- 5 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 296ea8a1ed2..e4b70166b0e 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -3880,7 +3880,7 @@ show_indexsearches_info(PlanState *planstate, ExplainState *es) { IndexScanState *indexstate = ((IndexScanState *) planstate); - nsearches = indexstate->iss_Instrument.nsearches; + nsearches = indexstate->iss_Instrument->nsearches; SharedInfo = indexstate->iss_SharedInfo; break; } @@ -3888,7 +3888,7 @@ show_indexsearches_info(PlanState *planstate, ExplainState *es) { IndexOnlyScanState *indexstate = ((IndexOnlyScanState *) planstate); - nsearches = indexstate->ioss_Instrument.nsearches; + nsearches = indexstate->ioss_Instrument->nsearches; SharedInfo = indexstate->ioss_SharedInfo; break; } @@ -3896,7 +3896,7 @@ show_indexsearches_info(PlanState *planstate, ExplainState *es) { BitmapIndexScanState *indexstate = ((BitmapIndexScanState *) planstate); - nsearches = indexstate->biss_Instrument.nsearches; + nsearches = indexstate->biss_Instrument->nsearches; SharedInfo = indexstate->biss_SharedInfo; break; } diff --git a/src/backend/executor/nodeBitmapIndexscan.c b/src/backend/executor/nodeBitmapIndexscan.c index e6f378c05da..70c55ee6d61 100644 --- a/src/backend/executor/nodeBitmapIndexscan.c +++ b/src/backend/executor/nodeBitmapIndexscan.c @@ -203,7 +203,7 @@ ExecEndBitmapIndexScan(BitmapIndexScanState *node) * shutdown on the workers. On rescan it will spin up new workers * which will have a new BitmapIndexScanState and zeroed stats. */ - winstrument->nsearches += node->biss_Instrument.nsearches; + winstrument->nsearches += node->biss_Instrument->nsearches; } /* @@ -274,6 +274,10 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags) if (eflags & EXEC_FLAG_EXPLAIN_ONLY) return indexstate; + /* Set up instrumentation of bitmap index scans if requested */ + if (estate->es_instrument) + indexstate->biss_Instrument = palloc0_object(IndexScanInstrumentation); + /* Open the index relation. */ lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode; indexstate->biss_RelationDesc = index_open(node->indexid, lockmode); @@ -325,7 +329,7 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags) indexstate->biss_ScanDesc = index_beginscan_bitmap(indexstate->biss_RelationDesc, estate->es_snapshot, - &indexstate->biss_Instrument, + indexstate->biss_Instrument, indexstate->biss_NumScanKeys); /* diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c index c8db357e69f..9eab81fd1c8 100644 --- a/src/backend/executor/nodeIndexonlyscan.c +++ b/src/backend/executor/nodeIndexonlyscan.c @@ -93,7 +93,7 @@ IndexOnlyNext(IndexOnlyScanState *node) scandesc = index_beginscan(node->ss.ss_currentRelation, node->ioss_RelationDesc, estate->es_snapshot, - &node->ioss_Instrument, + node->ioss_Instrument, node->ioss_NumScanKeys, node->ioss_NumOrderByKeys); @@ -433,7 +433,7 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node) * shutdown on the workers. On rescan it will spin up new workers * which will have a new IndexOnlyScanState and zeroed stats. */ - winstrument->nsearches += node->ioss_Instrument.nsearches; + winstrument->nsearches += node->ioss_Instrument->nsearches; } /* @@ -606,6 +606,10 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags) if (eflags & EXEC_FLAG_EXPLAIN_ONLY) return indexstate; + /* Set up instrumentation of index-only scans if requested */ + if (estate->es_instrument) + indexstate->ioss_Instrument = palloc0_object(IndexScanInstrumentation); + /* Open the index relation. */ lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode; indexRelation = index_open(node->indexid, lockmode); @@ -787,7 +791,7 @@ ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node, node->ioss_ScanDesc = index_beginscan_parallel(node->ss.ss_currentRelation, node->ioss_RelationDesc, - &node->ioss_Instrument, + node->ioss_Instrument, node->ioss_NumScanKeys, node->ioss_NumOrderByKeys, piscan); @@ -853,7 +857,7 @@ ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, node->ioss_ScanDesc = index_beginscan_parallel(node->ss.ss_currentRelation, node->ioss_RelationDesc, - &node->ioss_Instrument, + node->ioss_Instrument, node->ioss_NumScanKeys, node->ioss_NumOrderByKeys, piscan); diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index bd83e4712b3..06143e94c5a 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -111,7 +111,7 @@ IndexNext(IndexScanState *node) scandesc = index_beginscan(node->ss.ss_currentRelation, node->iss_RelationDesc, estate->es_snapshot, - &node->iss_Instrument, + node->iss_Instrument, node->iss_NumScanKeys, node->iss_NumOrderByKeys); @@ -207,7 +207,7 @@ IndexNextWithReorder(IndexScanState *node) scandesc = index_beginscan(node->ss.ss_currentRelation, node->iss_RelationDesc, estate->es_snapshot, - &node->iss_Instrument, + node->iss_Instrument, node->iss_NumScanKeys, node->iss_NumOrderByKeys); @@ -813,7 +813,7 @@ ExecEndIndexScan(IndexScanState *node) * shutdown on the workers. On rescan it will spin up new workers * which will have a new IndexOnlyScanState and zeroed stats. */ - winstrument->nsearches += node->iss_Instrument.nsearches; + winstrument->nsearches += node->iss_Instrument->nsearches; } /* @@ -974,6 +974,10 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) if (eflags & EXEC_FLAG_EXPLAIN_ONLY) return indexstate; + /* Set up instrumentation of index scans if requested */ + if (estate->es_instrument) + indexstate->iss_Instrument = palloc0_object(IndexScanInstrumentation); + /* Open the index relation. */ lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode; indexstate->iss_RelationDesc = index_open(node->indexid, lockmode); @@ -1723,7 +1727,7 @@ ExecIndexScanInitializeDSM(IndexScanState *node, node->iss_ScanDesc = index_beginscan_parallel(node->ss.ss_currentRelation, node->iss_RelationDesc, - &node->iss_Instrument, + node->iss_Instrument, node->iss_NumScanKeys, node->iss_NumOrderByKeys, piscan); @@ -1787,7 +1791,7 @@ ExecIndexScanInitializeWorker(IndexScanState *node, node->iss_ScanDesc = index_beginscan_parallel(node->ss.ss_currentRelation, node->iss_RelationDesc, - &node->iss_Instrument, + node->iss_Instrument, node->iss_NumScanKeys, node->iss_NumOrderByKeys, piscan); diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 2162ff56c38..684e398f824 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -1732,7 +1732,7 @@ typedef struct IndexScanState ExprContext *iss_RuntimeContext; Relation iss_RelationDesc; struct IndexScanDescData *iss_ScanDesc; - IndexScanInstrumentation iss_Instrument; + IndexScanInstrumentation *iss_Instrument; SharedIndexScanInstrumentation *iss_SharedInfo; /* These are needed for re-checking ORDER BY expr ordering */ @@ -1783,7 +1783,7 @@ typedef struct IndexOnlyScanState ExprContext *ioss_RuntimeContext; Relation ioss_RelationDesc; struct IndexScanDescData *ioss_ScanDesc; - IndexScanInstrumentation ioss_Instrument; + IndexScanInstrumentation *ioss_Instrument; SharedIndexScanInstrumentation *ioss_SharedInfo; TupleTableSlot *ioss_TableSlot; Buffer ioss_VMBuffer; @@ -1824,7 +1824,7 @@ typedef struct BitmapIndexScanState ExprContext *biss_RuntimeContext; Relation biss_RelationDesc; struct IndexScanDescData *biss_ScanDesc; - IndexScanInstrumentation biss_Instrument; + IndexScanInstrumentation *biss_Instrument; SharedIndexScanInstrumentation *biss_SharedInfo; } BitmapIndexScanState;