Refactor bitmap heap scan in preparation for parallel support.

The final patch will be less messy if the prefetching support is
a bit better isolated, so do that.

Dilip Kumar, with some changes by me.  The larger patch set of which
this is a part has been reviewed and tested by (at least) Andres
Freund, Amit Khandekar, Tushar Ahuja, Rafia Sabih, Haribabu Kommi, and
Thomas Munro.
This commit is contained in:
Robert Haas 2017-03-02 18:47:40 +05:30
parent 3c3bb99330
commit 9e0fe09fc5
1 changed files with 88 additions and 60 deletions

View File

@ -53,6 +53,11 @@
static TupleTableSlot *BitmapHeapNext(BitmapHeapScanState *node); static TupleTableSlot *BitmapHeapNext(BitmapHeapScanState *node);
static void bitgetpage(HeapScanDesc scan, TBMIterateResult *tbmres); static void bitgetpage(HeapScanDesc scan, TBMIterateResult *tbmres);
static inline void BitmapAdjustPrefetchIterator(BitmapHeapScanState *node,
TBMIterateResult *tbmres);
static inline void BitmapAdjustPrefetchTarget(BitmapHeapScanState *node);
static inline void BitmapPrefetch(BitmapHeapScanState *node,
HeapScanDesc scan);
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
@ -69,10 +74,6 @@ BitmapHeapNext(BitmapHeapScanState *node)
TIDBitmap *tbm; TIDBitmap *tbm;
TBMIterator *tbmiterator; TBMIterator *tbmiterator;
TBMIterateResult *tbmres; TBMIterateResult *tbmres;
#ifdef USE_PREFETCH
TBMIterator *prefetch_iterator;
#endif
OffsetNumber targoffset; OffsetNumber targoffset;
TupleTableSlot *slot; TupleTableSlot *slot;
@ -85,9 +86,6 @@ BitmapHeapNext(BitmapHeapScanState *node)
tbm = node->tbm; tbm = node->tbm;
tbmiterator = node->tbmiterator; tbmiterator = node->tbmiterator;
tbmres = node->tbmres; tbmres = node->tbmres;
#ifdef USE_PREFETCH
prefetch_iterator = node->prefetch_iterator;
#endif
/* /*
* If we haven't yet performed the underlying index scan, do it, and begin * If we haven't yet performed the underlying index scan, do it, and begin
@ -115,7 +113,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
#ifdef USE_PREFETCH #ifdef USE_PREFETCH
if (node->prefetch_maximum > 0) if (node->prefetch_maximum > 0)
{ {
node->prefetch_iterator = prefetch_iterator = tbm_begin_iterate(tbm); node->prefetch_iterator = tbm_begin_iterate(tbm);
node->prefetch_pages = 0; node->prefetch_pages = 0;
node->prefetch_target = -1; node->prefetch_target = -1;
} }
@ -139,21 +137,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
break; break;
} }
#ifdef USE_PREFETCH BitmapAdjustPrefetchIterator(node, tbmres);
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 * Ignore any claimed entries past what we think is the end of the
@ -182,23 +166,8 @@ BitmapHeapNext(BitmapHeapScanState *node)
*/ */
scan->rs_cindex = 0; scan->rs_cindex = 0;
#ifdef USE_PREFETCH /* Adjust the prefetch target */
BitmapAdjustPrefetchTarget(node);
/*
* 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 >= node->prefetch_maximum)
/* don't increase any further */ ;
else if (node->prefetch_target >= node->prefetch_maximum / 2)
node->prefetch_target = node->prefetch_maximum;
else if (node->prefetch_target > 0)
node->prefetch_target *= 2;
else
node->prefetch_target++;
#endif /* USE_PREFETCH */
} }
else else
{ {
@ -227,8 +196,6 @@ BitmapHeapNext(BitmapHeapScanState *node)
continue; continue;
} }
#ifdef USE_PREFETCH
/* /*
* We issue prefetch requests *after* fetching the current page to try * We issue prefetch requests *after* fetching the current page to try
* to avoid having prefetching interfere with the main I/O. Also, this * to avoid having prefetching interfere with the main I/O. Also, this
@ -236,24 +203,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
* to do on the current page, else we may uselessly prefetch the same * to do on the current page, else we may uselessly prefetch the same
* page we are just about to request for real. * page we are just about to request for real.
*/ */
if (prefetch_iterator) BitmapPrefetch(node, scan);
{
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 * Okay to fetch the tuple
@ -411,6 +361,84 @@ bitgetpage(HeapScanDesc scan, TBMIterateResult *tbmres)
scan->rs_ntuples = ntup; scan->rs_ntuples = ntup;
} }
/*
* BitmapAdjustPrefetchIterator - Adjust the prefetch iterator
*/
static inline void
BitmapAdjustPrefetchIterator(BitmapHeapScanState *node,
TBMIterateResult *tbmres)
{
#ifdef USE_PREFETCH
TBMIterator *prefetch_iterator = node->prefetch_iterator;
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 */
}
/*
* BitmapAdjustPrefetchTarget - Adjust the prefetch target
*
* 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.
*/
static inline void
BitmapAdjustPrefetchTarget(BitmapHeapScanState *node)
{
#ifdef USE_PREFETCH
if (node->prefetch_target >= node->prefetch_maximum)
/* don't increase any further */ ;
else if (node->prefetch_target >= node->prefetch_maximum / 2)
node->prefetch_target = node->prefetch_maximum;
else if (node->prefetch_target > 0)
node->prefetch_target *= 2;
else
node->prefetch_target++;
#endif /* USE_PREFETCH */
}
/*
* BitmapPrefetch - Prefetch, if prefetch_pages are behind prefetch_target
*/
static inline void
BitmapPrefetch(BitmapHeapScanState *node, HeapScanDesc scan)
{
#ifdef USE_PREFETCH
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);
}
}
#endif /* USE_PREFETCH */
}
/* /*
* BitmapHeapRecheck -- access method routine to recheck a tuple in EvalPlanQual * BitmapHeapRecheck -- access method routine to recheck a tuple in EvalPlanQual
*/ */