nbtree: _bt_readnextpage doesn't affect markPos.
authorPeter Geoghegan <pg@bowt.ie>
Fri, 13 Jun 2025 23:58:47 +0000 (19:58 -0400)
committerPeter Geoghegan <pg@bowt.ie>
Fri, 13 Jun 2025 23:58:47 +0000 (19:58 -0400)
_bt_readnextpage expects so->currPos.buf to be InvalidBuffer (and for
the position's page to be unlocked) when called.  However, it does not
expect there to be no pins held on any page.  In particular, so->markPos
might hold a separate pin, both before and after the call.  Fix some
comments that seemed to suggest otherwise.

Follow-up commit to commit 7c319f54, which made _bt_killitems drop pins
it acquired itself.

src/backend/access/nbtree/nbtsearch.c

index 070f14c8b91f03b4480c0a67c9d5723b2f222934..36544ecfd5878f2502d1d9f64ed02af9058d94b2 100644 (file)
@@ -2282,9 +2282,12 @@ _bt_readfirstpage(IndexScanDesc scan, OffsetNumber offnum, ScanDirection dir)
  * previously-saved right link or left link.  lastcurrblkno is the page that
  * was current at the point where the blkno link was saved, which we use to
  * reason about concurrent page splits/page deletions during backwards scans.
+ * In the common case where seized=false, blkno is either so->currPos.nextPage
+ * or so->currPos.prevPage, and lastcurrblkno is so->currPos.currPage.
  *
- * On entry, caller shouldn't hold any locks or pins on any page (we work
- * directly off of blkno and lastcurrblkno instead).  Parallel scan callers
+ * On entry, so->currPos shouldn't be locked by caller.  so->currPos.buf must
+ * be InvalidBuffer/unpinned as needed by caller (note that lastcurrblkno
+ * won't need to be read again in almost all cases).  Parallel scan callers
  * that seized the scan before calling here should pass seized=true; such a
  * caller's blkno and lastcurrblkno arguments come from the seized scan.
  * seized=false callers just pass us the blkno/lastcurrblkno taken from their
@@ -2301,8 +2304,8 @@ _bt_readfirstpage(IndexScanDesc scan, OffsetNumber offnum, ScanDirection dir)
  * success exit (except during so->dropPin index scans, when we drop the pin
  * eagerly to avoid blocking VACUUM).
  *
- * If there are no more matching records in the given direction, we drop all
- * locks and pins, invalidate so->currPos, and return false.
+ * If there are no more matching records in the given direction, we invalidate
+ * so->currPos (while ensuring it retains no locks or pins), and return false.
  *
  * We always release the scan for a parallel scan caller, regardless of
  * success or failure; we'll call _bt_parallel_release as soon as possible.