diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0944aa4162..7ac17779c8 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -41,6 +41,7 @@ #include "miscadmin.h" #include "pgstat.h" #include "postmaster/bgwriter.h" +#include "postmaster/startup.h" #include "replication/walreceiver.h" #include "replication/walsender.h" #include "storage/bufmgr.h" @@ -584,19 +585,6 @@ typedef struct xl_restore_point char rp_name[MAXFNAMELEN]; } xl_restore_point; -/* - * Flags set by interrupt handlers for later service in the redo loop. - */ -static volatile sig_atomic_t got_SIGHUP = false; -static volatile sig_atomic_t shutdown_requested = false; -static volatile sig_atomic_t promote_triggered = false; - -/* - * Flag set when executing a restore command, to tell SIGTERM signal handler - * that it's safe to just proc_exit. - */ -static volatile sig_atomic_t in_restore_command = false; - static void XLogArchiveNotify(const char *xlog); static void XLogArchiveNotifySeg(uint32 log, uint32 seg); @@ -3068,21 +3056,16 @@ RestoreArchivedFile(char *path, const char *xlogfname, xlogRestoreCmd))); /* - * Set in_restore_command to tell the signal handler that we should exit - * right away on SIGTERM. We know that we're at a safe point to do that. - * Check if we had already received the signal, so that we don't miss a - * shutdown request received just before this. + * Check signals before restore command and reset afterwards. */ - in_restore_command = true; - if (shutdown_requested) - proc_exit(1); + PreRestoreCommand(); /* * Copy xlog from archival storage to XLOGDIR */ rc = system(xlogRestoreCmd); - in_restore_command = false; + PostRestoreCommand(); if (rc == 0) { @@ -9946,177 +9929,6 @@ CancelBackup(void) } } -/* ------------------------------------------------------ - * Startup Process main entry point and signal handlers - * ------------------------------------------------------ - */ - -/* - * startupproc_quickdie() occurs when signalled SIGQUIT by the postmaster. - * - * Some backend has bought the farm, - * so we need to stop what we're doing and exit. - */ -static void -startupproc_quickdie(SIGNAL_ARGS) -{ - 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(2) not exit(0). This is to force the postmaster into a - * system reset cycle if some idiot DBA sends a manual SIGQUIT to a random - * backend. This is necessary precisely because we don't clean up our - * shared memory state. (The "dead man switch" mechanism in pmsignal.c - * should ensure the postmaster sees this as a crash, too, but no harm in - * being doubly sure.) - */ - exit(2); -} - - -/* SIGUSR1: let latch facility handle the signal */ -static void -StartupProcSigUsr1Handler(SIGNAL_ARGS) -{ - int save_errno = errno; - - latch_sigusr1_handler(); - - errno = save_errno; -} - -/* SIGUSR2: set flag to finish recovery */ -static void -StartupProcTriggerHandler(SIGNAL_ARGS) -{ - int save_errno = errno; - - promote_triggered = true; - WakeupRecovery(); - - errno = save_errno; -} - -/* SIGHUP: set flag to re-read config file at next convenient time */ -static void -StartupProcSigHupHandler(SIGNAL_ARGS) -{ - int save_errno = errno; - - got_SIGHUP = true; - WakeupRecovery(); - - errno = save_errno; -} - -/* SIGTERM: set flag to abort redo and exit */ -static void -StartupProcShutdownHandler(SIGNAL_ARGS) -{ - int save_errno = errno; - - if (in_restore_command) - proc_exit(1); - else - shutdown_requested = true; - WakeupRecovery(); - - errno = save_errno; -} - -/* Handle SIGHUP and SIGTERM signals of startup process */ -void -HandleStartupProcInterrupts(void) -{ - /* - * Check if we were requested to re-read config file. - */ - if (got_SIGHUP) - { - got_SIGHUP = false; - ProcessConfigFile(PGC_SIGHUP); - } - - /* - * Check if we were requested to exit without finishing recovery. - */ - if (shutdown_requested) - proc_exit(1); - - /* - * Emergency bailout if postmaster has died. This is to avoid the - * necessity for manual cleanup of all postmaster children. - */ - if (IsUnderPostmaster && !PostmasterIsAlive()) - exit(1); -} - -/* Main entry point for startup process */ -void -StartupProcessMain(void) -{ - /* - * 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 - - /* - * Properly accept or ignore signals the postmaster might send us. - * - * Note: ideally we'd not enable handle_standby_sig_alarm unless actually - * doing hot standby, but we don't know that yet. Rely on it to not do - * anything if it shouldn't. - */ - pqsignal(SIGHUP, StartupProcSigHupHandler); /* reload config file */ - pqsignal(SIGINT, SIG_IGN); /* ignore query cancel */ - pqsignal(SIGTERM, StartupProcShutdownHandler); /* request shutdown */ - pqsignal(SIGQUIT, startupproc_quickdie); /* hard crash time */ - if (EnableHotStandby) - pqsignal(SIGALRM, handle_standby_sig_alarm); /* ignored unless - * InHotStandby */ - else - pqsignal(SIGALRM, SIG_IGN); - pqsignal(SIGPIPE, SIG_IGN); - pqsignal(SIGUSR1, StartupProcSigUsr1Handler); - pqsignal(SIGUSR2, StartupProcTriggerHandler); - - /* - * Reset some signals that are accepted by postmaster but not here - */ - pqsignal(SIGCHLD, SIG_DFL); - pqsignal(SIGTTIN, SIG_DFL); - pqsignal(SIGTTOU, SIG_DFL); - pqsignal(SIGCONT, SIG_DFL); - pqsignal(SIGWINCH, SIG_DFL); - - /* - * Unblock signals (they were blocked when the postmaster forked us) - */ - PG_SETMASK(&UnBlockSig); - - StartupXLOG(); - - /* - * Exit normally. Exit code 0 tells postmaster that we completed recovery - * successfully. - */ - proc_exit(0); -} - /* * Read the XLOG page containing RecPtr into readBuf (if not read already). * Returns true if the page is read successfully. @@ -10564,12 +10376,12 @@ CheckForStandbyTrigger(void) if (triggered) return true; - if (promote_triggered) + if (IsPromoteTriggered()) { ereport(LOG, (errmsg("received promote request"))); ShutdownWalRcv(); - promote_triggered = false; + ResetPromoteTriggered(); triggered = true; return true; } diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index f9b839c3da..6bf2421f65 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -29,6 +29,7 @@ #include "miscadmin.h" #include "nodes/makefuncs.h" #include "postmaster/bgwriter.h" +#include "postmaster/startup.h" #include "postmaster/walwriter.h" #include "replication/walreceiver.h" #include "storage/bufmgr.h" diff --git a/src/backend/postmaster/Makefile b/src/backend/postmaster/Makefile index e7414d20de..3056b09f0d 100644 --- a/src/backend/postmaster/Makefile +++ b/src/backend/postmaster/Makefile @@ -13,6 +13,6 @@ top_builddir = ../../.. include $(top_builddir)/src/Makefile.global OBJS = autovacuum.o bgwriter.o fork_process.o pgarch.o pgstat.o postmaster.o \ - syslogger.o walwriter.o checkpointer.o + startup.o syslogger.o walwriter.o checkpointer.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c new file mode 100644 index 0000000000..c4146845f2 --- /dev/null +++ b/src/backend/postmaster/startup.c @@ -0,0 +1,259 @@ +/*------------------------------------------------------------------------- + * + * startup.c + * + * The Startup process initialises the server and performs any recovery + * actions that have been specified. Notice that there is no "main loop" + * since the Startup process ends as soon as initialisation is complete. + * + * + * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group + * + * + * IDENTIFICATION + * src/backend/postmaster/startup.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include +#include + +#include "access/xlog.h" +#include "libpq/pqsignal.h" +#include "miscadmin.h" +#include "postmaster/startup.h" +#include "storage/ipc.h" +#include "storage/latch.h" +#include "storage/pmsignal.h" +#include "storage/proc.h" +#include "utils/guc.h" + + +/* + * Flags set by interrupt handlers for later service in the redo loop. + */ +static volatile sig_atomic_t got_SIGHUP = false; +static volatile sig_atomic_t shutdown_requested = false; +static volatile sig_atomic_t promote_triggered = false; + +/* + * Flag set when executing a restore command, to tell SIGTERM signal handler + * that it's safe to just proc_exit. + */ +static volatile sig_atomic_t in_restore_command = false; + +/* Signal handlers */ +static void startupproc_quickdie(SIGNAL_ARGS); +static void StartupProcSigUsr1Handler(SIGNAL_ARGS); +static void StartupProcTriggerHandler(SIGNAL_ARGS); +static void StartupProcSigHupHandler(SIGNAL_ARGS); + + +/* -------------------------------- + * signal handler routines + * -------------------------------- + */ + +/* + * startupproc_quickdie() occurs when signalled SIGQUIT by the postmaster. + * + * Some backend has bought the farm, + * so we need to stop what we're doing and exit. + */ +static void +startupproc_quickdie(SIGNAL_ARGS) +{ + 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(2) not exit(0). This is to force the postmaster into a + * system reset cycle if some idiot DBA sends a manual SIGQUIT to a random + * backend. This is necessary precisely because we don't clean up our + * shared memory state. (The "dead man switch" mechanism in pmsignal.c + * should ensure the postmaster sees this as a crash, too, but no harm in + * being doubly sure.) + */ + exit(2); +} + + +/* SIGUSR1: let latch facility handle the signal */ +static void +StartupProcSigUsr1Handler(SIGNAL_ARGS) +{ + int save_errno = errno; + + latch_sigusr1_handler(); + + errno = save_errno; +} + +/* SIGUSR2: set flag to finish recovery */ +static void +StartupProcTriggerHandler(SIGNAL_ARGS) +{ + int save_errno = errno; + + promote_triggered = true; + WakeupRecovery(); + + errno = save_errno; +} + +/* SIGHUP: set flag to re-read config file at next convenient time */ +static void +StartupProcSigHupHandler(SIGNAL_ARGS) +{ + int save_errno = errno; + + got_SIGHUP = true; + WakeupRecovery(); + + errno = save_errno; +} + +/* SIGTERM: set flag to abort redo and exit */ +static void +StartupProcShutdownHandler(SIGNAL_ARGS) +{ + int save_errno = errno; + + if (in_restore_command) + proc_exit(1); + else + shutdown_requested = true; + WakeupRecovery(); + + errno = save_errno; +} + +/* Handle SIGHUP and SIGTERM signals of startup process */ +void +HandleStartupProcInterrupts(void) +{ + /* + * Check if we were requested to re-read config file. + */ + if (got_SIGHUP) + { + got_SIGHUP = false; + ProcessConfigFile(PGC_SIGHUP); + } + + /* + * Check if we were requested to exit without finishing recovery. + */ + if (shutdown_requested) + proc_exit(1); + + /* + * Emergency bailout if postmaster has died. This is to avoid the + * necessity for manual cleanup of all postmaster children. + */ + if (IsUnderPostmaster && !PostmasterIsAlive()) + exit(1); +} + + +/* ---------------------------------- + * Startup Process main entry point + * ---------------------------------- + */ +void +StartupProcessMain(void) +{ + /* + * 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 + + /* + * Properly accept or ignore signals the postmaster might send us. + * + * Note: ideally we'd not enable handle_standby_sig_alarm unless actually + * doing hot standby, but we don't know that yet. Rely on it to not do + * anything if it shouldn't. + */ + pqsignal(SIGHUP, StartupProcSigHupHandler); /* reload config file */ + pqsignal(SIGINT, SIG_IGN); /* ignore query cancel */ + pqsignal(SIGTERM, StartupProcShutdownHandler); /* request shutdown */ + pqsignal(SIGQUIT, startupproc_quickdie); /* hard crash time */ + if (EnableHotStandby) + pqsignal(SIGALRM, handle_standby_sig_alarm); /* ignored unless + * InHotStandby */ + else + pqsignal(SIGALRM, SIG_IGN); + pqsignal(SIGPIPE, SIG_IGN); + pqsignal(SIGUSR1, StartupProcSigUsr1Handler); + pqsignal(SIGUSR2, StartupProcTriggerHandler); + + /* + * Reset some signals that are accepted by postmaster but not here + */ + pqsignal(SIGCHLD, SIG_DFL); + pqsignal(SIGTTIN, SIG_DFL); + pqsignal(SIGTTOU, SIG_DFL); + pqsignal(SIGCONT, SIG_DFL); + pqsignal(SIGWINCH, SIG_DFL); + + /* + * Unblock signals (they were blocked when the postmaster forked us) + */ + PG_SETMASK(&UnBlockSig); + + StartupXLOG(); + + /* + * Exit normally. Exit code 0 tells postmaster that we completed recovery + * successfully. + */ + proc_exit(0); +} + +void +PreRestoreCommand(void) +{ + /* + * Set in_restore_command to tell the signal handler that we should exit + * right away on SIGTERM. We know that we're at a safe point to do that. + * Check if we had already received the signal, so that we don't miss a + * shutdown request received just before this. + */ + in_restore_command = true; + if (shutdown_requested) + proc_exit(1); +} + +void +PostRestoreCommand(void) +{ + in_restore_command = false; +} + +bool +IsPromoteTriggered(void) +{ + return promote_triggered; +} + +void +ResetPromoteTriggered(void) +{ + promote_triggered = false; +} diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c index 29c2f806e0..5bce1c34a1 100644 --- a/src/backend/replication/walreceiverfuncs.c +++ b/src/backend/replication/walreceiverfuncs.c @@ -24,6 +24,7 @@ #include #include "access/xlog_internal.h" +#include "postmaster/startup.h" #include "replication/walreceiver.h" #include "storage/pmsignal.h" #include "storage/shmem.h" @@ -110,6 +111,7 @@ WalRcvInProgress(void) /* * Stop walreceiver (if running) and wait for it to die. + * Executed by the Startup process. */ void ShutdownWalRcv(void) diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index e4a13a18ab..6c7b021673 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -312,8 +312,6 @@ extern XLogRecPtr GetFlushRecPtr(void); extern void GetNextXidAndEpoch(TransactionId *xid, uint32 *epoch); extern TimeLineID GetRecoveryTargetTLI(void); -extern void HandleStartupProcInterrupts(void); -extern void StartupProcessMain(void); extern bool CheckPromoteSignal(void); extern void WakeupRecovery(void); diff --git a/src/include/postmaster/startup.h b/src/include/postmaster/startup.h new file mode 100644 index 0000000000..8c57adf0bb --- /dev/null +++ b/src/include/postmaster/startup.h @@ -0,0 +1,22 @@ +/*------------------------------------------------------------------------- + * + * startup.h + * Exports from postmaster/startup.c. + * + * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group + * + * src/include/postmaster/startup.h + * + *------------------------------------------------------------------------- + */ +#ifndef _STARTUP_H +#define _STARTUP_H + +extern void HandleStartupProcInterrupts(void); +extern void StartupProcessMain(void); +extern void PreRestoreCommand(void); +extern void PostRestoreCommand(void); +extern bool IsPromoteTriggered(void); +extern void ResetPromoteTriggered(void); + +#endif /* _STARTUP_H */