Skip to content

Commit 87b7fcc

Browse files
committed
Guard against spurious signals in LockBufferForCleanup.
When LockBufferForCleanup() has to wait for getting a cleanup lock on a buffer it does so by setting a flag in the buffer header and then wait for other backends to signal it using ProcWaitForSignal(). Unfortunately LockBufferForCleanup() missed that ProcWaitForSignal() can return for other reasons than the signal it is hoping for. If such a spurious signal arrives the wait flags on the buffer header will still be set. That then triggers "ERROR: multiple backends attempting to wait for pincount 1". The fix is simple, unset the flag if still set when retrying. That implies an additional spinlock acquisition/release, but that's unlikely to matter given the cost of waiting for a cleanup lock. Alternatively it'd have been possible to move responsibility for maintaining the relevant flag to the waiter all together, but that might have had negative consequences due to possible floods of signals. Besides being more invasive. This looks to be a very longstanding bug. The relevant code in LockBufferForCleanup() hasn't changed materially since its introduction and ProcWaitForSignal() was documented to return for unrelated reasons since 8.2. The master only patch series removing ImmediateInterruptOK made it much easier to hit though, as ProcSendSignal/ProcWaitForSignal now uses a latch shared with other tasks. Per discussion with Kevin Grittner, Tom Lane and me. Backpatch to all supported branches. Discussion: 11553.1423805224@sss.pgh.pa.us
1 parent 8878eaa commit 87b7fcc

File tree

1 file changed

+14
-0
lines changed

1 file changed

+14
-0
lines changed

src/backend/storage/buffer/bufmgr.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2479,6 +2479,20 @@ LockBufferForCleanup(Buffer buffer)
24792479
else
24802480
ProcWaitForSignal();
24812481

2482+
/*
2483+
* Remove flag marking us as waiter. Normally this will not be set
2484+
* anymore, but ProcWaitForSignal() can return for other signals as
2485+
* well. We take care to only reset the flag if we're the waiter, as
2486+
* theoretically another backend could have started waiting. That's
2487+
* impossible with the current usages due to table level locking, but
2488+
* better be safe.
2489+
*/
2490+
LockBufHdr(bufHdr);
2491+
if ((bufHdr->flags & BM_PIN_COUNT_WAITER) != 0 &&
2492+
bufHdr->wait_backend_pid == MyProcPid)
2493+
bufHdr->flags &= ~BM_PIN_COUNT_WAITER;
2494+
UnlockBufHdr(bufHdr);
2495+
24822496
PinCountWaitBuf = NULL;
24832497
/* Loop back and try again */
24842498
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy