]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Introduce pg_dsm_registry_allocations view.
authorNathan Bossart <nathan@postgresql.org>
Wed, 9 Jul 2025 14:17:56 +0000 (09:17 -0500)
committerNathan Bossart <nathan@postgresql.org>
Wed, 9 Jul 2025 14:17:56 +0000 (09:17 -0500)
This commit adds a new system view that provides information about
entries in the dynamic shared memory (DSM) registry.  Specifically,
it returns the name, type, and size of each entry.  Note that since
we cannot discover the size of dynamic shared memory areas (DSAs)
and hash tables backed by DSAs (dshashes) without first attaching
to them, the size column is left as NULL for those.

Bumps catversion.

Author: Florents Tselai <florents.tselai@gmail.com>
Reviewed-by: Sungwoo Chang <swchangdev@gmail.com>
Discussion: https://postgr.es/m/4D445D3E-81C5-4135-95BB-D414204A0AB4%40gmail.com

doc/src/sgml/system-views.sgml
src/backend/catalog/system_views.sql
src/backend/storage/ipc/dsm_registry.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.dat
src/test/modules/test_dsm_registry/expected/test_dsm_registry.out
src/test/modules/test_dsm_registry/sql/test_dsm_registry.sql
src/test/regress/expected/privileges.out
src/test/regress/expected/rules.out
src/test/regress/sql/privileges.sql

index e1ac544ee4079de5e721d59e8a423b5873314cc4..d3ff8c35738573cc493ceb828c17a4717c7dce23 100644 (file)
       <entry>open cursors</entry>
      </row>
 
+     <row>
+      <entry><link linkend="view-pg-dsm-registry-allocations"><structname>pg_dsm_registry_allocations</structname></link></entry>
+      <entry>shared memory allocations tracked in the DSM registry</entry>
+     </row>
+
      <row>
       <entry><link linkend="view-pg-file-settings"><structname>pg_file_settings</structname></link></entry>
       <entry>summary of configuration file contents</entry>
@@ -1086,6 +1091,75 @@ AND c1.path[c2.level] = c2.path[c2.level];
 
  </sect1>
 
+ <sect1 id="view-pg-dsm-registry-allocations">
+  <title><structname>pg_dsm_registry_allocations</structname></title>
+
+  <indexterm zone="view-pg-dsm-registry-allocations">
+   <primary>pg_dsm_registry_allocations</primary>
+  </indexterm>
+
+  <para>
+   The <structname>pg_dsm_registry_allocations</structname> view shows shared
+   memory allocations tracked in the dynamic shared memory (DSM) registry.
+   This includes memory allocated by extensions using the mechanisms detailed
+   in <xref linkend="xfunc-shared-addin-after-startup" />.
+  </para>
+
+  <table>
+   <title><structname>pg_dsm_registry_allocations</structname> Columns</title>
+   <tgroup cols="1">
+    <thead>
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       Column Type
+      </para>
+      <para>
+       Description
+      </para></entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>name</structfield> <type>text</type>
+      </para>
+      <para>
+       The name of the allocation in the DSM registry.
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>type</structfield> <type>text</type>
+      </para>
+      <para>
+       The type of allocation.  Possible values are <literal>segment</literal>,
+       <literal>area</literal>, and <literal>hash</literal>, which correspond
+       to dynamic shared memory segments, areas, and hash tables, respectively.
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>size</structfield> <type>int8</type>
+      </para>
+      <para>
+       Size of the allocation in bytes.  NULL for entries of type
+       <literal>area</literal> and <literal>hash</literal>.
+      </para></entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+  <para>
+   By default, the <structname>pg_dsm_registry_allocations</structname> view
+   can be read only by superusers or roles with privileges of the
+   <literal>pg_read_all_stats</literal> role.
+  </para>
+ </sect1>
+
  <sect1 id="view-pg-file-settings">
   <title><structname>pg_file_settings</structname></title>
 
index e5dbbe61b811ab18dfea0102e66ad64c13936b61..b2d5332effc1b513c73739c5adc80a9ea1078214 100644 (file)
@@ -666,6 +666,14 @@ GRANT SELECT ON pg_shmem_allocations_numa TO pg_read_all_stats;
 REVOKE EXECUTE ON FUNCTION pg_get_shmem_allocations_numa() FROM PUBLIC;
 GRANT EXECUTE ON FUNCTION pg_get_shmem_allocations_numa() TO pg_read_all_stats;
 
+CREATE VIEW pg_dsm_registry_allocations AS
+    SELECT * FROM pg_get_dsm_registry_allocations();
+
+REVOKE ALL ON pg_dsm_registry_allocations FROM PUBLIC;
+GRANT SELECT ON pg_dsm_registry_allocations TO pg_read_all_stats;
+REVOKE EXECUTE ON FUNCTION pg_get_dsm_registry_allocations() FROM PUBLIC;
+GRANT EXECUTE ON FUNCTION pg_get_dsm_registry_allocations() TO pg_read_all_stats;
+
 CREATE VIEW pg_backend_memory_contexts AS
     SELECT * FROM pg_get_backend_memory_contexts();
 
