2525#include "utils/rel.h"
2626
2727
28- static void _bt_drop_lock_and_maybe_pin (IndexScanDesc scan , BTScanPos sp );
28+ static inline void _bt_drop_lock_and_maybe_pin (Relation rel , BTScanOpaque so );
2929static Buffer _bt_moveright (Relation rel , Relation heaprel , BTScanInsert key ,
3030 Buffer buf , bool forupdate , BTStack stack ,
3131 int access );
@@ -57,24 +57,29 @@ static bool _bt_endpoint(IndexScanDesc scan, ScanDirection dir);
5757/*
5858 * _bt_drop_lock_and_maybe_pin()
5959 *
60- * Unlock the buffer; and if it is safe to release the pin, do that, too.
61- * This will prevent vacuum from stalling in a blocked state trying to read a
62- * page when a cursor is sitting on it.
63- *
64- * See nbtree/README section on making concurrent TID recycling safe.
60+ * Unlock so->currPos.buf. If scan is so->dropPin, drop the pin, too.
61+ * Dropping the pin prevents VACUUM from blocking on acquiring a cleanup lock.
6562 */
66- static void
67- _bt_drop_lock_and_maybe_pin (IndexScanDesc scan , BTScanPos sp )
63+ static inline void
64+ _bt_drop_lock_and_maybe_pin (Relation rel , BTScanOpaque so )
6865{
69- _bt_unlockbuf (scan -> indexRelation , sp -> buf );
70-
71- if (IsMVCCSnapshot (scan -> xs_snapshot ) &&
72- RelationNeedsWAL (scan -> indexRelation ) &&
73- !scan -> xs_want_itup )
66+ if (!so -> dropPin )
7467 {
75- ReleaseBuffer (sp -> buf );
76- sp -> buf = InvalidBuffer ;
68+ /* Just drop the lock (not the pin) */
69+ _bt_unlockbuf (rel , so -> currPos .buf );
70+ return ;
7771 }
72+
73+ /*
74+ * Drop both the lock and the pin.
75+ *
76+ * Have to set so->currPos.lsn so that _bt_killitems has a way to detect
77+ * when concurrent heap TID recycling by VACUUM might have taken place.
78+ */
79+ Assert (RelationNeedsWAL (rel ));
80+ so -> currPos .lsn = BufferGetLSNAtomic (so -> currPos .buf );
81+ _bt_relbuf (rel , so -> currPos .buf );
82+ so -> currPos .buf = InvalidBuffer ;
7883}
7984
8085/*
@@ -866,8 +871,8 @@ _bt_compare(Relation rel,
866871 * if backwards scan, the last item) in the tree that satisfies the
867872 * qualifications in the scan key. On success exit, data about the
868873 * matching tuple(s) on the page has been loaded into so->currPos. We'll
869- * drop all locks and hold onto a pin on page's buffer, except when
870- * _bt_drop_lock_and_maybe_pin dropped the pin to avoid blocking VACUUM .
874+ * drop all locks and hold onto a pin on page's buffer, except during
875+ * so->dropPin scans, when we drop both the lock and the pin .
871876 * _bt_returnitem sets the next item to return to scan on success exit.
872877 *
873878 * If there are no matching items in the index, we return false, with no
@@ -1610,7 +1615,13 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum,
16101615 so -> currPos .currPage = BufferGetBlockNumber (so -> currPos .buf );
16111616 so -> currPos .prevPage = opaque -> btpo_prev ;
16121617 so -> currPos .nextPage = opaque -> btpo_next ;
1618+ /* delay setting so->currPos.lsn until _bt_drop_lock_and_maybe_pin */
1619+ so -> currPos .dir = dir ;
1620+ so -> currPos .nextTupleOffset = 0 ;
16131621
1622+ /* either moreRight or moreLeft should be set now (may be unset later) */
1623+ Assert (ScanDirectionIsForward (dir ) ? so -> currPos .moreRight :
1624+ so -> currPos .moreLeft );
16141625 Assert (!P_IGNORE (opaque ));
16151626 Assert (BTScanPosIsPinned (so -> currPos ));
16161627 Assert (!so -> needPrimScan );
@@ -1626,14 +1637,6 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum,
16261637 so -> currPos .currPage );
16271638 }
16281639
1629- /* initialize remaining currPos fields related to current page */
1630- so -> currPos .lsn = BufferGetLSNAtomic (so -> currPos .buf );
1631- so -> currPos .dir = dir ;
1632- so -> currPos .nextTupleOffset = 0 ;
1633- /* either moreLeft or moreRight should be set now (may be unset later) */
1634- Assert (ScanDirectionIsForward (dir ) ? so -> currPos .moreRight :
1635- so -> currPos .moreLeft );
1636-
16371640 PredicateLockPage (rel , so -> currPos .currPage , scan -> xs_snapshot );
16381641
16391642 /* initialize local variables */
@@ -2107,10 +2110,9 @@ _bt_returnitem(IndexScanDesc scan, BTScanOpaque so)
21072110 *
21082111 * Wrapper on _bt_readnextpage that performs final steps for the current page.
21092112 *
2110- * On entry, if so->currPos.buf is valid the buffer is pinned but not locked.
2111- * If there's no pin held, it's because _bt_drop_lock_and_maybe_pin dropped
2112- * the pin eagerly earlier on. The scan must have so->currPos.currPage set to
2113- * a valid block, in any case.
2113+ * On entry, so->currPos must be valid. Its buffer will be pinned, though
2114+ * never locked. (Actually, when so->dropPin there won't even be a pin held,
2115+ * though so->currPos.currPage must still be set to a valid block number.)
21142116 */
21152117static bool
21162118_bt_steppage (IndexScanDesc scan , ScanDirection dir )
@@ -2251,12 +2253,14 @@ _bt_readfirstpage(IndexScanDesc scan, OffsetNumber offnum, ScanDirection dir)
22512253 */
22522254 if (_bt_readpage (scan , dir , offnum , true))
22532255 {
2256+ Relation rel = scan -> indexRelation ;
2257+
22542258 /*
22552259 * _bt_readpage succeeded. Drop the lock (and maybe the pin) on
22562260 * so->currPos.buf in preparation for btgettuple returning tuples.
22572261 */
22582262 Assert (BTScanPosIsPinned (so -> currPos ));
2259- _bt_drop_lock_and_maybe_pin (scan , & so -> currPos );
2263+ _bt_drop_lock_and_maybe_pin (rel , so );
22602264 return true;
22612265 }
22622266
@@ -2294,8 +2298,8 @@ _bt_readfirstpage(IndexScanDesc scan, OffsetNumber offnum, ScanDirection dir)
22942298 *
22952299 * On success exit, so->currPos is updated to contain data from the next
22962300 * interesting page, and we return true. We hold a pin on the buffer on
2297- * success exit, except when _bt_drop_lock_and_maybe_pin decided it was safe
2298- * to eagerly drop the pin ( to avoid blocking VACUUM).
2301+ * success exit ( except during so->dropPin index scans, when we drop the pin
2302+ * eagerly to avoid blocking VACUUM).
22992303 *
23002304 * If there are no more matching records in the given direction, we drop all
23012305 * locks and pins, invalidate so->currPos, and return false.
@@ -2413,7 +2417,7 @@ _bt_readnextpage(IndexScanDesc scan, BlockNumber blkno,
24132417 */
24142418 Assert (so -> currPos .currPage == blkno );
24152419 Assert (BTScanPosIsPinned (so -> currPos ));
2416- _bt_drop_lock_and_maybe_pin (scan , & so -> currPos );
2420+ _bt_drop_lock_and_maybe_pin (rel , so );
24172421
24182422 return true;
24192423}
0 commit comments