From 73142adf6e56e44d97bd9f855072cba17ef5ea4c Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Thu, 31 Aug 2017 12:24:47 -0400 Subject: [PATCH v2] Add background worker type Add bgw_type field to background worker structure. It is intended to be set to the same value for all workers of the same type, so they can be grouped in pg_stat_activity, for example. The backend_type column in pg_stat_activity now shows bgw_type for a background worker. The ps listing and some log messages no longer call out that a process is a "background worker" but just show the bgw_type. That way, being a background worker is effectively an implementation detail now that is not shown to the user. --- contrib/pg_prewarm/autoprewarm.c | 6 ++-- doc/src/sgml/bgworker.sgml | 12 +++++-- src/backend/access/transam/parallel.c | 1 + src/backend/postmaster/bgworker.c | 53 +++++++++++++++++++++++++++--- src/backend/postmaster/postmaster.c | 10 ++---- src/backend/replication/logical/launcher.c | 3 ++ src/backend/utils/adt/pgstatfuncs.c | 16 +++++++-- src/include/postmaster/bgworker.h | 2 ++ src/test/modules/test_shm_mq/setup.c | 2 +- src/test/modules/worker_spi/worker_spi.c | 8 +++-- 10 files changed, 91 insertions(+), 22 deletions(-) diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c index cc0350e6d6..006c3153db 100644 --- a/contrib/pg_prewarm/autoprewarm.c +++ b/contrib/pg_prewarm/autoprewarm.c @@ -800,7 +800,8 @@ apw_start_master_worker(void) worker.bgw_start_time = BgWorkerStart_ConsistentState; strcpy(worker.bgw_library_name, "pg_prewarm"); strcpy(worker.bgw_function_name, "autoprewarm_main"); - strcpy(worker.bgw_name, "autoprewarm"); + strcpy(worker.bgw_name, "autoprewarm master"); + strcpy(worker.bgw_type, "autoprewarm master"); if (process_shared_preload_libraries_in_progress) { @@ -840,7 +841,8 @@ apw_start_database_worker(void) worker.bgw_start_time = BgWorkerStart_ConsistentState; strcpy(worker.bgw_library_name, "pg_prewarm"); strcpy(worker.bgw_function_name, "autoprewarm_database_main"); - strcpy(worker.bgw_name, "autoprewarm"); + strcpy(worker.bgw_name, "autoprewarm worker"); + strcpy(worker.bgw_type, "autoprewarm worker"); /* must set notify PID to wait for shutdown */ worker.bgw_notify_pid = MyProcPid; diff --git a/doc/src/sgml/bgworker.sgml b/doc/src/sgml/bgworker.sgml index b422323081..822632bf02 100644 --- a/doc/src/sgml/bgworker.sgml +++ b/doc/src/sgml/bgworker.sgml @@ -51,6 +51,7 @@ Background Worker Processes typedef struct BackgroundWorker { char bgw_name[BGW_MAXLEN]; + char bgw_type[BGW_MAXLEN]; int bgw_flags; BgWorkerStartTime bgw_start_time; int bgw_restart_time; /* in seconds, or BGW_NEVER_RESTART */ @@ -64,8 +65,15 @@ Background Worker Processes - bgw_name is a string to be used in log messages, process - listings and similar contexts. + bgw_name and bgw_type are + strings to be used in log messages, process listings and similar contexts. + bgw_type should be the same for all background + workers of the same type, so that it is possible to group such workers in a + process listing, for example. bgw_name on the + other hand can contain additional information about the specific process. + (Typically, the string for bgw_name will contain + the string for bgw_type somehow, but that is not + strictly required.) diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c index 17b10383e4..9828259e6d 100644 --- a/src/backend/access/transam/parallel.c +++ b/src/backend/access/transam/parallel.c @@ -438,6 +438,7 @@ LaunchParallelWorkers(ParallelContext *pcxt) memset(&worker, 0, sizeof(worker)); snprintf(worker.bgw_name, BGW_MAXLEN, "parallel worker for PID %d", MyProcPid); + snprintf(worker.bgw_type, BGW_MAXLEN, "parallel worker"); worker.bgw_flags = BGWORKER_SHMEM_ACCESS | BGWORKER_BACKEND_DATABASE_CONNECTION | BGWORKER_CLASS_PARALLEL; diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index 28af6f0f07..da7d12d91a 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -344,6 +344,8 @@ BackgroundWorkerStateChange(void) */ ascii_safe_strlcpy(rw->rw_worker.bgw_name, slot->worker.bgw_name, BGW_MAXLEN); + ascii_safe_strlcpy(rw->rw_worker.bgw_type, + slot->worker.bgw_type, BGW_MAXLEN); ascii_safe_strlcpy(rw->rw_worker.bgw_library_name, slot->worker.bgw_library_name, BGW_MAXLEN); ascii_safe_strlcpy(rw->rw_worker.bgw_function_name, @@ -630,6 +632,12 @@ SanityCheckBackgroundWorker(BackgroundWorker *worker, int elevel) return false; } + /* + * If bgw_type is not filled in, use bgw_name. + */ + if (strcmp(worker->bgw_type, "") == 0) + strcpy(worker->bgw_type, worker->bgw_name); + return true; } @@ -670,8 +678,8 @@ bgworker_die(SIGNAL_ARGS) ereport(FATAL, (errcode(ERRCODE_ADMIN_SHUTDOWN), - errmsg("terminating background worker \"%s\" due to administrator command", - MyBgworkerEntry->bgw_name))); + errmsg("terminating %s due to administrator command", + MyBgworkerEntry->bgw_type))); } /* @@ -700,7 +708,6 @@ void StartBackgroundWorker(void) { sigjmp_buf local_sigjmp_buf; - char buf[MAXPGPATH]; BackgroundWorker *worker = MyBgworkerEntry; bgworker_main_type entrypt; @@ -710,8 +717,7 @@ StartBackgroundWorker(void) IsBackgroundWorker = true; /* Identify myself via ps */ - snprintf(buf, MAXPGPATH, "bgworker: %s", worker->bgw_name); - init_ps_display(buf, "", "", ""); + init_ps_display(worker->bgw_name, "", "", ""); /* * If we're not supposed to have shared memory access, then detach from @@ -1233,3 +1239,40 @@ LookupBackgroundWorkerFunction(const char *libraryname, const char *funcname) return (bgworker_main_type) load_external_function(libraryname, funcname, true, NULL); } + +/* + * Given a PID, get the bgw_type of the background worker. Returns NULL if + * not a valid background worker. + * + * The return value is in static memory belonging to this function, so it has + * to be used before calling this function again. This is so that the caller + * doesn't have to worry about the background worker locking protocol. + */ +const char * +GetBackgroundWorkerTypeByPid(pid_t pid) +{ + int slotno; + bool found = false; + static char result[BGW_MAXLEN]; + + LWLockAcquire(BackgroundWorkerLock, LW_SHARED); + + for (slotno = 0; slotno < BackgroundWorkerData->total_slots; slotno++) + { + BackgroundWorkerSlot *slot = &BackgroundWorkerData->slot[slotno]; + + if (slot->pid > 0 && slot->pid == pid) + { + strcpy(result, slot->worker.bgw_type); + found = true; + break; + } + } + + LWLockRelease(BackgroundWorkerLock); + + if (!found) + return NULL; + + return result; +} diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 95180b2ef5..cf4bffa8b3 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -3096,7 +3096,6 @@ static bool CleanupBackgroundWorker(int pid, int exitstatus) /* child's exit status */ { - char namebuf[MAXPGPATH]; slist_mutable_iter iter; slist_foreach_modify(iter, &BackgroundWorkerList) @@ -3114,9 +3113,6 @@ CleanupBackgroundWorker(int pid, exitstatus = 0; #endif - snprintf(namebuf, MAXPGPATH, "%s: %s", _("worker process"), - rw->rw_worker.bgw_name); - if (!EXIT_STATUS_0(exitstatus)) { /* Record timestamp, so we know when to restart the worker. */ @@ -3138,7 +3134,7 @@ CleanupBackgroundWorker(int pid, { if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_1(exitstatus)) { - HandleChildCrash(pid, exitstatus, namebuf); + HandleChildCrash(pid, exitstatus, rw->rw_worker.bgw_name); return true; } } @@ -3151,7 +3147,7 @@ CleanupBackgroundWorker(int pid, if (!ReleasePostmasterChildSlot(rw->rw_child_slot) && (rw->rw_worker.bgw_flags & BGWORKER_SHMEM_ACCESS) != 0) { - HandleChildCrash(pid, exitstatus, namebuf); + HandleChildCrash(pid, exitstatus, rw->rw_worker.bgw_name); return true; } @@ -3176,7 +3172,7 @@ CleanupBackgroundWorker(int pid, ReportBackgroundWorkerExit(&iter); /* report child death */ LogChildExit(EXIT_STATUS_0(exitstatus) ? DEBUG1 : LOG, - namebuf, pid, exitstatus); + rw->rw_worker.bgw_name, pid, exitstatus); return true; } diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c index 6c894421a3..cf5f02aef8 100644 --- a/src/backend/replication/logical/launcher.c +++ b/src/backend/replication/logical/launcher.c @@ -421,6 +421,7 @@ logicalrep_worker_launch(Oid dbid, Oid subid, const char *subname, Oid userid, else snprintf(bgw.bgw_name, BGW_MAXLEN, "logical replication worker for subscription %u", subid); + snprintf(bgw.bgw_type, BGW_MAXLEN, "logical replication worker"); bgw.bgw_restart_time = BGW_NEVER_RESTART; bgw.bgw_notify_pid = MyProcPid; @@ -768,6 +769,8 @@ ApplyLauncherRegister(void) snprintf(bgw.bgw_function_name, BGW_MAXLEN, "ApplyLauncherMain"); snprintf(bgw.bgw_name, BGW_MAXLEN, "logical replication launcher"); + snprintf(bgw.bgw_type, BGW_MAXLEN, + "logical replication launcher"); bgw.bgw_restart_time = 5; bgw.bgw_notify_pid = 0; bgw.bgw_main_arg = (Datum) 0; diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 20ce48b2d8..dd5898ec0a 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -21,6 +21,7 @@ #include "funcapi.h" #include "miscadmin.h" #include "pgstat.h" +#include "postmaster/bgworker_internals.h" #include "postmaster/postmaster.h" #include "storage/proc.h" #include "storage/procarray.h" @@ -820,8 +821,19 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) } } /* Add backend type */ - values[17] = - CStringGetTextDatum(pgstat_get_backend_desc(beentry->st_backendType)); + if (beentry->st_backendType == B_BG_WORKER) + { + const char *bgw_type; + + bgw_type = GetBackgroundWorkerTypeByPid(beentry->st_procpid); + if (bgw_type) + values[17] = CStringGetTextDatum(bgw_type); + else + nulls[17] = true; + } + else + values[17] = + CStringGetTextDatum(pgstat_get_backend_desc(beentry->st_backendType)); } else { diff --git a/src/include/postmaster/bgworker.h b/src/include/postmaster/bgworker.h index e2ecd3c9eb..6b4e631880 100644 --- a/src/include/postmaster/bgworker.h +++ b/src/include/postmaster/bgworker.h @@ -88,6 +88,7 @@ typedef enum typedef struct BackgroundWorker { char bgw_name[BGW_MAXLEN]; + char bgw_type[BGW_MAXLEN]; int bgw_flags; BgWorkerStartTime bgw_start_time; int bgw_restart_time; /* in seconds, or BGW_NEVER_RESTART */ @@ -122,6 +123,7 @@ extern BgwHandleStatus GetBackgroundWorkerPid(BackgroundWorkerHandle *handle, extern BgwHandleStatus WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *pid); extern BgwHandleStatus WaitForBackgroundWorkerShutdown(BackgroundWorkerHandle *); +extern const char *GetBackgroundWorkerTypeByPid(pid_t pid); /* Terminate a bgworker */ extern void TerminateBackgroundWorker(BackgroundWorkerHandle *handle); diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c index 3ae9018360..561f6f9bac 100644 --- a/src/test/modules/test_shm_mq/setup.c +++ b/src/test/modules/test_shm_mq/setup.c @@ -219,7 +219,7 @@ setup_background_workers(int nworkers, dsm_segment *seg) worker.bgw_restart_time = BGW_NEVER_RESTART; sprintf(worker.bgw_library_name, "test_shm_mq"); sprintf(worker.bgw_function_name, "test_shm_mq_main"); - snprintf(worker.bgw_name, BGW_MAXLEN, "test_shm_mq"); + snprintf(worker.bgw_type, BGW_MAXLEN, "test_shm_mq"); worker.bgw_main_arg = UInt32GetDatum(dsm_segment_handle(seg)); /* set bgw_notify_pid, so we can detect if the worker stops */ worker.bgw_notify_pid = MyProcPid; diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c index 12c8cd5774..4c6ab6d575 100644 --- a/src/test/modules/worker_spi/worker_spi.c +++ b/src/test/modules/worker_spi/worker_spi.c @@ -111,7 +111,7 @@ initialize_worker_spi(worktable *table) StartTransactionCommand(); SPI_connect(); PushActiveSnapshot(GetTransactionSnapshot()); - pgstat_report_activity(STATE_RUNNING, "initializing spi_worker schema"); + pgstat_report_activity(STATE_RUNNING, "initializing worker_spi schema"); /* XXX could we use CREATE SCHEMA IF NOT EXISTS? */ initStringInfo(&buf); @@ -359,7 +359,8 @@ _PG_init(void) */ for (i = 1; i <= worker_spi_total_workers; i++) { - snprintf(worker.bgw_name, BGW_MAXLEN, "worker %d", i); + snprintf(worker.bgw_name, BGW_MAXLEN, "worker_spi worker %d", i); + snprintf(worker.bgw_type, BGW_MAXLEN, "worker_spi"); worker.bgw_main_arg = Int32GetDatum(i); RegisterBackgroundWorker(&worker); @@ -385,7 +386,8 @@ worker_spi_launch(PG_FUNCTION_ARGS) worker.bgw_restart_time = BGW_NEVER_RESTART; sprintf(worker.bgw_library_name, "worker_spi"); sprintf(worker.bgw_function_name, "worker_spi_main"); - snprintf(worker.bgw_name, BGW_MAXLEN, "worker %d", i); + snprintf(worker.bgw_name, BGW_MAXLEN, "worker_spi worker %d", i); + snprintf(worker.bgw_type, BGW_MAXLEN, "worker_spi"); worker.bgw_main_arg = Int32GetDatum(i); /* set bgw_notify_pid so that we can use WaitForBackgroundWorkerStartup */ worker.bgw_notify_pid = MyProcPid; base-commit: b5c75feca7ffb2667c42b86286e262d6cb709b76 -- 2.14.1