PostgreSQL Source Code git master
nodeBitmapHeapscan.c File Reference
#include "postgres.h"
#include <math.h>
#include "access/relscan.h"
#include "access/tableam.h"
#include "access/visibilitymap.h"
#include "executor/executor.h"
#include "executor/nodeBitmapHeapscan.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "storage/bufmgr.h"
#include "utils/rel.h"
#include "utils/spccache.h"
Include dependency graph for nodeBitmapHeapscan.c:

Go to the source code of this file.

Functions

static TupleTableSlotBitmapHeapNext (BitmapHeapScanState *node)
 
static void BitmapDoneInitializingSharedState (ParallelBitmapHeapState *pstate)
 
static void BitmapAdjustPrefetchIterator (BitmapHeapScanState *node)
 
static void BitmapAdjustPrefetchTarget (BitmapHeapScanState *node)
 
static void BitmapPrefetch (BitmapHeapScanState *node, TableScanDesc scan)
 
static bool BitmapShouldInitializeSharedState (ParallelBitmapHeapState *pstate)
 
static bool BitmapHeapRecheck (BitmapHeapScanState *node, TupleTableSlot *slot)
 
static TupleTableSlotExecBitmapHeapScan (PlanState *pstate)
 
void ExecReScanBitmapHeapScan (BitmapHeapScanState *node)
 
void ExecEndBitmapHeapScan (BitmapHeapScanState *node)
 
BitmapHeapScanStateExecInitBitmapHeapScan (BitmapHeapScan *node, EState *estate, int eflags)
 
void ExecBitmapHeapEstimate (BitmapHeapScanState *node, ParallelContext *pcxt)
 
void ExecBitmapHeapInitializeDSM (BitmapHeapScanState *node, ParallelContext *pcxt)
 
void ExecBitmapHeapReInitializeDSM (BitmapHeapScanState *node, ParallelContext *pcxt)
 
void ExecBitmapHeapInitializeWorker (BitmapHeapScanState *node, ParallelWorkerContext *pwcxt)
 
void ExecBitmapHeapRetrieveInstrumentation (BitmapHeapScanState *node)
 

Function Documentation

◆ BitmapAdjustPrefetchIterator()

static void BitmapAdjustPrefetchIterator ( BitmapHeapScanState node)
inlinestatic

Definition at line 308 of file nodeBitmapHeapscan.c.

309{
310#ifdef USE_PREFETCH
311 ParallelBitmapHeapState *pstate = node->pstate;
312 TBMIterateResult *tbmpre;
313
314 if (pstate == NULL)
315 {
316 TBMIterator *prefetch_iterator = &node->prefetch_iterator;
317
318 if (node->prefetch_pages > 0)
319 {
320 /* The main iterator has closed the distance by one page */
321 node->prefetch_pages--;
322 }
323 else if (!tbm_exhausted(prefetch_iterator))
324 {
325 tbmpre = tbm_iterate(prefetch_iterator);
326 node->prefetch_blockno = tbmpre ? tbmpre->blockno :
328 }
329 return;
330 }
331
332 /*
333 * XXX: There is a known issue with keeping the prefetch and current block
334 * iterators in sync for parallel bitmap table scans. This can lead to
335 * prefetching blocks that have already been read. See the discussion
336 * here:
337 * https://postgr.es/m/20240315211449.en2jcmdqxv5o6tlz%40alap3.anarazel.de
338 * Note that moving the call site of BitmapAdjustPrefetchIterator()
339 * exacerbates the effects of this bug.
340 */
341 if (node->prefetch_maximum > 0)
342 {
343 TBMIterator *prefetch_iterator = &node->prefetch_iterator;
344
345 SpinLockAcquire(&pstate->mutex);
346 if (pstate->prefetch_pages > 0)
347 {
348 pstate->prefetch_pages--;
349 SpinLockRelease(&pstate->mutex);
350 }
351 else
352 {
353 /* Release the mutex before iterating */
354 SpinLockRelease(&pstate->mutex);
355
356 /*
357 * In case of shared mode, we can not ensure that the current
358 * blockno of the main iterator and that of the prefetch iterator
359 * are same. It's possible that whatever blockno we are
360 * prefetching will be processed by another process. Therefore,
361 * we don't validate the blockno here as we do in non-parallel
362 * case.
363 */
364 if (!tbm_exhausted(prefetch_iterator))
365 {
366 tbmpre = tbm_iterate(prefetch_iterator);
367 node->prefetch_blockno = tbmpre ? tbmpre->blockno :
369 }
370 }
371 }
372#endif /* USE_PREFETCH */
373}
#define InvalidBlockNumber
Definition: block.h:33
#define SpinLockRelease(lock)
Definition: spin.h:61
#define SpinLockAcquire(lock)
Definition: spin.h:59
ParallelBitmapHeapState * pstate
Definition: execnodes.h:1875
BlockNumber prefetch_blockno
Definition: execnodes.h:1879
TBMIterator prefetch_iterator
Definition: execnodes.h:1870
BlockNumber blockno
Definition: tidbitmap.h:56
TBMIterateResult * tbm_iterate(TBMIterator *iterator)
Definition: tidbitmap.c:1614
static bool tbm_exhausted(TBMIterator *iterator)
Definition: tidbitmap.h:96

References TBMIterateResult::blockno, InvalidBlockNumber, ParallelBitmapHeapState::mutex, BitmapHeapScanState::prefetch_blockno, BitmapHeapScanState::prefetch_iterator, BitmapHeapScanState::prefetch_maximum, ParallelBitmapHeapState::prefetch_pages, BitmapHeapScanState::prefetch_pages, BitmapHeapScanState::pstate, SpinLockAcquire, SpinLockRelease, tbm_exhausted(), and tbm_iterate().

Referenced by BitmapHeapNext().

