v20-0004-heapam-Track-heap-block-in-IndexFetchHeapData.patch
application/octet-stream
Filename: v20-0004-heapam-Track-heap-block-in-IndexFetchHeapData.patch
Type: application/octet-stream
Part: 14
Message:
Re: index prefetching
Patch
Format: format-patch
Series: patch v20-0004
Subject: heapam: Track heap block in IndexFetchHeapData.
| File | + | − |
|---|---|---|
| src/backend/access/heap/heapam_indexscan.c | 22 | 13 |
| src/include/access/heapam.h | 3 | 2 |
From e159d0a4bd3571911f7c6787cde51da993a4a7a7 Mon Sep 17 00:00:00 2001
From: Peter Geoghegan <pg@bowt.ie>
Date: Tue, 10 Mar 2026 14:40:35 -0400
Subject: [PATCH v20 04/17] heapam: Track heap block in IndexFetchHeapData.
Add an explicit BlockNumber field (xs_blk) to IndexFetchHeapData that
tracks which heap block is currently pinned in xs_cbuf.
heapam_index_fetch_tuple now uses xs_blk to determine when buffer
switching is needed, replacing the previous approach that compared
buffer identities via ReleaseAndReadBuffer on every non-HOT-chain call.
This is preparatory work for an upcoming commit that will add index
prefetching using a read stream. Delegating the release of a currently
pinned buffer to ReleaseAndReadBuffer won't work anymore -- at least not
when the next buffer that the scan needs to pin is one returned by
read_stream_next_buffer (not a buffer returned by ReadBuffer).
Author: Peter Geoghegan <pg@bowt.ie>
Reviewed-By: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/CAH2-Wz=g=JTSyDB4UtB5su2ZcvsS7VbP+ZMvvaG6ABoCb+s8Lw@mail.gmail.com
---
src/include/access/heapam.h | 5 ++--
src/backend/access/heap/heapam_indexscan.c | 35 ++++++++++++++--------
2 files changed, 25 insertions(+), 15 deletions(-)
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index d76d3e7fd..a78fc0df2 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -122,10 +122,11 @@ typedef struct IndexFetchHeapData
IndexFetchTableData xs_base; /* AM independent part of the descriptor */
/*
- * Current heap buffer in scan, if any. NB: if xs_cbuf is not
- * InvalidBuffer, we hold a pin on that buffer.
+ * Current heap buffer in scan (and its block number), if any. NB: if
+ * xs_blk is not InvalidBlockNumber, we hold a pin in xs_cbuf.
*/
Buffer xs_cbuf;
+ BlockNumber xs_blk;
/* Current heap block's corresponding page in the visibility map */
Buffer xs_vmbuffer;
diff --git a/src/backend/access/heap/heapam_indexscan.c b/src/backend/access/heap/heapam_indexscan.c
index 23635b6bc..459b69eee 100644
--- a/src/backend/access/heap/heapam_indexscan.c
+++ b/src/backend/access/heap/heapam_indexscan.c
@@ -50,6 +50,7 @@ heapam_index_fetch_begin(Relation rel, uint32 flags)
hscan->xs_base.flags = flags;
hscan->xs_cbuf = InvalidBuffer;
+ hscan->xs_blk = InvalidBlockNumber;
hscan->xs_vmbuffer = InvalidBuffer;
/*
@@ -68,6 +69,7 @@ heapam_index_fetch_reset(IndexScanDesc scan)
{
ReleaseBuffer(hscan->xs_cbuf);
hscan->xs_cbuf = InvalidBuffer;
+ hscan->xs_blk = InvalidBlockNumber;
}
if (BufferIsValid(hscan->xs_vmbuffer))
@@ -324,23 +326,30 @@ heapam_index_fetch_tuple_impl(Relation rel,
Assert(TTS_IS_BUFFERTUPLE(slot));
- /* We can skip the buffer-switching logic if we're in mid-HOT chain. */
- if (!*heap_continue)
+ /* We can skip the buffer-switching logic if we're on the same page. */
+ if (hscan->xs_blk != ItemPointerGetBlockNumber(tid))
{
- /* Switch to correct buffer if we don't have it already */
- Buffer prev_buf = hscan->xs_cbuf;
+ Assert(!*heap_continue);
- hscan->xs_cbuf = ReleaseAndReadBuffer(hscan->xs_cbuf, rel,
- ItemPointerGetBlockNumber(tid));
+ /* Remember this buffer's block number for next time */
+ hscan->xs_blk = ItemPointerGetBlockNumber(tid);
+
+ if (BufferIsValid(hscan->xs_cbuf))
+ ReleaseBuffer(hscan->xs_cbuf);
+
+ hscan->xs_cbuf = ReadBuffer(rel, hscan->xs_blk);
/*
- * Prune page, but only if we weren't already on this page
+ * Prune page when it is pinned for the first time
*/
- if (prev_buf != hscan->xs_cbuf)
- heap_page_prune_opt(rel, hscan->xs_cbuf, &hscan->xs_vmbuffer,
- hscan->xs_base.flags & SO_HINT_REL_READ_ONLY);
+ heap_page_prune_opt(rel, hscan->xs_cbuf,
+ &hscan->xs_vmbuffer,
+ hscan->xs_base.flags & SO_HINT_REL_READ_ONLY);
}
+ Assert(BufferGetBlockNumber(hscan->xs_cbuf) == hscan->xs_blk);
+ Assert(hscan->xs_blk == ItemPointerGetBlockNumber(tid));
+
/* Obtain share-lock on the buffer so we can examine visibility */
LockBuffer(hscan->xs_cbuf, BUFFER_LOCK_SHARE);
got_heap_tuple = heap_hot_search_buffer(tid,
@@ -443,11 +452,11 @@ heapam_index_getnext_slot(IndexScanDesc scan, ScanDirection direction,
*/
if (unlikely(scan->xs_visited_pages_limit > 0))
{
- BlockNumber blk = ItemPointerGetBlockNumber(tid);
+ Assert(hscan->xs_blk == ItemPointerGetBlockNumber(tid));
- if (blk != last_visited_block)
+ if (hscan->xs_blk != last_visited_block)
{
- last_visited_block = blk;
+ last_visited_block = hscan->xs_blk;
if (++n_visited_pages > scan->xs_visited_pages_limit)
return false; /* give up */
}
--
2.53.0