LCOV - code coverage report
Current view: top level - src/backend/executor - nodeBitmapHeapscan.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 312 326 95.7 %
Date: 2019-11-22 06:06:53 Functions: 14 15 93.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13