diff options
Diffstat (limited to 'src/backend/postmaster/postmaster.c')
-rw-r--r-- | src/backend/postmaster/postmaster.c | 517 |
1 files changed, 79 insertions, 438 deletions
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 6610bd5f866..9a82c3dafaf 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -2,9 +2,9 @@ * * postmaster.c * This program acts as a clearing house for requests to the - * POSTGRES system. Frontend programs send a startup message - * to the Postmaster and the postmaster uses the info in the - * message to setup a backend process. + * POSTGRES system. Frontend programs connect to the Postmaster, + * and postmaster forks a new backend process to handle the + * connection. * * The postmaster also manages system-wide operations such as * startup and shutdown. The postmaster itself doesn't do those @@ -106,7 +106,6 @@ #include "postmaster/autovacuum.h" #include "postmaster/auxprocess.h" #include "postmaster/bgworker_internals.h" -#include "postmaster/fork_process.h" #include "postmaster/pgarch.h" #include "postmaster/postmaster.h" #include "postmaster/syslogger.h" @@ -427,7 +426,6 @@ typedef enum CAC_state } CAC_state; static void BackendInitialize(ClientSocket *client_sock, CAC_state cac); -static void BackendRun(void) pg_attribute_noreturn(); static void ExitPostmaster(int status) pg_attribute_noreturn(); static int ServerLoop(void); static int BackendStartup(ClientSocket *client_sock); @@ -485,13 +483,6 @@ typedef struct } win32_deadchild_waitinfo; #endif /* WIN32 */ -static pid_t backend_forkexec(ClientSocket *client_sock, CAC_state cac); - - -/* in launch_backend.c */ -extern pid_t internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundWorker *worker); -extern void read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **worker); - static void ShmemBackendArrayAdd(Backend *bn); static void ShmemBackendArrayRemove(Backend *bn); #endif /* EXEC_BACKEND */ @@ -1748,7 +1739,7 @@ ServerLoop(void) (AutoVacuumingActive() || start_autovac_launcher) && pmState == PM_RUN) { - AutoVacPID = StartAutoVacLauncher(); + AutoVacPID = StartChildProcess(B_AUTOVAC_LAUNCHER); if (AutoVacPID != 0) start_autovac_launcher = false; /* signal processed */ } @@ -2902,7 +2893,7 @@ process_pm_child_exit(void) * situation, some of them may be alive already. */ if (!IsBinaryUpgrade && AutoVacuumingActive() && AutoVacPID == 0) - AutoVacPID = StartAutoVacLauncher(); + AutoVacPID = StartChildProcess(B_AUTOVAC_LAUNCHER); if (PgArchStartupAllowed() && PgArchPID == 0) PgArchPID = StartChildProcess(B_ARCHIVER); MaybeStartSlotSyncWorker(); @@ -3964,6 +3955,12 @@ TerminateChildren(int signal) signal_child(SlotSyncWorkerPID, signal); } +/* Information passed from postmaster to backend process */ +typedef struct BackendStartupData +{ + CAC_state canAcceptConnections; +} BackendStartupData; + /* * BackendStartup -- start backend process * @@ -3976,7 +3973,7 @@ BackendStartup(ClientSocket *client_sock) { Backend *bn; /* for backend cleanup */ pid_t pid; - CAC_state cac; + BackendStartupData startup_data; /* * Create backend data structure. Better before the fork() so we can @@ -4005,11 +4002,10 @@ BackendStartup(ClientSocket *client_sock) return STATUS_ERROR; } - bn->cancel_key = MyCancelKey; - /* Pass down canAcceptConnections state */ - cac = canAcceptConnections(BACKEND_TYPE_NORMAL); - bn->dead_end = (cac != CAC_OK); + startup_data.canAcceptConnections = canAcceptConnections(BACKEND_TYPE_NORMAL); + bn->dead_end = (startup_data.canAcceptConnections != CAC_OK); + bn->cancel_key = MyCancelKey; /* * Unless it's a dead_end child, assign it a child slot number @@ -4022,26 +4018,9 @@ BackendStartup(ClientSocket *client_sock) /* Hasn't asked to be notified about any bgworkers yet */ bn->bgworker_notify = false; -#ifdef EXEC_BACKEND - pid = backend_forkexec(client_sock, cac); -#else /* !EXEC_BACKEND */ - pid = fork_process(); - if (pid == 0) /* child */ - { - /* Detangle from postmaster */ - InitPostmasterChild(); - - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - - /* Perform additional initialization and collect startup packet */ - BackendInitialize(client_sock, cac); - - /* And run the backend */ - BackendRun(); - } -#endif /* EXEC_BACKEND */ - + pid = postmaster_child_launch(B_BACKEND, + (char *) &startup_data, sizeof(startup_data), + client_sock); if (pid < 0) { /* in parent, fork failed */ @@ -4351,269 +4330,57 @@ BackendInitialize(ClientSocket *client_sock, CAC_state cac) set_ps_display("initializing"); } - -/* - * BackendRun -- set up the backend's argument list and invoke PostgresMain() - * - * returns: - * Doesn't return at all. - */ -static void -BackendRun(void) -{ - /* - * Create a per-backend PGPROC struct in shared memory. We must do this - * before we can use LWLocks or access any shared memory. - */ - InitProcess(); - - /* - * Make sure we aren't in PostmasterContext anymore. (We can't delete it - * just yet, though, because InitPostgres will need the HBA data.) - */ - MemoryContextSwitchTo(TopMemoryContext); - - PostgresMain(MyProcPort->database_name, MyProcPort->user_name); -} - - -#ifdef EXEC_BACKEND - -/* - * postmaster_forkexec -- fork and exec a postmaster subprocess - * - * The caller must have set up the argv array already, except for argv[2] - * which will be filled with the name of the temp variable file. - * - * Returns the child process PID, or -1 on fork failure (a suitable error - * message has been logged on failure). - * - * All uses of this routine will dispatch to SubPostmasterMain in the - * child process. - */ -pid_t -postmaster_forkexec(int argc, char *argv[]) -{ - return internal_forkexec(argc, argv, NULL, NULL); -} - -/* - * 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(ClientSocket *client_sock, CAC_state cac) -{ - char *av[5]; - int ac = 0; - char cacbuf[10]; - - av[ac++] = "postgres"; - av[ac++] = "--forkbackend"; - av[ac++] = NULL; /* filled in by internal_forkexec */ - - snprintf(cacbuf, sizeof(cacbuf), "%d", (int) cac); - av[ac++] = cacbuf; - - av[ac] = NULL; - Assert(ac < lengthof(av)); - - return internal_forkexec(ac, av, client_sock, NULL); -} - -/* - * SubPostmasterMain -- Get the fork/exec'd process into a state equivalent - * to what it would be if we'd simply forked on Unix, and then - * dispatch to the appropriate place. - * - * The first two command line arguments are expected to be "--forkFOO" - * (where FOO indicates which postmaster child we are to become), and - * the name of a variables file that we can read to load data that would - * have been inherited by fork() on Unix. Remaining arguments go to the - * subprocess FooMain() routine. - */ void -SubPostmasterMain(int argc, char *argv[]) +BackendMain(char *startup_data, size_t startup_data_len) { - ClientSocket *client_sock; - BackgroundWorker *worker; - - /* In EXEC_BACKEND case we will not have inherited these settings */ - IsPostmasterEnvironment = true; - whereToSendOutput = DestNone; - - /* Setup essential subsystems (to ensure elog() behaves sanely) */ - InitializeGUCOptions(); - - /* Check we got appropriate args */ - if (argc < 3) - elog(FATAL, "invalid subpostmaster invocation"); - - /* Read in the variables file */ - read_backend_variables(argv[2], &client_sock, &worker); + BackendStartupData *bsdata = (BackendStartupData *) startup_data; - /* Close the postmaster's sockets (as soon as we know them) */ - ClosePostmasterPorts(strcmp(argv[1], "--forklog") == 0); + Assert(startup_data_len == sizeof(BackendStartupData)); + Assert(MyClientSocket != NULL); - /* Setup as postmaster child */ - InitPostmasterChild(); +#ifdef EXEC_BACKEND /* - * 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 - * same address the postmaster used. On the other hand, if we choose not - * to re-attach, we may have other cleanup to do. - * - * If testing EXEC_BACKEND on Linux, you should run this as root before - * starting the postmaster: + * Need to reinitialize the SSL library in the backend, since the context + * structures contain function pointers and cannot be passed through the + * parameter file. * - * sysctl -w kernel.randomize_va_space=0 + * If for some reason reload fails (maybe the user installed broken key + * files), soldier on without SSL; that's better than all connections + * becoming impossible. * - * This prevents using randomized stack and code addresses that cause the - * child process's memory map to be different from the parent's, making it - * sometimes impossible to attach to shared memory at the desired address. - * Return the setting to its old value (usually '1' or '2') when finished. + * XXX should we do this in all child processes? For the moment it's + * enough to do it in backend children. */ - if (strcmp(argv[1], "--forkbackend") == 0 || - strcmp(argv[1], "--forkavlauncher") == 0 || - strcmp(argv[1], "--forkssworker") == 0 || - strcmp(argv[1], "--forkavworker") == 0 || - strcmp(argv[1], "--forkaux") == 0 || - strcmp(argv[1], "--forkbgworker") == 0) - PGSharedMemoryReAttach(); - else - PGSharedMemoryNoReAttach(); +#ifdef USE_SSL + if (EnableSSL) + { + if (secure_initialize(false) == 0) + LoadedSSL = true; + else + ereport(LOG, + (errmsg("SSL configuration could not be loaded in child process"))); + } +#endif +#endif - /* Read in remaining GUC variables */ - read_nondefault_variables(); + /* Perform additional initialization and collect startup packet */ + BackendInitialize(MyClientSocket, bsdata->canAcceptConnections); /* - * Check that the data directory looks valid, which will also check the - * privileges on the data directory and update our umask and file/group - * variables for creating files later. Note: this should really be done - * before we create any files or directories. - */ - checkDataDir(); - - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. + * Create a per-backend PGPROC struct in shared memory. We must do this + * before we can use LWLocks or access any shared memory. */ - LocalProcessControlFile(false); + InitProcess(); /* - * Reload any libraries that were preloaded by the postmaster. Since we - * exec'd this process, those libraries didn't come along with us; but we - * should load them into all child processes to be consistent with the - * non-EXEC_BACKEND behavior. + * Make sure we aren't in PostmasterContext anymore. (We can't delete it + * just yet, though, because InitPostgres will need the HBA data.) */ - process_shared_preload_libraries(); - - /* Run backend or appropriate child */ - if (strcmp(argv[1], "--forkbackend") == 0) - { - CAC_state cac; - - Assert(argc == 4); - cac = (CAC_state) atoi(argv[3]); - - /* - * Need to reinitialize the SSL library in the backend, since the - * context structures contain function pointers and cannot be passed - * through the parameter file. - * - * If for some reason reload fails (maybe the user installed broken - * key files), soldier on without SSL; that's better than all - * connections becoming impossible. - * - * XXX should we do this in all child processes? For the moment it's - * enough to do it in backend children. - */ -#ifdef USE_SSL - if (EnableSSL) - { - if (secure_initialize(false) == 0) - LoadedSSL = true; - else - ereport(LOG, - (errmsg("SSL configuration could not be loaded in child process"))); - } -#endif - - /* - * 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. - */ - BackendInitialize(client_sock, cac); - - /* Restore basic shared memory pointers */ - InitShmemAccess(UsedShmemSegAddr); - - /* And run the backend */ - BackendRun(); /* does not return */ - - } - if (strcmp(argv[1], "--forkaux") == 0) - { - BackendType auxtype; - - Assert(argc == 4); - - /* Restore basic shared memory pointers */ - InitShmemAccess(UsedShmemSegAddr); - - auxtype = atoi(argv[3]); - AuxiliaryProcessMain(auxtype); /* does not return */ - } - if (strcmp(argv[1], "--forkavlauncher") == 0) - { - /* Restore basic shared memory pointers */ - InitShmemAccess(UsedShmemSegAddr); - - AutoVacLauncherMain(argc - 2, argv + 2); /* does not return */ - } - if (strcmp(argv[1], "--forkavworker") == 0) - { - /* Restore basic shared memory pointers */ - InitShmemAccess(UsedShmemSegAddr); - - AutoVacWorkerMain(argc - 2, argv + 2); /* does not return */ - } - if (strcmp(argv[1], "--forkssworker") == 0) - { - /* Restore basic shared memory pointers */ - InitShmemAccess(UsedShmemSegAddr); - - ReplSlotSyncWorkerMain(argc - 2, argv + 2); /* does not return */ - } - if (strcmp(argv[1], "--forkbgworker") == 0) - { - /* Restore basic shared memory pointers */ - InitShmemAccess(UsedShmemSegAddr); - - MyBgworkerEntry = worker; - BackgroundWorkerMain(); - } - if (strcmp(argv[1], "--forklog") == 0) - { - /* Do not want to attach to shared memory */ - - SysLoggerMain(argc, argv); /* does not return */ - } + MemoryContextSwitchTo(TopMemoryContext); - abort(); /* shouldn't get here */ + PostgresMain(MyProcPort->database_name, MyProcPort->user_name); } -#endif /* EXEC_BACKEND */ /* @@ -4912,87 +4679,12 @@ StartChildProcess(BackendType type) { pid_t pid; -#ifdef EXEC_BACKEND - { - char *av[10]; - int ac = 0; - char typebuf[32]; - - /* - * Set up command-line arguments for subprocess - */ - av[ac++] = "postgres"; - av[ac++] = "--forkaux"; - av[ac++] = NULL; /* filled in by postmaster_forkexec */ - - snprintf(typebuf, sizeof(typebuf), "%d", type); - av[ac++] = typebuf; - - av[ac] = NULL; - Assert(ac < lengthof(av)); - - pid = postmaster_forkexec(ac, av); - } -#else /* !EXEC_BACKEND */ - pid = fork_process(); - - if (pid == 0) /* child */ - { - InitPostmasterChild(); - - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - - /* Release postmaster's working memory context */ - MemoryContextSwitchTo(TopMemoryContext); - MemoryContextDelete(PostmasterContext); - PostmasterContext = NULL; - - AuxiliaryProcessMain(type); /* does not return */ - } -#endif /* EXEC_BACKEND */ - + pid = postmaster_child_launch(type, NULL, 0, NULL); if (pid < 0) { /* in parent, fork failed */ - int save_errno = errno; - - errno = save_errno; - switch (type) - { - case B_STARTUP: - ereport(LOG, - (errmsg("could not fork startup process: %m"))); - break; - case B_ARCHIVER: - ereport(LOG, - (errmsg("could not fork archiver process: %m"))); - break; - case B_BG_WRITER: - ereport(LOG, - (errmsg("could not fork background writer process: %m"))); - break; - case B_CHECKPOINTER: - ereport(LOG, - (errmsg("could not fork checkpointer process: %m"))); - break; - case B_WAL_WRITER: - ereport(LOG, - (errmsg("could not fork WAL writer process: %m"))); - break; - case B_WAL_RECEIVER: - ereport(LOG, - (errmsg("could not fork WAL receiver process: %m"))); - break; - case B_WAL_SUMMARIZER: - ereport(LOG, - (errmsg("could not fork WAL summarizer process: %m"))); - break; - default: - ereport(LOG, - (errmsg("could not fork process: %m"))); - break; - } + ereport(LOG, + (errmsg("could not fork \"%s\" process: %m", PostmasterChildName(type)))); /* * fork failure is fatal during startup, but there's no need to choke @@ -5056,7 +4748,7 @@ StartAutovacuumWorker(void) bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot(); bn->bgworker_notify = false; - bn->pid = StartAutoVacWorker(); + bn->pid = StartChildProcess(B_AUTOVAC_WORKER); if (bn->pid > 0) { bn->bkend_type = BACKEND_TYPE_AUTOVAC; @@ -5070,7 +4762,7 @@ StartAutovacuumWorker(void) /* * fork failed, fall through to report -- actual error message was - * logged by StartAutoVacWorker + * logged by StartChildProcess */ (void) ReleasePostmasterChildSlot(bn->child_slot); pfree(bn); @@ -5153,7 +4845,7 @@ MaybeStartSlotSyncWorker(void) if (SlotSyncWorkerPID == 0 && pmState == PM_HOT_STANDBY && Shutdown <= SmartShutdown && sync_replication_slots && ValidateSlotSyncParams(LOG) && SlotSyncWorkerCanRestart()) - SlotSyncWorkerPID = StartSlotSyncWorker(); + SlotSyncWorkerPID = StartChildProcess(B_SLOTSYNC_WORKER); } /* @@ -5293,24 +4985,6 @@ BackgroundWorkerUnblockSignals(void) sigprocmask(SIG_SETMASK, &UnBlockSig, NULL); } -#ifdef EXEC_BACKEND -static pid_t -bgworker_forkexec(BackgroundWorker *worker) -{ - char *av[10]; - int ac = 0; - - av[ac++] = "postgres"; - av[ac++] = "--forkbgworker"; - av[ac++] = NULL; /* filled in by internal_forkexec */ - av[ac] = NULL; - - Assert(ac < lengthof(av)); - - return internal_forkexec(ac, av, NULL, worker); -} -#endif - /* * Start a new bgworker. * Starting time conditions must have been checked already. @@ -5347,65 +5021,32 @@ do_start_bgworker(RegisteredBgWorker *rw) (errmsg_internal("starting background worker process \"%s\"", rw->rw_worker.bgw_name))); -#ifdef EXEC_BACKEND - switch ((worker_pid = bgworker_forkexec(&rw->rw_worker))) -#else - switch ((worker_pid = fork_process())) -#endif + worker_pid = postmaster_child_launch(B_BG_WORKER, (char *) &rw->rw_worker, sizeof(BackgroundWorker), NULL); + if (worker_pid == -1) { - case -1: - /* in postmaster, fork failed ... */ - ereport(LOG, - (errmsg("could not fork background worker process: %m"))); - /* undo what assign_backendlist_entry did */ - ReleasePostmasterChildSlot(rw->rw_child_slot); - rw->rw_child_slot = 0; - pfree(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; - - BackgroundWorkerMain(); + /* in postmaster, fork failed ... */ + ereport(LOG, + (errmsg("could not fork background worker process: %m"))); + /* undo what assign_backendlist_entry did */ + ReleasePostmasterChildSlot(rw->rw_child_slot); + rw->rw_child_slot = 0; + pfree(rw->rw_backend); + rw->rw_backend = NULL; + /* mark entry as crashed, so we'll try again later */ + rw->rw_crashed_at = GetCurrentTimestamp(); + return false; + } - 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); + /* 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); + ShmemBackendArrayAdd(rw->rw_backend); #endif - return true; - } - - return false; + return true; } /* |