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