Enhance pg_log_backend_memory_contexts() for auxiliary processes.
authorFujii Masao <fujii@postgresql.org>
Tue, 11 Jan 2022 14:19:59 +0000 (23:19 +0900)
committerFujii Masao <fujii@postgresql.org>
Tue, 11 Jan 2022 14:19:59 +0000 (23:19 +0900)
Previously pg_log_backend_memory_contexts() could request to
log the memory contexts of backends, but not of auxiliary processes
such as checkpointer. This commit enhances the function so that
it can also send the request to auxiliary processes. It's useful to
look at the memory contexts of those processes for debugging purpose
and better understanding of the memory usage pattern of them.

Note that pg_log_backend_memory_contexts() cannot send the request
to logger or statistics collector. Because this logging request
mechanism is based on shared memory but those processes aren't
connected to that.

Author: Bharath Rupireddy
Reviewed-by: Vignesh C, Kyotaro Horiguchi, Fujii Masao
Discussion: https://postgr.es/m/CALj2ACU1nBzpacOK2q=a65S_4+Oaz_rLTsU1Ri0gf7YUmnmhfQ@mail.gmail.com

doc/src/sgml/func.sgml
src/backend/postmaster/checkpointer.c
src/backend/postmaster/interrupt.c
src/backend/postmaster/pgarch.c
src/backend/postmaster/startup.c
src/backend/postmaster/walwriter.c
src/backend/utils/adt/mcxtfuncs.c
src/test/regress/expected/misc_functions.out
src/test/regress/sql/misc_functions.sql

index e58efce5865aee60335dd379e03de041955512ea..391d01bcf3d1d61f24c85e55b39db2872c6a4364 100644 (file)
@@ -25421,7 +25421,9 @@ SELECT collation for ('foo' COLLATE "de_DE");
        </para>
        <para>
         Requests to log the memory contexts of the backend with the
-        specified process ID.  These memory contexts will be logged at
+        specified process ID.  This function can send the request to
+        backends and auxiliary processes except logger and statistics
+        collector.  These memory contexts will be logged at
         <literal>LOG</literal> message level. They will appear in
         the server log based on the log configuration set
         (See <xref linkend="runtime-config-logging"/> for more information),
index 940b773fe1bab6a4a52d0098b5b562ea3608b401..23f691cd47538842706049190bf2bc8734d5fb77 100644 (file)
@@ -577,6 +577,10 @@ HandleCheckpointerInterrupts(void)
                /* Normal exit from the checkpointer is here */
                proc_exit(0);                   /* done */
        }
+
+       /* Perform logging of memory contexts of this process */
+       if (LogMemoryContextPending)
+               ProcessLogMemoryContextInterrupt();
 }
 
 /*
index b3db4f2a4c1d7c9101b9fbcf80d1d43a33cddfe7..3f412dad2e62cec23b0c00563ba2836cd6394508 100644 (file)
@@ -22,6 +22,7 @@
 #include "storage/latch.h"
 #include "storage/procsignal.h"
 #include "utils/guc.h"
+#include "utils/memutils.h"
 
 volatile sig_atomic_t ConfigReloadPending = false;
 volatile sig_atomic_t ShutdownRequestPending = false;
@@ -43,6 +44,10 @@ HandleMainLoopInterrupts(void)
 
        if (ShutdownRequestPending)
                proc_exit(0);
+
+       /* Perform logging of memory contexts of this process */
+       if (LogMemoryContextPending)
+               ProcessLogMemoryContextInterrupt();
 }
 
 /*
index b319d032904711e07c87df378b72e368da1e30d2..1121e4fb29c78d95b45c92617909190f9150ad5b 100644 (file)
@@ -50,6 +50,7 @@
 #include "storage/shmem.h"
 #include "storage/spin.h"
 #include "utils/guc.h"
+#include "utils/memutils.h"
 #include "utils/ps_status.h"
 
 
@@ -861,8 +862,9 @@ pgarch_die(int code, Datum arg)
  * Interrupt handler for WAL archiver process.
  *
  * This is called in the loops pgarch_MainLoop and pgarch_ArchiverCopyLoop.
- * It checks for barrier events and config update, but not shutdown request
- * because how to handle shutdown request is different between those loops.
+ * It checks for barrier events, config update and request for logging of
+ * memory contexts, but not shutdown request because how to handle
+ * shutdown request is different between those loops.
  */
 static void
 HandlePgArchInterrupts(void)
@@ -875,4 +877,8 @@ HandlePgArchInterrupts(void)
                ConfigReloadPending = false;
                ProcessConfigFile(PGC_SIGHUP);
        }
+
+       /* Perform logging of memory contexts of this process */
+       if (LogMemoryContextPending)
+               ProcessLogMemoryContextInterrupt();
 }
index e9518beedca153f16d198520fd7ad82623273f20..9bae16bfc78ff370323b66e1d2e6df6c18166598 100644 (file)
@@ -32,6 +32,7 @@
 #include "storage/procsignal.h"
 #include "storage/standby.h"
 #include "utils/guc.h"
+#include "utils/memutils.h"
 #include "utils/timeout.h"
 
 
@@ -200,6 +201,10 @@ HandleStartupProcInterrupts(void)
        /* Process barrier events */
        if (ProcSignalBarrierPending)
                ProcessProcSignalBarrier();
