25
25
#include "utils/rel.h"
26
26
27
27
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 );
29
29
static Buffer _bt_moveright (Relation rel , Relation heaprel , BTScanInsert key ,
30
30
Buffer buf , bool forupdate , BTStack stack ,
31
31
int access );
@@ -57,24 +57,29 @@ static bool _bt_endpoint(IndexScanDesc scan, ScanDirection dir);
57
57
/*
58
58
* _bt_drop_lock_and_maybe_pin()
59
59
*
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.
65
62
*/
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 )
68
65
{
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 )
74
67
{
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 ;
77
71
}
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 ;
78
83
}
79
84
80
85
/*
@@ -866,8 +871,8 @@ _bt_compare(Relation rel,
866
871
* if backwards scan, the last item) in the tree that satisfies the
867
872
* qualifications in the scan key. On success exit, data about the
868
873
* 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 .
871
876
* _bt_returnitem sets the next item to return to scan on success exit.
872
877
*
873
878
* 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,
1610
1615
so -> currPos .currPage = BufferGetBlockNumber (so -> currPos .buf );
1611
1616
so -> currPos .prevPage = opaque -> btpo_prev ;
1612
1617
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 ;
1613
1621
1622
+ /* either moreRight or moreLeft should be set now (may be unset later) */
1623
+ Assert (ScanDirectionIsForward (dir ) ? so -> currPos .moreRight :
1624
+ so -> currPos .moreLeft );
1614
1625
Assert (!P_IGNORE (opaque ));
1615
1626
Assert (BTScanPosIsPinned (so -> currPos ));
1616
1627
Assert (!so -> needPrimScan );
@@ -1626,14 +1637,6 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum,
1626
1637
so -> currPos .currPage );
1627
1638
}
1628
1639
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
-
1637
1640
PredicateLockPage (rel , so -> currPos .currPage , scan -> xs_snapshot );
1638
1641
1639
1642
/* initialize local variables */
@@ -2107,10 +2110,9 @@ _bt_returnitem(IndexScanDesc scan, BTScanOpaque so)
2107
2110
*
2108
2111
* Wrapper on _bt_readnextpage that performs final steps for the current page.
2109
2112
*
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.)
2114
2116
*/
2115
2117
static bool
2116
2118
_bt_steppage (IndexScanDesc scan , ScanDirection dir )
@@ -2251,12 +2253,14 @@ _bt_readfirstpage(IndexScanDesc scan, OffsetNumber offnum, ScanDirection dir)
2251
2253
*/
2252
2254
if (_bt_readpage (scan , dir , offnum , true))
2253
2255
{
2256
+ Relation rel = scan -> indexRelation ;
2257
+
2254
2258
/*
2255
2259
* _bt_readpage succeeded. Drop the lock (and maybe the pin) on
2256
2260
* so->currPos.buf in preparation for btgettuple returning tuples.
2257
2261
*/
2258
2262
Assert (BTScanPosIsPinned (so -> currPos ));
2259
- _bt_drop_lock_and_maybe_pin (scan , & so -> currPos );
2263
+ _bt_drop_lock_and_maybe_pin (rel , so );
2260
2264
return true;
2261
2265
}
2262
2266
@@ -2294,8 +2298,8 @@ _bt_readfirstpage(IndexScanDesc scan, OffsetNumber offnum, ScanDirection dir)
2294
2298
*
2295
2299
* On success exit, so->currPos is updated to contain data from the next
2296
2300
* 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).
2299
2303
*
2300
2304
* If there are no more matching records in the given direction, we drop all
2301
2305
* locks and pins, invalidate so->currPos, and return false.
@@ -2413,7 +2417,7 @@ _bt_readnextpage(IndexScanDesc scan, BlockNumber blkno,
2413
2417
*/
2414
2418
Assert (so -> currPos .currPage == blkno );
2415
2419
Assert (BTScanPosIsPinned (so -> currPos ));
2416
- _bt_drop_lock_and_maybe_pin (scan , & so -> currPos );
2420
+ _bt_drop_lock_and_maybe_pin (rel , so );
2417
2421
2418
2422
return true;
2419
2423
}
0 commit comments