Skip to content

Commit 2a912bc

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 8a84861 commit 2a912bc

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
@@ -5943,8 +5943,8 @@ heap_abort_speculative(Relation relation, ItemPointer tid)
59435943
* transaction. If compatible, return true with the buffer exclusive-locked,
59445944
* and the caller must release that by calling
59455945
* heap_inplace_update_and_unlock(), calling heap_inplace_unlock(), or raising
5946-
* an error. Otherwise, return false after blocking transactions, if any,
5947-
* have ended.
5946+
* an error. Otherwise, call release_callback(arg), wait for blocking
5947+
* transactions to end, and return false.
59485948
*
59495949
* Since this is intended for system catalogs and SERIALIZABLE doesn't cover
59505950
* DDL, this doesn't guarantee any particular predicate locking.
@@ -5978,7 +5978,8 @@ heap_abort_speculative(Relation relation, ItemPointer tid)
59785978
*/
59795979
bool
59805980
heap_inplace_lock(Relation relation,
5981-
HeapTuple oldtup_ptr, Buffer buffer)
5981+
HeapTuple oldtup_ptr, Buffer buffer,
5982+
void (*release_callback) (void *), void *arg)
59825983
{
59835984
HeapTupleData oldtup = *oldtup_ptr; /* minimize diff vs. heap_update() */
59845985
TM_Result result;
@@ -6043,6 +6044,7 @@ heap_inplace_lock(Relation relation,
60436044
lockmode, NULL))
60446045
{
60456046
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
6047+
release_callback(arg);
60466048
ret = false;
60476049
MultiXactIdWait((MultiXactId) xwait, mxact_status, infomask,
60486050
relation, &oldtup.t_self, XLTW_Update,
@@ -6058,6 +6060,7 @@ heap_inplace_lock(Relation relation,
60586060
else
60596061
{
60606062
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
6063+
release_callback(arg);
60616064
ret = false;
60626065
XactLockTableWait(xwait, relation, &oldtup.t_self,
60636066
XLTW_Update);
@@ -6069,6 +6072,7 @@ heap_inplace_lock(Relation relation,
60696072
if (!ret)
60706073
{
60716074
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
6075+
release_callback(arg);
60726076
}
60736077
}
60746078

src/backend/access/index/genam.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,7 @@ systable_inplace_update_begin(Relation relation,
708708
int retries = 0;
709709
SysScanDesc scan;
710710
HeapTuple oldtup;
711+
BufferHeapTupleTableSlot *bslot;
711712

712713
/*
713714
* For now, we don't allow parallel updates. Unlike a regular update,
@@ -729,10 +730,9 @@ systable_inplace_update_begin(Relation relation,
729730
Assert(IsInplaceUpdateRelation(relation) || !IsSystemRelation(relation));
730731

731732
/* Loop for an exclusive-locked buffer of a non-updated tuple. */
732-
for (;;)
733+
do
733734
{
734735
TupleTableSlot *slot;
735-
BufferHeapTupleTableSlot *bslot;
736736

737737
CHECK_FOR_INTERRUPTS();
738738

@@ -758,11 +758,9 @@ systable_inplace_update_begin(Relation relation,
758758
slot = scan->slot;
759759
Assert(TTS_IS_BUFFERTUPLE(slot));
760760
bslot = (BufferHeapTupleTableSlot *) slot;
761-
if (heap_inplace_lock(scan->heap_rel,
762-
bslot->base.tuple, bslot->buffer))
763-
break;
764-
systable_endscan(scan);
765-
};
761+
} while (!heap_inplace_lock(scan->heap_rel,
762+
bslot->base.tuple, bslot->buffer,
763+
(void (*) (void *)) systable_endscan, scan));
766764

767765
*oldtupcopy = heap_copytuple(oldtup);
768766
*state = scan;

src/include/access/heapam.h

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

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

0 commit comments

Comments
 (0)