+
+       /* Perform logging of memory contexts of this process */
+       if (LogMemoryContextPending)
+               ProcessLogMemoryContextInterrupt();
 }
 
 
index 9db9d98653962e9c131e5411bb915a839567e40f..102fa2a089f69d8312951e9fcc0da79af8414425 100644 (file)
@@ -306,4 +306,8 @@ HandleWalWriterInterrupts(void)
 
                proc_exit(0);
        }
+
+       /* Perform logging of memory contexts of this process */
+       if (LogMemoryContextPending)
+               ProcessLogMemoryContextInterrupt();
 }
index 845d619d6058fb487359464c529f1c2d0b5168b8..28cb9d3ff10b5d4ec8645b75380ef6c853923dff 100644 (file)
@@ -160,33 +160,47 @@ pg_get_backend_memory_contexts(PG_FUNCTION_ARGS)
 
 /*
  * pg_log_backend_memory_contexts
- *             Signal a backend process to log its memory contexts.
+ *             Signal a backend or an auxiliary process to log its memory contexts.
  *
  * By default, only superusers are allowed to signal to log the memory
  * contexts because allowing any users to issue this request at an unbounded
  * rate would cause lots of log messages and which can lead to denial of
  * service. Additional roles can be permitted with GRANT.
  *
- * On receipt of this signal, a backend sets the flag in the signal
- * handler, which causes the next CHECK_FOR_INTERRUPTS() to log the
- * memory contexts.
+ * On receipt of this signal, a backend or an auxiliary process sets the flag
+ * in the signal handler, which causes the next CHECK_FOR_INTERRUPTS()
+ * or process-specific interrupt handler to log the memory contexts.
  */
 Datum
 pg_log_backend_memory_contexts(PG_FUNCTION_ARGS)
 {
        int                     pid = PG_GETARG_INT32(0);
        PGPROC     *proc;
+       BackendId       backendId = InvalidBackendId;
 
        proc = BackendPidGetProc(pid);
 
        /*
-        * BackendPidGetProc returns NULL if the pid isn't valid; but by the time
-        * we reach kill(), a process for which we get a valid proc here might
-        * have terminated on its own.  There's no way to acquire a lock on an
-        * arbitrary process to prevent that. But since this mechanism is usually
-        * used to debug a backend running and consuming lots of memory, that it
-        * might end on its own first and its memory contexts are not logged is
-        * not a problem.
+        * See if the process with given pid is a backend or an auxiliary process.
+        *
+        * If the given process is a backend, use its backend id in
+        * SendProcSignal() later to speed up the operation. Otherwise, don't do
+        * that because auxiliary processes (except the startup process) don't
+        * have a valid backend id.
+        */
+       if (proc != NULL)
+               backendId = proc->backendId;
+       else
+               proc = AuxiliaryPidGetProc(pid);
+
+       /*
+        * BackendPidGetProc() and AuxiliaryPidGetProc() return NULL if the pid
+        * isn't valid; but by the time we reach kill(), a process for which we
+        * get a valid proc here might have terminated on its own.  There's no way
+        * to acquire a lock on an arbitrary process to prevent that. But since
+        * this mechanism is usually used to debug a backend or an auxiliary
+        * process running and consuming lots of memory, that it might end on its
+        * own first and its memory contexts are not logged is not a problem.
         */
        if (proc == NULL)
        {
@@ -199,7 +213,7 @@ pg_log_backend_memory_contexts(PG_FUNCTION_ARGS)
                PG_RETURN_BOOL(false);
        }
 
-       if (SendProcSignal(pid, PROCSIG_LOG_MEMORY_CONTEXT, proc->backendId) < 0)
+       if (SendProcSignal(pid, PROCSIG_LOG_MEMORY_CONTEXT, backendId) < 0)
        {
                /* Again, just a warning to allow loops */
                ereport(WARNING,
index 1013d17f87d5327abd0ffdb8c372ecd91569f647..e2c77d0ac8438fd0de08f77425a564589ee57cb6 100644 (file)
@@ -147,6 +147,13 @@ SELECT pg_log_backend_memory_contexts(pg_backend_pid());
  t
 (1 row)
 
+SELECT pg_log_backend_memory_contexts(pid) FROM pg_stat_activity
+  WHERE backend_type = 'checkpointer';
+ pg_log_backend_memory_contexts 
+--------------------------------
+ t
+(1 row)
+
 CREATE ROLE regress_log_memory;
 SELECT has_function_privilege('regress_log_memory',
   'pg_log_backend_memory_contexts(integer)', 'EXECUTE'); -- no
index 7ab9b2a1509b0dde681146efb69953f29267cf4c..1159f6b5855586d9e2d2b19c7c8a0be163dd8ed8 100644 (file)
@@ -41,6 +41,9 @@ SELECT num_nulls();
 
 SELECT pg_log_backend_memory_contexts(pg_backend_pid());
 
+SELECT pg_log_backend_memory_contexts(pid) FROM pg_stat_activity
+  WHERE backend_type = 'checkpointer';
+
 CREATE ROLE regress_log_memory;
 
 SELECT has_function_privilege('regress_log_memory',