From f4432681ab1284edf8ec0ea0e0f277880f936b60 Mon Sep 17 00:00:00 2001
From: Melanie Plageman <melanieplageman@gmail.com>
Date: Mon, 2 Feb 2026 11:29:43 -0500
Subject: [PATCH v15 06/19] Allow PinBuffer to skip increasing usage count

Future commits will allow eagerly flushing buffers when flushing a
target buffer. In those cases, they do not want PinBuffer() to incrase
the usage count on the buffer, as it is not being used by that flusher.

BufferUsageCountChange allows increasing the usage count by either zero,
a maximum of one (in case we don't want to increase it beyond one), or
one unconditionally. This commit only introduces this but doesn't use
the zero option.
---
 src/backend/storage/buffer/bufmgr.c | 41 +++++++++++++++++++++++------
 src/tools/pgindent/typedefs.list    |  1 +
 2 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 771130b06a1..f9c3dcea2c3 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -180,6 +180,19 @@ typedef struct SMgrSortArray
 	SMgrRelation srel;
 } SMgrSortArray;
 
+/* How much PinBuffer() should increase the usage count of the target buffer */
+typedef enum BufferUsageCountChange
+{
+	/* Do not increase the usage count */
+	BUC_ZERO,
+
+	/* Increase usage count by one to a maximum of one (used with strategies) */
+	BUC_MAX_ONE,
+
+	/* Increase usage count by one up to the max (BM_MAX_USAGE_COUNT) */
+	BUC_ONE,
+} BufferUsageCountChange;
+
 /* GUC variables */
 bool		zero_damaged_pages = false;
 int			bgwriter_lru_maxpages = 100;
@@ -623,7 +636,7 @@ static BlockNumber ExtendBufferedRelShared(BufferManagerRelation bmr,
 										   BlockNumber extend_upto,
 										   Buffer *buffers,
 										   uint32 *extended_by);
-static bool PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy,
+static bool PinBuffer(BufferDesc *buf, BufferUsageCountChange usage_count_change,
 					  bool skip_if_not_valid);
 static void PinBuffer_Locked(BufferDesc *buf);
 static void UnpinBuffer(BufferDesc *buf);
@@ -854,7 +867,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN
 		 * pin.
 		 */
 		if (BufferTagsEqual(&tag, &bufHdr->tag) &&
-			PinBuffer(bufHdr, NULL, true))
+			PinBuffer(bufHdr, BUC_ONE, true))
 		{
 			if (BufferTagsEqual(&tag, &bufHdr->tag))
 			{
@@ -2231,7 +2244,9 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
 		 */
 		buf = GetBufferDescriptor(existing_buf_id);
 
-		valid = PinBuffer(buf, strategy, false);
+		valid = PinBuffer(buf,
+						  strategy ? BUC_MAX_ONE : BUC_ONE,
+						  false);
 
 		/* Can release the mapping lock as soon as we've pinned it */
 		LWLockRelease(newPartitionLock);
@@ -2293,7 +2308,9 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
 
 		existing_buf_hdr = GetBufferDescriptor(existing_buf_id);
 
-		valid = PinBuffer(existing_buf_hdr, strategy, false);
+		valid = PinBuffer(existing_buf_hdr,
+						  strategy ? BUC_MAX_ONE : BUC_ONE,
+						  false);
 
 		/* Can release the mapping lock as soon as we've pinned it */
 		LWLockRelease(newPartitionLock);
@@ -2931,7 +2948,9 @@ ExtendBufferedRelShared(BufferManagerRelation bmr,
 			 * Pin the existing buffer before releasing the partition lock,
 			 * preventing it from being evicted.
 			 */
-			valid = PinBuffer(existing_hdr, strategy, false);
+			valid = PinBuffer(existing_hdr,
+							  strategy ? BUC_MAX_ONE : BUC_ONE,
+							  false);
 
 			LWLockRelease(partition_lock);
 			UnpinBuffer(victim_buf_hdr);
@@ -3247,6 +3266,7 @@ ReleaseAndReadBuffer(Buffer buffer,
 /*
  * PinBuffer -- make buffer unavailable for replacement.
  *
+ * Most callers will want to bump the usage count to at least one.
  * For the default access strategy, the buffer's usage_count is incremented
  * when we first pin it; for other strategies we just make sure the usage_count
  * isn't zero.  (The idea of the latter is that we don't want synchronized
@@ -3270,7 +3290,7 @@ ReleaseAndReadBuffer(Buffer buffer,
  * (recently) invalid and has not been pinned.
  */
 static bool
-PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy,
+PinBuffer(BufferDesc *buf, BufferUsageCountChange usage_count_change,
 		  bool skip_if_not_valid)
 {
 	Buffer		b = BufferDescriptorGetBuffer(buf);
@@ -3310,13 +3330,13 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy,
 			/* increase refcount */
 			buf_state += BUF_REFCOUNT_ONE;
 
-			if (strategy == NULL)
+			if (usage_count_change == BUC_ONE)
 			{
 				/* Default case: increase usagecount unless already max. */
 				if (BUF_STATE_GET_USAGECOUNT(buf_state) < BM_MAX_USAGE_COUNT)
 					buf_state += BUF_USAGECOUNT_ONE;
 			}
-			else
+			else if (usage_count_change == BUC_MAX_ONE)
 			{
 				/*
 				 * Ring buffers shouldn't evict others from pool.  Thus we
@@ -3325,6 +3345,11 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy,
 				if (BUF_STATE_GET_USAGECOUNT(buf_state) == 0)
 					buf_state += BUF_USAGECOUNT_ONE;
 			}
+			else
+			{
+				/* Don't increase usage count */
+				Assert(usage_count_change == BUC_ZERO);
+			}
 
 			if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state,
 											   buf_state))
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 1969d467c1d..2954f47d286 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -368,6 +368,7 @@ BufferManagerRelation
 BufferStrategyControl
 BufferTag
 BufferUsage
+BufferUsageCountChange
 BuildAccumulator
 BuiltinScript
 BulkInsertState
-- 
2.43.0

