buffreelistlock_reduction.v1.patch

text/x-patch

Filename: buffreelistlock_reduction.v1.patch
Type: text/x-patch
Part: 0
Message: Re: our buffer replacement strategy is kind of lame

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
Series: patch v1
File+
src/backend/storage/buffer/bufmgr.c 5 3
src/backend/storage/buffer/freelist.c 46 9
src/include/storage/buf_internals.h 2 1
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 91cc001..86af943 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -1242,7 +1242,7 @@ BufferSync(int flags)
 	 * Note that we don't read the buffer alloc count here --- that should be
 	 * left untouched till the next BgBufferSync() call.
 	 */
-	buf_id = StrategySyncStart(NULL, NULL);
+	buf_id = StrategySyncStart(NULL, NULL, NULL);
 	num_to_scan = NBuffers;
 	num_written = 0;
 	while (num_to_scan-- > 0)
@@ -1315,6 +1315,7 @@ BgBufferSync(void)
 	int			strategy_buf_id;
 	uint32		strategy_passes;
 	uint32		recent_alloc;
+	bool		with_lock;
 
 	/*
 	 * Information saved between calls so we can determine the strategy
@@ -1352,10 +1353,11 @@ BgBufferSync(void)
 	 * Find out where the freelist clock sweep currently is, and how many
 	 * buffer allocations have happened since our last call.
 	 */
-	strategy_buf_id = StrategySyncStart(&strategy_passes, &recent_alloc);
+	strategy_buf_id = StrategySyncStart(&strategy_passes, &recent_alloc, &with_lock);
 
 	/* Report buffer alloc counts to pgstat */
-	BgWriterStats.m_buf_alloc += recent_alloc;
+	if (with_lock)
+		BgWriterStats.m_buf_alloc += recent_alloc;
 
 	/*
 	 * If we're not running the LRU scan, just stop after doing the stats
diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c
index 3e62448..27d4ae8 100644
--- a/src/backend/storage/buffer/freelist.c
+++ b/src/backend/storage/buffer/freelist.c
@@ -252,20 +252,57 @@ StrategyFreeBuffer(volatile BufferDesc *buf)
  * being read.
  */
 int
-StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc)
+StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc, bool *withlock)
 {
 	int			result;
 
-	LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
-	result = StrategyControl->nextVictimBuffer;
-	if (complete_passes)
-		*complete_passes = StrategyControl->completePasses;
-	if (num_buf_alloc)
+	if (withlock)
 	{
-		*num_buf_alloc = StrategyControl->numBufferAllocs;
-		StrategyControl->numBufferAllocs = 0;
+		bool	gotlock = false;
+
+		/*
+		 * Try to get the lock without waiting.
+		 */
+		if (LWLockConditionalAcquire(BufFreelistLock, LW_EXCLUSIVE))
+			gotlock = true;
+
+		/*
+		 * If lock isn't available without waiting then mostly we don't
+		 * care and just read the nextVictimBuffer without a lock.
+		 *
+		 * Bgwriter stats reporting relies on us reading accurate values
+		 * and being able to reset the counter, so about 1% of the time
+		 * we want to wait for the lock so we stats don't get starved out.
+		 */
+		if (!gotlock && random() <= (MAX_RANDOM_VALUE / 100))
+		{
+			LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
+			gotlock = true;
+		}
+
+		if (gotlock)
+		{
+			*withlock = true;
+			result = StrategyControl->nextVictimBuffer;
+			if (complete_passes)
+				*complete_passes = StrategyControl->completePasses;
+			if (num_buf_alloc)
+			{
+				*num_buf_alloc = StrategyControl->numBufferAllocs;
+				StrategyControl->numBufferAllocs = 0;
+			}
+			LWLockRelease(BufFreelistLock);
+
+			return result;
+		}
 	}
-	LWLockRelease(BufFreelistLock);
+
+	/*
+	 * We didn't get the lock, but read the value anyway on the assumption
+	 * that reading this value is atomic.
+	 */
+	result = StrategyControl->nextVictimBuffer;
+
 	return result;
 }
 
diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h
index e43719e..95a5a2f 100644
--- a/src/include/storage/buf_internals.h
+++ b/src/include/storage/buf_internals.h
@@ -187,7 +187,8 @@ extern void StrategyFreeBuffer(volatile BufferDesc *buf);
 extern bool StrategyRejectBuffer(BufferAccessStrategy strategy,
 					 volatile BufferDesc *buf);
 
-extern int	StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc);
+extern int	StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc,
+								bool *withlock);
 extern Size StrategyShmemSize(void);
 extern void StrategyInitialize(bool init);