From dda8560aa4034dee9e5dde7177ad265f58b3feb7 Mon Sep 17 00:00:00 2001 From: Vigneshwaran C Date: Mon, 15 Nov 2021 09:28:47 +0530 Subject: [PATCH v12 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 | 25 ++++++++------ 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/procsignal.c | 5 ++- src/backend/storage/ipc/signalfuncs.c | 35 ++++++++++++++------ src/test/regress/expected/misc_functions.out | 11 ++++++ src/test/regress/sql/misc_functions.sql | 9 +++++ 10 files changed, 82 insertions(+), 23 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 8d147825eb..8098246897 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -25355,19 +25355,24 @@ SELECT collation for ('foo' COLLATE "de_DE"); Requests to log the backtrace of the - backend - with the specified process ID. The backtrace will be logged at message - level LOG. It will appear in the server log based on - the log configuration set (See - for more information), but will not be sent to the client regardless of + backend or the + WAL sender or the + auxiliary process + with the specified process ID. All of the + auxiliary processes + are supported except the logger + and the statistics collector + as they are not connected to shared memory the function can not make requests. + The backtrace will be logged at LOG message level. + They will appear in the server log based on the log configuration set + (See for more information), + but will not be sent to the client regardless of . 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 emit a warning - and return false. + This feature will be available if PostgreSQL was built with the + ability to capture backtrace. If not available, the function will emit + a warning and return false. 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 3b33e01d95..e6b38572bf 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -856,4 +856,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/procsignal.c b/src/backend/storage/ipc/procsignal.c index 80fa6d4990..9151e4cf81 100644 --- a/src/backend/storage/ipc/procsignal.c +++ b/src/backend/storage/ipc/procsignal.c @@ -632,9 +632,8 @@ HandlePrintBacktraceInterrupt(void) * backend process. * * Any backend that participates in ProcSignal signaling must arrange - * to call this function if we see PrintBacktracePending set. - * It is called from CHECK_FOR_INTERRUPTS(), which is enough because - * the target process for logging of backtrace is a backend. + * to call this function if we see PrintBacktracePending set. It is called from + * CHECK_FOR_INTERRUPTS() or from process specific interrupt handlers. */ void ProcessPrintBacktraceInterrupt(void) diff --git a/src/backend/storage/ipc/signalfuncs.c b/src/backend/storage/ipc/signalfuncs.c index df942d6015..e59a010279 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