From 7d82b91e64689474b030137d8021c8bd7a5bfea9 Mon Sep 17 00:00:00 2001
From: Jakub Wartak <jakub.wartak@enterprisedb.com>
Date: Thu, 8 Jan 2026 14:34:53 +0100
Subject: [PATCH v3 4/4] Expose meaning of new per-wait wait_event_arg through
 pg_wait_events and docs

Add description of meaning to the core wait_event_names.txt as 4-th column.

Alter generate-wait_event_types.pl script so that it can generate proper
structure(s) that are used by SGML documentation and pg_wait_events view.

Author: Jakub Wartak <jakub.wartak@enterprisedb.com>
Reviewed-by:
Discussion: https://www.postgresql.org/message-id/flat/CAKZiRmyKcTaeSGzMYDN6aRR-BwYGPeZbzDRKvGkJhxAghfb4LQ%40mail.gmail.com
---
 .../activity/generate-wait_event_types.pl     | 29 ++++++++++-----
 src/backend/utils/activity/wait_event_funcs.c |  8 +++--
 .../utils/activity/wait_event_names.txt       | 36 +++++++++----------
 src/include/catalog/pg_proc.dat               |  4 +--
 src/test/regress/expected/rules.out           |  5 +--
 5 files changed, 50 insertions(+), 32 deletions(-)

diff --git a/src/backend/utils/activity/generate-wait_event_types.pl b/src/backend/utils/activity/generate-wait_event_types.pl
index 938ca47f86..067d0d7ba4 100644
--- a/src/backend/utils/activity/generate-wait_event_types.pl
+++ b/src/backend/utils/activity/generate-wait_event_types.pl
@@ -97,10 +97,11 @@ if ($gen_code)
 foreach my $line (@lines_sorted)
 {
 	die "unable to parse wait_event_names.txt for line $line\n"
-	  unless $line =~ /^(\w+)\t+(\w+)\t+("\w.*\.")$/;
+	  unless $line =~ /^(\w+)\t+(\w+)\t+("\w.*?")(?:\t+("\w.*"))?$/;
 
-	(my $waitclassname, my $waiteventname, my $waitevendocsentence) =
-	  ($1, $2, $3);
+	(my $waitclassname, my $waiteventname, my $waitevendocsentence, my $waiteventargdesc) =
+	  ($1, $2, $3, $4);
+	$waiteventargdesc = "" if !defined($waiteventargdesc);
 
 	# Generate the element name for the enums based on the
 	# description.  The C symbols are prefixed with "WAIT_EVENT_".
@@ -126,7 +127,7 @@ foreach my $line (@lines_sorted)
 
 	# Store the event into the list for each class.
 	my @waiteventlist =
-	  [ $waiteventenumname, $waiteventdescription, $waitevendocsentence ];
+	  [ $waiteventenumname, $waiteventdescription, $waitevendocsentence, $waiteventargdesc ];
 	push(@{ $hashwe{$waitclassname} }, @waiteventlist);
 }
 
@@ -257,8 +258,11 @@ if ($gen_code)
 		foreach my $wev (@{ $hashwe{$waitclass} })
 		{
 			my $new_desc = substr $wev->[2], 1, -2;
+			my $waiteventargdesc = $wev->[3];
+
 			# Escape single quotes.
 			$new_desc =~ s/'/\\'/g;
+			$waiteventargdesc =~ s/"//g;
 
 			# Replace the "quote" markups by real ones.
 			$new_desc =~ s/<quote>(.*?)<\/quote>/\\"$1\\"/g;
@@ -279,9 +283,9 @@ if ($gen_code)
 			$new_desc =~ s/; see.*$//;
 
 			# Build one element of the C structure holding the
-			# wait event info, as of (type, name, description).
-			printf $wc "\t{\"%s\", \"%s\", \"%s\"},\n", $last, $wev->[1],
-			  $new_desc;
+			# wait event info, as of (type, name, description, waiteventargdesc).
+			printf $wc "\t{\"%s\", \"%s\", \"%s\", \"%s\"},\n", $last, $wev->[1],
+			  $new_desc, $waiteventargdesc;
 		}
 	}
 
@@ -315,22 +319,31 @@ elsif ($gen_docs)
 		printf $s
 		  "   <title>Wait Events of Type <literal>%s</literal></title>\n",
 		  ucfirst($lastlc);
