diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index e58efce586..391d01bcf3 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -25421,7 +25421,9 @@ SELECT collation for ('foo' COLLATE "de_DE"); 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 LOG message level. They will appear in the server log based on the log configuration set (See for more information), diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index 940b773fe1..23f691cd47 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -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(); } /* diff --git a/src/backend/postmaster/interrupt.c b/src/backend/postmaster/interrupt.c index b3db4f2a4c..3f412dad2e 100644 --- a/src/backend/postmaster/interrupt.c +++ b/src/backend/postmaster/interrupt.c @@ -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(); } /* diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index b319d03290..1121e4fb29 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -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(); } diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c index e9518beedc..9bae16bfc7 100644 --- a/src/backend/postmaster/startup.c +++ b/src/backend/postmaster/startup.c @@ -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(); } diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c index 9db9d98653..102fa2a089 100644 --- a/src/backend/postmaster/walwriter.c +++ b/src/backend/postmaster/walwriter.c @@ -306,4 +306,8 @@ HandleWalWriterInterrupts(void) proc_exit(0); } + + /* Perform logging of memory contexts of this process */ + if (LogMemoryContextPending) + ProcessLogMemoryContextInterrupt(); } diff --git a/src/backend/utils/adt/mcxtfuncs.c b/src/backend/utils/adt/mcxtfuncs.c index 845d619d60..28cb9d3ff1 100644 --- a/src/backend/utils/adt/mcxtfuncs.c +++ b/src/backend/utils/adt/mcxtfuncs.c @@ -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, diff --git a/src/test/regress/expected/misc_functions.out b/src/test/regress/expected/misc_functions.out index 1013d17f87..e2c77d0ac8 100644 --- a/src/test/regress/expected/misc_functions.out +++ b/src/test/regress/expected/misc_functions.out @@ -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 diff --git a/src/test/regress/sql/misc_functions.sql b/src/test/regress/sql/misc_functions.sql index 7ab9b2a150..1159f6b585 100644 --- a/src/test/regress/sql/misc_functions.sql +++ b/src/test/regress/sql/misc_functions.sql @@ -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',