v4-0004-Merge-partition-locks-array-with-buffer-locks-arr.patch

application/octet-stream

Filename: v4-0004-Merge-partition-locks-array-with-buffer-locks-arr.patch
Type: application/octet-stream
Part: 4
Message: Re: SLRU optimization - configurable buffer pool and partitioning the SLRU lock

Patch

Format: format-patch
Series: patch v4-0004
Subject: Merge partition locks array with buffer locks array
File+
src/backend/access/transam/slru.c 64 58
src/include/access/slru.h 5 5
From 30cc4cc9d7f2c65bfa072349ddd26aaa3b3ae0cd Mon Sep 17 00:00:00 2001
From: Dilip Kumar <dilip.kumar@enterprisedb.com>
Date: Thu, 2 Nov 2023 10:59:03 +0530
Subject: [PATCH v4 4/5] Merge partition locks array with buffer locks array

This will help us getting the part_cur_lru_count in same cacheline
which is frequently accessed in SlruRecentlyUsed.
---
 src/backend/access/transam/slru.c | 122 ++++++++++++++++--------------
 src/include/access/slru.h         |  10 +--
 2 files changed, 69 insertions(+), 63 deletions(-)

diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index ab7cd276ce..8b89a86a10 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -152,8 +152,7 @@ SimpleLruStructSize(int nslots, int nlsns)
 	sz += MAXALIGN(nslots * sizeof(bool));	/* page_dirty[] */
 	sz += MAXALIGN(nslots * sizeof(int));	/* page_number[] */
 	sz += MAXALIGN(nslots * sizeof(int));	/* page_lru_count[] */
-	sz += MAXALIGN(nslots * sizeof(LWLockPadded));	/* buffer_locks[] */
-	sz += MAXALIGN(SLRU_NUM_PARTITIONS * sizeof(LWLockPadded));	/* part_locks[] */
+	sz += MAXALIGN((nslots + SLRU_NUM_PARTITIONS) * sizeof(LWLockPadded));	/* locks[] */
 	sz += MAXALIGN(SLRU_NUM_PARTITIONS * sizeof(int));   /* part_cur_lru_count[] */
 
 	if (nlsns > 0)
@@ -231,10 +230,8 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
 		offset += MAXALIGN(nslots * sizeof(int));
 
 		/* Initialize LWLocks */
-		shared->buffer_locks = (LWLockPadded *) (ptr + offset);
-		offset += MAXALIGN(nslots * sizeof(LWLockPadded));
-		shared->part_locks = (LWLockPadded *) (ptr + offset);
-		offset += MAXALIGN(SLRU_NUM_PARTITIONS * sizeof(LWLockPadded));
+		shared->locks = (LWLockPadded *) (ptr + offset);
+		offset += MAXALIGN((nslots + SLRU_NUM_PARTITIONS) * sizeof(LWLockPadded));
 		shared->part_cur_lru_count = (int *) (ptr + offset);
 		offset += MAXALIGN(SLRU_NUM_PARTITIONS * sizeof(int));
 
@@ -247,8 +244,7 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
 		ptr += BUFFERALIGN(offset);
 		for (slotno = 0; slotno < nslots; slotno++)
 		{
-			LWLockInitialize(&shared->buffer_locks[slotno].lock,
-							 buffer_tranche_id);
+			LWLockInitialize(&shared->locks[slotno].lock, buffer_tranche_id);
 
 			shared->page_buffer[slotno] = ptr;
 			shared->page_status[slotno] = SLRU_PAGE_EMPTY;
@@ -259,7 +255,7 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
 		/* Initialize partition locks for each buffer partition. */
 		for (partno = 0; partno < SLRU_NUM_PARTITIONS; partno++)
 		{
-			LWLockInitialize(&shared->part_locks[partno].lock,
+			LWLockInitialize(&shared->locks[nslots + partno].lock,
 							 part_tranche_id);
 			shared->part_cur_lru_count[partno] = 0;
 		}
@@ -369,12 +365,13 @@ SimpleLruWaitIO(SlruCtl ctl, int slotno)
 {
 	SlruShared	shared = ctl->shared;
 	int			partno = slotno / ctl->part_size;
+	int			partlockoffset = shared->num_slots + partno;
 
 	/* See notes at top of file */
-	LWLockRelease(&shared->part_locks[partno].lock);
-	LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_SHARED);
-	LWLockRelease(&shared->buffer_locks[slotno].lock);
-	LWLockAcquire(&shared->part_locks[partno].lock, LW_EXCLUSIVE);
+	LWLockRelease(&shared->locks[partlockoffset].lock);
+	LWLockAcquire(&shared->locks[slotno].lock, LW_SHARED);
+	LWLockRelease(&shared->locks[slotno].lock);
+	LWLockAcquire(&shared->locks[partlockoffset].lock, LW_EXCLUSIVE);
 
 	/*
 	 * If the slot is still in an io-in-progress state, then either someone
@@ -387,7 +384,7 @@ SimpleLruWaitIO(SlruCtl ctl, int slotno)
 	if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS ||
 		shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS)
 	{
-		if (LWLockConditionalAcquire(&shared->buffer_locks[slotno].lock, LW_SHARED))
+		if (LWLockConditionalAcquire(&shared->locks[slotno].lock, LW_SHARED))
 		{
 			/* indeed, the I/O must have failed */
 			if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS)
@@ -400,7 +397,7 @@ SimpleLruWaitIO(SlruCtl ctl, int slotno)
 				shared->page_status[slotno] = SLRU_PAGE_VALID;
 				shared->page_dirty[slotno] = true;
 			}
