*** a/src/backend/access/transam/xlog.c --- b/src/backend/access/transam/xlog.c *************** *** 41,46 **** --- 41,47 ---- #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,602 **** 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); --- 585,590 ---- *************** *** 3068,3088 **** 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. */ ! in_restore_command = true; ! if (shutdown_requested) ! proc_exit(1); /* * Copy xlog from archival storage to XLOGDIR */ rc = system(xlogRestoreCmd); ! in_restore_command = false; if (rc == 0) { --- 3056,3071 ---- xlogRestoreCmd))); /* ! * Check signals before restore command and reset afterwards. */ ! PreRestoreCommand(); /* * Copy xlog from archival storage to XLOGDIR */ rc = system(xlogRestoreCmd); ! PostRestoreCommand(); if (rc == 0) { *************** *** 9931,10107 **** 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. --- 9914,9919 ---- *************** *** 10549,10560 **** CheckForStandbyTrigger(void) if (triggered) return true; ! if (promote_triggered) { ereport(LOG, (errmsg("received promote request"))); ShutdownWalRcv(); ! promote_triggered = false; triggered = true; return true; } --- 10361,10372 ---- if (triggered) return true; ! if (IsPromoteTriggered()) { ereport(LOG, (errmsg("received promote request"))); ShutdownWalRcv(); ! ResetPromoteTriggered(); triggered = true; return true; } *** a/src/backend/bootstrap/bootstrap.c --- b/src/backend/bootstrap/bootstrap.c *************** *** 29,34 **** --- 29,35 ---- #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" *** a/src/backend/postmaster/Makefile --- b/src/backend/postmaster/Makefile *************** *** 13,18 **** 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 include $(top_srcdir)/src/backend/common.mk --- 13,18 ---- include $(top_builddir)/src/Makefile.global OBJS = autovacuum.o bgwriter.o fork_process.o pgarch.o pgstat.o postmaster.o \ ! startup.o syslogger.o walwriter.o checkpointer.o include $(top_srcdir)/src/backend/common.mk *** /dev/null --- b/src/backend/postmaster/startup.c *************** *** 0 **** --- 1,261 ---- + /*------------------------------------------------------------------------- + * + * 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 "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) + { + if (promote_triggered) + return true; + else + return false; + } + + void + ResetPromoteTriggered(void) + { + promote_triggered = false; + } *** a/src/backend/replication/walreceiverfuncs.c --- b/src/backend/replication/walreceiverfuncs.c *************** *** 24,29 **** --- 24,30 ---- #include #include "access/xlog_internal.h" + #include "postmaster/startup.h" #include "replication/walreceiver.h" #include "storage/pmsignal.h" #include "storage/shmem.h" *************** *** 110,115 **** WalRcvInProgress(void) --- 111,117 ---- /* * Stop walreceiver (if running) and wait for it to die. + * Executed by the Startup process. */ void ShutdownWalRcv(void) *** a/src/include/access/xlog.h --- b/src/include/access/xlog.h *************** *** 312,319 **** 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); --- 312,317 ---- *** /dev/null --- b/src/include/postmaster/startup.h *************** *** 0 **** --- 1,26 ---- + /*------------------------------------------------------------------------- + * + * 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); + + /* in xlog.c */ + extern void WakeupRecovery(void); + extern void StartupXLOG(void); + + #endif /* _STARTUP_H */