From 96972c00ae3ee2110d176f3ae2eb425949d0db6d Mon Sep 17 00:00:00 2001 From: Vigneshwaran C Date: Thu, 11 Nov 2021 11:50:34 +0530 Subject: [PATCH v10 2/2] pg_print_backtrace support for printing backtrace of aux procs Enhanced pg_print_backtrace to support printing backtrace of auxiliary processes such as bgwriter, checkpointer, wal writer, archiver, startup process and wal receiver. It will be useful to look at the backtrace of these processes too, for debugging purposes and to check if the process is genuinely taking time or if it is a stuck process. Inside the code, we could use the AuxiliaryPidGetProc() to get the PGPROC of these processes. Note that, neither AuxiliaryPidGetProc() nor BackendPidGetProc() can return PGPROC(as they don't have PGPROC entries at all) entries for the syslogger and stats collector processes. --- doc/src/sgml/func.sgml | 9 +++-- src/backend/postmaster/checkpointer.c | 4 +++ src/backend/postmaster/interrupt.c | 4 +++ src/backend/postmaster/pgarch.c | 4 +++ src/backend/postmaster/startup.c | 4 +++ src/backend/postmaster/walwriter.c | 4 +++ src/backend/storage/ipc/signalfuncs.c | 35 ++++++++++++++------ src/test/regress/expected/misc_functions.out | 11 ++++++ src/test/regress/sql/misc_functions.sql | 9 +++++ 9 files changed, 69 insertions(+), 15 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index c9e6e470f3..2ce236cf7b 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -25362,11 +25362,10 @@ SELECT collation for ('foo' COLLATE "de_DE"); . A backtrace will identify where exactly the backend process is currently executing. This may be useful to developers to diagnose stuck processes and other problems. - This feature is not supported for the postmaster, logger, checkpointer, - walwriter, background writer or statistics collector process. This - feature will be available if PostgreSQL was built with the ability to - capture backtrace. If not available, the function will return false - and a warning is issued, for example: + This feature is not supported for the postmaster, logger or statistics + collector process. This feature will be available if PostgreSQL was + built with the ability to capture backtrace. If not available, the + function will return false and a warning is issued, for example: WARNING: backtrace generation is not supported by this installation pg_print_backtrace diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index be7366379d..83d78a0126 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -581,6 +581,10 @@ HandleCheckpointerInterrupts(void) /* Normal exit from the checkpointer is here */ proc_exit(0); /* done */ } + + /* Process printing backtrace */ + if (PrintBacktracePending) + ProcessPrintBacktraceInterrupt(); } /* diff --git a/src/backend/postmaster/interrupt.c b/src/backend/postmaster/interrupt.c index dd9136a942..ad5716053e 100644 --- a/src/backend/postmaster/interrupt.c +++ b/src/backend/postmaster/interrupt.c @@ -43,6 +43,10 @@ HandleMainLoopInterrupts(void) if (ShutdownRequestPending) proc_exit(0); + + /* Process printing backtrace */ + if (PrintBacktracePending) + ProcessPrintBacktraceInterrupt(); } /* diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index 74a7d7c4d0..1c6410a410 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -715,4 +715,8 @@ HandlePgArchInterrupts(void) ConfigReloadPending = false; ProcessConfigFile(PGC_SIGHUP); } + + /* Process printing backtrace */ + if (PrintBacktracePending) + ProcessPrintBacktraceInterrupt(); } diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c index 47ec737888..91be95992e 100644 --- a/src/backend/postmaster/startup.c +++ b/src/backend/postmaster/startup.c @@ -200,6 +200,10 @@ HandleStartupProcInterrupts(void) /* Process barrier events */ if (ProcSignalBarrierPending) ProcessProcSignalBarrier(); + + /* Process printing backtrace */ + if (PrintBacktracePending) + ProcessPrintBacktraceInterrupt(); } diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c index 626fae8454..1ec5c892ac 100644 --- a/src/backend/postmaster/walwriter.c +++ b/src/backend/postmaster/walwriter.c @@ -306,4 +306,8 @@ HandleWalWriterInterrupts(void) proc_exit(0); } + + /* Process printing backtrace */ + if (PrintBacktracePending) + ProcessPrintBacktraceInterrupt(); } diff --git a/src/backend/storage/ipc/signalfuncs.c b/src/backend/storage/ipc/signalfuncs.c index df942d6015..93108448a5 100644 --- a/src/backend/storage/ipc/signalfuncs.c +++ b/src/backend/storage/ipc/signalfuncs.c @@ -312,29 +312,44 @@ pg_print_backtrace(PG_FUNCTION_ARGS) #ifdef HAVE_BACKTRACE_SYMBOLS int pid = PG_GETARG_INT32(0); PGPROC *proc; + PGPROC *aux_proc = NULL; + BackendId backendId = InvalidBackendId; /* - * 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 CPU cycles, that it might - * end on its own first and its backtrace are not logged is not a problem. + * BackendPidGetProc or AuxiliaryPidGetProc 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 CPU cycles, that it might end on its own first and its backtrace are + * not logged is not a problem. */ proc = BackendPidGetProc(pid); if (proc == NULL) { - ereport(WARNING, - (errmsg("PID %d is not a PostgreSQL server process", pid))); - PG_RETURN_BOOL(false); + /* See if the process with given pid is an auxiliary process. */ + aux_proc = AuxiliaryPidGetProc(pid); + if (aux_proc == NULL) + { + ereport(WARNING, + (errmsg("PID %d is not a PostgreSQL server process", pid))); + PG_RETURN_BOOL(false); + } } + /* + * Only regular backends will have valid backend id, auxiliary processes + * don't. + */ + if (!aux_proc) + backendId = proc->backendId; + /* * Send SIGUSR1 to postgres backend whose pid matches pid by * setting PROCSIG_PRINT_BACKTRACE, the backend process will print * the backtrace once the signal is received. */ - if (!SendProcSignal(pid, PROCSIG_PRINT_BACKTRACE, proc->backendId)) + if (!SendProcSignal(pid, PROCSIG_PRINT_BACKTRACE, backendId)) PG_RETURN_BOOL(true); else ereport(WARNING, diff --git a/src/test/regress/expected/misc_functions.out b/src/test/regress/expected/misc_functions.out index c75cef00e7..765a94abf5 100644 --- a/src/test/regress/expected/misc_functions.out +++ b/src/test/regress/expected/misc_functions.out @@ -189,6 +189,17 @@ SELECT pg_print_backtrace(pg_backend_pid()); t (1 row) +CREATE FUNCTION get_proc_pid(text) +RETURNS int +LANGUAGE SQL +AS 'SELECT pid FROM pg_stat_activity WHERE backend_type = $1'; +SELECT pg_print_backtrace(get_proc_pid('checkpointer')); + pg_print_backtrace +-------------------- + t +(1 row) + +DROP FUNCTION get_proc_pid(text); CREATE ROLE regress_print_backtrace; SELECT has_function_privilege('regress_print_backtrace', 'pg_print_backtrace(integer)', 'EXECUTE'); -- no diff --git a/src/test/regress/sql/misc_functions.sql b/src/test/regress/sql/misc_functions.sql index d63d2e2ddb..bb1d02f143 100644 --- a/src/test/regress/sql/misc_functions.sql +++ b/src/test/regress/sql/misc_functions.sql @@ -72,6 +72,15 @@ DROP ROLE regress_log_memory; SELECT pg_print_backtrace(pg_backend_pid()); +CREATE FUNCTION get_proc_pid(text) +RETURNS int +LANGUAGE SQL +AS 'SELECT pid FROM pg_stat_activity WHERE backend_type = $1'; + +SELECT pg_print_backtrace(get_proc_pid('checkpointer')); + +DROP FUNCTION get_proc_pid(text); + CREATE ROLE regress_print_backtrace; SELECT has_function_privilege('regress_print_backtrace', -- 2.30.2