#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().
1.7.1