/* ---------------------------------------------------------------- * ExecReScanBitmapHeapScan(node) * ---------------------------------------------------------------- */ void ExecReScanBitmapHeapScan(BitmapHeapScanState *node) { PlanState *outerPlan = outerPlanState(node); /* rescan to release any page pin */ heap_rescan(node->ss.ss_currentScanDesc, NULL); if (node->tbmiterator) tbm_end_iterate(node->tbmiterator); if (node->prefetch_iterator) tbm_end_iterate(node->prefetch_iterator); if (node->shared_tbmiterator) tbm_end_shared_iterate(node->shared_tbmiterator); if (node->shared_prefetch_iterator) tbm_end_shared_iterate(node->shared_prefetch_iterator); if (node->tbm) tbm_free(node->tbm); node->tbm = NULL; node->tbmiterator = NULL; node->tbmres = NULL; node->prefetch_iterator = NULL; node->initialized = false; node->shared_tbmiterator = NULL; node->shared_prefetch_iterator = NULL; ExecScanReScan(&node->ss); /* * if chgParam of subnode is not null then plan will be re-scanned by * first ExecProcNode. */ if (outerPlan->chgParam == NULL) ExecReScan(outerPlan); }
/* ---------------------------------------------------------------- * ExecReScanBitmapHeapScan(node) * ---------------------------------------------------------------- */ void ExecReScanBitmapHeapScan(BitmapHeapScanState *node) { /* rescan to release any page pin */ heap_rescan(node->ss.ss_currentScanDesc, NULL); if (node->tbmiterator) tbm_end_iterate(node->tbmiterator); if (node->prefetch_iterator) tbm_end_iterate(node->prefetch_iterator); if (node->tbm) tbm_free(node->tbm); node->tbm = NULL; node->tbmiterator = NULL; node->tbmres = NULL; node->prefetch_iterator = NULL; ExecScanReScan(&node->ss); /* * if chgParam of subnode is not null then plan will be re-scanned by * first ExecProcNode. */ if (node->ss.ps.lefttree->chgParam == NULL) ExecReScan(node->ss.ps.lefttree); }
/* ---------------------------------------------------------------- * ExecEndBitmapHeapScan * ---------------------------------------------------------------- */ void ExecEndBitmapHeapScan(BitmapHeapScanState *node) { Relation relation; HeapScanDesc scanDesc; /* * extract information from the node */ relation = node->ss.ss_currentRelation; scanDesc = node->ss.ss_currentScanDesc; /* * Free the exprcontext */ ExecFreeExprContext(&node->ss.ps); /* * clear out tuple table slots */ ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); /* * close down subplans */ ExecEndNode(outerPlanState(node)); /* * release bitmap if any */ if (node->tbmiterator) tbm_end_iterate(node->tbmiterator); if (node->prefetch_iterator) tbm_end_iterate(node->prefetch_iterator); if (node->tbm) tbm_free(node->tbm); if (node->shared_tbmiterator) tbm_end_shared_iterate(node->shared_tbmiterator); if (node->shared_prefetch_iterator) tbm_end_shared_iterate(node->shared_prefetch_iterator); /* * close heap scan */ heap_endscan(scanDesc); /* * close the heap relation. */ ExecCloseScanRelation(relation); }
/* ---------------------------------------------------------------- * ExecReScanBitmapHeapScan(node) * ---------------------------------------------------------------- */ void ExecReScanBitmapHeapScan(BitmapHeapScanState *node) { PlanState *outerPlan = outerPlanState(node); /* rescan to release any page pin */ heap_rescan(node->ss.ss_currentScanDesc, NULL); if (node->tbmiterator) tbm_end_iterate(node->tbmiterator); if (node->prefetch_iterator) tbm_end_iterate(node->prefetch_iterator); if (node->shared_tbmiterator) tbm_end_shared_iterate(node->shared_tbmiterator); if (node->shared_prefetch_iterator) tbm_end_shared_iterate(node->shared_prefetch_iterator); if (node->tbm) tbm_free(node->tbm); node->tbm = NULL; node->tbmiterator = NULL; node->tbmres = NULL; node->prefetch_iterator = NULL; node->initialized = false; node->shared_tbmiterator = NULL; node->shared_prefetch_iterator = NULL; /* Reset parallel bitmap state, if present */ if (node->pstate) { dsa_area *dsa = node->ss.ps.state->es_query_dsa; node->pstate->state = BM_INITIAL; if (DsaPointerIsValid(node->pstate->tbmiterator)) tbm_free_shared_area(dsa, node->pstate->tbmiterator); if (DsaPointerIsValid(node->pstate->prefetch_iterator)) tbm_free_shared_area(dsa, node->pstate->prefetch_iterator); node->pstate->tbmiterator = InvalidDsaPointer; node->pstate->prefetch_iterator = InvalidDsaPointer; } ExecScanReScan(&node->ss); /* * if chgParam of subnode is not null then plan will be re-scanned by * first ExecProcNode. */ if (outerPlan->chgParam == NULL) ExecReScan(outerPlan); }
/* ---------------------------------------------------------------- * ExecEndBitmapHeapScan * ---------------------------------------------------------------- */ void ExecEndBitmapHeapScan(BitmapHeapScanState *node) { HeapScanDesc scanDesc; /* * extract information from the node */ scanDesc = node->ss.ss_currentScanDesc; /* * Free the exprcontext */ ExecFreeExprContext(&node->ss.ps); /* * clear out tuple table slots */ if (node->ss.ps.ps_ResultTupleSlot) ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); /* * close down subplans */ ExecEndNode(outerPlanState(node)); /* * release bitmaps and buffers if any */ if (node->tbmiterator) tbm_end_iterate(node->tbmiterator); if (node->prefetch_iterator) tbm_end_iterate(node->prefetch_iterator); if (node->tbm) tbm_free(node->tbm); if (node->shared_tbmiterator) tbm_end_shared_iterate(node->shared_tbmiterator); if (node->shared_prefetch_iterator) tbm_end_shared_iterate(node->shared_prefetch_iterator); if (node->vmbuffer != InvalidBuffer) ReleaseBuffer(node->vmbuffer); if (node->pvmbuffer != InvalidBuffer) ReleaseBuffer(node->pvmbuffer); /* * close heap scan */ heap_endscan(scanDesc); }
/* * Release current scan keys, if any. */ void ginFreeScanKeys(GinScanOpaque so) { uint32 i; if (so->keys == NULL) return; for (i = 0; i < so->totalentries; i++) { GinScanEntry entry = so->entries[i]; if (entry->buffer != InvalidBuffer) ReleaseBuffer(entry->buffer); if (entry->list) pfree(entry->list); if (entry->matchIterator) tbm_end_iterate(entry->matchIterator); if (entry->matchBitmap) tbm_free(entry->matchBitmap); } MemoryContextResetAndDeleteChildren(so->keyCtx); so->keys = NULL; so->nkeys = 0; so->entries = NULL; so->totalentries = 0; }
static void freeScanKeys(GinScanOpaque so) { uint32 i; if (so->keys == NULL) return; for (i = 0; i < so->nkeys; i++) { GinScanKey key = so->keys + i; pfree(key->scanEntry); pfree(key->entryRes); } pfree(so->keys); so->keys = NULL; so->nkeys = 0; for (i = 0; i < so->totalentries; i++) { GinScanEntry entry = so->entries[i]; if (entry->buffer != InvalidBuffer) ReleaseBuffer(entry->buffer); if (entry->list) pfree(entry->list); if (entry->matchIterator) tbm_end_iterate(entry->matchIterator); if (entry->matchBitmap) tbm_free(entry->matchBitmap); pfree(entry); } pfree(so->entries); so->entries = NULL; so->totalentries = 0; }
/* ---------------------------------------------------------------- * BitmapHeapNext * * Retrieve next tuple from the BitmapHeapScan node's currentRelation * ---------------------------------------------------------------- */ static TupleTableSlot * BitmapHeapNext(BitmapHeapScanState *node) { ExprContext *econtext; HeapScanDesc scan; TIDBitmap *tbm; TBMIterator *tbmiterator; TBMIterateResult *tbmres; TBMIterator *prefetch_iterator; OffsetNumber targoffset; TupleTableSlot *slot; /* * extract necessary information from index scan node */ econtext = node->ss.ps.ps_ExprContext; slot = node->ss.ss_ScanTupleSlot; scan = node->ss.ss_currentScanDesc; tbm = node->tbm; tbmiterator = node->tbmiterator; tbmres = node->tbmres; prefetch_iterator = node->prefetch_iterator; /* * If we haven't yet performed the underlying index scan, do it, and begin * the iteration over the bitmap. * * For prefetching, we use *two* iterators, one for the pages we are * actually scanning and another that runs ahead of the first for * prefetching. node->prefetch_pages tracks exactly how many pages ahead * the prefetch iterator is. Also, node->prefetch_target tracks the * desired prefetch distance, which starts small and increases up to the * GUC-controlled maximum, target_prefetch_pages. This is to avoid doing * a lot of prefetching in a scan that stops after a few tuples because of * a LIMIT. */ if (tbm == NULL) { tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node)); if (!tbm || !IsA(tbm, TIDBitmap)) elog(ERROR, "unrecognized result from subplan"); node->tbm = tbm; node->tbmiterator = tbmiterator = tbm_begin_iterate(tbm); node->tbmres = tbmres = NULL; #ifdef USE_PREFETCH if (target_prefetch_pages > 0) { node->prefetch_iterator = prefetch_iterator = tbm_begin_iterate(tbm); node->prefetch_pages = 0; node->prefetch_target = -1; } #endif /* USE_PREFETCH */ } for (;;) { Page dp; ItemId lp; /* * Get next page of results if needed */ if (tbmres == NULL) { node->tbmres = tbmres = tbm_iterate(tbmiterator); if (tbmres == NULL) { /* no more entries in the bitmap */ break; } #ifdef USE_PREFETCH if (node->prefetch_pages > 0) { /* The main iterator has closed the distance by one page */ node->prefetch_pages--; } else if (prefetch_iterator) { /* Do not let the prefetch iterator get behind the main one */ TBMIterateResult *tbmpre = tbm_iterate(prefetch_iterator); if (tbmpre == NULL || tbmpre->blockno != tbmres->blockno) elog(ERROR, "prefetch and main iterators are out of sync"); } #endif /* USE_PREFETCH */ /* * Ignore any claimed entries past what we think is the end of the * relation. (This is probably not necessary given that we got at * least AccessShareLock on the table before performing any of the * indexscans, but let's be safe.) */ if (tbmres->blockno >= scan->rs_nblocks) { node->tbmres = tbmres = NULL; continue; } /* * Fetch the current heap page and identify candidate tuples. */ bitgetpage(scan, tbmres); /* * Set rs_cindex to first slot to examine */ scan->rs_cindex = 0; #ifdef USE_PREFETCH /* * Increase prefetch target if it's not yet at the max. Note that * we will increase it to zero after fetching the very first * page/tuple, then to one after the second tuple is fetched, then * it doubles as later pages are fetched. */ if (node->prefetch_target >= target_prefetch_pages) /* don't increase any further */ ; else if (node->prefetch_target >= target_prefetch_pages / 2) node->prefetch_target = target_prefetch_pages; else if (node->prefetch_target > 0) node->prefetch_target *= 2; else node->prefetch_target++; #endif /* USE_PREFETCH */ } else { /* * Continuing in previously obtained page; advance rs_cindex */ scan->rs_cindex++; #ifdef USE_PREFETCH /* * Try to prefetch at least a few pages even before we get to the * second page if we don't stop reading after the first tuple. */ if (node->prefetch_target < target_prefetch_pages) node->prefetch_target++; #endif /* USE_PREFETCH */ } /* * Out of range? If so, nothing more to look at on this page */ if (scan->rs_cindex < 0 || scan->rs_cindex >= scan->rs_ntuples) { node->tbmres = tbmres = NULL; continue; } #ifdef USE_PREFETCH /* * We issue prefetch requests *after* fetching the current page to try * to avoid having prefetching interfere with the main I/O. Also, this * should happen only when we have determined there is still something * to do on the current page, else we may uselessly prefetch the same * page we are just about to request for real. */ if (prefetch_iterator) { while (node->prefetch_pages < node->prefetch_target) { TBMIterateResult *tbmpre = tbm_iterate(prefetch_iterator); if (tbmpre == NULL) { /* No more pages to prefetch */ tbm_end_iterate(prefetch_iterator); node->prefetch_iterator = prefetch_iterator = NULL; break; } node->prefetch_pages++; PrefetchBuffer(scan->rs_rd, MAIN_FORKNUM, tbmpre->blockno); } } #endif /* USE_PREFETCH */ /* * Okay to fetch the tuple */ targoffset = scan->rs_vistuples[scan->rs_cindex]; dp = (Page) BufferGetPage(scan->rs_cbuf); lp = PageGetItemId(dp, targoffset); Assert(ItemIdIsNormal(lp)); scan->rs_ctup.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp); scan->rs_ctup.t_len = ItemIdGetLength(lp); ItemPointerSet(&scan->rs_ctup.t_self, tbmres->blockno, targoffset); pgstat_count_heap_fetch(scan->rs_rd); /* * Set up the result slot to point to this tuple. Note that the slot * acquires a pin on the buffer. */ ExecStoreTuple(&scan->rs_ctup, slot, scan->rs_cbuf, false); /* * If we are using lossy info, we have to recheck the qual conditions * at every tuple. */ if (tbmres->recheck) { econtext->ecxt_scantuple = slot; ResetExprContext(econtext); if (!ExecQual(node->bitmapqualorig, econtext, false)) { /* Fails recheck, so drop it and loop back for another */ ExecClearTuple(slot); continue; } } /* OK to return this tuple */ return slot; } /* * if we get here it means we are at the end of the scan.. */ return ExecClearTuple(slot); }
/* * BitmapPrefetch - Prefetch, if prefetch_pages are behind prefetch_target */ static inline void BitmapPrefetch(BitmapHeapScanState *node, HeapScanDesc scan) { #ifdef USE_PREFETCH ParallelBitmapHeapState *pstate = node->pstate; if (pstate == NULL) { TBMIterator *prefetch_iterator = node->prefetch_iterator; if (prefetch_iterator) { while (node->prefetch_pages < node->prefetch_target) { TBMIterateResult *tbmpre = tbm_iterate(prefetch_iterator); if (tbmpre == NULL) { /* No more pages to prefetch */ tbm_end_iterate(prefetch_iterator); node->prefetch_iterator = NULL; break; } node->prefetch_pages++; PrefetchBuffer(scan->rs_rd, MAIN_FORKNUM, tbmpre->blockno); } } return; } if (pstate->prefetch_pages < pstate->prefetch_target) { TBMSharedIterator *prefetch_iterator = node->shared_prefetch_iterator; if (prefetch_iterator) { while (1) { TBMIterateResult *tbmpre; bool do_prefetch = false; /* * Recheck under the mutex. If some other process has already * done enough prefetching then we need not to do anything. */ SpinLockAcquire(&pstate->mutex); if (pstate->prefetch_pages < pstate->prefetch_target) { pstate->prefetch_pages++; do_prefetch = true; } SpinLockRelease(&pstate->mutex); if (!do_prefetch) return; tbmpre = tbm_shared_iterate(prefetch_iterator); if (tbmpre == NULL) { /* No more pages to prefetch */ tbm_end_shared_iterate(prefetch_iterator); node->shared_prefetch_iterator = NULL; break; } PrefetchBuffer(scan->rs_rd, MAIN_FORKNUM, tbmpre->blockno); } } } #endif /* USE_PREFETCH */ }
/* * BitmapPrefetch - Prefetch, if prefetch_pages are behind prefetch_target */ static inline void BitmapPrefetch(BitmapHeapScanState *node, HeapScanDesc scan) { #ifdef USE_PREFETCH ParallelBitmapHeapState *pstate = node->pstate; if (pstate == NULL) { TBMIterator *prefetch_iterator = node->prefetch_iterator; if (prefetch_iterator) { while (node->prefetch_pages < node->prefetch_target) { TBMIterateResult *tbmpre = tbm_iterate(prefetch_iterator); bool skip_fetch; if (tbmpre == NULL) { /* No more pages to prefetch */ tbm_end_iterate(prefetch_iterator); node->prefetch_iterator = NULL; break; } node->prefetch_pages++; /* * If we expect not to have to actually read this heap page, * skip this prefetch call, but continue to run the prefetch * logic normally. (Would it be better not to increment * prefetch_pages?) * * This depends on the assumption that the index AM will * report the same recheck flag for this future heap page as * it did for the current heap page; which is not a certainty * but is true in many cases. */ skip_fetch = (node->can_skip_fetch && (node->tbmres ? !node->tbmres->recheck : false) && VM_ALL_VISIBLE(node->ss.ss_currentRelation, tbmpre->blockno, &node->pvmbuffer)); if (!skip_fetch) PrefetchBuffer(scan->rs_rd, MAIN_FORKNUM, tbmpre->blockno); } } return; } if (pstate->prefetch_pages < pstate->prefetch_target) { TBMSharedIterator *prefetch_iterator = node->shared_prefetch_iterator; if (prefetch_iterator) { while (1) { TBMIterateResult *tbmpre; bool do_prefetch = false; bool skip_fetch; /* * Recheck under the mutex. If some other process has already * done enough prefetching then we need not to do anything. */ SpinLockAcquire(&pstate->mutex); if (pstate->prefetch_pages < pstate->prefetch_target) { pstate->prefetch_pages++; do_prefetch = true; } SpinLockRelease(&pstate->mutex); if (!do_prefetch) return; tbmpre = tbm_shared_iterate(prefetch_iterator); if (tbmpre == NULL) { /* No more pages to prefetch */ tbm_end_shared_iterate(prefetch_iterator); node->shared_prefetch_iterator = NULL; break; } /* As above, skip prefetch if we expect not to need page */ skip_fetch = (node->can_skip_fetch && (node->tbmres ? !node->tbmres->recheck : false) && VM_ALL_VISIBLE(node->ss.ss_currentRelation, tbmpre->blockno, &node->pvmbuffer)); if (!skip_fetch) PrefetchBuffer(scan->rs_rd, MAIN_FORKNUM, tbmpre->blockno); } } } #endif /* USE_PREFETCH */ }