Show size of DSAs and dshashes in pg_dsm_registry_allocations.
authorNathan Bossart <nathan@postgresql.org>
Tue, 2 Dec 2025 16:29:45 +0000 (10:29 -0600)
committerNathan Bossart <nathan@postgresql.org>
Tue, 2 Dec 2025 16:29:45 +0000 (10:29 -0600)
Presently, this view reports NULL for the size of DSAs and dshash
tables because 1) the current backend might not be attached to them
and 2) the registry doesn't save the pointers to the dsa_area or
dshash_table in local memory.  Also, the view doesn't show
partially-initialized entries to avoid ambiguity, since those
entries would report a NULL size as well.

This commit introduces a function that looks up the size of a DSA
given its handle (transiently attaching to the control segment if
needed) and teaches pg_dsm_registry_allocations to use it to show
the size of successfully-initialized DSA and dshash entries.
Furthermore, the view now reports partially-initialized entries
with a NULL size.

Reviewed-by: Rahila Syed <rahilasyed90@gmail.com>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/aSeEDeznAsHR1_YF%40nathan

doc/src/sgml/system-views.sgml
src/backend/storage/ipc/dsm_registry.c
src/backend/utils/mmgr/dsa.c
src/include/utils/dsa.h
src/test/modules/test_dsm_registry/expected/test_dsm_registry.out
src/test/modules/test_dsm_registry/sql/test_dsm_registry.sql

index 7db8f73eba20ee4be22e697a4eb9a011c41b692f..162c76b729ac54a5b6f484527066044b48afd50b 100644 (file)
@@ -1150,8 +1150,8 @@ AND c1.path[c2.level] = c2.path[c2.level];
        <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>.
+       Size of the allocation in bytes.  NULL for entries that failed
+       initialization.
       </para></entry>
      </row>
     </tbody>
index ef6533b1100039990924af4cd1951bb4b6646bb1..66240318e83dd0c50f2ffd0afd431c511233a8c9 100644 (file)
@@ -463,26 +463,19 @@ pg_get_dsm_registry_allocations(PG_FUNCTION_ARGS)
        Datum       vals[3];
        bool        nulls[3] = {0};
 
-       /* Do not show partially-initialized entries. */
-       if (entry->type == DSMR_ENTRY_TYPE_DSM &&
-           entry->dsm.handle == DSM_HANDLE_INVALID)
-           continue;
-       if (entry->type == DSMR_ENTRY_TYPE_DSA &&
-           entry->dsa.handle == DSA_HANDLE_INVALID)
-           continue;
-       if (entry->type == DSMR_ENTRY_TYPE_DSH &&
-           entry->dsh.dsa_handle == DSA_HANDLE_INVALID)
-           continue;
-
        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)
+       /* Be careful to only return the sizes of initialized entries. */
+       if (entry->type == DSMR_ENTRY_TYPE_DSM &&
+           entry->dsm.handle != DSM_HANDLE_INVALID)
            vals[2] = Int64GetDatum(entry->dsm.size);
+       else if (entry->type == DSMR_ENTRY_TYPE_DSA &&
+                entry->dsa.handle != DSA_HANDLE_INVALID)
+           vals[2] = Int64GetDatum(dsa_get_total_size_from_handle(entry->dsa.handle));
+       else if (entry->type == DSMR_ENTRY_TYPE_DSH &&
+                entry->dsh.dsa_handle !=DSA_HANDLE_INVALID)
+           vals[2] = Int64GetDatum(dsa_get_total_size_from_handle(entry->dsh.dsa_handle));
        else
            nulls[2] = true;
 
index be43e9351c3d3db427621f2206503c6a5faa563b..c8a7268617752b2816f4d8bc854b760c5416ad89 100644 (file)
@@ -1050,6 +1050,41 @@ dsa_get_total_size(dsa_area *area)
    return size;
 }
 
