From a249feb0e7654865f53f3853c310a5cec58e185e Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Date: Wed, 20 Aug 2025 10:55:27 +0530
Subject: [PATCH 10/19] WIP: Monitoring views

Modifies pg_shmem_allocations to report shared memory segment as well.

Adds pg_shmem_segments to report shared memory segment information.

TODO:
This commit should be merged with the earlier commit introducing
multiple shared memory segments.

Author: Ashutosh Bapat
---
 doc/src/sgml/system-views.sgml       |  9 +++
 src/backend/catalog/system_views.sql |  7 +++
 src/backend/storage/ipc/shmem.c      | 90 ++++++++++++++++++++++------
 src/include/catalog/pg_proc.dat      | 12 +++-
 src/include/storage/pg_shmem.h       |  1 -
 src/include/storage/shmem.h          |  1 +
 src/test/regress/expected/rules.out  | 10 +++-
 7 files changed, 108 insertions(+), 22 deletions(-)

diff --git a/doc/src/sgml/system-views.sgml b/doc/src/sgml/system-views.sgml
index 8f3e2741051..bc70a3ee6c9 100644
--- a/doc/src/sgml/system-views.sgml
+++ b/doc/src/sgml/system-views.sgml
@@ -4233,6 +4233,15 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
       </para></entry>
      </row>
 
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>segment</structfield> <type>text</type>
+      </para>
+      <para>
+       The name of the shared memory segment concerning the allocation. 
+      </para></entry>
+     </row>
+
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
        <structfield>off</structfield> <type>int8</type>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index c7240250c07..94a2b5a9a67 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -668,6 +668,13 @@ GRANT SELECT ON pg_shmem_allocations TO pg_read_all_stats;
 REVOKE EXECUTE ON FUNCTION pg_get_shmem_allocations() FROM PUBLIC;
 GRANT EXECUTE ON FUNCTION pg_get_shmem_allocations() TO pg_read_all_stats;
 
+CREATE VIEW pg_shmem_segments AS
+    SELECT * FROM pg_get_shmem_segments();
+
+REVOKE ALL ON pg_shmem_segments FROM PUBLIC;
+GRANT SELECT ON pg_shmem_segments TO pg_read_all_stats;
+REVOKE EXECUTE ON FUNCTION pg_get_shmem_segments() FROM PUBLIC;
+GRANT EXECUTE ON FUNCTION pg_get_shmem_segments() TO pg_read_all_stats;
 CREATE VIEW pg_shmem_allocations_numa AS
     SELECT * FROM pg_get_shmem_allocations_numa();
 
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index 90c21a97225..9499f332e77 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -531,6 +531,7 @@ ShmemInitStructInSegment(const char *name, Size size, bool *foundPtr,
 		result->size = size;
 		result->allocated_size = allocated_size;
 		result->location = structPtr;
+		result->shmem_segment = shmem_segment;
 	}
 
 	LWLockRelease(ShmemIndexLock);
@@ -582,13 +583,14 @@ mul_size(Size s1, Size s2)
 Datum
 pg_get_shmem_allocations(PG_FUNCTION_ARGS)
 {
-#define PG_GET_SHMEM_SIZES_COLS 4
+#define PG_GET_SHMEM_SIZES_COLS 5
 	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
 	HASH_SEQ_STATUS hstat;
 	ShmemIndexEnt *ent;
-	Size		named_allocated = 0;
+	Size		named_allocated[ANON_MAPPINGS] = {0};
 	Datum		values[PG_GET_SHMEM_SIZES_COLS];
 	bool		nulls[PG_GET_SHMEM_SIZES_COLS];
+	int			i;
 
 	InitMaterializedSRF(fcinfo, 0);
 
@@ -598,33 +600,42 @@ pg_get_shmem_allocations(PG_FUNCTION_ARGS)
 
 	/* output all allocated entries */
 	memset(nulls, 0, sizeof(nulls));
-	/* XXX: take all shared memory segments into account. */
 	while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL)
 	{
 		values[0] = CStringGetTextDatum(ent->key);
-		values[1] = Int64GetDatum((char *) ent->location - (char *) Segments[MAIN_SHMEM_SEGMENT].ShmemSegHdr);
-		values[2] = Int64GetDatum(ent->size);
-		values[3] = Int64GetDatum(ent->allocated_size);
-		named_allocated += ent->allocated_size;
+		values[1] = CStringGetTextDatum(MappingName(ent->shmem_segment));
+		values[2] = Int64GetDatum((char *) ent->location - (char *) Segments[ent->shmem_segment].ShmemSegHdr);
+		values[3] = Int64GetDatum(ent->size);
+		values[4] = Int64GetDatum(ent->allocated_size);
+		named_allocated[ent->shmem_segment] += ent->allocated_size;
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
 							 values, nulls);
 	}
 
 	/* output shared memory allocated but not counted via the shmem index */