◆ BitmapAdjustPrefetchTarget()

static void BitmapAdjustPrefetchTarget ( BitmapHeapScanState node)
inlinestatic

Definition at line 384 of file nodeBitmapHeapscan.c.

385{
386#ifdef USE_PREFETCH
387 ParallelBitmapHeapState *pstate = node->pstate;
388
389 if (pstate == NULL)
390 {
391 if (node->prefetch_target >= node->prefetch_maximum)
392 /* don't increase any further */ ;
393 else if (node->prefetch_target >= node->prefetch_maximum / 2)
394 node->prefetch_target = node->prefetch_maximum;
395 else if (node->prefetch_target > 0)
396 node->prefetch_target *= 2;
397 else
398 node->prefetch_target++;
399 return;
400 }
401
402 /* Do an unlocked check first to save spinlock acquisitions. */
403 if (pstate->prefetch_target < node->prefetch_maximum)
404 {
405 SpinLockAcquire(&pstate->mutex);
406 if (pstate->prefetch_target >= node->prefetch_maximum)
407 /* don't increase any further */ ;
408 else if (pstate->prefetch_target >= node->prefetch_maximum / 2)
409 pstate->prefetch_target = node->prefetch_maximum;
410 else if (pstate->prefetch_target > 0)
411 pstate->prefetch_target *= 2;
412 else
413 pstate->prefetch_target++;
414 SpinLockRelease(&pstate->mutex);
415 }
416#endif /* USE_PREFETCH */
417}

References ParallelBitmapHeapState::mutex, BitmapHeapScanState::prefetch_maximum, ParallelBitmapHeapState::prefetch_target, BitmapHeapScanState::prefetch_target, BitmapHeapScanState::pstate, SpinLockAcquire, and SpinLockRelease.

Referenced by BitmapHeapNext().

◆ BitmapDoneInitializingSharedState()

static void BitmapDoneInitializingSharedState ( ParallelBitmapHeapState pstate)
inlinestatic

Definition at line 292 of file nodeBitmapHeapscan.c.

293{
294 SpinLockAcquire(&pstate->mutex);
295 pstate->state = BM_FINISHED;
296 SpinLockRelease(&pstate->mutex);
298}
void ConditionVariableBroadcast(ConditionVariable *cv)
@ BM_FINISHED
Definition: execnodes.h:1804
SharedBitmapState state
Definition: execnodes.h:1826
ConditionVariable cv
Definition: execnodes.h:1827

References BM_FINISHED, ConditionVariableBroadcast(), ParallelBitmapHeapState::cv, ParallelBitmapHeapState::mutex, SpinLockAcquire, SpinLockRelease, and ParallelBitmapHeapState::state.

Referenced by BitmapHeapNext().

◆ BitmapHeapNext()

static TupleTableSlot * BitmapHeapNext ( BitmapHeapScanState node)
static

Definition at line 67 of file nodeBitmapHeapscan.c.

