buffreelistlock_reduction.v1.patch
text/x-patch
Filename: buffreelistlock_reduction.v1.patch
Type: text/x-patch
Part: 0
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);