-	values[0] = CStringGetTextDatum("<anonymous>");
-	nulls[1] = true;
-	values[2] = Int64GetDatum(Segments[MAIN_SHMEM_SEGMENT].ShmemSegHdr->freeoffset - named_allocated);
-	values[3] = values[2];
-	tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
+	for (i = 0; i < ANON_MAPPINGS; i++)
+	{
+		values[0] = CStringGetTextDatum("<anonymous>");
+		values[1] = CStringGetTextDatum(MappingName(i));
+		nulls[2] = true;
+		values[3] = Int64GetDatum(Segments[i].ShmemSegHdr->freeoffset - named_allocated[i]);
+		values[4] = values[3];
+		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
+	}
 
 	/* output as-of-yet unused shared memory */
-	nulls[0] = true;
-	values[1] = Int64GetDatum(Segments[MAIN_SHMEM_SEGMENT].ShmemSegHdr->freeoffset);
-	nulls[1] = false;
-	values[2] = Int64GetDatum(Segments[MAIN_SHMEM_SEGMENT].ShmemSegHdr->totalsize - Segments[MAIN_SHMEM_SEGMENT].ShmemSegHdr->freeoffset);
-	values[3] = values[2];
-	tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
+	memset(nulls, 0, sizeof(nulls));
+
+	for (i = 0; i < ANON_MAPPINGS; i++)
+	{
+		nulls[0] = true;
+		values[1] = CStringGetTextDatum(MappingName(i));
+		values[2] = Int64GetDatum(Segments[i].ShmemSegHdr->freeoffset);
+		values[3] = Int64GetDatum(Segments[i].ShmemSegHdr->totalsize - Segments[i].ShmemSegHdr->freeoffset);
+		values[4] = values[3];
+		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
+	}
 
 	LWLockRelease(ShmemIndexLock);
 
@@ -825,3 +836,46 @@ pg_numa_available(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_BOOL(pg_numa_init() != -1);
 }
+
+/* SQL SRF showing shared memory segments */
+Datum
+pg_get_shmem_segments(PG_FUNCTION_ARGS)
+{
+#define PG_GET_SHMEM_SEGS_COLS 6
+	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+	Datum		values[PG_GET_SHMEM_SEGS_COLS];
+	bool		nulls[PG_GET_SHMEM_SEGS_COLS];
+	int i;
+
+	InitMaterializedSRF(fcinfo, 0);
+
+	/* output all allocated entries */
+	for (i = 0; i < ANON_MAPPINGS; i++)
+	{
+		PGShmemHeader *shmhdr = Segments[i].ShmemSegHdr;
+		AnonymousMapping *segmapping = &Mappings[i];
+		int j;
+
+		if (shmhdr == NULL)
+		{
+			for (j = 0; j < PG_GET_SHMEM_SEGS_COLS; j++)
+				nulls[j] = true;
+		}
+		else
+		{
+			memset(nulls, 0, sizeof(nulls));
+			values[0] = Int32GetDatum(i);
+			values[1] = CStringGetTextDatum(MappingName(i));
+			values[2] = Int64GetDatum(shmhdr->totalsize);
+			values[3] = Int64GetDatum(shmhdr->freeoffset);
+			values[4] = Int64GetDatum(segmapping->shmem_size);
+			values[5] = Int64GetDatum(segmapping->shmem_reserved);
+		}
+
+		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
+							 values, nulls);
+	}
+
+	return (Datum) 0;
+}
+
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index e631323a325..8f1d0b7c031 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -8576,8 +8576,8 @@
 { oid => '5052', descr => 'allocations from the main shared memory segment',
   proname => 'pg_get_shmem_allocations', prorows => '50', proretset => 't',
   provolatile => 'v', prorettype => 'record', proargtypes => '',
-  proallargtypes => '{text,int8,int8,int8}', proargmodes => '{o,o,o,o}',
-  proargnames => '{name,off,size,allocated_size}',
+  proallargtypes => '{text,text,int8,int8,int8}', proargmodes => '{o,o,o,o,o}',
+  proargnames => '{name,segment,off,size,allocated_size}',
   prosrc => 'pg_get_shmem_allocations' },
 
 { oid => '4099', descr => 'Is NUMA support available?',
@@ -8600,6 +8600,14 @@
   proargmodes => '{o,o,o}', proargnames => '{name,type,size}',
   prosrc => 'pg_get_dsm_registry_allocations' },
 
