On Tue, Mar 17, 2020 at 02:50:19PM -0400, Mike Palmiotto wrote: > The patchset is now split out. I've just noticed that Peter Eisentraut > included some changes for a generic MyBackendType, which I should have > been aware of. I was unable to rebase due to these changes, but can > fold these patches into that framework if others think it's > worthwhile.
I don't have many comments on the patch, but it's easy enough to rebase. I think maybe you'll want to do something more with this new function: GetBackendTypeDesc() + /* Don't panic. */ +1 -- Justin
>From 4234a083913d93b27cd6763f41c092adc8d4cf6c Mon Sep 17 00:00:00 2001 From: Mike Palmiotto <mike.palmio...@crunchydata.com> Date: Mon, 9 Mar 2020 22:12:10 +0000 Subject: [PATCH v2 01/12] Add subprocess infrastructure This commit introduces a new infrastructure for postmaster subprocesses initialization, forking, exec'ing and main function control. The intent is to have all subprocess control information live in the process_types struct, defined in subprocess.h. As more processes are added to the struct, the fields will be expanded to differentiate actions. There are several advantages to such an infrastructure: 1) Centralized definition of subprocess information 2) Standardized function arguments/naming schemes 3) Code minimization and removal of duplicate code --- src/backend/bootstrap/bootstrap.c | 74 +++++++-------------------- src/backend/postmaster/Makefile | 1 + src/backend/postmaster/bgwriter.c | 2 +- src/backend/postmaster/checkpointer.c | 2 +- src/backend/postmaster/startup.c | 3 +- src/backend/postmaster/subprocess.c | 62 ++++++++++++++++++++++ src/backend/postmaster/walwriter.c | 2 +- src/backend/replication/walreceiver.c | 2 +- src/include/bootstrap/bootstrap.h | 3 +- src/include/postmaster/bgwriter.h | 4 +- src/include/postmaster/startup.h | 5 +- src/include/postmaster/subprocess.h | 44 ++++++++++++++++ src/include/postmaster/walwriter.h | 2 +- src/include/replication/walreceiver.h | 2 +- 14 files changed, 140 insertions(+), 68 deletions(-) create mode 100644 src/backend/postmaster/subprocess.c create mode 100644 src/include/postmaster/subprocess.h diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index 5480a024e0..9d41567467 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -35,6 +35,7 @@ #include "pgstat.h" #include "postmaster/bgwriter.h" #include "postmaster/startup.h" +#include "postmaster/subprocess.h" #include "postmaster/walwriter.h" #include "replication/walreceiver.h" #include "storage/bufmgr.h" @@ -56,8 +57,6 @@ uint32 bootstrap_data_checksum_version = 0; /* No checksum */ #define ALLOC(t, c) \ ((t *) MemoryContextAllocZero(TopMemoryContext, (unsigned)(c) * sizeof(t))) -static void CheckerModeMain(void); -static void BootstrapModeMain(void); static void bootstrap_signals(void); static void ShutdownAuxiliaryProcess(int code, Datum arg); static Form_pg_attribute AllocateAttribute(void); @@ -334,6 +333,12 @@ AuxiliaryProcessMain(int argc, char *argv[]) default: MyBackendType = B_INVALID; } + + /* + * We've read the arguments and know what backend type we are. + */ + InitMySubprocess((SubprocessType)MyAuxProcType); + if (IsUnderPostmaster) init_ps_display(NULL); @@ -418,56 +423,10 @@ AuxiliaryProcessMain(int argc, char *argv[]) */ SetProcessingMode(NormalProcessing); - switch (MyAuxProcType) - { - case CheckerProcess: - /* don't set signals, they're useless here */ - CheckerModeMain(); - proc_exit(1); /* should never return */ - - case BootstrapProcess: - - /* - * There was a brief instant during which mode was Normal; this is - * okay. We need to be in bootstrap mode during BootStrapXLOG for - * the sake of multixact initialization. - */ - SetProcessingMode(BootstrapProcessing); - bootstrap_signals(); - BootStrapXLOG(); - BootstrapModeMain(); - proc_exit(1); /* should never return */ - - case StartupProcess: - /* don't set signals, startup process has its own agenda */ - StartupProcessMain(); - proc_exit(1); /* should never return */ - - case BgWriterProcess: - /* don't set signals, bgwriter has its own agenda */ - BackgroundWriterMain(); - proc_exit(1); /* should never return */ - - case CheckpointerProcess: - /* don't set signals, checkpointer has its own agenda */ - CheckpointerMain(); - proc_exit(1); /* should never return */ - - case WalWriterProcess: - /* don't set signals, walwriter has its own agenda */ - InitXLOGAccess(); - WalWriterMain(); - proc_exit(1); /* should never return */ - - case WalReceiverProcess: - /* don't set signals, walreceiver has its own agenda */ - WalReceiverMain(); - proc_exit(1); /* should never return */ + /* Now jump into the subprocess main function and never look back! */ + MySubprocess->entrypoint(argc, argv); - default: - elog(PANIC, "unrecognized process type: %d", (int) MyAuxProcType); - proc_exit(1); - } + proc_exit(1); /* should never return */ } /* @@ -476,8 +435,8 @@ AuxiliaryProcessMain(int argc, char *argv[]) * settings). Since, in fact, that was already done by BaseInit(), * we have nothing more to do here. */ -static void -CheckerModeMain(void) +void +CheckerModeMain(int argc, char *argv[]) { proc_exit(0); } @@ -489,11 +448,15 @@ CheckerModeMain(void) * The bootstrap backend doesn't speak SQL, but instead expects * commands in a special bootstrap language. */ -static void -BootstrapModeMain(void) +void +BootstrapModeMain(int argc, char *argv[]) { int i; + SetProcessingMode(BootstrapProcessing); + bootstrap_signals(); + BootStrapXLOG(); + Assert(!IsUnderPostmaster); Assert(IsBootstrapProcessingMode()); @@ -508,7 +471,6 @@ BootstrapModeMain(void) * Do backend-like initialization for bootstrap mode */ InitProcess(); - InitPostgres(NULL, InvalidOid, NULL, InvalidOid, NULL, false); /* Initialize stuff for bootstrap-file processing */ diff --git a/src/backend/postmaster/Makefile b/src/backend/postmaster/Makefile index bfdf6a833d..52b4c2142c 100644 --- a/src/backend/postmaster/Makefile +++ b/src/backend/postmaster/Makefile @@ -23,6 +23,7 @@ OBJS = \ pgstat.o \ postmaster.o \ startup.o \ + subprocess.o \ syslogger.o \ walwriter.o diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c index 069e27e427..b2170938f3 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -91,7 +91,7 @@ static XLogRecPtr last_snapshot_lsn = InvalidXLogRecPtr; * basic execution environment, but not enabled signals yet. */ void -BackgroundWriterMain(void) +BackgroundWriterMain(int argc, char *argv[]) { sigjmp_buf local_sigjmp_buf; MemoryContext bgwriter_context; diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index e354a78725..83f7be1b1e 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -180,7 +180,7 @@ static void ReqCheckpointHandler(SIGNAL_ARGS); * basic execution environment, but not enabled signals yet. */ void -CheckpointerMain(void) +CheckpointerMain(int argc, char *argv[]) { sigjmp_buf local_sigjmp_buf; MemoryContext checkpointer_context; diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c index c2250d7d4e..e29649a6a1 100644 --- a/src/backend/postmaster/startup.c +++ b/src/backend/postmaster/startup.c @@ -127,13 +127,12 @@ HandleStartupProcInterrupts(void) ProcessProcSignalBarrier(); } - /* ---------------------------------- * Startup Process main entry point * ---------------------------------- */ void -StartupProcessMain(void) +StartupProcessMain(int argc, char *argv[]) { /* * Properly accept or ignore signals the postmaster might send us. diff --git a/src/backend/postmaster/subprocess.c b/src/backend/postmaster/subprocess.c new file mode 100644 index 0000000000..3e7a45bf10 --- /dev/null +++ b/src/backend/postmaster/subprocess.c @@ -0,0 +1,62 @@ +/*------------------------------------------------------------------------- + * + * subprocess.c + * + * Copyright (c) 2004-2020, PostgreSQL Global Development Group + * + * + * IDENTIFICATION + * src/backend/postmaster/syslogger.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" +#include "bootstrap/bootstrap.h" +#include "postmaster/bgwriter.h" +#include "postmaster/postmaster.h" +#include "postmaster/startup.h" +#include "postmaster/subprocess.h" +#include "postmaster/walwriter.h" +#include "replication/walreceiver.h" + +SubprocessType MySubprocessType; +PgSubprocess *MySubprocess; + +static PgSubprocess process_types[] = { + { + .desc = "checker", + .entrypoint = CheckerModeMain + }, + { + .desc = "bootstrap", + .entrypoint = BootstrapModeMain + }, + { + .desc = "startup", + .entrypoint = StartupProcessMain + }, + { + .desc = "background writer", + .entrypoint = BackgroundWriterMain + }, + { + .desc = "checkpointer", + .entrypoint = CheckpointerMain + }, + { + .desc = "wal writer", + .entrypoint = WalWriterMain + }, + { + .desc = "wal receiver", + .entrypoint = WalReceiverMain + } +}; + +void +InitMySubprocess(SubprocessType type) +{ + MySubprocessType = type; + MySubprocess = &process_types[type]; + MySubprocess->desc = gettext(MySubprocess->desc); +} diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c index 45a2757969..3a0cec3371 100644 --- a/src/backend/postmaster/walwriter.c +++ b/src/backend/postmaster/walwriter.c @@ -85,7 +85,7 @@ int WalWriterFlushAfter = 128; * basic execution environment, but not enabled signals yet. */ void -WalWriterMain(void) +WalWriterMain(int argc, char *argv[]) { sigjmp_buf local_sigjmp_buf; MemoryContext walwriter_context; diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 25e0333c9e..cd39a8c982 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -165,7 +165,7 @@ ProcessWalRcvInterrupts(void) /* Main entry point for walreceiver process */ void -WalReceiverMain(void) +WalReceiverMain(int argc, char *argv[]) { char conninfo[MAXCONNINFO]; char *tmp_conninfo; diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h index b67fa9acc1..f85cfb5202 100644 --- a/src/include/bootstrap/bootstrap.h +++ b/src/include/bootstrap/bootstrap.h @@ -16,7 +16,6 @@ #include "nodes/execnodes.h" - /* * MAXATTR is the maximum number of attributes in a relation supported * at bootstrap time (i.e., the max possible in a system table). @@ -31,6 +30,8 @@ extern Relation boot_reldesc; extern Form_pg_attribute attrtypes[MAXATTR]; extern int numattr; +extern void CheckerModeMain(int argc, char *argv[]); +extern void BootstrapModeMain(int argc, char *argv[]); extern void AuxiliaryProcessMain(int argc, char *argv[]) pg_attribute_noreturn(); diff --git a/src/include/postmaster/bgwriter.h b/src/include/postmaster/bgwriter.h index 0a5708b32e..6fb1ee1d6d 100644 --- a/src/include/postmaster/bgwriter.h +++ b/src/include/postmaster/bgwriter.h @@ -27,8 +27,8 @@ extern int CheckPointTimeout; extern int CheckPointWarning; extern double CheckPointCompletionTarget; -extern void BackgroundWriterMain(void) pg_attribute_noreturn(); -extern void CheckpointerMain(void) pg_attribute_noreturn(); +extern void BackgroundWriterMain(int argc, char *argv[]) pg_attribute_noreturn(); +extern void CheckpointerMain(int argc, char *argv[]) pg_attribute_noreturn(); extern void RequestCheckpoint(int flags); extern void CheckpointWriteDelay(int flags, double progress); diff --git a/src/include/postmaster/startup.h b/src/include/postmaster/startup.h index 9f59c1ffa3..6a8108dfe0 100644 --- a/src/include/postmaster/startup.h +++ b/src/include/postmaster/startup.h @@ -13,10 +13,13 @@ #define _STARTUP_H extern void HandleStartupProcInterrupts(void); -extern void StartupProcessMain(void) pg_attribute_noreturn(); extern void PreRestoreCommand(void); extern void PostRestoreCommand(void); extern bool IsPromoteTriggered(void); extern void ResetPromoteTriggered(void); +/* Startup subprocess functions */ +extern void StartupProcessMain(int argc, char *argv[]) pg_attribute_noreturn(); +extern bool StartupCleanup(int child_errno); + #endif /* _STARTUP_H */ diff --git a/src/include/postmaster/subprocess.h b/src/include/postmaster/subprocess.h new file mode 100644 index 0000000000..56e8edf2d8 --- /dev/null +++ b/src/include/postmaster/subprocess.h @@ -0,0 +1,44 @@ +/*------------------------------------------------------------------------- + * + * subprocess.h + * + * Copyright (c) 1996-2020, PostgreSQL Global Development Group + * + * src/include/postmaster/subprocess.h + * + *------------------------------------------------------------------------- + */ +#ifndef SUBPROCESS_H +#define SUBPROCESS_H + +#include "postmaster.h" + +typedef enum +{ + NoProcessType = -1, + CheckerType = 0, + BootstrapType, + StartupType, + BgWriterType, + CheckpointerType, + WalWriterType, + WalReceiverType, /* end of Auxiliary Process Forks */ + + NUMSUBPROCESSTYPES /* Must be last! */ +} SubprocessType; + +typedef void (*SubprocessEntryPoint) (int argc, char *argv[]); + +/* Current subprocess initializer */ +extern void InitMySubprocess(SubprocessType type); + +typedef struct PgSubprocess +{ + const char *desc; + SubprocessEntryPoint entrypoint; +} PgSubprocess; + +extern SubprocessType MySubprocessType; +extern PGDLLIMPORT PgSubprocess *MySubprocess; + +#endif /* SUBPROCESS_H */ diff --git a/src/include/postmaster/walwriter.h b/src/include/postmaster/walwriter.h index 011dc26a6e..596c437c54 100644 --- a/src/include/postmaster/walwriter.h +++ b/src/include/postmaster/walwriter.h @@ -16,6 +16,6 @@ extern int WalWriterDelay; extern int WalWriterFlushAfter; -extern void WalWriterMain(void) pg_attribute_noreturn(); +extern void WalWriterMain(int argc, char *argv[]) pg_attribute_noreturn(); #endif /* _WALWRITER_H */ diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h index e08afc6548..2025f19ab3 100644 --- a/src/include/replication/walreceiver.h +++ b/src/include/replication/walreceiver.h @@ -311,7 +311,7 @@ walrcv_clear_result(WalRcvExecResult *walres) } /* prototypes for functions in walreceiver.c */ -extern void WalReceiverMain(void) pg_attribute_noreturn(); +extern void WalReceiverMain(int argc, char *argv[]); extern void ProcessWalRcvInterrupts(void); /* prototypes for functions in walreceiverfuncs.c */ -- 2.17.0
>From e468f43243a3a82ea3a5b782a0bda3ed42c1286a Mon Sep 17 00:00:00 2001 From: Mike Palmiotto <mike.palmio...@crunchydata.com> Date: Tue, 10 Mar 2020 14:58:07 +0000 Subject: [PATCH v2 02/12] Use centralized StartSubprocess for aux procs Modifies StartChildProcess and moves the auxiliary processes under its control. This is the next step toward making use of the Subprocess infrastructure. This patch introduces the fork_failure function, which may be implemented by each subprocess to control failure when attempting to fork the subprocess. This is used by the startup subprocess to exit postmaster on fork failure. Future subprocesses may use it to do cleanup (and optionally exit postmaster) after a fork failure. Additionally, the patch adds a new backend variable for establishing a backend variable to be shared across fork/exec. --- src/backend/postmaster/postmaster.c | 156 ++++++++++++++-------------- src/backend/postmaster/startup.c | 12 +++ src/backend/postmaster/subprocess.c | 35 +++++-- src/include/postmaster/startup.h | 2 +- src/include/postmaster/subprocess.h | 4 + 5 files changed, 121 insertions(+), 88 deletions(-) diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 2b9ab32293..4b86aeec2d 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -114,6 +114,7 @@ #include "postmaster/fork_process.h" #include "postmaster/pgarch.h" #include "postmaster/postmaster.h" +#include "postmaster/subprocess.h" #include "postmaster/syslogger.h" #include "replication/logicallauncher.h" #include "replication/walsender.h" @@ -191,7 +192,8 @@ static Backend *ShmemBackendArray; BackgroundWorker *MyBgworkerEntry = NULL; - +/* Struct containing postmaster subprocess control info */ +SubprocessType MySubprocessType; /* The socket number we are listening for connections on */ int PostPortNumber; @@ -421,7 +423,7 @@ static int CountChildren(int target); static bool assign_backendlist_entry(RegisteredBgWorker *rw); static void maybe_start_bgworkers(void); static bool CreateOptsFile(int argc, char *argv[], char *fullprogname); -static pid_t StartChildProcess(AuxProcType type); +static pid_t StartSubprocess(SubprocessType type); static void StartAutovacuumWorker(void); static void MaybeStartWalReceiver(void); static void InitPostmasterDeathWatchHandle(void); @@ -507,6 +509,9 @@ typedef struct TimestampTz PgStartTime; TimestampTz PgReloadTime; pg_time_t first_syslogger_file_time; + + SubprocessType MySubprocessType; + bool redirection_done; bool IsBinaryUpgrade; int max_safe_fds; @@ -538,11 +543,6 @@ static void ShmemBackendArrayAdd(Backend *bn); static void ShmemBackendArrayRemove(Backend *bn); #endif /* EXEC_BACKEND */ -#define StartupDataBase() StartChildProcess(StartupProcess) -#define StartBackgroundWriter() StartChildProcess(BgWriterProcess) -#define StartCheckpointer() StartChildProcess(CheckpointerProcess) -#define StartWalWriter() StartChildProcess(WalWriterProcess) -#define StartWalReceiver() StartChildProcess(WalReceiverProcess) /* Macros to check exit status of a child process */ #define EXIT_STATUS_0(st) ((st) == 0) @@ -1389,7 +1389,7 @@ PostmasterMain(int argc, char *argv[]) /* * We're ready to rock and roll... */ - StartupPID = StartupDataBase(); + StartupPID = StartSubprocess(StartupType); Assert(StartupPID != 0); StartupStatus = STARTUP_RUNNING; pmState = PM_STARTUP; @@ -1750,9 +1750,9 @@ ServerLoop(void) pmState == PM_HOT_STANDBY) { if (CheckpointerPID == 0) - CheckpointerPID = StartCheckpointer(); + CheckpointerPID = StartSubprocess(CheckpointerType); if (BgWriterPID == 0) - BgWriterPID = StartBackgroundWriter(); + BgWriterPID = StartSubprocess(BgWriterType); } /* @@ -1761,7 +1761,7 @@ ServerLoop(void) * be writing any new WAL). */ if (WalWriterPID == 0 && pmState == PM_RUN) - WalWriterPID = StartWalWriter(); + WalWriterPID = StartSubprocess(WalWriterType); /* * If we have lost the autovacuum launcher, try to start a new one. We @@ -3042,11 +3042,11 @@ reaper(SIGNAL_ARGS) * if this fails, we'll just try again later. */ if (CheckpointerPID == 0) - CheckpointerPID = StartCheckpointer(); + CheckpointerPID = StartSubprocess(CheckpointerType); if (BgWriterPID == 0) - BgWriterPID = StartBackgroundWriter(); + BgWriterPID = StartSubprocess(BgWriterType); if (WalWriterPID == 0) - WalWriterPID = StartWalWriter(); + WalWriterPID = StartSubprocess(WalWriterType); /* * Likewise, start other special children as needed. In a restart @@ -3860,7 +3860,7 @@ PostmasterStateMachine(void) Assert(Shutdown > NoShutdown); /* Start the checkpointer if not running */ if (CheckpointerPID == 0) - CheckpointerPID = StartCheckpointer(); + CheckpointerPID = StartSubprocess(CheckpointerType); /* And tell it to shut down */ if (CheckpointerPID != 0) { @@ -4001,7 +4001,7 @@ PostmasterStateMachine(void) reset_shared(); - StartupPID = StartupDataBase(); + StartupPID = StartSubprocess(StartupType); Assert(StartupPID != 0); StartupStatus = STARTUP_RUNNING; pmState = PM_STARTUP; @@ -4917,6 +4917,10 @@ SubPostmasterMain(int argc, char *argv[]) errmsg("out of memory"))); #endif + /* We should only be here once per fork */ + Assert(!MySubprocess); + InitMySubprocess(MySubprocessType); + /* * If appropriate, physically re-attach to shared memory segment. We want * to do this before going any further to ensure that we can attach at the @@ -5037,19 +5041,6 @@ SubPostmasterMain(int argc, char *argv[]) /* And run the backend */ BackendRun(&port); /* does not return */ } - if (strcmp(argv[1], "--forkboot") == 0) - { - /* Restore basic shared memory pointers */ - InitShmemAccess(UsedShmemSegAddr); - - /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */ - InitAuxiliaryProcess(); - - /* Attach process to shared data structures */ - CreateSharedMemoryAndSemaphores(); - - AuxiliaryProcessMain(argc - 2, argv + 2); /* does not return */ - } if (strcmp(argv[1], "--forkavlauncher") == 0) { /* Restore basic shared memory pointers */ @@ -5117,6 +5108,20 @@ SubPostmasterMain(int argc, char *argv[]) SysLoggerMain(argc, argv); /* does not return */ } + if (MySubprocess->needs_aux_proc) + { + /* Restore basic shared memory pointers */ + InitShmemAccess(UsedShmemSegAddr); + + /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */ + InitAuxiliaryProcess(); + + /* Attach process to shared data structures */ + CreateSharedMemoryAndSemaphores(); + + AuxiliaryProcessMain(argc - 2, argv + 2); /* does not return */ + } + abort(); /* shouldn't get here */ } #endif /* EXEC_BACKEND */ @@ -5198,9 +5203,9 @@ sigusr1_handler(SIGNAL_ARGS) * we'll just try again later. */ Assert(CheckpointerPID == 0); - CheckpointerPID = StartCheckpointer(); + CheckpointerPID = StartSubprocess(CheckpointerType); Assert(BgWriterPID == 0); - BgWriterPID = StartBackgroundWriter(); + BgWriterPID = StartSubprocess(BgWriterType); /* * Start the archiver if we're responsible for (re-)archiving received @@ -5425,42 +5430,49 @@ CountChildren(int target) return cnt; } - /* * StartChildProcess -- start an auxiliary process for the postmaster * - * "type" determines what kind of child will be started. All child types - * initially go to AuxiliaryProcessMain, which will handle common setup. + * "type" determines what kind of child will be started. This code relies + * heavily on MySubprocess, which is an entry in the process_types struct in + * subprocess.c. All auxiliary processes go through AuxiliaryProcessMain after + * forking. Everything else goes through the designated entrypoint. * - * Return value of StartChildProcess is subprocess' PID, or 0 if failed - * to start subprocess. + * Return value of StartChildProcess is subprocess' PID on success. On failure, + * the subprocess cleanup function decides whether or not to panic. */ static pid_t -StartChildProcess(AuxProcType type) +StartSubprocess(SubprocessType type) { pid_t pid; - char *av[10]; - int ac = 0; + char *argv[10]; + int argc = 0; char typebuf[32]; +#ifdef EXEC_BACKEND + char forkname[32]; +#endif /* - * Set up command-line arguments for subprocess + * Get new subprocess data every time we start a new subprocess. */ - av[ac++] = "postgres"; + InitMySubprocess(type); + + argv[argc++] = "postgres"; #ifdef EXEC_BACKEND - av[ac++] = "--forkboot"; - av[ac++] = NULL; /* filled in by postmaster_forkexec */ + snprintf(forkname, sizeof(forkname), "--fork%s", MySubprocess->name); + argv[argc++] = forkname; + argv[argc++] = NULL; #endif snprintf(typebuf, sizeof(typebuf), "-x%d", type); - av[ac++] = typebuf; + argv[argc++] = typebuf; - av[ac] = NULL; - Assert(ac < lengthof(av)); + argv[argc] = NULL; + Assert(argc < lengthof(argv)); #ifdef EXEC_BACKEND - pid = postmaster_forkexec(ac, av); + pid = postmaster_forkexec(argc, argv); #else /* !EXEC_BACKEND */ pid = fork_process(); @@ -5476,7 +5488,7 @@ StartChildProcess(AuxProcType type) MemoryContextDelete(PostmasterContext); PostmasterContext = NULL; - AuxiliaryProcessMain(ac, av); + AuxiliaryProcessMain(argc, argv); ExitPostmaster(0); } #endif /* EXEC_BACKEND */ @@ -5487,40 +5499,20 @@ StartChildProcess(AuxProcType type) int save_errno = errno; errno = save_errno; - switch (type) - { - case StartupProcess: - ereport(LOG, - (errmsg("could not fork startup process: %m"))); - break; - case BgWriterProcess: - ereport(LOG, - (errmsg("could not fork background writer process: %m"))); - break; - case CheckpointerProcess: - ereport(LOG, - (errmsg("could not fork checkpointer process: %m"))); - break; - case WalWriterProcess: - ereport(LOG, - (errmsg("could not fork WAL writer process: %m"))); - break; - case WalReceiverProcess: - ereport(LOG, - (errmsg("could not fork WAL receiver process: %m"))); - break; - default: - ereport(LOG, - (errmsg("could not fork process: %m"))); - break; - } + ereport(LOG, + (errmsg("could not fork %s process: %m", MySubprocess->desc))); /* - * fork failure is fatal during startup, but there's no need to choke - * immediately if starting other child types fails. + * Handle fork-failure per subprocess type. Each subprocess handles + * fork-failure by returning a boolean which tells postmaster whether or + * not to panic. */ - if (type == StartupProcess) - ExitPostmaster(1); + if (MySubprocess->fork_failure) + { + if (MySubprocess->fork_failure(save_errno)) + ExitPostmaster(1); + } + return 0; } @@ -5638,7 +5630,7 @@ MaybeStartWalReceiver(void) pmState == PM_HOT_STANDBY || pmState == PM_WAIT_READONLY) && Shutdown == NoShutdown) { - WalReceiverPID = StartWalReceiver(); + WalReceiverPID = StartSubprocess(WalReceiverType); if (WalReceiverPID != 0) WalReceiverRequested = false; /* else leave the flag set, so we'll try again later */ @@ -6198,6 +6190,8 @@ save_backend_variables(BackendParameters *param, Port *port, param->PgReloadTime = PgReloadTime; param->first_syslogger_file_time = first_syslogger_file_time; + param->MySubprocessType = MySubprocessType; + param->redirection_done = redirection_done; param->IsBinaryUpgrade = IsBinaryUpgrade; param->max_safe_fds = max_safe_fds; @@ -6433,6 +6427,8 @@ restore_backend_variables(BackendParameters *param, Port *port) PgReloadTime = param->PgReloadTime; first_syslogger_file_time = param->first_syslogger_file_time; + MySubprocessType = param->MySubprocessType; + redirection_done = param->redirection_done; IsBinaryUpgrade = param->IsBinaryUpgrade; max_safe_fds = param->max_safe_fds; diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c index e29649a6a1..782cd608ff 100644 --- a/src/backend/postmaster/startup.c +++ b/src/backend/postmaster/startup.c @@ -175,6 +175,18 @@ StartupProcessMain(int argc, char *argv[]) proc_exit(0); } +/* + * StartupForkFailure + * + * Tell the postmaster to exit/panic on failure to fork. + */ +bool +StartupForkFailure(int fork_errno) +{ + /* Panic! */ + return true; +} + void PreRestoreCommand(void) { diff --git a/src/backend/postmaster/subprocess.c b/src/backend/postmaster/subprocess.c index 3e7a45bf10..7e96678dfb 100644 --- a/src/backend/postmaster/subprocess.c +++ b/src/backend/postmaster/subprocess.c @@ -24,32 +24,53 @@ PgSubprocess *MySubprocess; static PgSubprocess process_types[] = { { + .name = "boot", .desc = "checker", - .entrypoint = CheckerModeMain + .needs_aux_proc = true, + .entrypoint = CheckerModeMain, + .fork_failure = NULL }, { + .name = "boot", .desc = "bootstrap", - .entrypoint = BootstrapModeMain + .needs_aux_proc = true, + .entrypoint = BootstrapModeMain, + .fork_failure = NULL }, { + .name = "boot", .desc = "startup", - .entrypoint = StartupProcessMain + .needs_aux_proc = true, + .entrypoint = StartupProcessMain, + .fork_failure = StartupForkFailure }, { + .name = "boot", .desc = "background writer", - .entrypoint = BackgroundWriterMain + .needs_aux_proc = true, + .entrypoint = BackgroundWriterMain, + .fork_failure = NULL }, { + .name = "boot", .desc = "checkpointer", - .entrypoint = CheckpointerMain + .needs_aux_proc = true, + .entrypoint = CheckpointerMain, + .fork_failure = NULL }, { + .name = "boot", .desc = "wal writer", - .entrypoint = WalWriterMain + .needs_aux_proc = true, + .entrypoint = WalWriterMain, + .fork_failure = NULL }, { + .name = "boot", .desc = "wal receiver", - .entrypoint = WalReceiverMain + .needs_aux_proc = true, + .entrypoint = WalReceiverMain, + .fork_failure = NULL } }; diff --git a/src/include/postmaster/startup.h b/src/include/postmaster/startup.h index 6a8108dfe0..c182c76960 100644 --- a/src/include/postmaster/startup.h +++ b/src/include/postmaster/startup.h @@ -20,6 +20,6 @@ extern void ResetPromoteTriggered(void); /* Startup subprocess functions */ extern void StartupProcessMain(int argc, char *argv[]) pg_attribute_noreturn(); -extern bool StartupCleanup(int child_errno); +extern bool StartupForkFailure(int fork_errno); #endif /* _STARTUP_H */ diff --git a/src/include/postmaster/subprocess.h b/src/include/postmaster/subprocess.h index 56e8edf2d8..33f6a7ab04 100644 --- a/src/include/postmaster/subprocess.h +++ b/src/include/postmaster/subprocess.h @@ -28,14 +28,18 @@ typedef enum } SubprocessType; typedef void (*SubprocessEntryPoint) (int argc, char *argv[]); +typedef bool (*SubprocessForkFailure) (int fork_errno); /* Current subprocess initializer */ extern void InitMySubprocess(SubprocessType type); typedef struct PgSubprocess { + const char *name; const char *desc; + bool needs_aux_proc; SubprocessEntryPoint entrypoint; + SubprocessForkFailure fork_failure; } PgSubprocess; extern SubprocessType MySubprocessType; -- 2.17.0
>From 9e649e32ee68d9a7145a35d02c59bdc03442d165 Mon Sep 17 00:00:00 2001 From: Mike Palmiotto <mike.palmio...@crunchydata.com> Date: Tue, 10 Mar 2020 22:29:44 +0000 Subject: [PATCH v2 03/12] Add AutoVacLauncherType to subprocess struct --- src/backend/postmaster/autovacuum.c | 66 ++--------------------------- src/backend/postmaster/postmaster.c | 36 +++++++++------- src/backend/postmaster/subprocess.c | 8 ++++ src/include/postmaster/autovacuum.h | 3 +- src/include/postmaster/subprocess.h | 1 + 5 files changed, 34 insertions(+), 80 deletions(-) diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index da75e755f0..d0fdb7e5ee 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -95,6 +95,7 @@ #include "storage/procsignal.h" #include "storage/sinvaladt.h" #include "storage/smgr.h" +#include "postmaster/subprocess.h" #include "tcop/tcopprot.h" #include "utils/fmgroids.h" #include "utils/fmgrprotos.h" @@ -303,11 +304,9 @@ static WorkerInfo MyWorkerInfo = NULL; int AutovacuumLauncherPid = 0; #ifdef EXEC_BACKEND -static pid_t avlauncher_forkexec(void); static pid_t avworker_forkexec(void); #endif NON_EXEC_STATIC void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn(); -NON_EXEC_STATIC void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_noreturn(); static Oid do_start_worker(void); static void HandleAutoVacLauncherInterrupts(void); @@ -353,26 +352,6 @@ static void autovac_refresh_stats(void); ********************************************************************/ #ifdef EXEC_BACKEND -/* - * forkexec routine for the autovacuum launcher process. - * - * Format up the arglist, then fork and exec. - */ -static pid_t -avlauncher_forkexec(void) -{ - char *av[10]; - int ac = 0; - - av[ac++] = "postgres"; - av[ac++] = "--forkavlauncher"; - av[ac++] = NULL; /* filled in by postmaster_forkexec */ - av[ac] = NULL; - - Assert(ac < lengthof(av)); - - return postmaster_forkexec(ac, av); -} /* * We need this set from the outside, before InitProcess is called @@ -384,50 +363,11 @@ AutovacuumLauncherIAm(void) } #endif -/* - * Main entry point for autovacuum launcher process, to be called from the - * postmaster. - */ -int -StartAutoVacLauncher(void) -{ - pid_t AutoVacPID; - -#ifdef EXEC_BACKEND - switch ((AutoVacPID = avlauncher_forkexec())) -#else - switch ((AutoVacPID = fork_process())) -#endif - { - case -1: - ereport(LOG, - (errmsg("could not fork autovacuum launcher process: %m"))); - return 0; - -#ifndef EXEC_BACKEND - case 0: - /* in postmaster child ... */ - InitPostmasterChild(); - - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - - AutoVacLauncherMain(0, NULL); - break; -#endif - default: - return (int) AutoVacPID; - } - - /* shouldn't get here */ - return 0; -} - /* * Main loop for the autovacuum launcher process. */ -NON_EXEC_STATIC void -AutoVacLauncherMain(int argc, char *argv[]) +void +AutoVacLauncherMain(pg_attribute_unused() int argc, pg_attribute_unused() char *argv[]) { sigjmp_buf local_sigjmp_buf; diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 4b86aeec2d..2251303589 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -1773,7 +1773,7 @@ ServerLoop(void) (AutoVacuumingActive() || start_autovac_launcher) && pmState == PM_RUN) { - AutoVacPID = StartAutoVacLauncher(); + AutoVacPID = StartSubprocess(AutoVacuumLauncherType); if (AutoVacPID != 0) start_autovac_launcher = false; /* signal processed */ } @@ -3053,7 +3053,7 @@ reaper(SIGNAL_ARGS) * situation, some of them may be alive already. */ if (!IsBinaryUpgrade && AutoVacuumingActive() && AutoVacPID == 0) - AutoVacPID = StartAutoVacLauncher(); + AutoVacPID = StartSubprocess(AutoVacuumLauncherType); if (PgArchStartupAllowed() && PgArchPID == 0) PgArchPID = pgarch_start(); if (PgStatPID == 0) @@ -5041,19 +5041,6 @@ SubPostmasterMain(int argc, char *argv[]) /* And run the backend */ BackendRun(&port); /* does not return */ } - if (strcmp(argv[1], "--forkavlauncher") == 0) - { - /* Restore basic shared memory pointers */ - InitShmemAccess(UsedShmemSegAddr); - - /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */ - InitProcess(); - - /* Attach process to shared data structures */ - CreateSharedMemoryAndSemaphores(); - - AutoVacLauncherMain(argc - 2, argv + 2); /* does not return */ - } if (strcmp(argv[1], "--forkavworker") == 0) { /* Restore basic shared memory pointers */ @@ -5121,6 +5108,19 @@ SubPostmasterMain(int argc, char *argv[]) AuxiliaryProcessMain(argc - 2, argv + 2); /* does not return */ } + else + { + /* Restore basic shared memory pointers */ + InitShmemAccess(UsedShmemSegAddr); + + /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */ + InitProcess(); + + /* Attach process to shared data structures */ + CreateSharedMemoryAndSemaphores(); + + MySubprocess->entrypoint(argc - 2, argv + 2); + } abort(); /* shouldn't get here */ } @@ -5488,7 +5488,11 @@ StartSubprocess(SubprocessType type) MemoryContextDelete(PostmasterContext); PostmasterContext = NULL; - AuxiliaryProcessMain(argc, argv); + if (MySubprocess->needs_aux_proc) + AuxiliaryProcessMain(argc, argv); + else + MySubprocess->entrypoint(argc, argv); + ExitPostmaster(0); } #endif /* EXEC_BACKEND */ diff --git a/src/backend/postmaster/subprocess.c b/src/backend/postmaster/subprocess.c index 7e96678dfb..9aa60cc93e 100644 --- a/src/backend/postmaster/subprocess.c +++ b/src/backend/postmaster/subprocess.c @@ -12,6 +12,7 @@ */ #include "postgres.h" #include "bootstrap/bootstrap.h" +#include "postmaster/autovacuum.h" #include "postmaster/bgwriter.h" #include "postmaster/postmaster.h" #include "postmaster/startup.h" @@ -71,6 +72,13 @@ static PgSubprocess process_types[] = { .needs_aux_proc = true, .entrypoint = WalReceiverMain, .fork_failure = NULL + }, + { + .name = "avlauncher", + .desc = "autovacuum launcher", + .needs_aux_proc = false, + .entrypoint = AutoVacLauncherMain, + .fork_failure = NULL } }; diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h index d40ed55531..08050cd81c 100644 --- a/src/include/postmaster/autovacuum.h +++ b/src/include/postmaster/autovacuum.h @@ -58,6 +58,8 @@ extern void autovac_init(void); extern int StartAutoVacLauncher(void); extern int StartAutoVacWorker(void); +extern void AutoVacLauncherMain(int argc, char *argv[]); + /* called from postmaster when a worker could not be forked */ extern void AutoVacWorkerFailed(void); @@ -65,7 +67,6 @@ extern void AutoVacWorkerFailed(void); extern void AutoVacuumUpdateDelay(void); #ifdef EXEC_BACKEND -extern void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_noreturn(); extern void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn(); extern void AutovacuumWorkerIAm(void); extern void AutovacuumLauncherIAm(void); diff --git a/src/include/postmaster/subprocess.h b/src/include/postmaster/subprocess.h index 33f6a7ab04..9e3c743333 100644 --- a/src/include/postmaster/subprocess.h +++ b/src/include/postmaster/subprocess.h @@ -23,6 +23,7 @@ typedef enum CheckpointerType, WalWriterType, WalReceiverType, /* end of Auxiliary Process Forks */ + AutoVacuumLauncherType, NUMSUBPROCESSTYPES /* Must be last! */ } SubprocessType; -- 2.17.0
>From f804f37d6e0cba40fdad14f91e6ca08d626c0ffe Mon Sep 17 00:00:00 2001 From: Mike Palmiotto <mike.palmio...@crunchydata.com> Date: Tue, 10 Mar 2020 23:33:39 +0000 Subject: [PATCH v2 04/12] Add AutoVacuumWorkerType to subprocess struct --- src/backend/postmaster/autovacuum.c | 69 +---------------------------- src/backend/postmaster/postmaster.c | 17 +------ src/backend/postmaster/subprocess.c | 7 +++ src/include/postmaster/autovacuum.h | 4 +- src/include/postmaster/subprocess.h | 1 + 5 files changed, 13 insertions(+), 85 deletions(-) diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index d0fdb7e5ee..ba19a9c5d2 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -83,7 +83,6 @@ #include "nodes/makefuncs.h" #include "pgstat.h" #include "postmaster/autovacuum.h" -#include "postmaster/fork_process.h" #include "postmaster/interrupt.h" #include "postmaster/postmaster.h" #include "storage/bufmgr.h" @@ -303,11 +302,6 @@ static WorkerInfo MyWorkerInfo = NULL; /* PID of launcher, valid only in worker while shutting down */ int AutovacuumLauncherPid = 0; -#ifdef EXEC_BACKEND -static pid_t avworker_forkexec(void); -#endif -NON_EXEC_STATIC void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn(); - static Oid do_start_worker(void); static void HandleAutoVacLauncherInterrupts(void); static void AutoVacLauncherShutdown(void) pg_attribute_noreturn(); @@ -1364,27 +1358,6 @@ avl_sigusr2_handler(SIGNAL_ARGS) ********************************************************************/ #ifdef EXEC_BACKEND -/* - * forkexec routines for the autovacuum worker. - * - * Format up the arglist, then fork and exec. - */ -static pid_t -avworker_forkexec(void) -{ - char *av[10]; - int ac = 0; - - av[ac++] = "postgres"; - av[ac++] = "--forkavworker"; - av[ac++] = NULL; /* filled in by postmaster_forkexec */ - av[ac] = NULL; - - Assert(ac < lengthof(av)); - - return postmaster_forkexec(ac, av); -} - /* * We need this set from the outside, before InitProcess is called */ @@ -1395,50 +1368,10 @@ AutovacuumWorkerIAm(void) } #endif -/* - * Main entry point for autovacuum worker process. - * - * This code is heavily based on pgarch.c, q.v. - */ -int -StartAutoVacWorker(void) -{ - pid_t worker_pid; - -#ifdef EXEC_BACKEND - switch ((worker_pid = avworker_forkexec())) -#else - switch ((worker_pid = fork_process())) -#endif - { - case -1: - ereport(LOG, - (errmsg("could not fork autovacuum worker process: %m"))); - return 0; - -#ifndef EXEC_BACKEND - case 0: - /* in postmaster child ... */ - InitPostmasterChild(); - - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - - AutoVacWorkerMain(0, NULL); - break; -#endif - default: - return (int) worker_pid; - } - - /* shouldn't get here */ - return 0; -} - /* * AutoVacWorkerMain */ -NON_EXEC_STATIC void +void AutoVacWorkerMain(int argc, char *argv[]) { sigjmp_buf local_sigjmp_buf; diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 2251303589..21bbbf8194 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -5041,19 +5041,6 @@ SubPostmasterMain(int argc, char *argv[]) /* And run the backend */ BackendRun(&port); /* does not return */ } - if (strcmp(argv[1], "--forkavworker") == 0) - { - /* Restore basic shared memory pointers */ - InitShmemAccess(UsedShmemSegAddr); - - /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */ - InitProcess(); - - /* Attach process to shared data structures */ - CreateSharedMemoryAndSemaphores(); - - AutoVacWorkerMain(argc - 2, argv + 2); /* does not return */ - } if (strncmp(argv[1], "--forkbgworker=", 15) == 0) { int shmem_slot; @@ -5573,7 +5560,7 @@ StartAutovacuumWorker(void) bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot(); bn->bgworker_notify = false; - bn->pid = StartAutoVacWorker(); + bn->pid = StartSubprocess(AutoVacuumWorkerType); if (bn->pid > 0) { bn->bkend_type = BACKEND_TYPE_AUTOVAC; @@ -5587,7 +5574,7 @@ StartAutovacuumWorker(void) /* * fork failed, fall through to report -- actual error message was - * logged by StartAutoVacWorker + * logged by StartSubprocess */ (void) ReleasePostmasterChildSlot(bn->child_slot); free(bn); diff --git a/src/backend/postmaster/subprocess.c b/src/backend/postmaster/subprocess.c index 9aa60cc93e..0fbd067310 100644 --- a/src/backend/postmaster/subprocess.c +++ b/src/backend/postmaster/subprocess.c @@ -79,6 +79,13 @@ static PgSubprocess process_types[] = { .needs_aux_proc = false, .entrypoint = AutoVacLauncherMain, .fork_failure = NULL + }, + { + .name = "avworker", + .desc = "autovacuum worker", + .needs_aux_proc = false, + .entrypoint = AutoVacWorkerMain, + .fork_failure = NULL } }; diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h index 08050cd81c..51546fd4c9 100644 --- a/src/include/postmaster/autovacuum.h +++ b/src/include/postmaster/autovacuum.h @@ -58,7 +58,8 @@ extern void autovac_init(void); extern int StartAutoVacLauncher(void); extern int StartAutoVacWorker(void); -extern void AutoVacLauncherMain(int argc, char *argv[]); +extern void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_noreturn(); +extern void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn(); /* called from postmaster when a worker could not be forked */ extern void AutoVacWorkerFailed(void); @@ -67,7 +68,6 @@ extern void AutoVacWorkerFailed(void); extern void AutoVacuumUpdateDelay(void); #ifdef EXEC_BACKEND -extern void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn(); extern void AutovacuumWorkerIAm(void); extern void AutovacuumLauncherIAm(void); #endif diff --git a/src/include/postmaster/subprocess.h b/src/include/postmaster/subprocess.h index 9e3c743333..e11c24cc62 100644 --- a/src/include/postmaster/subprocess.h +++ b/src/include/postmaster/subprocess.h @@ -24,6 +24,7 @@ typedef enum WalWriterType, WalReceiverType, /* end of Auxiliary Process Forks */ AutoVacuumLauncherType, + AutoVacuumWorkerType, NUMSUBPROCESSTYPES /* Must be last! */ } SubprocessType; -- 2.17.0
>From dfb5814036358afa44670f377ef9768f782753a1 Mon Sep 17 00:00:00 2001 From: Mike Palmiotto <mike.palmio...@crunchydata.com> Date: Wed, 11 Mar 2020 00:24:42 +0000 Subject: [PATCH v2 05/12] Add PgstatCollectorType to subprocess struct Introduce two new fields to handle subprocess control: 1) needs_shmem controls whether or not the subprocess needs to attach to shmem. Up until now, all subprocesses needed to attach. This field paves the way for easier handling of subprocesses which do not. 2) fork_prep allows StartSubprocess to do some preparation for fork/exec. This is necessary to split out any functionality that previously happened in Start functions prior to fork/exec. --- src/backend/postmaster/pgstat.c | 86 +++-------------------------- src/backend/postmaster/postmaster.c | 39 +++++++------ src/backend/postmaster/subprocess.c | 28 ++++++++++ src/include/pgstat.h | 4 +- src/include/postmaster/subprocess.h | 8 ++- 5 files changed, 65 insertions(+), 100 deletions(-) diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index f9287b7942..6d4f2ace56 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -48,9 +48,9 @@ #include "pg_trace.h" #include "pgstat.h" #include "postmaster/autovacuum.h" -#include "postmaster/fork_process.h" #include "postmaster/interrupt.h" #include "postmaster/postmaster.h" +#include "postmaster/subprocess.h" #include "replication/walsender.h" #include "storage/backendid.h" #include "storage/dsm.h" @@ -275,11 +275,6 @@ static instr_time total_func_time; * Local function forward declarations * ---------- */ -#ifdef EXEC_BACKEND -static pid_t pgstat_forkexec(void); -#endif - -NON_EXEC_STATIC void PgstatCollectorMain(int argc, char *argv[]) pg_attribute_noreturn(); static void pgstat_beshutdown_hook(int code, Datum arg); static PgStat_StatDBEntry *pgstat_get_db_entry(Oid databaseid, bool create); @@ -685,46 +680,15 @@ pgstat_reset_all(void) pgstat_reset_remove_files(PGSTAT_STAT_PERMANENT_DIRECTORY); } -#ifdef EXEC_BACKEND - /* - * pgstat_forkexec() - + * PgstatCollectorPrep * - * Format up the arglist for, then fork and exec, statistics collector process - */ -static pid_t -pgstat_forkexec(void) -{ - char *av[10]; - int ac = 0; - - av[ac++] = "postgres"; - av[ac++] = "--forkcol"; - av[ac++] = NULL; /* filled in by postmaster_forkexec */ - - av[ac] = NULL; - Assert(ac < lengthof(av)); - - return postmaster_forkexec(ac, av); -} -#endif /* EXEC_BACKEND */ - - -/* - * pgstat_start() - - * - * Called from postmaster at startup or after an existing collector - * died. Attempt to fire up a fresh statistics collector. - * - * Returns PID of child process, or 0 if fail. - * - * Note: if fail, we will be called again from the postmaster main loop. + * Called from StartSubprocess to prepare a new collector fork */ int -pgstat_start(void) +PgstatCollectorPrep(int argc, char *argv[]) { time_t curtime; - pid_t pgStatPid; /* * Check that the socket is there, else pgstat_init failed and we can do @@ -740,46 +704,10 @@ pgstat_start(void) * from the postmaster main loop, we will get another chance later. */ curtime = time(NULL); - if ((unsigned int) (curtime - last_pgstat_start_time) < + if ((unsigned int) (curtime - last_pgstat_start_time) >= (unsigned int) PGSTAT_RESTART_INTERVAL) - return 0; - last_pgstat_start_time = curtime; + last_pgstat_start_time = curtime; - /* - * Okay, fork off the collector. - */ -#ifdef EXEC_BACKEND - switch ((pgStatPid = pgstat_forkexec())) -#else - switch ((pgStatPid = fork_process())) -#endif - { - case -1: - ereport(LOG, - (errmsg("could not fork statistics collector: %m"))); - return 0; - -#ifndef EXEC_BACKEND - case 0: - /* in postmaster child ... */ - InitPostmasterChild(); - - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - - /* Drop our connection to postmaster's shared memory, as well */ - dsm_detach_all(); - PGSharedMemoryDetach(); - - PgstatCollectorMain(0, NULL); - break; -#endif - - default: - return (int) pgStatPid; - } - - /* shouldn't get here */ return 0; } @@ -4326,7 +4254,7 @@ pgstat_send_bgwriter(void) * The argc/argv parameters are valid only in EXEC_BACKEND case. * ---------- */ -NON_EXEC_STATIC void +void PgstatCollectorMain(int argc, char *argv[]) { int len; diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 21bbbf8194..e2ad879452 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -1781,7 +1781,7 @@ ServerLoop(void) /* If we have lost the stats collector, try to start a new one */ if (PgStatPID == 0 && (pmState == PM_RUN || pmState == PM_HOT_STANDBY)) - PgStatPID = pgstat_start(); + PgStatPID = StartSubprocess(PgstatCollectorType); /* If we have lost the archiver, try to start a new one. */ if (PgArchPID == 0 && PgArchStartupAllowed()) @@ -3057,7 +3057,7 @@ reaper(SIGNAL_ARGS) if (PgArchStartupAllowed() && PgArchPID == 0) PgArchPID = pgarch_start(); if (PgStatPID == 0) - PgStatPID = pgstat_start(); + PgStatPID = StartSubprocess(PgstatCollectorType); /* workers may be scheduled to start now */ maybe_start_bgworkers(); @@ -3219,7 +3219,7 @@ reaper(SIGNAL_ARGS) LogChildExit(LOG, _("statistics collector process"), pid, exitstatus); if (pmState == PM_RUN || pmState == PM_HOT_STANDBY) - PgStatPID = pgstat_start(); + PgStatPID = StartSubprocess(PgstatCollectorType); continue; } @@ -5069,12 +5069,6 @@ SubPostmasterMain(int argc, char *argv[]) PgArchiverMain(argc, argv); /* does not return */ } - if (strcmp(argv[1], "--forkcol") == 0) - { - /* Do not want to attach to shared memory */ - - PgstatCollectorMain(argc, argv); /* does not return */ - } if (strcmp(argv[1], "--forklog") == 0) { /* Do not want to attach to shared memory */ @@ -5097,14 +5091,17 @@ SubPostmasterMain(int argc, char *argv[]) } else { - /* Restore basic shared memory pointers */ - InitShmemAccess(UsedShmemSegAddr); + if (MySubprocess->needs_shmem) + { + /* Restore basic shared memory pointers */ + InitShmemAccess(UsedShmemSegAddr); - /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */ - InitProcess(); + /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */ + InitProcess(); - /* Attach process to shared data structures */ - CreateSharedMemoryAndSemaphores(); + /* Attach process to shared data structures */ + CreateSharedMemoryAndSemaphores(); + } MySubprocess->entrypoint(argc - 2, argv + 2); } @@ -5224,7 +5221,7 @@ sigusr1_handler(SIGNAL_ARGS) * Likewise, start other special children as needed. */ Assert(PgStatPID == 0); - PgStatPID = pgstat_start(); + PgStatPID = StartSubprocess(PgstatCollectorType); ereport(LOG, (errmsg("database system is ready to accept read only connections"))); @@ -5475,6 +5472,16 @@ StartSubprocess(SubprocessType type) MemoryContextDelete(PostmasterContext); PostmasterContext = NULL; + /* + * Drop connection to postmaster's shared memory if the subprocess + * doesn't need it. + */ + if (!MySubprocess->needs_shmem) + { + dsm_detach_all(); + PGSharedMemoryDetach(); + } + if (MySubprocess->needs_aux_proc) AuxiliaryProcessMain(argc, argv); else diff --git a/src/backend/postmaster/subprocess.c b/src/backend/postmaster/subprocess.c index 0fbd067310..ee44ef0789 100644 --- a/src/backend/postmaster/subprocess.c +++ b/src/backend/postmaster/subprocess.c @@ -12,6 +12,7 @@ */ #include "postgres.h" #include "bootstrap/bootstrap.h" +#include "pgstat.h" #include "postmaster/autovacuum.h" #include "postmaster/bgwriter.h" #include "postmaster/postmaster.h" @@ -28,6 +29,8 @@ static PgSubprocess process_types[] = { .name = "boot", .desc = "checker", .needs_aux_proc = true, + .needs_shmem = true, + .fork_prep = NULL, .entrypoint = CheckerModeMain, .fork_failure = NULL }, @@ -35,6 +38,8 @@ static PgSubprocess process_types[] = { .name = "boot", .desc = "bootstrap", .needs_aux_proc = true, + .needs_shmem = true, + .fork_prep = NULL, .entrypoint = BootstrapModeMain, .fork_failure = NULL }, @@ -42,6 +47,8 @@ static PgSubprocess process_types[] = { .name = "boot", .desc = "startup", .needs_aux_proc = true, + .needs_shmem = true, + .fork_prep = NULL, .entrypoint = StartupProcessMain, .fork_failure = StartupForkFailure }, @@ -49,6 +56,8 @@ static PgSubprocess process_types[] = { .name = "boot", .desc = "background writer", .needs_aux_proc = true, + .needs_shmem = true, + .fork_prep = NULL, .entrypoint = BackgroundWriterMain, .fork_failure = NULL }, @@ -56,6 +65,8 @@ static PgSubprocess process_types[] = { .name = "boot", .desc = "checkpointer", .needs_aux_proc = true, + .needs_shmem = true, + .fork_prep = NULL, .entrypoint = CheckpointerMain, .fork_failure = NULL }, @@ -63,6 +74,8 @@ static PgSubprocess process_types[] = { .name = "boot", .desc = "wal writer", .needs_aux_proc = true, + .needs_shmem = true, + .fork_prep = NULL, .entrypoint = WalWriterMain, .fork_failure = NULL }, @@ -70,6 +83,8 @@ static PgSubprocess process_types[] = { .name = "boot", .desc = "wal receiver", .needs_aux_proc = true, + .needs_shmem = true, + .fork_prep = NULL, .entrypoint = WalReceiverMain, .fork_failure = NULL }, @@ -77,6 +92,8 @@ static PgSubprocess process_types[] = { .name = "avlauncher", .desc = "autovacuum launcher", .needs_aux_proc = false, + .needs_shmem = true, + .fork_prep = NULL, .entrypoint = AutoVacLauncherMain, .fork_failure = NULL }, @@ -84,8 +101,19 @@ static PgSubprocess process_types[] = { .name = "avworker", .desc = "autovacuum worker", .needs_aux_proc = false, + .needs_shmem = true, + .fork_prep = NULL, .entrypoint = AutoVacWorkerMain, .fork_failure = NULL + }, + { + .name = "col", + .desc = "statistics collector", + .needs_aux_proc = false, + .needs_shmem = false, + .fork_prep = PgstatCollectorPrep, + .entrypoint = PgstatCollectorMain, + .fork_failure = NULL } }; diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 1a19921f80..92943f5cff 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -1224,10 +1224,8 @@ extern int pgstat_start(void); extern void pgstat_reset_all(void); extern void allow_immediate_pgstat_restart(void); -#ifdef EXEC_BACKEND +extern int PgstatCollectorPrep(int argc, char *argv[]); extern void PgstatCollectorMain(int argc, char *argv[]) pg_attribute_noreturn(); -#endif - /* ---------- * Functions called from backends diff --git a/src/include/postmaster/subprocess.h b/src/include/postmaster/subprocess.h index e11c24cc62..a7ab036b7b 100644 --- a/src/include/postmaster/subprocess.h +++ b/src/include/postmaster/subprocess.h @@ -25,12 +25,14 @@ typedef enum WalReceiverType, /* end of Auxiliary Process Forks */ AutoVacuumLauncherType, AutoVacuumWorkerType, + PgstatCollectorType, NUMSUBPROCESSTYPES /* Must be last! */ } SubprocessType; -typedef void (*SubprocessEntryPoint) (int argc, char *argv[]); -typedef bool (*SubprocessForkFailure) (int fork_errno); +typedef int (*SubprocessPrep) (int argc, char *argv[]); +typedef void (*SubprocessEntryPoint) (int argc, char *argv[]); +typedef bool (*SubprocessForkFailure) (int fork_errno); /* Current subprocess initializer */ extern void InitMySubprocess(SubprocessType type); @@ -40,6 +42,8 @@ typedef struct PgSubprocess const char *name; const char *desc; bool needs_aux_proc; + bool needs_shmem; + SubprocessPrep fork_prep; SubprocessEntryPoint entrypoint; SubprocessForkFailure fork_failure; } PgSubprocess; -- 2.17.0
>From 7db474baf6b386261688760c8f32f9bf1c4a549b Mon Sep 17 00:00:00 2001 From: Mike Palmiotto <mike.palmio...@crunchydata.com> Date: Wed, 11 Mar 2020 01:07:05 +0000 Subject: [PATCH v2 06/12] Add PgArchiverType to subprocess struct --- src/backend/postmaster/pgarch.c | 87 ++++------------------------- src/backend/postmaster/postmaster.c | 14 ++--- src/backend/postmaster/subprocess.c | 10 ++++ src/include/postmaster/pgarch.h | 9 +-- src/include/postmaster/subprocess.h | 1 + 5 files changed, 26 insertions(+), 95 deletions(-) diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index 01ffd6513c..9c1761ad94 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -38,10 +38,10 @@ #include "libpq/pqsignal.h" #include "miscadmin.h" #include "pgstat.h" -#include "postmaster/fork_process.h" #include "postmaster/interrupt.h" #include "postmaster/pgarch.h" #include "postmaster/postmaster.h" +#include "postmaster/subprocess.h" #include "storage/dsm.h" #include "storage/fd.h" #include "storage/ipc.h" @@ -91,11 +91,6 @@ static volatile sig_atomic_t ready_to_stop = false; * Local function forward declarations * ---------- */ -#ifdef EXEC_BACKEND -static pid_t pgarch_forkexec(void); -#endif - -NON_EXEC_STATIC void PgArchiverMain(int argc, char *argv[]) pg_attribute_noreturn(); static void pgarch_exit(SIGNAL_ARGS); static void pgarch_waken(SIGNAL_ARGS); static void pgarch_waken_stop(SIGNAL_ARGS); @@ -122,10 +117,9 @@ static void pgarch_archiveDone(char *xlog); * Note: if fail, we will be called again from the postmaster main loop. */ int -pgarch_start(void) +PgArchiverPrep(int argc, char *argv[]) { time_t curtime; - pid_t pgArchPid; /* * Do nothing if no archiver needed @@ -140,86 +134,20 @@ pgarch_start(void) * the postmaster main loop, we will get another chance later. */ curtime = time(NULL); - if ((unsigned int) (curtime - last_pgarch_start_time) < + if ((unsigned int) (curtime - last_pgarch_start_time) >= (unsigned int) PGARCH_RESTART_INTERVAL) - return 0; - last_pgarch_start_time = curtime; - -#ifdef EXEC_BACKEND - switch ((pgArchPid = pgarch_forkexec())) -#else - switch ((pgArchPid = fork_process())) -#endif - { - case -1: - ereport(LOG, - (errmsg("could not fork archiver: %m"))); - return 0; - -#ifndef EXEC_BACKEND - case 0: - /* in postmaster child ... */ - InitPostmasterChild(); - - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - - /* Drop our connection to postmaster's shared memory, as well */ - dsm_detach_all(); - PGSharedMemoryDetach(); + last_pgarch_start_time = curtime; - PgArchiverMain(0, NULL); - break; -#endif - - default: - return (int) pgArchPid; - } - - /* shouldn't get here */ return 0; } -/* ------------------------------------------------------------ - * Local functions called by archiver follow - * ------------------------------------------------------------ - */ - - -#ifdef EXEC_BACKEND - -/* - * pgarch_forkexec() - - * - * Format up the arglist for, then fork and exec, archive process - */ -static pid_t -pgarch_forkexec(void) -{ - char *av[10]; - int ac = 0; - - av[ac++] = "postgres"; - - av[ac++] = "--forkarch"; - - av[ac++] = NULL; /* filled in by postmaster_forkexec */ - - av[ac] = NULL; - Assert(ac < lengthof(av)); - - return postmaster_forkexec(ac, av); -} -#endif /* EXEC_BACKEND */ - - /* * PgArchiverMain * * The argc/argv parameters are valid only in EXEC_BACKEND case. However, * since we don't use 'em, it hardly matters... */ -NON_EXEC_STATIC void +void PgArchiverMain(int argc, char *argv[]) { /* @@ -246,6 +174,11 @@ PgArchiverMain(int argc, char *argv[]) exit(0); } +/* ------------------------------------------------------------ + * Local functions called by archiver follow + * ------------------------------------------------------------ + */ + /* SIGQUIT signal handler for archiver process */ static void pgarch_exit(SIGNAL_ARGS) diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index e2ad879452..88d010ceb1 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -1785,7 +1785,7 @@ ServerLoop(void) /* If we have lost the archiver, try to start a new one. */ if (PgArchPID == 0 && PgArchStartupAllowed()) - PgArchPID = pgarch_start(); + PgArchPID = StartSubprocess(PgArchiverType); /* If we need to signal the autovacuum launcher, do so now */ if (avlauncher_needs_signal) @@ -3055,7 +3055,7 @@ reaper(SIGNAL_ARGS) if (!IsBinaryUpgrade && AutoVacuumingActive() && AutoVacPID == 0) AutoVacPID = StartSubprocess(AutoVacuumLauncherType); if (PgArchStartupAllowed() && PgArchPID == 0) - PgArchPID = pgarch_start(); + PgArchPID = StartSubprocess(PgArchiverType); if (PgStatPID == 0) PgStatPID = StartSubprocess(PgstatCollectorType); @@ -3203,7 +3203,7 @@ reaper(SIGNAL_ARGS) LogChildExit(LOG, _("archiver process"), pid, exitstatus); if (PgArchStartupAllowed()) - PgArchPID = pgarch_start(); + PgArchPID = StartSubprocess(PgArchiverType); continue; } @@ -5063,12 +5063,6 @@ SubPostmasterMain(int argc, char *argv[]) StartBackgroundWorker(); } - if (strcmp(argv[1], "--forkarch") == 0) - { - /* Do not want to attach to shared memory */ - - PgArchiverMain(argc, argv); /* does not return */ - } if (strcmp(argv[1], "--forklog") == 0) { /* Do not want to attach to shared memory */ @@ -5197,7 +5191,7 @@ sigusr1_handler(SIGNAL_ARGS) */ Assert(PgArchPID == 0); if (XLogArchivingAlways()) - PgArchPID = pgarch_start(); + PgArchPID = StartSubprocess(PgArchiverType); /* * If we aren't planning to enter hot standby mode later, treat diff --git a/src/backend/postmaster/subprocess.c b/src/backend/postmaster/subprocess.c index ee44ef0789..f9d71a627c 100644 --- a/src/backend/postmaster/subprocess.c +++ b/src/backend/postmaster/subprocess.c @@ -15,6 +15,7 @@ #include "pgstat.h" #include "postmaster/autovacuum.h" #include "postmaster/bgwriter.h" +#include "postmaster/pgarch.h" #include "postmaster/postmaster.h" #include "postmaster/startup.h" #include "postmaster/subprocess.h" @@ -114,6 +115,15 @@ static PgSubprocess process_types[] = { .fork_prep = PgstatCollectorPrep, .entrypoint = PgstatCollectorMain, .fork_failure = NULL + }, + { + .name = "arch", + .desc = "archiver", + .needs_aux_proc = false, + .needs_shmem = false, + .fork_prep = PgArchiverPrep, + .entrypoint = PgArchiverMain, + .fork_failure = NULL } }; diff --git a/src/include/postmaster/pgarch.h b/src/include/postmaster/pgarch.h index b3200874ca..ac527212b1 100644 --- a/src/include/postmaster/pgarch.h +++ b/src/include/postmaster/pgarch.h @@ -26,14 +26,7 @@ #define MAX_XFN_CHARS 40 #define VALID_XFN_CHARS "0123456789ABCDEF.history.backup.partial" -/* ---------- - * Functions called from postmaster - * ---------- - */ -extern int pgarch_start(void); - -#ifdef EXEC_BACKEND +extern int PgArchiverPrep(int argc, char *argv[]); extern void PgArchiverMain(int argc, char *argv[]) pg_attribute_noreturn(); -#endif #endif /* _PGARCH_H */ diff --git a/src/include/postmaster/subprocess.h b/src/include/postmaster/subprocess.h index a7ab036b7b..3f00f904dc 100644 --- a/src/include/postmaster/subprocess.h +++ b/src/include/postmaster/subprocess.h @@ -26,6 +26,7 @@ typedef enum AutoVacuumLauncherType, AutoVacuumWorkerType, PgstatCollectorType, + PgArchiverType, NUMSUBPROCESSTYPES /* Must be last! */ } SubprocessType; -- 2.17.0
>From 0da9a9de5ab07e90e59ce496a39bf1e48e354170 Mon Sep 17 00:00:00 2001 From: Mike Palmiotto <mike.palmio...@crunchydata.com> Date: Wed, 11 Mar 2020 02:58:08 +0000 Subject: [PATCH v2 07/12] Add SysLoggerType to subprocess struct This commit introduces two new fields to the subprocess struct: 1) keep_postmaster_memcontext allows subprocesses to specify whether or not the PostmasterMemoryContext should be kept around after a fork. 2) postmaster_main allows postmaster to gain control to do some necessary processing after a successful fork. --- src/backend/postmaster/postmaster.c | 39 +++-- src/backend/postmaster/subprocess.c | 56 +++++-- src/backend/postmaster/syslogger.c | 227 +++++++++++----------------- src/include/postmaster/subprocess.h | 18 ++- src/include/postmaster/syslogger.h | 5 +- 5 files changed, 177 insertions(+), 168 deletions(-) diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 88d010ceb1..f724727b1e 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -1083,7 +1083,7 @@ PostmasterMain(int argc, char *argv[]) /* * If enabled, start up syslogger collection subprocess */ - SysLoggerPID = SysLogger_Start(); + SysLoggerPID = StartSubprocess(SysLoggerType); /* * Reset whereToSendOutput from DestDebug (its starting state) to @@ -1739,7 +1739,7 @@ ServerLoop(void) /* If we have lost the log collector, try to start a new one */ if (SysLoggerPID == 0 && Logging_collector) - SysLoggerPID = SysLogger_Start(); + SysLoggerPID = StartSubprocess(SysLoggerType); /* * If no background writer process is running, and we are not in a @@ -3228,7 +3228,7 @@ reaper(SIGNAL_ARGS) { SysLoggerPID = 0; /* for safety's sake, launch new logger *first* */ - SysLoggerPID = SysLogger_Start(); + SysLoggerPID = StartSubprocess(SysLoggerType); if (!EXIT_STATUS_0(exitstatus)) LogChildExit(LOG, _("system logger process"), pid, exitstatus); @@ -5063,12 +5063,6 @@ SubPostmasterMain(int argc, char *argv[]) StartBackgroundWorker(); } - if (strcmp(argv[1], "--forklog") == 0) - { - /* Do not want to attach to shared memory */ - - SysLoggerMain(argc, argv); /* does not return */ - } if (MySubprocess->needs_aux_proc) { @@ -5446,6 +5440,15 @@ StartSubprocess(SubprocessType type) snprintf(typebuf, sizeof(typebuf), "-x%d", type); argv[argc++] = typebuf; + /* Prep subprocess for forking */ + if (MySubprocess->fork_prep) + { + if (MySubprocess->fork_prep(argc, argv)) + { + return 0; + } + } + argv[argc] = NULL; Assert(argc < lengthof(argv)); @@ -5461,10 +5464,16 @@ StartSubprocess(SubprocessType type) /* Close the postmaster's sockets */ ClosePostmasterPorts(false); - /* Release postmaster's working memory context */ - MemoryContextSwitchTo(TopMemoryContext); - MemoryContextDelete(PostmasterContext); - PostmasterContext = NULL; + /* + * Release postmaster's working memory context if the subprocess doesn't + * need it + */ + if (!MySubprocess->keep_postmaster_memcontext) + { + MemoryContextSwitchTo(TopMemoryContext); + MemoryContextDelete(PostmasterContext); + PostmasterContext = NULL; + } /* * Drop connection to postmaster's shared memory if the subprocess @@ -5508,6 +5517,10 @@ StartSubprocess(SubprocessType type) return 0; } + /* Some subprocesses need to do more work in postmaster. */ + if (MySubprocess->postmaster_main) + MySubprocess->postmaster_main(argc, argv); + /* * in parent, successful fork */ diff --git a/src/backend/postmaster/subprocess.c b/src/backend/postmaster/subprocess.c index f9d71a627c..f9d07de4ae 100644 --- a/src/backend/postmaster/subprocess.c +++ b/src/backend/postmaster/subprocess.c @@ -19,6 +19,7 @@ #include "postmaster/postmaster.h" #include "postmaster/startup.h" #include "postmaster/subprocess.h" +#include "postmaster/syslogger.h" #include "postmaster/walwriter.h" #include "replication/walreceiver.h" @@ -31,99 +32,132 @@ static PgSubprocess process_types[] = { .desc = "checker", .needs_aux_proc = true, .needs_shmem = true, + .keep_postmaster_memcontext = false, .fork_prep = NULL, .entrypoint = CheckerModeMain, - .fork_failure = NULL + .fork_failure = NULL, + .postmaster_main = NULL }, { .name = "boot", .desc = "bootstrap", .needs_aux_proc = true, .needs_shmem = true, + .keep_postmaster_memcontext = false, .fork_prep = NULL, .entrypoint = BootstrapModeMain, - .fork_failure = NULL + .fork_failure = NULL, + .postmaster_main = NULL }, { .name = "boot", .desc = "startup", .needs_aux_proc = true, .needs_shmem = true, + .keep_postmaster_memcontext = false, .fork_prep = NULL, .entrypoint = StartupProcessMain, - .fork_failure = StartupForkFailure + .fork_failure = StartupForkFailure, + .postmaster_main = NULL }, { .name = "boot", .desc = "background writer", .needs_aux_proc = true, .needs_shmem = true, + .keep_postmaster_memcontext = false, .fork_prep = NULL, .entrypoint = BackgroundWriterMain, - .fork_failure = NULL + .fork_failure = NULL, + .postmaster_main = NULL }, { .name = "boot", .desc = "checkpointer", .needs_aux_proc = true, .needs_shmem = true, + .keep_postmaster_memcontext = false, .fork_prep = NULL, .entrypoint = CheckpointerMain, - .fork_failure = NULL + .fork_failure = NULL, + .postmaster_main = NULL }, { .name = "boot", .desc = "wal writer", .needs_aux_proc = true, .needs_shmem = true, + .keep_postmaster_memcontext = false, .fork_prep = NULL, .entrypoint = WalWriterMain, - .fork_failure = NULL + .fork_failure = NULL, + .postmaster_main = NULL }, { .name = "boot", .desc = "wal receiver", .needs_aux_proc = true, .needs_shmem = true, + .keep_postmaster_memcontext = false, .fork_prep = NULL, .entrypoint = WalReceiverMain, - .fork_failure = NULL + .fork_failure = NULL, + .postmaster_main = NULL }, { .name = "avlauncher", .desc = "autovacuum launcher", .needs_aux_proc = false, .needs_shmem = true, + .keep_postmaster_memcontext = false, .fork_prep = NULL, .entrypoint = AutoVacLauncherMain, - .fork_failure = NULL + .fork_failure = NULL, + .postmaster_main = NULL }, { .name = "avworker", .desc = "autovacuum worker", .needs_aux_proc = false, .needs_shmem = true, + .keep_postmaster_memcontext = false, .fork_prep = NULL, .entrypoint = AutoVacWorkerMain, - .fork_failure = NULL + .fork_failure = NULL, + .postmaster_main = NULL }, { .name = "col", .desc = "statistics collector", .needs_aux_proc = false, .needs_shmem = false, + .keep_postmaster_memcontext = false, .fork_prep = PgstatCollectorPrep, .entrypoint = PgstatCollectorMain, - .fork_failure = NULL + .fork_failure = NULL, + .postmaster_main = NULL }, { .name = "arch", .desc = "archiver", .needs_aux_proc = false, .needs_shmem = false, + .keep_postmaster_memcontext = false, .fork_prep = PgArchiverPrep, .entrypoint = PgArchiverMain, - .fork_failure = NULL + .fork_failure = NULL, + .postmaster_main = NULL + }, + { + .name = "log", + .desc = "syslogger", + .needs_aux_proc = false, + .needs_shmem = false, + .keep_postmaster_memcontext = true, + .fork_prep = SysLoggerPrep, + .entrypoint = SysLoggerMain, + .fork_failure = NULL, + .postmaster_main = SysLoggerPostmasterMain } }; diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c index ffcb54968f..e56b0a77dd 100644 --- a/src/backend/postmaster/syslogger.c +++ b/src/backend/postmaster/syslogger.c @@ -38,8 +38,8 @@ #include "nodes/pg_list.h" #include "pgstat.h" #include "pgtime.h" -#include "postmaster/fork_process.h" #include "postmaster/postmaster.h" +#include "postmaster/subprocess.h" #include "postmaster/syslogger.h" #include "storage/dsm.h" #include "storage/fd.h" @@ -129,10 +129,8 @@ static volatile sig_atomic_t rotation_requested = false; /* Local subroutines */ #ifdef EXEC_BACKEND -static pid_t syslogger_forkexec(void); static void syslogger_parseArgs(int argc, char *argv[]); #endif -NON_EXEC_STATIC void SysLoggerMain(int argc, char *argv[]) pg_attribute_noreturn(); static void process_pipe_input(char *logbuffer, int *bytes_in_logbuffer); static void flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer); static FILE *logfile_open(const char *filename, const char *mode, @@ -153,7 +151,7 @@ static void update_metainfo_datafile(void); * Main entry point for syslogger process * argc/argv parameters are valid only in EXEC_BACKEND case. */ -NON_EXEC_STATIC void +void SysLoggerMain(int argc, char *argv[]) { #ifndef WIN32 @@ -537,13 +535,17 @@ SysLoggerMain(int argc, char *argv[]) * Postmaster subroutine to start a syslogger subprocess. */ int -SysLogger_Start(void) +SysLoggerPrep(int argc, char *argv[]) { - pid_t sysloggerPid; char *filename; +#ifdef EXEC_BACKEND + char filenobuf[32]; + char csvfilenobuf[32]; +#endif + /* Tell postmaster to stop forking */ if (!Logging_collector) - return 0; + return -1; /* * If first time through, create the pipe which will receive stderr @@ -626,129 +628,6 @@ SysLogger_Start(void) } #ifdef EXEC_BACKEND - switch ((sysloggerPid = syslogger_forkexec())) -#else - switch ((sysloggerPid = fork_process())) -#endif - { - case -1: - ereport(LOG, - (errmsg("could not fork system logger: %m"))); - return 0; - -#ifndef EXEC_BACKEND - case 0: - /* in postmaster child ... */ - InitPostmasterChild(); - - /* Close the postmaster's sockets */ - ClosePostmasterPorts(true); - - /* Drop our connection to postmaster's shared memory, as well */ - dsm_detach_all(); - PGSharedMemoryDetach(); - - /* do the work */ - SysLoggerMain(0, NULL); - break; -#endif - - default: - /* success, in postmaster */ - - /* now we redirect stderr, if not done already */ - if (!redirection_done) - { -#ifdef WIN32 - int fd; -#endif - - /* - * Leave a breadcrumb trail when redirecting, in case the user - * forgets that redirection is active and looks only at the - * original stderr target file. - */ - ereport(LOG, - (errmsg("redirecting log output to logging collector process"), - errhint("Future log output will appear in directory \"%s\".", - Log_directory))); - -#ifndef WIN32 - fflush(stdout); - if (dup2(syslogPipe[1], fileno(stdout)) < 0) - ereport(FATAL, - (errcode_for_file_access(), - errmsg("could not redirect stdout: %m"))); - fflush(stderr); - if (dup2(syslogPipe[1], fileno(stderr)) < 0) - ereport(FATAL, - (errcode_for_file_access(), - errmsg("could not redirect stderr: %m"))); - /* Now we are done with the write end of the pipe. */ - close(syslogPipe[1]); - syslogPipe[1] = -1; -#else - - /* - * open the pipe in binary mode and make sure stderr is binary - * after it's been dup'ed into, to avoid disturbing the pipe - * chunking protocol. - */ - fflush(stderr); - fd = _open_osfhandle((intptr_t) syslogPipe[1], - _O_APPEND | _O_BINARY); - if (dup2(fd, _fileno(stderr)) < 0) - ereport(FATAL, - (errcode_for_file_access(), - errmsg("could not redirect stderr: %m"))); - close(fd); - _setmode(_fileno(stderr), _O_BINARY); - - /* - * Now we are done with the write end of the pipe. - * CloseHandle() must not be called because the preceding - * close() closes the underlying handle. - */ - syslogPipe[1] = 0; -#endif - redirection_done = true; - } - - /* postmaster will never write the file(s); close 'em */ - fclose(syslogFile); - syslogFile = NULL; - if (csvlogFile != NULL) - { - fclose(csvlogFile); - csvlogFile = NULL; - } - return (int) sysloggerPid; - } - - /* we should never reach here */ - return 0; -} - - -#ifdef EXEC_BACKEND - -/* - * syslogger_forkexec() - - * - * Format up the arglist for, then fork and exec, a syslogger process - */ -static pid_t -syslogger_forkexec(void) -{ - char *av[10]; - int ac = 0; - char filenobuf[32]; - char csvfilenobuf[32]; - - av[ac++] = "postgres"; - av[ac++] = "--forklog"; - av[ac++] = NULL; /* filled in by postmaster_forkexec */ - /* static variables (those not passed by write_backend_variables) */ #ifndef WIN32 if (syslogFile != NULL) @@ -763,7 +642,7 @@ syslogger_forkexec(void) else strcpy(filenobuf, "0"); #endif /* WIN32 */ - av[ac++] = filenobuf; + argv[argc++] = filenobuf; #ifndef WIN32 if (csvlogFile != NULL) @@ -778,14 +657,92 @@ syslogger_forkexec(void) else strcpy(csvfilenobuf, "0"); #endif /* WIN32 */ - av[ac++] = csvfilenobuf; + argv[argc++] = csvfilenobuf; - av[ac] = NULL; - Assert(ac < lengthof(av)); +#endif /* EXEC_BACKEND */ - return postmaster_forkexec(ac, av); + return 0; } +/* + * SysLoggerPostmasterMain + * + * Control function for subprocess parent (postmaster) after a successful fork. + */ +void +SysLoggerPostmasterMain(int argc, char *argv[]) +{ + /* success, in postmaster */ + + /* now we redirect stderr, if not done already */ + if (!redirection_done) + { +#ifdef WIN32 + int fd; +#endif + + /* + * Leave a breadcrumb trail when redirecting, in case the user + * forgets that redirection is active and looks only at the + * original stderr target file. + */ + ereport(LOG, + (errmsg("redirecting log output to logging collector process"), + errhint("Future log output will appear in directory \"%s\".", + Log_directory))); + +#ifndef WIN32 + fflush(stdout); + if (dup2(syslogPipe[1], fileno(stdout)) < 0) + ereport(FATAL, + (errcode_for_file_access(), + errmsg("could not redirect stdout: %m"))); + fflush(stderr); + if (dup2(syslogPipe[1], fileno(stderr)) < 0) + ereport(FATAL, + (errcode_for_file_access(), + errmsg("could not redirect stderr: %m"))); + /* Now we are done with the write end of the pipe. */ + close(syslogPipe[1]); + syslogPipe[1] = -1; +#else + + /* + * open the pipe in binary mode and make sure stderr is binary + * after it's been dup'ed into, to avoid disturbing the pipe + * chunking protocol. + */ + fflush(stderr); + fd = _open_osfhandle((intptr_t) syslogPipe[1], + _O_APPEND | _O_BINARY); + if (dup2(fd, _fileno(stderr)) < 0) + ereport(FATAL, + (errcode_for_file_access(), + errmsg("could not redirect stderr: %m"))); + close(fd); + _setmode(_fileno(stderr), _O_BINARY); + + /* + * Now we are done with the write end of the pipe. + * CloseHandle() must not be called because the preceding + * close() closes the underlying handle. + */ + syslogPipe[1] = 0; +#endif + redirection_done = true; + } + + /* postmaster will never write the file(s); close 'em */ + fclose(syslogFile); + syslogFile = NULL; + if (csvlogFile != NULL) + { + fclose(csvlogFile); + csvlogFile = NULL; + } +} + +#ifdef EXEC_BACKEND /* * syslogger_parseArgs() - * diff --git a/src/include/postmaster/subprocess.h b/src/include/postmaster/subprocess.h index 3f00f904dc..d0d98a5d69 100644 --- a/src/include/postmaster/subprocess.h +++ b/src/include/postmaster/subprocess.h @@ -27,6 +27,7 @@ typedef enum AutoVacuumWorkerType, PgstatCollectorType, PgArchiverType, + SysLoggerType, NUMSUBPROCESSTYPES /* Must be last! */ } SubprocessType; @@ -34,19 +35,22 @@ typedef enum typedef int (*SubprocessPrep) (int argc, char *argv[]); typedef void (*SubprocessEntryPoint) (int argc, char *argv[]); typedef bool (*SubprocessForkFailure) (int fork_errno); +typedef void (*SubprocessPostmasterMain) (int argc, char *argv[]); /* Current subprocess initializer */ extern void InitMySubprocess(SubprocessType type); typedef struct PgSubprocess { - const char *name; - const char *desc; - bool needs_aux_proc; - bool needs_shmem; - SubprocessPrep fork_prep; - SubprocessEntryPoint entrypoint; - SubprocessForkFailure fork_failure; + const char *name; + const char *desc; + bool needs_aux_proc; + bool needs_shmem; + bool keep_postmaster_memcontext; + SubprocessPrep fork_prep; + SubprocessEntryPoint entrypoint; + SubprocessForkFailure fork_failure; + SubprocessPostmasterMain postmaster_main; } PgSubprocess; extern SubprocessType MySubprocessType; diff --git a/src/include/postmaster/syslogger.h b/src/include/postmaster/syslogger.h index f611bd1411..a498c73121 100644 --- a/src/include/postmaster/syslogger.h +++ b/src/include/postmaster/syslogger.h @@ -81,9 +81,10 @@ extern int SysLogger_Start(void); extern void write_syslogger_file(const char *buffer, int count, int dest); -#ifdef EXEC_BACKEND +/* Subprocess startup functions */ +extern int SysLoggerPrep(int argc, char *argv[]); extern void SysLoggerMain(int argc, char *argv[]) pg_attribute_noreturn(); -#endif +extern void SysLoggerPostmasterMain(int argc, char *argv[]); extern bool CheckLogrotateSignal(void); extern void RemoveLogrotateSignalFiles(void); -- 2.17.0
>From e4e1f4360d44508e9d562cb32543cce0bb424a95 Mon Sep 17 00:00:00 2001 From: Mike Palmiotto <mike.palmio...@crunchydata.com> Date: Wed, 11 Mar 2020 03:32:41 +0000 Subject: [PATCH v2 08/12] Add BgWorkerType to subprocess struct Export some of the backend-specific code and move the some bgworker startup code out to src/backend/postmaster/bgworker.c. --- src/backend/postmaster/bgworker.c | 165 ++++++++++- src/backend/postmaster/postmaster.c | 294 +++----------------- src/backend/postmaster/subprocess.c | 12 + src/backend/utils/init/globals.c | 1 + src/include/miscadmin.h | 1 + src/include/postmaster/bgworker_internals.h | 8 +- src/include/postmaster/postmaster.h | 53 ++++ src/include/postmaster/subprocess.h | 1 + 8 files changed, 268 insertions(+), 267 deletions(-) diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index 6c684b5e12..6f62cd4889 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -33,8 +33,10 @@ #include "storage/shmem.h" #include "tcop/tcopprot.h" #include "utils/ascii.h" +#include "utils/memutils.h" #include "utils/ps_status.h" #include "utils/timeout.h" +#include "utils/timestamp.h" /* * The postmaster's list of registered background workers, in private memory. @@ -133,7 +135,55 @@ static const struct /* Private functions. */ static bgworker_main_type LookupBackgroundWorkerFunction(const char *libraryname, const char *funcname); +static bool assign_backendlist_entry(RegisteredBgWorker *rw); +/* + * Allocate the Backend struct for a connected background worker, but don't + * add it to the list of backends just yet. + * + * On failure, return false without changing any worker state. + * + * Some info from the Backend is copied into the passed rw. + */ +static bool +assign_backendlist_entry(RegisteredBgWorker *rw) +{ + Backend *bn; + + /* + * Compute the cancel key that will be assigned to this session. We + * probably don't need cancel keys for background workers, but we'd better + * have something random in the field to prevent unfriendly people from + * sending cancels to them. + */ + if (!RandomCancelKey(&MyCancelKey)) + { + ereport(LOG, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("could not generate random cancel key"))); + return false; + } + + bn = malloc(sizeof(Backend)); + if (bn == NULL) + { + ereport(LOG, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + return false; + } + + bn->cancel_key = MyCancelKey; + bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot(); + bn->bkend_type = BACKEND_TYPE_BGWORKER; + bn->dead_end = false; + bn->bgworker_notify = false; + + rw->rw_backend = bn; + rw->rw_child_slot = bn->child_slot; + + return true; +} /* * Calculate shared memory needed. @@ -670,6 +720,55 @@ bgworker_sigusr1_handler(SIGNAL_ARGS) errno = save_errno; } +/* + * BackgroundWorkerPrep + * + * Postmaster subroutine to prepare a bgworker subprocess. + * + * Returns 0 on success or -1 on failure. + * + * Note: if fail, we will be called again from the postmaster main loop. + */ +int +BackgroundWorkerPrep(int argc, char *argv[]) +{ + RegisteredBgWorker *rw = MyRegisteredBgWorker; +#ifdef EXEC_BACKEND + char forkav[MAXPGPATH]; +#endif + + Assert(MyRegisteredBgWorker); + Assert(rw->rw_pid == 0); + + /* + * Allocate and assign the Backend element. Note we must do this before + * forking, so that we can handle out of memory properly. + * + * Treat failure as though the worker had crashed. That way, the + * postmaster will wait a bit before attempting to start it again; if it + * tried again right away, most likely it'd find itself repeating the + * out-of-memory or fork failure condition. + */ + if (!assign_backendlist_entry(rw)) + { + rw->rw_crashed_at = GetCurrentTimestamp(); + return -1; + } + + ereport(DEBUG1, + (errmsg("starting background worker process \"%s\"", + rw->rw_worker.bgw_name))); + +#ifdef EXEC_BACKEND + /* Rewrite bgworker fork parameter with shmem_slot */ + snprintf(forkav, MAXPGPATH, "%s=%d", argv[1], rw->rw_shmem_slot); + argv[1] = forkav; +#endif + + return 0; +} + + /* * Start a new background worker * @@ -677,12 +776,28 @@ bgworker_sigusr1_handler(SIGNAL_ARGS) * postmaster. */ void -StartBackgroundWorker(void) +BackgroundWorkerMain(pg_attribute_unused() int argc, pg_attribute_unused() char *argv[]) { sigjmp_buf local_sigjmp_buf; - BackgroundWorker *worker = MyBgworkerEntry; + BackgroundWorker *worker; bgworker_main_type entrypt; +#ifndef EXEC_BACKEND + /* + * Before blowing away PostmasterContext, save this bgworker's + * data where it can find it. + */ + MyBgworkerEntry = (BackgroundWorker *) + MemoryContextAlloc(TopMemoryContext, sizeof(BackgroundWorker)); + memcpy(MyBgworkerEntry, &(MyRegisteredBgWorker->rw_worker), sizeof(BackgroundWorker)); + + /* Now we can release postmaster's working memory context */ + MemoryContextSwitchTo(TopMemoryContext); + MemoryContextDelete(PostmasterContext); + PostmasterContext = NULL; +#endif + + worker = MyBgworkerEntry; if (worker == NULL) elog(FATAL, "unable to find bgworker entry"); @@ -816,6 +931,52 @@ StartBackgroundWorker(void) proc_exit(0); } +/* + * BackgroundWorkerForkFailure + * + * Handle bgworker fork failure gracefully. + */ +bool +BackgroundWorkerForkFailure(int fork_errno) +{ + RegisteredBgWorker *rw = MyRegisteredBgWorker; + + errno = fork_errno; + + /* in postmaster, fork failed ... */ + ereport(LOG, + (errmsg("could not fork worker process: %m"))); + + /* undo what assign_backendlist_entry did */ + ReleasePostmasterChildSlot(rw->rw_child_slot); + rw->rw_child_slot = 0; + free(rw->rw_backend); + rw->rw_backend = NULL; + /* mark entry as crashed, so we'll try again later */ + rw->rw_crashed_at = GetCurrentTimestamp(); + + /* Don't panic. */ + return false; +} + +/* + * BackgroundWorkerPostmasterMain + */ +void +BackgroundWorkerPostmasterMain(pg_attribute_unused() int argc, pg_attribute_unused() char *argv[]) +{ + RegisteredBgWorker *rw = MyRegisteredBgWorker; + + rw->rw_pid = MyChildProcPid; + rw->rw_backend->pid = rw->rw_pid; + ReportBackgroundWorkerPID(rw); + /* add new worker to lists of backends */ + dlist_push_head(&BackendList, &(rw->rw_backend->elem)); +#ifdef EXEC_BACKEND + ShmemBackendArrayAdd(rw->rw_backend); +#endif +} + /* * Register a new static background worker. * diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index f724727b1e..8343a81923 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -137,60 +137,14 @@ #include "storage/spin.h" #endif - -/* - * Possible types of a backend. Beyond being the possible bkend_type values in - * struct bkend, these are OR-able request flag bits for SignalSomeChildren() - * and CountChildren(). - */ -#define BACKEND_TYPE_NORMAL 0x0001 /* normal backend */ -#define BACKEND_TYPE_AUTOVAC 0x0002 /* autovacuum worker process */ -#define BACKEND_TYPE_WALSND 0x0004 /* walsender process */ -#define BACKEND_TYPE_BGWORKER 0x0008 /* bgworker process */ -#define BACKEND_TYPE_ALL 0x000F /* OR of all the above */ - -#define BACKEND_TYPE_WORKER (BACKEND_TYPE_AUTOVAC | BACKEND_TYPE_BGWORKER) - -/* - * List of active backends (or child processes anyway; we don't actually - * know whether a given child has become a backend or is still in the - * authorization phase). This is used mainly to keep track of how many - * children we have and send them appropriate signals when necessary. - * - * "Special" children such as the startup, bgwriter and autovacuum launcher - * tasks are not in this list. Autovacuum worker and walsender are in it. - * Also, "dead_end" children are in it: these are children launched just for - * the purpose of sending a friendly rejection message to a would-be client. - * We must track them because they are attached to shared memory, but we know - * they will never become live backends. dead_end children are not assigned a - * PMChildSlot. - * - * Background workers are in this list, too. - */ -typedef struct bkend -{ - pid_t pid; /* process id of backend */ - int32 cancel_key; /* cancel key for cancels for this backend */ - int child_slot; /* PMChildSlot for this backend, if any */ - - /* - * Flavor of backend or auxiliary process. Note that BACKEND_TYPE_WALSND - * backends initially announce themselves as BACKEND_TYPE_NORMAL, so if - * bkend_type is normal, you should check for a recent transition. - */ - int bkend_type; - bool dead_end; /* is it going to send an error and quit? */ - bool bgworker_notify; /* gets bgworker start/stop notifications */ - dlist_node elem; /* list link in BackendList */ -} Backend; - -static dlist_head BackendList = DLIST_STATIC_INIT(BackendList); +dlist_head BackendList = DLIST_STATIC_INIT(BackendList); #ifdef EXEC_BACKEND static Backend *ShmemBackendArray; #endif BackgroundWorker *MyBgworkerEntry = NULL; +RegisteredBgWorker *MyRegisteredBgWorker = NULL; /* Struct containing postmaster subprocess control info */ SubprocessType MySubprocessType; @@ -412,7 +366,6 @@ static void processCancelRequest(Port *port, void *pkt); static int initMasks(fd_set *rmask); static void report_fork_failure_to_client(Port *port, int errnum); static CAC_state canAcceptConnections(int backend_type); -static bool RandomCancelKey(int32 *cancel_key); static void signal_child(pid_t pid, int signal); static bool SignalSomeChildren(int signal, int targets); static void TerminateChildren(int signal); @@ -420,7 +373,6 @@ static void TerminateChildren(int signal); #define SignalChildren(sig) SignalSomeChildren(sig, BACKEND_TYPE_ALL) static int CountChildren(int target); -static bool assign_backendlist_entry(RegisteredBgWorker *rw); static void maybe_start_bgworkers(void); static bool CreateOptsFile(int argc, char *argv[], char *fullprogname); static pid_t StartSubprocess(SubprocessType type); @@ -539,10 +491,10 @@ static bool save_backend_variables(BackendParameters *param, Port *port, HANDLE childProcess, pid_t childPid); #endif -static void ShmemBackendArrayAdd(Backend *bn); static void ShmemBackendArrayRemove(Backend *bn); #endif /* EXEC_BACKEND */ +#define BGWORKER_LEN 15 /* Macros to check exit status of a child process */ #define EXIT_STATUS_0(st) ((st) == 0) @@ -4878,6 +4830,7 @@ void SubPostmasterMain(int argc, char *argv[]) { Port port; + int shmem_slot; /* In EXEC_BACKEND case we will not have inherited these settings */ IsPostmasterEnvironment = true; @@ -5041,59 +4994,48 @@ SubPostmasterMain(int argc, char *argv[]) /* And run the backend */ BackendRun(&port); /* does not return */ } - if (strncmp(argv[1], "--forkbgworker=", 15) == 0) - { - int shmem_slot; - - /* do this as early as possible; in particular, before InitProcess() */ - IsBackgroundWorker = true; + if (MySubprocess->needs_aux_proc) + { /* Restore basic shared memory pointers */ InitShmemAccess(UsedShmemSegAddr); /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */ - InitProcess(); + InitAuxiliaryProcess(); /* Attach process to shared data structures */ CreateSharedMemoryAndSemaphores(); - /* Fetch MyBgworkerEntry from shared memory */ - shmem_slot = atoi(argv[1] + 15); - MyBgworkerEntry = BackgroundWorkerEntry(shmem_slot); + AuxiliaryProcessMain(argc - 2, argv + 2); /* does not return */ + } - StartBackgroundWorker(); + if (MySubprocessType == BgWorkerType) + { + /* do this as early as possible; in particular, before InitProcess() */ + IsBackgroundWorker = true; } - if (MySubprocess->needs_aux_proc) + if (MySubprocess->needs_shmem) { /* Restore basic shared memory pointers */ InitShmemAccess(UsedShmemSegAddr); /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */ - InitAuxiliaryProcess(); + InitProcess(); /* Attach process to shared data structures */ CreateSharedMemoryAndSemaphores(); - - AuxiliaryProcessMain(argc - 2, argv + 2); /* does not return */ } - else - { - if (MySubprocess->needs_shmem) - { - /* Restore basic shared memory pointers */ - InitShmemAccess(UsedShmemSegAddr); - - /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */ - InitProcess(); - /* Attach process to shared data structures */ - CreateSharedMemoryAndSemaphores(); - } - - MySubprocess->entrypoint(argc - 2, argv + 2); + if (MySubprocessType == BgWorkerType) + { + /* Fetch MyBgworkerEntry from shared memory */ + shmem_slot = atoi(argv[1] + 15); + MyBgworkerEntry = BackgroundWorkerEntry(shmem_slot); } + MySubprocess->entrypoint(argc - 2, argv + 2); + abort(); /* shouldn't get here */ } #endif /* EXEC_BACKEND */ @@ -5356,7 +5298,7 @@ StartupPacketTimeoutHandler(void) /* * Generate a random cancel key. */ -static bool +bool RandomCancelKey(int32 *cancel_key) { return pg_strong_random(cancel_key, sizeof(int32)); @@ -5454,15 +5396,17 @@ StartSubprocess(SubprocessType type) #ifdef EXEC_BACKEND pid = postmaster_forkexec(argc, argv); + MyChildProcPid = pid; #else /* !EXEC_BACKEND */ pid = fork_process(); + MyChildProcPid = pid; if (pid == 0) /* child */ { InitPostmasterChild(); /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); + ClosePostmasterPorts(MySubprocessType == SysLoggerType); /* * Release postmaster's working memory context if the subprocess doesn't @@ -5512,6 +5456,8 @@ StartSubprocess(SubprocessType type) { if (MySubprocess->fork_failure(save_errno)) ExitPostmaster(1); + else + return -1; } return 0; @@ -5754,124 +5700,6 @@ BackgroundWorkerUnblockSignals(void) PG_SETMASK(&UnBlockSig); } -#ifdef EXEC_BACKEND -static pid_t -bgworker_forkexec(int shmem_slot) -{ - char *av[10]; - int ac = 0; - char forkav[MAXPGPATH]; - - snprintf(forkav, MAXPGPATH, "--forkbgworker=%d", shmem_slot); - - av[ac++] = "postgres"; - av[ac++] = forkav; - av[ac++] = NULL; /* filled in by postmaster_forkexec */ - av[ac] = NULL; - - Assert(ac < lengthof(av)); - - return postmaster_forkexec(ac, av); -} -#endif - -/* - * Start a new bgworker. - * Starting time conditions must have been checked already. - * - * Returns true on success, false on failure. - * In either case, update the RegisteredBgWorker's state appropriately. - * - * This code is heavily based on autovacuum.c, q.v. - */ -static bool -do_start_bgworker(RegisteredBgWorker *rw) -{ - pid_t worker_pid; - - Assert(rw->rw_pid == 0); - - /* - * Allocate and assign the Backend element. Note we must do this before - * forking, so that we can handle failures (out of memory or child-process - * slots) cleanly. - * - * Treat failure as though the worker had crashed. That way, the - * postmaster will wait a bit before attempting to start it again; if we - * tried again right away, most likely we'd find ourselves hitting the - * same resource-exhaustion condition. - */ - if (!assign_backendlist_entry(rw)) - { - rw->rw_crashed_at = GetCurrentTimestamp(); - return false; - } - - ereport(DEBUG1, - (errmsg("starting background worker process \"%s\"", - rw->rw_worker.bgw_name))); - -#ifdef EXEC_BACKEND - switch ((worker_pid = bgworker_forkexec(rw->rw_shmem_slot))) -#else - switch ((worker_pid = fork_process())) -#endif - { - case -1: - /* in postmaster, fork failed ... */ - ereport(LOG, - (errmsg("could not fork worker process: %m"))); - /* undo what assign_backendlist_entry did */ - ReleasePostmasterChildSlot(rw->rw_child_slot); - rw->rw_child_slot = 0; - free(rw->rw_backend); - rw->rw_backend = NULL; - /* mark entry as crashed, so we'll try again later */ - rw->rw_crashed_at = GetCurrentTimestamp(); - break; - -#ifndef EXEC_BACKEND - case 0: - /* in postmaster child ... */ - InitPostmasterChild(); - - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - - /* - * Before blowing away PostmasterContext, save this bgworker's - * data where it can find it. - */ - MyBgworkerEntry = (BackgroundWorker *) - MemoryContextAlloc(TopMemoryContext, sizeof(BackgroundWorker)); - memcpy(MyBgworkerEntry, &rw->rw_worker, sizeof(BackgroundWorker)); - - /* Release postmaster's working memory context */ - MemoryContextSwitchTo(TopMemoryContext); - MemoryContextDelete(PostmasterContext); - PostmasterContext = NULL; - - StartBackgroundWorker(); - - exit(1); /* should not get here */ - break; -#endif - default: - /* in postmaster, fork successful ... */ - rw->rw_pid = worker_pid; - rw->rw_backend->pid = rw->rw_pid; - ReportBackgroundWorkerPID(rw); - /* add new worker to lists of backends */ - dlist_push_head(&BackendList, &rw->rw_backend->elem); -#ifdef EXEC_BACKEND - ShmemBackendArrayAdd(rw->rw_backend); -#endif - return true; - } - - return false; -} - /* * Does the current postmaster state require starting a worker with the * specified start_time? @@ -5912,67 +5740,6 @@ bgworker_should_start_now(BgWorkerStartTime start_time) return false; } -/* - * Allocate the Backend struct for a connected background worker, but don't - * add it to the list of backends just yet. - * - * On failure, return false without changing any worker state. - * - * Some info from the Backend is copied into the passed rw. - */ -static bool -assign_backendlist_entry(RegisteredBgWorker *rw) -{ - Backend *bn; - - /* - * Check that database state allows another connection. Currently the - * only possible failure is CAC_TOOMANY, so we just log an error message - * based on that rather than checking the error code precisely. - */ - if (canAcceptConnections(BACKEND_TYPE_BGWORKER) != CAC_OK) - { - ereport(LOG, - (errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED), - errmsg("no slot available for new worker process"))); - return false; - } - - /* - * Compute the cancel key that will be assigned to this session. We - * probably don't need cancel keys for background workers, but we'd better - * have something random in the field to prevent unfriendly people from - * sending cancels to them. - */ - if (!RandomCancelKey(&MyCancelKey)) - { - ereport(LOG, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("could not generate random cancel key"))); - return false; - } - - bn = malloc(sizeof(Backend)); - if (bn == NULL) - { - ereport(LOG, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); - return false; - } - - bn->cancel_key = MyCancelKey; - bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot(); - bn->bkend_type = BACKEND_TYPE_BGWORKER; - bn->dead_end = false; - bn->bgworker_notify = false; - - rw->rw_backend = bn; - rw->rw_child_slot = bn->child_slot; - - return true; -} - /* * If the time is right, start background worker(s). * @@ -6077,7 +5844,8 @@ maybe_start_bgworkers(void) * crashed, but there's no need because the next run of this * function will do that. */ - if (!do_start_bgworker(rw)) + MyRegisteredBgWorker = rw; + if (StartSubprocess(BgWorkerType) <= 0) { StartWorkerNeeded = true; return; @@ -6488,7 +6256,7 @@ ShmemBackendArrayAllocation(void) memset(ShmemBackendArray, 0, size); } -static void +void ShmemBackendArrayAdd(Backend *bn) { /* The array slot corresponding to my PMChildSlot should be free */ diff --git a/src/backend/postmaster/subprocess.c b/src/backend/postmaster/subprocess.c index f9d07de4ae..d4df791aeb 100644 --- a/src/backend/postmaster/subprocess.c +++ b/src/backend/postmaster/subprocess.c @@ -14,6 +14,7 @@ #include "bootstrap/bootstrap.h" #include "pgstat.h" #include "postmaster/autovacuum.h" +#include "postmaster/bgworker_internals.h" #include "postmaster/bgwriter.h" #include "postmaster/pgarch.h" #include "postmaster/postmaster.h" @@ -158,6 +159,17 @@ static PgSubprocess process_types[] = { .entrypoint = SysLoggerMain, .fork_failure = NULL, .postmaster_main = SysLoggerPostmasterMain + }, + { + .name = "bgworker", + .desc = "background worker", + .needs_aux_proc = false, + .needs_shmem = true, + .keep_postmaster_memcontext = true, + .fork_prep = BackgroundWorkerPrep, + .entrypoint = BackgroundWorkerMain, + .fork_failure = BackgroundWorkerForkFailure, + .postmaster_main = BackgroundWorkerPostmasterMain } }; diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c index eb19644419..b31ce82f75 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -38,6 +38,7 @@ volatile uint32 QueryCancelHoldoffCount = 0; volatile uint32 CritSectionCount = 0; int MyProcPid; +int MyChildProcPid; pg_time_t MyStartTime; TimestampTz MyStartTimestamp; struct Port *MyProcPort; diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 14fa127ab1..541ca5145d 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -163,6 +163,7 @@ extern PGDLLIMPORT int max_worker_processes; extern PGDLLIMPORT int max_parallel_workers; extern PGDLLIMPORT int MyProcPid; +extern PGDLLIMPORT int MyChildProcPid; extern PGDLLIMPORT pg_time_t MyStartTime; extern PGDLLIMPORT TimestampTz MyStartTimestamp; extern PGDLLIMPORT struct Port *MyProcPort; diff --git a/src/include/postmaster/bgworker_internals.h b/src/include/postmaster/bgworker_internals.h index f7e24664d5..874d5a203f 100644 --- a/src/include/postmaster/bgworker_internals.h +++ b/src/include/postmaster/bgworker_internals.h @@ -43,6 +43,7 @@ typedef struct RegisteredBgWorker } RegisteredBgWorker; extern slist_head BackgroundWorkerList; +extern RegisteredBgWorker *MyRegisteredBgWorker; extern Size BackgroundWorkerShmemSize(void); extern void BackgroundWorkerShmemInit(void); @@ -53,8 +54,11 @@ extern void ReportBackgroundWorkerExit(slist_mutable_iter *cur); extern void BackgroundWorkerStopNotifications(pid_t pid); extern void ResetBackgroundWorkerCrashTimes(void); -/* Function to start a background worker, called from postmaster.c */ -extern void StartBackgroundWorker(void) pg_attribute_noreturn(); +/* BgWorkerType subprocess */ +extern int BackgroundWorkerPrep(int argc, char *argv[]); +extern void BackgroundWorkerMain(int argc, char *argv[]); +extern bool BackgroundWorkerForkFailure(int fork_errno); +extern void BackgroundWorkerPostmasterMain(int argc, char *argv[]); #ifdef EXEC_BACKEND extern BackgroundWorker *BackgroundWorkerEntry(int slotno); diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h index babc87dfc9..b1411c1ed2 100644 --- a/src/include/postmaster/postmaster.h +++ b/src/include/postmaster/postmaster.h @@ -13,6 +13,41 @@ #ifndef _POSTMASTER_H #define _POSTMASTER_H +#include "lib/ilist.h" + +/* + * List of active backends (or child processes anyway; we don't actually + * know whether a given child has become a backend or is still in the + * authorization phase). This is used mainly to keep track of how many + * children we have and send them appropriate signals when necessary. + * + * "Special" children such as the startup, bgwriter and autovacuum launcher + * tasks are not in this list. Autovacuum worker and walsender are in it. + * Also, "dead_end" children are in it: these are children launched just for + * the purpose of sending a friendly rejection message to a would-be client. + * We must track them because they are attached to shared memory, but we know + * they will never become live backends. dead_end children are not assigned a + * PMChildSlot. + * + * Background workers are in this list, too. + */ +typedef struct bkend +{ + pid_t pid; /* process id of backend */ + int32 cancel_key; /* cancel key for cancels for this backend */ + int child_slot; /* PMChildSlot for this backend, if any */ + + /* + * Flavor of backend or auxiliary process. Note that BACKEND_TYPE_WALSND + * backends initially announce themselves as BACKEND_TYPE_NORMAL, so if + * bkend_type is normal, you should check for a recent transition. + */ + int bkend_type; + bool dead_end; /* is it going to send an error and quit? */ + bool bgworker_notify; /* gets bgworker start/stop notifications */ + dlist_node elem; /* list link in BackendList */ +} Backend; + /* GUC options */ extern bool EnableSSL; extern int ReservedBackends; @@ -54,14 +89,19 @@ extern int MaxLivePostmasterChildren(void); extern bool PostmasterMarkPIDForWorkerNotify(int); +extern bool RandomCancelKey(int32 *cancel_key); + #ifdef EXEC_BACKEND extern pid_t postmaster_forkexec(int argc, char *argv[]); extern void SubPostmasterMain(int argc, char *argv[]) pg_attribute_noreturn(); extern Size ShmemBackendArraySize(void); extern void ShmemBackendArrayAllocation(void); +extern void ShmemBackendArrayAdd(Backend *bn); #endif +extern PGDLLIMPORT dlist_head BackendList; + /* * Note: MAX_BACKENDS is limited to 2^18-1 because that's the width reserved * for buffer references in buf_internals.h. This limitation could be lifted @@ -74,4 +114,17 @@ extern void ShmemBackendArrayAllocation(void); */ #define MAX_BACKENDS 0x3FFFF +/* + * Possible types of a backend. Beyond being the possible bkend_type values in + * struct bkend, these are OR-able request flag bits for SignalSomeChildren() + * and CountChildren(). + */ +#define BACKEND_TYPE_NORMAL 0x0001 /* normal backend */ +#define BACKEND_TYPE_AUTOVAC 0x0002 /* autovacuum worker process */ +#define BACKEND_TYPE_WALSND 0x0004 /* walsender process */ +#define BACKEND_TYPE_BGWORKER 0x0008 /* bgworker process */ +#define BACKEND_TYPE_ALL 0x000F /* OR of all the above */ + +#define BACKEND_TYPE_WORKER (BACKEND_TYPE_AUTOVAC | BACKEND_TYPE_BGWORKER) + #endif /* _POSTMASTER_H */ diff --git a/src/include/postmaster/subprocess.h b/src/include/postmaster/subprocess.h index d0d98a5d69..706d60e4d6 100644 --- a/src/include/postmaster/subprocess.h +++ b/src/include/postmaster/subprocess.h @@ -28,6 +28,7 @@ typedef enum PgstatCollectorType, PgArchiverType, SysLoggerType, + BgWorkerType, NUMSUBPROCESSTYPES /* Must be last! */ } SubprocessType; -- 2.17.0
>From aa2c3209969fe4b6d193b37d92959dfd3809c804 Mon Sep 17 00:00:00 2001 From: Mike Palmiotto <mike.palmio...@crunchydata.com> Date: Mon, 16 Mar 2020 23:05:33 +0000 Subject: [PATCH v2 09/12] Add Backends to subprocess struct --- src/backend/postmaster/postmaster.c | 407 +++++++++++++++------------- src/backend/postmaster/subprocess.c | 11 + src/include/postmaster/postmaster.h | 6 + src/include/postmaster/subprocess.h | 1 + 4 files changed, 235 insertions(+), 190 deletions(-) diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 8343a81923..f979d505df 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -359,7 +359,6 @@ static void BackendInitialize(Port *port); static void BackendRun(Port *port) pg_attribute_noreturn(); static void ExitPostmaster(int status) pg_attribute_noreturn(); static int ServerLoop(void); -static int BackendStartup(Port *port); static int ProcessStartupPacket(Port *port, bool secure_done); static void SendNegotiateProtocolVersion(List *unrecognized_protocol_options); static void processCancelRequest(Port *port, void *pkt); @@ -409,7 +408,6 @@ typedef struct } win32_deadchild_waitinfo; #endif /* WIN32 */ -static pid_t backend_forkexec(Port *port); static pid_t internal_forkexec(int argc, char *argv[], Port *port); /* Type for a socket that can be inherited to a client process */ @@ -512,6 +510,8 @@ int postmaster_alive_fds[2] = {-1, -1}; HANDLE PostmasterHandle; #endif +static Port *ConnProcPort = NULL; + /* * Postmaster main entry point */ @@ -1671,19 +1671,18 @@ ServerLoop(void) break; if (FD_ISSET(ListenSocket[i], &rmask)) { - Port *port; + ConnProcPort = ConnCreate(ListenSocket[i]); - port = ConnCreate(ListenSocket[i]); - if (port) + if (ConnProcPort) { - BackendStartup(port); + StartSubprocess(ClientBackendType); /* * We no longer need the open socket or port structure * in this process */ - StreamClose(port->sock); - ConnFree(port); + StreamClose(ConnProcPort->sock); + ConnFree(ConnProcPort); } } } @@ -3215,6 +3214,174 @@ reaper(SIGNAL_ARGS) errno = save_errno; } +/* + * BackendPrep + * + * Do all of the pre-fork setup for a new Backend. +*/ +int +BackendPrep(int argc, char *argv[]) +{ + /* + * Create backend data structure. Better before the fork() so we can + * handle failure cleanly. + */ + Backend *bn; + + bn = (Backend *) malloc(sizeof(Backend)); + if (!bn) + { + ereport(LOG, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + } + + /* + * Compute the cancel key that will be assigned to this backend. The + * backend will have its own copy in the forked-off process' value of + * MyCancelKey, so that it can transmit the key to the frontend. + */ + if (!RandomCancelKey(&MyCancelKey)) + { + free(bn); + ereport(LOG, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("could not generate random cancel key"))); + } + + bn->cancel_key = MyCancelKey; + + /* Pass down canAcceptConnections state */ + ConnProcPort->canAcceptConnections = canAcceptConnections(BACKEND_TYPE_NORMAL); + bn->dead_end = (ConnProcPort->canAcceptConnections != CAC_OK && + ConnProcPort->canAcceptConnections != CAC_WAITBACKUP); + + /* + * Unless it's a dead_end child, assign it a child slot number + */ + if (!bn->dead_end) + bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot(); + else + bn->child_slot = 0; + + /* Hasn't asked to be notified about any bgworkers yet */ + bn->bgworker_notify = false; + + /* + * Push the Backend to the stack as-is so it can be retreived by the parent + * on the other side of the fork/exec. They will modify this entry in place. + */ + dlist_push_head(&BackendList, &bn->elem); + + return 0; +} + +/* + * BackendMain + * + * Child code when forking a Backend. + */ +void BackendMain(pg_attribute_unused() int argc, pg_attribute_unused() char *argv[]) +{ + /* + * Perform additional initialization and collect startup packet. + * + * We want to do this before InitProcess() for a couple of reasons: 1. + * so that we aren't eating up a PGPROC slot while waiting on the + * client. 2. so that if InitProcess() fails due to being out of + * PGPROC slots, we have already initialized libpq and are able to + * report the error to the client. + */ +#ifndef EXEC_BACKEND + BackendInitialize(ConnProcPort); +#endif + + /* And run the backend */ + BackendRun(ConnProcPort); /* does not return */ +} + +/* + * BackendPostmasterMain + * + * Parent code when forking a Backend. + */ +void BackendPostmasterMain(pg_attribute_unused() int argc, pg_attribute_unused() char *argv[]) +{ + dlist_mutable_iter iter; + + /* + * Find our backend node by popping the element with a matching child slot + * off the list. This was pushed to the stack (incomplete) by BackendPrep. + * We need to fix it up and push back. + */ + dlist_foreach_modify(iter, &BackendList) + { + Backend *bp = dlist_container(Backend, elem, iter.cur); + + /* MyPMChildSlot is guaranteed to match the child MyPMChildSlot */ + if (bp->child_slot == MyPMChildSlot) + { + /* + * Everything's been successful, it's safe to add this backend to our list + * of backends. + */ + bp->pid = MyChildProcPid; + bp->bkend_type = BACKEND_TYPE_NORMAL; /* Can change later to WALSND */ + +#ifdef EXEC_BACKEND + if (!bp->dead_end) + ShmemBackendArrayAdd(bp); +#endif + break; /* There is only one entry and we've found it */ + } + } + + /* in parent, successful fork */ + ereport(DEBUG2, + (errmsg_internal("forked new backend, pid=%d socket=%d", + (int) MyChildProcPid, (int) MyProcPort->sock))); +} + +/* + * BackendForkFailure + * + * Backend cleanup in case a failure occurs forking a new Backend. + */ +bool +BackendForkFailure(int child_errno) +{ + dlist_mutable_iter iter; + + dlist_foreach_modify(iter, &BackendList) + { + Backend *bp = dlist_container(Backend, elem, iter.cur); + + if (bp->child_slot == MyPMChildSlot) + { + if (!bp->dead_end) + { + if (!ReleasePostmasterChildSlot(bp->child_slot)) + { + /* Could not release child slot! Panic! */ + return true; + } +#ifdef EXEC_BACKEND + ShmemBackendArrayRemove(bp); +#endif + } + dlist_delete(iter.cur); + free(bp); + break; + } + } + + report_fork_failure_to_client(MyProcPort, child_errno); + + /* Don't panic */ + return false; +} + + /* * Scan the bgworkers list and see if the given PID (which has just stopped * or crashed) is in it. Handle its shutdown if so, and return true. If not a @@ -4075,122 +4242,6 @@ TerminateChildren(int signal) signal_child(PgStatPID, signal); } -/* - * BackendStartup -- start backend process - * - * returns: STATUS_ERROR if the fork failed, STATUS_OK otherwise. - * - * Note: if you change this code, also consider StartAutovacuumWorker. - */ -static int -BackendStartup(Port *port) -{ - Backend *bn; /* for backend cleanup */ - pid_t pid; - - /* - * Create backend data structure. Better before the fork() so we can - * handle failure cleanly. - */ - bn = (Backend *) malloc(sizeof(Backend)); - if (!bn) - { - ereport(LOG, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); - return STATUS_ERROR; - } - - /* - * Compute the cancel key that will be assigned to this backend. The - * backend will have its own copy in the forked-off process' value of - * MyCancelKey, so that it can transmit the key to the frontend. - */ - if (!RandomCancelKey(&MyCancelKey)) - { - free(bn); - ereport(LOG, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("could not generate random cancel key"))); - return STATUS_ERROR; - } - - bn->cancel_key = MyCancelKey; - - /* Pass down canAcceptConnections state */ - port->canAcceptConnections = canAcceptConnections(BACKEND_TYPE_NORMAL); - bn->dead_end = (port->canAcceptConnections != CAC_OK && - port->canAcceptConnections != CAC_WAITBACKUP); - - /* - * Unless it's a dead_end child, assign it a child slot number - */ - if (!bn->dead_end) - bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot(); - else - bn->child_slot = 0; - - /* Hasn't asked to be notified about any bgworkers yet */ - bn->bgworker_notify = false; - -#ifdef EXEC_BACKEND - pid = backend_forkexec(port); -#else /* !EXEC_BACKEND */ - pid = fork_process(); - if (pid == 0) /* child */ - { - free(bn); - - /* Detangle from postmaster */ - InitPostmasterChild(); - - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - - /* Perform additional initialization and collect startup packet */ - BackendInitialize(port); - - /* And run the backend */ - BackendRun(port); - } -#endif /* EXEC_BACKEND */ - - if (pid < 0) - { - /* in parent, fork failed */ - int save_errno = errno; - - if (!bn->dead_end) - (void) ReleasePostmasterChildSlot(bn->child_slot); - free(bn); - errno = save_errno; - ereport(LOG, - (errmsg("could not fork new process for connection: %m"))); - report_fork_failure_to_client(port, save_errno); - return STATUS_ERROR; - } - - /* in parent, successful fork */ - ereport(DEBUG2, - (errmsg_internal("forked new backend, pid=%d socket=%d", - (int) pid, (int) port->sock))); - - /* - * Everything's been successful, it's safe to add this backend to our list - * of backends. - */ - bn->pid = pid; - bn->bkend_type = BACKEND_TYPE_NORMAL; /* Can change later to WALSND */ - dlist_push_head(&BackendList, &bn->elem); - -#ifdef EXEC_BACKEND - if (!bn->dead_end) - ShmemBackendArrayAdd(bn); -#endif - - return STATUS_OK; -} - /* * Try to report backend fork() failure to client before we close the * connection. Since we do not care to risk blocking the postmaster on @@ -4483,33 +4534,12 @@ postmaster_forkexec(int argc, char *argv[]) Port port; /* This entry point passes dummy values for the Port variables */ - memset(&port, 0, sizeof(port)); - return internal_forkexec(argc, argv, &port); -} - -/* - * backend_forkexec -- fork/exec off a backend process - * - * Some operating systems (WIN32) don't have fork() so we have to simulate - * it by storing parameters that need to be passed to the child and - * then create a new child process. - * - * returns the pid of the fork/exec'd process, or -1 on failure - */ -static pid_t -backend_forkexec(Port *port) -{ - char *av[4]; - int ac = 0; - - av[ac++] = "postgres"; - av[ac++] = "--forkbackend"; - av[ac++] = NULL; /* filled in by internal_forkexec */ - - av[ac] = NULL; - Assert(ac < lengthof(av)); + if (!ConnProcPort) + memset(&port, 0, sizeof(port)); + else + port = *ConnProcPort; - return internal_forkexec(ac, av, port); + return internal_forkexec(argc, argv, &port); } #ifndef WIN32 @@ -4849,6 +4879,7 @@ SubPostmasterMain(int argc, char *argv[]) /* Read in the variables file */ memset(&port, 0, sizeof(Port)); read_backend_variables(argv[2], &port); + ConnProcPort = &port; /* Close the postmaster's sockets (as soon as we know them) */ ClosePostmasterPorts(strcmp(argv[1], "--forklog") == 0); @@ -4890,11 +4921,7 @@ SubPostmasterMain(int argc, char *argv[]) * sometimes impossible to attach to shared memory at the desired address. * Return the setting to its old value (usually '1' or '2') when finished. */ - if (strcmp(argv[1], "--forkbackend") == 0 || - strcmp(argv[1], "--forkavlauncher") == 0 || - strcmp(argv[1], "--forkavworker") == 0 || - strcmp(argv[1], "--forkboot") == 0 || - strncmp(argv[1], "--forkbgworker=", 15) == 0) + if (MySubprocess->needs_shmem) PGSharedMemoryReAttach(); else PGSharedMemoryNoReAttach(); @@ -4943,11 +4970,23 @@ SubPostmasterMain(int argc, char *argv[]) */ process_shared_preload_libraries(); - /* Run backend or appropriate child */ - if (strcmp(argv[1], "--forkbackend") == 0) + if (MySubprocess->needs_aux_proc) { - Assert(argc == 3); /* shouldn't be any more args */ + /* Restore basic shared memory pointers */ + InitShmemAccess(UsedShmemSegAddr); + /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */ + InitAuxiliaryProcess(); + + /* Attach process to shared data structures */ + CreateSharedMemoryAndSemaphores(); + + AuxiliaryProcessMain(argc - 2, argv + 2); /* does not return */ + } + + /* Run backend or appropriate child */ + if (MySubprocessType == ClientBackendType) + { /* * Need to reinitialize the SSL library in the backend, since the * context structures contain function pointers and cannot be passed @@ -4981,32 +5020,6 @@ SubPostmasterMain(int argc, char *argv[]) * report the error to the client. */ BackendInitialize(&port); - - /* Restore basic shared memory pointers */ - InitShmemAccess(UsedShmemSegAddr); - - /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */ - InitProcess(); - - /* Attach process to shared data structures */ - CreateSharedMemoryAndSemaphores(); - - /* And run the backend */ - BackendRun(&port); /* does not return */ - } - - if (MySubprocess->needs_aux_proc) - { - /* Restore basic shared memory pointers */ - InitShmemAccess(UsedShmemSegAddr); - - /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */ - InitAuxiliaryProcess(); - - /* Attach process to shared data structures */ - CreateSharedMemoryAndSemaphores(); - - AuxiliaryProcessMain(argc - 2, argv + 2); /* does not return */ } if (MySubprocessType == BgWorkerType) @@ -5027,15 +5040,29 @@ SubPostmasterMain(int argc, char *argv[]) CreateSharedMemoryAndSemaphores(); } - if (MySubprocessType == BgWorkerType) + switch (MySubprocessType) { - /* Fetch MyBgworkerEntry from shared memory */ - shmem_slot = atoi(argv[1] + 15); - MyBgworkerEntry = BackgroundWorkerEntry(shmem_slot); + case AutoVacuumLauncherType: + case AutoVacuumWorkerType: + MySubprocess->entrypoint(argc - 2, argv + 2); + break; + case BgWorkerType: + /* Fetch MyBgworkerEntry from shared memory */ + shmem_slot = atoi(argv[1] + 15); + MyBgworkerEntry = BackgroundWorkerEntry(shmem_slot); + /* fallthrough */ + case PgArchiverType: + case PgstatCollectorType: + case SysLoggerType: + case ClientBackendType: + MySubprocess->entrypoint(argc, argv); + break; + default: + ereport(LOG, + (errmsg("could not start unknown process type (%d) under postmaster", + MySubprocessType))); } - MySubprocess->entrypoint(argc - 2, argv + 2); - abort(); /* shouldn't get here */ } #endif /* EXEC_BACKEND */ diff --git a/src/backend/postmaster/subprocess.c b/src/backend/postmaster/subprocess.c index d4df791aeb..9d7ce86918 100644 --- a/src/backend/postmaster/subprocess.c +++ b/src/backend/postmaster/subprocess.c @@ -170,6 +170,17 @@ static PgSubprocess process_types[] = { .entrypoint = BackgroundWorkerMain, .fork_failure = BackgroundWorkerForkFailure, .postmaster_main = BackgroundWorkerPostmasterMain + }, + { + .name = "backend", + .desc = "backend", + .needs_aux_proc = false, + .needs_shmem = true, + .keep_postmaster_memcontext = true, + .fork_prep = BackendPrep, + .entrypoint = BackendMain, + .fork_failure = BackendForkFailure, + .postmaster_main = BackendPostmasterMain } }; diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h index b1411c1ed2..6bc0af7c2b 100644 --- a/src/include/postmaster/postmaster.h +++ b/src/include/postmaster/postmaster.h @@ -91,6 +91,12 @@ extern bool PostmasterMarkPIDForWorkerNotify(int); extern bool RandomCancelKey(int32 *cancel_key); +extern int BackendPrep(int argc, char *argv[]); +extern void BackendMain(int argc, char *argv[]); +extern void BackendPostmasterMain(int argc, char *argv[]); +extern bool BackendForkFailure(int child_errno); +extern void BackgroundWorkerMain(int argc, char *argv[]); + #ifdef EXEC_BACKEND extern pid_t postmaster_forkexec(int argc, char *argv[]); extern void SubPostmasterMain(int argc, char *argv[]) pg_attribute_noreturn(); diff --git a/src/include/postmaster/subprocess.h b/src/include/postmaster/subprocess.h index 706d60e4d6..06e67efecc 100644 --- a/src/include/postmaster/subprocess.h +++ b/src/include/postmaster/subprocess.h @@ -29,6 +29,7 @@ typedef enum PgArchiverType, SysLoggerType, BgWorkerType, + ClientBackendType, NUMSUBPROCESSTYPES /* Must be last! */ } SubprocessType; -- 2.17.0
>From f0f10fce0d28847d33a1145ab93b478fac2308fa Mon Sep 17 00:00:00 2001 From: Mike Palmiotto <mike.palmio...@crunchydata.com> Date: Tue, 17 Mar 2020 18:39:12 +0000 Subject: [PATCH v2 10/12] Add WalSenderType to subprocess struct --- src/backend/postmaster/subprocess.c | 11 +++++++++++ src/include/postmaster/subprocess.h | 1 + 2 files changed, 12 insertions(+) diff --git a/src/backend/postmaster/subprocess.c b/src/backend/postmaster/subprocess.c index 9d7ce86918..8cc88792ea 100644 --- a/src/backend/postmaster/subprocess.c +++ b/src/backend/postmaster/subprocess.c @@ -181,6 +181,17 @@ static PgSubprocess process_types[] = { .entrypoint = BackendMain, .fork_failure = BackendForkFailure, .postmaster_main = BackendPostmasterMain + }, + { /* Wal Sender placeholder */ + .name = "walsender", + .desc = "wal sender", + .needs_aux_proc = false, + .needs_shmem = false, + .keep_postmaster_memcontext = false, + .fork_prep = NULL, + .entrypoint = NULL, + .fork_failure = NULL, + .postmaster_main = NULL } }; diff --git a/src/include/postmaster/subprocess.h b/src/include/postmaster/subprocess.h index 06e67efecc..867e1cb499 100644 --- a/src/include/postmaster/subprocess.h +++ b/src/include/postmaster/subprocess.h @@ -31,6 +31,7 @@ typedef enum BgWorkerType, ClientBackendType, + WalSenderType, /* placeholder for wal sender so it can be identified in pgstat */ NUMSUBPROCESSTYPES /* Must be last! */ } SubprocessType; -- 2.17.0
>From b6108d834dec272440f4bc69ad8a5f170e9054b1 Mon Sep 17 00:00:00 2001 From: Mike Palmiotto <mike.palmio...@crunchydata.com> Date: Tue, 17 Mar 2020 18:39:30 +0000 Subject: [PATCH v2 11/12] Get rid of st_beckendType and use MySubprocess --- src/backend/postmaster/pgstat.c | 7 +++---- src/backend/postmaster/postmaster.c | 1 + src/backend/utils/adt/pgstatfuncs.c | 10 ++++++---- src/include/pgstat.h | 3 --- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 6d4f2ace56..6bb063420f 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -2820,7 +2820,6 @@ pgstat_bestart(void) * out-of-line data. Those have to be handled separately, below. */ lbeentry.st_procpid = MyProcPid; - lbeentry.st_backendType = MyBackendType; lbeentry.st_proc_start_timestamp = MyStartTimestamp; lbeentry.st_activity_start_timestamp = 0; lbeentry.st_state_start_timestamp = 0; @@ -2828,9 +2827,9 @@ pgstat_bestart(void) lbeentry.st_databaseid = MyDatabaseId; /* We have userid for client-backends, wal-sender and bgworker processes */ - if (lbeentry.st_backendType == B_BACKEND - || lbeentry.st_backendType == B_WAL_SENDER - || lbeentry.st_backendType == B_BG_WORKER) + if (MySubprocessType == ClientBackendType + || MySubprocessType == WalSenderType + || MySubprocessType == BgWorkerType) lbeentry.st_userid = GetSessionUserId(); else lbeentry.st_userid = InvalidOid; diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index f979d505df..65305a18ee 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -2085,6 +2085,7 @@ retry1: */ if (strcmp(valptr, "database") == 0) { + InitMySubprocess(WalSenderType); am_walsender = true; am_db_walsender = true; } diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index cea01534a5..599e9219ec 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -24,6 +24,7 @@ #include "pgstat.h" #include "postmaster/bgworker_internals.h" #include "postmaster/postmaster.h" +#include "postmaster/subprocess.h" #include "storage/proc.h" #include "storage/procarray.h" #include "utils/acl.h" @@ -693,7 +694,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) proc = BackendPidGetProc(beentry->st_procpid); - if (proc == NULL && (beentry->st_backendType != B_BACKEND)) + if (proc == NULL && (MySubprocessType != ClientBackendType)) { /* * For an auxiliary process, retrieve process info from @@ -741,7 +742,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) * date. */ if (beentry->st_xact_start_timestamp != 0 && - beentry->st_backendType != B_WAL_SENDER) + MySubprocessType != WalSenderType) values[8] = TimestampTzGetDatum(beentry->st_xact_start_timestamp); else nulls[8] = true; @@ -829,7 +830,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) } } /* Add backend type */ - if (beentry->st_backendType == B_BG_WORKER) + if (MySubprocessType == BgWorkerType) { const char *bgw_type; @@ -841,7 +842,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) } else values[17] = - CStringGetTextDatum(GetBackendTypeDesc(beentry->st_backendType)); + // CStringGetTextDatum(GetBackendTypeDesc(beentry->st_backendType)); + CStringGetTextDatum(MySubprocess->desc); /* SSL information */ if (beentry->st_ssl) diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 92943f5cff..405a3224cd 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -1031,9 +1031,6 @@ typedef struct PgBackendStatus /* The entry is valid iff st_procpid > 0, unused if st_procpid == 0 */ int st_procpid; - /* Type of backends */ - BackendType st_backendType; - /* Times when current backend, transaction, and activity started */ TimestampTz st_proc_start_timestamp; TimestampTz st_xact_start_timestamp; -- 2.17.0
>From e34e34399e65ab40660f927eedc2cdbae0b4d76e Mon Sep 17 00:00:00 2001 From: Mike Palmiotto <mike.palmio...@crunchydata.com> Date: Tue, 17 Mar 2020 14:43:52 -0400 Subject: [PATCH v2 12/12] Move away from argv string comparison --- src/backend/postmaster/postmaster.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 65305a18ee..b31fcc7d12 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -4883,7 +4883,7 @@ SubPostmasterMain(int argc, char *argv[]) ConnProcPort = &port; /* Close the postmaster's sockets (as soon as we know them) */ - ClosePostmasterPorts(strcmp(argv[1], "--forklog") == 0); + ClosePostmasterPorts(MySubprocessType == SysLoggerType); /* * Set reference point for stack-depth checking @@ -4928,9 +4928,9 @@ SubPostmasterMain(int argc, char *argv[]) PGSharedMemoryNoReAttach(); /* autovacuum needs this set before calling InitProcess */ - if (strcmp(argv[1], "--forkavlauncher") == 0) + if (MySubprocessType == AutoVacuumLauncherType) AutovacuumLauncherIAm(); - if (strcmp(argv[1], "--forkavworker") == 0) + if (MySubprocessType == AutoVacuumWorkerType) AutovacuumWorkerIAm(); /* -- 2.17.0