Skip to content

Commit c2139db

Browse files
committed
Unpin buffer before inplace update waits for an XID to end.
Commit a07e03f changed inplace updates to wait for heap_update() commands like GRANT TABLE and GRANT DATABASE. By keeping the pin during that wait, a sequence of autovacuum workers and an uncommitted GRANT starved one foreground LockBufferForCleanup() for six minutes, on buildfarm member sarus. Prevent, at the cost of a bit of complexity. Back-patch to v12, like the earlier commit. That commit and heap_inplace_lock() have not yet appeared in any release. Discussion: https://postgr.es/m/20241026184936.ae.nmisch@google.com
1 parent 8f1759c commit c2139db

File tree

3 files changed

+14
-11
lines changed

3 files changed

+14
-11
lines changed

src/backend/access/heap/heapam.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5974,8 +5974,8 @@ heap_abort_speculative(Relation relation, ItemPointer tid)
59745974
* transaction. If compatible, return true with the buffer exclusive-locked,
59755975
* and the caller must release that by calling
59765976
* heap_inplace_update_and_unlock(), calling heap_inplace_unlock(), or raising
5977-
* an error. Otherwise, return false after blocking transactions, if any,
5978-
* have ended.
5977+
* an error. Otherwise, call release_callback(arg), wait for blocking
5978+
* transactions to end, and return false.
59795979
*
59805980
* Since this is intended for system catalogs and SERIALIZABLE doesn't cover
59815981
* DDL, this doesn't guarantee any particular predicate locking.
@@ -6009,7 +6009,8 @@ heap_abort_speculative(Relation relation, ItemPointer tid)
60096009
*/
60106010
bool
60116011
heap_inplace_lock(Relation relation,
6012-
HeapTuple oldtup_ptr, Buffer buffer)
6012+
HeapTuple oldtup_ptr, Buffer buffer,
6013+
void (*release_callback) (void *), void *arg)
60136014
{
60146015
HeapTupleData oldtup = *oldtup_ptr; /* minimize diff vs. heap_update() */
60156016
TM_Result result;
@@ -6074,6 +6075,7 @@ heap_inplace_lock(Relation relation,
60746075
lockmode, NULL))
60756076
{
60766077
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
6078+
release_callback(arg);
60776079
ret = false;
60786080
MultiXactIdWait((MultiXactId) xwait, mxact_status, infomask,
60796081
relation, &oldtup.t_self, XLTW_Update,
@@ -6089,6 +6091,7 @@ heap_inplace_lock(Relation relation,
60896091
else
60906092
{
60916093
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
6094+
release_callback(arg);
60926095
ret = false;
60936096
XactLockTableWait(xwait, relation, &oldtup.t_self,
60946097
XLTW_Update);
@@ -6100,6 +6103,7 @@ heap_inplace_lock(Relation relation,
61006103
if (!ret)
61016104
{
61026105
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
6106+
release_callback(arg);
61036107
}
61046108
}
61056109

src/backend/access/index/genam.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,7 @@ systable_inplace_update_begin(Relation relation,
704704
int retries = 0;
705705
SysScanDesc scan;
706706
HeapTuple oldtup;
707+
BufferHeapTupleTableSlot *bslot;
707708

708709
/*
709710
* For now, we don't allow parallel updates. Unlike a regular update,
@@ -725,10 +726,9 @@ systable_inplace_update_begin(Relation relation,
725726
Assert(IsInplaceUpdateRelation(relation) || !IsSystemRelation(relation));
726727

727728
/* Loop for an exclusive-locked buffer of a non-updated tuple. */
728-
for (;;)
729+
do
729730
{
730731
TupleTableSlot *slot;
731-
BufferHeapTupleTableSlot *bslot;
732732

733733
CHECK_FOR_INTERRUPTS();
734734

@@ -754,11 +754,9 @@ systable_inplace_update_begin(Relation relation,
754754
slot = scan->slot;
755755
Assert(TTS_IS_BUFFERTUPLE(slot));
756756
bslot = (BufferHeapTupleTableSlot *) slot;
757-
if (heap_inplace_lock(scan->heap_rel,
758-
bslot->base.tuple, bslot->buffer))
759-
break;
760-
systable_endscan(scan);
761-
};
757+
} while (!heap_inplace_lock(scan->heap_rel,
758+
bslot->base.tuple, bslot->buffer,
759+
(void (*) (void *)) systable_endscan, scan));
762760

763761
*oldtupcopy = heap_copytuple(oldtup);
764762
*state = scan;

src/include/access/heapam.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@ extern TM_Result heap_lock_tuple(Relation relation, HeapTuple tuple,
157157
Buffer *buffer, struct TM_FailureData *tmfd);
158158

159159
extern bool heap_inplace_lock(Relation relation,
160-
HeapTuple oldtup_ptr, Buffer buffer);
160+
HeapTuple oldtup_ptr, Buffer buffer,
161+
void (*release_callback) (void *), void *arg);
161162
extern void heap_inplace_update_and_unlock(Relation relation,
162163
HeapTuple oldtup, HeapTuple tuple,
163164
Buffer buffer);

0 commit comments

Comments
 (0)