68{
69 ExprContext *econtext;
70 TableScanDesc scan;
71 TIDBitmap *tbm;
72 TupleTableSlot *slot;
73 ParallelBitmapHeapState *pstate = node->pstate;
74 dsa_area *dsa = node->ss.ps.state->es_query_dsa;
75
76 /*
77 * extract necessary information from index scan node
78 */
79 econtext = node->ss.ps.ps_ExprContext;
80 slot = node->ss.ss_ScanTupleSlot;
81 scan = node->ss.ss_currentScanDesc;
82 tbm = node->tbm;
83
84 /*
85 * If we haven't yet performed the underlying index scan, do it, and begin
86 * the iteration over the bitmap.
87 *
88 * For prefetching, we use *two* iterators, one for the pages we are
89 * actually scanning and another that runs ahead of the first for
90 * prefetching. node->prefetch_pages tracks exactly how many pages ahead
91 * the prefetch iterator is. Also, node->prefetch_target tracks the
92 * desired prefetch distance, which starts small and increases up to the
93 * node->prefetch_maximum. This is to avoid doing a lot of prefetching in
94 * a scan that stops after a few tuples because of a LIMIT.
95 */
96 if (!node->initialized)
97 {
98 TBMIterator tbmiterator;
99
100 if (!pstate)
101 {
103
104 if (!tbm || !IsA(tbm, TIDBitmap))
105 elog(ERROR, "unrecognized result from subplan");
106
107 node->tbm = tbm;
108 }
109 else if (BitmapShouldInitializeSharedState(pstate))
110 {
111 /*
112 * The leader will immediately come out of the function, but
113 * others will be blocked until leader populates the TBM and wakes
114 * them up.
115 */
117 if (!tbm || !IsA(tbm, TIDBitmap))
118 elog(ERROR, "unrecognized result from subplan");
119
120 node->tbm = tbm;
121
122 /*
123 * Prepare to iterate over the TBM. This will return the
124 * dsa_pointer of the iterator state which will be used by
125 * multiple processes to iterate jointly.
126 */
128
129#ifdef USE_PREFETCH
130 if (node->prefetch_maximum > 0)
131 {
132 pstate->prefetch_iterator =
134 }
135#endif /* USE_PREFETCH */
136
137 /* We have initialized the shared state so wake up others. */
139 }
140
141 tbmiterator = tbm_begin_iterate(tbm, dsa,
142 pstate ?
143 pstate->tbmiterator :
145
146#ifdef USE_PREFETCH
147 if (node->prefetch_maximum > 0)
148 node->prefetch_iterator =
149 tbm_begin_iterate(tbm, dsa,
150 pstate ?
151 pstate->prefetch_iterator :
153#endif /* USE_PREFETCH */
154
155 /*
156 * If this is the first scan of the underlying table, create the table
157 * scan descriptor and begin the scan.
158 */
159 if (!scan)
160 {
161 bool need_tuples = false;
162
163 /*
164 * We can potentially skip fetching heap pages if we do not need
165 * any columns of the table, either for checking non-indexable
166 * quals or for returning data. This test is a bit simplistic, as
167 * it checks the stronger condition that there's no qual or return
168 * tlist at all. But in most cases it's probably not worth working
169 * harder than that.
170 */
171 need_tuples = (node->ss.ps.plan->qual != NIL ||
172 node->ss.ps.plan->targetlist != NIL);
173
175 node->ss.ps.state->es_snapshot,
176 0,
177 NULL,
178 need_tuples);
179
180 node->ss.ss_currentScanDesc = scan;
181 }
182
183 scan->st.rs_tbmiterator = tbmiterator;
184 node->initialized = true;
185
186 goto new_page;
187 }
188
189 for (;;)
190 {
191 while (table_scan_bitmap_next_tuple(scan, slot))
192 {
193 /*
194 * Continuing in previously obtained page.
195 */
196
198
199#ifdef USE_PREFETCH
200
201 /*
202 * Try to prefetch at least a few pages even before we get to the
203 * second page if we don't stop reading after the first tuple.
204 */
205 if (!pstate)
206 {
207 if (node->prefetch_target < node->prefetch_maximum)
208 node->prefetch_target++;
209 }
210 else if (pstate->prefetch_target < node->prefetch_maximum)
211 {
212 /* take spinlock while updating shared state */
213 SpinLockAcquire(&pstate->mutex);
214 if (pstate->prefetch_target < node->prefetch_maximum)
215 pstate->prefetch_target++;
216 SpinLockRelease(&pstate->mutex);
217 }
218#endif /* USE_PREFETCH */
219
220 /*
221 * We issue prefetch requests *after* fetching the current page to
222 * try to avoid having prefetching interfere with the main I/O.
223 * Also, this should happen only when we have determined there is
224 * still something to do on the current page, else we may
225 * uselessly prefetch the same page we are just about to request
226 * for real.
227 */
228 BitmapPrefetch(node, scan);
229
230 /*
231 * If we are using lossy info, we have to recheck the qual
232 * conditions at every tuple.
233 */
234 if (node->recheck)
235 {
236 econtext->ecxt_scantuple = slot;
237 if (!ExecQualAndReset(node->bitmapqualorig, econtext))
238 {
239 /* Fails recheck, so drop it and loop back for another */
240 InstrCountFiltered2(node, 1);
241 ExecClearTuple(slot);
242 continue;
243 }
244 }
245
246 /* OK to return this tuple */
247 return slot;
248 }
249
250new_page:
251
253
254 /*
255 * Returns false if the bitmap is exhausted and there are no further
256 * blocks we need to scan.
257 */
258 if (!table_scan_bitmap_next_block(scan, &node->blockno,
259 &node->recheck,
260 &node->stats.lossy_pages,
261 &node->stats.exact_pages))
262 break;
263
264 /*
265 * If serial, we can error out if the prefetch block doesn't stay
266 * ahead of the current block.
267 */
268 if (node->pstate == NULL &&
270 node->prefetch_blockno < node->blockno)
271 elog(ERROR,
272 "prefetch and main iterators are out of sync. pfblockno: %d. blockno: %d",
273 node->prefetch_blockno, node->blockno);
274
275 /* Adjust the prefetch target */
277 }
278
279 /*
280 * if we get here it means we are at the end of the scan..
281 */
282 return ExecClearTuple(slot);
283}
#define InvalidDsaPointer
Definition: dsa.h:78
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
Node * MultiExecProcNode(PlanState *node)
Definition: execProcnode.c:507
#define outerPlanState(node)
Definition: execnodes.h:1237
#define InstrCountFiltered2(node, delta)
Definition: execnodes.h:1250
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:453
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
static bool BitmapShouldInitializeSharedState(ParallelBitmapHeapState *pstate)
static void BitmapPrefetch(BitmapHeapScanState *node, TableScanDesc scan)
static void BitmapAdjustPrefetchTarget(BitmapHeapScanState *node)
static void BitmapDoneInitializingSharedState(ParallelBitmapHeapState *pstate)
static void BitmapAdjustPrefetchIterator(BitmapHeapScanState *node)
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define NIL
Definition: pg_list.h:68
ExprState * bitmapqualorig
Definition: execnodes.h:1866
BitmapHeapScanInstrumentation stats
Definition: execnodes.h:1869
TIDBitmap * tbm
Definition: execnodes.h:1867
BlockNumber blockno
Definition: execnodes.h:1878
struct dsa_area * es_query_dsa
Definition: execnodes.h:733
Snapshot es_snapshot
Definition: execnodes.h:648
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:267
dsa_pointer tbmiterator
Definition: execnodes.h:1821
dsa_pointer prefetch_iterator
Definition: execnodes.h:1822
Plan * plan
Definition: execnodes.h:1141
EState * state
Definition: execnodes.h:1143
ExprContext * ps_ExprContext
Definition: execnodes.h:1180
List * qual
Definition: plannodes.h:154
List * targetlist
Definition: plannodes.h:153
Relation ss_currentRelation
Definition: execnodes.h:1589
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1591
PlanState ps
Definition: execnodes.h:1588
struct TableScanDescData * ss_currentScanDesc
Definition: execnodes.h:1590
TBMIterator rs_tbmiterator
Definition: relscan.h:47
union TableScanDescData::@49 st
Definition: dsa.c:348
static bool table_scan_bitmap_next_tuple(TableScanDesc scan, TupleTableSlot *slot)
Definition: tableam.h:2005
static bool table_scan_bitmap_next_block(TableScanDesc scan, BlockNumber *blockno, bool *recheck, uint64 *lossy_pages, uint64 *exact_pages)
Definition: tableam.h:1976
static TableScanDesc table_beginscan_bm(Relation rel, Snapshot snapshot, int nkeys, struct ScanKeyData *key, bool need_tuple)
Definition: tableam.h:957
dsa_pointer tbm_prepare_shared_iterate(TIDBitmap *tbm)
Definition: tidbitmap.c:767
TBMIterator tbm_begin_iterate(TIDBitmap *tbm, dsa_area *dsa, dsa_pointer dsp)
Definition: tidbitmap.c:1572
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454

References BitmapAdjustPrefetchIterator(), BitmapAdjustPrefetchTarget(), BitmapDoneInitializingSharedState(), BitmapPrefetch(), BitmapHeapScanState::bitmapqualorig, BitmapShouldInitializeSharedState(), BitmapHeapScanState::blockno, CHECK_FOR_INTERRUPTS, ExprContext::ecxt_scantuple, elog, ERROR, EState::es_query_dsa, EState::es_snapshot, BitmapHeapScanInstrumentation::exact_pages, ExecClearTuple(), ExecQualAndReset(), BitmapHeapScanState::initialized, InstrCountFiltered2, InvalidDsaPointer, IsA, BitmapHeapScanInstrumentation::lossy_pages, MultiExecProcNode(), ParallelBitmapHeapState::mutex, NIL, outerPlanState, PlanState::plan, BitmapHeapScanState::prefetch_blockno, ParallelBitmapHeapState::prefetch_iterator, BitmapHeapScanState::prefetch_iterator, BitmapHeapScanState::prefetch_maximum, ParallelBitmapHeapState::prefetch_target, BitmapHeapScanState::prefetch_target, ScanState::ps, PlanState::ps_ExprContext, BitmapHeapScanState::pstate, Plan::qual, BitmapHeapScanState::recheck, TableScanDescData::rs_tbmiterator, SpinLockAcquire, SpinLockRelease, BitmapHeapScanState::ss, ScanState::ss_currentRelation, ScanState::ss_currentScanDesc, ScanState::ss_ScanTupleSlot, TableScanDescData::st, PlanState::state, BitmapHeapScanState::stats, table_beginscan_bm(), table_scan_bitmap_next_block(), table_scan_bitmap_next_tuple(), Plan::targetlist, BitmapHeapScanState::tbm, tbm_begin_iterate(), tbm_exhausted(), tbm_prepare_shared_iterate(), and ParallelBitmapHeapState::tbmiterator.

Referenced by ExecBitmapHeapScan().

◆ BitmapHeapRecheck()

static bool BitmapHeapRecheck ( BitmapHeapScanState node,
TupleTableSlot slot 
)
static

Definition at line 524 of file nodeBitmapHeapscan.c.

525{
526 ExprContext *econtext;
527
528 /*
529 * extract necessary information from index scan node
530 */
531 econtext = node->ss.ps.ps_ExprContext;
532
533 /* Does the tuple meet the original qual conditions? */
534 econtext->ecxt_scantuple = slot;
535 return ExecQualAndReset(node->bitmapqualorig, econtext);
536}

References BitmapHeapScanState::bitmapqualorig, ExprContext::ecxt_scantuple, ExecQualAndReset(), ScanState::ps, PlanState::ps_ExprContext, and BitmapHeapScanState::ss.

Referenced by ExecBitmapHeapScan().

◆ BitmapPrefetch()

static void BitmapPrefetch ( BitmapHeapScanState node,
TableScanDesc  scan 
)
inlinestatic

Definition at line 423 of file nodeBitmapHeapscan.c.

424{
425#ifdef USE_PREFETCH
426 ParallelBitmapHeapState *pstate = node->pstate;
427
428 if (pstate == NULL)
429 {
430 TBMIterator *prefetch_iterator = &node->prefetch_iterator;
431
432 if (!tbm_exhausted(prefetch_iterator))
433 {
434 while (node->prefetch_pages < node->prefetch_target)
435 {
436 TBMIterateResult *tbmpre = tbm_iterate(prefetch_iterator);
437 bool skip_fetch;
438
439 if (tbmpre == NULL)
440 {
441 /* No more pages to prefetch */
442 tbm_end_iterate(prefetch_iterator);
443 break;
444 }
445 node->prefetch_pages++;
446 node->prefetch_blockno = tbmpre->blockno;
447
448 /*
449 * If we expect not to have to actually read this heap page,
450 * skip this prefetch call, but continue to run the prefetch
451 * logic normally. (Would it be better not to increment
452 * prefetch_pages?)
453 */
454 skip_fetch = (!(scan->rs_flags & SO_NEED_TUPLES) &&
455 !tbmpre->recheck &&
457 tbmpre->blockno,
458 &node->pvmbuffer));
459
460 if (!skip_fetch)
461 PrefetchBuffer(scan->rs_rd, MAIN_FORKNUM, tbmpre->blockno);
462 }
463 }
464
465 return;
466 }
467
468 if (pstate->prefetch_pages < pstate->prefetch_target)
469 {
470 TBMIterator *prefetch_iterator = &node->prefetch_iterator;
471
472 if (!tbm_exhausted(prefetch_iterator))
473 {
474 while (1)
475 {
476 TBMIterateResult *tbmpre;
477 bool do_prefetch = false;
478 bool skip_fetch;
479
480 /*
481 * Recheck under the mutex. If some other process has already
482 * done enough prefetching then we need not to do anything.
483 */
484 SpinLockAcquire(&pstate->mutex);
485 if (pstate->prefetch_pages < pstate->prefetch_target)
486 {
487 pstate->prefetch_pages++;
488 do_prefetch = true;
489 }
490 SpinLockRelease(&pstate->mutex);
491
492 if (!do_prefetch)
493 return;
494
495 tbmpre = tbm_iterate(prefetch_iterator);
496 if (tbmpre == NULL)
497 {
498 /* No more pages to prefetch */
499 tbm_end_iterate(prefetch_iterator);
500 break;
501 }
502
503 node->prefetch_blockno = tbmpre->blockno;
504
505 /* As above, skip prefetch if we expect not to need page */
506 skip_fetch = (!(scan->rs_flags & SO_NEED_TUPLES) &&
507 !tbmpre->recheck &&
509 tbmpre->blockno,
510 &node->pvmbuffer));
511
512 if (!skip_fetch)
513 PrefetchBuffer(scan->rs_rd, MAIN_FORKNUM, tbmpre->blockno);
514 }
515 }
516 }
517#endif /* USE_PREFETCH */
518}
PrefetchBufferResult PrefetchBuffer(Relation reln, ForkNumber forkNum, BlockNumber blockNum)
Definition: bufmgr.c:639
@ MAIN_FORKNUM
Definition: relpath.h:58
Relation rs_rd
Definition: relscan.h:36
uint32 rs_flags
Definition: relscan.h:64
@ SO_NEED_TUPLES
Definition: tableam.h:71
void tbm_end_iterate(TBMIterator *iterator)
Definition: tidbitmap.c:1595
#define VM_ALL_VISIBLE(r, b, v)
Definition: visibilitymap.h:24

