#include "postgres.h"
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/wait.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <limits.h>
#include "access/transam.h"
#include "access/xlog.h"
#include "bootstrap/bootstrap.h"
#include "catalog/pg_control.h"
#include "lib/ilist.h"
#include "libpq/auth.h"
#include "libpq/ip.h"
#include "libpq/libpq.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "postmaster/bgworker.h"
#include "postmaster/fork_process.h"
#include "postmaster/pgarch.h"
#include "postmaster/postmaster.h"
#include "postmaster/syslogger.h"
#include "replication/walsender.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/pg_shmem.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/datetime.h"
#include "utils/memutils.h"
#include "utils/ps_status.h"
#include "utils/timeout.h"
Go to the source code of this file.
Data Structures | |
struct | bkend |
struct | RegisteredBgWorker |
Defines | |
#define | BACKEND_TYPE_NORMAL 0x0001 |
#define | BACKEND_TYPE_AUTOVAC 0x0002 |
#define | BACKEND_TYPE_WALSND 0x0004 |
#define | BACKEND_TYPE_BGWORKER 0x0008 |
#define | BACKEND_TYPE_ALL 0x000F |
#define | BACKEND_TYPE_WORKER (BACKEND_TYPE_AUTOVAC | BACKEND_TYPE_BGWORKER) |
#define | MAXLISTEN 64 |
#define | NoShutdown 0 |
#define | SmartShutdown 1 |
#define | FastShutdown 2 |
#define | SignalChildren(sig) SignalSomeChildren(sig, BACKEND_TYPE_ALL) |
#define | StartupDataBase() StartChildProcess(StartupProcess) |
#define | StartBackgroundWriter() StartChildProcess(BgWriterProcess) |
#define | StartCheckpointer() StartChildProcess(CheckpointerProcess) |
#define | StartWalWriter() StartChildProcess(WalWriterProcess) |
#define | StartWalReceiver() StartChildProcess(WalReceiverProcess) |
#define | EXIT_STATUS_0(st) ((st) == 0) |
#define | EXIT_STATUS_1(st) (WIFEXITED(st) && WEXITSTATUS(st) == 1) |
#define | OPTS_FILE "postmaster.opts" |
Typedefs | |
typedef struct bkend | Backend |
typedef struct RegisteredBgWorker | RegisteredBgWorker |
Enumerations | |
enum | PMState { PM_INIT, PM_STARTUP, PM_RECOVERY, PM_HOT_STANDBY, PM_RUN, PM_WAIT_BACKUP, PM_WAIT_READONLY, PM_WAIT_BACKENDS, PM_SHUTDOWN, PM_SHUTDOWN_2, PM_WAIT_DEAD_END, PM_NO_CHILDREN } |
Functions | |
static void | unlink_external_pid_file (int status, Datum arg) |
static void | getInstallationPaths (const char *argv0) |
static void | checkDataDir (void) |
static Port * | ConnCreate (int serverFd) |
static void | ConnFree (Port *port) |
static void | reset_shared (int port) |
static void | SIGHUP_handler (SIGNAL_ARGS) |
static void | pmdie (SIGNAL_ARGS) |
static void | reaper (SIGNAL_ARGS) |
static void | sigusr1_handler (SIGNAL_ARGS) |
static void | startup_die (SIGNAL_ARGS) |
static void | dummy_handler (SIGNAL_ARGS) |
static int | GetNumRegisteredBackgroundWorkers (int flags) |
static void | StartupPacketTimeoutHandler (void) |
static void | CleanupBackend (int pid, int exitstatus) |
static bool | CleanupBackgroundWorker (int pid, int exitstatus) |
static void | do_start_bgworker (void) |
static void | HandleChildCrash (int pid, int exitstatus, const char *procname) |
static void | LogChildExit (int lev, const char *procname, int pid, int exitstatus) |
static void | PostmasterStateMachine (void) |
static void | BackendInitialize (Port *port) |
static void | BackendRun (Port *port) __attribute__((noreturn)) |
static void | ExitPostmaster (int status) __attribute__((noreturn)) |
static int | ServerLoop (void) |
static int | BackendStartup (Port *port) |
static int | ProcessStartupPacket (Port *port, bool SSLdone) |
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 (void) |
static long | PostmasterRandom (void) |
static void | RandomSalt (char *md5Salt) |
static void | signal_child (pid_t pid, int signal) |
static bool | SignalSomeChildren (int signal, int targets) |
static bool | SignalUnconnectedWorkers (int signal) |
static int | CountChildren (int target) |
static int | CountUnconnectedWorkers (void) |
static void | StartOneBackgroundWorker (void) |
static bool | CreateOptsFile (int argc, char *argv[], char *fullprogname) |
static pid_t | StartChildProcess (AuxProcType type) |
static void | StartAutovacuumWorker (void) |
static void | InitPostmasterDeathWatchHandle (void) |
void | PostmasterMain (int argc, char *argv[]) |
static void | DetermineSleepTime (struct timeval *timeout) |
void | ClosePostmasterPorts (bool am_syslogger) |
int | MaxLivePostmasterChildren (void) |
void | RegisterBackgroundWorker (BackgroundWorker *worker) |
void | BackgroundWorkerInitializeConnection (char *dbname, char *username) |
void | BackgroundWorkerBlockSignals (void) |
void | BackgroundWorkerUnblockSignals (void) |
static void | bgworker_quickdie (SIGNAL_ARGS) |
static void | bgworker_die (SIGNAL_ARGS) |
static void | bgworker_sigusr1_handler (SIGNAL_ARGS) |
int | GetNumShmemAttachedBgworkers (void) |
static void | start_bgworker (RegisteredBgWorker *rw) |
static bool | bgworker_should_start_now (BgWorkerStartTime start_time) |
static bool | assign_backendlist_entry (RegisteredBgWorker *rw) |
Variables | |
static dlist_head | BackendList = DLIST_STATIC_INIT(BackendList) |
static slist_head | BackgroundWorkerList = SLIST_STATIC_INIT(BackgroundWorkerList) |
BackgroundWorker * | MyBgworkerEntry = NULL |
int | PostPortNumber |
char * | Unix_socket_directories |
char * | ListenAddresses |
int | ReservedBackends |
static pgsocket | ListenSocket [MAXLISTEN] |
static char | ExtraOptions [MAXPGPATH] |
static bool | Reinit = true |
static int | SendStop = false |
bool | EnableSSL = false |
int | PreAuthDelay = 0 |
int | AuthenticationTimeout = 60 |
bool | log_hostname |
bool | Log_connections = false |
bool | Db_user_namespace = false |
bool | enable_bonjour = false |
char * | bonjour_name |
bool | restart_after_crash = true |
char * | output_config_variable = NULL |
static pid_t | StartupPID = 0 |
static pid_t | BgWriterPID = 0 |
static pid_t | CheckpointerPID = 0 |
static pid_t | WalWriterPID = 0 |
static pid_t | WalReceiverPID = 0 |
static pid_t | AutoVacPID = 0 |
static pid_t | PgArchPID = 0 |
static pid_t | PgStatPID = 0 |
static pid_t | SysLoggerPID = 0 |
static int | Shutdown = NoShutdown |
static bool | FatalError = false |
static bool | RecoveryError = false |
static PMState | pmState = PM_INIT |
static bool | ReachedNormalRunning = false |
bool | ClientAuthInProgress = false |
bool | redirection_done = false |
static volatile sig_atomic_t | start_autovac_launcher = false |
static volatile bool | avlauncher_needs_signal = false |
static volatile bool | StartWorkerNeeded = true |
static volatile bool | HaveCrashedWorker = false |
static unsigned int | random_seed = 0 |
static struct timeval | random_start_time |
char * | optarg |
int | optind |
int | opterr |
int | postmaster_alive_fds [2] = {-1, -1} |
#define BACKEND_TYPE_ALL 0x000F |
Definition at line 138 of file postmaster.c.
Referenced by canAcceptConnections(), CountChildren(), PostmasterStateMachine(), and SignalSomeChildren().
#define BACKEND_TYPE_AUTOVAC 0x0002 |
Definition at line 135 of file postmaster.c.
Referenced by pmdie().
#define BACKEND_TYPE_BGWORKER 0x0008 |
Definition at line 137 of file postmaster.c.
Referenced by HandleChildCrash(), and pmdie().
#define BACKEND_TYPE_NORMAL 0x0001 |
Definition at line 134 of file postmaster.c.
Referenced by CountChildren(), pmdie(), PostmasterStateMachine(), and SignalSomeChildren().
#define BACKEND_TYPE_WALSND 0x0004 |
Definition at line 136 of file postmaster.c.
#define BACKEND_TYPE_WORKER (BACKEND_TYPE_AUTOVAC | BACKEND_TYPE_BGWORKER) |
Definition at line 140 of file postmaster.c.
Referenced by PostmasterStateMachine().
#define EXIT_STATUS_0 | ( | st | ) | ((st) == 0) |
Definition at line 539 of file postmaster.c.
Referenced by CleanupBackend(), CleanupBackgroundWorker(), LogChildExit(), and reaper().
#define EXIT_STATUS_1 | ( | st | ) | (WIFEXITED(st) && WEXITSTATUS(st) == 1) |
Definition at line 540 of file postmaster.c.
Referenced by CleanupBackend(), CleanupBackgroundWorker(), and reaper().
#define FastShutdown 2 |
Definition at line 275 of file postmaster.c.
Referenced by pmdie().
#define MAXLISTEN 64 |
Definition at line 227 of file postmaster.c.
#define NoShutdown 0 |
Definition at line 273 of file postmaster.c.
Referenced by canAcceptConnections(), DetermineSleepTime(), PostmasterStateMachine(), reaper(), and sigusr1_handler().
#define OPTS_FILE "postmaster.opts" |
Referenced by CreateOptsFile().
Definition at line 423 of file postmaster.c.
Referenced by pmdie(), PostmasterStateMachine(), reaper(), and SIGHUP_handler().
#define SmartShutdown 1 |
Definition at line 274 of file postmaster.c.
Referenced by pmdie(), and SIGHUP_handler().
#define StartBackgroundWriter | ( | ) | StartChildProcess(BgWriterProcess) |
Definition at line 533 of file postmaster.c.
Referenced by reaper(), ServerLoop(), and sigusr1_handler().
#define StartCheckpointer | ( | ) | StartChildProcess(CheckpointerProcess) |
Definition at line 534 of file postmaster.c.
Referenced by PostmasterStateMachine(), reaper(), ServerLoop(), and sigusr1_handler().
#define StartupDataBase | ( | ) | StartChildProcess(StartupProcess) |
Definition at line 532 of file postmaster.c.
Referenced by PostmasterMain(), and PostmasterStateMachine().
#define StartWalReceiver | ( | ) | StartChildProcess(WalReceiverProcess) |
Definition at line 536 of file postmaster.c.
Referenced by sigusr1_handler().
#define StartWalWriter | ( | ) | StartChildProcess(WalWriterProcess) |
Definition at line 535 of file postmaster.c.
Referenced by reaper(), and ServerLoop().
typedef struct RegisteredBgWorker RegisteredBgWorker |
enum PMState |
PM_INIT | |
PM_STARTUP | |
PM_RECOVERY | |
PM_HOT_STANDBY | |
PM_RUN | |
PM_WAIT_BACKUP | |
PM_WAIT_READONLY | |
PM_WAIT_BACKENDS | |
PM_SHUTDOWN | |
PM_SHUTDOWN_2 | |
PM_WAIT_DEAD_END | |
PM_NO_CHILDREN |
Definition at line 326 of file postmaster.c.
{ PM_INIT, /* postmaster starting */ PM_STARTUP, /* waiting for startup subprocess */ PM_RECOVERY, /* in archive recovery mode */ PM_HOT_STANDBY, /* in hot standby mode */ PM_RUN, /* normal "database is alive" state */ PM_WAIT_BACKUP, /* waiting for online backup mode to end */ PM_WAIT_READONLY, /* waiting for read only backends to exit */ PM_WAIT_BACKENDS, /* waiting for live backends to exit */ PM_SHUTDOWN, /* waiting for checkpointer to do shutdown * ckpt */ PM_SHUTDOWN_2, /* waiting for archiver and walsenders to * finish */ PM_WAIT_DEAD_END, /* waiting for dead_end children to exit */ PM_NO_CHILDREN /* all important children have exited */ } PMState;
static bool assign_backendlist_entry | ( | RegisteredBgWorker * | rw | ) | [static] |
Definition at line 5661 of file postmaster.c.
References AssignPostmasterChildSlot(), bkend::bkend_type, bkend::cancel_key, bkend::child_slot, bkend::dead_end, ereport, errcode(), errmsg(), GetCurrentTimestamp(), LOG, malloc, MyCancelKey, MyPMChildSlot, NULL, PostmasterRandom(), RegisteredBgWorker::rw_backend, RegisteredBgWorker::rw_child_slot, and RegisteredBgWorker::rw_crashed_at.
Referenced by StartOneBackgroundWorker().
{ Backend *bn = malloc(sizeof(Backend)); if (bn == NULL) { ereport(LOG, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); /* * The worker didn't really crash, but setting this nonzero makes * postmaster wait a bit before attempting to start it again; if it * tried again right away, most likely it'd find itself under the same * memory pressure. */ rw->rw_crashed_at = GetCurrentTimestamp(); 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. */ MyCancelKey = PostmasterRandom(); bn->cancel_key = MyCancelKey; bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot(); bn->bkend_type = BACKEND_TYPE_BGWORKER; bn->dead_end = false; rw->rw_backend = bn; rw->rw_child_slot = bn->child_slot; return true; }
static void BackendInitialize | ( | Port * | port | ) | [static] |
Definition at line 3756 of file postmaster.c.
References SockAddr::addr, am_walsender, AuthenticationTimeout, BlockSig, ClientAuthInProgress, Port::database_name, disable_timeout(), elog, enable_timeout_after(), ereport, errmsg(), errmsg_internal(), FATAL, gai_strerror, GetCurrentTimestamp(), init_ps_display(), InitializeTimeouts(), LOG, Log_connections, log_hostname, MyProcPort, MyStartTime, NI_NUMERICHOST, NI_NUMERICSERV, pg_getnameinfo_all(), PG_SETMASK, pg_usleep(), pq_init(), pqsignal(), PreAuthDelay, proc_exit(), ProcessStartupPacket(), Port::raddr, RegisterTimeout(), Port::remote_host, Port::remote_hostname, Port::remote_port, SockAddr::salen, Port::SessionStartTime, SIGQUIT, snprintf(), startup_die(), STARTUP_PACKET_TIMEOUT, StartupBlockSig, StartupPacketTimeoutHandler(), STATUS_OK, timestamptz_to_time_t(), update_process_title, Port::user_name, WARNING, and whereToSendOutput.
Referenced by BackendStartup().
{ int status; int ret; char remote_host[NI_MAXHOST]; char remote_port[NI_MAXSERV]; char remote_ps_data[NI_MAXHOST]; /* Save port etc. for ps status */ MyProcPort = port; /* * PreAuthDelay is a debugging aid for investigating problems in the * authentication cycle: it can be set in postgresql.conf to allow time to * attach to the newly-forked backend with a debugger. (See also * PostAuthDelay, which we allow clients to pass through PGOPTIONS, but it * is not honored until after authentication.) */ if (PreAuthDelay > 0) pg_usleep(PreAuthDelay * 1000000L); /* This flag will remain set until InitPostgres finishes authentication */ ClientAuthInProgress = true; /* limit visibility of log messages */ /* save process start time */ port->SessionStartTime = GetCurrentTimestamp(); MyStartTime = timestamptz_to_time_t(port->SessionStartTime); /* set these to empty in case they are needed before we set them up */ port->remote_host = ""; port->remote_port = ""; /* * Initialize libpq and enable reporting of ereport errors to the client. * Must do this now because authentication uses libpq to send messages. */ pq_init(); /* initialize libpq to talk to client */ whereToSendOutput = DestRemote; /* now safe to ereport to client */ /* * If possible, make this process a group leader, so that the postmaster * can signal any child processes too. (We do this now on the off chance * that something might spawn a child process during authentication.) */ #ifdef HAVE_SETSID if (setsid() < 0) elog(FATAL, "setsid() failed: %m"); #endif /* * We arrange for a simple exit(1) if we receive SIGTERM or SIGQUIT or * timeout while trying to collect the startup packet. Otherwise the * postmaster cannot shutdown the database FAST or IMMED cleanly if a * buggy client fails to send the packet promptly. */ pqsignal(SIGTERM, startup_die); pqsignal(SIGQUIT, startup_die); InitializeTimeouts(); /* establishes SIGALRM handler */ PG_SETMASK(&StartupBlockSig); /* * Get the remote host name and port for logging and status display. */ remote_host[0] = '\0'; remote_port[0] = '\0'; if ((ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen, remote_host, sizeof(remote_host), remote_port, sizeof(remote_port), (log_hostname ? 0 : NI_NUMERICHOST) | NI_NUMERICSERV)) != 0) ereport(WARNING, (errmsg_internal("pg_getnameinfo_all() failed: %s", gai_strerror(ret)))); if (remote_port[0] == '\0') snprintf(remote_ps_data, sizeof(remote_ps_data), "%s", remote_host); else snprintf(remote_ps_data, sizeof(remote_ps_data), "%s(%s)", remote_host, remote_port); if (Log_connections) { if (remote_port[0]) ereport(LOG, (errmsg("connection received: host=%s port=%s", remote_host, remote_port))); else ereport(LOG, (errmsg("connection received: host=%s", remote_host))); } /* * save remote_host and remote_port in port structure */ port->remote_host = strdup(remote_host); port->remote_port = strdup(remote_port); if (log_hostname) port->remote_hostname = port->remote_host; /* * Ready to begin client interaction. We will give up and exit(1) after a * time delay, so that a broken client can't hog a connection * indefinitely. PreAuthDelay and any DNS interactions above don't count * against the time limit. * * Note: AuthenticationTimeout is applied here while waiting for the * startup packet, and then again in InitPostgres for the duration of any * authentication operations. So a hostile client could tie up the * process for nearly twice AuthenticationTimeout before we kick him off. * * Note: because PostgresMain will call InitializeTimeouts again, the * registration of STARTUP_PACKET_TIMEOUT will be lost. This is okay * since we never use it again after this function. */ RegisterTimeout(STARTUP_PACKET_TIMEOUT, StartupPacketTimeoutHandler); enable_timeout_after(STARTUP_PACKET_TIMEOUT, AuthenticationTimeout * 1000); /* * Receive the startup packet (which might turn out to be a cancel request * packet). */ status = ProcessStartupPacket(port, false); /* * Stop here if it was bad or a cancel packet. ProcessStartupPacket * already did any appropriate error reporting. */ if (status != STATUS_OK) proc_exit(0); /* * Now that we have the user and database name, we can set the process * title for ps. It's good to do this as early as possible in startup. * * For a walsender, the ps display is set in the following form: * * postgres: wal sender process <user> <host> <activity> * * To achieve that, we pass "wal sender process" as username and username * as dbname to init_ps_display(). XXX: should add a new variant of * init_ps_display() to avoid abusing the parameters like this. */ if (am_walsender) init_ps_display("wal sender process", port->user_name, remote_ps_data, update_process_title ? "authentication" : ""); else init_ps_display(port->user_name, port->database_name, remote_ps_data, update_process_title ? "authentication" : ""); /* * Disable the timeout, and prevent SIGTERM/SIGQUIT again. */ disable_timeout(STARTUP_PACKET_TIMEOUT, false); PG_SETMASK(&BlockSig); }
static void BackendRun | ( | Port * | port | ) | [static] |
Definition at line 3920 of file postmaster.c.
References Assert, av, Port::database_name, DEBUG3, ereport, errmsg_internal(), ExtraOptions, MemoryContextAlloc(), MemoryContextSwitchTo(), MyProcPid, pg_split_opts(), PostgresMain(), progname, random_seed, random_start_time, Port::SessionStartTime, srandom(), TimestampDifference(), TopMemoryContext, and Port::user_name.
Referenced by BackendStartup().
{ char **av; int maxac; int ac; long secs; int usecs; int i; /* * Don't want backend to be able to see the postmaster random number * generator state. We have to clobber the static random_seed *and* start * a new random sequence in the random() library function. */ random_seed = 0; random_start_time.tv_usec = 0; /* slightly hacky way to get integer microseconds part of timestamptz */ TimestampDifference(0, port->SessionStartTime, &secs, &usecs); srandom((unsigned int) (MyProcPid ^ usecs)); /* * Now, build the argv vector that will be given to PostgresMain. * * The maximum possible number of commandline arguments that could come * from ExtraOptions is (strlen(ExtraOptions) + 1) / 2; see * pg_split_opts(). */ maxac = 2; /* for fixed args supplied below */ maxac += (strlen(ExtraOptions) + 1) / 2; av = (char **) MemoryContextAlloc(TopMemoryContext, maxac * sizeof(char *)); ac = 0; av[ac++] = "postgres"; /* * Pass any backend switches specified with -o on the postmaster's own * command line. We assume these are secure. (It's OK to mangle * ExtraOptions now, since we're safely inside a subprocess.) */ pg_split_opts(av, &ac, ExtraOptions); av[ac] = NULL; Assert(ac < maxac); /* * Debug: print arguments being passed to backend */ ereport(DEBUG3, (errmsg_internal("%s child[%d]: starting with (", progname, (int) getpid()))); for (i = 0; i < ac; ++i) ereport(DEBUG3, (errmsg_internal("\t%s", av[i]))); ereport(DEBUG3, (errmsg_internal(")"))); /* * 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(ac, av, port->database_name, port->user_name); }
static int BackendStartup | ( | Port * | port | ) | [static] |
Definition at line 3606 of file postmaster.c.
References AssignPostmasterChildSlot(), BackendInitialize(), BackendRun(), bkend::bkend_type, CAC_OK, canAcceptConnections(), Port::canAcceptConnections, bkend::cancel_key, bkend::child_slot, ClosePostmasterPorts(), bkend::dead_end, DEBUG2, dlist_push_head(), bkend::elem, ereport, errcode(), errmsg(), errmsg_internal(), fork_process(), free, IsUnderPostmaster, LOG, malloc, MyCancelKey, MyPMChildSlot, MyProcPid, MyStartTime, NULL, on_exit_reset(), bkend::pid, PostmasterRandom(), ReleasePostmasterChildSlot(), report_fork_failure_to_client(), and Port::sock.
Referenced by ServerLoop().
{ 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. */ MyCancelKey = PostmasterRandom(); bn->cancel_key = MyCancelKey; /* Pass down canAcceptConnections state */ port->canAcceptConnections = canAcceptConnections(); 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; #ifdef EXEC_BACKEND pid = backend_forkexec(port); #else /* !EXEC_BACKEND */ pid = fork_process(); if (pid == 0) /* child */ { free(bn); /* * Let's clean up ourselves as the postmaster child, and close the * postmaster's listen sockets. (In EXEC_BACKEND case this is all * done in SubPostmasterMain.) */ IsUnderPostmaster = true; /* we are a postmaster subprocess now */ MyProcPid = getpid(); /* reset MyProcPid */ MyStartTime = time(NULL); /* We don't want the postmaster's proc_exit() handlers */ on_exit_reset(); /* 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; }
void BackgroundWorkerBlockSignals | ( | void | ) |
Definition at line 5287 of file postmaster.c.
References BlockSig, and PG_SETMASK.
{ PG_SETMASK(&BlockSig); }
void BackgroundWorkerInitializeConnection | ( | char * | dbname, | |
char * | username | |||
) |
Definition at line 5264 of file postmaster.c.
References BackgroundWorker::bgw_flags, BGWORKER_BACKEND_DATABASE_CONNECTION, ereport, errcode(), errmsg(), ERROR, FATAL, InitPostgres(), InvalidOid, IsInitProcessingMode, NormalProcessing, NULL, and SetProcessingMode.
Referenced by worker_spi_main().
{ BackgroundWorker *worker = MyBgworkerEntry; /* XXX is this the right errcode? */ if (!(worker->bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION)) ereport(FATAL, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("database connection requirement not indicated during registration"))); InitPostgres(dbname, InvalidOid, username, NULL); /* it had better not gotten out of "init" mode yet */ if (!IsInitProcessingMode()) ereport(ERROR, (errmsg("invalid processing mode in bgworker"))); SetProcessingMode(NormalProcessing); }
void BackgroundWorkerUnblockSignals | ( | void | ) |
Definition at line 5293 of file postmaster.c.
References PG_SETMASK, and UnBlockSig.
Referenced by worker_spi_main().
{ PG_SETMASK(&UnBlockSig); }
static void bgworker_die | ( | SIGNAL_ARGS | ) | [static] |
Definition at line 5347 of file postmaster.c.
References BackgroundWorker::bgw_name, BlockSig, ereport, errcode(), errmsg(), FATAL, and PG_SETMASK.
Referenced by do_start_bgworker().
{ PG_SETMASK(&BlockSig); ereport(FATAL, (errcode(ERRCODE_ADMIN_SHUTDOWN), errmsg("terminating background worker \"%s\" due to administrator command", MyBgworkerEntry->bgw_name))); }
static void bgworker_quickdie | ( | SIGNAL_ARGS | ) | [static] |
Definition at line 5318 of file postmaster.c.
References BlockSig, on_exit_reset(), PG_SETMASK, sigaddset, and SIGQUIT.
Referenced by do_start_bgworker().
{ sigaddset(&BlockSig, SIGQUIT); /* prevent nested calls */ PG_SETMASK(&BlockSig); /* * We DO NOT want to run proc_exit() callbacks -- we're here because * shared memory may be corrupted, so we don't want to try to clean up our * transaction. Just nail the windows shut and get out of town. Now that * there's an atexit callback to prevent third-party code from breaking * things by calling exit() directly, we have to reset the callbacks * explicitly to make this work as intended. */ on_exit_reset(); /* * Note we do exit(0) here, not exit(2) like quickdie. The reason is that * we don't want to be seen this worker as independently crashed, because * then postmaster would delay restarting it again afterwards. If some * idiot DBA manually sends SIGQUIT to a random bgworker, the "dead man * switch" will ensure that postmaster sees this as a crash. */ exit(0); }
static bool bgworker_should_start_now | ( | BgWorkerStartTime | start_time | ) | [static] |
Definition at line 5619 of file postmaster.c.
References BgWorkerStart_ConsistentState, BgWorkerStart_PostmasterStart, BgWorkerStart_RecoveryFinished, PM_HOT_STANDBY, PM_INIT, PM_NO_CHILDREN, PM_RECOVERY, PM_RUN, PM_SHUTDOWN, PM_SHUTDOWN_2, PM_STARTUP, PM_WAIT_BACKENDS, PM_WAIT_BACKUP, PM_WAIT_DEAD_END, PM_WAIT_READONLY, and pmState.
Referenced by StartOneBackgroundWorker().
{ switch (pmState) { case PM_NO_CHILDREN: case PM_WAIT_DEAD_END: case PM_SHUTDOWN_2: case PM_SHUTDOWN: case PM_WAIT_BACKENDS: case PM_WAIT_READONLY: case PM_WAIT_BACKUP: break; case PM_RUN: if (start_time == BgWorkerStart_RecoveryFinished) return true; /* fall through */ case PM_HOT_STANDBY: if (start_time == BgWorkerStart_ConsistentState) return true; /* fall through */ case PM_RECOVERY: case PM_STARTUP: case PM_INIT: if (start_time == BgWorkerStart_PostmasterStart) return true; /* fall through */ } return false; }
static void bgworker_sigusr1_handler | ( | SIGNAL_ARGS | ) | [static] |
Definition at line 5364 of file postmaster.c.
References latch_sigusr1_handler().
Referenced by do_start_bgworker().
{ int save_errno = errno; latch_sigusr1_handler(); errno = save_errno; }
static CAC_state canAcceptConnections | ( | void | ) | [static] |
Definition at line 2068 of file postmaster.c.
References BACKEND_TYPE_ALL, CountChildren(), FatalError, MaxLivePostmasterChildren(), NoShutdown, PM_HOT_STANDBY, PM_RECOVERY, PM_RUN, PM_STARTUP, PM_WAIT_BACKUP, pmState, and Shutdown.
Referenced by BackendStartup(), and StartAutovacuumWorker().
{ CAC_state result = CAC_OK; /* * Can't start backends when in startup/shutdown/inconsistent recovery * state. * * In state PM_WAIT_BACKUP only superusers can connect (this must be * allowed so that a superuser can end online backup mode); we return * CAC_WAITBACKUP code to indicate that this must be checked later. Note * that neither CAC_OK nor CAC_WAITBACKUP can safely be returned until we * have checked for too many children. */ if (pmState != PM_RUN) { if (pmState == PM_WAIT_BACKUP) result = CAC_WAITBACKUP; /* allow superusers only */ else if (Shutdown > NoShutdown) return CAC_SHUTDOWN; /* shutdown is pending */ else if (!FatalError && (pmState == PM_STARTUP || pmState == PM_RECOVERY)) return CAC_STARTUP; /* normal startup */ else if (!FatalError && pmState == PM_HOT_STANDBY) result = CAC_OK; /* connection OK during hot standby */ else return CAC_RECOVERY; /* else must be crash recovery */ } /* * Don't start too many children. * * We allow more connections than we can have backends here because some * might still be authenticating; they might fail auth, or some existing * backend might exit before the auth cycle is completed. The exact * MaxBackends limit is enforced when a new backend tries to join the * shared-inval backend array. * * The limit here must match the sizes of the per-child-process arrays; * see comments for MaxLivePostmasterChildren(). */ if (CountChildren(BACKEND_TYPE_ALL) >= MaxLivePostmasterChildren()) result = CAC_TOOMANY; return result; }
static void checkDataDir | ( | void | ) | [static] |
Definition at line 1322 of file postmaster.c.
References AllocateFile(), Assert, DataDir, ereport, errcode(), errcode_for_file_access(), errdetail(), errhint(), errmsg(), ExitPostmaster(), FATAL, FreeFile(), NULL, PG_BINARY_R, progname, S_IRWXG, S_IRWXO, snprintf(), strerror(), ValidatePgVersion(), and write_stderr.
Referenced by PostmasterMain().
{ char path[MAXPGPATH]; FILE *fp; struct stat stat_buf; Assert(DataDir); if (stat(DataDir, &stat_buf) != 0) { if (errno == ENOENT) ereport(FATAL, (errcode_for_file_access(), errmsg("data directory \"%s\" does not exist", DataDir))); else ereport(FATAL, (errcode_for_file_access(), errmsg("could not read permissions of directory \"%s\": %m", DataDir))); } /* eventual chdir would fail anyway, but let's test ... */ if (!S_ISDIR(stat_buf.st_mode)) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("specified data directory \"%s\" is not a directory", DataDir))); /* * Check that the directory belongs to my userid; if not, reject. * * This check is an essential part of the interlock that prevents two * postmasters from starting in the same directory (see CreateLockFile()). * Do not remove or weaken it. * * XXX can we safely enable this check on Windows? */ #if !defined(WIN32) && !defined(__CYGWIN__) if (stat_buf.st_uid != geteuid()) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("data directory \"%s\" has wrong ownership", DataDir), errhint("The server must be started by the user that owns the data directory."))); #endif /* * Check if the directory has group or world access. If so, reject. * * It would be possible to allow weaker constraints (for example, allow * group access) but we cannot make a general assumption that that is * okay; for example there are platforms where nearly all users * customarily belong to the same group. Perhaps this test should be * configurable. * * XXX temporarily suppress check when on Windows, because there may not * be proper support for Unix-y file permissions. Need to think of a * reasonable check to apply on Windows. */ #if !defined(WIN32) && !defined(__CYGWIN__) if (stat_buf.st_mode & (S_IRWXG | S_IRWXO)) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("data directory \"%s\" has group or world access", DataDir), errdetail("Permissions should be u=rwx (0700)."))); #endif /* Look for PG_VERSION before looking for pg_control */ ValidatePgVersion(DataDir); snprintf(path, sizeof(path), "%s/global/pg_control", DataDir); fp = AllocateFile(path, PG_BINARY_R); if (fp == NULL) { write_stderr("%s: could not find the database system\n" "Expected to find it in the directory \"%s\",\n" "but could not open file \"%s\": %s\n", progname, DataDir, path, strerror(errno)); ExitPostmaster(2); } FreeFile(fp); }
static void CleanupBackend | ( | int | pid, | |
int | exitstatus | |||
) | [static] |
Definition at line 2877 of file postmaster.c.
References _, bkend::child_slot, dlist_mutable_iter::cur, bkend::dead_end, DEBUG2, dlist_container, dlist_delete(), dlist_foreach_modify, EXIT_STATUS_0, EXIT_STATUS_1, free, HandleChildCrash(), LOG, LogChildExit(), bkend::pid, and ReleasePostmasterChildSlot().
Referenced by reaper().
{ dlist_mutable_iter iter; LogChildExit(DEBUG2, _("server process"), pid, exitstatus); /* * If a backend dies in an ugly way then we must signal all other backends * to quickdie. If exit status is zero (normal) or one (FATAL exit), we * assume everything is all right and proceed to remove the backend from * the active backend list. */ #ifdef WIN32 /* * On win32, also treat ERROR_WAIT_NO_CHILDREN (128) as nonfatal case, * since that sometimes happens under load when the process fails to start * properly (long before it starts using shared memory). Microsoft reports * it is related to mutex failure: * http://archives.postgresql.org/pgsql-hackers/2010-09/msg00790.php */ if (exitstatus == ERROR_WAIT_NO_CHILDREN) { LogChildExit(LOG, _("server process"), pid, exitstatus); exitstatus = 0; } #endif if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_1(exitstatus)) { HandleChildCrash(pid, exitstatus, _("server process")); return; } dlist_foreach_modify(iter, &BackendList) { Backend *bp = dlist_container(Backend, elem, iter.cur); if (bp->pid == pid) { if (!bp->dead_end) { if (!ReleasePostmasterChildSlot(bp->child_slot)) { /* * Uh-oh, the child failed to clean itself up. Treat as a * crash after all. */ HandleChildCrash(pid, exitstatus, _("server process")); return; } #ifdef EXEC_BACKEND ShmemBackendArrayRemove(bp); #endif } dlist_delete(iter.cur); free(bp); break; } } }
static bool CleanupBackgroundWorker | ( | int | pid, | |
int | exitstatus | |||
) | [static] |
Definition at line 2791 of file postmaster.c.
References _, Assert, BackgroundWorker::bgw_flags, BackgroundWorker::bgw_name, BGWORKER_BACKEND_DATABASE_CONNECTION, BGWORKER_SHMEM_ACCESS, slist_iter::cur, dlist_delete(), bkend::elem, EXIT_STATUS_0, EXIT_STATUS_1, free, GetCurrentTimestamp(), HandleChildCrash(), LOG, LogChildExit(), MAXPGPATH, ReleasePostmasterChildSlot(), RegisteredBgWorker::rw_backend, RegisteredBgWorker::rw_child_slot, RegisteredBgWorker::rw_crashed_at, RegisteredBgWorker::rw_pid, RegisteredBgWorker::rw_worker, slist_container, slist_foreach, and snprintf().
Referenced by reaper().
{ char namebuf[MAXPGPATH]; slist_iter iter; slist_foreach(iter, &BackgroundWorkerList) { RegisteredBgWorker *rw; rw = slist_container(RegisteredBgWorker, rw_lnode, iter.cur); if (rw->rw_pid != pid) continue; #ifdef WIN32 /* see CleanupBackend */ if (exitstatus == ERROR_WAIT_NO_CHILDREN) exitstatus = 0; #endif snprintf(namebuf, MAXPGPATH, "%s: %s", _("worker process"), rw->rw_worker.bgw_name); /* Delay restarting any bgworker that exits with a nonzero status. */ if (!EXIT_STATUS_0(exitstatus)) rw->rw_crashed_at = GetCurrentTimestamp(); else rw->rw_crashed_at = 0; /* * Additionally, for shared-memory-connected workers, just like a * backend, any exit status other than 0 or 1 is considered a crash * and causes a system-wide restart. */ if (rw->rw_worker.bgw_flags & BGWORKER_SHMEM_ACCESS) { if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_1(exitstatus)) { rw->rw_crashed_at = GetCurrentTimestamp(); HandleChildCrash(pid, exitstatus, namebuf); return true; } } if (!ReleasePostmasterChildSlot(rw->rw_child_slot)) { /* * Uh-oh, the child failed to clean itself up. Treat as a crash * after all. */ rw->rw_crashed_at = GetCurrentTimestamp(); HandleChildCrash(pid, exitstatus, namebuf); return true; } /* Get it out of the BackendList and clear out remaining data */ if (rw->rw_backend) { Assert(rw->rw_worker.bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION); dlist_delete(&rw->rw_backend->elem); #ifdef EXEC_BACKEND ShmemBackendArrayRemove(rw->rw_backend); #endif free(rw->rw_backend); rw->rw_backend = NULL; } rw->rw_pid = 0; rw->rw_child_slot = 0; LogChildExit(LOG, namebuf, pid, exitstatus); return true; } return false; }
void ClosePostmasterPorts | ( | bool | am_syslogger | ) |
Definition at line 2199 of file postmaster.c.
References close, ereport, errcode_for_file_access(), errmsg_internal(), FATAL, ListenSocket, PGINVALID_SOCKET, POSTMASTER_FD_OWN, StreamClose(), and syslogPipe.
Referenced by BackendStartup(), pgarch_start(), pgstat_start(), start_bgworker(), StartAutoVacLauncher(), StartAutoVacWorker(), StartChildProcess(), and SysLogger_Start().
{ int i; #ifndef WIN32 /* * Close the write end of postmaster death watch pipe. It's important to * do this as early as possible, so that if postmaster dies, others won't * think that it's still running because we're holding the pipe open. */ if (close(postmaster_alive_fds[POSTMASTER_FD_OWN])) ereport(FATAL, (errcode_for_file_access(), errmsg_internal("could not close postmaster death monitoring pipe in child process: %m"))); postmaster_alive_fds[POSTMASTER_FD_OWN] = -1; #endif /* Close the listen sockets */ for (i = 0; i < MAXLISTEN; i++) { if (ListenSocket[i] != PGINVALID_SOCKET) { StreamClose(ListenSocket[i]); ListenSocket[i] = PGINVALID_SOCKET; } } /* If using syslogger, close the read side of the pipe */ if (!am_syslogger) { #ifndef WIN32 if (syslogPipe[0] >= 0) close(syslogPipe[0]); syslogPipe[0] = -1; #else if (syslogPipe[0]) CloseHandle(syslogPipe[0]); syslogPipe[0] = 0; #endif } #ifdef USE_BONJOUR /* If using Bonjour, close the connection to the mDNS daemon */ if (bonjour_sdref) close(DNSServiceRefSockFD(bonjour_sdref)); #endif }
static Port * ConnCreate | ( | int | serverFd | ) | [static] |
Definition at line 2124 of file postmaster.c.
References calloc, ConnFree(), ereport, errcode(), errmsg(), ExitPostmaster(), Port::gss, LOG, Port::md5Salt, RandomSalt(), Port::sock, STATUS_OK, StreamClose(), and StreamConnection().
Referenced by ServerLoop().
{ Port *port; if (!(port = (Port *) calloc(1, sizeof(Port)))) { ereport(LOG, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); ExitPostmaster(1); } if (StreamConnection(serverFd, port) != STATUS_OK) { if (port->sock >= 0) StreamClose(port->sock); ConnFree(port); return NULL; } /* * Precompute password salt values to use for this connection. It's * slightly annoying to do this long in advance of knowing whether we'll * need 'em or not, but we must do the random() calls before we fork, not * after. Else the postmaster's random sequence won't get advanced, and * all backends would end up using the same salt... */ RandomSalt(port->md5Salt); /* * Allocate GSSAPI specific state struct */ #ifndef EXEC_BACKEND #if defined(ENABLE_GSS) || defined(ENABLE_SSPI) port->gss = (pg_gssinfo *) calloc(1, sizeof(pg_gssinfo)); if (!port->gss) { ereport(LOG, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); ExitPostmaster(1); } #endif #endif return port; }
static void ConnFree | ( | Port * | port | ) | [static] |
Definition at line 2177 of file postmaster.c.
References free, Port::gss, and secure_close().
Referenced by ConnCreate(), and ServerLoop().
static int CountChildren | ( | int | target | ) | [static] |
Definition at line 4863 of file postmaster.c.
References BACKEND_TYPE_ALL, BACKEND_TYPE_NORMAL, bkend::bkend_type, bkend::child_slot, dlist_iter::cur, bkend::dead_end, dlist_container, dlist_foreach, and IsPostmasterChildWalSender().
Referenced by canAcceptConnections(), and PostmasterStateMachine().
{ dlist_iter iter; int cnt = 0; dlist_foreach(iter, &BackendList) { Backend *bp = dlist_container(Backend, elem, iter.cur); if (bp->dead_end) continue; /* * Since target == BACKEND_TYPE_ALL is the most common case, we test * it first and avoid touching shared memory for every child. */ if (target != BACKEND_TYPE_ALL) { /* * Assign bkend_type for any recently announced WAL Sender * processes. */ if (bp->bkend_type == BACKEND_TYPE_NORMAL && IsPostmasterChildWalSender(bp->child_slot)) bp->bkend_type = BACKEND_TYPE_WALSND; if (!(target & bp->bkend_type)) continue; } cnt++; } return cnt; }
static int CountUnconnectedWorkers | ( | void | ) | [static] |
Definition at line 4836 of file postmaster.c.
References slist_iter::cur, NULL, RegisteredBgWorker::rw_backend, RegisteredBgWorker::rw_pid, slist_container, and slist_foreach.
Referenced by PostmasterStateMachine().
{ slist_iter iter; int cnt = 0; slist_foreach(iter, &BackgroundWorkerList) { RegisteredBgWorker *rw; rw = slist_container(RegisteredBgWorker, rw_lnode, iter.cur); if (rw->rw_pid == 0) continue; /* ignore connected workers */ if (rw->rw_backend != NULL) continue; cnt++; } return cnt; }
static bool CreateOptsFile | ( | int | argc, | |
char * | argv[], | |||
char * | fullprogname | |||
) | [static] |
Definition at line 5090 of file postmaster.c.
References elog, LOG, NULL, and OPTS_FILE.
Referenced by PostmasterMain().
{ FILE *fp; int i; #define OPTS_FILE "postmaster.opts" if ((fp = fopen(OPTS_FILE, "w")) == NULL) { elog(LOG, "could not create file \"%s\": %m", OPTS_FILE); return false; } fprintf(fp, "%s", fullprogname); for (i = 1; i < argc; i++) fprintf(fp, " \"%s\"", argv[i]); fputs("\n", fp); if (fclose(fp)) { elog(LOG, "could not write file \"%s\": %m", OPTS_FILE); return false; } return true; }
static void DetermineSleepTime | ( | struct timeval * | timeout | ) | [static] |
Definition at line 1417 of file postmaster.c.
References BGW_NEVER_RESTART, BackgroundWorker::bgw_restart_time, slist_iter::cur, GetCurrentTimestamp(), HaveCrashedWorker, NoShutdown, RegisteredBgWorker::rw_crashed_at, RegisteredBgWorker::rw_worker, Shutdown, slist_container, slist_foreach, StartWorkerNeeded, TimestampDifference(), and TimestampTzPlusMilliseconds.
Referenced by ServerLoop().
{ TimestampTz next_wakeup = 0; /* * Normal case: either there are no background workers at all, or we're in * a shutdown sequence (during which we ignore bgworkers altogether). */ if (Shutdown > NoShutdown || (!StartWorkerNeeded && !HaveCrashedWorker)) { timeout->tv_sec = 60; timeout->tv_usec = 0; return; } if (StartWorkerNeeded) { timeout->tv_sec = 0; timeout->tv_usec = 0; return; } if (HaveCrashedWorker) { slist_iter siter; /* * When there are crashed bgworkers, we sleep just long enough that * they are restarted when they request to be. Scan the list to * determine the minimum of all wakeup times according to most recent * crash time and requested restart interval. */ slist_foreach(siter, &BackgroundWorkerList) { RegisteredBgWorker *rw; TimestampTz this_wakeup; rw = slist_container(RegisteredBgWorker, rw_lnode, siter.cur); if (rw->rw_crashed_at == 0) continue; if (rw->rw_worker.bgw_restart_time == BGW_NEVER_RESTART) continue; this_wakeup = TimestampTzPlusMilliseconds(rw->rw_crashed_at, 1000L * rw->rw_worker.bgw_restart_time); if (next_wakeup == 0 || this_wakeup < next_wakeup) next_wakeup = this_wakeup; } } if (next_wakeup != 0) { int microsecs; TimestampDifference(GetCurrentTimestamp(), next_wakeup, &timeout->tv_sec, µsecs); timeout->tv_usec = microsecs; /* Ensure we don't exceed one minute */ if (timeout->tv_sec > 60) { timeout->tv_sec = 60; timeout->tv_usec = 0; } } else { timeout->tv_sec = 60; timeout->tv_usec = 0; } }
static void do_start_bgworker | ( | void | ) | [static] |
Definition at line 5374 of file postmaster.c.
References BaseInit(), BackgroundWorker::bgw_flags, BackgroundWorker::bgw_main, BackgroundWorker::bgw_main_arg, BackgroundWorker::bgw_name, BackgroundWorker::bgw_sighup, BackgroundWorker::bgw_sigterm, BGWORKER_BACKEND_DATABASE_CONNECTION, bgworker_die(), bgworker_quickdie(), BGWORKER_SHMEM_ACCESS, bgworker_sigusr1_handler(), buf, elog, EmitErrorReport(), error_context_stack, FATAL, FloatExceptionHandler(), HOLD_INTERRUPTS, init_ps_display(), InitializeTimeouts(), InitProcess(), InitProcessing, IsBackgroundWorker, IsUnderPostmaster, MAXPGPATH, MyProcPid, MyStartTime, NULL, PG_exception_stack, pg_usleep(), PostAuthDelay, pqsignal(), proc_exit(), procsignal_sigusr1_handler(), SetProcessingMode, SIG_DFL, SIG_IGN, SIGCHLD, SIGHUP, sigjmp_buf, SIGPIPE, SIGQUIT, sigsetjmp, SIGUSR1, SIGUSR2, snprintf(), and StatementCancelHandler().
Referenced by start_bgworker().
{ sigjmp_buf local_sigjmp_buf; char buf[MAXPGPATH]; BackgroundWorker *worker = MyBgworkerEntry; if (worker == NULL) elog(FATAL, "unable to find bgworker entry"); /* we are a postmaster subprocess now */ IsUnderPostmaster = true; IsBackgroundWorker = true; /* reset MyProcPid */ MyProcPid = getpid(); /* record Start Time for logging */ MyStartTime = time(NULL); /* Identify myself via ps */ snprintf(buf, MAXPGPATH, "bgworker: %s", worker->bgw_name); init_ps_display(buf, "", "", ""); SetProcessingMode(InitProcessing); /* Apply PostAuthDelay */ if (PostAuthDelay > 0) pg_usleep(PostAuthDelay * 1000000L); /* * If possible, make this process a group leader, so that the postmaster * can signal any child processes too. */ #ifdef HAVE_SETSID if (setsid() < 0) elog(FATAL, "setsid() failed: %m"); #endif /* * Set up signal handlers. */ if (worker->bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION) { /* * SIGINT is used to signal canceling the current action */ pqsignal(SIGINT, StatementCancelHandler); pqsignal(SIGUSR1, procsignal_sigusr1_handler); pqsignal(SIGFPE, FloatExceptionHandler); /* XXX Any other handlers needed here? */ } else { pqsignal(SIGINT, SIG_IGN); pqsignal(SIGUSR1, bgworker_sigusr1_handler); pqsignal(SIGFPE, SIG_IGN); } /* SIGTERM and SIGHUP are configurable */ if (worker->bgw_sigterm) pqsignal(SIGTERM, worker->bgw_sigterm); else pqsignal(SIGTERM, bgworker_die); if (worker->bgw_sighup) pqsignal(SIGHUP, worker->bgw_sighup); else pqsignal(SIGHUP, SIG_IGN); pqsignal(SIGQUIT, bgworker_quickdie); InitializeTimeouts(); /* establishes SIGALRM handler */ pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGUSR2, SIG_IGN); pqsignal(SIGCHLD, SIG_DFL); /* * If an exception is encountered, processing resumes here. * * See notes in postgres.c about the design of this coding. */ if (sigsetjmp(local_sigjmp_buf, 1) != 0) { /* Since not using PG_TRY, must reset error stack by hand */ error_context_stack = NULL; /* Prevent interrupts while cleaning up */ HOLD_INTERRUPTS(); /* Report the error to the server log */ EmitErrorReport(); /* * Do we need more cleanup here? For shmem-connected bgworkers, we * will call InitProcess below, which will install ProcKill as exit * callback. That will take care of releasing locks, etc. */ /* and go away */ proc_exit(1); } /* We can now handle ereport(ERROR) */ PG_exception_stack = &local_sigjmp_buf; /* Early initialization */ BaseInit(); /* * If necessary, create a per-backend PGPROC struct in shared memory, * except in the EXEC_BACKEND case where this was done in * SubPostmasterMain. We must do this before we can use LWLocks (and in * the EXEC_BACKEND case we already had to do some stuff with LWLocks). */ #ifndef EXEC_BACKEND if (worker->bgw_flags & BGWORKER_SHMEM_ACCESS) InitProcess(); #endif /* * Note that in normal processes, we would call InitPostgres here. For a * worker, however, we don't know what database to connect to, yet; so we * need to wait until the user code does it via * BackgroundWorkerInitializeConnection(). */ /* * Now invoke the user-defined worker code */ worker->bgw_main(worker->bgw_main_arg); /* ... and if it returns, we're done */ proc_exit(0); }
static void dummy_handler | ( | SIGNAL_ARGS | ) | [static] |
static void ExitPostmaster | ( | int | status | ) | [static] |
Definition at line 4599 of file postmaster.c.
References proc_exit().
Referenced by checkDataDir(), ConnCreate(), pmdie(), PostmasterMain(), PostmasterStateMachine(), reaper(), and StartChildProcess().
static void getInstallationPaths | ( | const char * | argv0 | ) | [static] |
Definition at line 1271 of file postmaster.c.
References AllocateDir(), elog, ereport, errcode_for_file_access(), errhint(), errmsg(), ERROR, FATAL, find_my_exec(), find_other_exec(), FreeDir(), get_pkglib_path(), my_exec_path, NULL, PG_BACKEND_VERSIONSTR, and pkglib_path.
Referenced by PostmasterMain().
{ DIR *pdir; /* Locate the postgres executable itself */ if (find_my_exec(argv0, my_exec_path) < 0) elog(FATAL, "%s: could not locate my own executable path", argv0); #ifdef EXEC_BACKEND /* Locate executable backend before we change working directory */ if (find_other_exec(argv0, "postgres", PG_BACKEND_VERSIONSTR, postgres_exec_path) < 0) ereport(FATAL, (errmsg("%s: could not locate matching postgres executable", argv0))); #endif /* * Locate the pkglib directory --- this has to be set early in case we try * to load any modules from it in response to postgresql.conf entries. */ get_pkglib_path(my_exec_path, pkglib_path); /* * Verify that there's a readable directory there; otherwise the Postgres * installation is incomplete or corrupt. (A typical cause of this * failure is that the postgres executable has been moved or hardlinked to * some directory that's not a sibling of the installation lib/ * directory.) */ pdir = AllocateDir(pkglib_path); if (pdir == NULL) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open directory \"%s\": %m", pkglib_path), errhint("This may indicate an incomplete PostgreSQL installation, or that the file \"%s\" has been moved away from its proper location.", my_exec_path))); FreeDir(pdir); /* * XXX is it worth similarly checking the share/ directory? If the lib/ * directory is there, then share/ probably is too. */ }
static int GetNumRegisteredBackgroundWorkers | ( | int | flags | ) | [static] |
Definition at line 5515 of file postmaster.c.
References BackgroundWorker::bgw_flags, slist_iter::cur, RegisteredBgWorker::rw_worker, slist_container, and slist_foreach.
Referenced by GetNumShmemAttachedBgworkers(), and MaxLivePostmasterChildren().
{ slist_iter iter; int count = 0; slist_foreach(iter, &BackgroundWorkerList) { RegisteredBgWorker *rw; rw = slist_container(RegisteredBgWorker, rw_lnode, iter.cur); if (flags != 0 && !(rw->rw_worker.bgw_flags & flags)) continue; count++; } return count; }
int GetNumShmemAttachedBgworkers | ( | void | ) |
Definition at line 5540 of file postmaster.c.
References BGWORKER_SHMEM_ACCESS, and GetNumRegisteredBackgroundWorkers().
Referenced by check_autovacuum_max_workers(), check_maxconnections(), and InitializeMaxBackends().
{ return GetNumRegisteredBackgroundWorkers(BGWORKER_SHMEM_ACCESS); }
static void HandleChildCrash | ( | int | pid, | |
int | exitstatus, | |||
const char * | procname | |||
) | [static] |
Definition at line 2948 of file postmaster.c.
References allow_immediate_pgstat_restart(), AutoVacPID, BACKEND_TYPE_BGWORKER, BgWriterPID, bkend::bkend_type, CheckpointerPID, bkend::child_slot, dlist_mutable_iter::cur, slist_iter::cur, bkend::dead_end, DEBUG2, dlist_container, dlist_delete(), dlist_foreach_modify, bkend::elem, ereport, errmsg(), errmsg_internal(), FatalError, free, LOG, LogChildExit(), PgArchPID, PgStatPID, bkend::pid, PM_HOT_STANDBY, PM_RECOVERY, PM_RUN, PM_SHUTDOWN, PM_WAIT_BACKUP, PM_WAIT_READONLY, pmState, ReleasePostmasterChildSlot(), RegisteredBgWorker::rw_backend, RegisteredBgWorker::rw_child_slot, RegisteredBgWorker::rw_pid, SendStop, signal_child(), SIGQUIT, SIGSTOP, slist_container, slist_foreach, StartupPID, WalReceiverPID, and WalWriterPID.
Referenced by CleanupBackend(), CleanupBackgroundWorker(), and reaper().
{ dlist_mutable_iter iter; slist_iter siter; Backend *bp; /* * Make log entry unless there was a previous crash (if so, nonzero exit * status is to be expected in SIGQUIT response; don't clutter log) */ if (!FatalError) { LogChildExit(LOG, procname, pid, exitstatus); ereport(LOG, (errmsg("terminating any other active server processes"))); } /* Process background workers. */ slist_foreach(siter, &BackgroundWorkerList) { RegisteredBgWorker *rw; rw = slist_container(RegisteredBgWorker, rw_lnode, siter.cur); if (rw->rw_pid == 0) continue; /* not running */ if (rw->rw_pid == pid) { /* * Found entry for freshly-dead worker, so remove it. */ (void) ReleasePostmasterChildSlot(rw->rw_child_slot); if (rw->rw_backend) { dlist_delete(&rw->rw_backend->elem); #ifdef EXEC_BACKEND ShmemBackendArrayRemove(rw->rw_backend); #endif free(rw->rw_backend); rw->rw_backend = NULL; } rw->rw_pid = 0; rw->rw_child_slot = 0; /* don't reset crashed_at */ /* Keep looping so we can signal remaining workers */ } else { /* * This worker is still alive. Unless we did so already, tell it * to commit hara-kiri. * * SIGQUIT is the special signal that says exit without proc_exit * and let the user know what's going on. But if SendStop is set * (-s on command line), then we send SIGSTOP instead, so that we * can get core dumps from all backends by hand. */ if (!FatalError) { ereport(DEBUG2, (errmsg_internal("sending %s to process %d", (SendStop ? "SIGSTOP" : "SIGQUIT"), (int) rw->rw_pid))); signal_child(rw->rw_pid, (SendStop ? SIGSTOP : SIGQUIT)); } } } /* Process regular backends */ dlist_foreach_modify(iter, &BackendList) { bp = dlist_container(Backend, elem, iter.cur); if (bp->pid == pid) { /* * Found entry for freshly-dead backend, so remove it. */ if (!bp->dead_end) { (void) ReleasePostmasterChildSlot(bp->child_slot); #ifdef EXEC_BACKEND ShmemBackendArrayRemove(bp); #endif } dlist_delete(iter.cur); free(bp); /* Keep looping so we can signal remaining backends */ } else { /* * This backend is still alive. Unless we did so already, tell it * to commit hara-kiri. * * SIGQUIT is the special signal that says exit without proc_exit * and let the user know what's going on. But if SendStop is set * (-s on command line), then we send SIGSTOP instead, so that we * can get core dumps from all backends by hand. * * We could exclude dead_end children here, but at least in the * SIGSTOP case it seems better to include them. * * Background workers were already processed above; ignore them * here. */ if (bp->bkend_type == BACKEND_TYPE_BGWORKER) continue; if (!FatalError) { ereport(DEBUG2, (errmsg_internal("sending %s to process %d", (SendStop ? "SIGSTOP" : "SIGQUIT"), (int) bp->pid))); signal_child(bp->pid, (SendStop ? SIGSTOP : SIGQUIT)); } } } /* Take care of the startup process too */ if (pid == StartupPID) StartupPID = 0; else if (StartupPID != 0 && !FatalError) { ereport(DEBUG2, (errmsg_internal("sending %s to process %d", (SendStop ? "SIGSTOP" : "SIGQUIT"), (int) StartupPID))); signal_child(StartupPID, (SendStop ? SIGSTOP : SIGQUIT)); } /* Take care of the bgwriter too */ if (pid == BgWriterPID) BgWriterPID = 0; else if (BgWriterPID != 0 && !FatalError) { ereport(DEBUG2, (errmsg_internal("sending %s to process %d", (SendStop ? "SIGSTOP" : "SIGQUIT"), (int) BgWriterPID))); signal_child(BgWriterPID, (SendStop ? SIGSTOP : SIGQUIT)); } /* Take care of the checkpointer too */ if (pid == CheckpointerPID) CheckpointerPID = 0; else if (CheckpointerPID != 0 && !FatalError) { ereport(DEBUG2, (errmsg_internal("sending %s to process %d", (SendStop ? "SIGSTOP" : "SIGQUIT"), (int) CheckpointerPID))); signal_child(CheckpointerPID, (SendStop ? SIGSTOP : SIGQUIT)); } /* Take care of the walwriter too */ if (pid == WalWriterPID) WalWriterPID = 0; else if (WalWriterPID != 0 && !FatalError) { ereport(DEBUG2, (errmsg_internal("sending %s to process %d", (SendStop ? "SIGSTOP" : "SIGQUIT"), (int) WalWriterPID))); signal_child(WalWriterPID, (SendStop ? SIGSTOP : SIGQUIT)); } /* Take care of the walreceiver too */ if (pid == WalReceiverPID) WalReceiverPID = 0; else if (WalReceiverPID != 0 && !FatalError) { ereport(DEBUG2, (errmsg_internal("sending %s to process %d", (SendStop ? "SIGSTOP" : "SIGQUIT"), (int) WalReceiverPID))); signal_child(WalReceiverPID, (SendStop ? SIGSTOP : SIGQUIT)); } /* Take care of the autovacuum launcher too */ if (pid == AutoVacPID) AutoVacPID = 0; else if (AutoVacPID != 0 && !FatalError) { ereport(DEBUG2, (errmsg_internal("sending %s to process %d", (SendStop ? "SIGSTOP" : "SIGQUIT"), (int) AutoVacPID))); signal_child(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT)); } /* * Force a power-cycle of the pgarch process too. (This isn't absolutely * necessary, but it seems like a good idea for robustness, and it * simplifies the state-machine logic in the case where a shutdown request * arrives during crash processing.) */ if (PgArchPID != 0 && !FatalError) { ereport(DEBUG2, (errmsg_internal("sending %s to process %d", "SIGQUIT", (int) PgArchPID))); signal_child(PgArchPID, SIGQUIT); } /* * Force a power-cycle of the pgstat process too. (This isn't absolutely * necessary, but it seems like a good idea for robustness, and it * simplifies the state-machine logic in the case where a shutdown request * arrives during crash processing.) */ if (PgStatPID != 0 && !FatalError) { ereport(DEBUG2, (errmsg_internal("sending %s to process %d", "SIGQUIT", (int) PgStatPID))); signal_child(PgStatPID, SIGQUIT); allow_immediate_pgstat_restart(); } /* We do NOT restart the syslogger */ FatalError = true; /* We now transit into a state of waiting for children to die */ if (pmState == PM_RECOVERY || pmState == PM_HOT_STANDBY || pmState == PM_RUN || pmState == PM_WAIT_BACKUP || pmState == PM_WAIT_READONLY || pmState == PM_SHUTDOWN) pmState = PM_WAIT_BACKENDS; }
static int initMasks | ( | fd_set * | rmask | ) | [static] |
Definition at line 1669 of file postmaster.c.
References fd(), i, ListenSocket, and PGINVALID_SOCKET.
Referenced by ServerLoop().
{ int maxsock = -1; int i; FD_ZERO(rmask); for (i = 0; i < MAXLISTEN; i++) { int fd = ListenSocket[i]; if (fd == PGINVALID_SOCKET) break; FD_SET(fd, rmask); if (fd > maxsock) maxsock = fd; } return maxsock + 1; }
static void InitPostmasterDeathWatchHandle | ( | void | ) | [static] |
Definition at line 6238 of file postmaster.c.
References Assert, ereport, errcode_for_file_access(), errcode_for_socket_access(), errmsg_internal(), FATAL, MyProcPid, POSTMASTER_FD_WATCH, PostmasterPid, and TRUE.
Referenced by PostmasterMain().
{ #ifndef WIN32 /* * Create a pipe. Postmaster holds the write end of the pipe open * (POSTMASTER_FD_OWN), and children hold the read end. Children can pass * the read file descriptor to select() to wake up in case postmaster * dies, or check for postmaster death with a (read() == 0). Children must * close the write end as soon as possible after forking, because EOF * won't be signaled in the read end until all processes have closed the * write fd. That is taken care of in ClosePostmasterPorts(). */ Assert(MyProcPid == PostmasterPid); if (pipe(postmaster_alive_fds)) ereport(FATAL, (errcode_for_file_access(), errmsg_internal("could not create pipe to monitor postmaster death: %m"))); /* * Set O_NONBLOCK to allow testing for the fd's presence with a read() * call. */ if (fcntl(postmaster_alive_fds[POSTMASTER_FD_WATCH], F_SETFL, O_NONBLOCK)) ereport(FATAL, (errcode_for_socket_access(), errmsg_internal("could not set postmaster death monitoring pipe to nonblocking mode: %m"))); #else /* * On Windows, we use a process handle for the same purpose. */ if (DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &PostmasterHandle, 0, TRUE, DUPLICATE_SAME_ACCESS) == 0) ereport(FATAL, (errmsg_internal("could not duplicate postmaster handle: error code %lu", GetLastError()))); #endif /* WIN32 */ }
static void LogChildExit | ( | int | lev, | |
const char * | procname, | |||
int | pid, | |||
int | exitstatus | |||
) | [static] |
Definition at line 3187 of file postmaster.c.
References ereport, errdetail(), errhint(), errmsg(), EXIT_STATUS_0, pgstat_get_crashed_backend_activity(), WEXITSTATUS, WIFEXITED, WIFSIGNALED, and WTERMSIG.
Referenced by CleanupBackend(), CleanupBackgroundWorker(), HandleChildCrash(), and reaper().
{ /* * size of activity_buffer is arbitrary, but set equal to default * track_activity_query_size */ char activity_buffer[1024]; const char *activity = NULL; if (!EXIT_STATUS_0(exitstatus)) activity = pgstat_get_crashed_backend_activity(pid, activity_buffer, sizeof(activity_buffer)); if (WIFEXITED(exitstatus)) ereport(lev, /*------ translator: %s is a noun phrase describing a child process, such as "server process" */ (errmsg("%s (PID %d) exited with exit code %d", procname, pid, WEXITSTATUS(exitstatus)), activity ? errdetail("Failed process was running: %s", activity) : 0)); else if (WIFSIGNALED(exitstatus)) #if defined(WIN32) ereport(lev, /*------ translator: %s is a noun phrase describing a child process, such as "server process" */ (errmsg("%s (PID %d) was terminated by exception 0x%X", procname, pid, WTERMSIG(exitstatus)), errhint("See C include file \"ntstatus.h\" for a description of the hexadecimal value."), activity ? errdetail("Failed process was running: %s", activity) : 0)); #elif defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST ereport(lev, /*------ translator: %s is a noun phrase describing a child process, such as "server process" */ (errmsg("%s (PID %d) was terminated by signal %d: %s", procname, pid, WTERMSIG(exitstatus), WTERMSIG(exitstatus) < NSIG ? sys_siglist[WTERMSIG(exitstatus)] : "(unknown)"), activity ? errdetail("Failed process was running: %s", activity) : 0)); #else ereport(lev, /*------ translator: %s is a noun phrase describing a child process, such as "server process" */ (errmsg("%s (PID %d) was terminated by signal %d", procname, pid, WTERMSIG(exitstatus)), activity ? errdetail("Failed process was running: %s", activity) : 0)); #endif else ereport(lev, /*------ translator: %s is a noun phrase describing a child process, such as "server process" */ (errmsg("%s (PID %d) exited with unrecognized status %d", procname, pid, exitstatus), activity ? errdetail("Failed process was running: %s", activity) : 0)); }
int MaxLivePostmasterChildren | ( | void | ) |
Definition at line 5130 of file postmaster.c.
References autovacuum_max_workers, GetNumRegisteredBackgroundWorkers(), and MaxConnections.
Referenced by canAcceptConnections(), PMSignalShmemInit(), PMSignalShmemSize(), and processCancelRequest().
{ return 2 * (MaxConnections + autovacuum_max_workers + 1 + GetNumRegisteredBackgroundWorkers(0)); }
static void pmdie | ( | SIGNAL_ARGS | ) | [static] |
Definition at line 2328 of file postmaster.c.
References AutoVacPID, BACKEND_TYPE_AUTOVAC, BACKEND_TYPE_BGWORKER, BACKEND_TYPE_NORMAL, BgWriterPID, BlockSig, CheckpointerPID, DEBUG2, ereport, errmsg(), errmsg_internal(), ExitPostmaster(), FastShutdown, LOG, PG_SETMASK, PgArchPID, PgStatPID, PM_HOT_STANDBY, PM_RECOVERY, PM_RUN, PM_STARTUP, PM_WAIT_BACKENDS, PM_WAIT_BACKUP, PM_WAIT_READONLY, pmState, PostmasterStateMachine(), Shutdown, signal_child(), SignalChildren, SignalSomeChildren(), SignalUnconnectedWorkers(), SIGQUIT, SmartShutdown, StartupPID, UnBlockSig, WalReceiverPID, and WalWriterPID.
Referenced by PostmasterMain().
{ int save_errno = errno; PG_SETMASK(&BlockSig); ereport(DEBUG2, (errmsg_internal("postmaster received signal %d", postgres_signal_arg))); switch (postgres_signal_arg) { case SIGTERM: /* * Smart Shutdown: * * Wait for children to end their work, then shut down. */ if (Shutdown >= SmartShutdown) break; Shutdown = SmartShutdown; ereport(LOG, (errmsg("received smart shutdown request"))); if (pmState == PM_RUN || pmState == PM_RECOVERY || pmState == PM_HOT_STANDBY || pmState == PM_STARTUP) { /* autovac workers are told to shut down immediately */ /* and bgworkers too; does this need tweaking? */ SignalSomeChildren(SIGTERM, BACKEND_TYPE_AUTOVAC | BACKEND_TYPE_BGWORKER); SignalUnconnectedWorkers(SIGTERM); /* and the autovac launcher too */ if (AutoVacPID != 0) signal_child(AutoVacPID, SIGTERM); /* and the bgwriter too */ if (BgWriterPID != 0) signal_child(BgWriterPID, SIGTERM); /* and the walwriter too */ if (WalWriterPID != 0) signal_child(WalWriterPID, SIGTERM); /* * If we're in recovery, we can't kill the startup process * right away, because at present doing so does not release * its locks. We might want to change this in a future * release. For the time being, the PM_WAIT_READONLY state * indicates that we're waiting for the regular (read only) * backends to die off; once they do, we'll kill the startup * and walreceiver processes. */ pmState = (pmState == PM_RUN) ? PM_WAIT_BACKUP : PM_WAIT_READONLY; } /* * Now wait for online backup mode to end and backends to exit. If * that is already the case, PostmasterStateMachine will take the * next step. */ PostmasterStateMachine(); break; case SIGINT: /* * Fast Shutdown: * * Abort all children with SIGTERM (rollback active transactions * and exit) and shut down when they are gone. */ if (Shutdown >= FastShutdown) break; Shutdown = FastShutdown; ereport(LOG, (errmsg("received fast shutdown request"))); if (StartupPID != 0) signal_child(StartupPID, SIGTERM); if (BgWriterPID != 0) signal_child(BgWriterPID, SIGTERM); if (WalReceiverPID != 0) signal_child(WalReceiverPID, SIGTERM); SignalUnconnectedWorkers(SIGTERM); if (pmState == PM_RECOVERY) { /* * Only startup, bgwriter, walreceiver, unconnected bgworkers, * and/or checkpointer should be active in this state; we just * signaled the first four, and we don't want to kill * checkpointer yet. */ pmState = PM_WAIT_BACKENDS; } else if (pmState == PM_RUN || pmState == PM_WAIT_BACKUP || pmState == PM_WAIT_READONLY || pmState == PM_WAIT_BACKENDS || pmState == PM_HOT_STANDBY) { ereport(LOG, (errmsg("aborting any active transactions"))); /* shut down all backends and workers */ SignalSomeChildren(SIGTERM, BACKEND_TYPE_NORMAL | BACKEND_TYPE_AUTOVAC | BACKEND_TYPE_BGWORKER); /* and the autovac launcher too */ if (AutoVacPID != 0) signal_child(AutoVacPID, SIGTERM); /* and the walwriter too */ if (WalWriterPID != 0) signal_child(WalWriterPID, SIGTERM); pmState = PM_WAIT_BACKENDS; } /* * Now wait for backends to exit. If there are none, * PostmasterStateMachine will take the next step. */ PostmasterStateMachine(); break; case SIGQUIT: /* * Immediate Shutdown: * * abort all children with SIGQUIT and exit without attempt to * properly shut down data base system. */ ereport(LOG, (errmsg("received immediate shutdown request"))); SignalChildren(SIGQUIT); if (StartupPID != 0) signal_child(StartupPID, SIGQUIT); if (BgWriterPID != 0) signal_child(BgWriterPID, SIGQUIT); if (CheckpointerPID != 0) signal_child(CheckpointerPID, SIGQUIT); if (WalWriterPID != 0) signal_child(WalWriterPID, SIGQUIT); if (WalReceiverPID != 0) signal_child(WalReceiverPID, SIGQUIT); if (AutoVacPID != 0) signal_child(AutoVacPID, SIGQUIT); if (PgArchPID != 0) signal_child(PgArchPID, SIGQUIT); if (PgStatPID != 0) signal_child(PgStatPID, SIGQUIT); SignalUnconnectedWorkers(SIGQUIT); ExitPostmaster(0); break; } PG_SETMASK(&UnBlockSig); errno = save_errno; }
void PostmasterMain | ( | int | argc, | |
char * | argv[] | |||
) |
Definition at line 557 of file postmaster.c.
References AddToDataDirLockFile(), ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), Assert, autovac_init(), BlockSig, bonjour_name, ChangeToDataDir(), checkDataDir(), CheckDateTokenTables(), CreateDataDirLockFile(), CreateOptsFile(), DEBUG3, dummy_handler(), elog, enable_bonjour, EnableSSL, environ, ereport, errcode(), errmsg(), errmsg_internal(), ERROR, ExitPostmaster(), external_pid_file, ExtraOptions, FATAL, free, get_stats_option_name(), GetConfigOption(), GetCurrentTimestamp(), getInstallationPaths(), getopt(), gettimeofday(), i, InitializeGUCOptions(), InitializeMaxBackends(), InitPostmasterDeathWatchHandle(), IsBinaryUpgrade, IsPostmasterEnvironment, lfirst, list_free(), list_free_deep(), ListenAddresses, ListenSocket, load_hba(), load_ident(), LOCK_FILE_LINE_LISTEN_ADDR, LOCK_FILE_LINE_SOCKET_DIR, LOG, max_wal_senders, MaxConnections, MemoryContextInit(), MemoryContextSwitchTo(), my_exec_path, MyProcPid, MyStartTime, name, NIL, NULL, on_proc_exit(), optarg, opterr, optind, output_config_variable, ParseLongOption(), pfree(), PG_SETMASK, PGC_POSTMASTER, PGC_S_ARGV, PGINVALID_SOCKET, PgStartTime, pgstat_init(), pmdie(), pmState, PostmasterContext, PostmasterPid, PostPortNumber, pqinitmask(), pqsignal(), process_shared_preload_libraries(), progname, pstrdup(), random_start_time, reaper(), Reinit, RemovePgTempFiles(), ReservedBackends, reset_shared(), S_IRGRP, S_IROTH, S_IRWXG, S_IRWXO, secure_initialize(), SelectConfigFiles(), SendStop, ServerLoop(), set_debug_options(), set_max_safe_fds(), set_plan_disabling_options(), set_stack_base(), SetConfigOption(), SIG_IGN, SIGALRM, SIGCHLD, SIGHUP, SIGHUP_handler(), SIGPIPE, SIGQUIT, SIGTTIN, SIGTTOU, SIGUSR1, sigusr1_handler(), SIGUSR2, snprintf(), SplitDirectoriesString(), SplitIdentifierString(), StartOneBackgroundWorker(), StartupDataBase, StartupPID, STATUS_OK, StreamServerPort(), strerror(), SysLogger_Start(), SysLoggerPID, TopMemoryContext, Unix_socket_directories, unlink_external_pid_file(), userDoption, value, wal_level, WAL_LEVEL_MINIMAL, WARNING, whereToSendOutput, write_stderr, and XLogArchiveMode.
Referenced by main().
{ int opt; int status; char *userDoption = NULL; bool listen_addr_saved = false; int i; MyProcPid = PostmasterPid = getpid(); MyStartTime = time(NULL); IsPostmasterEnvironment = true; /* * for security, no dir or file created can be group or other accessible */ umask(S_IRWXG | S_IRWXO); /* * Fire up essential subsystems: memory management */ MemoryContextInit(); /* * By default, palloc() requests in the postmaster will be allocated in * the PostmasterContext, which is space that can be recycled by backends. * Allocated data that needs to be available to backends should be * allocated in TopMemoryContext. */ PostmasterContext = AllocSetContextCreate(TopMemoryContext, "Postmaster", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); MemoryContextSwitchTo(PostmasterContext); /* Initialize paths to installation files */ getInstallationPaths(argv[0]); /* * Options setup */ InitializeGUCOptions(); opterr = 1; /* * Parse command-line options. CAUTION: keep this in sync with * tcop/postgres.c (the option sets should not conflict) and with the * common help() function in main/main.c. */ while ((opt = getopt(argc, argv, "A:B:bc:C:D:d:EeFf:h:ijk:lN:nOo:Pp:r:S:sTt:W:-:")) != -1) { switch (opt) { case 'A': SetConfigOption("debug_assertions", optarg, PGC_POSTMASTER, PGC_S_ARGV); break; case 'B': SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV); break; case 'b': /* Undocumented flag used for binary upgrades */ IsBinaryUpgrade = true; break; case 'C': output_config_variable = strdup(optarg); break; case 'D': userDoption = strdup(optarg); break; case 'd': set_debug_options(atoi(optarg), PGC_POSTMASTER, PGC_S_ARGV); break; case 'E': SetConfigOption("log_statement", "all", PGC_POSTMASTER, PGC_S_ARGV); break; case 'e': SetConfigOption("datestyle", "euro", PGC_POSTMASTER, PGC_S_ARGV); break; case 'F': SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV); break; case 'f': if (!set_plan_disabling_options(optarg, PGC_POSTMASTER, PGC_S_ARGV)) { write_stderr("%s: invalid argument for option -f: \"%s\"\n", progname, optarg); ExitPostmaster(1); } break; case 'h': SetConfigOption("listen_addresses", optarg, PGC_POSTMASTER, PGC_S_ARGV); break; case 'i': SetConfigOption("listen_addresses", "*", PGC_POSTMASTER, PGC_S_ARGV); break; case 'j': /* only used by interactive backend */ break; case 'k': SetConfigOption("unix_socket_directories", optarg, PGC_POSTMASTER, PGC_S_ARGV); break; case 'l': SetConfigOption("ssl", "true", PGC_POSTMASTER, PGC_S_ARGV); break; case 'N': SetConfigOption("max_connections", optarg, PGC_POSTMASTER, PGC_S_ARGV); break; case 'n': /* Don't reinit shared mem after abnormal exit */ Reinit = false; break; case 'O': SetConfigOption("allow_system_table_mods", "true", PGC_POSTMASTER, PGC_S_ARGV); break; case 'o': /* Other options to pass to the backend on the command line */ snprintf(ExtraOptions + strlen(ExtraOptions), sizeof(ExtraOptions) - strlen(ExtraOptions), " %s", optarg); break; case 'P': SetConfigOption("ignore_system_indexes", "true", PGC_POSTMASTER, PGC_S_ARGV); break; case 'p': SetConfigOption("port", optarg, PGC_POSTMASTER, PGC_S_ARGV); break; case 'r': /* only used by single-user backend */ break; case 'S': SetConfigOption("work_mem", optarg, PGC_POSTMASTER, PGC_S_ARGV); break; case 's': SetConfigOption("log_statement_stats", "true", PGC_POSTMASTER, PGC_S_ARGV); break; case 'T': /* * In the event that some backend dumps core, send SIGSTOP, * rather than SIGQUIT, to all its peers. This lets the wily * post_hacker collect core dumps from everyone. */ SendStop = true; break; case 't': { const char *tmp = get_stats_option_name(optarg); if (tmp) { SetConfigOption(tmp, "true", PGC_POSTMASTER, PGC_S_ARGV); } else { write_stderr("%s: invalid argument for option -t: \"%s\"\n", progname, optarg); ExitPostmaster(1); } break; } case 'W': SetConfigOption("post_auth_delay", optarg, PGC_POSTMASTER, PGC_S_ARGV); break; case 'c': case '-': { char *name, *value; ParseLongOption(optarg, &name, &value); if (!value) { if (opt == '-') ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("--%s requires a value", optarg))); else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("-c %s requires a value", optarg))); } SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV); free(name); if (value) free(value); break; } default: write_stderr("Try \"%s --help\" for more information.\n", progname); ExitPostmaster(1); } } /* * Postmaster accepts no non-option switch arguments. */ if (optind < argc) { write_stderr("%s: invalid argument: \"%s\"\n", progname, argv[optind]); write_stderr("Try \"%s --help\" for more information.\n", progname); ExitPostmaster(1); } /* * Locate the proper configuration files and data directory, and read * postgresql.conf for the first time. */ if (!SelectConfigFiles(userDoption, progname)) ExitPostmaster(2); if (output_config_variable != NULL) { /* * permission is handled because the user is reading inside the data * dir */ puts(GetConfigOption(output_config_variable, false, false)); ExitPostmaster(0); } /* Verify that DataDir looks reasonable */ checkDataDir(); /* And switch working directory into it */ ChangeToDataDir(); /* * Check for invalid combinations of GUC settings. */ if (ReservedBackends >= MaxConnections) { write_stderr("%s: superuser_reserved_connections must be less than max_connections\n", progname); ExitPostmaster(1); } if (max_wal_senders >= MaxConnections) { write_stderr("%s: max_wal_senders must be less than max_connections\n", progname); ExitPostmaster(1); } if (XLogArchiveMode && wal_level == WAL_LEVEL_MINIMAL) ereport(ERROR, (errmsg("WAL archival (archive_mode=on) requires wal_level \"archive\" or \"hot_standby\""))); if (max_wal_senders > 0 && wal_level == WAL_LEVEL_MINIMAL) ereport(ERROR, (errmsg("WAL streaming (max_wal_senders > 0) requires wal_level \"archive\" or \"hot_standby\""))); /* * Other one-time internal sanity checks can go here, if they are fast. * (Put any slow processing further down, after postmaster.pid creation.) */ if (!CheckDateTokenTables()) { write_stderr("%s: invalid datetoken tables, please fix\n", progname); ExitPostmaster(1); } /* * Now that we are done processing the postmaster arguments, reset * getopt(3) library so that it will work correctly in subprocesses. */ optind = 1; #ifdef HAVE_INT_OPTRESET optreset = 1; /* some systems need this too */ #endif /* For debugging: display postmaster environment */ { extern char **environ; char **p; ereport(DEBUG3, (errmsg_internal("%s: PostmasterMain: initial environment dump:", progname))); ereport(DEBUG3, (errmsg_internal("-----------------------------------------"))); for (p = environ; *p; ++p) ereport(DEBUG3, (errmsg_internal("\t%s", *p))); ereport(DEBUG3, (errmsg_internal("-----------------------------------------"))); } /* * Create lockfile for data directory. * * We want to do this before we try to grab the input sockets, because the * data directory interlock is more reliable than the socket-file * interlock (thanks to whoever decided to put socket files in /tmp :-(). * For the same reason, it's best to grab the TCP socket(s) before the * Unix socket(s). */ CreateDataDirLockFile(true); /* * Initialize SSL library, if specified. */ #ifdef USE_SSL if (EnableSSL) secure_initialize(); #endif /* * process any libraries that should be preloaded at postmaster start */ process_shared_preload_libraries(); /* * Now that loadable modules have had their chance to register background * workers, calculate MaxBackends. */ InitializeMaxBackends(); /* * Establish input sockets. */ for (i = 0; i < MAXLISTEN; i++) ListenSocket[i] = PGINVALID_SOCKET; if (ListenAddresses) { char *rawstring; List *elemlist; ListCell *l; int success = 0; /* Need a modifiable copy of ListenAddresses */ rawstring = pstrdup(ListenAddresses); /* Parse string into list of hostnames */ if (!SplitIdentifierString(rawstring, ',', &elemlist)) { /* syntax error in list */ ereport(FATAL, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid list syntax for \"listen_addresses\""))); } foreach(l, elemlist) { char *curhost = (char *) lfirst(l); if (strcmp(curhost, "*") == 0) status = StreamServerPort(AF_UNSPEC, NULL, (unsigned short) PostPortNumber, NULL, ListenSocket, MAXLISTEN); else status = StreamServerPort(AF_UNSPEC, curhost, (unsigned short) PostPortNumber, NULL, ListenSocket, MAXLISTEN); if (status == STATUS_OK) { success++; /* record the first successful host addr in lockfile */ if (!listen_addr_saved) { AddToDataDirLockFile(LOCK_FILE_LINE_LISTEN_ADDR, curhost); listen_addr_saved = true; } } else ereport(WARNING, (errmsg("could not create listen socket for \"%s\"", curhost))); } if (!success && elemlist != NIL) ereport(FATAL, (errmsg("could not create any TCP/IP sockets"))); list_free(elemlist); pfree(rawstring); } #ifdef USE_BONJOUR /* Register for Bonjour only if we opened TCP socket(s) */ if (enable_bonjour && ListenSocket[0] != PGINVALID_SOCKET) { DNSServiceErrorType err; /* * We pass 0 for interface_index, which will result in registering on * all "applicable" interfaces. It's not entirely clear from the * DNS-SD docs whether this would be appropriate if we have bound to * just a subset of the available network interfaces. */ err = DNSServiceRegister(&bonjour_sdref, 0, 0, bonjour_name, "_postgresql._tcp.", NULL, NULL, htons(PostPortNumber), 0, NULL, NULL, NULL); if (err != kDNSServiceErr_NoError) elog(LOG, "DNSServiceRegister() failed: error code %ld", (long) err); /* * We don't bother to read the mDNS daemon's reply, and we expect that * it will automatically terminate our registration when the socket is * closed at postmaster termination. So there's nothing more to be * done here. However, the bonjour_sdref is kept around so that * forked children can close their copies of the socket. */ } #endif #ifdef HAVE_UNIX_SOCKETS if (Unix_socket_directories) { char *rawstring; List *elemlist; ListCell *l; int success = 0; /* Need a modifiable copy of Unix_socket_directories */ rawstring = pstrdup(Unix_socket_directories); /* Parse string into list of directories */ if (!SplitDirectoriesString(rawstring, ',', &elemlist)) { /* syntax error in list */ ereport(FATAL, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid list syntax for \"unix_socket_directories\""))); } foreach(l, elemlist) { char *socketdir = (char *) lfirst(l); status = StreamServerPort(AF_UNIX, NULL, (unsigned short) PostPortNumber, socketdir, ListenSocket, MAXLISTEN); if (status == STATUS_OK) { success++; /* record the first successful Unix socket in lockfile */ if (success == 1) AddToDataDirLockFile(LOCK_FILE_LINE_SOCKET_DIR, socketdir); } else ereport(WARNING, (errmsg("could not create Unix-domain socket in directory \"%s\"", socketdir))); } if (!success && elemlist != NIL) ereport(FATAL, (errmsg("could not create any Unix-domain sockets"))); list_free_deep(elemlist); pfree(rawstring); } #endif /* * check that we have some socket to listen on */ if (ListenSocket[0] == PGINVALID_SOCKET) ereport(FATAL, (errmsg("no socket created for listening"))); /* * If no valid TCP ports, write an empty line for listen address, * indicating the Unix socket must be used. Note that this line is not * added to the lock file until there is a socket backing it. */ if (!listen_addr_saved) AddToDataDirLockFile(LOCK_FILE_LINE_LISTEN_ADDR, ""); /* * Set up shared memory and semaphores. */ reset_shared(PostPortNumber); /* * Estimate number of openable files. This must happen after setting up * semaphores, because on some platforms semaphores count as open files. */ set_max_safe_fds(); /* * Set reference point for stack-depth checking. */ set_stack_base(); /* * Initialize pipe (or process handle on Windows) that allows children to * wake up from sleep on postmaster death. */ InitPostmasterDeathWatchHandle(); #ifdef WIN32 /* * Initialize I/O completion port used to deliver list of dead children. */ win32ChildQueue = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); if (win32ChildQueue == NULL) ereport(FATAL, (errmsg("could not create I/O completion port for child queue"))); #endif /* * Record postmaster options. We delay this till now to avoid recording * bogus options (eg, NBuffers too high for available memory). */ if (!CreateOptsFile(argc, argv, my_exec_path)) ExitPostmaster(1); #ifdef EXEC_BACKEND /* Write out nondefault GUC settings for child processes to use */ write_nondefault_variables(PGC_POSTMASTER); #endif /* * Write the external PID file if requested */ if (external_pid_file) { FILE *fpidfile = fopen(external_pid_file, "w"); if (fpidfile) { fprintf(fpidfile, "%d\n", MyProcPid); fclose(fpidfile); /* Make PID file world readable */ if (chmod(external_pid_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) != 0) write_stderr("%s: could not change permissions of external PID file \"%s\": %s\n", progname, external_pid_file, strerror(errno)); } else write_stderr("%s: could not write external PID file \"%s\": %s\n", progname, external_pid_file, strerror(errno)); on_proc_exit(unlink_external_pid_file, 0); } /* * Set up signal handlers for the postmaster process. * * CAUTION: when changing this list, check for side-effects on the signal * handling setup of child processes. See tcop/postgres.c, * bootstrap/bootstrap.c, postmaster/bgwriter.c, postmaster/walwriter.c, * postmaster/autovacuum.c, postmaster/pgarch.c, postmaster/pgstat.c, * postmaster/syslogger.c, postmaster/bgworker.c and * postmaster/checkpointer.c. */ pqinitmask(); PG_SETMASK(&BlockSig); pqsignal(SIGHUP, SIGHUP_handler); /* reread config file and have * children do same */ pqsignal(SIGINT, pmdie); /* send SIGTERM and shut down */ pqsignal(SIGQUIT, pmdie); /* send SIGQUIT and die */ pqsignal(SIGTERM, pmdie); /* wait for children and shut down */ pqsignal(SIGALRM, SIG_IGN); /* ignored */ pqsignal(SIGPIPE, SIG_IGN); /* ignored */ pqsignal(SIGUSR1, sigusr1_handler); /* message from child process */ pqsignal(SIGUSR2, dummy_handler); /* unused, reserve for children */ pqsignal(SIGCHLD, reaper); /* handle child termination */ pqsignal(SIGTTIN, SIG_IGN); /* ignored */ pqsignal(SIGTTOU, SIG_IGN); /* ignored */ /* ignore SIGXFSZ, so that ulimit violations work like disk full */ #ifdef SIGXFSZ pqsignal(SIGXFSZ, SIG_IGN); /* ignored */ #endif /* * If enabled, start up syslogger collection subprocess */ SysLoggerPID = SysLogger_Start(); /* * Reset whereToSendOutput from DestDebug (its starting state) to * DestNone. This stops ereport from sending log messages to stderr unless * Log_destination permits. We don't do this until the postmaster is * fully launched, since startup failures may as well be reported to * stderr. */ whereToSendOutput = DestNone; /* * Initialize stats collection subsystem (this does NOT start the * collector process!) */ pgstat_init(); /* * Initialize the autovacuum subsystem (again, no process start yet) */ autovac_init(); /* * Load configuration files for client authentication. */ if (!load_hba()) { /* * It makes no sense to continue if we fail to load the HBA file, * since there is no way to connect to the database in this case. */ ereport(FATAL, (errmsg("could not load pg_hba.conf"))); } if (!load_ident()) { /* * We can start up without the IDENT file, although it means that you * cannot log in using any of the authentication methods that need a * user name mapping. load_ident() already logged the details of * error to the log. */ } /* * Remove old temporary files. At this point there can be no other * Postgres processes running in this directory, so this should be safe. */ RemovePgTempFiles(); /* * Remember postmaster startup time */ PgStartTime = GetCurrentTimestamp(); /* PostmasterRandom wants its own copy */ gettimeofday(&random_start_time, NULL); /* * We're ready to rock and roll... */ StartupPID = StartupDataBase(); Assert(StartupPID != 0); pmState = PM_STARTUP; /* Some workers may be scheduled to start now */ StartOneBackgroundWorker(); status = ServerLoop(); /* * ServerLoop probably shouldn't ever return, but if it does, close down. */ ExitPostmaster(status != STATUS_OK); abort(); /* not reached */ }
static long PostmasterRandom | ( | void | ) | [static] |
Definition at line 4800 of file postmaster.c.
References gettimeofday(), NULL, random(), random_seed, random_start_time, and srandom().
Referenced by assign_backendlist_entry(), BackendStartup(), RandomSalt(), and StartAutovacuumWorker().
{ /* * Select a random seed at the time of first receiving a request. */ if (random_seed == 0) { do { struct timeval random_stop_time; gettimeofday(&random_stop_time, NULL); /* * We are not sure how much precision is in tv_usec, so we swap * the high and low 16 bits of 'random_stop_time' and XOR them * with 'random_start_time'. On the off chance that the result is * 0, we loop until it isn't. */ random_seed = random_start_time.tv_usec ^ ((random_stop_time.tv_usec << 16) | ((random_stop_time.tv_usec >> 16) & 0xffff)); } while (random_seed == 0); srandom(random_seed); } return random(); }
static void PostmasterStateMachine | ( | void | ) | [static] |
Definition at line 3260 of file postmaster.c.
References Assert, AutoVacPID, BACKEND_TYPE_ALL, BACKEND_TYPE_NORMAL, BACKEND_TYPE_WORKER, BackupInProgress(), BgWriterPID, CancelBackup(), CheckpointerPID, CountChildren(), CountUnconnectedWorkers(), dlist_is_empty(), ereport, errmsg(), ExitPostmaster(), FatalError, LOG, NoShutdown, PgArchPID, PgStatPID, PM_NO_CHILDREN, PM_SHUTDOWN_2, PM_WAIT_BACKENDS, PM_WAIT_BACKUP, PM_WAIT_DEAD_END, PM_WAIT_READONLY, pmState, PostPortNumber, ReachedNormalRunning, RecoveryError, reset_shared(), restart_after_crash, shmem_exit(), Shutdown, signal_child(), SignalChildren, SIGQUIT, SIGUSR2, StartCheckpointer, StartupDataBase, StartupPID, WalReceiverPID, and WalWriterPID.
Referenced by pmdie(), reaper(), and sigusr1_handler().
{ if (pmState == PM_WAIT_BACKUP) { /* * PM_WAIT_BACKUP state ends when online backup mode is not active. */ if (!BackupInProgress()) pmState = PM_WAIT_BACKENDS; } if (pmState == PM_WAIT_READONLY) { /* * PM_WAIT_READONLY state ends when we have no regular backends that * have been started during recovery. We kill the startup and * walreceiver processes and transition to PM_WAIT_BACKENDS. Ideally, * we might like to kill these processes first and then wait for * backends to die off, but that doesn't work at present because * killing the startup process doesn't release its locks. */ if (CountChildren(BACKEND_TYPE_NORMAL) == 0) { if (StartupPID != 0) signal_child(StartupPID, SIGTERM); if (WalReceiverPID != 0) signal_child(WalReceiverPID, SIGTERM); pmState = PM_WAIT_BACKENDS; } } /* * If we are in a state-machine state that implies waiting for backends to * exit, see if they're all gone, and change state if so. */ if (pmState == PM_WAIT_BACKENDS) { /* * PM_WAIT_BACKENDS state ends when we have no regular backends * (including autovac workers), no bgworkers (including unconnected * ones), and no walwriter, autovac launcher or bgwriter. If we are * doing crash recovery then we expect the checkpointer to exit as * well, otherwise not. The archiver, stats, and syslogger processes * are disregarded since they are not connected to shared memory; we * also disregard dead_end children here. Walsenders are also * disregarded, they will be terminated later after writing the * checkpoint record, like the archiver process. */ if (CountChildren(BACKEND_TYPE_NORMAL | BACKEND_TYPE_WORKER) == 0 && CountUnconnectedWorkers() == 0 && StartupPID == 0 && WalReceiverPID == 0 && BgWriterPID == 0 && (CheckpointerPID == 0 || !FatalError) && WalWriterPID == 0 && AutoVacPID == 0) { if (FatalError) { /* * Start waiting for dead_end children to die. This state * change causes ServerLoop to stop creating new ones. */ pmState = PM_WAIT_DEAD_END; /* * We already SIGQUIT'd the archiver and stats processes, if * any, when we entered FatalError state. */ } else { /* * If we get here, we are proceeding with normal shutdown. All * the regular children are gone, and it's time to tell the * checkpointer to do a shutdown checkpoint. */ Assert(Shutdown > NoShutdown); /* Start the checkpointer if not running */ if (CheckpointerPID == 0) CheckpointerPID = StartCheckpointer(); /* And tell it to shut down */ if (CheckpointerPID != 0) { signal_child(CheckpointerPID, SIGUSR2); pmState = PM_SHUTDOWN; } else { /* * If we failed to fork a checkpointer, just shut down. * Any required cleanup will happen at next restart. We * set FatalError so that an "abnormal shutdown" message * gets logged when we exit. */ FatalError = true; pmState = PM_WAIT_DEAD_END; /* Kill the walsenders, archiver and stats collector too */ SignalChildren(SIGQUIT); if (PgArchPID != 0) signal_child(PgArchPID, SIGQUIT); if (PgStatPID != 0) signal_child(PgStatPID, SIGQUIT); } } } } if (pmState == PM_SHUTDOWN_2) { /* * PM_SHUTDOWN_2 state ends when there's no other children than * dead_end children left. There shouldn't be any regular backends * left by now anyway; what we're really waiting for is walsenders and * archiver. * * Walreceiver should normally be dead by now, but not when a fast * shutdown is performed during recovery. */ if (PgArchPID == 0 && CountChildren(BACKEND_TYPE_ALL) == 0 && WalReceiverPID == 0) { pmState = PM_WAIT_DEAD_END; } } if (pmState == PM_WAIT_DEAD_END) { /* * PM_WAIT_DEAD_END state ends when the BackendList is entirely empty * (ie, no dead_end children remain), and the archiver and stats * collector are gone too. * * The reason we wait for those two is to protect them against a new * postmaster starting conflicting subprocesses; this isn't an * ironclad protection, but it at least helps in the * shutdown-and-immediately-restart scenario. Note that they have * already been sent appropriate shutdown signals, either during a * normal state transition leading up to PM_WAIT_DEAD_END, or during * FatalError processing. */ if (dlist_is_empty(&BackendList) && PgArchPID == 0 && PgStatPID == 0) { /* These other guys should be dead already */ Assert(StartupPID == 0); Assert(WalReceiverPID == 0); Assert(BgWriterPID == 0); Assert(CheckpointerPID == 0); Assert(WalWriterPID == 0); Assert(AutoVacPID == 0); /* syslogger is not considered here */ pmState = PM_NO_CHILDREN; } } /* * If we've been told to shut down, we exit as soon as there are no * remaining children. If there was a crash, cleanup will occur at the * next startup. (Before PostgreSQL 8.3, we tried to recover from the * crash before exiting, but that seems unwise if we are quitting because * we got SIGTERM from init --- there may well not be time for recovery * before init decides to SIGKILL us.) * * Note that the syslogger continues to run. It will exit when it sees * EOF on its input pipe, which happens when there are no more upstream * processes. */ if (Shutdown > NoShutdown && pmState == PM_NO_CHILDREN) { if (FatalError) { ereport(LOG, (errmsg("abnormal database system shutdown"))); ExitPostmaster(1); } else { /* * Terminate exclusive backup mode to avoid recovery after a clean * fast shutdown. Since an exclusive backup can only be taken * during normal running (and not, for example, while running * under Hot Standby) it only makes sense to do this if we reached * normal running. If we're still in recovery, the backup file is * one we're recovering *from*, and we must keep it around so that * recovery restarts from the right place. */ if (ReachedNormalRunning) CancelBackup(); /* Normal exit from the postmaster is here */ ExitPostmaster(0); } } /* * If recovery failed, or the user does not want an automatic restart * after backend crashes, wait for all non-syslogger children to exit, and * then exit postmaster. We don't try to reinitialize when recovery fails, * because more than likely it will just fail again and we will keep * trying forever. */ if (pmState == PM_NO_CHILDREN && (RecoveryError || !restart_after_crash)) ExitPostmaster(1); /* * If we need to recover from a crash, wait for all non-syslogger children * to exit, then reset shmem and StartupDataBase. */ if (FatalError && pmState == PM_NO_CHILDREN) { ereport(LOG, (errmsg("all server processes terminated; reinitializing"))); shmem_exit(1); reset_shared(PostPortNumber); StartupPID = StartupDataBase(); Assert(StartupPID != 0); pmState = PM_STARTUP; } }
static void processCancelRequest | ( | Port * | port, | |
void * | pkt | |||
) | [static] |
Definition at line 2009 of file postmaster.c.
References CancelRequestPacket::backendPID, bkend::cancel_key, CancelRequestPacket::cancelAuthCode, dlist_iter::cur, DEBUG2, dlist_container, dlist_foreach, ereport, errmsg(), errmsg_internal(), i, LOG, MaxLivePostmasterChildren(), bkend::pid, and signal_child().
Referenced by ProcessStartupPacket().
{ CancelRequestPacket *canc = (CancelRequestPacket *) pkt; int backendPID; long cancelAuthCode; Backend *bp; #ifndef EXEC_BACKEND dlist_iter iter; #else int i; #endif backendPID = (int) ntohl(canc->backendPID); cancelAuthCode = (long) ntohl(canc->cancelAuthCode); /* * See if we have a matching backend. In the EXEC_BACKEND case, we can no * longer access the postmaster's own backend list, and must rely on the * duplicate array in shared memory. */ #ifndef EXEC_BACKEND dlist_foreach(iter, &BackendList) { bp = dlist_container(Backend, elem, iter.cur); #else for (i = MaxLivePostmasterChildren() - 1; i >= 0; i--) { bp = (Backend *) &ShmemBackendArray[i]; #endif if (bp->pid == backendPID) { if (bp->cancel_key == cancelAuthCode) { /* Found a match; signal that backend to cancel current op */ ereport(DEBUG2, (errmsg_internal("processing cancel request: sending SIGINT to process %d", backendPID))); signal_child(bp->pid, SIGINT); } else /* Right PID, wrong key: no way, Jose */ ereport(LOG, (errmsg("wrong key in cancel request for process %d", backendPID))); return; } } /* No matching backend */ ereport(LOG, (errmsg("PID %d in cancel request did not match any process", backendPID))); }
Definition at line 1704 of file postmaster.c.
References SockAddr::addr, am_walsender, buf, CAC_OK, CAC_RECOVERY, CAC_SHUTDOWN, CAC_STARTUP, CAC_TOOMANY, CAC_WAITBACKUP, Port::canAcceptConnections, CANCEL_REQUEST_CODE, Port::cmdline_options, COMMERROR, StartupPacket::database, Port::database_name, Db_user_namespace, EINTR, EnableSSL, ereport, errcode(), ERRCODE_CANNOT_CONNECT_NOW, errcode_for_socket_access(), errmsg(), FATAL, FrontendProtocol, Port::guc_options, IS_AF_UNIX, Port::laddr, lappend(), MAX_STARTUP_PACKET_LENGTH, MemoryContextSwitchTo(), NAMEDATALEN, NEGOTIATE_SSL_CODE, NULL, StartupPacket::options, palloc(), palloc0(), parse_bool(), PG_PROTOCOL_EARLIEST, PG_PROTOCOL_LATEST, PG_PROTOCOL_MAJOR, PG_PROTOCOL_MINOR, pq_getbytes(), processCancelRequest(), Port::proto, pstrdup(), secure_open_server(), send, Port::sock, TopMemoryContext, StartupPacket::user, and Port::user_name.
Referenced by BackendInitialize().
{ int32 len; void *buf; ProtocolVersion proto; MemoryContext oldcontext; if (pq_getbytes((char *) &len, 4) == EOF) { /* * EOF after SSLdone probably means the client didn't like our * response to NEGOTIATE_SSL_CODE. That's not an error condition, so * don't clutter the log with a complaint. */ if (!SSLdone) ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("incomplete startup packet"))); return STATUS_ERROR; } len = ntohl(len); len -= 4; if (len < (int32) sizeof(ProtocolVersion) || len > MAX_STARTUP_PACKET_LENGTH) { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("invalid length of startup packet"))); return STATUS_ERROR; } /* * Allocate at least the size of an old-style startup packet, plus one * extra byte, and make sure all are zeroes. This ensures we will have * null termination of all strings, in both fixed- and variable-length * packet layouts. */ if (len <= (int32) sizeof(StartupPacket)) buf = palloc0(sizeof(StartupPacket) + 1); else buf = palloc0(len + 1); if (pq_getbytes(buf, len) == EOF) { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("incomplete startup packet"))); return STATUS_ERROR; } /* * The first field is either a protocol version number or a special * request code. */ port->proto = proto = ntohl(*((ProtocolVersion *) buf)); if (proto == CANCEL_REQUEST_CODE) { processCancelRequest(port, buf); /* Not really an error, but we don't want to proceed further */ return STATUS_ERROR; } if (proto == NEGOTIATE_SSL_CODE && !SSLdone) { char SSLok; #ifdef USE_SSL /* No SSL when disabled or on Unix sockets */ if (!EnableSSL || IS_AF_UNIX(port->laddr.addr.ss_family)) SSLok = 'N'; else SSLok = 'S'; /* Support for SSL */ #else SSLok = 'N'; /* No support for SSL */ #endif retry1: if (send(port->sock, &SSLok, 1, 0) != 1) { if (errno == EINTR) goto retry1; /* if interrupted, just retry */ ereport(COMMERROR, (errcode_for_socket_access(), errmsg("failed to send SSL negotiation response: %m"))); return STATUS_ERROR; /* close the connection */ } #ifdef USE_SSL if (SSLok == 'S' && secure_open_server(port) == -1) return STATUS_ERROR; #endif /* regular startup packet, cancel, etc packet should follow... */ /* but not another SSL negotiation request */ return ProcessStartupPacket(port, true); } /* Could add additional special packet types here */ /* * Set FrontendProtocol now so that ereport() knows what format to send if * we fail during startup. */ FrontendProtocol = proto; /* Check we can handle the protocol the frontend is using. */ if (PG_PROTOCOL_MAJOR(proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) || PG_PROTOCOL_MAJOR(proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) || (PG_PROTOCOL_MAJOR(proto) == PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) && PG_PROTOCOL_MINOR(proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST))) ereport(FATAL, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("unsupported frontend protocol %u.%u: server supports %u.0 to %u.%u", PG_PROTOCOL_MAJOR(proto), PG_PROTOCOL_MINOR(proto), PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST), PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST), PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)))); /* * Now fetch parameters out of startup packet and save them into the Port * structure. All data structures attached to the Port struct must be * allocated in TopMemoryContext so that they will remain available in a * running backend (even after PostmasterContext is destroyed). We need * not worry about leaking this storage on failure, since we aren't in the * postmaster process anymore. */ oldcontext = MemoryContextSwitchTo(TopMemoryContext); if (PG_PROTOCOL_MAJOR(proto) >= 3) { int32 offset = sizeof(ProtocolVersion); /* * Scan packet body for name/option pairs. We can assume any string * beginning within the packet body is null-terminated, thanks to * zeroing extra byte above. */ port->guc_options = NIL; while (offset < len) { char *nameptr = ((char *) buf) + offset; int32 valoffset; char *valptr; if (*nameptr == '\0') break; /* found packet terminator */ valoffset = offset + strlen(nameptr) + 1; if (valoffset >= len) break; /* missing value, will complain below */ valptr = ((char *) buf) + valoffset; if (strcmp(nameptr, "database") == 0) port->database_name = pstrdup(valptr); else if (strcmp(nameptr, "user") == 0) port->user_name = pstrdup(valptr); else if (strcmp(nameptr, "options") == 0) port->cmdline_options = pstrdup(valptr); else if (strcmp(nameptr, "replication") == 0) { if (!parse_bool(valptr, &am_walsender)) ereport(FATAL, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid value for boolean option \"replication\""))); } else { /* Assume it's a generic GUC option */ port->guc_options = lappend(port->guc_options, pstrdup(nameptr)); port->guc_options = lappend(port->guc_options, pstrdup(valptr)); } offset = valoffset + strlen(valptr) + 1; } /* * If we didn't find a packet terminator exactly at the end of the * given packet length, complain. */ if (offset != len - 1) ereport(FATAL, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("invalid startup packet layout: expected terminator as last byte"))); } else { /* * Get the parameters from the old-style, fixed-width-fields startup * packet as C strings. The packet destination was cleared first so a * short packet has zeros silently added. We have to be prepared to * truncate the pstrdup result for oversize fields, though. */ StartupPacket *packet = (StartupPacket *) buf; port->database_name = pstrdup(packet->database); if (strlen(port->database_name) > sizeof(packet->database)) port->database_name[sizeof(packet->database)] = '\0'; port->user_name = pstrdup(packet->user); if (strlen(port->user_name) > sizeof(packet->user)) port->user_name[sizeof(packet->user)] = '\0'; port->cmdline_options = pstrdup(packet->options); if (strlen(port->cmdline_options) > sizeof(packet->options)) port->cmdline_options[sizeof(packet->options)] = '\0'; port->guc_options = NIL; } /* Check a user name was given. */ if (port->user_name == NULL || port->user_name[0] == '\0') ereport(FATAL, (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), errmsg("no PostgreSQL user name specified in startup packet"))); /* The database defaults to the user name. */ if (port->database_name == NULL || port->database_name[0] == '\0') port->database_name = pstrdup(port->user_name); if (Db_user_namespace) { /* * If user@, it is a global user, remove '@'. We only want to do this * if there is an '@' at the end and no earlier in the user string or * they may fake as a local user of another database attaching to this * database. */ if (strchr(port->user_name, '@') == port->user_name + strlen(port->user_name) - 1) *strchr(port->user_name, '@') = '\0'; else { /* Append '@' and dbname */ char *db_user; db_user = palloc(strlen(port->user_name) + strlen(port->database_name) + 2); sprintf(db_user, "%s@%s", port->user_name, port->database_name); port->user_name = db_user; } } /* * Truncate given database and user names to length of a Postgres name. * This avoids lookup failures when overlength names are given. */ if (strlen(port->database_name) >= NAMEDATALEN) port->database_name[NAMEDATALEN - 1] = '\0'; if (strlen(port->user_name) >= NAMEDATALEN) port->user_name[NAMEDATALEN - 1] = '\0'; /* Walsender is not related to a particular database */ if (am_walsender) port->database_name[0] = '\0'; /* * Done putting stuff in TopMemoryContext. */ MemoryContextSwitchTo(oldcontext); /* * If we're going to reject the connection due to database state, say so * now instead of wasting cycles on an authentication exchange. (This also * allows a pg_ping utility to be written.) */ switch (port->canAcceptConnections) { case CAC_STARTUP: ereport(FATAL, (errcode(ERRCODE_CANNOT_CONNECT_NOW), errmsg("the database system is starting up"))); break; case CAC_SHUTDOWN: ereport(FATAL, (errcode(ERRCODE_CANNOT_CONNECT_NOW), errmsg("the database system is shutting down"))); break; case CAC_RECOVERY: ereport(FATAL, (errcode(ERRCODE_CANNOT_CONNECT_NOW), errmsg("the database system is in recovery mode"))); break; case CAC_TOOMANY: ereport(FATAL, (errcode(ERRCODE_TOO_MANY_CONNECTIONS), errmsg("sorry, too many clients already"))); break; case CAC_WAITBACKUP: /* OK for now, will check in InitPostgres */ break; case CAC_OK: break; } return STATUS_OK; }
static void RandomSalt | ( | char * | md5Salt | ) | [static] |
Definition at line 4777 of file postmaster.c.
References PostmasterRandom().
Referenced by ConnCreate().
{ long rand; /* * We use % 255, sacrificing one possible byte value, so as to ensure that * all bits of the random() value participate in the result. While at it, * add one to avoid generating any null bytes. */ rand = PostmasterRandom(); md5Salt[0] = (rand % 255) + 1; rand = PostmasterRandom(); md5Salt[1] = (rand % 255) + 1; rand = PostmasterRandom(); md5Salt[2] = (rand % 255) + 1; rand = PostmasterRandom(); md5Salt[3] = (rand % 255) + 1; }
static void reaper | ( | SIGNAL_ARGS | ) | [static] |
Definition at line 2492 of file postmaster.c.
References _, Assert, AutoVacPID, AutoVacuumingActive(), BgWriterPID, BlockSig, CheckpointerPID, CleanupBackend(), CleanupBackgroundWorker(), DEBUG4, ereport, errmsg(), errmsg_internal(), EXIT_STATUS_0, EXIT_STATUS_1, ExitPostmaster(), FatalError, HandleChildCrash(), HaveCrashedWorker, IsBinaryUpgrade, LOG, LogChildExit(), NoShutdown, PG_SETMASK, pgarch_start(), PgArchPID, pgstat_start(), PgStatPID, PM_RUN, PM_SHUTDOWN, PM_STARTUP, pmState, PostmasterStateMachine(), ReachedNormalRunning, RecoveryError, Shutdown, signal_child(), SignalChildren, SIGQUIT, SIGUSR2, StartAutoVacLauncher(), StartBackgroundWriter, StartCheckpointer, StartOneBackgroundWorker(), StartupPID, StartWalWriter, SysLogger_Start(), SysLoggerPID, UnBlockSig, WalReceiverPID, WalWriterPID, and XLogArchivingActive.
Referenced by PostmasterMain().
{ int save_errno = errno; int pid; /* process id of dead child process */ int exitstatus; /* its exit status */ PG_SETMASK(&BlockSig); ereport(DEBUG4, (errmsg_internal("reaping dead processes"))); while ((pid = waitpid(-1, &exitstatus, WNOHANG)) > 0) { /* * Check if this child was a startup process. */ if (pid == StartupPID) { StartupPID = 0; /* * Startup process exited in response to a shutdown request (or it * completed normally regardless of the shutdown request). */ if (Shutdown > NoShutdown && (EXIT_STATUS_0(exitstatus) || EXIT_STATUS_1(exitstatus))) { pmState = PM_WAIT_BACKENDS; /* PostmasterStateMachine logic does the rest */ continue; } /* * Unexpected exit of startup process (including FATAL exit) * during PM_STARTUP is treated as catastrophic. There are no * other processes running yet, so we can just exit. */ if (pmState == PM_STARTUP && !EXIT_STATUS_0(exitstatus)) { LogChildExit(LOG, _("startup process"), pid, exitstatus); ereport(LOG, (errmsg("aborting startup due to startup process failure"))); ExitPostmaster(1); } /* * After PM_STARTUP, any unexpected exit (including FATAL exit) of * the startup process is catastrophic, so kill other children, * and set RecoveryError so we don't try to reinitialize after * they're gone. Exception: if FatalError is already set, that * implies we previously sent the startup process a SIGQUIT, so * that's probably the reason it died, and we do want to try to * restart in that case. */ if (!EXIT_STATUS_0(exitstatus)) { if (!FatalError) RecoveryError = true; HandleChildCrash(pid, exitstatus, _("startup process")); continue; } /* * Startup succeeded, commence normal operations */ FatalError = false; ReachedNormalRunning = true; pmState = PM_RUN; /* * Crank up the background tasks, if we didn't do that already * when we entered consistent recovery state. It doesn't matter * if this fails, we'll just try again later. */ if (CheckpointerPID == 0) CheckpointerPID = StartCheckpointer(); if (BgWriterPID == 0) BgWriterPID = StartBackgroundWriter(); if (WalWriterPID == 0) WalWriterPID = StartWalWriter(); /* * Likewise, start other special children as needed. In a restart * situation, some of them may be alive already. */ if (!IsBinaryUpgrade && AutoVacuumingActive() && AutoVacPID == 0) AutoVacPID = StartAutoVacLauncher(); if (XLogArchivingActive() && PgArchPID == 0) PgArchPID = pgarch_start(); if (PgStatPID == 0) PgStatPID = pgstat_start(); /* some workers may be scheduled to start now */ StartOneBackgroundWorker(); /* at this point we are really open for business */ ereport(LOG, (errmsg("database system is ready to accept connections"))); continue; } /* * Was it the bgwriter? Normal exit can be ignored; we'll start a new * one at the next iteration of the postmaster's main loop, if * necessary. Any other exit condition is treated as a crash. */ if (pid == BgWriterPID) { BgWriterPID = 0; if (!EXIT_STATUS_0(exitstatus)) HandleChildCrash(pid, exitstatus, _("background writer process")); continue; } /* * Was it the checkpointer? */ if (pid == CheckpointerPID) { CheckpointerPID = 0; if (EXIT_STATUS_0(exitstatus) && pmState == PM_SHUTDOWN) { /* * OK, we saw normal exit of the checkpointer after it's been * told to shut down. We expect that it wrote a shutdown * checkpoint. (If for some reason it didn't, recovery will * occur on next postmaster start.) * * At this point we should have no normal backend children * left (else we'd not be in PM_SHUTDOWN state) but we might * have dead_end children to wait for. * * If we have an archiver subprocess, tell it to do a last * archive cycle and quit. Likewise, if we have walsender * processes, tell them to send any remaining WAL and quit. */ Assert(Shutdown > NoShutdown); /* Waken archiver for the last time */ if (PgArchPID != 0) signal_child(PgArchPID, SIGUSR2); /* * Waken walsenders for the last time. No regular backends * should be around anymore. */ SignalChildren(SIGUSR2); pmState = PM_SHUTDOWN_2; /* * We can also shut down the stats collector now; there's * nothing left for it to do. */ if (PgStatPID != 0) signal_child(PgStatPID, SIGQUIT); } else { /* * Any unexpected exit of the checkpointer (including FATAL * exit) is treated as a crash. */ HandleChildCrash(pid, exitstatus, _("checkpointer process")); } continue; } /* * Was it the wal writer? Normal exit can be ignored; we'll start a * new one at the next iteration of the postmaster's main loop, if * necessary. Any other exit condition is treated as a crash. */ if (pid == WalWriterPID) { WalWriterPID = 0; if (!EXIT_STATUS_0(exitstatus)) HandleChildCrash(pid, exitstatus, _("WAL writer process")); continue; } /* * Was it the wal receiver? If exit status is zero (normal) or one * (FATAL exit), we assume everything is all right just like normal * backends. */ if (pid == WalReceiverPID) { WalReceiverPID = 0; if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_1(exitstatus)) HandleChildCrash(pid, exitstatus, _("WAL receiver process")); continue; } /* * Was it the autovacuum launcher? Normal exit can be ignored; we'll * start a new one at the next iteration of the postmaster's main * loop, if necessary. Any other exit condition is treated as a * crash. */ if (pid == AutoVacPID) { AutoVacPID = 0; if (!EXIT_STATUS_0(exitstatus)) HandleChildCrash(pid, exitstatus, _("autovacuum launcher process")); continue; } /* * Was it the archiver? If so, just try to start a new one; no need * to force reset of the rest of the system. (If fail, we'll try * again in future cycles of the main loop.). Unless we were waiting * for it to shut down; don't restart it in that case, and * PostmasterStateMachine() will advance to the next shutdown step. */ if (pid == PgArchPID) { PgArchPID = 0; if (!EXIT_STATUS_0(exitstatus)) LogChildExit(LOG, _("archiver process"), pid, exitstatus); if (XLogArchivingActive() && pmState == PM_RUN) PgArchPID = pgarch_start(); continue; } /* * Was it the statistics collector? If so, just try to start a new * one; no need to force reset of the rest of the system. (If fail, * we'll try again in future cycles of the main loop.) */ if (pid == PgStatPID) { PgStatPID = 0; if (!EXIT_STATUS_0(exitstatus)) LogChildExit(LOG, _("statistics collector process"), pid, exitstatus); if (pmState == PM_RUN) PgStatPID = pgstat_start(); continue; } /* Was it the system logger? If so, try to start a new one */ if (pid == SysLoggerPID) { SysLoggerPID = 0; /* for safety's sake, launch new logger *first* */ SysLoggerPID = SysLogger_Start(); if (!EXIT_STATUS_0(exitstatus)) LogChildExit(LOG, _("system logger process"), pid, exitstatus); continue; } /* Was it one of our background workers? */ if (CleanupBackgroundWorker(pid, exitstatus)) { /* have it be restarted */ HaveCrashedWorker = true; continue; } /* * Else do standard backend child cleanup. */ CleanupBackend(pid, exitstatus); } /* loop over pending child-death reports */ /* * After cleaning out the SIGCHLD queue, see if we have any state changes * or actions to make. */ PostmasterStateMachine(); /* Done with signal handler */ PG_SETMASK(&UnBlockSig); errno = save_errno; }
void RegisterBackgroundWorker | ( | BackgroundWorker * | worker | ) |
Definition at line 5143 of file postmaster.c.
References autovacuum_max_workers, BackgroundWorker::bgw_flags, BackgroundWorker::bgw_name, BGW_NEVER_RESTART, BackgroundWorker::bgw_restart_time, BackgroundWorker::bgw_start_time, BGWORKER_BACKEND_DATABASE_CONNECTION, BGWORKER_SHMEM_ACCESS, BgWorkerStart_PostmasterStart, ereport, errcode(), errdetail(), errmsg(), IsUnderPostmaster, LOG, malloc, MAX_BACKENDS, MaxConnections, NULL, process_shared_preload_libraries_in_progress, RegisteredBgWorker::rw_backend, RegisteredBgWorker::rw_child_slot, RegisteredBgWorker::rw_crashed_at, RegisteredBgWorker::rw_lnode, RegisteredBgWorker::rw_pid, RegisteredBgWorker::rw_worker, slist_push_head(), strlcpy(), and USECS_PER_DAY.
Referenced by _PG_init().
{ RegisteredBgWorker *rw; int namelen = strlen(worker->bgw_name); static int maxworkers; static int numworkers = 0; #ifdef EXEC_BACKEND /* * Use 1 here, not 0, to avoid confusing a possible bogus cookie read by * atoi() in SubPostmasterMain. */ static int BackgroundWorkerCookie = 1; #endif /* initialize upper limit on first call */ if (numworkers == 0) maxworkers = MAX_BACKENDS - (MaxConnections + autovacuum_max_workers + 1); if (!IsUnderPostmaster) ereport(LOG, (errmsg("registering background worker: %s", worker->bgw_name))); if (!process_shared_preload_libraries_in_progress) { if (!IsUnderPostmaster) ereport(LOG, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("background worker \"%s\": must be registered in shared_preload_libraries", worker->bgw_name))); return; } /* sanity check for flags */ if (worker->bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION) { if (!(worker->bgw_flags & BGWORKER_SHMEM_ACCESS)) { if (!IsUnderPostmaster) ereport(LOG, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("background worker \"%s\": must attach to shared memory in order to request a database connection", worker->bgw_name))); return; } if (worker->bgw_start_time == BgWorkerStart_PostmasterStart) { if (!IsUnderPostmaster) ereport(LOG, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("background worker \"%s\": cannot request database access if starting at postmaster start", worker->bgw_name))); return; } /* XXX other checks? */ } if ((worker->bgw_restart_time < 0 && worker->bgw_restart_time != BGW_NEVER_RESTART) || (worker->bgw_restart_time > USECS_PER_DAY / 1000)) { if (!IsUnderPostmaster) ereport(LOG, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("background worker \"%s\": invalid restart interval", worker->bgw_name))); return; } /* * Enforce maximum number of workers. Note this is overly restrictive: * we could allow more non-shmem-connected workers, because these don't * count towards the MAX_BACKENDS limit elsewhere. This doesn't really * matter for practical purposes; several million processes would need to * run on a single server. */ if (++numworkers > maxworkers) { ereport(LOG, (errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED), errmsg("too many background workers"), errdetail("Up to %d background workers can be registered with the current settings.", maxworkers))); return; } /* * Copy the registration data into the registered workers list. */ rw = malloc(sizeof(RegisteredBgWorker) + namelen + 1); if (rw == NULL) { ereport(LOG, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); return; } rw->rw_worker = *worker; rw->rw_worker.bgw_name = ((char *) rw) + sizeof(RegisteredBgWorker); strlcpy(rw->rw_worker.bgw_name, worker->bgw_name, namelen + 1); rw->rw_backend = NULL; rw->rw_pid = 0; rw->rw_child_slot = 0; rw->rw_crashed_at = 0; #ifdef EXEC_BACKEND rw->rw_cookie = BackgroundWorkerCookie++; #endif slist_push_head(&BackgroundWorkerList, &rw->rw_lnode); }
static void report_fork_failure_to_client | ( | Port * | port, | |
int | errnum | |||
) | [static] |
Definition at line 3723 of file postmaster.c.
References _, EINTR, pg_set_noblock(), send, snprintf(), Port::sock, and strerror().
Referenced by BackendStartup().
{ char buffer[1000]; int rc; /* Format the error message packet (always V2 protocol) */ snprintf(buffer, sizeof(buffer), "E%s%s\n", _("could not fork new process for connection: "), strerror(errnum)); /* Set port to non-blocking. Don't do send() if this fails */ if (!pg_set_noblock(port->sock)) return; /* We'll retry after EINTR, but ignore all other failures */ do { rc = send(port->sock, buffer, strlen(buffer) + 1, 0); } while (rc < 0 && errno == EINTR); }
static void reset_shared | ( | int | port | ) | [static] |
Definition at line 2253 of file postmaster.c.
References CreateSharedMemoryAndSemaphores().
Referenced by PostmasterMain(), and PostmasterStateMachine().
{ /* * Create or re-create shared memory and semaphores. * * Note: in each "cycle of life" we will normally assign the same IPC keys * (if using SysV shmem and/or semas), since the port number is used to * determine IPC keys. This helps ensure that we will clean up dead IPC * objects if the postmaster crashes and is restarted. */ CreateSharedMemoryAndSemaphores(false, port); }
static int ServerLoop | ( | void | ) | [static] |
Definition at line 1496 of file postmaster.c.
References AutoVacPID, AutoVacuumingActive(), avlauncher_needs_signal, BackendStartup(), BgWriterPID, BlockSig, CheckpointerPID, ConnCreate(), ConnFree(), DetermineSleepTime(), EINTR, ereport, errcode_for_socket_access(), errmsg(), EWOULDBLOCK, HaveCrashedWorker, i, initMasks(), IsBinaryUpgrade, ListenSocket, LOG, Logging_collector, NULL, PG_SETMASK, pg_usleep(), pgarch_start(), PgArchPID, PGINVALID_SOCKET, pgstat_start(), PgStatPID, PM_HOT_STANDBY, PM_RECOVERY, PM_RUN, PM_WAIT_DEAD_END, pmState, port, SECS_PER_MINUTE, select, SIGUSR2, Port::sock, start_autovac_launcher, StartAutoVacLauncher(), StartBackgroundWriter, StartCheckpointer, StartOneBackgroundWorker(), StartWalWriter, StartWorkerNeeded, StreamClose(), SysLogger_Start(), SysLoggerPID, TouchSocketFiles(), TouchSocketLockFiles(), UnBlockSig, WalWriterPID, and XLogArchivingActive.
Referenced by PostmasterMain().
{ fd_set readmask; int nSockets; time_t now, last_touch_time; last_touch_time = time(NULL); nSockets = initMasks(&readmask); for (;;) { fd_set rmask; int selres; /* * Wait for a connection request to arrive. * * If we are in PM_WAIT_DEAD_END state, then we don't want to accept * any new connections, so we don't call select() at all; just sleep * for a little bit with signals unblocked. */ memcpy((char *) &rmask, (char *) &readmask, sizeof(fd_set)); PG_SETMASK(&UnBlockSig); if (pmState == PM_WAIT_DEAD_END) { pg_usleep(100000L); /* 100 msec seems reasonable */ selres = 0; } else { /* must set timeout each time; some OSes change it! */ struct timeval timeout; DetermineSleepTime(&timeout); selres = select(nSockets, &rmask, NULL, NULL, &timeout); } /* * Block all signals until we wait again. (This makes it safe for our * signal handlers to do nontrivial work.) */ PG_SETMASK(&BlockSig); /* Now check the select() result */ if (selres < 0) { if (errno != EINTR && errno != EWOULDBLOCK) { ereport(LOG, (errcode_for_socket_access(), errmsg("select() failed in postmaster: %m"))); return STATUS_ERROR; } } /* * New connection pending on any of our sockets? If so, fork a child * process to deal with it. */ if (selres > 0) { int i; for (i = 0; i < MAXLISTEN; i++) { if (ListenSocket[i] == PGINVALID_SOCKET) break; if (FD_ISSET(ListenSocket[i], &rmask)) { Port *port; port = ConnCreate(ListenSocket[i]); if (port) { BackendStartup(port); /* * We no longer need the open socket or port structure * in this process */ StreamClose(port->sock); ConnFree(port); } } } } /* If we have lost the log collector, try to start a new one */ if (SysLoggerPID == 0 && Logging_collector) SysLoggerPID = SysLogger_Start(); /* * If no background writer process is running, and we are not in a * state that prevents it, start one. It doesn't matter if this * fails, we'll just try again later. Likewise for the checkpointer. */ if (pmState == PM_RUN || pmState == PM_RECOVERY || pmState == PM_HOT_STANDBY) { if (CheckpointerPID == 0) CheckpointerPID = StartCheckpointer(); if (BgWriterPID == 0) BgWriterPID = StartBackgroundWriter(); } /* * Likewise, if we have lost the walwriter process, try to start a new * one. But this is needed only in normal operation (else we cannot * be writing any new WAL). */ if (WalWriterPID == 0 && pmState == PM_RUN) WalWriterPID = StartWalWriter(); /* * If we have lost the autovacuum launcher, try to start a new one. We * don't want autovacuum to run in binary upgrade mode because * autovacuum might update relfrozenxid for empty tables before the * physical files are put in place. */ if (!IsBinaryUpgrade && AutoVacPID == 0 && (AutoVacuumingActive() || start_autovac_launcher) && pmState == PM_RUN) { AutoVacPID = StartAutoVacLauncher(); if (AutoVacPID != 0) start_autovac_launcher = false; /* signal processed */ } /* If we have lost the archiver, try to start a new one */ if (XLogArchivingActive() && PgArchPID == 0 && pmState == PM_RUN) PgArchPID = pgarch_start(); /* If we have lost the stats collector, try to start a new one */ if (PgStatPID == 0 && pmState == PM_RUN) PgStatPID = pgstat_start(); /* If we need to signal the autovacuum launcher, do so now */ if (avlauncher_needs_signal) { avlauncher_needs_signal = false; if (AutoVacPID != 0) kill(AutoVacPID, SIGUSR2); } /* Get other worker processes running, if needed */ if (StartWorkerNeeded || HaveCrashedWorker) StartOneBackgroundWorker(); /* * Touch Unix socket and lock files every 58 minutes, to ensure that * they are not removed by overzealous /tmp-cleaning tasks. We assume * no one runs cleaners with cutoff times of less than an hour ... */ now = time(NULL); if (now - last_touch_time >= 58 * SECS_PER_MINUTE) { TouchSocketFiles(); TouchSocketLockFiles(); last_touch_time = now; } } }
static void SIGHUP_handler | ( | SIGNAL_ARGS | ) | [static] |
Definition at line 2271 of file postmaster.c.
References AutoVacPID, BgWriterPID, BlockSig, CheckpointerPID, ereport, errmsg(), load_hba(), load_ident(), LOG, PG_SETMASK, PgArchPID, PGC_SIGHUP, PgStatPID, ProcessConfigFile(), Shutdown, SIGHUP, signal_child(), SignalChildren, SignalUnconnectedWorkers(), SmartShutdown, StartupPID, SysLoggerPID, UnBlockSig, WalReceiverPID, WalWriterPID, and WARNING.
Referenced by PostmasterMain().
{ int save_errno = errno; PG_SETMASK(&BlockSig); if (Shutdown <= SmartShutdown) { ereport(LOG, (errmsg("received SIGHUP, reloading configuration files"))); ProcessConfigFile(PGC_SIGHUP); SignalChildren(SIGHUP); SignalUnconnectedWorkers(SIGHUP); if (StartupPID != 0) signal_child(StartupPID, SIGHUP); if (BgWriterPID != 0) signal_child(BgWriterPID, SIGHUP); if (CheckpointerPID != 0) signal_child(CheckpointerPID, SIGHUP); if (WalWriterPID != 0) signal_child(WalWriterPID, SIGHUP); if (WalReceiverPID != 0) signal_child(WalReceiverPID, SIGHUP); if (AutoVacPID != 0) signal_child(AutoVacPID, SIGHUP); if (PgArchPID != 0) signal_child(PgArchPID, SIGHUP); if (SysLoggerPID != 0) signal_child(SysLoggerPID, SIGHUP); if (PgStatPID != 0) signal_child(PgStatPID, SIGHUP); /* Reload authentication config files too */ if (!load_hba()) ereport(WARNING, (errmsg("pg_hba.conf not reloaded"))); if (!load_ident()) ereport(WARNING, (errmsg("pg_ident.conf not reloaded"))); #ifdef EXEC_BACKEND /* Update the starting-point file for future children */ write_nondefault_variables(PGC_SIGHUP); #endif } PG_SETMASK(&UnBlockSig); errno = save_errno; }
static void signal_child | ( | pid_t | pid, | |
int | signal | |||
) | [static] |
Definition at line 3501 of file postmaster.c.
References DEBUG3, elog, SIGQUIT, and SIGSTOP.
Referenced by HandleChildCrash(), pmdie(), PostmasterStateMachine(), processCancelRequest(), reaper(), SIGHUP_handler(), SignalSomeChildren(), SignalUnconnectedWorkers(), and sigusr1_handler().
{ if (kill(pid, signal) < 0) elog(DEBUG3, "kill(%ld,%d) failed: %m", (long) pid, signal); #ifdef HAVE_SETSID switch (signal) { case SIGINT: case SIGTERM: case SIGQUIT: case SIGSTOP: if (kill(-pid, signal) < 0) elog(DEBUG3, "kill(%ld,%d) failed: %m", (long) (-pid), signal); break; default: break; } #endif }
static bool SignalSomeChildren | ( | int | signal, | |
int | targets | |||
) | [static] |
Definition at line 3559 of file postmaster.c.
References BACKEND_TYPE_ALL, BACKEND_TYPE_NORMAL, bkend::bkend_type, bkend::child_slot, dlist_iter::cur, bkend::dead_end, DEBUG4, dlist_container, dlist_foreach, ereport, errmsg_internal(), IsPostmasterChildWalSender(), bkend::pid, signal_child(), and signaled.
Referenced by pmdie().
{ dlist_iter iter; bool signaled = false; dlist_foreach(iter, &BackendList) { Backend *bp = dlist_container(Backend, elem, iter.cur); if (bp->dead_end) continue; /* * Since target == BACKEND_TYPE_ALL is the most common case, we test * it first and avoid touching shared memory for every child. */ if (target != BACKEND_TYPE_ALL) { /* * Assign bkend_type for any recently announced WAL Sender * processes. */ if (bp->bkend_type == BACKEND_TYPE_NORMAL && IsPostmasterChildWalSender(bp->child_slot)) bp->bkend_type = BACKEND_TYPE_WALSND; if (!(target & bp->bkend_type)) continue; } ereport(DEBUG4, (errmsg_internal("sending signal %d to process %d", signal, (int) bp->pid))); signal_child(bp->pid, signal); signaled = true; } return signaled; }
static bool SignalUnconnectedWorkers | ( | int | signal | ) | [static] |
Definition at line 3528 of file postmaster.c.
References slist_iter::cur, DEBUG4, ereport, errmsg_internal(), NULL, RegisteredBgWorker::rw_backend, RegisteredBgWorker::rw_pid, signal_child(), signaled, slist_container, and slist_foreach.
Referenced by pmdie(), and SIGHUP_handler().
{ slist_iter iter; bool signaled = false; slist_foreach(iter, &BackgroundWorkerList) { RegisteredBgWorker *rw; rw = slist_container(RegisteredBgWorker, rw_lnode, iter.cur); if (rw->rw_pid == 0) continue; /* ignore connected workers */ if (rw->rw_backend != NULL) continue; ereport(DEBUG4, (errmsg_internal("sending signal %d to process %d", signal, (int) rw->rw_pid))); signal_child(rw->rw_pid, signal); signaled = true; } return signaled; }
static void sigusr1_handler | ( | SIGNAL_ARGS | ) | [static] |
Definition at line 4617 of file postmaster.c.
References Assert, BgWriterPID, BlockSig, CheckpointerPID, CheckPostmasterSignal(), CheckPromoteSignal(), ereport, errmsg(), FatalError, LOG, NoShutdown, PG_SETMASK, PgArchPID, pgstat_start(), PgStatPID, PM_HOT_STANDBY, PM_RECOVERY, PM_STARTUP, PM_WAIT_BACKENDS, PM_WAIT_BACKUP, PM_WAIT_READONLY, PMSIGNAL_ADVANCE_STATE_MACHINE, PMSIGNAL_BEGIN_HOT_STANDBY, PMSIGNAL_RECOVERY_STARTED, PMSIGNAL_ROTATE_LOGFILE, PMSIGNAL_START_AUTOVAC_LAUNCHER, PMSIGNAL_START_AUTOVAC_WORKER, PMSIGNAL_START_WALRECEIVER, PMSIGNAL_WAKEN_ARCHIVER, pmState, PostmasterStateMachine(), Shutdown, signal_child(), SIGUSR1, SIGUSR2, start_autovac_launcher, StartAutovacuumWorker(), StartBackgroundWriter, StartCheckpointer, StartOneBackgroundWorker(), StartupPID, StartWalReceiver, SysLoggerPID, UnBlockSig, and WalReceiverPID.
Referenced by PostmasterMain().
{ int save_errno = errno; PG_SETMASK(&BlockSig); /* * RECOVERY_STARTED and BEGIN_HOT_STANDBY signals are ignored in * unexpected states. If the startup process quickly starts up, completes * recovery, exits, we might process the death of the startup process * first. We don't want to go back to recovery in that case. */ if (CheckPostmasterSignal(PMSIGNAL_RECOVERY_STARTED) && pmState == PM_STARTUP && Shutdown == NoShutdown) { /* WAL redo has started. We're out of reinitialization. */ FatalError = false; /* * Crank up the background tasks. It doesn't matter if this fails, * we'll just try again later. */ Assert(CheckpointerPID == 0); CheckpointerPID = StartCheckpointer(); Assert(BgWriterPID == 0); BgWriterPID = StartBackgroundWriter(); pmState = PM_RECOVERY; } if (CheckPostmasterSignal(PMSIGNAL_BEGIN_HOT_STANDBY) && pmState == PM_RECOVERY && Shutdown == NoShutdown) { /* * Likewise, start other special children as needed. */ Assert(PgStatPID == 0); PgStatPID = pgstat_start(); ereport(LOG, (errmsg("database system is ready to accept read only connections"))); pmState = PM_HOT_STANDBY; /* Some workers may be scheduled to start now */ StartOneBackgroundWorker(); } if (CheckPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER) && PgArchPID != 0) { /* * Send SIGUSR1 to archiver process, to wake it up and begin archiving * next transaction log file. */ signal_child(PgArchPID, SIGUSR1); } if (CheckPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE) && SysLoggerPID != 0) { /* Tell syslogger to rotate logfile */ signal_child(SysLoggerPID, SIGUSR1); } if (CheckPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER) && Shutdown == NoShutdown) { /* * Start one iteration of the autovacuum daemon, even if autovacuuming * is nominally not enabled. This is so we can have an active defense * against transaction ID wraparound. We set a flag for the main loop * to do it rather than trying to do it here --- this is because the * autovac process itself may send the signal, and we want to handle * that by launching another iteration as soon as the current one * completes. */ start_autovac_launcher = true; } if (CheckPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER) && Shutdown == NoShutdown) { /* The autovacuum launcher wants us to start a worker process. */ StartAutovacuumWorker(); } if (CheckPostmasterSignal(PMSIGNAL_START_WALRECEIVER) && WalReceiverPID == 0 && (pmState == PM_STARTUP || pmState == PM_RECOVERY || pmState == PM_HOT_STANDBY || pmState == PM_WAIT_READONLY) && Shutdown == NoShutdown) { /* Startup Process wants us to start the walreceiver process. */ WalReceiverPID = StartWalReceiver(); } if (CheckPostmasterSignal(PMSIGNAL_ADVANCE_STATE_MACHINE) && (pmState == PM_WAIT_BACKUP || pmState == PM_WAIT_BACKENDS)) { /* Advance postmaster's state machine */ PostmasterStateMachine(); } if (CheckPromoteSignal() && StartupPID != 0 && (pmState == PM_STARTUP || pmState == PM_RECOVERY || pmState == PM_HOT_STANDBY || pmState == PM_WAIT_READONLY)) { /* Tell startup process to finish recovery */ signal_child(StartupPID, SIGUSR2); } PG_SETMASK(&UnBlockSig); errno = save_errno; }
static void start_bgworker | ( | RegisteredBgWorker * | rw | ) | [static] |
Definition at line 5573 of file postmaster.c.
References BackgroundWorker::bgw_name, ClosePostmasterPorts(), do_start_bgworker(), ereport, errmsg(), fork_process(), LOG, on_exit_reset(), bkend::pid, RegisteredBgWorker::rw_backend, RegisteredBgWorker::rw_pid, and RegisteredBgWorker::rw_worker.
Referenced by StartOneBackgroundWorker().
{ pid_t worker_pid; ereport(LOG, (errmsg("starting background worker process \"%s\"", rw->rw_worker.bgw_name))); #ifdef EXEC_BACKEND switch ((worker_pid = bgworker_forkexec(rw->rw_cookie))) #else switch ((worker_pid = fork_process())) #endif { case -1: ereport(LOG, (errmsg("could not fork worker process: %m"))); return; #ifndef EXEC_BACKEND case 0: /* in postmaster child ... */ /* Close the postmaster's sockets */ ClosePostmasterPorts(false); /* Lose the postmaster's on-exit routines */ on_exit_reset(); /* Do NOT release postmaster's working memory context */ MyBgworkerEntry = &rw->rw_worker; do_start_bgworker(); break; #endif default: rw->rw_pid = worker_pid; if (rw->rw_backend) rw->rw_backend->pid = rw->rw_pid; } }
static void StartAutovacuumWorker | ( | void | ) | [static] |
Definition at line 5016 of file postmaster.c.
References AssignPostmasterChildSlot(), AutoVacPID, AutoVacWorkerFailed(), avlauncher_needs_signal, bkend::bkend_type, CAC_OK, canAcceptConnections(), bkend::cancel_key, bkend::child_slot, bkend::dead_end, dlist_push_head(), bkend::elem, ereport, errcode(), errmsg(), free, LOG, malloc, MyCancelKey, MyPMChildSlot, bkend::pid, PostmasterRandom(), ReleasePostmasterChildSlot(), and StartAutoVacWorker().
Referenced by sigusr1_handler().
{ Backend *bn; /* * If not in condition to run a process, don't try, but handle it like a * fork failure. This does not normally happen, since the signal is only * supposed to be sent by autovacuum launcher when it's OK to do it, but * we have to check to avoid race-condition problems during DB state * changes. */ if (canAcceptConnections() == CAC_OK) { bn = (Backend *) malloc(sizeof(Backend)); if (bn) { /* * Compute the cancel key that will be assigned to this session. * We probably don't need cancel keys for autovac workers, but * we'd better have something random in the field to prevent * unfriendly people from sending cancels to them. */ MyCancelKey = PostmasterRandom(); bn->cancel_key = MyCancelKey; /* Autovac workers are not dead_end and need a child slot */ bn->dead_end = false; bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot(); bn->pid = StartAutoVacWorker(); if (bn->pid > 0) { bn->bkend_type = BACKEND_TYPE_AUTOVAC; dlist_push_head(&BackendList, &bn->elem); #ifdef EXEC_BACKEND ShmemBackendArrayAdd(bn); #endif /* all OK */ return; } /* * fork failed, fall through to report -- actual error message was * logged by StartAutoVacWorker */ (void) ReleasePostmasterChildSlot(bn->child_slot); free(bn); } else ereport(LOG, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); } /* * Report the failure to the launcher, if it's running. (If it's not, we * might not even be connected to shared memory, so don't try to call * AutoVacWorkerFailed.) Note that we also need to signal it so that it * responds to the condition, but we don't do that here, instead waiting * for ServerLoop to do it. This way we avoid a ping-pong signalling in * quick succession between the autovac launcher and postmaster in case * things get ugly. */ if (AutoVacPID != 0) { AutoVacWorkerFailed(); avlauncher_needs_signal = true; } }
static pid_t StartChildProcess | ( | AuxProcType | type | ) | [static] |
Definition at line 4909 of file postmaster.c.
References Assert, AuxiliaryProcessMain(), BgWriterProcess, CheckpointerProcess, ClosePostmasterPorts(), ereport, errmsg(), ExitPostmaster(), fork_process(), IsUnderPostmaster, lengthof, LOG, MemoryContextDelete(), MemoryContextSwitchTo(), on_exit_reset(), PostmasterContext, snprintf(), StartupProcess, TopMemoryContext, WalReceiverProcess, and WalWriterProcess.
{ pid_t pid; char *av[10]; int ac = 0; char typebuf[32]; /* * Set up command-line arguments for subprocess */ av[ac++] = "postgres"; #ifdef EXEC_BACKEND av[ac++] = "--forkboot"; av[ac++] = NULL; /* filled in by postmaster_forkexec */ #endif snprintf(typebuf, sizeof(typebuf), "-x%d", type); av[ac++] = typebuf; av[ac] = NULL; Assert(ac < lengthof(av)); #ifdef EXEC_BACKEND pid = postmaster_forkexec(ac, av); #else /* !EXEC_BACKEND */ pid = fork_process(); if (pid == 0) /* child */ { IsUnderPostmaster = true; /* we are a postmaster subprocess now */ /* Close the postmaster's sockets */ ClosePostmasterPorts(false); /* Lose the postmaster's on-exit routines and port connections */ on_exit_reset(); /* Release postmaster's working memory context */ MemoryContextSwitchTo(TopMemoryContext); MemoryContextDelete(PostmasterContext); PostmasterContext = NULL; AuxiliaryProcessMain(ac, av); ExitPostmaster(0); } #endif /* EXEC_BACKEND */ if (pid < 0) { /* in parent, fork failed */ 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; } /* * fork failure is fatal during startup, but there's no need to choke * immediately if starting other child types fails. */ if (type == StartupProcess) ExitPostmaster(1); return 0; } /* * in parent, successful fork */ return pid; }
static void StartOneBackgroundWorker | ( | void | ) | [static] |
Definition at line 5708 of file postmaster.c.
References assign_backendlist_entry(), AssignPostmasterChildSlot(), BackgroundWorker::bgw_flags, BGW_NEVER_RESTART, BackgroundWorker::bgw_restart_time, BackgroundWorker::bgw_start_time, BGWORKER_BACKEND_DATABASE_CONNECTION, bgworker_should_start_now(), slist_iter::cur, dlist_push_head(), bkend::elem, FatalError, GetCurrentTimestamp(), HaveCrashedWorker, MyPMChildSlot, now(), RegisteredBgWorker::rw_backend, RegisteredBgWorker::rw_child_slot, RegisteredBgWorker::rw_crashed_at, RegisteredBgWorker::rw_pid, RegisteredBgWorker::rw_worker, slist_container, slist_foreach, start_bgworker(), StartWorkerNeeded, and TimestampDifferenceExceeds().
Referenced by PostmasterMain(), reaper(), ServerLoop(), and sigusr1_handler().
{ slist_iter iter; TimestampTz now = 0; if (FatalError) { StartWorkerNeeded = false; HaveCrashedWorker = false; return; /* not yet */ } HaveCrashedWorker = false; slist_foreach(iter, &BackgroundWorkerList) { RegisteredBgWorker *rw; rw = slist_container(RegisteredBgWorker, rw_lnode, iter.cur); /* already running? */ if (rw->rw_pid != 0) continue; /* * If this worker has crashed previously, maybe it needs to be * restarted (unless on registration it specified it doesn't want to * be restarted at all). Check how long ago did a crash last happen. * If the last crash is too recent, don't start it right away; let it * be restarted once enough time has passed. */ if (rw->rw_crashed_at != 0) { if (rw->rw_worker.bgw_restart_time == BGW_NEVER_RESTART) continue; if (now == 0) now = GetCurrentTimestamp(); if (!TimestampDifferenceExceeds(rw->rw_crashed_at, now, rw->rw_worker.bgw_restart_time * 1000)) { HaveCrashedWorker = true; continue; } } if (bgworker_should_start_now(rw->rw_worker.bgw_start_time)) { /* reset crash time before calling assign_backendlist_entry */ rw->rw_crashed_at = 0; /* * If necessary, allocate and assign the Backend element. Note we * must do this before forking, so that we can handle out of * memory properly. * * If not connected, we don't need a Backend element, but we still * need a PMChildSlot. */ if (rw->rw_worker.bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION) { if (!assign_backendlist_entry(rw)) return; } else rw->rw_child_slot = MyPMChildSlot = AssignPostmasterChildSlot(); start_bgworker(rw); /* sets rw->rw_pid */ if (rw->rw_backend) { dlist_push_head(&BackendList, &rw->rw_backend->elem); #ifdef EXEC_BACKEND ShmemBackendArrayAdd(rw->rw_backend); #endif } /* * Have ServerLoop call us again. Note that there might not * actually *be* another runnable worker, but we don't care all * that much; we will find out the next time we run. */ StartWorkerNeeded = true; return; } } /* no runnable worker found */ StartWorkerNeeded = false; }
static void startup_die | ( | SIGNAL_ARGS | ) | [static] |
Definition at line 4743 of file postmaster.c.
References proc_exit().
Referenced by BackendInitialize().
{ proc_exit(1); }
static void StartupPacketTimeoutHandler | ( | void | ) | [static] |
Definition at line 4767 of file postmaster.c.
References proc_exit().
Referenced by BackendInitialize().
{ proc_exit(1); }
static void unlink_external_pid_file | ( | int | status, | |
Datum | arg | |||
) | [static] |
Definition at line 1259 of file postmaster.c.
References external_pid_file, and unlink().
Referenced by PostmasterMain().
{ if (external_pid_file) unlink(external_pid_file); }
int AuthenticationTimeout = 60 |
Definition at line 249 of file postmaster.c.
Referenced by BackendInitialize(), and PerformAuthentication().
pid_t AutoVacPID = 0 [static] |
Definition at line 267 of file postmaster.c.
Referenced by HandleChildCrash(), pmdie(), PostmasterStateMachine(), reaper(), ServerLoop(), SIGHUP_handler(), StartAutoVacLauncher(), and StartAutovacuumWorker().
volatile bool avlauncher_needs_signal = false [static] |
Definition at line 357 of file postmaster.c.
Referenced by ServerLoop(), and StartAutovacuumWorker().
dlist_head BackendList = DLIST_STATIC_INIT(BackendList) [static] |
Definition at line 175 of file postmaster.c.
slist_head BackgroundWorkerList = SLIST_STATIC_INIT(BackgroundWorkerList) [static] |
Definition at line 202 of file postmaster.c.
pid_t BgWriterPID = 0 [static] |
Definition at line 263 of file postmaster.c.
Referenced by HandleChildCrash(), pmdie(), PostmasterStateMachine(), reaper(), ServerLoop(), SIGHUP_handler(), and sigusr1_handler().
char* bonjour_name |
Definition at line 256 of file postmaster.c.
Referenced by PostmasterMain().
pid_t CheckpointerPID = 0 [static] |
Definition at line 264 of file postmaster.c.
Referenced by HandleChildCrash(), pmdie(), PostmasterStateMachine(), reaper(), ServerLoop(), SIGHUP_handler(), and sigusr1_handler().
bool ClientAuthInProgress = false |
Definition at line 348 of file postmaster.c.
Referenced by BackendInitialize(), errstart(), PerformAuthentication(), pg_re_throw(), ProcessInterrupts(), and quickdie().
bool Db_user_namespace = false |
Definition at line 253 of file postmaster.c.
Referenced by ClientAuthentication(), parse_hba_line(), and ProcessStartupPacket().
bool enable_bonjour = false |
Definition at line 255 of file postmaster.c.
Referenced by PostmasterMain().
Definition at line 246 of file postmaster.c.
Referenced by parse_hba_line(), PostmasterMain(), and ProcessStartupPacket().
char ExtraOptions[MAXPGPATH] [static] |
Definition at line 233 of file postmaster.c.
Referenced by BackendRun(), and PostmasterMain().
bool FatalError = false [static] |
Definition at line 279 of file postmaster.c.
Referenced by canAcceptConnections(), HandleChildCrash(), PostmasterStateMachine(), reaper(), sigusr1_handler(), and StartOneBackgroundWorker().
volatile bool HaveCrashedWorker = false [static] |
Definition at line 361 of file postmaster.c.
Referenced by DetermineSleepTime(), reaper(), ServerLoop(), and StartOneBackgroundWorker().
char* ListenAddresses |
Definition at line 213 of file postmaster.c.
Referenced by PostmasterMain().
pgsocket ListenSocket[MAXLISTEN] [static] |
Definition at line 228 of file postmaster.c.
Referenced by ClosePostmasterPorts(), initMasks(), PostmasterMain(), and ServerLoop().
bool Log_connections = false |
Definition at line 252 of file postmaster.c.
Referenced by BackendInitialize(), and PerformAuthentication().
Definition at line 251 of file postmaster.c.
Referenced by BackendInitialize().
BackgroundWorker* MyBgworkerEntry = NULL |
Definition at line 204 of file postmaster.c.
Referenced by worker_spi_main().
char* output_config_variable = NULL |
Definition at line 259 of file postmaster.c.
Referenced by PostmasterMain().
pid_t PgArchPID = 0 [static] |
Definition at line 268 of file postmaster.c.
Referenced by HandleChildCrash(), pmdie(), PostmasterStateMachine(), reaper(), ServerLoop(), SIGHUP_handler(), and sigusr1_handler().
pid_t PgStatPID = 0 [static] |
Definition at line 269 of file postmaster.c.
Referenced by HandleChildCrash(), pmdie(), PostmasterStateMachine(), reaper(), ServerLoop(), SIGHUP_handler(), and sigusr1_handler().
Definition at line 344 of file postmaster.c.
Referenced by bgworker_should_start_now(), canAcceptConnections(), HandleChildCrash(), pmdie(), PostmasterMain(), PostmasterStateMachine(), reaper(), ServerLoop(), and sigusr1_handler().
int postmaster_alive_fds[2] = {-1, -1} |
Definition at line 547 of file postmaster.c.
Referenced by PostmasterIsAlive(), and WaitLatchOrSocket().
int PostPortNumber |
Definition at line 209 of file postmaster.c.
Referenced by CreateLockFile(), PostmasterMain(), and PostmasterStateMachine().
int PreAuthDelay = 0 |
Definition at line 248 of file postmaster.c.
Referenced by BackendInitialize().
unsigned int random_seed = 0 [static] |
Definition at line 368 of file postmaster.c.
Referenced by BackendRun(), and PostmasterRandom().
struct timeval random_start_time [static] |
Definition at line 369 of file postmaster.c.
Referenced by BackendRun(), PostmasterMain(), and PostmasterRandom().
bool ReachedNormalRunning = false [static] |
Definition at line 346 of file postmaster.c.
Referenced by PostmasterStateMachine(), and reaper().
bool RecoveryError = false [static] |
Definition at line 280 of file postmaster.c.
Referenced by PostmasterStateMachine(), and reaper().
bool redirection_done = false |
Definition at line 351 of file postmaster.c.
Referenced by SysLogger_Start(), and SysLoggerMain().
Definition at line 242 of file postmaster.c.
Referenced by PostmasterMain().
int ReservedBackends |
Definition at line 224 of file postmaster.c.
Referenced by InitPostgres(), and PostmasterMain().
bool restart_after_crash = true |
Definition at line 257 of file postmaster.c.
Referenced by PostmasterStateMachine().
int SendStop = false [static] |
Definition at line 243 of file postmaster.c.
Referenced by HandleChildCrash(), and PostmasterMain().
int Shutdown = NoShutdown [static] |
Definition at line 277 of file postmaster.c.
Referenced by canAcceptConnections(), DetermineSleepTime(), pmdie(), PostmasterStateMachine(), reaper(), SIGHUP_handler(), and sigusr1_handler().
volatile sig_atomic_t start_autovac_launcher = false [static] |
Definition at line 354 of file postmaster.c.
Referenced by ServerLoop(), and sigusr1_handler().
pid_t StartupPID = 0 [static] |
Definition at line 262 of file postmaster.c.
Referenced by HandleChildCrash(), pmdie(), PostmasterMain(), PostmasterStateMachine(), reaper(), SIGHUP_handler(), and sigusr1_handler().
volatile bool StartWorkerNeeded = true [static] |
Definition at line 360 of file postmaster.c.
Referenced by DetermineSleepTime(), ServerLoop(), and StartOneBackgroundWorker().
pid_t SysLoggerPID = 0 [static] |
Definition at line 270 of file postmaster.c.
Referenced by PostmasterMain(), reaper(), ServerLoop(), SIGHUP_handler(), and sigusr1_handler().
char* Unix_socket_directories |
Definition at line 211 of file postmaster.c.
Referenced by PostmasterMain().
pid_t WalReceiverPID = 0 [static] |
Definition at line 266 of file postmaster.c.
Referenced by HandleChildCrash(), pmdie(), PostmasterStateMachine(), reaper(), SIGHUP_handler(), and sigusr1_handler().
pid_t WalWriterPID = 0 [static] |
Definition at line 265 of file postmaster.c.
Referenced by HandleChildCrash(), pmdie(), PostmasterStateMachine(), reaper(), ServerLoop(), and SIGHUP_handler().