From 168603c7f9dc1852c2e5a927da3b7b31baf65eb2 Mon Sep 17 00:00:00 2001
From: Jakub Wartak <jakub.wartak@enterprisedb.com>
Date: Thu, 8 Jan 2026 12:18:03 +0100
Subject: [PATCH v3 3/4] wait_event_arg: implement SLRU type reporting for
 IO/Slru* wait events

pg_stat_activity.wait_event_arg now can be used to pinpoint exact SLRU type
in case of backends performing lots of SLRU I/O.

Author: Jakub Wartak <jakub.wartak@enterprisedb.com>
Reviewed-by:
Discussion: https://www.postgresql.org/message-id/flat/CAKZiRmyKcTaeSGzMYDN6aRR-BwYGPeZbzDRKvGkJhxAghfb4LQ%40mail.gmail.com
---
 src/backend/access/transam/clog.c      |  2 +-
 src/backend/access/transam/commit_ts.c | 11 ++++++-----
 src/backend/access/transam/multixact.c |  4 ++--
 src/backend/access/transam/slru.c      | 11 ++++++-----
 src/backend/access/transam/subtrans.c  |  7 ++++---
 src/backend/commands/async.c           |  7 ++++---
 src/backend/storage/lmgr/predicate.c   |  2 +-
 src/include/access/slru.h              | 17 ++++++++++++++++-
 src/test/modules/test_slru/test_slru.c |  2 +-
 9 files changed, 41 insertions(+), 22 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index b5c38bbb16..6a42ce239a 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -807,7 +807,7 @@ CLOGShmemInit(void)
 	Assert(transaction_buffers != 0);
 
 	XactCtl->PagePrecedes = CLOGPagePrecedes;