References TBMIterateResult::blockno, MAIN_FORKNUM, ParallelBitmapHeapState::mutex, BitmapHeapScanState::prefetch_blockno, BitmapHeapScanState::prefetch_iterator, ParallelBitmapHeapState::prefetch_pages, BitmapHeapScanState::prefetch_pages, ParallelBitmapHeapState::prefetch_target, BitmapHeapScanState::prefetch_target, PrefetchBuffer(), BitmapHeapScanState::pstate, BitmapHeapScanState::pvmbuffer, TBMIterateResult::recheck, TableScanDescData::rs_flags, TableScanDescData::rs_rd, SO_NEED_TUPLES, SpinLockAcquire, SpinLockRelease, BitmapHeapScanState::ss, ScanState::ss_currentRelation, tbm_end_iterate(), tbm_exhausted(), tbm_iterate(), and VM_ALL_VISIBLE.

Referenced by BitmapHeapNext().

◆ BitmapShouldInitializeSharedState()

static bool BitmapShouldInitializeSharedState ( ParallelBitmapHeapState pstate)
static

Definition at line 781 of file nodeBitmapHeapscan.c.

782{
784
785 while (1)
786 {
787 SpinLockAcquire(&pstate->mutex);
788 state = pstate->state;
789 if (pstate->state == BM_INITIAL)
790 pstate->state = BM_INPROGRESS;
791 SpinLockRelease(&pstate->mutex);
792
793 /* Exit if bitmap is done, or if we're the leader. */
794 if (state != BM_INPROGRESS)
795 break;
796
797 /* Wait for the leader to wake us up. */
798 ConditionVariableSleep(&pstate->cv, WAIT_EVENT_PARALLEL_BITMAP_SCAN);
799 }
800
802
803 return (state == BM_INITIAL);
804}
bool ConditionVariableCancelSleep(void)
void ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
SharedBitmapState
Definition: execnodes.h:1801
@ BM_INITIAL
Definition: execnodes.h:1802
@ BM_INPROGRESS
Definition: execnodes.h:1803
Definition: regguts.h:323

