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-2024, 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 <math.h>
39 :
40 : #include "access/relscan.h"
41 : #include "access/tableam.h"
42 : #include "access/visibilitymap.h"
43 : #include "executor/executor.h"
44 : #include "executor/nodeBitmapHeapscan.h"
45 : #include "miscadmin.h"
46 : #include "pgstat.h"
47 : #include "storage/bufmgr.h"
48 : #include "utils/rel.h"
49 : #include "utils/snapmgr.h"
50 : #include "utils/spccache.h"
51 :
52 : static TupleTableSlot *BitmapHeapNext(BitmapHeapScanState *node);
53 : static inline void BitmapDoneInitializingSharedState(ParallelBitmapHeapState *pstate);
54 : static inline void BitmapAdjustPrefetchIterator(BitmapHeapScanState *node,
55 : BlockNumber blockno);
56 : static inline void BitmapAdjustPrefetchTarget(BitmapHeapScanState *node);
57 : static inline void BitmapPrefetch(BitmapHeapScanState *node,
58 : TableScanDesc scan);
59 : static bool BitmapShouldInitializeSharedState(ParallelBitmapHeapState *pstate);
60 :
61 :
62 : /* ----------------------------------------------------------------
63 : * BitmapHeapNext
64 : *
65 : * Retrieve next tuple from the BitmapHeapScan node's currentRelation
66 : * ----------------------------------------------------------------
67 : */
68 : static TupleTableSlot *
69 5768560 : BitmapHeapNext(BitmapHeapScanState *node)
70 : {
71 : ExprContext *econtext;
72 : TableScanDesc scan;
73 : TIDBitmap *tbm;
74 5768560 : TBMIterator *tbmiterator = NULL;
75 5768560 : TBMSharedIterator *shared_tbmiterator = NULL;
76 : TBMIterateResult *tbmres;
77 : TupleTableSlot *slot;
78 5768560 : ParallelBitmapHeapState *pstate = node->pstate;
79 5768560 : dsa_area *dsa = node->ss.ps.state->es_query_dsa;
80 :
81 : /*
82 : * extract necessary information from index scan node
83 : */
84 5768560 : econtext = node->ss.ps.ps_ExprContext;
85 5768560 : slot = node->ss.ss_ScanTupleSlot;
86 5768560 : scan = node->ss.ss_currentScanDesc;
87 5768560 : tbm = node->tbm;
88 5768560 : if (pstate == NULL)
89 4574218 : tbmiterator = node->tbmiterator;
90 : else
91 1194342 : shared_tbmiterator = node->shared_tbmiterator;
92 5768560 : tbmres = node->tbmres;
93 :
94 : /*
95 : * If we haven't yet performed the underlying index scan, do it, and begin
96 : * the iteration over the bitmap.
97 : *
98 : * For prefetching, we use *two* iterators, one for the pages we are
99 : * actually scanning and another that runs ahead of the first for
100 : * prefetching. node->prefetch_pages tracks exactly how many pages ahead
101 : * the prefetch iterator is. Also, node->prefetch_target tracks the
102 : * desired prefetch distance, which starts small and increases up to the
103 : * node->prefetch_maximum. This is to avoid doing a lot of prefetching in
104 : * a scan that stops after a few tuples because of a LIMIT.
105 : */
106 5768560 : if (!node->initialized)
107 : {
108 20798 : if (!pstate)
109 : {
110 20450 : tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
111 :
112 20450 : if (!tbm || !IsA(tbm, TIDBitmap))
113 0 : elog(ERROR, "unrecognized result from subplan");
114 :
115 20450 : node->tbm = tbm;
116 20450 : node->tbmiterator = tbmiterator = tbm_begin_iterate(tbm);
117 20450 : node->tbmres = tbmres = NULL;
118 :
119 : #ifdef USE_PREFETCH
120 20450 : if (node->prefetch_maximum > 0)
121 : {
122 20450 : node->prefetch_iterator = tbm_begin_iterate(tbm);
123 20450 : node->prefetch_pages = 0;
124 20450 : node->prefetch_target = -1;
125 : }
126 : #endif /* USE_PREFETCH */
127 : }
128 : else
129 : {
130 : /*
131 : * The leader will immediately come out of the function, but
132 : * others will be blocked until leader populates the TBM and wakes
133 : * them up.
134 : */
135 348 : if (BitmapShouldInitializeSharedState(pstate))
136 : {
137 72 : tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
138 72 : if (!tbm || !IsA(tbm, TIDBitmap))
139 0 : elog(ERROR, "unrecognized result from subplan");
140 :
141 72 : node->tbm = tbm;
142 :
143 : /*
144 : * Prepare to iterate over the TBM. This will return the
145 : * dsa_pointer of the iterator state which will be used by
146 : * multiple processes to iterate jointly.
147 : */
148 72 : pstate->tbmiterator = tbm_prepare_shared_iterate(tbm);
149 : #ifdef USE_PREFETCH
150 72 : if (node->prefetch_maximum > 0)
151 : {
152 72 : pstate->prefetch_iterator =
153 72 : tbm_prepare_shared_iterate(tbm);
154 :
155 : /*
156 : * We don't need the mutex here as we haven't yet woke up
157 : * others.
158 : */
159 72 : pstate->prefetch_pages = 0;
160 72 : pstate->prefetch_target = -1;
161 : }
162 : #endif
163 :
164 : /* We have initialized the shared state so wake up others. */
165 72 : BitmapDoneInitializingSharedState(pstate);
166 : }
167 :
168 : /* Allocate a private iterator and attach the shared state to it */
169 348 : node->shared_tbmiterator = shared_tbmiterator =
170 348 : tbm_attach_shared_iterate(dsa, pstate->tbmiterator);
171 348 : node->tbmres = tbmres = NULL;
172 :
173 : #ifdef USE_PREFETCH
174 348 : if (node->prefetch_maximum > 0)
175 : {
176 348 : node->shared_prefetch_iterator =
177 348 : tbm_attach_shared_iterate(dsa, pstate->prefetch_iterator);
178 : }
179 : #endif /* USE_PREFETCH */
180 : }
181 :
182 : /*
183 : * If this is the first scan of the underlying table, create the table
184 : * scan descriptor and begin the scan.
185 : */
186 20798 : if (!scan)
187 : {
188 16758 : bool need_tuples = false;
189 :
190 : /*
191 : * We can potentially skip fetching heap pages if we do not need
192 : * any columns of the table, either for checking non-indexable
193 : * quals or for returning data. This test is a bit simplistic, as
194 : * it checks the stronger condition that there's no qual or return
195 : * tlist at all. But in most cases it's probably not worth working
196 : * harder than that.
197 : */
198 29404 : need_tuples = (node->ss.ps.plan->qual != NIL ||
199 12646 : node->ss.ps.plan->targetlist != NIL);
200 :
201 16758 : scan = table_beginscan_bm(node->ss.ss_currentRelation,
202 16758 : node->ss.ps.state->es_snapshot,
203 : 0,
204 : NULL,
205 : need_tuples);
206 :
207 16758 : node->ss.ss_currentScanDesc = scan;
208 : }
209 :
210 20798 : node->initialized = true;
211 : }
212 :
213 : for (;;)
214 982760 : {
215 : bool valid_block;
216 :
217 6751320 : CHECK_FOR_INTERRUPTS();
218 :
219 : /*
220 : * Get next page of results if needed
221 : */
222 6751320 : if (tbmres == NULL)
223 : {
224 410044 : if (!pstate)
225 379588 : node->tbmres = tbmres = tbm_iterate(tbmiterator);
226 : else
227 30456 : node->tbmres = tbmres = tbm_shared_iterate(shared_tbmiterator);
228 410044 : if (tbmres == NULL)
229 : {
230 : /* no more entries in the bitmap */
231 20278 : break;
232 : }
233 :
234 389766 : BitmapAdjustPrefetchIterator(node, tbmres->blockno);
235 :
236 389766 : valid_block = table_scan_bitmap_next_block(scan, tbmres);
237 :
238 389760 : if (tbmres->ntuples >= 0)
239 232468 : node->exact_pages++;
240 : else
241 157292 : node->lossy_pages++;
242 :
243 389760 : if (!valid_block)
244 : {
245 : /* AM doesn't think this block is valid, skip */
246 6008 : continue;
247 : }
248 :
249 : /* Adjust the prefetch target */
250 383752 : BitmapAdjustPrefetchTarget(node);
251 : }
252 : else
253 : {
254 : /*
255 : * Continuing in previously obtained page.
256 : */
257 :
258 : #ifdef USE_PREFETCH
259 :
260 : /*
261 : * Try to prefetch at least a few pages even before we get to the
262 : * second page if we don't stop reading after the first tuple.
263 : */
264 6341276 : if (!pstate)
265 : {
266 5147276 : if (node->prefetch_target < node->prefetch_maximum)
267 14536 : node->prefetch_target++;
268 : }
269 1194000 : else if (pstate->prefetch_target < node->prefetch_maximum)
270 : {
271 : /* take spinlock while updating shared state */
272 1926 : SpinLockAcquire(&pstate->mutex);
273 1926 : if (pstate->prefetch_target < node->prefetch_maximum)
274 1926 : pstate->prefetch_target++;
275 1926 : SpinLockRelease(&pstate->mutex);
276 : }
277 : #endif /* USE_PREFETCH */
278 : }
279 :
280 : /*
281 : * We issue prefetch requests *after* fetching the current page to try
282 : * to avoid having prefetching interfere with the main I/O. Also, this
283 : * should happen only when we have determined there is still something
284 : * to do on the current page, else we may uselessly prefetch the same
285 : * page we are just about to request for real.
286 : */
287 6725028 : BitmapPrefetch(node, scan);
288 :
289 : /*
290 : * Attempt to fetch tuple from AM.
291 : */
292 6725028 : if (!table_scan_bitmap_next_tuple(scan, tbmres, slot))
293 : {
294 : /* nothing more to look at on this page */
295 389246 : node->tbmres = tbmres = NULL;
296 389246 : continue;
297 : }
298 :
299 : /*
300 : * If we are using lossy info, we have to recheck the qual conditions
301 : * at every tuple.
302 : */
303 6335782 : if (tbmres->recheck)
304 : {
305 3124632 : econtext->ecxt_scantuple = slot;
306 3124632 : if (!ExecQualAndReset(node->bitmapqualorig, econtext))
307 : {
308 : /* Fails recheck, so drop it and loop back for another */
309 587506 : InstrCountFiltered2(node, 1);
310 587506 : ExecClearTuple(slot);
311 587506 : continue;
312 : }
313 : }
314 :
315 : /* OK to return this tuple */
316 5748276 : return slot;
317 : }
318 :
319 : /*
320 : * if we get here it means we are at the end of the scan..
321 : */
322 20278 : return ExecClearTuple(slot);
323 : }
324 :
325 : /*
326 : * BitmapDoneInitializingSharedState - Shared state is initialized
327 : *
328 : * By this time the leader has already populated the TBM and initialized the
329 : * shared state so wake up other processes.
330 : */
331 : static inline void
332 72 : BitmapDoneInitializingSharedState(ParallelBitmapHeapState *pstate)
333 : {
334 72 : SpinLockAcquire(&pstate->mutex);
335 72 : pstate->state = BM_FINISHED;
336 72 : SpinLockRelease(&pstate->mutex);
337 72 : ConditionVariableBroadcast(&pstate->cv);
338 72 : }
339 :
340 : /*
341 : * BitmapAdjustPrefetchIterator - Adjust the prefetch iterator
342 : */
343 : static inline void
344 389766 : BitmapAdjustPrefetchIterator(BitmapHeapScanState *node,
345 : BlockNumber blockno)
346 : {
347 : #ifdef USE_PREFETCH
348 389766 : ParallelBitmapHeapState *pstate = node->pstate;
349 :
350 389766 : if (pstate == NULL)
351 : {
352 359658 : TBMIterator *prefetch_iterator = node->prefetch_iterator;
353 :
354 359658 : if (node->prefetch_pages > 0)
355 : {
356 : /* The main iterator has closed the distance by one page */
357 344394 : node->prefetch_pages--;
358 : }
359 15264 : else if (prefetch_iterator)
360 : {
361 : /* Do not let the prefetch iterator get behind the main one */
362 15264 : TBMIterateResult *tbmpre = tbm_iterate(prefetch_iterator);
363 :
364 15264 : if (tbmpre == NULL || tbmpre->blockno != blockno)
365 0 : elog(ERROR, "prefetch and main iterators are out of sync");
366 : }
367 359658 : return;
368 : }
369 :
370 30108 : if (node->prefetch_maximum > 0)
371 : {
372 30108 : TBMSharedIterator *prefetch_iterator = node->shared_prefetch_iterator;
373 :
374 30108 : SpinLockAcquire(&pstate->mutex);
375 30108 : if (pstate->prefetch_pages > 0)
376 : {
377 30036 : pstate->prefetch_pages--;
378 30036 : SpinLockRelease(&pstate->mutex);
379 : }
380 : else
381 : {
382 : /* Release the mutex before iterating */
383 72 : SpinLockRelease(&pstate->mutex);
384 :
385 : /*
386 : * In case of shared mode, we can not ensure that the current
387 : * blockno of the main iterator and that of the prefetch iterator
388 : * are same. It's possible that whatever blockno we are
389 : * prefetching will be processed by another process. Therefore,
390 : * we don't validate the blockno here as we do in non-parallel
391 : * case.
392 : */
393 72 : if (prefetch_iterator)
394 72 : tbm_shared_iterate(prefetch_iterator);
395 : }
396 : }
397 : #endif /* USE_PREFETCH */
398 : }
399 :
400 : /*
401 : * BitmapAdjustPrefetchTarget - Adjust the prefetch target
402 : *
403 : * Increase prefetch target if it's not yet at the max. Note that
404 : * we will increase it to zero after fetching the very first
405 : * page/tuple, then to one after the second tuple is fetched, then
406 : * it doubles as later pages are fetched.
407 : */
408 : static inline void
409 383752 : BitmapAdjustPrefetchTarget(BitmapHeapScanState *node)
410 : {
411 : #ifdef USE_PREFETCH
412 383752 : ParallelBitmapHeapState *pstate = node->pstate;
413 :
414 383752 : if (pstate == NULL)
415 : {
416 353644 : if (node->prefetch_target >= node->prefetch_maximum)
417 : /* don't increase any further */ ;
418 14830 : else if (node->prefetch_target >= node->prefetch_maximum / 2)
419 232 : node->prefetch_target = node->prefetch_maximum;
420 14598 : else if (node->prefetch_target > 0)
421 0 : node->prefetch_target *= 2;
422 : else
423 14598 : node->prefetch_target++;
424 353644 : return;
425 : }
426 :
427 : /* Do an unlocked check first to save spinlock acquisitions. */
428 30108 : if (pstate->prefetch_target < node->prefetch_maximum)
429 : {
430 132 : SpinLockAcquire(&pstate->mutex);
431 132 : if (pstate->prefetch_target >= node->prefetch_maximum)
432 : /* don't increase any further */ ;
433 132 : else if (pstate->prefetch_target >= node->prefetch_maximum / 2)
434 60 : pstate->prefetch_target = node->prefetch_maximum;
435 72 : else if (pstate->prefetch_target > 0)
436 0 : pstate->prefetch_target *= 2;
437 : else
438 72 : pstate->prefetch_target++;
439 132 : SpinLockRelease(&pstate->mutex);
440 : }
441 : #endif /* USE_PREFETCH */
442 : }
443 :
444 : /*
445 : * BitmapPrefetch - Prefetch, if prefetch_pages are behind prefetch_target
446 : */
447 : static inline void
448 6725028 : BitmapPrefetch(BitmapHeapScanState *node, TableScanDesc scan)
449 : {
450 : #ifdef USE_PREFETCH
451 6725028 : ParallelBitmapHeapState *pstate = node->pstate;
452 :
453 6725028 : if (pstate == NULL)
454 : {
455 5500920 : TBMIterator *prefetch_iterator = node->prefetch_iterator;
456 :
457 5500920 : if (prefetch_iterator)
458 : {
459 5749904 : while (node->prefetch_pages < node->prefetch_target)
460 : {
461 358772 : TBMIterateResult *tbmpre = tbm_iterate(prefetch_iterator);
462 : bool skip_fetch;
463 :
464 358772 : if (tbmpre == NULL)
465 : {
466 : /* No more pages to prefetch */
467 14378 : tbm_end_iterate(prefetch_iterator);
468 14378 : node->prefetch_iterator = NULL;
469 14378 : break;
470 : }
471 344394 : node->prefetch_pages++;
472 :
473 : /*
474 : * If we expect not to have to actually read this heap page,
475 : * skip this prefetch call, but continue to run the prefetch
476 : * logic normally. (Would it be better not to increment
477 : * prefetch_pages?)
478 : */
479 755274 : skip_fetch = (!(scan->rs_flags & SO_NEED_TUPLES) &&
480 376130 : !tbmpre->recheck &&
481 31736 : VM_ALL_VISIBLE(node->ss.ss_currentRelation,
482 : tbmpre->blockno,
483 : &node->pvmbuffer));
484 :
485 344394 : if (!skip_fetch)
486 344324 : PrefetchBuffer(scan->rs_rd, MAIN_FORKNUM, tbmpre->blockno);
487 : }
488 : }
489 :
490 5500920 : return;
491 : }
492 :
493 1224108 : if (pstate->prefetch_pages < pstate->prefetch_target)
494 : {
495 138846 : TBMSharedIterator *prefetch_iterator = node->shared_prefetch_iterator;
496 :
497 138846 : if (prefetch_iterator)
498 : {
499 : while (1)
500 30036 : {
501 : TBMIterateResult *tbmpre;
502 58764 : bool do_prefetch = false;
503 : bool skip_fetch;
504 :
505 : /*
506 : * Recheck under the mutex. If some other process has already
507 : * done enough prefetching then we need not to do anything.
508 : */
509 58764 : SpinLockAcquire(&pstate->mutex);
510 58764 : if (pstate->prefetch_pages < pstate->prefetch_target)
511 : {
512 30108 : pstate->prefetch_pages++;
513 30108 : do_prefetch = true;
514 : }
515 58764 : SpinLockRelease(&pstate->mutex);
516 :
517 58764 : if (!do_prefetch)
518 28656 : return;
519 :
520 30108 : tbmpre = tbm_shared_iterate(prefetch_iterator);
521 30108 : if (tbmpre == NULL)
522 : {
523 : /* No more pages to prefetch */
524 72 : tbm_end_shared_iterate(prefetch_iterator);
525 72 : node->shared_prefetch_iterator = NULL;
526 72 : break;
527 : }
528 :
529 : /* As above, skip prefetch if we expect not to need page */
530 88116 : skip_fetch = (!(scan->rs_flags & SO_NEED_TUPLES) &&
531 54984 : !tbmpre->recheck &&
532 24948 : VM_ALL_VISIBLE(node->ss.ss_currentRelation,
533 : tbmpre->blockno,
534 : &node->pvmbuffer));
535 :
536 30036 : if (!skip_fetch)
537 9396 : PrefetchBuffer(scan->rs_rd, MAIN_FORKNUM, tbmpre->blockno);
538 : }
539 : }
540 : }
541 : #endif /* USE_PREFETCH */
542 : }
543 :
544 : /*
545 : * BitmapHeapRecheck -- access method routine to recheck a tuple in EvalPlanQual
546 : */
547 : static bool
548 0 : BitmapHeapRecheck(BitmapHeapScanState *node, TupleTableSlot *slot)
549 : {
550 : ExprContext *econtext;
551 :
552 : /*
553 : * extract necessary information from index scan node
554 : */
555 0 : econtext = node->ss.ps.ps_ExprContext;
556 :
557 : /* Does the tuple meet the original qual conditions? */
558 0 : econtext->ecxt_scantuple = slot;
559 0 : return ExecQualAndReset(node->bitmapqualorig, econtext);
560 : }
561 :
562 : /* ----------------------------------------------------------------
563 : * ExecBitmapHeapScan(node)
564 : * ----------------------------------------------------------------
565 : */
566 : static TupleTableSlot *
567 5516196 : ExecBitmapHeapScan(PlanState *pstate)
568 : {
569 5516196 : BitmapHeapScanState *node = castNode(BitmapHeapScanState, pstate);
570 :
571 5516196 : return ExecScan(&node->ss,
572 : (ExecScanAccessMtd) BitmapHeapNext,
573 : (ExecScanRecheckMtd) BitmapHeapRecheck);
574 : }
575 :
576 : /* ----------------------------------------------------------------
577 : * ExecReScanBitmapHeapScan(node)
578 : * ----------------------------------------------------------------
579 : */
580 : void
581 6752 : ExecReScanBitmapHeapScan(BitmapHeapScanState *node)
582 : {
583 6752 : PlanState *outerPlan = outerPlanState(node);
584 :
585 : /* rescan to release any page pin */
586 6752 : if (node->ss.ss_currentScanDesc)
587 4040 : table_rescan(node->ss.ss_currentScanDesc, NULL);
588 :
589 : /* release bitmaps and buffers if any */
590 6752 : if (node->tbmiterator)
591 3986 : tbm_end_iterate(node->tbmiterator);
592 6752 : if (node->prefetch_iterator)
593 1354 : tbm_end_iterate(node->prefetch_iterator);
594 6752 : if (node->shared_tbmiterator)
595 54 : tbm_end_shared_iterate(node->shared_tbmiterator);
596 6752 : if (node->shared_prefetch_iterator)
597 0 : tbm_end_shared_iterate(node->shared_prefetch_iterator);
598 6752 : if (node->tbm)
599 4040 : tbm_free(node->tbm);
600 6752 : if (node->pvmbuffer != InvalidBuffer)
601 54 : ReleaseBuffer(node->pvmbuffer);
602 6752 : node->tbm = NULL;
603 6752 : node->tbmiterator = NULL;
604 6752 : node->tbmres = NULL;
605 6752 : node->prefetch_iterator = NULL;
606 6752 : node->initialized = false;
607 6752 : node->shared_tbmiterator = NULL;
608 6752 : node->shared_prefetch_iterator = NULL;
609 6752 : node->pvmbuffer = InvalidBuffer;
610 :
611 6752 : ExecScanReScan(&node->ss);
612 :
613 : /*
614 : * if chgParam of subnode is not null then plan will be re-scanned by
615 : * first ExecProcNode.
616 : */
617 6752 : if (outerPlan->chgParam == NULL)
618 192 : ExecReScan(outerPlan);
619 6752 : }
620 :
621 : /* ----------------------------------------------------------------
622 : * ExecEndBitmapHeapScan
623 : * ----------------------------------------------------------------
624 : */
625 : void
626 21238 : ExecEndBitmapHeapScan(BitmapHeapScanState *node)
627 : {
628 : TableScanDesc scanDesc;
629 :
630 : /*
631 : * extract information from the node
632 : */
633 21238 : scanDesc = node->ss.ss_currentScanDesc;
634 :
635 : /*
636 : * close down subplans
637 : */
638 21238 : ExecEndNode(outerPlanState(node));
639 :
640 : /*
641 : * release bitmaps and buffers if any
642 : */
643 21238 : if (node->tbmiterator)
644 16368 : tbm_end_iterate(node->tbmiterator);
645 21238 : if (node->prefetch_iterator)
646 4706 : tbm_end_iterate(node->prefetch_iterator);
647 21238 : if (node->tbm)
648 16386 : tbm_free(node->tbm);
649 21238 : if (node->shared_tbmiterator)
650 294 : tbm_end_shared_iterate(node->shared_tbmiterator);
651 21238 : if (node->shared_prefetch_iterator)
652 276 : tbm_end_shared_iterate(node->shared_prefetch_iterator);
653 21238 : if (node->pvmbuffer != InvalidBuffer)
654 24 : ReleaseBuffer(node->pvmbuffer);
655 :
656 : /*
657 : * close heap scan
658 : */
659 21238 : if (scanDesc)
660 16662 : table_endscan(scanDesc);
661 :
662 21238 : }
663 :
664 : /* ----------------------------------------------------------------
665 : * ExecInitBitmapHeapScan
666 : *
667 : * Initializes the scan's state information.
668 : * ----------------------------------------------------------------
669 : */
670 : BitmapHeapScanState *
671 21334 : ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
672 : {
673 : BitmapHeapScanState *scanstate;
674 : Relation currentRelation;
675 :
676 : /* check for unsupported flags */
677 : Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
678 :
679 : /*
680 : * Assert caller didn't ask for an unsafe snapshot --- see comments at
681 : * head of file.
682 : */
683 : Assert(IsMVCCSnapshot(estate->es_snapshot));
684 :
685 : /*
686 : * create state structure
687 : */
688 21334 : scanstate = makeNode(BitmapHeapScanState);
689 21334 : scanstate->ss.ps.plan = (Plan *) node;
690 21334 : scanstate->ss.ps.state = estate;
691 21334 : scanstate->ss.ps.ExecProcNode = ExecBitmapHeapScan;
692 :
693 21334 : scanstate->tbm = NULL;
694 21334 : scanstate->tbmiterator = NULL;
695 21334 : scanstate->tbmres = NULL;
696 21334 : scanstate->pvmbuffer = InvalidBuffer;
697 21334 : scanstate->exact_pages = 0;
698 21334 : scanstate->lossy_pages = 0;
699 21334 : scanstate->prefetch_iterator = NULL;
700 21334 : scanstate->prefetch_pages = 0;
701 21334 : scanstate->prefetch_target = 0;
702 21334 : scanstate->initialized = false;
703 21334 : scanstate->shared_tbmiterator = NULL;
704 21334 : scanstate->shared_prefetch_iterator = NULL;
705 21334 : scanstate->pstate = NULL;
706 :
707 : /*
708 : * Miscellaneous initialization
709 : *
710 : * create expression context for node
711 : */
712 21334 : ExecAssignExprContext(estate, &scanstate->ss.ps);
713 :
714 : /*
715 : * open the scan relation
716 : */
717 21334 : currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
718 :
719 : /*
720 : * initialize child nodes
721 : */
722 21334 : outerPlanState(scanstate) = ExecInitNode(outerPlan(node), estate, eflags);
723 :
724 : /*
725 : * get the scan type from the relation descriptor.
726 : */
727 21334 : ExecInitScanTupleSlot(estate, &scanstate->ss,
728 : RelationGetDescr(currentRelation),
729 : table_slot_callbacks(currentRelation));
730 :
731 : /*
732 : * Initialize result type and projection.
733 : */
734 21334 : ExecInitResultTypeTL(&scanstate->ss.ps);
735 21334 : ExecAssignScanProjectionInfo(&scanstate->ss);
736 :
737 : /*
738 : * initialize child expressions
739 : */
740 21334 : scanstate->ss.ps.qual =
741 21334 : ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
742 21334 : scanstate->bitmapqualorig =
743 21334 : ExecInitQual(node->bitmapqualorig, (PlanState *) scanstate);
744 :
745 : /*
746 : * Maximum number of prefetches for the tablespace if configured,
747 : * otherwise the current value of the effective_io_concurrency GUC.
748 : */
749 21334 : scanstate->prefetch_maximum =
750 21334 : get_tablespace_io_concurrency(currentRelation->rd_rel->reltablespace);
751 :
752 21334 : scanstate->ss.ss_currentRelation = currentRelation;
753 :
754 : /*
755 : * all done.
756 : */
757 21334 : return scanstate;
758 : }
759 :
760 : /*----------------
761 : * BitmapShouldInitializeSharedState
762 : *
763 : * The first process to come here and see the state to the BM_INITIAL
764 : * will become the leader for the parallel bitmap scan and will be
765 : * responsible for populating the TIDBitmap. The other processes will
766 : * be blocked by the condition variable until the leader wakes them up.
767 : * ---------------
768 : */
769 : static bool
770 348 : BitmapShouldInitializeSharedState(ParallelBitmapHeapState *pstate)
771 : {
772 : SharedBitmapState state;
773 :
774 : while (1)
775 : {
776 348 : SpinLockAcquire(&pstate->mutex);
777 348 : state = pstate->state;
778 348 : if (pstate->state == BM_INITIAL)
779 72 : pstate->state = BM_INPROGRESS;
780 348 : SpinLockRelease(&pstate->mutex);
781 :
782 : /* Exit if bitmap is done, or if we're the leader. */
783 348 : if (state != BM_INPROGRESS)
784 348 : break;
785 :
786 : /* Wait for the leader to wake us up. */
787 0 : ConditionVariableSleep(&pstate->cv, WAIT_EVENT_PARALLEL_BITMAP_SCAN);
788 : }
789 :
790 348 : ConditionVariableCancelSleep();
791 :
792 348 : return (state == BM_INITIAL);
793 : }
794 :
795 : /* ----------------------------------------------------------------
796 : * ExecBitmapHeapEstimate
797 : *
798 : * Compute the amount of space we'll need in the parallel
799 : * query DSM, and inform pcxt->estimator about our needs.
800 : * ----------------------------------------------------------------
801 : */
802 : void
803 18 : ExecBitmapHeapEstimate(BitmapHeapScanState *node,
804 : ParallelContext *pcxt)
805 : {
806 18 : shm_toc_estimate_chunk(&pcxt->estimator, sizeof(ParallelBitmapHeapState));
807 18 : shm_toc_estimate_keys(&pcxt->estimator, 1);
808 18 : }
809 :
810 : /* ----------------------------------------------------------------
811 : * ExecBitmapHeapInitializeDSM
812 : *
813 : * Set up a parallel bitmap heap scan descriptor.
814 : * ----------------------------------------------------------------
815 : */
816 : void
817 18 : ExecBitmapHeapInitializeDSM(BitmapHeapScanState *node,
818 : ParallelContext *pcxt)
819 : {
820 : ParallelBitmapHeapState *pstate;
821 18 : dsa_area *dsa = node->ss.ps.state->es_query_dsa;
822 :
823 : /* If there's no DSA, there are no workers; initialize nothing. */
824 18 : if (dsa == NULL)
825 0 : return;
826 :
827 18 : pstate = shm_toc_allocate(pcxt->toc, sizeof(ParallelBitmapHeapState));
828 :
829 18 : pstate->tbmiterator = 0;
830 18 : pstate->prefetch_iterator = 0;
831 :
832 : /* Initialize the mutex */
833 18 : SpinLockInit(&pstate->mutex);
834 18 : pstate->prefetch_pages = 0;
835 18 : pstate->prefetch_target = 0;
836 18 : pstate->state = BM_INITIAL;
837 :
838 18 : ConditionVariableInit(&pstate->cv);
839 :
840 18 : shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pstate);
841 18 : node->pstate = pstate;
842 : }
843 :
844 : /* ----------------------------------------------------------------
845 : * ExecBitmapHeapReInitializeDSM
846 : *
847 : * Reset shared state before beginning a fresh scan.
848 : * ----------------------------------------------------------------
849 : */
850 : void
851 54 : ExecBitmapHeapReInitializeDSM(BitmapHeapScanState *node,
852 : ParallelContext *pcxt)
853 : {
854 54 : ParallelBitmapHeapState *pstate = node->pstate;
855 54 : dsa_area *dsa = node->ss.ps.state->es_query_dsa;
856 :
857 : /* If there's no DSA, there are no workers; do nothing. */
858 54 : if (dsa == NULL)
859 0 : return;
860 :
861 54 : pstate->state = BM_INITIAL;
862 :
863 54 : if (DsaPointerIsValid(pstate->tbmiterator))
864 54 : tbm_free_shared_area(dsa, pstate->tbmiterator);
865 :
866 54 : if (DsaPointerIsValid(pstate->prefetch_iterator))
867 54 : tbm_free_shared_area(dsa, pstate->prefetch_iterator);
868 :
869 54 : pstate->tbmiterator = InvalidDsaPointer;
870 54 : pstate->prefetch_iterator = InvalidDsaPointer;
871 : }
872 :
873 : /* ----------------------------------------------------------------
874 : * ExecBitmapHeapInitializeWorker
875 : *
876 : * Copy relevant information from TOC into planstate.
877 : * ----------------------------------------------------------------
878 : */
879 : void
880 276 : ExecBitmapHeapInitializeWorker(BitmapHeapScanState *node,
881 : ParallelWorkerContext *pwcxt)
882 : {
883 : ParallelBitmapHeapState *pstate;
884 :
885 : Assert(node->ss.ps.state->es_query_dsa != NULL);
886 :
887 276 : pstate = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
888 276 : node->pstate = pstate;
889 276 : }
|