-			LWLockRelease(&shared->buffer_locks[slotno].lock);
+			LWLockRelease(&shared->locks[slotno].lock);
 		}
 	}
 }
@@ -433,6 +430,7 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
 	{
 		int			slotno;
 		int			partno;
+		int			banklockoffset;
 		bool		ok;
 
 		/* See if page already is in memory; if not, pick victim slot */
@@ -477,11 +475,12 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
 		shared->page_dirty[slotno] = false;
 
 		/* Acquire per-buffer lock (cannot deadlock, see notes at top) */
-		LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_EXCLUSIVE);
+		LWLockAcquire(&shared->locks[slotno].lock, LW_EXCLUSIVE);
 		partno = slotno / ctl->part_size;
+		banklockoffset = shared->num_slots + partno;
 
 		/* Release control lock while doing I/O */
-		LWLockRelease(&shared->part_locks[partno].lock);
+		LWLockRelease(&shared->locks[banklockoffset].lock);
 
 		/* Do the read */
 		ok = SlruPhysicalReadPage(ctl, pageno, slotno);
@@ -490,7 +489,7 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
 		SimpleLruZeroLSNs(ctl, slotno);
 
 		/* Re-acquire control lock and update page state */
-		LWLockAcquire(&shared->part_locks[partno].lock, LW_EXCLUSIVE);
+		LWLockAcquire(&shared->locks[banklockoffset].lock, LW_EXCLUSIVE);
 
 		Assert(shared->page_number[slotno] == pageno &&
 			   shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&
@@ -504,7 +503,7 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
 			shared->page_status[slotno] = SLRU_PAGE_EMPTY;
 		}
 
-		LWLockRelease(&shared->buffer_locks[slotno].lock);
+		LWLockRelease(&shared->locks[slotno].lock);
 
 		/* Now it's okay to ereport if we failed */
 		if (!ok)
@@ -539,12 +538,14 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
 	SlruShared	shared = ctl->shared;
 	int			slotno;
 	int			partno;
+	int			partlockoffset;
 
 	/* Determine partition number for the page. */
 	partno = SlruMappingPartNo(ctl, pageno);
+	partlockoffset = shared->num_slots + partno;
 
 	/* Try to find the page while holding only shared partition lock */
-	LWLockAcquire(&shared->part_locks[partno].lock, LW_SHARED);
+	LWLockAcquire(&shared->locks[partlockoffset].lock, LW_SHARED);
 
 	/* See if page is already in a buffer */
 	slotno = SlruMappingFind(ctl, pageno);
@@ -564,8 +565,8 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
 	}
 
 	/* No luck, so switch to normal exclusive lock and do regular read */
-	LWLockRelease(&shared->part_locks[partno].lock);
-	LWLockAcquire(&shared->part_locks[partno].lock, LW_EXCLUSIVE);
+	LWLockRelease(&shared->locks[partlockoffset].lock);
+	LWLockAcquire(&shared->locks[partlockoffset].lock, LW_EXCLUSIVE);
 
 	return SimpleLruReadPage(ctl, pageno, true, xid);
 }
@@ -588,6 +589,7 @@ SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata)
 	int			pageno = shared->page_number[slotno];
 	bool		ok;
 	int			partno = slotno / ctl->part_size;
+	int			partlockoffset = shared->num_slots + partno;
 
 	/* If a write is in progress, wait for it to finish */
 	while (shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS &&
@@ -613,10 +615,10 @@ SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata)
 	shared->page_dirty[slotno] = false;
 
 	/* Acquire per-buffer lock (cannot deadlock, see notes at top) */
-	LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_EXCLUSIVE);
+	LWLockAcquire(&shared->locks[slotno].lock, LW_EXCLUSIVE);
 
 	/* Release control lock while doing I/O */