+/*
+ * Same as dsa_get_total_size(), but accepts a DSA handle.  The area must have
+ * been created with dsa_create (not dsa_create_in_place).
+ */
+size_t
+dsa_get_total_size_from_handle(dsa_handle handle)
+{
+   size_t      size;
+   bool        already_attached;
+   dsm_segment *segment;
+   dsa_area_control *control;
+
+   already_attached = dsa_is_attached(handle);
+   if (already_attached)
+       segment = dsm_find_mapping(handle);
+   else
+       segment = dsm_attach(handle);
+
+   if (segment == NULL)
+       ereport(ERROR,
+               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                errmsg("could not attach to dynamic shared area")));
+
+   control = (dsa_area_control *) dsm_segment_address(segment);
+
+   LWLockAcquire(&control->lock, LW_EXCLUSIVE);
+   size = control->total_segment_size;
+   LWLockRelease(&control->lock);
+
+   if (!already_attached)
+       dsm_detach(segment);
+
+   return size;
+}
+
 /*
  * Aggressively free all spare memory in the hope of returning DSM segments to
  * the operating system.
index f2104dacbfcc515ee4b2fad9121608a9417983ab..42449ff22deb8c9a061af5e78bdc307227883110 100644 (file)
@@ -161,6 +161,7 @@ extern dsa_pointer dsa_allocate_extended(dsa_area *area, size_t size, int flags)
 extern void dsa_free(dsa_area *area, dsa_pointer dp);
 extern void *dsa_get_address(dsa_area *area, dsa_pointer dp);
 extern size_t dsa_get_total_size(dsa_area *area);
+extern size_t dsa_get_total_size_from_handle(dsa_handle handle);
 extern void dsa_trim(dsa_area *area);
 extern void dsa_dump(dsa_area *area);
 
index ca8abbb377e6b67e4263056302ebafd58ba42da4..9128e171b1b3efec88d71e346e0cfb7a44d2015a 100644 (file)
@@ -1,8 +1,8 @@
-SELECT name, type, size IS DISTINCT FROM 0 AS size
+SELECT name, type, size > 0 AS size_ok
 FROM pg_dsm_registry_allocations
 WHERE name like 'test_dsm_registry%' ORDER BY name;
- name | type | size 
-------+------+------
+ name | type | size_ok 
+------+------+---------
 (0 rows)
 
 CREATE EXTENSION test_dsm_registry;
@@ -32,11 +32,11 @@ SELECT get_val_in_hash('test');
 (1 row)
 
 \c
-SELECT name, type, size IS DISTINCT FROM 0 AS size
+SELECT name, type, size > 0 AS size_ok
 FROM pg_dsm_registry_allocations
 WHERE name like 'test_dsm_registry%' ORDER BY name;
-          name          |  type   | size 
-------------------------+---------+------
+          name          |  type   | size_ok 
+------------------------+---------+---------
  test_dsm_registry_dsa  | area    | t
  test_dsm_registry_dsm  | segment | t
  test_dsm_registry_hash | hash    | t
index 965a3f1ebb63aa88a7ec17bc0030b7047a0a92e2..a606e8872a14e7f75d1af2bb9844edcf2d37b2f8 100644 (file)
@@ -1,4 +1,4 @@
-SELECT name, type, size IS DISTINCT FROM 0 AS size
+SELECT name, type, size > 0 AS size_ok
 FROM pg_dsm_registry_allocations
 WHERE name like 'test_dsm_registry%' ORDER BY name;
 CREATE EXTENSION test_dsm_registry;
@@ -8,6 +8,6 @@ SELECT set_val_in_hash('test', '1414');
 SELECT get_val_in_shmem();
 SELECT get_val_in_hash('test');
 \c
-SELECT name, type, size IS DISTINCT FROM 0 AS size
+SELECT name, type, size > 0 AS size_ok
 FROM pg_dsm_registry_allocations
 WHERE name like 'test_dsm_registry%' ORDER BY name;