index 828c2ff0c7f5e111a1f339c45717f50ce85d413f..1682cc6d34c7fbe6f9b36643797be05ee6ce1773 100644 (file)
 
 #include "postgres.h"
 
+#include "funcapi.h"
 #include "lib/dshash.h"
 #include "storage/dsm_registry.h"
 #include "storage/lwlock.h"
 #include "storage/shmem.h"
+#include "utils/builtins.h"
 #include "utils/memutils.h"
 
 #define DSMR_NAME_LEN                          128
@@ -88,6 +90,13 @@ typedef enum DSMREntryType
        DSMR_ENTRY_TYPE_DSH,
 } DSMREntryType;
 
+static const char *const DSMREntryTypeNames[] =
+{
+       [DSMR_ENTRY_TYPE_DSM] = "segment",
+       [DSMR_ENTRY_TYPE_DSA] = "area",
+       [DSMR_ENTRY_TYPE_DSH] = "hash",
+};
+
 typedef struct DSMRegistryEntry
 {
        char            name[DSMR_NAME_LEN];
@@ -435,3 +444,43 @@ GetNamedDSHash(const char *name, const dshash_parameters *params, bool *found)
 
        return ret;
 }
+
+Datum
+pg_get_dsm_registry_allocations(PG_FUNCTION_ARGS)
+{
+       ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+       DSMRegistryEntry *entry;
+       MemoryContext oldcontext;
+       dshash_seq_status status;
+
+       InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC);
+
+       /* Be sure any local memory allocated by DSM/DSA routines is persistent. */
+       oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+       init_dsm_registry();
+       MemoryContextSwitchTo(oldcontext);
+
+       dshash_seq_init(&status, dsm_registry_table, false);
+       while ((entry = dshash_seq_next(&status)) != NULL)
+       {
+               Datum           vals[3];
+               bool            nulls[3] = {0};
+
+               vals[0] = CStringGetTextDatum(entry->name);
+               vals[1] = CStringGetTextDatum(DSMREntryTypeNames[entry->type]);
+
+               /*
+                * Since we can't know the size of DSA/dshash entries without first
+                * attaching to them, return NULL for those.
+                */
+               if (entry->type == DSMR_ENTRY_TYPE_DSM)
+                       vals[2] = Int64GetDatum(entry->data.dsm.size);
+               else
+                       nulls[2] = true;
+
+               tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, vals, nulls);
+       }
+       dshash_seq_term(&status);
+
+       return (Datum) 0;
+}
index ff9ffd9d474988283d47b6f78b24b46619c3996b..a3f3315fed99747cf4d8d85c8edc2492769aeb5a 100644 (file)
@@ -57,6 +57,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     202506301
+#define CATALOG_VERSION_NO     202507091
 
 #endif
index d4650947c63a58aadc9f2bbba605b4472ee36319..1fc19146f46740db5fb26b4ffd1780e03d079def 100644 (file)
   proargnames => '{name,numa_node,size}',
   prosrc => 'pg_get_shmem_allocations_numa' },
 