+# shared memory segments 
+{ oid => '5101', descr => 'shared memory segments',
+  proname => 'pg_get_shmem_segments', prorows => '6', proretset => 't',
+  provolatile => 'v', prorettype => 'record', proargtypes => '',
+  proallargtypes => '{int4,text,int8,int8,int8,int8}', proargmodes => '{o,o,o,o,o,o}',
+  proargnames => '{id,name,size,freeoffset,mapping_size,mapping_reserved_size}',
+  prosrc => 'pg_get_shmem_segments' },
+
 # buffer lookup table
 { oid => '5102',
   descr => 'shared buffer lookup table',
diff --git a/src/include/storage/pg_shmem.h b/src/include/storage/pg_shmem.h
index a1fa6b43fe3..715f6acb5dd 100644
--- a/src/include/storage/pg_shmem.h
+++ b/src/include/storage/pg_shmem.h
@@ -69,7 +69,6 @@ typedef struct ShmemSegment
 extern PGDLLIMPORT ShmemSegment Segments[ANON_MAPPINGS];
 extern PGDLLIMPORT AnonymousMapping Mappings[ANON_MAPPINGS];
 
-
 /* GUC variables */
 extern PGDLLIMPORT int shared_memory_type;
 extern PGDLLIMPORT int huge_pages;
diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h
index 910c43f54f4..64ff5a286ba 100644
--- a/src/include/storage/shmem.h
+++ b/src/include/storage/shmem.h
@@ -71,6 +71,7 @@ typedef struct
 	void	   *location;		/* location in shared mem */
 	Size		size;			/* # bytes requested for the structure */
 	Size		allocated_size; /* # bytes actually allocated */
+	int			shmem_segment;	/* segment in which the structure is allocated */
 } ShmemIndexEnt;
 
 #endif							/* SHMEM_H */
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 83f566d3218..60c08081b69 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1772,14 +1772,22 @@ pg_shadow| SELECT pg_authid.rolname AS usename,
      LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid))))
   WHERE pg_authid.rolcanlogin;
 pg_shmem_allocations| SELECT name,
+    segment,
     off,
     size,
     allocated_size
-   FROM pg_get_shmem_allocations() pg_get_shmem_allocations(name, off, size, allocated_size);
+   FROM pg_get_shmem_allocations() pg_get_shmem_allocations(name, segment, off, size, allocated_size);
 pg_shmem_allocations_numa| SELECT name,
     numa_node,
     size
    FROM pg_get_shmem_allocations_numa() pg_get_shmem_allocations_numa(name, numa_node, size);
+pg_shmem_segments| SELECT id,
+    name,
+    size,
+    freeoffset,
+    mapping_size,
+    mapping_reserved_size
+   FROM pg_get_shmem_segments() pg_get_shmem_segments(id, name, size, freeoffset, mapping_size, mapping_reserved_size);
 pg_stat_activity| SELECT s.datid,
     d.datname,
     s.pid,
-- 
2.34.1