-	LWLockRelease(&shared->part_locks[partno].lock);
+	LWLockRelease(&shared->locks[partlockoffset].lock);
 
 	/* Do the write */
 	ok = SlruPhysicalWritePage(ctl, pageno, slotno, fdata);
@@ -631,7 +633,7 @@ SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata)
 	}
 
 	/* Re-acquire control lock and update page state */
-	LWLockAcquire(&shared->part_locks[partno].lock, LW_EXCLUSIVE);
+	LWLockAcquire(&shared->locks[partlockoffset].lock, LW_EXCLUSIVE);
 
 	Assert(shared->page_number[slotno] == pageno &&
 		   shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS);
@@ -642,7 +644,7 @@ SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata)
 
 	shared->page_status[slotno] = SLRU_PAGE_VALID;
 
-	LWLockRelease(&shared->buffer_locks[slotno].lock);
+	LWLockRelease(&shared->locks[slotno].lock);
 
 	/* Now it's okay to ereport if we failed */
 	if (!ok)
@@ -1219,7 +1221,7 @@ SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
 	int			slotno;
 	int			pageno = 0;
 	int			i;
-	int			lastpartno = 0;
+	int			prevlockoffset = shared->num_slots;
 	bool		ok;
 
 	/* update the stats counter of flushes */
@@ -1230,17 +1232,17 @@ SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
 	 */
 	fdata.num_files = 0;
 
-	LWLockAcquire(&shared->part_locks[0].lock, LW_EXCLUSIVE);
+	LWLockAcquire(&shared->locks[prevlockoffset].lock, LW_EXCLUSIVE);
 
 	for (slotno = 0; slotno < shared->num_slots; slotno++)
 	{
-		int			curpartno = slotno / ctl->part_size;
+		int			curlockoffset = shared->num_slots + slotno / ctl->part_size;
 
-		if (curpartno != lastpartno)
+		if (curlockoffset != prevlockoffset)
 		{
-			LWLockRelease(&shared->part_locks[lastpartno].lock);
-			LWLockAcquire(&shared->part_locks[curpartno].lock, LW_EXCLUSIVE);
-			lastpartno = curpartno;
+			LWLockRelease(&shared->locks[prevlockoffset].lock);
+			LWLockAcquire(&shared->locks[curlockoffset].lock, LW_EXCLUSIVE);
+			prevlockoffset = curlockoffset;
 		}
 
 		SlruInternalWritePage(ctl, slotno, &fdata);
@@ -1256,7 +1258,7 @@ SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
 				!shared->page_dirty[slotno]));
 	}
 
-	LWLockRelease(&shared->part_locks[lastpartno].lock);
+	LWLockRelease(&shared->locks[prevlockoffset].lock);
 
 	/*
 	 * Now close any files that were open
@@ -1296,7 +1298,8 @@ SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
 {
 	SlruShared	shared = ctl->shared;
 	int			slotno;
-	int			prevpartno;
+	int			nslots = shared->num_slots;
+	int			prevlockoffset;
 
 	/* update the stats counter of truncates */
 	pgstat_count_slru_truncate(shared->slru_stats_idx);
@@ -1322,21 +1325,21 @@ restart:
 		return;
 	}
 
-	prevpartno = 0;
-	LWLockAcquire(&shared->part_locks[prevpartno].lock, LW_EXCLUSIVE);
-	for (slotno = 0; slotno < shared->num_slots; slotno++)
+	prevlockoffset = nslots;
+	LWLockAcquire(&shared->locks[prevlockoffset].lock, LW_EXCLUSIVE);
+	for (slotno = 0; slotno < nslots; slotno++)
 	{
-		int			curpartno = slotno / ctl->part_size;
+		int			curlockoffset = nslots + (slotno / ctl->part_size);
 
 		/*
 		 * If the curpartno is not same as prevpartno then release the lock on
 		 * the prevpartno and acquire the lock on the curpartno.
 		 */
-		if (curpartno != prevpartno)
+		if (curlockoffset != prevlockoffset)
 		{
-			LWLockRelease(&shared->part_locks[prevpartno].lock);
-			LWLockAcquire(&shared->part_locks[curpartno].lock, LW_EXCLUSIVE);
-			prevpartno = curpartno;
+			LWLockRelease(&shared->locks[prevlockoffset].lock);
+			LWLockAcquire(&shared->locks[curlockoffset].lock, LW_EXCLUSIVE);
+			prevlockoffset = curlockoffset;
 		}
 
 		if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
@@ -1370,11 +1373,11 @@ restart:
 		else
 			SimpleLruWaitIO(ctl, slotno);
 
-		LWLockRelease(&shared->part_locks[prevpartno].lock);
+		LWLockRelease(&shared->locks[prevlockoffset].lock);
 		goto restart;
 	}
 