+{ oid => '9314',
+  descr => 'shared memory allocations tracked in the DSM registry',
+  proname => 'pg_get_dsm_registry_allocations', prorows => '50',
+  proretset => 't', provolatile => 'v', prorettype => 'record',
+  proargtypes => '', proallargtypes => '{text,text,int8}',
+  proargmodes => '{o,o,o}', proargnames => '{name,type,size}',
+  prosrc => 'pg_get_dsm_registry_allocations' },
+
 # memory context of local backend
 { oid => '2282',
   descr => 'information about all memory contexts of local backend',
index 8ded82e59d6f4b349c34dab99e1f47357708f722..ca8abbb377e6b67e4263056302ebafd58ba42da4 100644 (file)
@@ -1,3 +1,10 @@
+SELECT name, type, size IS DISTINCT FROM 0 AS size
+FROM pg_dsm_registry_allocations
+WHERE name like 'test_dsm_registry%' ORDER BY name;
+ name | type | size 
+------+------+------
+(0 rows)
+
 CREATE EXTENSION test_dsm_registry;
 SELECT set_val_in_shmem(1236);
  set_val_in_shmem 
@@ -24,3 +31,14 @@ SELECT get_val_in_hash('test');
  1414
 (1 row)
 
+\c
+SELECT name, type, size IS DISTINCT FROM 0 AS size
+FROM pg_dsm_registry_allocations
+WHERE name like 'test_dsm_registry%' ORDER BY name;
+          name          |  type   | size 
+------------------------+---------+------
+ test_dsm_registry_dsa  | area    | t
+ test_dsm_registry_dsm  | segment | t
+ test_dsm_registry_hash | hash    | t
+(3 rows)
+
index c2e25cddaae1d3343911626c33553d5c0f119ade..965a3f1ebb63aa88a7ec17bc0030b7047a0a92e2 100644 (file)
@@ -1,6 +1,13 @@
+SELECT name, type, size IS DISTINCT FROM 0 AS size
+FROM pg_dsm_registry_allocations
+WHERE name like 'test_dsm_registry%' ORDER BY name;
 CREATE EXTENSION test_dsm_registry;
 SELECT set_val_in_shmem(1236);
 SELECT set_val_in_hash('test', '1414');
 \c
 SELECT get_val_in_shmem();
 SELECT get_val_in_hash('test');
+\c
+SELECT name, type, size IS DISTINCT FROM 0 AS size
+FROM pg_dsm_registry_allocations
+WHERE name like 'test_dsm_registry%' ORDER BY name;
index c25062c288f32351b94db98f5066880d817b9c46..aadc328589d2cd45031989f33b496af5685d9163 100644 (file)
@@ -3220,7 +3220,8 @@ REVOKE MAINTAIN ON lock_table FROM regress_locktable_user;
 DROP TABLE lock_table;
 DROP USER regress_locktable_user;
 -- test to check privileges of system views pg_shmem_allocations,
--- pg_shmem_allocations_numa and pg_backend_memory_contexts.
+-- pg_shmem_allocations_numa, pg_dsm_registry_allocations, and
+-- pg_backend_memory_contexts.
 -- switch to superuser
 \c -
 CREATE ROLE regress_readallstats;
@@ -3248,6 +3249,12 @@ SELECT has_table_privilege('regress_readallstats','pg_shmem_allocations_numa','S
  f
 (1 row)
 
+SELECT has_table_privilege('regress_readallstats','pg_dsm_registry_allocations','SELECT'); -- no
+ has_table_privilege 
+---------------------
+ f
+(1 row)
+
 GRANT pg_read_all_stats TO regress_readallstats;
 SELECT has_table_privilege('regress_readallstats','pg_aios','SELECT'); -- yes
  has_table_privilege 
@@ -3273,6 +3280,12 @@ SELECT has_table_privilege('regress_readallstats','pg_shmem_allocations_numa','S
  t
 (1 row)
 
+SELECT has_table_privilege('regress_readallstats','pg_dsm_registry_allocations','SELECT'); -- yes
+ has_table_privilege 
+---------------------
+ t
+(1 row)
+
 -- run query to ensure that functions within views can be executed
 SET ROLE regress_readallstats;
 SELECT COUNT(*) >= 0 AS ok FROM pg_aios;
index 6cf828ca8d0dc4c82273f81e5a1d812560efe723..dce8c672b40fe19cee324c735897aec9b6bc9499 100644 (file)
@@ -1340,6 +1340,10 @@ pg_cursors| SELECT name,
     is_scrollable,
     creation_time
    FROM pg_cursor() c(name, statement, is_holdable, is_binary, is_scrollable, creation_time);
+pg_dsm_registry_allocations| SELECT name,
+    type,
+    size
+   FROM pg_get_dsm_registry_allocations() pg_get_dsm_registry_allocations(name, type, size);
 pg_file_settings| SELECT sourcefile,
     sourceline,
     seqno,
index f337aa67c13f23204d3d97f59f16a7c331bcd6a7..47bd4011dc99f424c7c6fc262a8ba118d9a0ced6 100644 (file)
@@ -1948,7 +1948,8 @@ DROP TABLE lock_table;
 DROP USER regress_locktable_user;
 
 -- test to check privileges of system views pg_shmem_allocations,
--- pg_shmem_allocations_numa and pg_backend_memory_contexts.
+-- pg_shmem_allocations_numa, pg_dsm_registry_allocations, and
+-- pg_backend_memory_contexts.
 
 -- switch to superuser
 \c -
@@ -1959,6 +1960,7 @@ SELECT has_table_privilege('regress_readallstats','pg_aios','SELECT'); -- no
 SELECT has_table_privilege('regress_readallstats','pg_backend_memory_contexts','SELECT'); -- no
 SELECT has_table_privilege('regress_readallstats','pg_shmem_allocations','SELECT'); -- no
 SELECT has_table_privilege('regress_readallstats','pg_shmem_allocations_numa','SELECT'); -- no
+SELECT has_table_privilege('regress_readallstats','pg_dsm_registry_allocations','SELECT'); -- no
 
 GRANT pg_read_all_stats TO regress_readallstats;
 
@@ -1966,6 +1968,7 @@ SELECT has_table_privilege('regress_readallstats','pg_aios','SELECT'); -- yes
 SELECT has_table_privilege('regress_readallstats','pg_backend_memory_contexts','SELECT'); -- yes
 SELECT has_table_privilege('regress_readallstats','pg_shmem_allocations','SELECT'); -- yes
 SELECT has_table_privilege('regress_readallstats','pg_shmem_allocations_numa','SELECT'); -- yes
+SELECT has_table_privilege('regress_readallstats','pg_dsm_registry_allocations','SELECT'); -- yes
 
 -- run query to ensure that functions within views can be executed
 SET ROLE regress_readallstats;