Skip to content

Commit c75ebc6

Browse files
committed
bufmgr: Allow some buffer state modifications while holding header lock
Until now BufferDesc.state was not allowed to be modified while the buffer header spinlock was held. This meant that operations like unpinning buffers needed to use a CAS loop, waiting for the buffer header spinlock to be released before updating. The benefit of that restriction is that it allowed us to unlock the buffer header spinlock with just a write barrier and an unlocked write (instead of a full atomic operation). That was important to avoid regressions in 4835458. However, since then the hottest buffer header spinlock uses have been replaced with atomic operations (in particular, the most common use of PinBuffer_Locked(), in GetVictimBuffer() (formerly in BufferAlloc()), has been removed in 5e89985). This change will allow, in a subsequent commit, to release buffer pins with a single atomic-sub operation. This previously was not possible while such operations were not allowed while the buffer header spinlock was held, as an atomic-sub would not have allowed a race-free check for the buffer header lock being held. Using atomic-sub to unpin buffers is a nice scalability win, however it is not the primary motivation for this change (although it would be sufficient). The primary motivation is that we would like to merge the buffer content lock into BufferDesc.state, which will result in more frequent changes of the state variable, which in some situations can cause a performance regression, due to an increased CAS failure rate when unpinning buffers. The regression entirely vanishes when using atomic-sub. Naively implementing this would require putting CAS loops in every place modifying the buffer state while holding the buffer header lock. To avoid that, introduce UnlockBufHdrExt(), which can set/add flags as well as the refcount, together with releasing the lock. Reviewed-by: Robert Haas <[email protected]> Reviewed-by: Matthias van de Meent <[email protected]> Discussion: https://postgr.es/m/fvfmkr5kk4nyex56ejgxj3uzi63isfxovp2biecb4bspbjrze7@az2pljabhnff
1 parent 448b6a4 commit c75ebc6

File tree

6 files changed

+224
-119
lines changed

6 files changed

+224
-119
lines changed

contrib/pg_buffercache/pg_buffercache_pages.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
220220
else
221221
fctx->record[i].isvalid = false;
222222

223-
UnlockBufHdr(bufHdr, buf_state);
223+
UnlockBufHdr(bufHdr);
224224
}
225225
}
226226

@@ -460,7 +460,6 @@ pg_buffercache_numa_pages(PG_FUNCTION_ARGS)
460460
{
461461
char *buffptr = (char *) BufferGetBlock(i + 1);
462462
BufferDesc *bufHdr;
463-
uint32 buf_state;
464463
uint32 bufferid;
465464
int32 page_num;
466465
char *startptr_buff,
@@ -471,9 +470,9 @@ pg_buffercache_numa_pages(PG_FUNCTION_ARGS)
471470
bufHdr = GetBufferDescriptor(i);
472471

473472
/* Lock each buffer header before inspecting. */
474-
buf_state = LockBufHdr(bufHdr);
473+
LockBufHdr(bufHdr);
475474
bufferid = BufferDescriptorGetBuffer(bufHdr);
476-
UnlockBufHdr(bufHdr, buf_state);
475+
UnlockBufHdr(bufHdr);
477476

478477
/* start of the first page of this buffer */
479478
startptr_buff = (char *) TYPEALIGN_DOWN(os_page_size, buffptr);

contrib/pg_prewarm/autoprewarm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,7 @@ apw_dump_now(bool is_bgworker, bool dump_unlogged)
730730
++num_blocks;
731731
}
732732

733-
UnlockBufHdr(bufHdr, buf_state);
733+
UnlockBufHdr(bufHdr);
734734
}
735735

736736
snprintf(transient_dump_file_path, MAXPGPATH, "%s.tmp", AUTOPREWARM_FILE);

0 commit comments

Comments
 (0)