-		printf $s "   <tgroup cols=\"2\">\n";
+		printf $s "   <tgroup cols=\"3\">\n";
 		printf $s "    <thead>\n";
 		printf $s "     <row>\n";
 		printf $s
 		  "      <entry><literal>$last</literal> Wait Event</entry>\n";
 		printf $s "      <entry>Description</entry>\n";
+		printf $s "      <entry>wait_event_arg description (optional)</entry>\n";
 		printf $s "     </row>\n";
 		printf $s "    </thead>\n\n";
 		printf $s "    <tbody>\n";
 
 		foreach my $wev (@{ $hashwe{$waitclass} })
 		{
+			my $waiteventargdesc = $wev->[3];
+			if (defined($waiteventargdesc)) {
+				$waiteventargdesc =~ s/\"//g;
+			} else {
+				$waiteventargdesc = "";
+			}
+
 			printf $s "     <row>\n";
 			printf $s "      <entry><literal>%s</literal></entry>\n",
 			  $wev->[1];
 			printf $s "      <entry>%s</entry>\n", substr $wev->[2], 1, -1;
+			printf $s "      <entry>%s</entry>\n", $waiteventargdesc;
 			printf $s "     </row>\n";
 		}
 
diff --git a/src/backend/utils/activity/wait_event_funcs.c b/src/backend/utils/activity/wait_event_funcs.c
index b62ee83ef7..5d211bbf63 100644
--- a/src/backend/utils/activity/wait_event_funcs.c
+++ b/src/backend/utils/activity/wait_event_funcs.c
@@ -27,13 +27,14 @@ static const struct
 	const char *type;
 	const char *name;
 	const char *description;
+	const char *waiteventargdesc;
 }
 
 			waitEventData[] =
 {
 #include "wait_event_funcs_data.c"
 	/* end of list */
-	{NULL, NULL, NULL}
+	{NULL, NULL, NULL, NULL}
 };
 
 
@@ -45,7 +46,7 @@ static const struct
 Datum
 pg_get_wait_events(PG_FUNCTION_ARGS)
 {
-#define PG_GET_WAIT_EVENTS_COLS 3
+#define PG_GET_WAIT_EVENTS_COLS 4
 	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
 	char	  **waiteventnames;
 	int			nbwaitevents;
@@ -62,6 +63,7 @@ pg_get_wait_events(PG_FUNCTION_ARGS)
 		values[0] = CStringGetTextDatum(waitEventData[idx].type);
 		values[1] = CStringGetTextDatum(waitEventData[idx].name);
 		values[2] = CStringGetTextDatum(waitEventData[idx].description);
+		values[3] = CStringGetTextDatum(waitEventData[idx].waiteventargdesc);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
@@ -86,6 +88,7 @@ pg_get_wait_events(PG_FUNCTION_ARGS)
 						 waiteventnames[idx]);
 
 		values[2] = CStringGetTextDatum(buf.data);
+		nulls[3] = true;
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
@@ -110,6 +113,7 @@ pg_get_wait_events(PG_FUNCTION_ARGS)
 						 waiteventnames[idx]);
 
 		values[2] = CStringGetTextDatum(buf.data);
+		nulls[3] = true;
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
diff --git a/src/backend/utils/activity/wait_event_names.txt b/src/backend/utils/activity/wait_event_names.txt
index 3299de23bb..764f49b4ee 100644
--- a/src/backend/utils/activity/wait_event_names.txt
+++ b/src/backend/utils/activity/wait_event_names.txt
@@ -8,9 +8,9 @@
 # related to wait events.
 #
 # This file defines one wait event per line, with the following
-# tab-separated fields:
+# tab-separated fields (the wait_event_arg description is optional):
 #
-#   "Typedef enum definitions" "description in the docs"
+#   "Typedef enum definitions" "desc in the docs" "desc of the wait_event_arg""
 #
 # The files generated from this one are:
 #
@@ -150,15 +150,15 @@ PARALLEL_FINISH	"Waiting for parallel workers to finish computing."
 PROCARRAY_GROUP_UPDATE	"Waiting for the group leader to clear the transaction ID at transaction end."
 PROC_SIGNAL_BARRIER	"Waiting for a barrier event to be processed by all backends."
 PROMOTE	"Waiting for standby promotion."
