LCOV - code coverage report
Current view: top level - src/backend/executor - nodeBitmapHeapscan.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 80.0 % 175 140
Test Date: 2026-04-07 14:16:30 Functions: 88.2 % 17 15
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * nodeBitmapHeapscan.c
       4              :  *    Routines to support bitmapped scans of relations
       5              :  *
       6              :  * NOTE: it is critical that this plan type only be used with MVCC-compliant
       7              :  * snapshots (ie, regular snapshots, not SnapshotAny or one of the other
       8              :  * special snapshots).  The reason is that since index and heap scans are
       9              :  * decoupled, there can be no assurance that the index tuple prompting a
      10              :  * visit to a particular heap TID still exists when the visit is made.
      11              :  * Therefore the tuple might not exist anymore either (which is OK because
      12              :  * heap_fetch will cope) --- but worse, the tuple slot could have been
      13              :  * re-used for a newer tuple.  With an MVCC snapshot the newer tuple is
      14              :  * certain to fail the time qual and so it will not be mistakenly returned,
      15              :  * but with anything else we might return a tuple that doesn't meet the
      16              :  * required index qual conditions.
      17              :  *
      18              :  *
      19              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      20              :  * Portions Copyright (c) 1994, Regents of the University of California
      21              :  *
      22              :  *
      23              :  * IDENTIFICATION
      24              :  *    src/backend/executor/nodeBitmapHeapscan.c
      25              :  *
      26              :  *-------------------------------------------------------------------------
      27              :  */
      28              : /*
      29              :  * INTERFACE ROUTINES
      30              :  *      ExecBitmapHeapScan          scans a relation using bitmap info
      31              :  *      ExecBitmapHeapNext          workhorse for above
      32              :  *      ExecInitBitmapHeapScan      creates and initializes state info.
      33              :  *      ExecReScanBitmapHeapScan    prepares to rescan the plan.
      34              :  *      ExecEndBitmapHeapScan       releases all storage.
      35              :  */
      36              : #include "postgres.h"
      37              : 
      38              : #include "access/relscan.h"
      39              : #include "access/tableam.h"
      40              : #include "access/visibilitymap.h"
      41              : #include "executor/executor.h"
      42              : #include "executor/instrument.h"
      43              : #include "executor/nodeBitmapHeapscan.h"
      44              : #include "miscadmin.h"
      45              : #include "pgstat.h"
      46              : #include "storage/bufmgr.h"
      47              : #include "storage/condition_variable.h"
      48              : #include "utils/dsa.h"
      49              : #include "utils/rel.h"
      50              : #include "utils/spccache.h"
      51              : #include "utils/wait_event.h"
      52              : 
      53              : static void BitmapTableScanSetup(BitmapHeapScanState *node);
      54              : static TupleTableSlot *BitmapHeapNext(BitmapHeapScanState *node);
      55              : static inline void BitmapDoneInitializingSharedState(ParallelBitmapHeapState *pstate);
      56              : static bool BitmapShouldInitializeSharedState(ParallelBitmapHeapState *pstate);
      57              : 
      58              : 
      59              : /* ----------------
      60              :  *   SharedBitmapState information
      61              :  *
      62              :  *      BM_INITIAL      TIDBitmap creation is not yet started, so first worker
      63              :  *                      to see this state will set the state to BM_INPROGRESS
      64              :  *                      and that process will be responsible for creating
      65              :  *                      TIDBitmap.
      66              :  *      BM_INPROGRESS   TIDBitmap creation is in progress; workers need to
      67              :  *                      sleep until it's finished.
      68              :  *      BM_FINISHED     TIDBitmap creation is done, so now all workers can
      69              :  *                      proceed to iterate over TIDBitmap.
      70              :  * ----------------
      71              :  */
      72              : typedef enum
      73              : {
      74              :     BM_INITIAL,
      75              :     BM_INPROGRESS,
      76              :     BM_FINISHED,
      77              : } SharedBitmapState;
      78              : 
      79              : /* ----------------
      80              :  *   ParallelBitmapHeapState information
      81              :  *      tbmiterator             iterator for scanning current pages
      82              :  *      mutex                   mutual exclusion for state
      83              :  *      state                   current state of the TIDBitmap
      84              :  *      cv                      conditional wait variable
      85              :  * ----------------
      86              :  */
      87              : typedef struct ParallelBitmapHeapState
      88              : {
      89              :     dsa_pointer tbmiterator;
      90              :     slock_t     mutex;
      91              :     SharedBitmapState state;
      92              :     ConditionVariable cv;
      93              : } ParallelBitmapHeapState;
      94              : 
      95              : 
      96              : /*
      97              :  * Do the underlying index scan, build the bitmap, set up the parallel state
      98              :  * needed for parallel workers to iterate through the bitmap, and set up the
      99              :  * underlying table scan descriptor.
     100              :  */
     101              : static void
     102        15949 : BitmapTableScanSetup(BitmapHeapScanState *node)
     103              : {
     104        15949 :     TBMIterator tbmiterator = {0};
     105        15949 :     ParallelBitmapHeapState *pstate = node->pstate;
     106        15949 :     dsa_area   *dsa = node->ss.ps.state->es_query_dsa;
     107              : 
     108        15949 :     if (!pstate)
     109              :     {
     110        15721 :         node->tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
     111              : 
     112        15721 :         if (!node->tbm || !IsA(node->tbm, TIDBitmap))
     113            0 :             elog(ERROR, "unrecognized result from subplan");
     114              :     }
     115          228 :     else if (BitmapShouldInitializeSharedState(pstate))
     116              :     {
     117              :         /*
     118              :          * The leader will immediately come out of the function, but others
     119              :          * will be blocked until leader populates the TBM and wakes them up.
     120              :          */
     121           48 :         node->tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
     122           48 :         if (!node->tbm || !IsA(node->tbm, TIDBitmap))
     123            0 :             elog(ERROR, "unrecognized result from subplan");
     124              : 
     125              :         /*
     126              :          * Prepare to iterate over the TBM. This will return the dsa_pointer
     127              :          * of the iterator state which will be used by multiple processes to
     128              :          * iterate jointly.
     129              :          */
     130           48 :         pstate->tbmiterator = tbm_prepare_shared_iterate(node->tbm);
     131              : 
     132              :         /* We have initialized the shared state so wake up others. */
     133           48 :         BitmapDoneInitializingSharedState(pstate);
     134              :     }
     135              : 
     136        15949 :     tbmiterator = tbm_begin_iterate(node->tbm, dsa,
     137              :                                     pstate ?
     138              :                                     pstate->tbmiterator :
     139              :                                     InvalidDsaPointer);
     140              : 
     141              :     /*
     142              :      * If this is the first scan of the underlying table, create the table
     143              :      * scan descriptor and begin the scan.
     144              :      */
     145        15949 :     if (!node->ss.ss_currentScanDesc)
     146              :     {
     147        13627 :         node->ss.ss_currentScanDesc =
     148        13627 :             table_beginscan_bm(node->ss.ss_currentRelation,
     149        13627 :                                node->ss.ps.state->es_snapshot,
     150              :                                0,
     151              :                                NULL,
     152        13627 :                                ScanRelIsReadOnly(&node->ss) ?
     153              :                                SO_HINT_REL_READ_ONLY : SO_NONE);
     154              :     }
     155              : 
     156        15949 :     node->ss.ss_currentScanDesc->st.rs_tbmiterator = tbmiterator;
     157        15949 :     node->initialized = true;
     158        15949 : }
     159              : 
     160              : /* ----------------------------------------------------------------
     161              :  *      BitmapHeapNext
     162              :  *
     163              :  *      Retrieve next tuple from the BitmapHeapScan node's currentRelation
     164              :  * ----------------------------------------------------------------
     165              :  */
     166              : static TupleTableSlot *
     167      3641597 : BitmapHeapNext(BitmapHeapScanState *node)
     168              : {
     169      3641597 :     ExprContext *econtext = node->ss.ps.ps_ExprContext;
     170      3641597 :     TupleTableSlot *slot = node->ss.ss_ScanTupleSlot;
     171              : 
     172              :     /*
     173              :      * If we haven't yet performed the underlying index scan, do it, and begin
     174              :      * the iteration over the bitmap.
     175              :      */
     176      3641597 :     if (!node->initialized)
     177        15949 :         BitmapTableScanSetup(node);
     178              : 
     179      4142132 :     while (table_scan_bitmap_next_tuple(node->ss.ss_currentScanDesc,
     180              :                                         slot, &node->recheck,
     181              :                                         &node->stats.lossy_pages,
     182              :                                         &node->stats.exact_pages))
     183              :     {
     184              :         /*
     185              :          * Continuing in previously obtained page.
     186              :          */
     187      4126512 :         CHECK_FOR_INTERRUPTS();
     188              : 
     189              :         /*
     190              :          * If we are using lossy info, we have to recheck the qual conditions
     191              :          * at every tuple.
     192              :          */
     193      4126512 :         if (node->recheck)
     194              :         {
     195      1889151 :             econtext->ecxt_scantuple = slot;
     196      1889151 :             if (!ExecQualAndReset(node->bitmapqualorig, econtext))
     197              :             {
     198              :                 /* Fails recheck, so drop it and loop back for another */
     199       500535 :                 InstrCountFiltered2(node, 1);
     200       500535 :                 ExecClearTuple(slot);
     201       500535 :                 continue;
     202              :             }
     203              :         }
     204              : 
     205              :         /* OK to return this tuple */
     206      3625977 :         return slot;
     207              :     }
     208              : 
     209              :     /*
     210              :      * if we get here it means we are at the end of the scan..
     211              :      */
     212        15617 :     return ExecClearTuple(slot);
     213              : }
     214              : 
     215              : /*
     216              :  *  BitmapDoneInitializingSharedState - Shared state is initialized
     217              :  *
     218              :  *  By this time the leader has already populated the TBM and initialized the
     219              :  *  shared state so wake up other processes.
     220              :  */
     221              : static inline void
     222           48 : BitmapDoneInitializingSharedState(ParallelBitmapHeapState *pstate)
     223              : {
     224           48 :     SpinLockAcquire(&pstate->mutex);
     225           48 :     pstate->state = BM_FINISHED;
     226           48 :     SpinLockRelease(&pstate->mutex);
     227           48 :     ConditionVariableBroadcast(&pstate->cv);
     228           48 : }
     229              : 
     230              : /*
     231              :  * BitmapHeapRecheck -- access method routine to recheck a tuple in EvalPlanQual
     232              :  */
     233              : static bool
     234            0 : BitmapHeapRecheck(BitmapHeapScanState *node, TupleTableSlot *slot)
     235              : {
     236              :     ExprContext *econtext;
     237              : 
     238              :     /*
     239              :      * extract necessary information from index scan node
     240              :      */
     241            0 :     econtext = node->ss.ps.ps_ExprContext;
     242              : 
     243              :     /* Does the tuple meet the original qual conditions? */
     244            0 :     econtext->ecxt_scantuple = slot;
     245            0 :     return ExecQualAndReset(node->bitmapqualorig, econtext);
     246              : }
     247              : 
     248              : /* ----------------------------------------------------------------
     249              :  *      ExecBitmapHeapScan(node)
     250              :  * ----------------------------------------------------------------
     251              :  */
     252              : static TupleTableSlot *
     253      3411547 : ExecBitmapHeapScan(PlanState *pstate)
     254              : {
     255      3411547 :     BitmapHeapScanState *node = castNode(BitmapHeapScanState, pstate);
     256              : 
     257      3411547 :     return ExecScan(&node->ss,
     258              :                     (ExecScanAccessMtd) BitmapHeapNext,
     259              :                     (ExecScanRecheckMtd) BitmapHeapRecheck);
     260              : }
     261              : 
     262              : /* ----------------------------------------------------------------
     263              :  *      ExecReScanBitmapHeapScan(node)
     264              :  * ----------------------------------------------------------------
     265              :  */
     266              : void
     267         2976 : ExecReScanBitmapHeapScan(BitmapHeapScanState *node)
     268              : {
     269         2976 :     PlanState  *outerPlan = outerPlanState(node);
     270              : 
     271         2976 :     TableScanDesc scan = node->ss.ss_currentScanDesc;
     272              : 
     273         2976 :     if (scan)
     274              :     {
     275              :         /*
     276              :          * End iteration on iterators saved in scan descriptor if they have
     277              :          * not already been cleaned up.
     278              :          */
     279         2326 :         if (!tbm_exhausted(&scan->st.rs_tbmiterator))
     280         2322 :             tbm_end_iterate(&scan->st.rs_tbmiterator);
     281              : 
     282              :         /* rescan to release any page pin */
     283         2326 :         table_rescan(node->ss.ss_currentScanDesc, NULL);
     284              :     }
     285              : 
     286              :     /* release bitmaps and buffers if any */
     287         2976 :     if (node->tbm)
     288         2322 :         tbm_free(node->tbm);
     289         2976 :     node->tbm = NULL;
     290         2976 :     node->initialized = false;
     291         2976 :     node->recheck = true;
     292              : 
     293         2976 :     ExecScanReScan(&node->ss);
     294              : 
     295              :     /*
     296              :      * if chgParam of subnode is not null then plan will be re-scanned by
     297              :      * first ExecProcNode.
     298              :      */
     299         2976 :     if (outerPlan->chgParam == NULL)
     300          198 :         ExecReScan(outerPlan);
     301         2976 : }
     302              : 
     303              : /* ----------------------------------------------------------------
     304              :  *      ExecEndBitmapHeapScan
     305              :  * ----------------------------------------------------------------
     306              :  */
     307              : void
     308        16609 : ExecEndBitmapHeapScan(BitmapHeapScanState *node)
     309              : {
     310              :     TableScanDesc scanDesc;
     311              : 
     312              :     /*
     313              :      * When ending a parallel worker, copy the statistics gathered by the
     314              :      * worker back into shared memory so that it can be picked up by the main
     315              :      * process to report in EXPLAIN ANALYZE.
     316              :      */
     317        16609 :     if (node->sinstrument != NULL && IsParallelWorker())
     318              :     {
     319              :         BitmapHeapScanInstrumentation *si;
     320              : 
     321              :         Assert(ParallelWorkerNumber < node->sinstrument->num_workers);
     322            0 :         si = &node->sinstrument->sinstrument[ParallelWorkerNumber];
     323              : 
     324              :         /*
     325              :          * Here we accumulate the stats rather than performing memcpy on
     326              :          * node->stats into si.  When a Gather/GatherMerge node finishes it
     327              :          * will perform planner shutdown on the workers.  On rescan it will
     328              :          * spin up new workers which will have a new BitmapHeapScanState and
     329              :          * zeroed stats.
     330              :          */
     331            0 :         si->exact_pages += node->stats.exact_pages;
     332            0 :         si->lossy_pages += node->stats.lossy_pages;
     333              :     }
     334              : 
     335              :     /*
     336              :      * extract information from the node
     337              :      */
     338        16609 :     scanDesc = node->ss.ss_currentScanDesc;
     339              : 
     340              :     /*
     341              :      * close down subplans
     342              :      */
     343        16609 :     ExecEndNode(outerPlanState(node));
     344              : 
     345        16609 :     if (scanDesc)
     346              :     {
     347              :         /*
     348              :          * End iteration on iterators saved in scan descriptor if they have
     349              :          * not already been cleaned up.
     350              :          */
     351        13546 :         if (!tbm_exhausted(&scanDesc->st.rs_tbmiterator))
     352        13546 :             tbm_end_iterate(&scanDesc->st.rs_tbmiterator);
     353              : 
     354              :         /*
     355              :          * close table scan
     356              :          */
     357        13546 :         table_endscan(scanDesc);
     358              :     }
     359              : 
     360              :     /*
     361              :      * release bitmaps and buffers if any
     362              :      */
     363        16609 :     if (node->tbm)
     364        13366 :         tbm_free(node->tbm);
     365        16609 : }
     366              : 
     367              : /* ----------------------------------------------------------------
     368              :  *      ExecInitBitmapHeapScan
     369              :  *
     370              :  *      Initializes the scan's state information.
     371              :  * ----------------------------------------------------------------
     372              :  */
     373              : BitmapHeapScanState *
     374        16690 : ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
     375              : {
     376              :     BitmapHeapScanState *scanstate;
     377              :     Relation    currentRelation;
     378              : 
     379              :     /* check for unsupported flags */
     380              :     Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
     381              : 
     382              :     /*
     383              :      * Assert caller didn't ask for an unsafe snapshot --- see comments at
     384              :      * head of file.
     385              :      */
     386              :     Assert(IsMVCCSnapshot(estate->es_snapshot));
     387              : 
     388              :     /*
     389              :      * create state structure
     390              :      */
     391        16690 :     scanstate = makeNode(BitmapHeapScanState);
     392        16690 :     scanstate->ss.ps.plan = (Plan *) node;
     393        16690 :     scanstate->ss.ps.state = estate;
     394        16690 :     scanstate->ss.ps.ExecProcNode = ExecBitmapHeapScan;
     395              : 
     396        16690 :     scanstate->tbm = NULL;
     397              : 
     398              :     /* Zero the statistics counters */
     399        16690 :     memset(&scanstate->stats, 0, sizeof(BitmapHeapScanInstrumentation));
     400              : 
     401        16690 :     scanstate->initialized = false;
     402        16690 :     scanstate->pstate = NULL;
     403        16690 :     scanstate->recheck = true;
     404              : 
     405              :     /*
     406              :      * Miscellaneous initialization
     407              :      *
     408              :      * create expression context for node
     409              :      */
     410        16690 :     ExecAssignExprContext(estate, &scanstate->ss.ps);
     411              : 
     412              :     /*
     413              :      * open the scan relation
     414              :      */
     415        16690 :     currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
     416              : 
     417              :     /*
     418              :      * initialize child nodes
     419              :      */
     420        16690 :     outerPlanState(scanstate) = ExecInitNode(outerPlan(node), estate, eflags);
     421              : 
     422              :     /*
     423              :      * get the scan type from the relation descriptor.
     424              :      */
     425        16690 :     ExecInitScanTupleSlot(estate, &scanstate->ss,
     426              :                           RelationGetDescr(currentRelation),
     427              :                           table_slot_callbacks(currentRelation),
     428              :                           TTS_FLAG_OBEYS_NOT_NULL_CONSTRAINTS);
     429              : 
     430              :     /*
     431              :      * Initialize result type and projection.
     432              :      */
     433        16690 :     ExecInitResultTypeTL(&scanstate->ss.ps);
     434        16690 :     ExecAssignScanProjectionInfo(&scanstate->ss);
     435              : 
     436              :     /*
     437              :      * initialize child expressions
     438              :      */
     439        16690 :     scanstate->ss.ps.qual =
     440        16690 :         ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
     441        16690 :     scanstate->bitmapqualorig =
     442        16690 :         ExecInitQual(node->bitmapqualorig, (PlanState *) scanstate);
     443              : 
     444        16690 :     scanstate->ss.ss_currentRelation = currentRelation;
     445              : 
     446              :     /*
     447              :      * all done.
     448              :      */
     449        16690 :     return scanstate;
     450              : }
     451              : 
     452              : /*----------------
     453              :  *      BitmapShouldInitializeSharedState
     454              :  *
     455              :  *      The first process to come here and see the state to the BM_INITIAL
     456              :  *      will become the leader for the parallel bitmap scan and will be
     457              :  *      responsible for populating the TIDBitmap.  The other processes will
     458              :  *      be blocked by the condition variable until the leader wakes them up.
     459              :  * ---------------
     460              :  */
     461              : static bool
     462          228 : BitmapShouldInitializeSharedState(ParallelBitmapHeapState *pstate)
     463              : {
     464              :     SharedBitmapState state;
     465              : 
     466              :     while (1)
     467              :     {
     468          256 :         SpinLockAcquire(&pstate->mutex);
     469          256 :         state = pstate->state;
     470          256 :         if (pstate->state == BM_INITIAL)
     471           48 :             pstate->state = BM_INPROGRESS;
     472          256 :         SpinLockRelease(&pstate->mutex);
     473              : 
     474              :         /* Exit if bitmap is done, or if we're the leader. */
     475          256 :         if (state != BM_INPROGRESS)
     476          228 :             break;
     477              : 
     478              :         /* Wait for the leader to wake us up. */
     479           28 :         ConditionVariableSleep(&pstate->cv, WAIT_EVENT_PARALLEL_BITMAP_SCAN);
     480              :     }
     481              : 
     482          228 :     ConditionVariableCancelSleep();
     483              : 
     484          228 :     return (state == BM_INITIAL);
     485              : }
     486              : 
     487              : /* ----------------------------------------------------------------
     488              :  *      ExecBitmapHeapEstimate
     489              :  *
     490              :  *      Compute the amount of space we'll need in the parallel
     491              :  *      query DSM, and inform pcxt->estimator about our needs.
     492              :  * ----------------------------------------------------------------
     493              :  */
     494              : void
     495           12 : ExecBitmapHeapEstimate(BitmapHeapScanState *node,
     496              :                        ParallelContext *pcxt)
     497              : {
     498           12 :     shm_toc_estimate_chunk(&pcxt->estimator,
     499              :                            MAXALIGN(sizeof(ParallelBitmapHeapState)));
     500           12 :     shm_toc_estimate_keys(&pcxt->estimator, 1);
     501           12 : }
     502              : 
     503              : /* ----------------------------------------------------------------
     504              :  *      ExecBitmapHeapInitializeDSM
     505              :  *
     506              :  *      Set up a parallel bitmap heap scan descriptor.
     507              :  * ----------------------------------------------------------------
     508              :  */
     509              : void
     510           12 : ExecBitmapHeapInitializeDSM(BitmapHeapScanState *node,
     511              :                             ParallelContext *pcxt)
     512              : {
     513              :     ParallelBitmapHeapState *pstate;
     514           12 :     dsa_area   *dsa = node->ss.ps.state->es_query_dsa;
     515              : 
     516              :     /* If there's no DSA, there are no workers; initialize nothing. */
     517           12 :     if (dsa == NULL)
     518            0 :         return;
     519              : 
     520              :     pstate = (ParallelBitmapHeapState *)
     521           12 :         shm_toc_allocate(pcxt->toc,
     522              :                          MAXALIGN(sizeof(ParallelBitmapHeapState)));
     523              : 
     524           12 :     pstate->tbmiterator = 0;
     525              : 
     526              :     /* Initialize the mutex */
     527           12 :     SpinLockInit(&pstate->mutex);
     528           12 :     pstate->state = BM_INITIAL;
     529              : 
     530           12 :     ConditionVariableInit(&pstate->cv);
     531              : 
     532           12 :     shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pstate);
     533           12 :     node->pstate = pstate;
     534              : }
     535              : 
     536              : /* ----------------------------------------------------------------
     537              :  *      ExecBitmapHeapReInitializeDSM
     538              :  *
     539              :  *      Reset shared state before beginning a fresh scan.
     540              :  * ----------------------------------------------------------------
     541              :  */
     542              : void
     543           36 : ExecBitmapHeapReInitializeDSM(BitmapHeapScanState *node,
     544              :                               ParallelContext *pcxt)
     545              : {
     546           36 :     ParallelBitmapHeapState *pstate = node->pstate;
     547           36 :     dsa_area   *dsa = node->ss.ps.state->es_query_dsa;
     548              : 
     549              :     /* If there's no DSA, there are no workers; do nothing. */
     550           36 :     if (dsa == NULL)
     551            0 :         return;
     552              : 
     553           36 :     pstate->state = BM_INITIAL;
     554              : 
     555           36 :     if (DsaPointerIsValid(pstate->tbmiterator))
     556           36 :         tbm_free_shared_area(dsa, pstate->tbmiterator);
     557              : 
     558           36 :     pstate->tbmiterator = InvalidDsaPointer;
     559              : }
     560              : 
     561              : /* ----------------------------------------------------------------
     562              :  *      ExecBitmapHeapInitializeWorker
     563              :  *
     564              :  *      Copy relevant information from TOC into planstate.
     565              :  * ----------------------------------------------------------------
     566              :  */
     567              : void
     568          180 : ExecBitmapHeapInitializeWorker(BitmapHeapScanState *node,
     569              :                                ParallelWorkerContext *pwcxt)
     570              : {
     571              :     Assert(node->ss.ps.state->es_query_dsa != NULL);
     572              : 
     573          180 :     node->pstate = (ParallelBitmapHeapState *)
     574          180 :         shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
     575          180 : }
     576              : 
     577              : /*
     578              :  * Compute the amount of space we'll need for the shared instrumentation and
     579              :  * inform pcxt->estimator.
     580              :  */
     581              : void
     582           13 : ExecBitmapHeapInstrumentEstimate(BitmapHeapScanState *node,
     583              :                                  ParallelContext *pcxt)
     584              : {
     585              :     Size        size;
     586              : 
     587           13 :     if (!node->ss.ps.instrument || pcxt->nworkers == 0)
     588           13 :         return;
     589              : 
     590            0 :     size = add_size(offsetof(SharedBitmapHeapInstrumentation, sinstrument),
     591            0 :                     mul_size(pcxt->nworkers, sizeof(BitmapHeapScanInstrumentation)));
     592            0 :     shm_toc_estimate_chunk(&pcxt->estimator, size);
     593            0 :     shm_toc_estimate_keys(&pcxt->estimator, 1);
     594              : }
     595              : 
     596              : /*
     597              :  * Set up parallel bitmap heap scan instrumentation.
     598              :  */
     599              : void
     600           13 : ExecBitmapHeapInstrumentInitDSM(BitmapHeapScanState *node,
     601              :                                 ParallelContext *pcxt)
     602              : {
     603              :     Size        size;
     604              : 
     605           13 :     if (!node->ss.ps.instrument || pcxt->nworkers == 0)
     606           13 :         return;
     607              : 
     608            0 :     size = add_size(offsetof(SharedBitmapHeapInstrumentation, sinstrument),
     609            0 :                     mul_size(pcxt->nworkers, sizeof(BitmapHeapScanInstrumentation)));
     610            0 :     node->sinstrument =
     611            0 :         (SharedBitmapHeapInstrumentation *) shm_toc_allocate(pcxt->toc, size);
     612              : 
     613              :     /* Each per-worker area must start out as zeroes */
     614            0 :     memset(node->sinstrument, 0, size);
     615            0 :     node->sinstrument->num_workers = pcxt->nworkers;
     616            0 :     shm_toc_insert(pcxt->toc,
     617            0 :                    node->ss.ps.plan->plan_node_id +
     618              :                    PARALLEL_KEY_SCAN_INSTRUMENT_OFFSET,
     619            0 :                    node->sinstrument);
     620              : }
     621              : 
     622              : /*
     623              :  * Look up and save the location of the shared instrumentation.
     624              :  */
     625              : void
     626          181 : ExecBitmapHeapInstrumentInitWorker(BitmapHeapScanState *node,
     627              :                                    ParallelWorkerContext *pwcxt)
     628              : {
     629          181 :     if (!node->ss.ps.instrument)
     630          181 :         return;
     631              : 
     632            0 :     node->sinstrument = (SharedBitmapHeapInstrumentation *)
     633            0 :         shm_toc_lookup(pwcxt->toc,
     634            0 :                        node->ss.ps.plan->plan_node_id +
     635              :                        PARALLEL_KEY_SCAN_INSTRUMENT_OFFSET,
     636              :                        false);
     637              : }
     638              : 
     639              : /* ----------------------------------------------------------------
     640              :  *      ExecBitmapHeapRetrieveInstrumentation
     641              :  *
     642              :  *      Transfer bitmap heap scan statistics from DSM to private memory.
     643              :  * ----------------------------------------------------------------
     644              :  */
     645              : void
     646            0 : ExecBitmapHeapRetrieveInstrumentation(BitmapHeapScanState *node)
     647              : {
     648            0 :     SharedBitmapHeapInstrumentation *sinstrument = node->sinstrument;
     649              :     Size        size;
     650              : 
     651            0 :     if (sinstrument == NULL)
     652            0 :         return;
     653              : 
     654            0 :     size = offsetof(SharedBitmapHeapInstrumentation, sinstrument)
     655            0 :         + sinstrument->num_workers * sizeof(BitmapHeapScanInstrumentation);
     656              : 
     657            0 :     node->sinstrument = palloc(size);
     658            0 :     memcpy(node->sinstrument, sinstrument, size);
     659              : }
        

Generated by: LCOV version 2.0-1