From b88b394b5a0b876fca2d5053c0b369d972bbad5e Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Thu, 26 Mar 2026 18:45:27 -0400 Subject: [PATCH v18 04/19] heapam: Keep buffer pins across index scan rescans. Avoid dropping the heap page pin (xs_cbuf) and visibility map pin (xs_vmbuffer) during heapam_index_fetch_reset. Retaining these pins saves cycles during tight nested loop joins and merge joins that frequently restore a saved mark, since the next tuple fetched after a rescan often falls on the same heap page. It can also avoid repeated pinning and unpinning of the same buffer when rescans happen to revisit the same page. Preparation for an upcoming patch that will add the amgetbatch interface to enable optimizations such as I/O prefetching. Author: Peter Geoghegan Reviewed-By: Andres Freund Discussion: https://postgr.es/m/CAH2-Wz=g=JTSyDB4UtB5su2ZcvsS7VbP+ZMvvaG6ABoCb+s8Lw@mail.gmail.com --- src/backend/access/heap/heapam_indexscan.c | 27 ++++++++++++---------- src/backend/access/index/indexam.c | 4 ++-- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/backend/access/heap/heapam_indexscan.c b/src/backend/access/heap/heapam_indexscan.c index cf9366ad4..7d463bfd1 100644 --- a/src/backend/access/heap/heapam_indexscan.c +++ b/src/backend/access/heap/heapam_indexscan.c @@ -58,18 +58,15 @@ heapam_index_fetch_reset(IndexFetchTableData *scan) { IndexFetchHeapData *hscan = (IndexFetchHeapData *) scan; - if (BufferIsValid(hscan->xs_cbuf)) - { - ReleaseBuffer(hscan->xs_cbuf); - hscan->xs_cbuf = InvalidBuffer; - hscan->xs_blk = InvalidBlockNumber; - } + /* Resets are a no-op (XXX amgetbatch commit resets xs_vm_items here) */ + (void) hscan; - if (BufferIsValid(hscan->xs_vmbuffer)) - { - ReleaseBuffer(hscan->xs_vmbuffer); - hscan->xs_vmbuffer = InvalidBuffer; - } + /* + * Deliberately avoid dropping pins now held in xs_cbuf and xs_vmbuffer. + * This saves cycles during certain tight nested loop joins, and during + * merge joins that frequently restore a saved mark. It can also avoid + * repeated pinning and unpinning of the same buffer across rescans. + */ } void @@ -77,7 +74,13 @@ heapam_index_fetch_end(IndexFetchTableData *scan) { IndexFetchHeapData *hscan = (IndexFetchHeapData *) scan; - heapam_index_fetch_reset(scan); + /* drop pin if there's a pinned heap page */ + if (BufferIsValid(hscan->xs_cbuf)) + ReleaseBuffer(hscan->xs_cbuf); + + /* drop pin if there's a pinned visibility map page */ + if (BufferIsValid(hscan->xs_vmbuffer)) + ReleaseBuffer(hscan->xs_vmbuffer); pfree(hscan); } diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c index 527e06e09..189e67684 100644 --- a/src/backend/access/index/indexam.c +++ b/src/backend/access/index/indexam.c @@ -386,7 +386,7 @@ index_rescan(IndexScanDesc scan, Assert(nkeys == scan->numberOfKeys); Assert(norderbys == scan->numberOfOrderBys); - /* Release resources (like buffer pins) from table accesses */ + /* reset table AM state for rescan */ if (scan->xs_heapfetch) table_index_fetch_reset(scan->xs_heapfetch); @@ -462,7 +462,7 @@ index_restrpos(IndexScanDesc scan) SCAN_CHECKS; CHECK_SCAN_PROCEDURE(amrestrpos); - /* release resources (like buffer pins) from table accesses */ + /* reset table AM state for rescan */ if (scan->xs_heapfetch) table_index_fetch_reset(scan->xs_heapfetch); -- 2.53.0