]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
heapam: Track heap block in IndexFetchHeapData.
authorPeter Geoghegan <pg@bowt.ie>
Sat, 4 Apr 2026 15:45:33 +0000 (11:45 -0400)
committerPeter Geoghegan <pg@bowt.ie>
Sat, 4 Apr 2026 15:45:33 +0000 (11:45 -0400)
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/backend/access/heap/heapam_indexscan.c
src/include/access/heapam.h

index c36b804d1e3f6fc517b9c9b2d0789eaa6b294061..bbd8a165ddc2378203fa75b8fab8ea6dc8e1e6a3 100644 (file)
@@ -32,6 +32,7 @@ heapam_index_fetch_begin(Relation rel, uint32 flags)
        hscan->xs_base.rel = rel;
        hscan->xs_base.flags = flags;
        hscan->xs_cbuf = InvalidBuffer;
+       hscan->xs_blk = InvalidBlockNumber;
        hscan->xs_vmbuffer = InvalidBuffer;
 
        return &hscan->xs_base;
@@ -46,6 +47,7 @@ heapam_index_fetch_reset(IndexFetchTableData *scan)
        {
                ReleaseBuffer(hscan->xs_cbuf);
                hscan->xs_cbuf = InvalidBuffer;
+               hscan->xs_blk = InvalidBlockNumber;
        }
 
        if (BufferIsValid(hscan->xs_vmbuffer))
@@ -240,25 +242,30 @@ heapam_index_fetch_tuple(struct IndexFetchTableData *scan,
 
        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,
-                                                                                         hscan->xs_base.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(hscan->xs_base.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(hscan->xs_base.rel, hscan->xs_cbuf,
-                                                               &hscan->xs_vmbuffer,
-                                                               hscan->xs_base.flags & SO_HINT_REL_READ_ONLY);
+               heap_page_prune_opt(hscan->xs_base.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,
index cc90c821be5e0a374c6eb68fd438821c3d723be5..5176478c29583dce96c23f6100025df4fe4379af 100644 (file)
@@ -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;