Skip to content

Commit 9aef6f1

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 cad6590 commit 9aef6f1

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
@@ -6183,8 +6183,8 @@ heap_abort_speculative(Relation relation, ItemPointer tid)
61836183
* transaction. If compatible, return true with the buffer exclusive-locked,
61846184
* and the caller must release that by calling
61856185
* heap_inplace_update_and_unlock(), calling heap_inplace_unlock(), or raising
6186-
* an error. Otherwise, return false after blocking transactions, if any,
6187-
* have ended.
6186+
* an error. Otherwise, call release_callback(arg), wait for blocking
6187+
* transactions to end, and return false.
61886188
*
61896189
* Since this is intended for system catalogs and SERIALIZABLE doesn't cover
61906190
* DDL, this doesn't guarantee any particular predicate locking.
@@ -6218,7 +6218,8 @@ heap_abort_speculative(Relation relation, ItemPointer tid)
62186218
*/
62196219
bool
62206220
heap_inplace_lock(Relation relation,
6221-
HeapTuple oldtup_ptr, Buffer buffer)
6221+
HeapTuple oldtup_ptr, Buffer buffer,
6222+
void (*release_callback) (void *), void *arg)
62226223
{
62236224
HeapTupleData oldtup = *oldtup_ptr; /* minimize diff vs. heap_update() */
62246225
TM_Result result;
@@ -6283,6 +6284,7 @@ heap_inplace_lock(Relation relation,
62836284
lockmode, NULL))
62846285
{
62856286
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
6287+
release_callback(arg);
62866288
ret = false;
62876289
MultiXactIdWait((MultiXactId) xwait, mxact_status, infomask,
62886290
relation, &oldtup.t_self, XLTW_Update,
@@ -6298,6 +6300,7 @@ heap_inplace_lock(Relation relation,
62986300
else
62996301
{
63006302
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
6303+
release_callback(arg);
63016304
ret = false;
63026305
XactLockTableWait(xwait, relation, &oldtup.t_self,
63036306
XLTW_Update);
@@ -6309,6 +6312,7 @@ heap_inplace_lock(Relation relation,
63096312
if (!ret)
63106313
{
63116314
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
6315+
release_callback(arg);
63126316
}
63136317
}
63146318

src/backend/access/index/genam.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,7 @@ systable_inplace_update_begin(Relation relation,
804804
int retries = 0;
805805
SysScanDesc scan;
806806
HeapTuple oldtup;
807+
BufferHeapTupleTableSlot *bslot;
807808

808809
/*
809810
* For now, we don't allow parallel updates. Unlike a regular update,
@@ -825,10 +826,9 @@ systable_inplace_update_begin(Relation relation,
825826
Assert(IsInplaceUpdateRelation(relation) || !IsSystemRelation(relation));
826827

827828
/* Loop for an exclusive-locked buffer of a non-updated tuple. */
828-
for (;;)
829+
do
829830
{
830831
TupleTableSlot *slot;
831-
BufferHeapTupleTableSlot *bslot;
832832

833833
CHECK_FOR_INTERRUPTS();
834834

@@ -855,11 +855,9 @@ systable_inplace_update_begin(Relation relation,
855855
slot = scan->slot;
856856
Assert(TTS_IS_BUFFERTUPLE(slot));
857857
bslot = (BufferHeapTupleTableSlot *) slot;
858-
if (heap_inplace_lock(scan->heap_rel,
859-
bslot->base.tuple, bslot->buffer))
860-
break;
861-
systable_endscan(scan);
862-
};
858+
} while (!heap_inplace_lock(scan->heap_rel,
859+
bslot->base.tuple, bslot->buffer,
860+
(void (*) (void *)) systable_endscan, scan));
863861

864862
*oldtupcopy = heap_copytuple(oldtup);
865863
*state = scan;

src/include/access/heapam.h

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

339339
extern bool heap_inplace_lock(Relation relation,
340-
HeapTuple oldtup_ptr, Buffer buffer);
340+
HeapTuple oldtup_ptr, Buffer buffer,
341+
void (*release_callback) (void *), void *arg);
341342
extern void heap_inplace_update_and_unlock(Relation relation,
342343
HeapTuple oldtup, HeapTuple tuple,
343344
Buffer buffer);

0 commit comments

Comments
 (0)