From 80eee071308c2548cb0dfc3f2dbdf04bd4b151bf Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Tue, 3 Feb 2026 11:01:58 -0500 Subject: [PATCH v13 3/3] bufmgr: Make UnlockReleaseBuffer() more efficient Now that the buffer content lock is implemented as part of BufferDesc.state, releasing the lock and unpinning the buffer can be implemented as a single atomic operation. This improves workloads that have heavy contention on a small number of buffers substantially, I e.g., see a ~20% improvement for pipelined readonly pgbench on an older two socket machine. Author: Reviewed-by: Discussion: https://postgr.es/m/ Backpatch: --- src/backend/storage/buffer/bufmgr.c | 55 +++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 53b327200d7..9147e4c127b 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -5508,13 +5508,62 @@ ReleaseBuffer(Buffer buffer) /* * UnlockReleaseBuffer -- release the content lock and pin on a buffer * - * This is just a shorthand for a common combination. + * This is just a, more efficient, shorthand for a common combination. */ void UnlockReleaseBuffer(Buffer buffer) { - LockBuffer(buffer, BUFFER_LOCK_UNLOCK); - ReleaseBuffer(buffer); + int mode; + BufferDesc *buf; + PrivateRefCountEntry *ref; + uint64 sub; + uint64 lockstate; + + Assert(BufferIsPinned(buffer)); + + if (BufferIsLocal(buffer)) + { + UnpinLocalBuffer(buffer); + return; + } + + ResourceOwnerForgetBuffer(CurrentResourceOwner, buffer); + + buf = GetBufferDescriptor(buffer - 1); + + mode = BufferLockDisownInternal(buffer, buf); + + /* compute state modification for lock release */ + sub = BufferLockReleaseSub(mode); + + /* compute state modification for pin release */ + ref = GetPrivateRefCountEntry(buffer, false); + Assert(ref != NULL); + Assert(ref->data.refcount > 0); + ref->data.refcount--; + + /* no more backend local pins, reduce shared pin count */ + if (likely(ref->data.refcount == 0)) + { + sub |= BUF_REFCOUNT_ONE; + ForgetPrivateRefCountEntry(ref); + } + + /* perform the lock and pin release in one atomic op */ + lockstate = pg_atomic_sub_fetch_u64(&buf->state, sub); + + /* wake up waiters for the lock */ + BufferLockProcessRelease(buf, mode, lockstate); + + /* wake up waiter for the pin release */ + if (lockstate & BM_PIN_COUNT_WAITER) + WakePinCountWaiter(buf); + + /* + * Now okay to allow cancel/die interrupts again, were held when the lock + * was acquired. + */ + RESUME_INTERRUPTS(); } /* -- 2.53.0.1.gb2826b52eb