-	SimpleLruInit(XactCtl, "transaction", CLOGShmemBuffers(), CLOG_LSNS_PER_PAGE,
+	SimpleLruInit(XactCtl, SLRU_TYPE_CLOG, "transaction", CLOGShmemBuffers(), CLOG_LSNS_PER_PAGE,
 				  "pg_xact", LWTRANCHE_XACT_BUFFER,
 				  LWTRANCHE_XACT_SLRU, SYNC_HANDLER_CLOG, false);
 	SlruPagePrecedesUnitTests(XactCtl, CLOG_XACTS_PER_PAGE);
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 082b564da8..8fedf839a7 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -551,11 +551,12 @@ CommitTsShmemInit(void)
 	Assert(commit_timestamp_buffers != 0);
 
 	CommitTsCtl->PagePrecedes = CommitTsPagePrecedes;
-	SimpleLruInit(CommitTsCtl, "commit_timestamp", CommitTsShmemBuffers(), 0,
-				  "pg_commit_ts", LWTRANCHE_COMMITTS_BUFFER,
-				  LWTRANCHE_COMMITTS_SLRU,
-				  SYNC_HANDLER_COMMIT_TS,
-				  false);
+	SimpleLruInit(CommitTsCtl, SLRU_TYPE_COMMIT_TS,
+			   "commit_timestamp", CommitTsShmemBuffers(), 0,
+			   "pg_commit_ts", LWTRANCHE_COMMITTS_BUFFER,
+			   LWTRANCHE_COMMITTS_SLRU,
+			   SYNC_HANDLER_COMMIT_TS,
+			   false);
 	SlruPagePrecedesUnitTests(CommitTsCtl, COMMIT_TS_XACTS_PER_PAGE);
 
 	commitTsShared = ShmemInitStruct("CommitTs shared",
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index b2a04e34b2..85ad857bf0 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1738,14 +1738,14 @@ MultiXactShmemInit(void)
 	MultiXactOffsetCtl->PagePrecedes = MultiXactOffsetPagePrecedes;
 	MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
 
-	SimpleLruInit(MultiXactOffsetCtl,
+	SimpleLruInit(MultiXactOffsetCtl, SLRU_TYPE_MULTIXACT_OFFSET,
 				  "multixact_offset", multixact_offset_buffers, 0,
 				  "pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER,
 				  LWTRANCHE_MULTIXACTOFFSET_SLRU,
 				  SYNC_HANDLER_MULTIXACT_OFFSET,
 				  false);
 	SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE);
-	SimpleLruInit(MultiXactMemberCtl,
+	SimpleLruInit(MultiXactMemberCtl, SLRU_TYPE_MULTIXACT_MEMBER,
 				  "multixact_member", multixact_member_buffers, 0,
 				  "pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER,
 				  LWTRANCHE_MULTIXACTMEMBER_SLRU,
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 549c7e3e64..434c07e031 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -249,7 +249,7 @@ SimpleLruAutotuneBuffers(int divisor, int max)
  * long_segment_names: use short or long segment names
  */
 void
-SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
+SimpleLruInit(SlruCtl ctl, SlruType type, const char *name, int nslots, int nlsns,
 			  const char *subdir, int buffer_tranche_id, int bank_tranche_id,
 			  SyncRequestHandler sync_handler, bool long_segment_names)
 {
@@ -345,6 +345,7 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
 	ctl->long_segment_names = long_segment_names;
 	ctl->nbanks = nbanks;
 	strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
+	ctl->type = type;
 }
 
 /*
@@ -862,7 +863,7 @@ SlruPhysicalReadPage(SlruCtl ctl, int64 pageno, int slotno)
 	}
 
 	errno = 0;
-	pgstat_report_wait_start(WAIT_EVENT_SLRU_READ);
+	pgstat_report_wait_start(WAIT_EVENT_SLRU_READ | ctl->type);
 	if (pg_pread(fd, shared->page_buffer[slotno], BLCKSZ, offset) != BLCKSZ)
 	{
 		pgstat_report_wait_end();
@@ -1014,7 +1015,7 @@ SlruPhysicalWritePage(SlruCtl ctl, int64 pageno, int slotno, SlruWriteAll fdata)
 	}
 
 	errno = 0;
-	pgstat_report_wait_start(WAIT_EVENT_SLRU_WRITE);
+	pgstat_report_wait_start(WAIT_EVENT_SLRU_WRITE | ctl->type);
 	if (pg_pwrite(fd, shared->page_buffer[slotno], BLCKSZ, offset) != BLCKSZ)
 	{
 		pgstat_report_wait_end();
@@ -1038,7 +1039,7 @@ SlruPhysicalWritePage(SlruCtl ctl, int64 pageno, int slotno, SlruWriteAll fdata)
 		if (!RegisterSyncRequest(&tag, SYNC_REQUEST, false))
 		{
 			/* No space to enqueue sync request.  Do it synchronously. */
-			pgstat_report_wait_start(WAIT_EVENT_SLRU_SYNC);
+			pgstat_report_wait_start(WAIT_EVENT_SLRU_SYNC | ctl->type);
 			if (pg_fsync(fd) != 0)
 			{
 				pgstat_report_wait_end();
@@ -1865,7 +1866,7 @@ SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
 	if (fd < 0)
 		return -1;
 
-	pgstat_report_wait_start(WAIT_EVENT_SLRU_FLUSH_SYNC);
+	pgstat_report_wait_start(WAIT_EVENT_SLRU_FLUSH_SYNC | ctl->type);
 	result = pg_fsync(fd);
 	pgstat_report_wait_end();
 	save_errno = errno;
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index c0987f43f1..bc50e3e7ab 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -240,9 +240,10 @@ SUBTRANSShmemInit(void)
 	Assert(subtransaction_buffers != 0);
 
 	SubTransCtl->PagePrecedes = SubTransPagePrecedes;
-	SimpleLruInit(SubTransCtl, "subtransaction", SUBTRANSShmemBuffers(), 0,
-				  "pg_subtrans", LWTRANCHE_SUBTRANS_BUFFER,
-				  LWTRANCHE_SUBTRANS_SLRU, SYNC_HANDLER_NONE, false);
+	SimpleLruInit(SubTransCtl, SLRU_TYPE_SUBTRANS, 
+			   "subtransaction", SUBTRANSShmemBuffers(), 0,
+			   "pg_subtrans", LWTRANCHE_SUBTRANS_BUFFER,
+			   LWTRANCHE_SUBTRANS_SLRU, SYNC_HANDLER_NONE, false);
 	SlruPagePrecedesUnitTests(SubTransCtl, SUBTRANS_XACTS_PER_PAGE);
 }
 
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 40c42f572e..1c2d07af18 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -534,9 +534,10 @@ AsyncShmemInit(void)
 	 * names are used in order to avoid wraparound.
 	 */
 	NotifyCtl->PagePrecedes = asyncQueuePagePrecedes;
-	SimpleLruInit(NotifyCtl, "notify", notify_buffers, 0,
-				  "pg_notify", LWTRANCHE_NOTIFY_BUFFER, LWTRANCHE_NOTIFY_SLRU,
-				  SYNC_HANDLER_NONE, true);
+	SimpleLruInit(NotifyCtl, SLRU_TYPE_NOTIFY, "notify", 
+			   notify_buffers, 0,
+			   "pg_notify", LWTRANCHE_NOTIFY_BUFFER, LWTRANCHE_NOTIFY_SLRU,
+			   SYNC_HANDLER_NONE, true);
 
 	if (!found)
 	{
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index fe75ead350..11cc9cf6ac 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -811,7 +811,7 @@ SerialInit(void)
 	 * Set up SLRU management of the pg_serial data.
 	 */
 	SerialSlruCtl->PagePrecedes = SerialPagePrecedesLogically;
-	SimpleLruInit(SerialSlruCtl, "serializable",
+	SimpleLruInit(SerialSlruCtl, SLRU_TYPE_SERIAL, "serializable",
 				  serializable_buffers, 0, "pg_serial",
 				  LWTRANCHE_SERIAL_BUFFER, LWTRANCHE_SERIAL_SLRU,
 				  SYNC_HANDLER_NONE, false);
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index 4cb8f478fc..a94df291bf 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -37,6 +37,18 @@ typedef enum
 	SLRU_PAGE_WRITE_IN_PROGRESS,	/* page is being written out */
 } SlruPageStatus;
 
+/* Used only for pg_stat_activity.wait_event_arg for Slru* wait events */
+typedef enum {
+	SLRU_TYPE_UNKNOWN,
+	SLRU_TYPE_NOTIFY,
+	SLRU_TYPE_CLOG,
+	SLRU_TYPE_SUBTRANS,
+	SLRU_TYPE_COMMIT_TS,
+	SLRU_TYPE_MULTIXACT_OFFSET,
+	SLRU_TYPE_MULTIXACT_MEMBER,
+	SLRU_TYPE_SERIAL
+} SlruType;
+
 /*
  * Shared-memory state
  *
@@ -113,6 +125,9 @@ typedef struct SlruCtlData
 {
 	SlruShared	shared;
 
+	/* Type of SLRU that is later passed pgstat_report_wait_start() */
+	SlruType 	type;
+
 	/* Number of banks in this SLRU. */
 	uint16		nbanks;
 
@@ -167,7 +182,7 @@ SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
 
 extern Size SimpleLruShmemSize(int nslots, int nlsns);
 extern int	SimpleLruAutotuneBuffers(int divisor, int max);
-extern void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
+extern void SimpleLruInit(SlruCtl ctl, SlruType type, const char *name, int nslots, int nlsns,
 						  const char *subdir, int buffer_tranche_id,
 						  int bank_tranche_id, SyncRequestHandler sync_handler,
 						  bool long_segment_names);
diff --git a/src/test/modules/test_slru/test_slru.c b/src/test/modules/test_slru/test_slru.c
index 4dc74e1962..c817629fa2 100644
--- a/src/test/modules/test_slru/test_slru.c
+++ b/src/test/modules/test_slru/test_slru.c
@@ -245,7 +245,7 @@ test_slru_shmem_startup(void)
 	}
 
 	TestSlruCtl->PagePrecedes = test_slru_page_precedes_logically;
-	SimpleLruInit(TestSlruCtl, "TestSLRU",
+	SimpleLruInit(TestSlruCtl, SLRU_TYPE_UNKNOWN, "TestSLRU",
 				  NUM_TEST_BUFFERS, 0, slru_dir_name,
 				  test_buffer_tranche_id, test_tranche_id, SYNC_HANDLER_NONE,
 				  long_segment_names);
-- 
2.43.0

