Skip to content

Commit 11e3f28

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 dedced7 commit 11e3f28

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
@@ -6215,8 +6215,8 @@ heap_abort_speculative(Relation relation, ItemPointer tid)
62156215
* transaction. If compatible, return true with the buffer exclusive-locked,
62166216
* and the caller must release that by calling
62176217
* heap_inplace_update_and_unlock(), calling heap_inplace_unlock(), or raising
6218-
* an error. Otherwise, return false after blocking transactions, if any,
6219-
* have ended.
6218+
* an error. Otherwise, call release_callback(arg), wait for blocking
6219+
* transactions to end, and return false.
62206220
*
62216221
* Since this is intended for system catalogs and SERIALIZABLE doesn't cover
62226222
* DDL, this doesn't guarantee any particular predicate locking.
@@ -6250,7 +6250,8 @@ heap_abort_speculative(Relation relation, ItemPointer tid)
62506250
*/
62516251
bool
62526252
heap_inplace_lock(Relation relation,
6253-
HeapTuple oldtup_ptr, Buffer buffer)
6253+
HeapTuple oldtup_ptr, Buffer buffer,
6254+
void (*release_callback) (void *), void *arg)
62546255
{
62556256
HeapTupleData oldtup = *oldtup_ptr; /* minimize diff vs. heap_update() */
62566257
TM_Result result;
@@ -6315,6 +6316,7 @@ heap_inplace_lock(Relation relation,
63156316
lockmode, NULL))
63166317
{
63176318
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
6319+
release_callback(arg);
63186320
ret = false;
63196321
MultiXactIdWait((MultiXactId) xwait, mxact_status, infomask,
63206322
relation, &oldtup.t_self, XLTW_Update,
@@ -6330,6 +6332,7 @@ heap_inplace_lock(Relation relation,
63306332
else
63316333
{
63326334
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
6335+
release_callback(arg);
63336336
ret = false;
63346337
XactLockTableWait(xwait, relation, &oldtup.t_self,
63356338
XLTW_Update);
@@ -6341,6 +6344,7 @@ heap_inplace_lock(Relation relation,
63416344
if (!ret)
63426345
{
63436346
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
6347+
release_callback(arg);
63446348
}
63456349
}
63466350

src/backend/access/index/genam.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,7 @@ systable_inplace_update_begin(Relation relation,
802802
int retries = 0;
803803
SysScanDesc scan;
804804
HeapTuple oldtup;
805+
BufferHeapTupleTableSlot *bslot;
805806

806807
/*
807808
* For now, we don't allow parallel updates. Unlike a regular update,
@@ -823,10 +824,9 @@ systable_inplace_update_begin(Relation relation,
823824
Assert(IsInplaceUpdateRelation(relation) || !IsSystemRelation(relation));
824825

825826
/* Loop for an exclusive-locked buffer of a non-updated tuple. */
826-
for (;;)
827+
do
827828
{
828829
TupleTableSlot *slot;
829-
BufferHeapTupleTableSlot *bslot;
830830

831831
CHECK_FOR_INTERRUPTS();
832832

@@ -852,11 +852,9 @@ systable_inplace_update_begin(Relation relation,
852852
slot = scan->slot;
853853
Assert(TTS_IS_BUFFERTUPLE(slot));
854854
bslot = (BufferHeapTupleTableSlot *) slot;
855-
if (heap_inplace_lock(scan->heap_rel,
856-
bslot->base.tuple, bslot->buffer))
857-
break;
858-
systable_endscan(scan);
859-
};
855+
} while (!heap_inplace_lock(scan->heap_rel,
856+
bslot->base.tuple, bslot->buffer,
857+
(void (*) (void *)) systable_endscan, scan));
860858

861859
*oldtupcopy = heap_copytuple(oldtup);
862860
*state = scan;

src/include/access/heapam.h

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

169169
extern bool heap_inplace_lock(Relation relation,
170-
HeapTuple oldtup_ptr, Buffer buffer);
170+
HeapTuple oldtup_ptr, Buffer buffer,
171+
void (*release_callback) (void *), void *arg);
171172
extern void heap_inplace_update_and_unlock(Relation relation,
172173
HeapTuple oldtup, HeapTuple tuple,
173174
Buffer buffer);

0 commit comments

Comments
 (0)