From 9e0fe09fc5dc1135479b532d1806e28cbc5a35aa Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Thu, 2 Mar 2017 18:47:40 +0530 Subject: [PATCH] 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. --- src/backend/executor/nodeBitmapHeapscan.c | 148 +++++++++++++--------- 1 file changed, 88 insertions(+), 60 deletions(-) diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c index c871aa0348..c1aa9f13bd 100644 --- a/src/backend/executor/nodeBitmapHeapscan.c +++ b/src/backend/executor/nodeBitmapHeapscan.c @@ -53,6 +53,11 @@ static TupleTableSlot *BitmapHeapNext(BitmapHeapScanState *node); 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; TBMIterator *tbmiterator; TBMIterateResult *tbmres; - -#ifdef USE_PREFETCH - TBMIterator *prefetch_iterator; -#endif OffsetNumber targoffset; TupleTableSlot *slot; @@ -85,9 +86,6 @@ BitmapHeapNext(BitmapHeapScanState *node) tbm = node->tbm; tbmiterator = node->tbmiterator; 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 @@ -115,7 +113,7 @@ BitmapHeapNext(BitmapHeapScanState *node) #ifdef USE_PREFETCH 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_target = -1; } @@ -139,21 +137,7 @@ BitmapHeapNext(BitmapHeapScanState *node) 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 */ + BitmapAdjustPrefetchIterator(node, tbmres); /* * Ignore any claimed entries past what we think is the end of the @@ -182,23 +166,8 @@ BitmapHeapNext(BitmapHeapScanState *node) */ 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 >= 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 */ + /* Adjust the prefetch target */ + BitmapAdjustPrefetchTarget(node); } else { @@ -227,8 +196,6 @@ BitmapHeapNext(BitmapHeapScanState *node) 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 @@ -236,24 +203,7 @@ BitmapHeapNext(BitmapHeapScanState *node) * 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 */ + BitmapPrefetch(node, scan); /* * Okay to fetch the tuple @@ -411,6 +361,84 @@ bitgetpage(HeapScanDesc scan, TBMIterateResult *tbmres) 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 */