> On 21 Feb 2026, at 00:13, Rahila Syed <[email protected]> wrote:
> Please find attached updated and rebased patches which incorporate
> code fixes suggested off-list by Daniel
>
> These changes include a fix to free dsa memory in one of the
> exit paths from the client-side function along with several documentation
> and comment improvements.
Thanks for the new version, I think this is looking pretty good now. The
attached .diff.txt (renamed to keep the CFBot from grabbing it) has mostly
whitespace fixes, but also a few small things which are discussed below:
+ <para>
+ After receiving memory context statistics from the target process, it
+ returns the results as one row per context. If all the contexts don't
Re-reading the docs I think the para's are in the wrong order, as the sentence
above makes little sense to be after the output has already been discussed. I
think this needs to go earlier, see the attached .diff.txt for what I am
proposing.
+ /*
+ * The client process should have created the required DSA and DSHash
+ * table. Here we just attach to those.
+ */
+ if (MemoryStatsDsaArea == NULL)
+ MemoryStatsDsaArea = GetNamedDSA("memory_context_statistics_dsa",
+ &found);
+
+ if (MemoryStatsDsHash == NULL)
+ MemoryStatsDsHash = GetNamedDSHash("memory_context_statistics_dshash",
+ &memctx_dsh_params, &found);
I think this needs an expanded comment discussing why there is no need the
check the DSA and DShash after the GetNamed_ functions, since they can be NULL
going in to this. The attached .diff.txt has a proposal along with an
Assertion to keep future changes of the API from risking subtly breaking this
assumption.
+REGRESS = test_memcontext_reporting
Since the test module doesn't contain any pg_regress style .sql/.out tests so
this line in the Makefile cause a test failure when running with Autoconf.
+$node->append_conf(
+ 'postgresql.conf',
+ qq[
+max_connections = 100
+log_statement = none
+restart_after_crash = false
+]);
Why do we need to set max_connections for this test?
+#Server should have thrown error
+$node->psql(
+ 'postgres',
+ qq(select pg_get_process_memory_contexts($pid, true);),
+ stderr => \$psql_err);
This test doesn't validate that the server actually errored does it? (There is
no proposed fix in the attached.)
--
Daniel Gustafsson
diff --git a/doc/src/sgml/func/func-admin.sgml
b/doc/src/sgml/func/func-admin.sgml
index 120f032f249..aa83b11e131 100644
--- a/doc/src/sgml/func/func-admin.sgml
+++ b/doc/src/sgml/func/func-admin.sgml
@@ -274,10 +274,19 @@
<para>
This function handles requests to display the memory contexts of a
<productname>PostgreSQL</productname> process with the specified
- process ID. The function can be used to send requests to backends as
- well as <glossterm linkend="glossary-auxiliary-proc">auxiliary
processes</glossterm>.
- If the process does not respond with memory contexts statistics in 5
seconds,
- the function returns NULL.
+ process ID. The function can be used to send requests to
+ <glossterm linkend="glossary-backend">backends</glossterm> as well as
+ <glossterm linkend="glossary-auxiliary-proc">auxiliary
processes</glossterm>.
+ If the process does not respond with memory contexts statistics in 5
+ seconds, the function returns NULL.
+ </para>
+ <para>
+ After receiving memory context statistics from the target process, it
+ returns the results as one row per context. If all the contexts don't
+ fit within the pre-determined size limit, the remaining context
+ statistics are aggregated and a cumulative total is displayed. The
+ <literal>num_agg_contexts</literal> column indicates the number of
+ contexts aggregated in the displayed statistics.
</para>
<para>
The returned record contains extended statistics per each memory
@@ -350,7 +359,8 @@
<listitem>
<para>
<parameter>num_agg_contexts</parameter> - The number of memory
- contexts aggregated in the displayed statistics.
+ contexts aggregated in the displayed statistics.
<literal>1</literal>
+ indicates that context statistics are displayed separately.
</para>
</listitem>
</itemizedlist>
@@ -365,16 +375,6 @@
<parameter>summary</parameter> is <literal>false</literal> (the
default),
<literal>the num_agg_contexts</literal> value is <literal>1</literal>,
indicating that individual statistics are being displayed.
- </para>
- <para>
- After receiving memory context statistics from the target process, it
- returns the results as one row per context. If all the contexts don't
- fit within the pre-determined size limit, the remaining context
- statistics are aggregated and a cumulative total is displayed. The
- <literal>num_agg_contexts</literal> column indicates the number of
- contexts aggregated in the displayed statistics. A
- <literal>num_agg_contexts</literal> value of <literal>1</literal>
- indicates that context statistics are displayed separately.
</para></entry>
</row>
</tbody>
diff --git a/src/backend/utils/adt/mcxtfuncs.c
b/src/backend/utils/adt/mcxtfuncs.c
index f18b6d47c60..fdf0043211b 100644
--- a/src/backend/utils/adt/mcxtfuncs.c
+++ b/src/backend/utils/adt/mcxtfuncs.c
@@ -978,7 +978,11 @@ ProcessGetMemoryContextInterrupt(void)
/*
* The client process should have created the required DSA and DSHash
- * table. Here we just attach to those.
+ * table, so we can connect to these directly. The GetNamedXXX
functions
+ * either return DSA/DSHash or error out (which we want to avoid as that
+ * would cause the current transaction to fail) so we don't need to
check
+ * for NULL. An assertion is enough to catch in case this API should be
+ * changed at some point.
*/
if (MemoryStatsDsaArea == NULL)
MemoryStatsDsaArea =
GetNamedDSA("memory_context_statistics_dsa",
@@ -988,6 +992,8 @@ ProcessGetMemoryContextInterrupt(void)
MemoryStatsDsHash =
GetNamedDSHash("memory_context_statistics_dshash",
&memctx_dsh_params, &found);
+ Assert(MemoryStatsDsaArea != NULL && MemoryStatsDsHash != NULL);
+
/*
* The entry lock is held by dshash_find_or_insert to protect writes to
* process specific memory. Two different processes publishing
statistics
@@ -1001,9 +1007,8 @@ ProcessGetMemoryContextInterrupt(void)
* if the caller has timed out waiting for us and have issued a request
to
* another backend.
*
- * Make sure that the client always deletes the entry after taking
- * required lock or this function may end up writing to unallocated
- * memory.
+ * Make sure that the client always deletes the entry after taking the
+ * required lock or this function may end up writing to unallocated
memory.
*/
if (!found || entry->target_server_id != MyProcPid)
{
@@ -1042,13 +1047,11 @@ ProcessGetMemoryContextInterrupt(void)
HASH_ENTER, &found);
Assert(!found);
- /*
- * context id starts with 1
- */
+ /* context id starts with 1 */
contextid_entry->context_id = cxt_id + 1;
/*
- * Copy statistics for each of TopMemoryContexts children. This
+ * Copy statistics for each of TopMemoryContext's children.
This
* includes statistics of at most 100 children per node, with
each
* child node limited to a depth of 100 in its subtree.
*/
diff --git a/src/test/modules/test_memcontext_reporting/Makefile
b/src/test/modules/test_memcontext_reporting/Makefile
index 47bce45bc1d..2ce169ffa69 100644
--- a/src/test/modules/test_memcontext_reporting/Makefile
+++ b/src/test/modules/test_memcontext_reporting/Makefile
@@ -11,8 +11,6 @@ OBJS = \
test_memcontext_reporting.o
PGFILEDESC = "test_memcontext_reporting - test code for memory context
reporting"
-REGRESS = test_memcontext_reporting
-
ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
diff --git a/src/test/modules/test_memcontext_reporting/t/001_memcontext_inj.pl
b/src/test/modules/test_memcontext_reporting/t/001_memcontext_inj.pl
index 73665abf902..152465c1570 100644
--- a/src/test/modules/test_memcontext_reporting/t/001_memcontext_inj.pl
+++ b/src/test/modules/test_memcontext_reporting/t/001_memcontext_inj.pl
@@ -21,7 +21,6 @@ $node->init;
$node->append_conf(
'postgresql.conf',
qq[
-max_connections = 100
log_statement = none
restart_after_crash = false
]);
@@ -36,7 +35,7 @@ $node->safe_psql('postgres',
my $pid = $node->safe_psql('postgres',
"SELECT pid from pg_stat_activity where backend_type='checkpointer'");
-#Client should have thrown error
+# Client should have thrown error
$node->psql(
'postgres',
qq(select pg_get_process_memory_contexts($pid, true);),
@@ -44,7 +43,8 @@ $node->psql(
like($psql_err,
qr/error triggered for injection point memcontext-client-injection/);
-#Query the same process after detaching the injection point, using some other
client and it should succeed.
+# Query the same process after detaching the injection point, using some other
+# client and it should succeed.
$node->safe_psql('postgres',
"select injection_points_detach('memcontext-client-injection');");
my $topcontext_name = $node->safe_psql('postgres',
@@ -57,13 +57,14 @@ $node->safe_psql('postgres',
"select injection_points_attach('memcontext-server-injection',
'error');"
);
-#Server should have thrown error
+# Server should have thrown error
$node->psql(
'postgres',
qq(select pg_get_process_memory_contexts($pid, true);),
stderr => \$psql_err);
-#Query the same process after detaching the injection point, using some other
client and it should succeed.
+# Query the same process after detaching the injection point, using some other
+# client and it should succeed.
$node->safe_psql('postgres',
"select injection_points_detach('memcontext-server-injection');");
$topcontext_name = $node->safe_psql('postgres',
@@ -71,8 +72,8 @@ $topcontext_name = $node->safe_psql('postgres',
);
ok($topcontext_name eq 'TopMemoryContext');
-# Test that two concurrent requests to the same process results in a warning
for
-# one of those
+# Test that two concurrent requests to the same process results in a warning
+# for one of those
$node->safe_psql('postgres',
"SELECT injection_points_attach('memcontext-client-injection',
'wait');");
@@ -80,8 +81,9 @@ $node->safe_psql('postgres',
"SELECT injection_points_attach('memcontext-server-wait', 'wait');");
my $psql_session1 = $node->background_psql('postgres');
-# We use query_until so that we can execute additional commands without having
to
-# wait for this command to complete, since it will pause at injection points.
+# We use query_until so that we can execute additional commands without having
+# to wait for this command to complete, since it will pause at injection
+# points.
$psql_session1->query_until(
qr//,
@@ -95,7 +97,7 @@ $node->psql(
stderr => \$psql_err);
ok($psql_err =~
/WARNING: server process $pid is processing previous request/);
-#Wake the client up.
+# Wake the client up.
$node->safe_psql('postgres',
"SELECT injection_points_wakeup('memcontext-client-injection');");
@@ -104,7 +106,8 @@ $node->safe_psql('postgres',
$node->safe_psql('postgres',
"select injection_points_detach('memcontext-server-wait');");
-# Test the client process exiting with timeout does not break the server
process
+# Test the client process exiting with timeout does not break the server
+# process
$node->safe_psql('postgres',
"SELECT injection_points_attach('memcontext-server-wait', 'wait');");
@@ -114,12 +117,12 @@ $node->psql(
qq(select name from pg_get_process_memory_contexts($pid, true) where
path = '{1}';),
stdout => \$psql_out);
is($psql_out, '', 'Query returns null');
-#Wakeup the server process up and detach the injection point.
+# Wakeup the server process up and detach the injection point.
$node->safe_psql('postgres',
"SELECT injection_points_wakeup('memcontext-server-wait');");
$node->safe_psql('postgres',
"select injection_points_detach('memcontext-server-wait');");
-#Query the same server process again and it should succeed.
+# Query the same server process again and it should succeed.
$topcontext_name = $node->safe_psql('postgres',
"select name from pg_get_process_memory_contexts($pid, true) where path
= '{1}';"
);
@@ -130,7 +133,7 @@ $node->safe_psql('postgres',
"select injection_points_attach('memcontext-client-injection',
'test_memcontext_reporting', 'crash', NULL);"
);
-#Client will crash
+# Client will crash
$node->psql(
'postgres',
qq(select name from pg_get_process_memory_contexts($pid, true) where
path = '{1}';),
@@ -143,7 +146,7 @@ like($psql_err,
$node->restart;
$node->poll_query_until('postgres', "SELECT 1;", '1');
-#Querying memory stats should succeed after server start
+# Querying memory stats should succeed after server start
$pid = $node->safe_psql('postgres',
"SELECT pid from pg_stat_activity where backend_type='checkpointer'");
$topcontext_name = $node->safe_psql('postgres',