References BM_INITIAL, BM_INPROGRESS, ConditionVariableCancelSleep(), ConditionVariableSleep(), ParallelBitmapHeapState::cv, ParallelBitmapHeapState::mutex, SpinLockAcquire, SpinLockRelease, and ParallelBitmapHeapState::state.

Referenced by BitmapHeapNext().

◆ ExecBitmapHeapEstimate()

void ExecBitmapHeapEstimate ( BitmapHeapScanState node,
ParallelContext pcxt 
)

Definition at line 814 of file nodeBitmapHeapscan.c.

816{
817 Size size;
818
820
821 /* account for instrumentation, if required */
822 if (node->ss.ps.instrument && pcxt->nworkers > 0)
823 {
824 size = add_size(size, offsetof(SharedBitmapHeapInstrumentation, sinstrument));
826 }
827
830}
#define MAXALIGN(LEN)
Definition: c.h:768
size_t Size
Definition: c.h:562
#define shm_toc_estimate_chunk(e, sz)
Definition: shm_toc.h:51
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
Size add_size(Size s1, Size s2)
Definition: shmem.c:488
Size mul_size(Size s1, Size s2)
Definition: shmem.c:505
static pg_noinline void Size size
Definition: slab.c:607
shm_toc_estimator estimator
Definition: parallel.h:41
Instrumentation * instrument
Definition: execnodes.h:1151

References add_size(), ParallelContext::estimator, PlanState::instrument, MAXALIGN, mul_size(), ParallelContext::nworkers, ScanState::ps, shm_toc_estimate_chunk, shm_toc_estimate_keys, size, and BitmapHeapScanState::ss.

Referenced by ExecParallelEstimate().

◆ ExecBitmapHeapInitializeDSM()

void ExecBitmapHeapInitializeDSM ( BitmapHeapScanState node,
ParallelContext pcxt 
)

Definition at line 839 of file nodeBitmapHeapscan.c.

