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