From e8a7576f3a593f4f88bd619ae2504ee320e61db2 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Sun, 4 May 2014 13:37:20 +0200 Subject: [PATCH] Add pg_shmem_allocations view. --- src/backend/catalog/system_views.sql | 3 ++ src/backend/storage/ipc/shmem.c | 97 ++++++++++++++++++++++++++++++++++++ src/include/catalog/pg_proc.h | 2 + src/include/utils/builtins.h | 3 ++ src/test/regress/expected/rules.out | 5 ++ 5 files changed, 110 insertions(+) diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 42a4c00..104491a 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -387,6 +387,9 @@ CREATE VIEW pg_timezone_abbrevs AS CREATE VIEW pg_timezone_names AS SELECT * FROM pg_timezone_names(); +CREATE VIEW pg_shmem_allocations AS + SELECT * FROM pg_get_shmem_allocations(); + -- Statistics views CREATE VIEW pg_stat_all_tables AS diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c index 1d27a89..5722c78 100644 --- a/src/backend/storage/ipc/shmem.c +++ b/src/backend/storage/ipc/shmem.c @@ -66,11 +66,14 @@ #include "postgres.h" #include "access/transam.h" +#include "fmgr.h" +#include "funcapi.h" #include "miscadmin.h" #include "storage/lwlock.h" #include "storage/pg_shmem.h" #include "storage/shmem.h" #include "storage/spin.h" +#include "utils/builtins.h" /* shared memory global variables */ @@ -459,3 +462,97 @@ mul_size(Size s1, Size s2) errmsg("requested shared memory size overflows size_t"))); return result; } + +/* SQL SRF showing allocated shared memory */ +Datum +pg_get_shmem_allocations(PG_FUNCTION_ARGS) +{ +#define PG_GET_SHMEM_SIZES_COLS 4 + + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + MemoryContext per_query_ctx; + MemoryContext oldcontext; + HASH_SEQ_STATUS hstat; + ShmemIndexEnt *ent; + + /* check to see if caller supports us returning a tuplestore */ + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("materialize mode required, but it is not " \ + "allowed in this context"))); + + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); + + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; + oldcontext = MemoryContextSwitchTo(per_query_ctx); + + tupstore = tuplestore_begin_heap(true, false, work_mem); + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; + + MemoryContextSwitchTo(oldcontext); + + hash_seq_init(&hstat, ShmemIndex); + + /* output all allocated entries */ + while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL) + { + Datum values[PG_GET_SHMEM_SIZES_COLS]; + bool nulls[PG_GET_SHMEM_SIZES_COLS]; + + /* key */ + values[0] = CStringGetTextDatum(ent->key); + nulls[0] = false; + + /* off */ + values[1] = Int64GetDatum((char *) ent->location - (char *) ShmemSegHdr); + nulls[1] = false; + + /* size */ + values[2] = Int64GetDatum(ent->size); + nulls[2] = false; + + /* allocated */ + values[3] = BoolGetDatum(true); + nulls[3] = false; + + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + } + + /* output as-of-yet unallocated memory */ + { + Datum values[PG_GET_SHMEM_SIZES_COLS]; + bool nulls[PG_GET_SHMEM_SIZES_COLS]; + + /* key, show unallocated as NULL */ + nulls[0] = true; + + /* off */ + values[1] = Int64GetDatum(ShmemSegHdr->freeoffset); + nulls[1] = false; + + /* size */ + values[2] = Int64GetDatum(ShmemSegHdr->totalsize - ShmemSegHdr->freeoffset); + nulls[2] = false; + + /* allocated */ + values[3] = BoolGetDatum(false); + nulls[3] = false; + + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + } + + tuplestore_donestoring(tupstore); + + return (Datum) 0; +} diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 98c183b..d018e6f 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -3899,6 +3899,8 @@ DATA(insert OID = 3035 ( pg_listening_channels PGNSP PGUID 12 1 10 0 0 f f f f DESCR("get the channels that the current backend listens to"); DATA(insert OID = 3036 ( pg_notify PGNSP PGUID 12 1 0 0 0 f f f f f f v 2 0 2278 "25 25" _null_ _null_ _null_ _null_ pg_notify _null_ _null_ _null_ )); DESCR("send a notification event"); +DATA(insert OID = 86 ( pg_get_shmem_allocations PGNSP PGUID 12 1 10 0 0 f f f f f t s 0 0 2249 "" "{25,20,20,16}" "{o,o,o,o}" "{key, off, size, allocated}" _null_ pg_get_shmem_allocations _null_ _null_ _null_ )); +DESCR("show shared memory allocations"); /* non-persistent series generator */ DATA(insert OID = 1066 ( generate_series PGNSP PGUID 12 1 1000 0 0 f f f f t t i 3 0 23 "23 23 23" _null_ _null_ _null_ _null_ generate_series_step_int4 _null_ _null_ _null_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 33b6dca..540015f 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -1209,4 +1209,7 @@ extern Datum pg_prepared_statement(PG_FUNCTION_ARGS); /* utils/mmgr/portalmem.c */ extern Datum pg_cursor(PG_FUNCTION_ARGS); +/* backend/storage/ipc/shmem.c */ +extern Datum pg_get_shmem_allocations(PG_FUNCTION_ARGS); + #endif /* BUILTINS_H */ diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 87870cf..58a125b 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1591,6 +1591,11 @@ pg_shadow| SELECT pg_authid.rolname AS usename, FROM (pg_authid 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 pg_get_shmem_allocations.key, + pg_get_shmem_allocations.off, + pg_get_shmem_allocations.size, + pg_get_shmem_allocations.allocated + FROM pg_get_shmem_allocations() pg_get_shmem_allocations(key, off, size, allocated); pg_stat_activity| SELECT s.datid, d.datname, s.pid, -- 1.8.5.rc2.dirty