841{
843 SharedBitmapHeapInstrumentation *sinstrument = NULL;
844 dsa_area *dsa = node->ss.ps.state->es_query_dsa;
845 char *ptr;
846 Size size;
847
848 /* If there's no DSA, there are no workers; initialize nothing. */
849 if (dsa == NULL)
850 return;
851
853 if (node->ss.ps.instrument && pcxt->nworkers > 0)
854 {
855 size = add_size(size, offsetof(SharedBitmapHeapInstrumentation, sinstrument));
857 }
858
859 ptr = shm_toc_allocate(pcxt->toc, size);
860 pstate = (ParallelBitmapHeapState *) ptr;
861 ptr += MAXALIGN(sizeof(ParallelBitmapHeapState));
862 if (node->ss.ps.instrument && pcxt->nworkers > 0)
863 sinstrument = (SharedBitmapHeapInstrumentation *) ptr;
864
865 pstate->tbmiterator = 0;
866 pstate->prefetch_iterator = 0;
867
868 /* Initialize the mutex */
869 SpinLockInit(&pstate->mutex);
870 pstate->prefetch_pages = 0;
871 pstate->prefetch_target = -1;
872 pstate->state = BM_INITIAL;
873
874 ConditionVariableInit(&pstate->cv);
875
876 if (sinstrument)
877 {
878 sinstrument->num_workers = pcxt->nworkers;
879
880 /* ensure any unfilled slots will contain zeroes */
881 memset(sinstrument->sinstrument, 0,
883 }
884
885 shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pstate);
886 node->pstate = pstate;
887 node->sinstrument = sinstrument;
888}
void ConditionVariableInit(ConditionVariable *cv)
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition: shm_toc.c:88
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition: shm_toc.c:171
#define SpinLockInit(lock)
Definition: spin.h:57
SharedBitmapHeapInstrumentation * sinstrument
Definition: execnodes.h:1876
shm_toc * toc
Definition: parallel.h:44
int plan_node_id
Definition: plannodes.h:152
BitmapHeapScanInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:1841

References add_size(), BM_INITIAL, ConditionVariableInit(), ParallelBitmapHeapState::cv, EState::es_query_dsa, PlanState::instrument, MAXALIGN, mul_size(), ParallelBitmapHeapState::mutex, SharedBitmapHeapInstrumentation::num_workers, ParallelContext::nworkers, PlanState::plan, Plan::plan_node_id, ParallelBitmapHeapState::prefetch_iterator, ParallelBitmapHeapState::prefetch_pages, ParallelBitmapHeapState::prefetch_target, ScanState::ps, BitmapHeapScanState::pstate, shm_toc_allocate(), shm_toc_insert(), SharedBitmapHeapInstrumentation::sinstrument, BitmapHeapScanState::sinstrument, size, SpinLockInit, BitmapHeapScanState::ss, PlanState::state, ParallelBitmapHeapState::state, ParallelBitmapHeapState::tbmiterator, and ParallelContext::toc.

Referenced by ExecParallelInitializeDSM().

◆ ExecBitmapHeapInitializeWorker()

void ExecBitmapHeapInitializeWorker ( BitmapHeapScanState node,
ParallelWorkerContext pwcxt 
)

Definition at line 928 of file nodeBitmapHeapscan.c.

930{
931 char *ptr;
932
933 Assert(node->ss.ps.state->es_query_dsa != NULL);
934
935 ptr = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
936
937 node->pstate = (ParallelBitmapHeapState *) ptr;
938 ptr += MAXALIGN(sizeof(ParallelBitmapHeapState));
939
940 if (node->ss.ps.instrument)
942}
#define Assert(condition)
Definition: c.h:815
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

References Assert, EState::es_query_dsa, PlanState::instrument, MAXALIGN, PlanState::plan, Plan::plan_node_id, ScanState::ps, BitmapHeapScanState::pstate, shm_toc_lookup(), BitmapHeapScanState::sinstrument, BitmapHeapScanState::ss, PlanState::state, and ParallelWorkerContext::toc.

Referenced by ExecParallelInitializeWorker().

◆ ExecBitmapHeapReInitializeDSM()

void ExecBitmapHeapReInitializeDSM ( BitmapHeapScanState node,
ParallelContext pcxt 
)

Definition at line 897 of file nodeBitmapHeapscan.c.

899{
900 ParallelBitmapHeapState *pstate = node->pstate;
901 dsa_area *dsa = node->ss.ps.state->es_query_dsa;
902
903 /* If there's no DSA, there are no workers; do nothing. */
904 if (dsa == NULL)
905 return;
906
907 pstate->state = BM_INITIAL;
908 pstate->prefetch_pages = 0;
909 pstate->prefetch_target = -1;
910
911 if (DsaPointerIsValid(pstate->tbmiterator))
912 tbm_free_shared_area(dsa, pstate->tbmiterator);
913
916
919}
#define DsaPointerIsValid(x)
Definition: dsa.h:106
void tbm_free_shared_area(dsa_area *dsa, dsa_pointer dp)
Definition: tidbitmap.c:341

References BM_INITIAL, DsaPointerIsValid, EState::es_query_dsa, InvalidDsaPointer, ParallelBitmapHeapState::prefetch_iterator, ParallelBitmapHeapState::prefetch_pages, ParallelBitmapHeapState::prefetch_target, ScanState::ps, BitmapHeapScanState::pstate, BitmapHeapScanState::ss, PlanState::state, ParallelBitmapHeapState::state, tbm_free_shared_area(), and ParallelBitmapHeapState::tbmiterator.

Referenced by ExecParallelReInitializeDSM().

◆ ExecBitmapHeapRetrieveInstrumentation()

void ExecBitmapHeapRetrieveInstrumentation ( BitmapHeapScanState node)

Definition at line 951 of file nodeBitmapHeapscan.c.

952{
953 SharedBitmapHeapInstrumentation *sinstrument = node->sinstrument;
954 Size size;
955
956 if (sinstrument == NULL)
957 return;
958
959 size = offsetof(SharedBitmapHeapInstrumentation, sinstrument)
960 + sinstrument->num_workers * sizeof(BitmapHeapScanInstrumentation);
961
962 node->sinstrument = palloc(size);
963 memcpy(node->sinstrument, sinstrument, size);
964}
struct BitmapHeapScanInstrumentation BitmapHeapScanInstrumentation
void * palloc(Size size)
Definition: mcxt.c:1317