-RECOVERY_CONFLICT_SNAPSHOT	"Waiting for recovery conflict resolution for a vacuum cleanup."
-RECOVERY_CONFLICT_TABLESPACE	"Waiting for recovery conflict resolution for dropping a tablespace."
+RECOVERY_CONFLICT_SNAPSHOT	"Waiting for recovery conflict resolution for a vacuum cleanup."	"relfilenode of the relation causing conflict."
+RECOVERY_CONFLICT_TABLESPACE	"Waiting for recovery conflict resolution for dropping a tablespace."	"tablespace Oid causing conflict."
 RECOVERY_END_COMMAND	"Waiting for <xref linkend="guc-recovery-end-command"/> to complete."
 RECOVERY_PAUSE	"Waiting for recovery to be resumed."
 REPLICATION_ORIGIN_DROP	"Waiting for a replication origin to become inactive so it can be dropped."
 REPLICATION_SLOT_DROP	"Waiting for a replication slot to become inactive so it can be dropped."
 RESTORE_COMMAND	"Waiting for <xref linkend="guc-restore-command"/> to complete."
 SAFE_SNAPSHOT	"Waiting to obtain a valid snapshot for a <literal>READ ONLY DEFERRABLE</literal> transaction."
-SYNC_REP	"Waiting for confirmation from a remote server during synchronous replication."
+SYNC_REP	"Waiting for confirmation from a remote server during synchronous replication."	"PID of the slowest walsender."
 WAL_RECEIVER_EXIT	"Waiting for the WAL receiver to exit."
 WAL_RECEIVER_WAIT_START	"Waiting for startup process to send initial data for streaming replication."
 WAL_SUMMARY_READY	"Waiting for a new WAL summary to be generated."
@@ -177,7 +177,7 @@ Section: ClassName - WaitEventTimeout
 BASE_BACKUP_THROTTLE	"Waiting during base backup when throttling activity."
 CHECKPOINT_WRITE_DELAY	"Waiting between writes while performing a checkpoint."
 COMMIT_DELAY	"Waiting for commit delay before WAL flush."
-PG_SLEEP	"Waiting due to a call to <function>pg_sleep</function> or a sibling function."
+PG_SLEEP	"Waiting due to a call to <function>pg_sleep</function> or a sibling function."	"how many seconds to sleep for."
 RECOVERY_APPLY_DELAY	"Waiting to apply WAL during recovery because of a delay setting."
 RECOVERY_RETRIEVE_RETRY_INTERVAL	"Waiting during recovery when WAL data is not available from any source (<filename>pg_wal</filename>, archive or stream)."
 REGISTER_SYNC_REQUEST	"Waiting while sending synchronization requests to the checkpointer, because the request queue is full."
@@ -213,14 +213,14 @@ CONTROL_FILE_WRITE_UPDATE	"Waiting for a write to update the <filename>pg_contro
 COPY_FILE_COPY	"Waiting for a file copy operation."
 COPY_FILE_READ	"Waiting for a read during a file copy operation."
 COPY_FILE_WRITE	"Waiting for a write during a file copy operation."
-DATA_FILE_EXTEND	"Waiting for a relation data file to be extended."
-DATA_FILE_FLUSH	"Waiting for a relation data file to reach durable storage."
-DATA_FILE_IMMEDIATE_SYNC	"Waiting for an immediate synchronization of a relation data file to durable storage."
-DATA_FILE_PREFETCH	"Waiting for an asynchronous prefetch from a relation data file."
-DATA_FILE_READ	"Waiting for a read from a relation data file."
-DATA_FILE_SYNC	"Waiting for changes to a relation data file to reach durable storage."
-DATA_FILE_TRUNCATE	"Waiting for a relation data file to be truncated."
-DATA_FILE_WRITE	"Waiting for a write to a relation data file."
+DATA_FILE_EXTEND	"Waiting for a relation data file to be extended."	"relfilenodeid of the relation."
+DATA_FILE_FLUSH	"Waiting for a relation data file to reach durable storage."	"relfilenodeid of the relation."
+DATA_FILE_IMMEDIATE_SYNC	"Waiting for an immediate synchronization of a relation data file to durable storage."	"relfilenodeid of the relation."
+DATA_FILE_PREFETCH	"Waiting for an asynchronous prefetch from a relation data file."	"relfilenodeid of the relation."
+DATA_FILE_READ	"Waiting for a read from a relation data file."	"relfilenodeid of the relation."
+DATA_FILE_SYNC	"Waiting for changes to a relation data file to reach durable storage."	"relfilenodeid of the relation."
+DATA_FILE_TRUNCATE	"Waiting for a relation data file to be truncated."	"relfilenodeid of the relation."
+DATA_FILE_WRITE	"Waiting for a write to a relation data file."	"relfilenodeid of the relation."
 DSM_ALLOCATE	"Waiting for a dynamic shared memory segment to be allocated."
 DSM_FILL_ZERO_WRITE	"Waiting to fill a dynamic shared memory backing file with zeroes."
 LOCK_FILE_ADDTODATADIR_READ	"Waiting for a read while adding a line to the data directory lock file."