-	LWLockRelease(&shared->part_locks[prevpartno].lock);
+	LWLockRelease(&shared->locks[prevlockoffset].lock);
 
 	/* Now we can remove the old segment(s) */
 	(void) SlruScanDirectory(ctl, SlruScanDirCbDeleteCutoff, &cutoffPage);
@@ -1415,28 +1418,29 @@ SlruDeleteSegment(SlruCtl ctl, int segno)
 	SlruShared	shared = ctl->shared;
 	int			slotno;
 	bool		did_write;
-	int			prevpartno = 0;
+	int			nslots = shared->num_slots;
+	int			prevlockoffset = nslots;
 
 	/* Clean out any possibly existing references to the segment. */
-	LWLockAcquire(&shared->part_locks[prevpartno].lock, LW_EXCLUSIVE);
+	LWLockAcquire(&shared->locks[prevlockoffset].lock, LW_EXCLUSIVE);
 restart:
 	did_write = false;
-	for (slotno = 0; slotno < shared->num_slots; slotno++)
+	for (slotno = 0; slotno < nslots; slotno++)
 	{
 		int			pagesegno;
-		int			curpartno;
+		int			curlockoffset;
 
-		curpartno = slotno / ctl->part_size;
+		curlockoffset = nslots + (slotno / ctl->part_size);
 
 		/*
 		 * If the curpartno is not same as prevpartno then release the lock on
 		 * the prevpartno and acquire the lock on the curpartno.
 		 */
-		if (curpartno != prevpartno)
+		if (curlockoffset != prevlockoffset)
 		{
-			LWLockRelease(&shared->part_locks[prevpartno].lock);
-			LWLockAcquire(&shared->part_locks[curpartno].lock, LW_EXCLUSIVE);
-			prevpartno = curpartno;
+			LWLockRelease(&shared->locks[prevlockoffset].lock);
+			LWLockAcquire(&shared->locks[curlockoffset].lock, LW_EXCLUSIVE);
+			prevlockoffset = curlockoffset;
 		}
 
 		pagesegno = shared->page_number[slotno] / SLRU_PAGES_PER_SEGMENT;
@@ -1474,7 +1478,7 @@ restart:
 
 	SlruInternalDeleteSegment(ctl, segno);
 
-	LWLockRelease(&shared->part_locks[prevpartno].lock);
+	LWLockRelease(&shared->locks[prevlockoffset].lock);
 }
 
 /*
@@ -1816,7 +1820,7 @@ SimpleLruGetPartitionLock(SlruCtl ctl, int pageno)
 {
 	int			partno = SlruMappingPartNo(ctl, pageno);
 
-	return &(ctl->shared->part_locks[partno].lock);
+	return &(ctl->shared->locks[ctl->shared->num_slots + partno].lock);
 }
 
 /*
@@ -1827,9 +1831,10 @@ SimpleLruLockAllPartitions(SlruCtl ctl, LWLockMode mode)
 {
 	SlruShared	shared = ctl->shared;
 	int			partno;
+	int			nslots = shared->num_slots;
 
 	for (partno = 0; partno < SLRU_NUM_PARTITIONS; partno++)
-		LWLockAcquire(&shared->part_locks[partno].lock, mode);
+		LWLockAcquire(&shared->locks[nslots + partno].lock, mode);
 }
 
 /*
@@ -1840,7 +1845,8 @@ SimpleLruUnLockAllPartitions(SlruCtl ctl)
 {
 	SlruShared	shared = ctl->shared;
 	int			partno;
+	int			nslots = shared->num_slots;
 
 	for (partno = 0; partno < SLRU_NUM_PARTITIONS; partno++)
-		LWLockRelease(&shared->part_locks[partno].lock);
+		LWLockRelease(&shared->locks[nslots + partno].lock);
 }
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index e6c54d5519..ac1227f29f 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -70,14 +70,14 @@ typedef struct SlruSharedData
 	bool	   *page_dirty;
 	int		   *page_number;
 	int		   *page_lru_count;
-	LWLockPadded *buffer_locks;
 
 	/*
-	 * Locks to protect the in memory buffer slot access in per SLRU bank. The
-	 * buffer_locks protects the I/O on each buffer slots whereas this lock
-	 * protect the in memory operation on the buffer within one SLRU bank.
+	 * This contains nslots numbers of buffers locks and nparts numbers of
+	 * part locks.  The buffer locks protects the I/O on each buffer slots
+	 * whereas the part lock protect the in memory operation on the buffer
+	 * within one SLRU part.
 	 */
-	LWLockPadded *part_locks;
+	LWLockPadded *locks;
 
 	/*----------
 	 * Instead of global counter we maintain a partition-wise lru counter
-- 
2.39.2 (Apple Git-143)