From 49da32783fece28aec798a9475e2d7097c340c0b Mon Sep 17 00:00:00 2001 From: Alexandre Felipe Date: Wed, 9 Sep 2026 10:19:22 +0100 Subject: [PATCH 2/2] rooms applied to BufferMapping This commit updates the BufMappingPartitionLock to compute both the partition (selecting a LWLock*) and room, that gives additional granularity for LW_EXCLUSIVE locks. The line LW_LOCK_ROOM_ALPHA(hashcode >> LOG2_NUM_BUFFER_PARTITIONS) doing a `- % + <<` another approach would be `& * >>` sequence. e.g. (hashcode & (0x1f << (32 - 5))) * 26 >> (32 - 5) or with a single 64-bit multiplications as (hashcode * 26ll) >> 32 But we might be about to sleep, that is a bigger concern. --- src/backend/storage/buffer/bufmgr.c | 23 +++++++---------------- src/include/storage/buf_internals.h | 23 ++++++++--------------- 2 files changed, 15 insertions(+), 31 deletions(-) diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 17f142e4c5b..b6a0a9130c4 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -712,10 +712,9 @@ PrefetchSharedBuffer(SMgrRelation smgr_reln, /* determine its hash code and partition lock ID */ newHash = BufTableHashCode(&newTag); - newPartitionLock = BufMappingPartitionLock(newHash); + newPartitionLock = BufMappingPartitionLock(newHash, LW_SHARED); /* see if the block is in the buffer pool already */ - LWLockAcquire(newPartitionLock, LW_SHARED); buf_id = BufTableLookup(&newTag, newHash); LWLockRelease(newPartitionLock); @@ -2217,10 +2216,9 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, /* determine its hash code and partition lock ID */ newHash = BufTableHashCode(&newTag); - newPartitionLock = BufMappingPartitionLock(newHash); + newPartitionLock = BufMappingPartitionLock(newHash, LW_SHARED); /* see if the block is in the buffer pool already */ - LWLockAcquire(newPartitionLock, LW_SHARED); existing_buf_id = BufTableLookup(&newTag, newHash); if (existing_buf_id >= 0) { @@ -2273,7 +2271,7 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, * somebody else inserted another buffer for the tag, we'll release the * victim buffer we acquired and use the already inserted one. */ - LWLockAcquire(newPartitionLock, LW_EXCLUSIVE); + newPartitionLock = BufMappingPartitionLock(newHash, LW_EXCLUSIVE); existing_buf_id = BufTableInsert(&newTag, newHash, victim_buf_hdr->buf_id); if (existing_buf_id >= 0) { @@ -2386,15 +2384,13 @@ InvalidateBuffer(BufferDesc *buf) * here? Probably not. */ oldHash = BufTableHashCode(&oldTag); - oldPartitionLock = BufMappingPartitionLock(oldHash); - retry: /* * Acquire exclusive mapping lock in preparation for changing the buffer's * association. */ - LWLockAcquire(oldPartitionLock, LW_EXCLUSIVE); + oldPartitionLock = BufMappingPartitionLock(oldHash, LW_EXCLUSIVE); /* Re-lock the buffer header */ buf_state = LockBufHdr(buf); @@ -2481,9 +2477,7 @@ InvalidateVictimBuffer(BufferDesc *buf_hdr) tag = buf_hdr->tag; hash = BufTableHashCode(&tag); - partition_lock = BufMappingPartitionLock(hash); - - LWLockAcquire(partition_lock, LW_EXCLUSIVE); + partition_lock = BufMappingPartitionLock(hash, LW_EXCLUSIVE); /* lock the buffer header */ buf_state = LockBufHdr(buf_hdr); @@ -2925,9 +2919,7 @@ ExtendBufferedRelShared(BufferManagerRelation bmr, InitBufferTag(&tag, &BMR_GET_SMGR(bmr)->smgr_rlocator.locator, fork, first_block + i); hash = BufTableHashCode(&tag); - partition_lock = BufMappingPartitionLock(hash); - - LWLockAcquire(partition_lock, LW_EXCLUSIVE); + partition_lock = BufMappingPartitionLock(hash, LW_EXCLUSIVE); existing_id = BufTableInsert(&tag, hash, victim_buf_hdr->buf_id); @@ -5094,10 +5086,9 @@ FindAndDropRelationBuffers(RelFileLocator rlocator, ForkNumber forkNum, /* determine its hash code and partition lock ID */ bufHash = BufTableHashCode(&bufTag); - bufPartitionLock = BufMappingPartitionLock(bufHash); + bufPartitionLock = BufMappingPartitionLock(bufHash, LW_SHARED); /* Check that it is in the buffer pool. If not, do nothing. */ - LWLockAcquire(bufPartitionLock, LW_SHARED); buf_id = BufTableLookup(&bufTag, bufHash); LWLockRelease(bufPartitionLock); diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index e4ff5619b79..e8b0cc72f48 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -242,25 +242,18 @@ BufTagMatchesRelFileLocator(const BufferTag *tag, * The shared buffer mapping table is partitioned to reduce contention. * To determine which partition lock a given tag requires, compute the tag's * hash code with BufTableHashCode(), then apply BufMappingPartitionLock(). - * NB: NUM_BUFFER_PARTITIONS must be a power of 2! + * */ -static inline uint32 -BufTableHashPartition(uint32 hashcode) -{ - return hashcode % NUM_BUFFER_PARTITIONS; -} - -static inline LWLock * -BufMappingPartitionLock(uint32 hashcode) -{ - return &MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + - BufTableHashPartition(hashcode)].lock; -} static inline LWLock * -BufMappingPartitionLockByIndex(uint32 index) +BufMappingPartitionLock(uint32 hashcode, LWLockMode mode) { - return &MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + index].lock; + int p = BUFFER_MAPPING_LWLOCK_OFFSET + (hashcode % NUM_BUFFER_PARTITIONS); + LWLock *lock = &MainLWLockArray[p].lock; + if(mode == LW_EXCLUSIVE) + mode += LW_LOCK_ROOM_ALPHA(hashcode >> LOG2_NUM_BUFFER_PARTITIONS); + LWLockAcquire(lock, mode); + return lock; } /* -- 2.53.0