Make IndexScanInstrumentation a pointer in executor scan nodes. master github/master
authorPeter Geoghegan <pg@bowt.ie>
Sun, 22 Mar 2026 17:20:29 +0000 (13:20 -0400)
committerPeter Geoghegan <pg@bowt.ie>
Sun, 22 Mar 2026 17:20:29 +0000 (13:20 -0400)
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 <pg@bowt.ie>
Reviewed-By: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/CAH2-Wz=g=JTSyDB4UtB5su2ZcvsS7VbP+ZMvvaG6ABoCb+s8Lw@mail.gmail.com

src/backend/commands/explain.c
src/backend/executor/nodeBitmapIndexscan.c
src/backend/executor/nodeIndexonlyscan.c
src/backend/executor/nodeIndexscan.c
src/include/nodes/execnodes.h

index 296ea8a1ed21ba57e919a5ff489a20b41efa5f09..e4b70166b0e50c79636ca6864f40cc42d73ae223 100644 (file)
@@ -3880,7 +3880,7 @@ show_indexsearches_info(PlanState *planstate, ExplainState *es)
            {
                IndexScanState *indexstate = ((IndexScanState *) planstate);
 
            {
                IndexScanState *indexstate = ((IndexScanState *) planstate);
 
-               nsearches = indexstate->iss_Instrument.nsearches;
+               nsearches = indexstate->iss_Instrument->nsearches;
                SharedInfo = indexstate->iss_SharedInfo;
                break;
            }
                SharedInfo = indexstate->iss_SharedInfo;
                break;
            }
@@ -3888,7 +3888,7 @@ show_indexsearches_info(PlanState *planstate, ExplainState *es)
            {
                IndexOnlyScanState *indexstate = ((IndexOnlyScanState *) planstate);
 
            {
                IndexOnlyScanState *indexstate = ((IndexOnlyScanState *) planstate);
 
-               nsearches = indexstate->ioss_Instrument.nsearches;
+               nsearches = indexstate->ioss_Instrument->nsearches;
                SharedInfo = indexstate->ioss_SharedInfo;
                break;
            }
                SharedInfo = indexstate->ioss_SharedInfo;
                break;
            }
@@ -3896,7 +3896,7 @@ show_indexsearches_info(PlanState *planstate, ExplainState *es)
            {
                BitmapIndexScanState *indexstate = ((BitmapIndexScanState *) planstate);
 
            {
                BitmapIndexScanState *indexstate = ((BitmapIndexScanState *) planstate);
 
-               nsearches = indexstate->biss_Instrument.nsearches;
+               nsearches = indexstate->biss_Instrument->nsearches;
                SharedInfo = indexstate->biss_SharedInfo;
                break;
            }
                SharedInfo = indexstate->biss_SharedInfo;
                break;
            }
index e6f378c05daf05ef7824d91eddddae5c3e00c450..70c55ee6d614df30ceaa3fb063b5fedc49e591f9 100644 (file)
@@ -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.
         */
         * 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;
 
    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);
    /* 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_ScanDesc =
        index_beginscan_bitmap(indexstate->biss_RelationDesc,
                               estate->es_snapshot,
-                              &indexstate->biss_Instrument,
+                              indexstate->biss_Instrument,
                               indexstate->biss_NumScanKeys);
 
    /*
                               indexstate->biss_NumScanKeys);
 
    /*
index c8db357e69f5377fd0fe611f8114a5727ab8c3e1..9eab81fd1c85b8fecaa95c58deb503775e653aa1 100644 (file)
@@ -93,7 +93,7 @@ IndexOnlyNext(IndexOnlyScanState *node)
        scandesc = index_beginscan(node->ss.ss_currentRelation,
                                   node->ioss_RelationDesc,
                                   estate->es_snapshot,
        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);
 
                                   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.
         */
         * 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;
 
    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);
    /* 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_ScanDesc =
        index_beginscan_parallel(node->ss.ss_currentRelation,
                                 node->ioss_RelationDesc,
-                                &node->ioss_Instrument,
+                                node->ioss_Instrument,
                                 node->ioss_NumScanKeys,
                                 node->ioss_NumOrderByKeys,
                                 piscan);
                                 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_ScanDesc =
        index_beginscan_parallel(node->ss.ss_currentRelation,
                                 node->ioss_RelationDesc,
-                                &node->ioss_Instrument,
+                                node->ioss_Instrument,
                                 node->ioss_NumScanKeys,
                                 node->ioss_NumOrderByKeys,
                                 piscan);
                                 node->ioss_NumScanKeys,
                                 node->ioss_NumOrderByKeys,
                                 piscan);
index bd83e4712b320c3de77f2dd48fb477fc539cb4bb..06143e94c5a44daed7724ac7ea8b033305dfbd34 100644 (file)
@@ -111,7 +111,7 @@ IndexNext(IndexScanState *node)
        scandesc = index_beginscan(node->ss.ss_currentRelation,
                                   node->iss_RelationDesc,
                                   estate->es_snapshot,
        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);
 
                                   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,
        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);
 
                                   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.
         */
         * 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;
 
    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);
    /* 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_ScanDesc =
        index_beginscan_parallel(node->ss.ss_currentRelation,
                                 node->iss_RelationDesc,
-                                &node->iss_Instrument,
+                                node->iss_Instrument,
                                 node->iss_NumScanKeys,
                                 node->iss_NumOrderByKeys,
                                 piscan);
                                 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_ScanDesc =
        index_beginscan_parallel(node->ss.ss_currentRelation,
                                 node->iss_RelationDesc,
-                                &node->iss_Instrument,
+                                node->iss_Instrument,
                                 node->iss_NumScanKeys,
                                 node->iss_NumOrderByKeys,
                                 piscan);
                                 node->iss_NumScanKeys,
                                 node->iss_NumOrderByKeys,
                                 piscan);
index 2162ff56c38bf613b87058efc3e343ba998893c9..684e398f82438969329322677ac37620d912d309 100644 (file)
@@ -1732,7 +1732,7 @@ typedef struct IndexScanState
    ExprContext *iss_RuntimeContext;
    Relation    iss_RelationDesc;
    struct IndexScanDescData *iss_ScanDesc;
    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 */
    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;
    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;
    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;
    ExprContext *biss_RuntimeContext;
    Relation    biss_RelationDesc;
    struct IndexScanDescData *biss_ScanDesc;
-   IndexScanInstrumentation biss_Instrument;
+   IndexScanInstrumentation *biss_Instrument;
    SharedIndexScanInstrumentation *biss_SharedInfo;
 } BitmapIndexScanState;
 
    SharedIndexScanInstrumentation *biss_SharedInfo;
 } BitmapIndexScanState;