v24-0012-Move-BitmapHeapScanNextBlock-next-to-other-helpe.patch
application/octet-stream
Filename: v24-0012-Move-BitmapHeapScanNextBlock-next-to-other-helpe.patch
Type: application/octet-stream
Part: 10
Patch
Format: format-patch
Series: patch v24-0012
Subject: Move BitmapHeapScanNextBlock() next to other helpers
| File | + | − |
|---|---|---|
| src/backend/access/heap/heapam_handler.c | 180 | 180 |
From e0ab52f8ad2d0c321644c09c558988e85cdc7090 Mon Sep 17 00:00:00 2001
From: Melanie Plageman <melanieplageman@gmail.com>
Date: Mon, 14 Oct 2024 16:10:59 -0400
Subject: [PATCH v24 12/12] Move BitmapHeapScanNextBlock() next to other
helpers
A previous commit turned heapam_scan_bitmap_next_block() into a helper
for heapam_scan_bitmap_next_tuple(). Move it down in heapam_handler.c
next to the other helpers. This is its own commit to make the diff more
readable.
---
src/backend/access/heap/heapam_handler.c | 360 +++++++++++------------
1 file changed, 180 insertions(+), 180 deletions(-)
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index 6fc779e1d0..6c5a7d3f4e 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -2121,186 +2121,6 @@ heapam_estimate_rel_size(Relation rel, int32 *attr_widths,
* ------------------------------------------------------------------------
*/
-/*
- * Helper function get the next block of a bitmap heap scan. Returns true when
- * it got the next block and saved it in the scan descriptor and false when the
- * bitmap and or relation are exhausted.
- */
-static bool
-BitmapHeapScanNextBlock(TableScanDesc scan,
- bool *recheck,
- uint64 *lossy_pages, uint64 *exact_pages)
-{
- BitmapHeapScanDesc *bscan = (BitmapHeapScanDesc *) scan;
- HeapScanDesc hscan = &bscan->rs_heap_base;
- BlockNumber block;
- Buffer buffer;
- Snapshot snapshot;
- int ntup;
- TBMIterateResult *tbmres;
-
- hscan->rs_cindex = 0;
- hscan->rs_ntuples = 0;
-
- *recheck = true;
-
- BitmapAdjustPrefetchIterator(bscan);
-
- do
- {
- CHECK_FOR_INTERRUPTS();
-
- tbmres = tbm_iterate(&scan->st.bts.tbmiterator);
-
- if (tbmres == NULL)
- return false;
-
- /*
- * Ignore any claimed entries past what we think is the end of the
- * relation. It may have been extended after the start of our scan (we
- * only hold an AccessShareLock, and it could be inserts from this
- * backend). We don't take this optimization in SERIALIZABLE
- * isolation though, as we need to examine all invisible tuples
- * reachable by the index.
- */
- } while (!IsolationIsSerializable() && tbmres->blockno >= hscan->rs_nblocks);
-
- /* Got a valid block */
- block = tbmres->blockno;
- *recheck = tbmres->recheck;
-
- /*
- * We can skip fetching the heap page if we don't need any fields from the
- * heap, the bitmap entries don't need rechecking, and all tuples on the
- * page are visible to our transaction.
- */
- if (!(scan->rs_flags & SO_NEED_TUPLES) &&
- !tbmres->recheck &&
- VM_ALL_VISIBLE(scan->rs_rd, tbmres->blockno, &bscan->rs_vmbuffer))
- {
- /* can't be lossy in the skip_fetch case */
- Assert(tbmres->ntuples >= 0);
- Assert(bscan->rs_empty_tuples_pending >= 0);
-
- bscan->rs_empty_tuples_pending += tbmres->ntuples;
-
- return true;
- }
-
- /*
- * Acquire pin on the target heap page, trading in any pin we held before.
- */
- hscan->rs_cbuf = ReleaseAndReadBuffer(hscan->rs_cbuf,
- scan->rs_rd,
- block);
- hscan->rs_cblock = block;
- buffer = hscan->rs_cbuf;
- snapshot = scan->rs_snapshot;
-
- ntup = 0;
-
- /*
- * Prune and repair fragmentation for the whole page, if possible.
- */
- heap_page_prune_opt(scan->rs_rd, buffer);
-
- /*
- * We must hold share lock on the buffer content while examining tuple
- * visibility. Afterwards, however, the tuples we have found to be
- * visible are guaranteed good as long as we hold the buffer pin.
- */
- LockBuffer(buffer, BUFFER_LOCK_SHARE);
-
- /*
- * We need two separate strategies for lossy and non-lossy cases.
- */
- if (tbmres->ntuples >= 0)
- {
- /*
- * Bitmap is non-lossy, so we just look through the offsets listed in
- * tbmres; but we have to follow any HOT chain starting at each such
- * offset.
- */
- int curslot;
-
- for (curslot = 0; curslot < tbmres->ntuples; curslot++)
- {
- OffsetNumber offnum = tbmres->offsets[curslot];
- ItemPointerData tid;
- HeapTupleData heapTuple;
-
- ItemPointerSet(&tid, block, offnum);
- if (heap_hot_search_buffer(&tid, scan->rs_rd, buffer, snapshot,
- &heapTuple, NULL, true))
- hscan->rs_vistuples[ntup++] = ItemPointerGetOffsetNumber(&tid);
- }
- }
- else
- {
- /*
- * Bitmap is lossy, so we must examine each line pointer on the page.
- * But we can ignore HOT chains, since we'll check each tuple anyway.
- */
- Page page = BufferGetPage(buffer);
- OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
- OffsetNumber offnum;
-
- for (offnum = FirstOffsetNumber; offnum <= maxoff; offnum = OffsetNumberNext(offnum))
- {
- ItemId lp;
- HeapTupleData loctup;
- bool valid;
-
- lp = PageGetItemId(page, offnum);
- if (!ItemIdIsNormal(lp))
- continue;
- loctup.t_data = (HeapTupleHeader) PageGetItem(page, lp);
- loctup.t_len = ItemIdGetLength(lp);
- loctup.t_tableOid = scan->rs_rd->rd_id;
- ItemPointerSet(&loctup.t_self, block, offnum);
- valid = HeapTupleSatisfiesVisibility(&loctup, snapshot, buffer);
- if (valid)
- {
- hscan->rs_vistuples[ntup++] = offnum;
- PredicateLockTID(scan->rs_rd, &loctup.t_self, snapshot,
- HeapTupleHeaderGetXmin(loctup.t_data));
- }
- HeapCheckForSerializableConflictOut(valid, scan->rs_rd, &loctup,
- buffer, snapshot);
- }
- }
-
- LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
-
- Assert(ntup <= MaxHeapTuplesPerPage);
- hscan->rs_ntuples = ntup;
-
- if (tbmres->ntuples >= 0)
- (*exact_pages)++;
- else
- (*lossy_pages)++;
-
- /*
- * If private, we can error out if the the prefetch block doesn't stay
- * ahead of the current block.
- */
- if (scan->st.bts.pstate == NULL &&
- !tbm_exhausted(&scan->st.bts.prefetch_iterator) &&
- bscan->rs_pfblockno < block)
- elog(ERROR, "prefetch and main iterators are out of sync. :fblockno: %d. block: %d", bscan->rs_pfblockno, block);
-
- /* Adjust the prefetch target */
- BitmapAdjustPrefetchTarget(bscan);
-
- /*
- * Return true to indicate that a valid block was found and the bitmap is
- * not exhausted. If there are no visible tuples on this page,
- * hscan->rs_ntuples will be 0 and heapam_scan_bitmap_next_tuple() will
- * invoke this function again.
- */
- return true;
-}
-
static bool
heapam_scan_bitmap_next_tuple(TableScanDesc scan,
TupleTableSlot *slot,
@@ -2902,6 +2722,186 @@ BitmapPrefetch(BitmapHeapScanDesc *bscan)
#endif /* USE_PREFETCH */
}
+/*
+ * Helper function get the next block of a bitmap heap scan. Returns true when
+ * it got the next block and saved it in the scan descriptor and false when the
+ * bitmap and or relation are exhausted.
+ */
+static bool
+BitmapHeapScanNextBlock(TableScanDesc scan,
+ bool *recheck,
+ uint64 *lossy_pages, uint64 *exact_pages)
+{
+ BitmapHeapScanDesc *bscan = (BitmapHeapScanDesc *) scan;
+ HeapScanDesc hscan = &bscan->rs_heap_base;
+ BlockNumber block;
+ Buffer buffer;
+ Snapshot snapshot;
+ int ntup;
+ TBMIterateResult *tbmres;
+
+ hscan->rs_cindex = 0;
+ hscan->rs_ntuples = 0;
+
+ *recheck = true;
+
+ BitmapAdjustPrefetchIterator(bscan);
+
+ do
+ {
+ CHECK_FOR_INTERRUPTS();
+
+ tbmres = tbm_iterate(&scan->st.bts.tbmiterator);
+
+ if (tbmres == NULL)
+ return false;
+
+ /*
+ * Ignore any claimed entries past what we think is the end of the
+ * relation. It may have been extended after the start of our scan (we
+ * only hold an AccessShareLock, and it could be inserts from this
+ * backend). We don't take this optimization in SERIALIZABLE
+ * isolation though, as we need to examine all invisible tuples
+ * reachable by the index.
+ */
+ } while (!IsolationIsSerializable() && tbmres->blockno >= hscan->rs_nblocks);
+
+ /* Got a valid block */
+ block = tbmres->blockno;
+ *recheck = tbmres->recheck;
+
+ /*
+ * We can skip fetching the heap page if we don't need any fields from the
+ * heap, the bitmap entries don't need rechecking, and all tuples on the
+ * page are visible to our transaction.
+ */
+ if (!(scan->rs_flags & SO_NEED_TUPLES) &&
+ !tbmres->recheck &&
+ VM_ALL_VISIBLE(scan->rs_rd, tbmres->blockno, &bscan->rs_vmbuffer))
+ {
+ /* can't be lossy in the skip_fetch case */
+ Assert(tbmres->ntuples >= 0);
+ Assert(bscan->rs_empty_tuples_pending >= 0);
+
+ bscan->rs_empty_tuples_pending += tbmres->ntuples;
+
+ return true;
+ }
+
+ /*
+ * Acquire pin on the target heap page, trading in any pin we held before.
+ */
+ hscan->rs_cbuf = ReleaseAndReadBuffer(hscan->rs_cbuf,
+ scan->rs_rd,
+ block);
+ hscan->rs_cblock = block;
+ buffer = hscan->rs_cbuf;
+ snapshot = scan->rs_snapshot;
+
+ ntup = 0;
+
+ /*
+ * Prune and repair fragmentation for the whole page, if possible.
+ */
+ heap_page_prune_opt(scan->rs_rd, buffer);
+
+ /*
+ * We must hold share lock on the buffer content while examining tuple
+ * visibility. Afterwards, however, the tuples we have found to be
+ * visible are guaranteed good as long as we hold the buffer pin.
+ */
+ LockBuffer(buffer, BUFFER_LOCK_SHARE);
+
+ /*
+ * We need two separate strategies for lossy and non-lossy cases.
+ */
+ if (tbmres->ntuples >= 0)
+ {
+ /*
+ * Bitmap is non-lossy, so we just look through the offsets listed in
+ * tbmres; but we have to follow any HOT chain starting at each such
+ * offset.
+ */
+ int curslot;
+
+ for (curslot = 0; curslot < tbmres->ntuples; curslot++)
+ {
+ OffsetNumber offnum = tbmres->offsets[curslot];
+ ItemPointerData tid;
+ HeapTupleData heapTuple;
+
+ ItemPointerSet(&tid, block, offnum);
+ if (heap_hot_search_buffer(&tid, scan->rs_rd, buffer, snapshot,
+ &heapTuple, NULL, true))
+ hscan->rs_vistuples[ntup++] = ItemPointerGetOffsetNumber(&tid);
+ }
+ }
+ else
+ {
+ /*
+ * Bitmap is lossy, so we must examine each line pointer on the page.
+ * But we can ignore HOT chains, since we'll check each tuple anyway.
+ */
+ Page page = BufferGetPage(buffer);
+ OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
+ OffsetNumber offnum;
+
+ for (offnum = FirstOffsetNumber; offnum <= maxoff; offnum = OffsetNumberNext(offnum))
+ {
+ ItemId lp;
+ HeapTupleData loctup;
+ bool valid;
+
+ lp = PageGetItemId(page, offnum);
+ if (!ItemIdIsNormal(lp))
+ continue;
+ loctup.t_data = (HeapTupleHeader) PageGetItem(page, lp);
+ loctup.t_len = ItemIdGetLength(lp);
+ loctup.t_tableOid = scan->rs_rd->rd_id;
+ ItemPointerSet(&loctup.t_self, block, offnum);
+ valid = HeapTupleSatisfiesVisibility(&loctup, snapshot, buffer);
+ if (valid)
+ {
+ hscan->rs_vistuples[ntup++] = offnum;
+ PredicateLockTID(scan->rs_rd, &loctup.t_self, snapshot,
+ HeapTupleHeaderGetXmin(loctup.t_data));
+ }
+ HeapCheckForSerializableConflictOut(valid, scan->rs_rd, &loctup,
+ buffer, snapshot);
+ }
+ }
+
+ LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
+
+ Assert(ntup <= MaxHeapTuplesPerPage);
+ hscan->rs_ntuples = ntup;
+
+ if (tbmres->ntuples >= 0)
+ (*exact_pages)++;
+ else
+ (*lossy_pages)++;
+
+ /*
+ * If private, we can error out if the the prefetch block doesn't stay
+ * ahead of the current block.
+ */
+ if (scan->st.bts.pstate == NULL &&
+ !tbm_exhausted(&scan->st.bts.prefetch_iterator) &&
+ bscan->rs_pfblockno < block)
+ elog(ERROR, "prefetch and main iterators are out of sync. pfblockno: %d. block: %d", bscan->rs_pfblockno, block);
+
+ /* Adjust the prefetch target */
+ BitmapAdjustPrefetchTarget(bscan);
+
+ /*
+ * Return true to indicate that a valid block was found and the bitmap is
+ * not exhausted. If there are no visible tuples on this page,
+ * hscan->rs_ntuples will be 0 and heapam_scan_bitmap_next_tuple() will
+ * invoke this function again.
+ */
+ return true;
+}
+
/* ------------------------------------------------------------------------
* Definition of the heap table access method.
--
2.45.2