On Fri, Mar 14, 2025 at 4:16 PM Nathan Bossart <nathandboss...@gmail.com> wrote:
> On Thu, Mar 13, 2025 at 06:54:09PM +0200, Florents Tselai wrote: > > I扉e been working with the DSM registry API. > > I was wondering if it is possible (it doesn愒 look like it) or if it has > been discussed: > > can we expose a view like pg_shmem_allocations, but fine-grained for > every named segment (i.e. created by GetNamedDSMSegment )? > > > > Currently, there is a "DSM Registry Data" entry in that view, > > but iiuc, it愀 only about the top-level hash table the registry uses. > > This seems like a generally reasonable idea to me. In theory, it should be > easy enough to build something that walks through the DSM registry hash > table. > Here's a first attempt towards a view pg_dsm_registry(name, size) that does just that So, using the test_dsm_registry module as a test bed, it would look like this. CREATE EXTENSION test_dsm_registry; SELECT set_val_in_shmem(1236); set_val_in_shmem ------------------ (1 row) -- 20 bytes = int (4 bytes) + LWLock (16bytes) SELECT * FROM pg_dsm_registry; name | size -------------------+------ test_dsm_registry | 20 (1 row) I'll create a cf entry to keep track of this
From 2f475e8a05142991feac2f62b57bc25b9c5ceebc Mon Sep 17 00:00:00 2001 From: Florents Tselai <florents.tselai@gmail.com> Date: Fri, 14 Mar 2025 23:34:13 +0200 Subject: [PATCH v1] First attempt towards a pg_dsm_registry view. Iterates over the registry hash table entries and reports the name and size. --- src/backend/catalog/system_views.sql | 8 ++ src/backend/storage/ipc/dsm_registry.c | 86 +++++++++++++++++++ src/include/catalog/pg_proc.dat | 6 ++ .../expected/test_dsm_registry.out | 7 ++ .../sql/test_dsm_registry.sql | 3 + src/test/regress/expected/rules.out | 3 + 6 files changed, 113 insertions(+) diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index a4d2cfdcaf5..63800af0769 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -658,6 +658,14 @@ 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_dsm_registry AS +SELECT * FROM pg_get_dsm_registry(); + +REVOKE ALL ON pg_dsm_registry FROM PUBLIC; +GRANT SELECT ON pg_dsm_registry TO pg_read_all_stats; +REVOKE EXECUTE ON FUNCTION pg_get_dsm_registry() FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pg_get_dsm_registry() TO pg_read_all_stats; + CREATE VIEW pg_backend_memory_contexts AS SELECT * FROM pg_get_backend_memory_contexts(); diff --git a/src/backend/storage/ipc/dsm_registry.c b/src/backend/storage/ipc/dsm_registry.c index 1d4fd31ffed..362452ab090 100644 --- a/src/backend/storage/ipc/dsm_registry.c +++ b/src/backend/storage/ipc/dsm_registry.c @@ -31,6 +31,10 @@ #include "storage/lwlock.h" #include "storage/shmem.h" #include "utils/memutils.h" +#include "fmgr.h" +#include "funcapi.h" +#include "miscadmin.h" +#include "utils/builtins.h" typedef struct DSMRegistryCtxStruct { @@ -198,3 +202,85 @@ GetNamedDSMSegment(const char *name, size_t size, return ret; } + +void +iterate_dsm_registry(void (*callback)(DSMRegistryEntry *, void *), void *arg); +void +iterate_dsm_registry(void (*callback)(DSMRegistryEntry *, void *), void *arg) +{ + DSMRegistryEntry *entry; + dshash_seq_status status; + + /* Ensure DSM registry is initialized */ + init_dsm_registry(); + + /* Use non-exclusive access to avoid blocking other backends */ + dshash_seq_init(&status, dsm_registry_table, false); + + while ((entry = dshash_seq_next(&status)) != NULL) + callback(entry, arg); + + dshash_seq_term(&status); +} + +/* SQL SRF showing DSM registry allocated memory */ +PG_FUNCTION_INFO_V1(pg_get_dsm_registry); + +typedef struct +{ + Tuplestorestate *tupstore; + TupleDesc tupdesc; +} DSMRegistrySRFContext; + +static void +collect_dsm_registry(DSMRegistryEntry *entry, void *arg) +{ + DSMRegistrySRFContext *ctx = (DSMRegistrySRFContext *) arg; + Datum values[2]; + bool nulls[2] = {false, false}; + + values[0] = CStringGetTextDatum(entry->name); + values[1] = Int64GetDatum(entry->size); + + tuplestore_putvalues(ctx->tupstore, ctx->tupdesc, values, nulls); +} + +Datum +pg_get_dsm_registry(PG_FUNCTION_ARGS) +{ + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + MemoryContext per_query_ctx; + MemoryContext oldcontext; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + DSMRegistrySRFContext ctx; + + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, (errmsg("pg_get_dsm_registry must be used in a SRF context"))); + + /* Set up tuple descriptor */ + tupdesc = CreateTemplateTupleDesc(2); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "size", INT8OID, -1, 0); + + /* Switch to per-query memory context */ + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; + oldcontext = MemoryContextSwitchTo(per_query_ctx); + + /* Initialize tuplestore */ + tupstore = tuplestore_begin_heap(false, false, work_mem); + + ctx.tupstore = tupstore; + ctx.tupdesc = tupdesc; + + /* Collect registry data */ + iterate_dsm_registry(collect_dsm_registry, &ctx); + + /* Switch back and return results */ + MemoryContextSwitchTo(oldcontext); + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; + + return (Datum) 0; +} diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 890822eaf79..3c012f52d95 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -8491,6 +8491,12 @@ proallargtypes => '{text,int8,int8,int8}', proargmodes => '{o,o,o,o}', proargnames => '{name,off,size,allocated_size}', prosrc => 'pg_get_shmem_allocations' }, +{ oid => '6062', descr => 'DSM registry allocations', + proname => 'pg_get_dsm_registry', prorows => '50', proretset => 't', + provolatile => 'v', prorettype => 'record', proargtypes => '', + proallargtypes => '{text,int8}', proargmodes => '{o,o}', + proargnames => '{name,size}', + prosrc => 'pg_get_dsm_registry' }, # memory context of local backend { oid => '2282', diff --git a/src/test/modules/test_dsm_registry/expected/test_dsm_registry.out b/src/test/modules/test_dsm_registry/expected/test_dsm_registry.out index 8ffbd343a05..229abf926b6 100644 --- a/src/test/modules/test_dsm_registry/expected/test_dsm_registry.out +++ b/src/test/modules/test_dsm_registry/expected/test_dsm_registry.out @@ -12,3 +12,10 @@ SELECT get_val_in_shmem(); 1236 (1 row) +-- 20 bytes = int (4 bytes) + LWLock (16bytes) +SELECT * FROM pg_dsm_registry; + name | size +-------------------+------ + test_dsm_registry | 20 +(1 row) + diff --git a/src/test/modules/test_dsm_registry/sql/test_dsm_registry.sql b/src/test/modules/test_dsm_registry/sql/test_dsm_registry.sql index b3351be0a16..aad402b5e64 100644 --- a/src/test/modules/test_dsm_registry/sql/test_dsm_registry.sql +++ b/src/test/modules/test_dsm_registry/sql/test_dsm_registry.sql @@ -2,3 +2,6 @@ CREATE EXTENSION test_dsm_registry; SELECT set_val_in_shmem(1236); \c SELECT get_val_in_shmem(); + +-- 20 bytes = int (4 bytes) + LWLock (16bytes) +SELECT * FROM pg_dsm_registry; diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 62f69ac20b2..fc35de68dae 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1324,6 +1324,9 @@ 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| SELECT name, + size + FROM pg_get_dsm_registry() pg_get_dsm_registry(name, size); pg_file_settings| SELECT sourcefile, sourceline, seqno, -- 2.48.1