From 7b65e934b0b18f1e6ccd7f5cf8906c9c4326b7c5 Mon Sep 17 00:00:00 2001 From: Melanie Plageman Date: Mon, 2 Feb 2026 11:29:43 -0500 Subject: [PATCH v14 04/12] Allow PinBuffer to skip increasing usage count A future commit will use PinBuffer() in background writer code. Since background writer does not increase the usage count for a buffer, we needed a way to indicate that to PinBuffer(). Add BufferUsageCountChange which 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 usage the zero option. --- src/backend/storage/buffer/bufmgr.c | 35 ++++++++++++++++++++++------- src/tools/pgindent/typedefs.list | 1 + 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 0b5adc9e4a6..902b91ab6c2 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -170,6 +170,13 @@ typedef struct SMgrSortArray SMgrRelation srel; } SMgrSortArray; +typedef enum BufferUsageCountChange +{ + BUC_ZERO, + BUC_MAX_ONE, + BUC_ONE, +} BufferUsageCountChange; + /* GUC variables */ bool zero_damaged_pages = false; int bgwriter_lru_maxpages = 100; @@ -619,7 +626,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); @@ -845,7 +852,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)) { @@ -2140,7 +2147,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); @@ -2202,7 +2211,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); @@ -2839,7 +2850,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); @@ -3147,6 +3160,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 @@ -3170,7 +3184,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); @@ -3205,13 +3219,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 @@ -3220,6 +3234,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 241945734ec..1645adc1d81 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -360,6 +360,7 @@ BufferManagerRelation BufferStrategyControl BufferTag BufferUsage +BufferUsageCountChange BuildAccumulator BuiltinScript BulkInsertState -- 2.43.0