From 9f31c6fc35414cfb1e52d8476e1f490c2b329c6d Mon Sep 17 00:00:00 2001 From: Melanie Plageman Date: Sat, 6 Apr 2024 12:41:05 -0400 Subject: [PATCH v21 04/20] Add common interface for TBMIterators Add and use TBMSerialIterator, which replaces the current TBMIterator for serial use cases, and repurpose TBMIterator to be a unified interface for both the serial and parallel TID Bitmap iterator interfaces. This encapsulation simplifies call sites for callers supporting both parallel and serial TID Bitmap access. TBMIterator is not yet used in this commit. Author: Melanie Plageman Discussion: https://postgr.es/m/CAAKRu_ZwCwWFeL_H3ia26bP2e7HiKLWt0ZmGXPVwPO6uXq0vaA%40mail.gmail.com --- src/backend/access/gin/ginget.c | 8 +- src/backend/access/gin/ginscan.c | 2 +- src/backend/access/heap/heapam_handler.c | 2 +- src/backend/executor/nodeBitmapHeapscan.c | 20 ++--- src/backend/nodes/tidbitmap.c | 102 +++++++++++++++++----- src/include/access/gin_private.h | 2 +- src/include/access/relscan.h | 4 +- src/include/access/tableam.h | 4 +- src/include/nodes/execnodes.h | 2 +- src/include/nodes/tidbitmap.h | 27 ++++-- src/tools/pgindent/typedefs.list | 1 + 11 files changed, 125 insertions(+), 49 deletions(-) diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c index 0b4f2ebadb6..0d66381df1e 100644 --- a/src/backend/access/gin/ginget.c +++ b/src/backend/access/gin/ginget.c @@ -373,7 +373,7 @@ restartScanEntry: if (entry->matchBitmap) { if (entry->matchIterator) - tbm_end_iterate(entry->matchIterator); + tbm_end_serial_iterate(entry->matchIterator); entry->matchIterator = NULL; tbm_free(entry->matchBitmap); entry->matchBitmap = NULL; @@ -385,7 +385,7 @@ restartScanEntry: if (entry->matchBitmap && !tbm_is_empty(entry->matchBitmap)) { - entry->matchIterator = tbm_begin_iterate(entry->matchBitmap); + entry->matchIterator = tbm_begin_serial_iterate(entry->matchBitmap); entry->isFinished = false; } } @@ -832,12 +832,12 @@ entryGetItem(GinState *ginstate, GinScanEntry entry, (ItemPointerIsLossyPage(&advancePast) && entry->matchResult->blockno == advancePastBlk)) { - entry->matchResult = tbm_iterate(entry->matchIterator); + entry->matchResult = tbm_serial_iterate(entry->matchIterator); if (entry->matchResult == NULL) { ItemPointerSetInvalid(&entry->curItem); - tbm_end_iterate(entry->matchIterator); + tbm_end_serial_iterate(entry->matchIterator); entry->matchIterator = NULL; entry->isFinished = true; break; diff --git a/src/backend/access/gin/ginscan.c b/src/backend/access/gin/ginscan.c index af24d38544e..46dde99514d 100644 --- a/src/backend/access/gin/ginscan.c +++ b/src/backend/access/gin/ginscan.c @@ -246,7 +246,7 @@ ginFreeScanKeys(GinScanOpaque so) if (entry->list) pfree(entry->list); if (entry->matchIterator) - tbm_end_iterate(entry->matchIterator); + tbm_end_serial_iterate(entry->matchIterator); if (entry->matchBitmap) tbm_free(entry->matchBitmap); } diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index 3110f97473f..ff46ad8f330 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -2143,7 +2143,7 @@ heapam_scan_bitmap_next_block(TableScanDesc scan, if (scan->shared_tbmiterator) tbmres = tbm_shared_iterate(scan->shared_tbmiterator); else - tbmres = tbm_iterate(scan->tbmiterator); + tbmres = tbm_serial_iterate(scan->tbmiterator); if (tbmres == NULL) return false; diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c index e8b4a754434..f6e066a0cb3 100644 --- a/src/backend/executor/nodeBitmapHeapscan.c +++ b/src/backend/executor/nodeBitmapHeapscan.c @@ -96,7 +96,7 @@ BitmapHeapNext(BitmapHeapScanState *node) */ if (!node->initialized) { - TBMIterator *tbmiterator = NULL; + TBMSerialIterator *tbmiterator = NULL; TBMSharedIterator *shared_tbmiterator = NULL; if (!pstate) @@ -107,12 +107,12 @@ BitmapHeapNext(BitmapHeapScanState *node) elog(ERROR, "unrecognized result from subplan"); node->tbm = tbm; - tbmiterator = tbm_begin_iterate(tbm); + tbmiterator = tbm_begin_serial_iterate(tbm); #ifdef USE_PREFETCH if (node->prefetch_maximum > 0) { - node->prefetch_iterator = tbm_begin_iterate(tbm); + node->prefetch_iterator = tbm_begin_serial_iterate(tbm); node->prefetch_pages = 0; node->prefetch_target = -1; } @@ -324,7 +324,7 @@ BitmapAdjustPrefetchIterator(BitmapHeapScanState *node) if (pstate == NULL) { - TBMIterator *prefetch_iterator = node->prefetch_iterator; + TBMSerialIterator *prefetch_iterator = node->prefetch_iterator; if (node->prefetch_pages > 0) { @@ -334,7 +334,7 @@ BitmapAdjustPrefetchIterator(BitmapHeapScanState *node) else if (prefetch_iterator) { /* Do not let the prefetch iterator get behind the main one */ - tbmpre = tbm_iterate(prefetch_iterator); + tbmpre = tbm_serial_iterate(prefetch_iterator); node->pfblockno = tbmpre ? tbmpre->blockno : InvalidBlockNumber; } return; @@ -437,19 +437,19 @@ BitmapPrefetch(BitmapHeapScanState *node, TableScanDesc scan) if (pstate == NULL) { - TBMIterator *prefetch_iterator = node->prefetch_iterator; + TBMSerialIterator *prefetch_iterator = node->prefetch_iterator; if (prefetch_iterator) { while (node->prefetch_pages < node->prefetch_target) { - TBMIterateResult *tbmpre = tbm_iterate(prefetch_iterator); + TBMIterateResult *tbmpre = tbm_serial_iterate(prefetch_iterator); bool skip_fetch; if (tbmpre == NULL) { /* No more pages to prefetch */ - tbm_end_iterate(prefetch_iterator); + tbm_end_serial_iterate(prefetch_iterator); node->prefetch_iterator = NULL; break; } @@ -576,7 +576,7 @@ ExecReScanBitmapHeapScan(BitmapHeapScanState *node) /* release bitmaps and buffers if any */ if (node->prefetch_iterator) - tbm_end_iterate(node->prefetch_iterator); + tbm_end_serial_iterate(node->prefetch_iterator); if (node->shared_prefetch_iterator) tbm_end_shared_iterate(node->shared_prefetch_iterator); if (node->tbm) @@ -632,7 +632,7 @@ ExecEndBitmapHeapScan(BitmapHeapScanState *node) * release bitmaps and buffers if any */ if (node->prefetch_iterator) - tbm_end_iterate(node->prefetch_iterator); + tbm_end_serial_iterate(node->prefetch_iterator); if (node->tbm) tbm_free(node->tbm); if (node->shared_prefetch_iterator) diff --git a/src/backend/nodes/tidbitmap.c b/src/backend/nodes/tidbitmap.c index e8ab5d78fcc..429cb8bd7c9 100644 --- a/src/backend/nodes/tidbitmap.c +++ b/src/backend/nodes/tidbitmap.c @@ -170,12 +170,12 @@ struct TIDBitmap }; /* - * When iterating over a bitmap in sorted order, a TBMIterator is used to - * track our progress. There can be several iterators scanning the same - * bitmap concurrently. Note that the bitmap becomes read-only as soon as - * any iterator is created. + * When iterating over a backend-local bitmap in sorted order, a + * TBMSerialIterator is used to track our progress. There can be several + * iterators scanning the same bitmap concurrently. Note that the bitmap + * becomes read-only as soon as any iterator is created. */ -struct TBMIterator +struct TBMSerialIterator { TIDBitmap *tbm; /* TIDBitmap we're iterating over */ int spageptr; /* next spages index */ @@ -213,8 +213,8 @@ typedef struct PTIterationArray } PTIterationArray; /* - * same as TBMIterator, but it is used for joint iteration, therefore this - * also holds a reference to the shared state. + * same as TBMSerialIterator, but it is used for joint iteration, therefore + * this also holds a reference to the shared state. */ struct TBMSharedIterator { @@ -673,31 +673,31 @@ tbm_is_empty(const TIDBitmap *tbm) } /* - * tbm_begin_iterate - prepare to iterate through a TIDBitmap + * tbm_begin_serial_iterate - prepare to iterate through a TIDBitmap * - * The TBMIterator struct is created in the caller's memory context. - * For a clean shutdown of the iteration, call tbm_end_iterate; but it's - * okay to just allow the memory context to be released, too. It is caller's - * responsibility not to touch the TBMIterator anymore once the TIDBitmap + * The TBMSerialIterator struct is created in the caller's memory context. For + * a clean shutdown of the iteration, call tbm_end_iterate; but it's okay to + * just allow the memory context to be released, too. It is caller's + * responsibility not to touch the TBMSerialIterator anymore once the TIDBitmap * is freed. * * NB: after this is called, it is no longer allowed to modify the contents * of the bitmap. However, you can call this multiple times to scan the * contents repeatedly, including parallel scans. */ -TBMIterator * -tbm_begin_iterate(TIDBitmap *tbm) +TBMSerialIterator * +tbm_begin_serial_iterate(TIDBitmap *tbm) { - TBMIterator *iterator; + TBMSerialIterator *iterator; Assert(tbm->iterating != TBM_ITERATING_SHARED); /* - * Create the TBMIterator struct, with enough trailing space to serve the - * needs of the TBMIterateResult sub-struct. + * Create the TBMSerialIterator struct, with enough trailing space to + * serve the needs of the TBMIterateResult sub-struct. */ - iterator = (TBMIterator *) palloc(sizeof(TBMIterator) + - MAX_TUPLES_PER_PAGE * sizeof(OffsetNumber)); + iterator = (TBMSerialIterator *) palloc(sizeof(TBMSerialIterator) + + MAX_TUPLES_PER_PAGE * sizeof(OffsetNumber)); iterator->tbm = tbm; /* @@ -956,7 +956,7 @@ tbm_advance_schunkbit(PagetableEntry *chunk, int *schunkbitp) } /* - * tbm_iterate - scan through next page of a TIDBitmap + * tbm_serial_iterate - scan through next page of a TIDBitmap * * Returns a TBMIterateResult representing one page, or NULL if there are * no more pages to scan. Pages are guaranteed to be delivered in numerical @@ -968,7 +968,7 @@ tbm_advance_schunkbit(PagetableEntry *chunk, int *schunkbitp) * testing, recheck is always set true when ntuples < 0.) */ TBMIterateResult * -tbm_iterate(TBMIterator *iterator) +tbm_serial_iterate(TBMSerialIterator *iterator) { TIDBitmap *tbm = iterator->tbm; TBMIterateResult *output = &(iterator->output); @@ -1143,7 +1143,7 @@ tbm_shared_iterate(TBMSharedIterator *iterator) * bitmap to return to read/write status when there are no more iterators.) */ void -tbm_end_iterate(TBMIterator *iterator) +tbm_end_serial_iterate(TBMSerialIterator *iterator) { pfree(iterator); } @@ -1556,3 +1556,61 @@ tbm_calculate_entries(double maxbytes) return nbuckets; } + +/* + * Start iteration on a shared or non-shared bitmap iterator. Note that tbm + * will only be provided by serial BitmapHeapScan callers. dsa and dsp will + * only be provided by parallel BitmapHeapScan callers. For shared callers, one + * process must already have called tbm_prepare_shared_iterate() to create and + * set up the TBMSharedIteratorState. The TBMIterator is passed by reference to + * accommodate callers who would like to allocate it inside an existing struct. + */ +void +tbm_begin_iterate(TBMIterator *iterator, TIDBitmap *tbm, + dsa_area *dsa, dsa_pointer dsp) +{ + Assert(iterator); + + iterator->serial = NULL; + iterator->parallel = NULL; + iterator->exhausted = false; + + /* Allocate a private iterator and attach the shared state to it */ + if (DsaPointerIsValid(dsp)) + iterator->parallel = tbm_attach_shared_iterate(dsa, dsp); + else + iterator->serial = tbm_begin_serial_iterate(tbm); +} + +/* + * Clean up shared or non-shared bitmap iterator. + */ +void +tbm_end_iterate(TBMIterator *iterator) +{ + Assert(iterator); + + if (iterator->serial) + tbm_end_serial_iterate(iterator->serial); + else if (iterator->parallel) + tbm_end_shared_iterate(iterator->parallel); + + iterator->serial = NULL; + iterator->parallel = NULL; + iterator->exhausted = true; +} + +/* + * Get the next TBMIterateResult from the shared or non-shared bitmap iterator. + */ +TBMIterateResult * +tbm_iterate(TBMIterator *iterator) +{ + Assert(iterator); + Assert(!iterator->exhausted); + + if (iterator->serial) + return tbm_serial_iterate(iterator->serial); + else + return tbm_shared_iterate(iterator->parallel); +} diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h index 3013a44bae1..cfac6ca3923 100644 --- a/src/include/access/gin_private.h +++ b/src/include/access/gin_private.h @@ -352,7 +352,7 @@ typedef struct GinScanEntryData /* for a partial-match or full-scan query, we accumulate all TIDs here */ TIDBitmap *matchBitmap; - TBMIterator *matchIterator; + TBMSerialIterator *matchIterator; TBMIterateResult *matchResult; /* used for Posting list and one page in Posting tree */ diff --git a/src/include/access/relscan.h b/src/include/access/relscan.h index 024dc08c420..74562a1a155 100644 --- a/src/include/access/relscan.h +++ b/src/include/access/relscan.h @@ -24,7 +24,7 @@ struct ParallelTableScanDescData; -struct TBMIterator; +struct TBMSerialIterator; struct TBMSharedIterator; /* @@ -40,7 +40,7 @@ typedef struct TableScanDescData struct ScanKeyData *rs_key; /* array of scan key descriptors */ /* Iterators for Bitmap Table Scans */ - struct TBMIterator *tbmiterator; + struct TBMSerialIterator *tbmiterator; struct TBMSharedIterator *shared_tbmiterator; /* Range of ItemPointers for table_scan_getnextslot_tidrange() to scan. */ diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h index 2f4e221870e..6829f542621 100644 --- a/src/include/access/tableam.h +++ b/src/include/access/tableam.h @@ -1033,7 +1033,7 @@ table_endscan(TableScanDesc scan) if (scan->tbmiterator) { - tbm_end_iterate(scan->tbmiterator); + tbm_end_serial_iterate(scan->tbmiterator); scan->tbmiterator = NULL; } } @@ -1058,7 +1058,7 @@ table_rescan(TableScanDesc scan, if (scan->tbmiterator) { - tbm_end_iterate(scan->tbmiterator); + tbm_end_serial_iterate(scan->tbmiterator); scan->tbmiterator = NULL; } } diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 0af7906a184..d1ed606fb71 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -1818,7 +1818,7 @@ typedef struct BitmapHeapScanState Buffer pvmbuffer; long exact_pages; long lossy_pages; - TBMIterator *prefetch_iterator; + TBMSerialIterator *prefetch_iterator; int prefetch_pages; int prefetch_target; int prefetch_maximum; diff --git a/src/include/nodes/tidbitmap.h b/src/include/nodes/tidbitmap.h index 1945f0639bf..7fc2c4a464c 100644 --- a/src/include/nodes/tidbitmap.h +++ b/src/include/nodes/tidbitmap.h @@ -32,8 +32,8 @@ */ typedef struct TIDBitmap TIDBitmap; -/* Likewise, TBMIterator is private */ -typedef struct TBMIterator TBMIterator; +/* Likewise, TBMSerialIterator is private */ +typedef struct TBMSerialIterator TBMSerialIterator; typedef struct TBMSharedIterator TBMSharedIterator; /* Result structure for tbm_iterate */ @@ -46,6 +46,17 @@ typedef struct TBMIterateResult OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]; } TBMIterateResult; +/* + * Callers with both serial and parallel implementations can use this unified + * API. + */ +typedef struct TBMIterator +{ + TBMSerialIterator *serial; + TBMSharedIterator *parallel; + bool exhausted; +} TBMIterator; + /* function prototypes in nodes/tidbitmap.c */ extern TIDBitmap *tbm_create(long maxbytes, dsa_area *dsa); @@ -62,14 +73,20 @@ extern void tbm_intersect(TIDBitmap *a, const TIDBitmap *b); extern bool tbm_is_empty(const TIDBitmap *tbm); -extern TBMIterator *tbm_begin_iterate(TIDBitmap *tbm); +extern TBMSerialIterator *tbm_begin_serial_iterate(TIDBitmap *tbm); extern dsa_pointer tbm_prepare_shared_iterate(TIDBitmap *tbm); -extern TBMIterateResult *tbm_iterate(TBMIterator *iterator); +extern TBMIterateResult *tbm_serial_iterate(TBMSerialIterator *iterator); extern TBMIterateResult *tbm_shared_iterate(TBMSharedIterator *iterator); -extern void tbm_end_iterate(TBMIterator *iterator); +extern void tbm_end_serial_iterate(TBMSerialIterator *iterator); extern void tbm_end_shared_iterate(TBMSharedIterator *iterator); extern TBMSharedIterator *tbm_attach_shared_iterate(dsa_area *dsa, dsa_pointer dp); extern long tbm_calculate_entries(double maxbytes); +extern void tbm_begin_iterate(TBMIterator *iterator, TIDBitmap *tbm, + dsa_area *dsa, dsa_pointer dsp); +extern void tbm_end_iterate(TBMIterator *iterator); +extern TBMIterateResult *tbm_iterate(TBMIterator *iterator); + + #endif /* TIDBITMAP_H */ diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 61ad417cde6..910fbdd880c 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -2795,6 +2795,7 @@ TAR_MEMBER TBMIterateResult TBMIteratingState TBMIterator +TBMSerialIterator TBMSharedIterator TBMSharedIteratorState TBMStatus -- 2.34.1