v16-0004-Add-VISITED_PAGES_LIMIT-to-heapam.patch
application/octet-stream
Filename: v16-0004-Add-VISITED_PAGES_LIMIT-to-heapam.patch
Type: application/octet-stream
Part: 13
Message:
Re: index prefetching
Patch
Format: format-patch
Series: patch v16-0004
Subject: Add VISITED_PAGES_LIMIT to heapam
| File | + | − |
|---|---|---|
| src/backend/access/heap/heapam_handler.c | 22 | 0 |
| src/backend/access/index/genam.c | 1 | 0 |
| src/backend/utils/adt/selfuncs.c | 5 | 4 |
| src/include/access/relscan.h | 7 | 0 |
From c1d6a412a943189372cc733b1041bff96e8c8e76 Mon Sep 17 00:00:00 2001
From: Peter Geoghegan <pg@bowt.ie>
Date: Thu, 19 Mar 2026 12:32:34 -0400
Subject: [PATCH v16 04/17] Add VISITED_PAGES_LIMIT to heapam
---
src/include/access/relscan.h | 7 +++++++
src/backend/access/heap/heapam_handler.c | 22 ++++++++++++++++++++++
src/backend/access/index/genam.c | 1 +
src/backend/utils/adt/selfuncs.c | 9 +++++----
4 files changed, 35 insertions(+), 4 deletions(-)
diff --git a/src/include/access/relscan.h b/src/include/access/relscan.h
index 9c1563c88..13370b1c9 100644
--- a/src/include/access/relscan.h
+++ b/src/include/access/relscan.h
@@ -372,6 +372,13 @@ typedef struct IndexScanDescData
/* parallel index scan information, in shared memory */
struct ParallelIndexScanDescData *parallel_scan;
+
+ /*
+ * Limit on distinct heap pages visited before giving up (0 = no limit).
+ * Used by selfuncs.c to bound the cost of get_actual_variable_endpoint().
+ */
+ uint8 xs_visited_pages_limit;
+
} IndexScanDescData;
/* Generic structure for parallel scans */
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index b8cc3d39c..1b58db199 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -824,6 +824,7 @@ heapam_index_only_getnext_slot(IndexScanDesc scan, ScanDirection direction,
heap_continue = false;
Assert(scan->xs_want_itup);
+ Assert(scan->xs_visited_pages_limit == 0);
for (;;)
{
@@ -906,6 +907,9 @@ heapam_index_only_batch_getnext_slot(IndexScanDesc scan, ScanDirection direction
ItemPointer tid;
bool all_visible,
heap_continue = false;
+ BlockNumber last_visited_block = InvalidBlockNumber;
+ uint8 n_visited_pages = 0,
+ xs_visited_pages_limit = scan->xs_visited_pages_limit;
Assert(scan->xs_want_itup);
@@ -936,7 +940,25 @@ heapam_index_only_batch_getnext_slot(IndexScanDesc scan, ScanDirection direction
scan->instrument->nheapfetches++;
if (!heapam_index_fetch_heap(scan, slot, &heap_continue, true))
+ {
+ /*
+ * No visible tuple. If caller set a visited-pages limit
+ * (only selfuncs.c does this), count distinct heap pages and
+ * give up once we've visited too many.
+ */
+ if (unlikely(xs_visited_pages_limit > 0))
+ {
+ Assert(hscan->xs_blk == ItemPointerGetBlockNumber(tid));
+
+ if (hscan->xs_blk != last_visited_block)
+ {
+ last_visited_block = hscan->xs_blk;
+ if (++n_visited_pages > xs_visited_pages_limit)
+ return false; /* give up */
+ }
+ }
continue; /* no visible tuple, try next index entry */
+ }
ExecClearTuple(slot);
diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c
index 6e87169c2..d0b68f38e 100644
--- a/src/backend/access/index/genam.c
+++ b/src/backend/access/index/genam.c
@@ -126,6 +126,7 @@ RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
scan->xs_itupdesc = NULL;
scan->xs_hitup = NULL;
scan->xs_hitupdesc = NULL;
+ scan->xs_visited_pages_limit = 0;
scan->batch_index_opaque_size = 0;
scan->batch_tuples_workspace = 0;
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 1f8b0e684..768581cf7 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -7168,11 +7168,11 @@ get_actual_variable_endpoint(Relation heapRel,
* pages. When we fail for that reason, the caller will end up using
* whatever extremal value is recorded in pg_statistic.
*
- * XXX This can't work with the new table_index_getnext_slot interface,
- * which simply won't return a tuple that isn't visible to our snapshot.
- * table_index_getnext_slot will need some kind of callback that provides
- * a way for the scan to give up when the costs start to get out of hand.
+ * We set xs_visited_pages_limit to tell the table AM to count distinct
+ * heap pages visited for non-visible tuples and give up after the limit
+ * is exceeded.
*/
+#define VISITED_PAGES_LIMIT 100
InitNonVacuumableSnapshot(SnapshotNonVacuumable,
GlobalVisTestFor(heapRel));
@@ -7180,6 +7180,7 @@ get_actual_variable_endpoint(Relation heapRel,
&SnapshotNonVacuumable, NULL,
1, 0);
Assert(index_scan->xs_want_itup);
+ index_scan->xs_visited_pages_limit = VISITED_PAGES_LIMIT;
index_rescan(index_scan, scankeys, 1, NULL, 0);
/* Fetch first/next tuple in specified direction */
--
2.53.0