From 2628271de4f2b185ae2eaec29927ffe12401bc60 Mon Sep 17 00:00:00 2001 From: Bharath Rupireddy Date: Wed, 7 Feb 2024 18:22:58 +0000 Subject: [PATCH v29 2/2] Extend backtrace logging function for auxiliary processes --- doc/src/sgml/func.sgml | 12 ++++--- src/backend/storage/ipc/procbacktrace.c | 35 ++++++++++++++------ src/backend/storage/lmgr/proc.c | 2 ++ src/test/regress/expected/misc_functions.out | 8 +++++ src/test/regress/sql/misc_functions.sql | 3 ++ 5 files changed, 45 insertions(+), 15 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index b7d7305331..b810a3dcaf 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -27196,11 +27196,13 @@ SELECT collation for ('foo' COLLATE "de_DE"); Requests to log the backtrace of a backend with the specified process - ID. The backtraces will be logged to stderr. - Typically, a backtrace identifies which function a process is currently - executing, and is useful for developers to diagnose stuck processes. - This function is supported only if PostgreSQL was built with the - ability to capture backtraces, otherwise it will emit a warning. + ID. This function can send the request to backends and auxiliary + processes except logger. The backtraces will be logged to + stderr. Typically, a backtrace identifies + which function a process is currently executing, and is useful for + developers to diagnose stuck processes. This function is supported only + if PostgreSQL was built with the ability to capture backtraces, + otherwise it will emit a warning. diff --git a/src/backend/storage/ipc/procbacktrace.c b/src/backend/storage/ipc/procbacktrace.c index bfab5783da..b85684cd19 100644 --- a/src/backend/storage/ipc/procbacktrace.c +++ b/src/backend/storage/ipc/procbacktrace.c @@ -92,15 +92,15 @@ LoadBacktraceFunctions(void) /* * pg_log_backend_backtrace - * Signal a backend to log its current backtrace. + * Signal a backend or an auxiliary process to log its current backtrace. * * By default, only superusers are allowed to signal to log the backtrace * because allowing any users to issue this request at an unbounded * rate would cause lots of log messages on stderr and which can lead to * denial of service. Additional roles can be permitted with GRANT. * - * On receipt of this signal, a backend emits the current backtrace to stderr - * in the signal handler. + * On receipt of this signal, a backend or an auxiliary process emits the + * current backtrace to stderr in the signal handler. */ Datum pg_log_backend_backtrace(PG_FUNCTION_ARGS) @@ -108,15 +108,31 @@ pg_log_backend_backtrace(PG_FUNCTION_ARGS) #ifdef HAVE_BACKTRACE_SYMBOLS int pid = PG_GETARG_INT32(0); PGPROC *proc; + BackendId backendId = InvalidBackendId; proc = BackendPidGetProc(pid); /* - * BackendPidGetProc returns NULL if the pid isn't valid. + * See if the process with given pid is a backend or an auxiliary process. * - * Note that the proc will also be NULL if the pid refers to an auxiliary - * process or the postmaster (neither of which can be signaled via - * pg_log_backend_backtrace() to get backtrace). + * 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) { @@ -125,12 +141,11 @@ pg_log_backend_backtrace(PG_FUNCTION_ARGS) * if one backend terminated on its own during the run. */ ereport(WARNING, - (errmsg("PID %d is not a PostgreSQL backend process", pid))); - + (errmsg("PID %d is not a PostgreSQL server process", pid))); PG_RETURN_BOOL(false); } - if (SendProcSignal(pid, PROCSIG_LOG_BACKTRACE, proc->backendId) < 0) + if (SendProcSignal(pid, PROCSIG_LOG_BACKTRACE, backendId) < 0) { /* Again, just a warning to allow loops */ ereport(WARNING, diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 73e0368c29..f61a6d0d8f 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -635,6 +635,8 @@ InitAuxiliaryProcess(void) */ InitLWLockAccess(); + LoadBacktraceFunctions(); + #ifdef EXEC_BACKEND /* diff --git a/src/test/regress/expected/misc_functions.out b/src/test/regress/expected/misc_functions.out index 3ff0136347..8751538c57 100644 --- a/src/test/regress/expected/misc_functions.out +++ b/src/test/regress/expected/misc_functions.out @@ -341,6 +341,14 @@ SELECT count(*) > 0 AS ok FROM pg_log_backend_backtrace(pg_backend_pid()); t (1 row) +SELECT pid AS c_pid FROM pg_stat_activity + WHERE backend_type = 'checkpointer' \gset +SELECT count(*) > 0 AS ok FROM pg_log_backend_backtrace(:c_pid); + ok +---- + t +(1 row) + RESET client_min_messages; CREATE ROLE regress_log_backtrace; SELECT has_function_privilege('regress_log_backtrace', diff --git a/src/test/regress/sql/misc_functions.sql b/src/test/regress/sql/misc_functions.sql index 2a3f9bacaa..0e51974ac3 100644 --- a/src/test/regress/sql/misc_functions.sql +++ b/src/test/regress/sql/misc_functions.sql @@ -114,6 +114,9 @@ DROP ROLE regress_log_memory; -- generation support. SET client_min_messages = 'ERROR'; SELECT count(*) > 0 AS ok FROM pg_log_backend_backtrace(pg_backend_pid()); +SELECT pid AS c_pid FROM pg_stat_activity + WHERE backend_type = 'checkpointer' \gset +SELECT count(*) > 0 AS ok FROM pg_log_backend_backtrace(:c_pid); RESET client_min_messages; CREATE ROLE regress_log_backtrace; -- 2.34.1