References SharedBitmapHeapInstrumentation::num_workers, palloc(), BitmapHeapScanState::sinstrument, and size.

Referenced by ExecParallelRetrieveInstrumentation().

◆ ExecBitmapHeapScan()

static TupleTableSlot * ExecBitmapHeapScan ( PlanState pstate)
static

Definition at line 543 of file nodeBitmapHeapscan.c.

544{
546
547 return ExecScan(&node->ss,
550}
TupleTableSlot * ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
Definition: execScan.c:47
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
Definition: executor.h:487
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
Definition: executor.h:486
static TupleTableSlot * BitmapHeapNext(BitmapHeapScanState *node)
static bool BitmapHeapRecheck(BitmapHeapScanState *node, TupleTableSlot *slot)
#define castNode(_type_, nodeptr)
Definition: nodes.h:176

References BitmapHeapNext(), BitmapHeapRecheck(), castNode, ExecScan(), and BitmapHeapScanState::ss.

Referenced by ExecInitBitmapHeapScan().

◆ ExecEndBitmapHeapScan()

void ExecEndBitmapHeapScan ( BitmapHeapScanState node)

Definition at line 610 of file nodeBitmapHeapscan.c.

611{
612 TableScanDesc scanDesc;
613
614 /*
615 * When ending a parallel worker, copy the statistics gathered by the
616 * worker back into shared memory so that it can be picked up by the main
617 * process to report in EXPLAIN ANALYZE.
618 */
619 if (node->sinstrument != NULL && IsParallelWorker())
620 {
622
623 Assert(ParallelWorkerNumber <= node->sinstrument->num_workers);
625
626 /*
627 * Here we accumulate the stats rather than performing memcpy on
628 * node->stats into si. When a Gather/GatherMerge node finishes it
629 * will perform planner shutdown on the workers. On rescan it will
630 * spin up new workers which will have a new BitmapHeapScanState and
631 * zeroed stats.
632 */
633 si->exact_pages += node->stats.exact_pages;
634 si->lossy_pages += node->stats.lossy_pages;
635 }
636
637 /*
638 * extract information from the node
639 */
640 scanDesc = node->ss.ss_currentScanDesc;
641
642 /*
643 * close down subplans
644 */
646
647 if (scanDesc)
648 {
649 /*
650 * End iteration on iterators saved in scan descriptor if they have
651 * not already been cleaned up.
652 */
653 if (!tbm_exhausted(&scanDesc->st.rs_tbmiterator))
655
656 /*
657 * close table scan
658 */
659 table_endscan(scanDesc);
660 }
661
662 /* If we did not already clean up the prefetch iterator, do so now. */
663 if (!tbm_exhausted(&node->prefetch_iterator))
665
666 /*
667 * release bitmaps and buffers if any
668 */
669 if (node->tbm)
670 tbm_free(node->tbm);
671 if (node->pvmbuffer != InvalidBuffer)
673}
int ParallelWorkerNumber
Definition: parallel.c:114
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4866
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:562
#define IsParallelWorker()
Definition: parallel.h:60
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:1024
void tbm_free(TIDBitmap *tbm)
Definition: tidbitmap.c:322

References Assert, BitmapHeapScanInstrumentation::exact_pages, ExecEndNode(), InvalidBuffer, IsParallelWorker, BitmapHeapScanInstrumentation::lossy_pages, outerPlanState, ParallelWorkerNumber, BitmapHeapScanState::prefetch_iterator, BitmapHeapScanState::pvmbuffer, ReleaseBuffer(), TableScanDescData::rs_tbmiterator, SharedBitmapHeapInstrumentation::sinstrument, BitmapHeapScanState::sinstrument, BitmapHeapScanState::ss, ScanState::ss_currentScanDesc, TableScanDescData::st, BitmapHeapScanState::stats, table_endscan(), BitmapHeapScanState::tbm, tbm_end_iterate(), tbm_exhausted(), and tbm_free().

Referenced by ExecEndNode().

◆ ExecInitBitmapHeapScan()

BitmapHeapScanState * ExecInitBitmapHeapScan ( BitmapHeapScan node,
EState estate,
int  eflags 
)

Definition at line 682 of file nodeBitmapHeapscan.c.

683{
684 BitmapHeapScanState *scanstate;
685 Relation currentRelation;
686
687 /* check for unsupported flags */
689
690 /*
691 * Assert caller didn't ask for an unsafe snapshot --- see comments at
692 * head of file.
693 */
695
696 /*
697 * create state structure
698 */
699 scanstate = makeNode(BitmapHeapScanState);
700 scanstate->ss.ps.plan = (Plan *) node;
701 scanstate->ss.ps.state = estate;
703
704 scanstate->tbm = NULL;
705 scanstate->pvmbuffer = InvalidBuffer;
706
707 /* Zero the statistics counters */
708 memset(&scanstate->stats, 0, sizeof(BitmapHeapScanInstrumentation));
709
710 scanstate->prefetch_pages = 0;
711 scanstate->prefetch_target = -1;
712 scanstate->initialized = false;
713 scanstate->pstate = NULL;
714 scanstate->recheck = true;
715 scanstate->blockno = InvalidBlockNumber;
717
718 /*
719 * Miscellaneous initialization
720 *
721 * create expression context for node
722 */
723 ExecAssignExprContext(estate, &scanstate->ss.ps);
724
725 /*
726 * open the scan relation
727 */
728 currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
729
730 /*
731 * initialize child nodes
732 */
733 outerPlanState(scanstate) = ExecInitNode(outerPlan(node), estate, eflags);
734
735 /*
736 * get the scan type from the relation descriptor.
737 */
738 ExecInitScanTupleSlot(estate, &scanstate->ss,
739 RelationGetDescr(currentRelation),
740 table_slot_callbacks(currentRelation));
741
742 /*
743 * Initialize result type and projection.
744 */
745 ExecInitResultTypeTL(&scanstate->ss.ps);
746 ExecAssignScanProjectionInfo(&scanstate->ss);
747
748 /*
749 * initialize child expressions
750 */
751 scanstate->ss.ps.qual =
752 ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
753 scanstate->bitmapqualorig =
754 ExecInitQual(node->bitmapqualorig, (PlanState *) scanstate);
755
756 /*
757 * Maximum number of prefetches for the tablespace if configured,
758 * otherwise the current value of the effective_io_concurrency GUC.
759 */
760 scanstate->prefetch_maximum =
761 get_tablespace_io_concurrency(currentRelation->rd_rel->reltablespace);
762
763 scanstate->ss.ss_currentRelation = currentRelation;
764
765 /*
766 * all done.
767 */
768 return scanstate;
769}
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:229
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:142
void ExecAssignScanProjectionInfo(ScanState *node)
Definition: execScan.c:81
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1998
void ExecInitResultTypeTL(PlanState *planstate)
Definition: execTuples.c:1942
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:485
Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
Definition: execUtils.c:742
#define EXEC_FLAG_BACKWARD
Definition: executor.h:68
#define EXEC_FLAG_MARK
Definition: executor.h:69
static TupleTableSlot * ExecBitmapHeapScan(PlanState *pstate)
#define makeNode(_type_)
Definition: nodes.h:155
#define outerPlan(node)
Definition: plannodes.h:183
#define RelationGetDescr(relation)
Definition: rel.h:531
#define IsMVCCSnapshot(snapshot)
Definition: snapmgr.h:55
int get_tablespace_io_concurrency(Oid spcid)
Definition: spccache.c:215
List * bitmapqualorig
Definition: plannodes.h:544
ExprState * qual
Definition: execnodes.h:1162
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1147
Form_pg_class rd_rel
Definition: rel.h:111
Index scanrelid
Definition: plannodes.h:392
const TupleTableSlotOps * table_slot_callbacks(Relation relation)
Definition: tableam.c:58

References Assert, BitmapHeapScanState::bitmapqualorig, BitmapHeapScan::bitmapqualorig, BitmapHeapScanState::blockno, EState::es_snapshot, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecAssignScanProjectionInfo(), ExecBitmapHeapScan(), ExecInitNode(), ExecInitQual(), ExecInitResultTypeTL(), ExecInitScanTupleSlot(), ExecOpenScanRelation(), PlanState::ExecProcNode, get_tablespace_io_concurrency(), BitmapHeapScanState::initialized, InvalidBlockNumber, InvalidBuffer, IsMVCCSnapshot, makeNode, outerPlan, outerPlanState, PlanState::plan, BitmapHeapScanState::prefetch_blockno, BitmapHeapScanState::prefetch_maximum, BitmapHeapScanState::prefetch_pages, BitmapHeapScanState::prefetch_target, ScanState::ps, BitmapHeapScanState::pstate, BitmapHeapScanState::pvmbuffer, PlanState::qual, RelationData::rd_rel, BitmapHeapScanState::recheck, RelationGetDescr, BitmapHeapScan::scan, Scan::scanrelid, BitmapHeapScanState::ss, ScanState::ss_currentRelation, PlanState::state, BitmapHeapScanState::stats, table_slot_callbacks(), and BitmapHeapScanState::tbm.

Referenced by ExecInitNode().

◆ ExecReScanBitmapHeapScan()

void ExecReScanBitmapHeapScan ( BitmapHeapScanState node)

Definition at line 557 of file nodeBitmapHeapscan.c.

558{
560
562
563 if (scan)
564 {
565 /*
566 * End iteration on iterators saved in scan descriptor if they have
567 * not already been cleaned up.
568 */
569 if (!tbm_exhausted(&scan->st.rs_tbmiterator))
571
572 /* rescan to release any page pin */
574 }
575
576 /* If we did not already clean up the prefetch iterator, do so now. */
577 if (!tbm_exhausted(&node->prefetch_iterator))
579
580 /* release bitmaps and buffers if any */
581 if (node->tbm)
582 tbm_free(node->tbm);
583 if (node->pvmbuffer != InvalidBuffer)
585 node->tbm = NULL;
586 node->initialized = false;
587 node->pvmbuffer = InvalidBuffer;
588 node->recheck = true;
589 /* Only used for serial BHS */
592 node->prefetch_pages = 0;
593 node->prefetch_target = -1;
594
595 ExecScanReScan(&node->ss);
596
597 /*
598 * if chgParam of subnode is not null then plan will be re-scanned by
599 * first ExecProcNode.
600 */
601 if (outerPlan->chgParam == NULL)
603}
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
void ExecScanReScan(ScanState *node)
Definition: execScan.c:108
static void table_rescan(TableScanDesc scan, struct ScanKeyData *key)
Definition: tableam.h:1033

References BitmapHeapScanState::blockno, ExecReScan(), ExecScanReScan(), BitmapHeapScanState::initialized, InvalidBlockNumber, InvalidBuffer, outerPlan, outerPlanState, BitmapHeapScanState::prefetch_blockno, BitmapHeapScanState::prefetch_iterator, BitmapHeapScanState::prefetch_pages, BitmapHeapScanState::prefetch_target, BitmapHeapScanState::pvmbuffer, BitmapHeapScanState::recheck, ReleaseBuffer(), TableScanDescData::rs_tbmiterator, BitmapHeapScanState::ss, ScanState::ss_currentScanDesc, TableScanDescData::st, table_rescan(), BitmapHeapScanState::tbm, tbm_end_iterate(), tbm_exhausted(), and tbm_free().

Referenced by ExecReScan().