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-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 *
6935 tgl@sss.pgh.pa.us 69 :CBC 2916060 : BitmapHeapNext(BitmapHeapScanState *node)
70 : : {
71 : : ExprContext *econtext;
72 : : TableScanDesc scan;
73 : : TIDBitmap *tbm;
2594 74 : 2916060 : TBMIterator *tbmiterator = NULL;
75 : 2916060 : TBMSharedIterator *shared_tbmiterator = NULL;
76 : : TBMIterateResult *tbmres;
77 : : TupleTableSlot *slot;
rhaas@postgresql.org 78 : 2916060 : ParallelBitmapHeapState *pstate = node->pstate;
79 : 2916060 : dsa_area *dsa = node->ss.ps.state->es_query_dsa;
80 : :
81 : : /*
82 : : * extract necessary information from index scan node
83 : : */
6935 tgl@sss.pgh.pa.us 84 : 2916060 : econtext = node->ss.ps.ps_ExprContext;
85 : 2916060 : slot = node->ss.ss_ScanTupleSlot;
6714 86 : 2916060 : scan = node->ss.ss_currentScanDesc;
6935 87 : 2916060 : tbm = node->tbm;
2594 rhaas@postgresql.org 88 [ + + ]: 2916060 : if (pstate == NULL)
89 : 2318889 : tbmiterator = node->tbmiterator;
90 : : else
91 : 597171 : shared_tbmiterator = node->shared_tbmiterator;
6935 tgl@sss.pgh.pa.us 92 : 2916060 : 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 : : */
2594 rhaas@postgresql.org 106 [ + + ]: 2916060 : if (!node->initialized)
107 : : {
108 [ + + ]: 9319 : if (!pstate)
109 : : {
110 : 9145 : tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
111 : :
112 [ + - - + ]: 9145 : if (!tbm || !IsA(tbm, TIDBitmap))
2594 rhaas@postgresql.org 113 [ # # ]:UBC 0 : elog(ERROR, "unrecognized result from subplan");
114 : :
2594 rhaas@postgresql.org 115 :CBC 9145 : node->tbm = tbm;
116 : 9145 : node->tbmiterator = tbmiterator = tbm_begin_iterate(tbm);
117 : 9145 : node->tbmres = tbmres = NULL;
118 : :
119 : : #ifdef USE_PREFETCH
120 [ + - ]: 9145 : if (node->prefetch_maximum > 0)
121 : : {
122 : 9145 : node->prefetch_iterator = tbm_begin_iterate(tbm);
123 : 9145 : node->prefetch_pages = 0;
124 : 9145 : 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 [ + + ]: 174 : if (BitmapShouldInitializeSharedState(pstate))
136 : : {
137 : 36 : tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
138 [ + - - + ]: 36 : if (!tbm || !IsA(tbm, TIDBitmap))
2594 rhaas@postgresql.org 139 [ # # ]:UBC 0 : elog(ERROR, "unrecognized result from subplan");
140 : :
2594 rhaas@postgresql.org 141 :CBC 36 : 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 : 36 : pstate->tbmiterator = tbm_prepare_shared_iterate(tbm);
149 : : #ifdef USE_PREFETCH
150 [ + - ]: 36 : if (node->prefetch_maximum > 0)
151 : : {
152 : 36 : pstate->prefetch_iterator =
153 : 36 : 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 : 36 : pstate->prefetch_pages = 0;
160 : 36 : pstate->prefetch_target = -1;
161 : : }
162 : : #endif
163 : :
164 : : /* We have initialized the shared state so wake up others. */
165 : 36 : BitmapDoneInitializingSharedState(pstate);
166 : : }
167 : :
168 : : /* Allocate a private iterator and attach the shared state to it */
169 : 174 : node->shared_tbmiterator = shared_tbmiterator =
170 : 174 : tbm_attach_shared_iterate(dsa, pstate->tbmiterator);
171 : 174 : node->tbmres = tbmres = NULL;
172 : :
173 : : #ifdef USE_PREFETCH
174 [ + - ]: 174 : if (node->prefetch_maximum > 0)
175 : : {
176 : 174 : node->shared_prefetch_iterator =
177 : 174 : 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 : : */
8 tomas.vondra@postgre 186 [ + + ]:GNC 9319 : if (!scan)
187 : : {
7 188 : 7329 : 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 [ + + ]: 13589 : need_tuples = (node->ss.ps.plan->qual != NIL ||
199 [ + + ]: 6260 : node->ss.ps.plan->targetlist != NIL);
200 : :
8 201 : 7329 : scan = table_beginscan_bm(node->ss.ss_currentRelation,
202 : 7329 : node->ss.ps.state->es_snapshot,
203 : : 0,
204 : : NULL,
205 : : need_tuples);
206 : :
207 : 7329 : node->ss.ss_currentScanDesc = scan;
208 : : }
209 : :
2594 rhaas@postgresql.org 210 :CBC 9319 : node->initialized = true;
211 : : }
212 : :
213 : : for (;;)
6935 tgl@sss.pgh.pa.us 214 : 490313 : {
215 : : bool valid_block;
216 : :
2455 andres@anarazel.de 217 [ - + ]: 3406373 : CHECK_FOR_INTERRUPTS();
218 : :
219 : : /*
220 : : * Get next page of results if needed
221 : : */
6935 tgl@sss.pgh.pa.us 222 [ + + ]: 3406373 : if (tbmres == NULL)
223 : : {
2594 rhaas@postgresql.org 224 [ + + ]: 203710 : if (!pstate)
225 : 188482 : node->tbmres = tbmres = tbm_iterate(tbmiterator);
226 : : else
227 : 15228 : node->tbmres = tbmres = tbm_shared_iterate(shared_tbmiterator);
6935 tgl@sss.pgh.pa.us 228 [ + + ]: 203710 : if (tbmres == NULL)
229 : : {
230 : : /* no more entries in the bitmap */
231 : 9060 : break;
232 : : }
233 : :
7 tomas.vondra@postgre 234 :GNC 194650 : BitmapAdjustPrefetchIterator(node, tbmres->blockno);
235 : :
236 : 194650 : valid_block = table_scan_bitmap_next_block(scan, tbmres);
237 : :
27 heikki.linnakangas@i 238 [ + + ]:CBC 194647 : if (tbmres->ntuples >= 0)
239 : 116006 : node->exact_pages++;
240 : : else
241 : 78641 : node->lossy_pages++;
242 : :
7 tomas.vondra@postgre 243 [ + + ]:GNC 194647 : if (!valid_block)
244 : : {
245 : : /* AM doesn't think this block is valid, skip */
1841 andres@anarazel.de 246 :CBC 2259 : continue;
247 : : }
248 : :
249 : : /* Adjust the prefetch target */
2600 rhaas@postgresql.org 250 : 192388 : 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 : : */
2594 264 [ + + ]: 3202663 : if (!pstate)
265 : : {
266 [ + + ]: 2605663 : if (node->prefetch_target < node->prefetch_maximum)
267 : 7008 : node->prefetch_target++;
268 : : }
269 [ + + ]: 597000 : else if (pstate->prefetch_target < node->prefetch_maximum)
270 : : {
271 : : /* take spinlock while updating shared state */
272 [ + + ]: 865 : SpinLockAcquire(&pstate->mutex);
273 [ + - ]: 865 : if (pstate->prefetch_target < node->prefetch_maximum)
274 : 865 : pstate->prefetch_target++;
275 : 865 : 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 : : */
2600 287 : 3395051 : BitmapPrefetch(node, scan);
288 : :
289 : : /*
290 : : * Attempt to fetch tuple from AM.
291 : : */
7 tomas.vondra@postgre 292 [ + + ]:GNC 3395051 : if (!table_scan_bitmap_next_tuple(scan, tbmres, slot))
293 : : {
294 : : /* nothing more to look at on this page */
295 : 194391 : node->tbmres = tbmres = NULL;
296 : 194391 : continue;
297 : : }
298 : :
299 : : /*
300 : : * If we are using lossy info, we have to recheck the qual conditions
301 : : * at every tuple.
302 : : */
303 [ + + ]: 3200660 : if (tbmres->recheck)
304 : : {
305 : 1562226 : econtext->ecxt_scantuple = slot;
306 [ + + ]: 1562226 : if (!ExecQualAndReset(node->bitmapqualorig, econtext))
307 : : {
308 : : /* Fails recheck, so drop it and loop back for another */
309 [ - + ]: 293663 : InstrCountFiltered2(node, 1);
310 : 293663 : ExecClearTuple(slot);
1841 andres@anarazel.de 311 : 293663 : continue;
312 : : }
313 : : }
314 : :
315 : : /* OK to return this tuple */
6714 tgl@sss.pgh.pa.us 316 :CBC 2906997 : return slot;
317 : : }
318 : :
319 : : /*
320 : : * if we get here it means we are at the end of the scan..
321 : : */
322 : 9060 : 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
2594 rhaas@postgresql.org 332 : 36 : BitmapDoneInitializingSharedState(ParallelBitmapHeapState *pstate)
333 : : {
334 [ - + ]: 36 : SpinLockAcquire(&pstate->mutex);
335 : 36 : pstate->state = BM_FINISHED;
336 : 36 : SpinLockRelease(&pstate->mutex);
337 : 36 : ConditionVariableBroadcast(&pstate->cv);
338 : 36 : }
339 : :
340 : : /*
341 : : * BitmapAdjustPrefetchIterator - Adjust the prefetch iterator
342 : : */
343 : : static inline void
2600 344 : 194650 : BitmapAdjustPrefetchIterator(BitmapHeapScanState *node,
345 : : BlockNumber blockno)
346 : : {
347 : : #ifdef USE_PREFETCH
2594 348 : 194650 : ParallelBitmapHeapState *pstate = node->pstate;
349 : :
350 [ + + ]: 194650 : if (pstate == NULL)
351 : : {
352 : 179596 : TBMIterator *prefetch_iterator = node->prefetch_iterator;
353 : :
354 [ + + ]: 179596 : if (node->prefetch_pages > 0)
355 : : {
356 : : /* The main iterator has closed the distance by one page */
357 : 172230 : node->prefetch_pages--;
358 : : }
359 [ + - ]: 7366 : else if (prefetch_iterator)
360 : : {
361 : : /* Do not let the prefetch iterator get behind the main one */
362 : 7366 : TBMIterateResult *tbmpre = tbm_iterate(prefetch_iterator);
363 : :
7 tomas.vondra@postgre 364 [ + - - + ]:GNC 7366 : if (tbmpre == NULL || tbmpre->blockno != blockno)
2594 rhaas@postgresql.org 365 [ # # ]:UBC 0 : elog(ERROR, "prefetch and main iterators are out of sync");
366 : : }
2594 rhaas@postgresql.org 367 :CBC 179596 : return;
368 : : }
369 : :
370 [ + - ]: 15054 : if (node->prefetch_maximum > 0)
371 : : {
372 : 15054 : TBMSharedIterator *prefetch_iterator = node->shared_prefetch_iterator;
373 : :
374 [ + + ]: 15054 : SpinLockAcquire(&pstate->mutex);
375 [ + + ]: 15054 : if (pstate->prefetch_pages > 0)
376 : : {
2567 377 : 15016 : pstate->prefetch_pages--;
2594 378 : 15016 : SpinLockRelease(&pstate->mutex);
379 : : }
380 : : else
381 : : {
382 : : /* Release the mutex before iterating */
383 : 38 : 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 [ + - ]: 38 : if (prefetch_iterator)
394 : 38 : 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
2600 409 : 192388 : BitmapAdjustPrefetchTarget(BitmapHeapScanState *node)
410 : : {
411 : : #ifdef USE_PREFETCH
2594 412 : 192388 : ParallelBitmapHeapState *pstate = node->pstate;
413 : :
414 [ + + ]: 192388 : if (pstate == NULL)
415 : : {
416 [ + + ]: 177334 : if (node->prefetch_target >= node->prefetch_maximum)
417 : : /* don't increase any further */ ;
418 [ + + ]: 7167 : else if (node->prefetch_target >= node->prefetch_maximum / 2)
419 : 110 : node->prefetch_target = node->prefetch_maximum;
420 [ - + ]: 7057 : else if (node->prefetch_target > 0)
2594 rhaas@postgresql.org 421 :UBC 0 : node->prefetch_target *= 2;
422 : : else
2594 rhaas@postgresql.org 423 :CBC 7057 : node->prefetch_target++;
424 : 177334 : return;
425 : : }
426 : :
427 : : /* Do an unlocked check first to save spinlock acquisitions. */
428 [ + + ]: 15054 : if (pstate->prefetch_target < node->prefetch_maximum)
429 : : {
430 [ - + ]: 72 : SpinLockAcquire(&pstate->mutex);
431 [ + - ]: 72 : if (pstate->prefetch_target >= node->prefetch_maximum)
432 : : /* don't increase any further */ ;
433 [ + + ]: 72 : else if (pstate->prefetch_target >= node->prefetch_maximum / 2)
434 : 33 : pstate->prefetch_target = node->prefetch_maximum;
435 [ + + ]: 39 : else if (pstate->prefetch_target > 0)
436 : 3 : pstate->prefetch_target *= 2;
437 : : else
438 : 36 : pstate->prefetch_target++;
439 : 72 : 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
1861 andres@anarazel.de 448 : 3395051 : BitmapPrefetch(BitmapHeapScanState *node, TableScanDesc scan)
449 : : {
450 : : #ifdef USE_PREFETCH
2594 rhaas@postgresql.org 451 : 3395051 : ParallelBitmapHeapState *pstate = node->pstate;
452 : :
453 [ + + ]: 3395051 : if (pstate == NULL)
454 : : {
455 : 2782997 : TBMIterator *prefetch_iterator = node->prefetch_iterator;
456 : :
457 [ + + ]: 2782997 : if (prefetch_iterator)
458 : : {
459 [ + + ]: 5641211 : while (node->prefetch_pages < node->prefetch_target)
460 : : {
461 : 179165 : TBMIterateResult *tbmpre = tbm_iterate(prefetch_iterator);
462 : : bool skip_fetch;
463 : :
464 [ + + ]: 179165 : if (tbmpre == NULL)
465 : : {
466 : : /* No more pages to prefetch */
467 : 6934 : tbm_end_iterate(prefetch_iterator);
468 : 6934 : node->prefetch_iterator = NULL;
469 : 6934 : break;
470 : : }
471 : 172231 : 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 : : */
7 tomas.vondra@postgre 479 :GNC 377692 : skip_fetch = (!(scan->rs_flags & SO_NEED_TUPLES) &&
480 [ + + + + ]: 188091 : !tbmpre->recheck &&
2356 tgl@sss.pgh.pa.us 481 [ + + ]:CBC 15860 : VM_ALL_VISIBLE(node->ss.ss_currentRelation,
482 : : tbmpre->blockno,
483 : : &node->pvmbuffer));
484 : :
485 [ + + ]: 172231 : if (!skip_fetch)
486 : 172204 : PrefetchBuffer(scan->rs_rd, MAIN_FORKNUM, tbmpre->blockno);
487 : : }
488 : : }
489 : :
2594 rhaas@postgresql.org 490 : 2782997 : return;
491 : : }
492 : :
493 [ + + ]: 612054 : if (pstate->prefetch_pages < pstate->prefetch_target)
494 : : {
495 : 71819 : TBMSharedIterator *prefetch_iterator = node->shared_prefetch_iterator;
496 : :
497 [ + + ]: 71819 : if (prefetch_iterator)
498 : : {
499 : : while (1)
2600 500 : 15016 : {
501 : : TBMIterateResult *tbmpre;
2594 502 : 32779 : 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 [ + + ]: 32779 : SpinLockAcquire(&pstate->mutex);
510 [ + + ]: 32779 : if (pstate->prefetch_pages < pstate->prefetch_target)
511 : : {
512 : 15182 : pstate->prefetch_pages++;
513 : 15182 : do_prefetch = true;
514 : : }
515 : 32779 : SpinLockRelease(&pstate->mutex);
516 : :
517 [ + + ]: 32779 : if (!do_prefetch)
518 : 17597 : return;
519 : :
520 : 15182 : tbmpre = tbm_shared_iterate(prefetch_iterator);
521 [ + + ]: 15182 : if (tbmpre == NULL)
522 : : {
523 : : /* No more pages to prefetch */
524 : 166 : tbm_end_shared_iterate(prefetch_iterator);
525 : 166 : node->shared_prefetch_iterator = NULL;
526 : 166 : break;
527 : : }
528 : :
529 : : /* As above, skip prefetch if we expect not to need page */
7 tomas.vondra@postgre 530 :GNC 44052 : skip_fetch = (!(scan->rs_flags & SO_NEED_TUPLES) &&
531 [ + + + + ]: 27488 : !tbmpre->recheck &&
2356 tgl@sss.pgh.pa.us 532 [ + + ]:CBC 12472 : VM_ALL_VISIBLE(node->ss.ss_currentRelation,
533 : : tbmpre->blockno,
534 : : &node->pvmbuffer));
535 : :
536 [ + + ]: 15016 : if (!skip_fetch)
537 : 4696 : 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
5284 tgl@sss.pgh.pa.us 548 :UBC 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;
2267 andres@anarazel.de 559 : 0 : return ExecQualAndReset(node->bitmapqualorig, econtext);
560 : : }
561 : :
562 : : /* ----------------------------------------------------------------
563 : : * ExecBitmapHeapScan(node)
564 : : * ----------------------------------------------------------------
565 : : */
566 : : static TupleTableSlot *
2463 andres@anarazel.de 567 :CBC 2789494 : ExecBitmapHeapScan(PlanState *pstate)
568 : : {
569 : 2789494 : BitmapHeapScanState *node = castNode(BitmapHeapScanState, pstate);
570 : :
5284 tgl@sss.pgh.pa.us 571 : 2789494 : return ExecScan(&node->ss,
572 : : (ExecScanAccessMtd) BitmapHeapNext,
573 : : (ExecScanRecheckMtd) BitmapHeapRecheck);
574 : : }
575 : :
576 : : /* ----------------------------------------------------------------
577 : : * ExecReScanBitmapHeapScan(node)
578 : : * ----------------------------------------------------------------
579 : : */
580 : : void
5025 581 : 2259 : ExecReScanBitmapHeapScan(BitmapHeapScanState *node)
582 : : {
3249 bruce@momjian.us 583 : 2259 : PlanState *outerPlan = outerPlanState(node);
584 : :
585 : : /* rescan to release any page pin */
8 tomas.vondra@postgre 586 [ + + ]:GNC 2259 : if (node->ss.ss_currentScanDesc)
587 : 1990 : table_rescan(node->ss.ss_currentScanDesc, NULL);
588 : :
589 : : /* release bitmaps and buffers if any */
5573 tgl@sss.pgh.pa.us 590 [ + + ]:CBC 2259 : if (node->tbmiterator)
591 : 1963 : tbm_end_iterate(node->tbmiterator);
5571 592 [ + + ]: 2259 : if (node->prefetch_iterator)
593 : 659 : tbm_end_iterate(node->prefetch_iterator);
2594 rhaas@postgresql.org 594 [ + + ]: 2259 : if (node->shared_tbmiterator)
595 : 27 : tbm_end_shared_iterate(node->shared_tbmiterator);
596 [ - + ]: 2259 : if (node->shared_prefetch_iterator)
2594 rhaas@postgresql.org 597 :LBC (1) : tbm_end_shared_iterate(node->shared_prefetch_iterator);
6935 tgl@sss.pgh.pa.us 598 [ + + ]:CBC 2259 : if (node->tbm)
599 : 1990 : tbm_free(node->tbm);
2356 600 [ + + ]: 2259 : if (node->pvmbuffer != InvalidBuffer)
601 : 27 : ReleaseBuffer(node->pvmbuffer);
6935 602 : 2259 : node->tbm = NULL;
5573 603 : 2259 : node->tbmiterator = NULL;
6935 604 : 2259 : node->tbmres = NULL;
5571 605 : 2259 : node->prefetch_iterator = NULL;
2594 rhaas@postgresql.org 606 : 2259 : node->initialized = false;
607 : 2259 : node->shared_tbmiterator = NULL;
608 : 2259 : node->shared_prefetch_iterator = NULL;
2356 tgl@sss.pgh.pa.us 609 : 2259 : node->pvmbuffer = InvalidBuffer;
610 : :
5284 611 : 2259 : ExecScanReScan(&node->ss);
612 : :
613 : : /*
614 : : * if chgParam of subnode is not null then plan will be re-scanned by
615 : : * first ExecProcNode.
616 : : */
3268 rhaas@postgresql.org 617 [ + + ]: 2259 : if (outerPlan->chgParam == NULL)
618 : 94 : ExecReScan(outerPlan);
6935 tgl@sss.pgh.pa.us 619 : 2259 : }
620 : :
621 : : /* ----------------------------------------------------------------
622 : : * ExecEndBitmapHeapScan
623 : : * ----------------------------------------------------------------
624 : : */
625 : : void
626 : 9453 : ExecEndBitmapHeapScan(BitmapHeapScanState *node)
627 : : {
628 : : TableScanDesc scanDesc;
629 : :
630 : : /*
631 : : * extract information from the node
632 : : */
633 : 9453 : scanDesc = node->ss.ss_currentScanDesc;
634 : :
635 : : /*
636 : : * close down subplans
637 : : */
638 : 9453 : ExecEndNode(outerPlanState(node));
639 : :
640 : : /*
641 : : * release bitmaps and buffers if any
642 : : */
5573 643 [ + + ]: 9453 : if (node->tbmiterator)
644 : 7135 : tbm_end_iterate(node->tbmiterator);
5571 645 [ + + ]: 9453 : if (node->prefetch_iterator)
646 : 1545 : tbm_end_iterate(node->prefetch_iterator);
6935 647 [ + + ]: 9453 : if (node->tbm)
648 : 7144 : tbm_free(node->tbm);
2594 rhaas@postgresql.org 649 [ + + ]: 9453 : if (node->shared_tbmiterator)
650 : 147 : tbm_end_shared_iterate(node->shared_tbmiterator);
651 [ + + ]: 9453 : if (node->shared_prefetch_iterator)
652 : 8 : tbm_end_shared_iterate(node->shared_prefetch_iterator);
2356 tgl@sss.pgh.pa.us 653 [ + + ]: 9453 : if (node->pvmbuffer != InvalidBuffer)
654 : 130 : ReleaseBuffer(node->pvmbuffer);
655 : :
656 : : /*
657 : : * close heap scan
658 : : */
8 tomas.vondra@postgre 659 [ + + ]:GNC 9453 : if (scanDesc)
660 : 7282 : table_endscan(scanDesc);
661 : :
6935 tgl@sss.pgh.pa.us 662 :CBC 9453 : }
663 : :
664 : : /* ----------------------------------------------------------------
665 : : * ExecInitBitmapHeapScan
666 : : *
667 : : * Initializes the scan's state information.
668 : : * ----------------------------------------------------------------
669 : : */
670 : : BitmapHeapScanState *
6620 671 : 9500 : ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
672 : : {
673 : : BitmapHeapScanState *scanstate;
674 : : Relation currentRelation;
675 : :
676 : : /* check for unsupported flags */
677 [ - + ]: 9500 : 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 : : */
6714 683 [ - + - - ]: 9500 : Assert(IsMVCCSnapshot(estate->es_snapshot));
684 : :
685 : : /*
686 : : * create state structure
687 : : */
6935 688 : 9500 : scanstate = makeNode(BitmapHeapScanState);
689 : 9500 : scanstate->ss.ps.plan = (Plan *) node;
690 : 9500 : scanstate->ss.ps.state = estate;
2463 andres@anarazel.de 691 : 9500 : scanstate->ss.ps.ExecProcNode = ExecBitmapHeapScan;
692 : :
6935 tgl@sss.pgh.pa.us 693 : 9500 : scanstate->tbm = NULL;
5573 694 : 9500 : scanstate->tbmiterator = NULL;
6935 695 : 9500 : scanstate->tbmres = NULL;
2356 696 : 9500 : scanstate->pvmbuffer = InvalidBuffer;
3744 rhaas@postgresql.org 697 : 9500 : scanstate->exact_pages = 0;
698 : 9500 : scanstate->lossy_pages = 0;
5571 tgl@sss.pgh.pa.us 699 : 9500 : scanstate->prefetch_iterator = NULL;
700 : 9500 : scanstate->prefetch_pages = 0;
701 : 9500 : scanstate->prefetch_target = 0;
2594 rhaas@postgresql.org 702 : 9500 : scanstate->initialized = false;
703 : 9500 : scanstate->shared_tbmiterator = NULL;
2356 tgl@sss.pgh.pa.us 704 : 9500 : scanstate->shared_prefetch_iterator = NULL;
2594 rhaas@postgresql.org 705 : 9500 : scanstate->pstate = NULL;
706 : :
707 : : /*
708 : : * Miscellaneous initialization
709 : : *
710 : : * create expression context for node
711 : : */
6935 tgl@sss.pgh.pa.us 712 : 9500 : ExecAssignExprContext(estate, &scanstate->ss.ps);
713 : :
714 : : /*
715 : : * open the scan relation
716 : : */
2249 andres@anarazel.de 717 : 9500 : currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
718 : :
719 : : /*
720 : : * initialize child nodes
721 : : */
722 : 9500 : outerPlanState(scanstate) = ExecInitNode(outerPlan(node), estate, eflags);
723 : :
724 : : /*
725 : : * get the scan type from the relation descriptor.
726 : : */
727 : 9500 : ExecInitScanTupleSlot(estate, &scanstate->ss,
728 : : RelationGetDescr(currentRelation),
729 : : table_slot_callbacks(currentRelation));
730 : :
731 : : /*
732 : : * Initialize result type and projection.
733 : : */
1983 734 : 9500 : ExecInitResultTypeTL(&scanstate->ss.ps);
2249 735 : 9500 : ExecAssignScanProjectionInfo(&scanstate->ss);
736 : :
737 : : /*
738 : : * initialize child expressions
739 : : */
740 : 9500 : scanstate->ss.ps.qual =
741 : 9500 : ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
742 : 9500 : scanstate->bitmapqualorig =
743 : 9500 : 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 : : */
1490 tmunro@postgresql.or 749 : 9500 : scanstate->prefetch_maximum =
3141 alvherre@alvh.no-ip. 750 : 9500 : get_tablespace_io_concurrency(currentRelation->rd_rel->reltablespace);
751 : :
6935 tgl@sss.pgh.pa.us 752 : 9500 : scanstate->ss.ss_currentRelation = currentRelation;
753 : :
754 : : /*
755 : : * all done.
756 : : */
757 : 9500 : 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
2594 rhaas@postgresql.org 770 : 174 : BitmapShouldInitializeSharedState(ParallelBitmapHeapState *pstate)
771 : : {
772 : : SharedBitmapState state;
773 : :
774 : : while (1)
775 : : {
776 [ + + ]: 198 : SpinLockAcquire(&pstate->mutex);
777 : 198 : state = pstate->state;
778 [ + + ]: 198 : if (pstate->state == BM_INITIAL)
779 : 36 : pstate->state = BM_INPROGRESS;
780 : 198 : SpinLockRelease(&pstate->mutex);
781 : :
782 : : /* Exit if bitmap is done, or if we're the leader. */
783 [ + + ]: 198 : if (state != BM_INPROGRESS)
784 : 174 : break;
785 : :
786 : : /* Wait for the leader to wake us up. */
787 : 24 : ConditionVariableSleep(&pstate->cv, WAIT_EVENT_PARALLEL_BITMAP_SCAN);
788 : : }
789 : :
790 : 174 : ConditionVariableCancelSleep();
791 : :
792 : 174 : 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 : 9 : ExecBitmapHeapEstimate(BitmapHeapScanState *node,
804 : : ParallelContext *pcxt)
805 : : {
31 heikki.linnakangas@i 806 :GNC 9 : shm_toc_estimate_chunk(&pcxt->estimator, sizeof(ParallelBitmapHeapState));
2594 rhaas@postgresql.org 807 :CBC 9 : shm_toc_estimate_keys(&pcxt->estimator, 1);
808 : 9 : }
809 : :
810 : : /* ----------------------------------------------------------------
811 : : * ExecBitmapHeapInitializeDSM
812 : : *
813 : : * Set up a parallel bitmap heap scan descriptor.
814 : : * ----------------------------------------------------------------
815 : : */
816 : : void
817 : 9 : ExecBitmapHeapInitializeDSM(BitmapHeapScanState *node,
818 : : ParallelContext *pcxt)
819 : : {
820 : : ParallelBitmapHeapState *pstate;
2329 821 : 9 : dsa_area *dsa = node->ss.ps.state->es_query_dsa;
822 : :
823 : : /* If there's no DSA, there are no workers; initialize nothing. */
824 [ - + ]: 9 : if (dsa == NULL)
2329 rhaas@postgresql.org 825 :UBC 0 : return;
826 : :
31 heikki.linnakangas@i 827 :GNC 9 : pstate = shm_toc_allocate(pcxt->toc, sizeof(ParallelBitmapHeapState));
828 : :
2594 rhaas@postgresql.org 829 :CBC 9 : pstate->tbmiterator = 0;
830 : 9 : pstate->prefetch_iterator = 0;
831 : :
832 : : /* Initialize the mutex */
833 : 9 : SpinLockInit(&pstate->mutex);
834 : 9 : pstate->prefetch_pages = 0;
835 : 9 : pstate->prefetch_target = 0;
836 : 9 : pstate->state = BM_INITIAL;
837 : :
838 : 9 : ConditionVariableInit(&pstate->cv);
839 : :
840 : 9 : shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pstate);
841 : 9 : node->pstate = pstate;
842 : : }
843 : :
844 : : /* ----------------------------------------------------------------
845 : : * ExecBitmapHeapReInitializeDSM
846 : : *
847 : : * Reset shared state before beginning a fresh scan.
848 : : * ----------------------------------------------------------------
849 : : */
850 : : void
2419 tgl@sss.pgh.pa.us 851 : 27 : ExecBitmapHeapReInitializeDSM(BitmapHeapScanState *node,
852 : : ParallelContext *pcxt)
853 : : {
854 : 27 : ParallelBitmapHeapState *pstate = node->pstate;
855 : 27 : dsa_area *dsa = node->ss.ps.state->es_query_dsa;
856 : :
857 : : /* If there's no DSA, there are no workers; do nothing. */
2329 rhaas@postgresql.org 858 [ - + ]: 27 : if (dsa == NULL)
2329 rhaas@postgresql.org 859 :UBC 0 : return;
860 : :
2419 tgl@sss.pgh.pa.us 861 :CBC 27 : pstate->state = BM_INITIAL;
862 : :
863 [ + - ]: 27 : if (DsaPointerIsValid(pstate->tbmiterator))
864 : 27 : tbm_free_shared_area(dsa, pstate->tbmiterator);
865 : :
866 [ + - ]: 27 : if (DsaPointerIsValid(pstate->prefetch_iterator))
867 : 27 : tbm_free_shared_area(dsa, pstate->prefetch_iterator);
868 : :
869 : 27 : pstate->tbmiterator = InvalidDsaPointer;
870 : 27 : pstate->prefetch_iterator = InvalidDsaPointer;
871 : : }
872 : :
873 : : /* ----------------------------------------------------------------
874 : : * ExecBitmapHeapInitializeWorker
875 : : *
876 : : * Copy relevant information from TOC into planstate.
877 : : * ----------------------------------------------------------------
878 : : */
879 : : void
2341 andres@anarazel.de 880 : 138 : ExecBitmapHeapInitializeWorker(BitmapHeapScanState *node,
881 : : ParallelWorkerContext *pwcxt)
882 : : {
883 : : ParallelBitmapHeapState *pstate;
884 : :
2329 rhaas@postgresql.org 885 [ - + ]: 138 : Assert(node->ss.ps.state->es_query_dsa != NULL);
886 : :
2341 andres@anarazel.de 887 : 138 : pstate = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
2594 rhaas@postgresql.org 888 : 138 : node->pstate = pstate;
889 : 138 : }
|