@@ -246,10 +246,10 @@ REPLICATION_SLOT_READ	"Waiting for a read from a replication slot control file."
 REPLICATION_SLOT_RESTORE_SYNC	"Waiting for a replication slot control file to reach durable storage while restoring it to memory."
 REPLICATION_SLOT_SYNC	"Waiting for a replication slot control file to reach durable storage."
 REPLICATION_SLOT_WRITE	"Waiting for a write to a replication slot control file."
-SLRU_FLUSH_SYNC	"Waiting for SLRU data to reach durable storage during a checkpoint or database shutdown."
-SLRU_READ	"Waiting for a read of an SLRU page."
-SLRU_SYNC	"Waiting for SLRU data to reach durable storage following a page write."
-SLRU_WRITE	"Waiting for a write of an SLRU page."
+SLRU_FLUSH_SYNC	"Waiting for SLRU data to reach durable storage during a checkpoint or database shutdown."	"SlruType: unknown(0), notify(1), clog(2), subtrans(3), committs(4), multixactoffset (5), multixactmembers(6), serialializable(7)"
+SLRU_READ	"Waiting for a read of an SLRU page."	"SlruType: unknown(0), notify(1), clog(2), subtrans(3), committs(4), multixactoffset (5), multixactmembers(6), serialializable(7)"
+SLRU_SYNC	"Waiting for SLRU data to reach durable storage following a page write."	"SlruType: unknown(0), notify(1), clog(2), subtrans(3), committs(4), multixactoffset (5), multixactmembers(6), serialializable(7)"
+SLRU_WRITE	"Waiting for a write of an SLRU page."	"SlruType: unknown(0), notify(1), clog(2), subtrans(3), committs(4), multixactoffset (5), multixactmembers(6), serialializable(7)"
 SNAPBUILD_READ	"Waiting for a read of a serialized historical catalog snapshot."
 SNAPBUILD_SYNC	"Waiting for a serialized historical catalog snapshot to reach durable storage."
 SNAPBUILD_WRITE	"Waiting for a write of a serialized historical catalog snapshot."
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index b79322cabf..0943d169a5 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5669,8 +5669,8 @@
 { oid => '6318', descr => 'describe wait events',
   proname => 'pg_get_wait_events', procost => '10', prorows => '250',
   proretset => 't', provolatile => 'v', prorettype => 'record',
-  proargtypes => '', proallargtypes => '{text,text,text}',
-  proargmodes => '{o,o,o}', proargnames => '{type,name,description}',
+  proargtypes => '', proallargtypes => '{text,text,text,text}',
+  proargmodes => '{o,o,o,o}', proargnames => '{type,name,description,waiteventarg_description}',
   prosrc => 'pg_get_wait_events' },
 { oid => '3318',
   descr => 'statistics: information about progress of backends running maintenance command',
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 07351145ac..6f60afe5b3 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -2772,8 +2772,9 @@ pg_views| SELECT n.nspname AS schemaname,
   WHERE (c.relkind = 'v'::"char");
 pg_wait_events| SELECT type,
     name,
-    description
-   FROM pg_get_wait_events() pg_get_wait_events(type, name, description);
+    description,
+    waiteventarg_description
+   FROM pg_get_wait_events() pg_get_wait_events(type, name, description, waiteventarg_description);
 SELECT tablename, rulename, definition FROM pg_rules
 WHERE schemaname = 'pg_catalog'
 ORDER BY tablename, rulename;
-- 
2.43.0

