v18-0007-Add-UnlockBufferGetLSN-utility-function.patch
application/octet-stream
Filename: v18-0007-Add-UnlockBufferGetLSN-utility-function.patch
Type: application/octet-stream
Part: 12
Message:
Re: index prefetching
Patch
Format: format-patch
Series: patch v18-0007
Subject: Add UnlockBufferGetLSN utility function.
| File | + | − |
|---|---|---|
| src/backend/access/index/indexbatch.c | 1 | 11 |
| src/backend/storage/buffer/bufmgr.c | 90 | 0 |
| src/include/storage/bufmgr.h | 1 | 0 |
From 5cfd98c132556aa6a95d74f7150a4048243e65e5 Mon Sep 17 00:00:00 2001
From: Peter Geoghegan <pg@bowt.ie>
Date: Tue, 17 Mar 2026 13:25:12 -0400
Subject: [PATCH v18 07/19] Add UnlockBufferGetLSN utility function.
This combines the functionality of BufferGetLSNAtomic() with
UnlockReleaseBuffer, with the option of not releasing buffer pin.
Author: Peter Geoghegan <pg@bowt.ie>
Discussion: https://postgr.es/m/CAH2-WzkyG01682zwqyUTwV=Zq+M_qGgi1NbXwp1H-piRSfJsgQ@mail.gmail.com
---
src/include/storage/bufmgr.h | 1 +
src/backend/access/index/indexbatch.c | 12 +---
src/backend/storage/buffer/bufmgr.c | 90 +++++++++++++++++++++++++++
3 files changed, 92 insertions(+), 11 deletions(-)
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index dd41b92f9..681a3e56f 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -255,6 +255,7 @@ extern void WaitReadBuffers(ReadBuffersOperation *operation);
extern void ReleaseBuffer(Buffer buffer);
extern void UnlockReleaseBuffer(Buffer buffer);
+extern XLogRecPtr UnlockBufferGetLSN(Buffer buffer, bool release);
extern bool BufferIsLockedByMe(Buffer buffer);
extern bool BufferIsLockedByMeInMode(Buffer buffer, BufferLockMode mode);
extern bool BufferIsDirty(Buffer buffer);
diff --git a/src/backend/access/index/indexbatch.c b/src/backend/access/index/indexbatch.c
index 3abf58453..565182430 100644
--- a/src/backend/access/index/indexbatch.c
+++ b/src/backend/access/index/indexbatch.c
@@ -491,17 +491,7 @@ indexam_util_batch_unlock(IndexScanDesc scan, IndexScanBatch batch, Buffer buf)
* Non-immediate-unguard scans retain the pin; the table AM will call
* amunguardbatch to drop the interlock when ready.
*/
- batch->lsn = BufferGetLSNAtomic(buf);
- if (scan->batchImmediateUnguard)
- {
- /* drop both the lock and the pin */
- UnlockReleaseBuffer(buf);
- }
- else
- {
- /* just drop the lock (hold on to interlock pin) */
- UnlockBuffer(buf);
- }
+ batch->lsn = UnlockBufferGetLSN(buf, scan->batchImmediateUnguard);
/* If we released buffer pin, batch is now unguarded */
batch->isGuarded = !scan->batchImmediateUnguard;
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index cd21ae3fc..4cdb565e4 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -5638,6 +5638,96 @@ UnlockReleaseBuffer(Buffer buffer)
RESUME_INTERRUPTS();
}
+/*
+ * UnlockBufferGetLSN
+ * Read a buffer's LSN, then unlock the buffer. Optionally release the
+ * pin too.
+ *
+ * This combines the functionality of BufferGetLSNAtomic() with
+ * UnlockReleaseBuffer, with the option of not releasing buffer pin.
+ *
+ * Used to unlock a buffer lock (and possibly to release its pin) when held on
+ * an index page. This is needed frequently enough to justify specialization.
+ */
+XLogRecPtr
+UnlockBufferGetLSN(Buffer buffer, bool release)
+{
+ BufferDesc *buf_hdr;
+ Page page;
+ XLogRecPtr lsn;
+ int mode;
+ uint64 sub;
+ uint64 lockstate;
+ PrivateRefCountEntry *ref;
+
+ Assert(BufferIsValid(buffer));
+ Assert(BufferIsPinned(buffer));
+
+ if (BufferIsLocal(buffer))
+ {
+ buf_hdr = GetLocalBufferDescriptor(-buffer - 1);
+ page = (Page) LocalBufHdrGetBlock(buf_hdr);
+ lsn = PageGetLSN(page);
+ if (release)
+ UnpinLocalBuffer(buffer);
+ return lsn;
+ }
+
+ buf_hdr = GetBufferDescriptor(buffer - 1);
+ page = (Page) BufHdrGetBlock(buf_hdr);
+
+#ifdef PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY
+ lsn = PageGetLSN(page);
+#else
+ lsn = BufferGetLSNAtomic(buffer);
+#endif
+
+ if (!release)
+ {
+ /* Just release the lock */
+ BufferLockUnlock(buffer, buf_hdr);
+ return lsn;
+ }
+
+ /* Release both lock and pin in one atomic op */
+ ResourceOwnerForgetBuffer(CurrentResourceOwner, buffer);
+
+ mode = BufferLockDisownInternal(buffer, buf_hdr);
+
+ /* 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))
+ {
+ /* See comment in UnpinBufferNoOwner() */
+ VALGRIND_MAKE_MEM_NOACCESS(BufHdrGetBlock(buf_hdr), BLCKSZ);
+
+ sub |= BUF_REFCOUNT_ONE;
+ ForgetPrivateRefCountEntry(ref);
+ }
+
+ /* perform the lock and pin release in one atomic op */
+ lockstate = pg_atomic_sub_fetch_u64(&buf_hdr->state, sub);
+
+ /* wake up waiters for the lock */
+ BufferLockProcessRelease(buf_hdr, mode, lockstate);
+
+ /* wake up waiter for the pin release */
+ if (lockstate & BM_PIN_COUNT_WAITER)
+ WakePinCountWaiter(buf_hdr);
+
+ RESUME_INTERRUPTS();
+
+ return lsn;
+}
+
/*
* IncrBufferRefCount
* Increment the pin count on a buffer that we have *already* pinned
--
2.53.0