diff options
Diffstat (limited to 'src/backend/postmaster/pgarch.c')
-rw-r--r-- | src/backend/postmaster/pgarch.c | 91 |
1 files changed, 75 insertions, 16 deletions
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index 6cb32fcb601..e181950c0fe 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -19,7 +19,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/postmaster/pgarch.c,v 1.37 2008/01/01 19:45:51 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/pgarch.c,v 1.38 2008/01/11 00:54:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -77,12 +77,15 @@ * ---------- */ static time_t last_pgarch_start_time; +static time_t last_sigterm_time = 0; /* * Flags set by interrupt handlers for later service in the main loop. */ static volatile sig_atomic_t got_SIGHUP = false; +static volatile sig_atomic_t got_SIGTERM = false; static volatile sig_atomic_t wakened = false; +static volatile sig_atomic_t ready_to_stop = false; /* ---------- * Local function forward declarations @@ -95,7 +98,9 @@ static pid_t pgarch_forkexec(void); NON_EXEC_STATIC void PgArchiverMain(int argc, char *argv[]); static void pgarch_exit(SIGNAL_ARGS); static void ArchSigHupHandler(SIGNAL_ARGS); +static void ArchSigTermHandler(SIGNAL_ARGS); static void pgarch_waken(SIGNAL_ARGS); +static void pgarch_waken_stop(SIGNAL_ARGS); static void pgarch_MainLoop(void); static void pgarch_ArchiverCopyLoop(void); static bool pgarch_archiveXlog(char *xlog); @@ -236,16 +241,16 @@ PgArchiverMain(int argc, char *argv[]) /* * Ignore all signals usually bound to some action in the postmaster, - * except for SIGHUP, SIGUSR1 and SIGQUIT. + * except for SIGHUP, SIGTERM, SIGUSR1, SIGUSR2, and SIGQUIT. */ pqsignal(SIGHUP, ArchSigHupHandler); pqsignal(SIGINT, SIG_IGN); - pqsignal(SIGTERM, SIG_IGN); + pqsignal(SIGTERM, ArchSigTermHandler); pqsignal(SIGQUIT, pgarch_exit); pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGUSR1, pgarch_waken); - pqsignal(SIGUSR2, SIG_IGN); + pqsignal(SIGUSR2, pgarch_waken_stop); pqsignal(SIGCHLD, SIG_DFL); pqsignal(SIGTTIN, SIG_DFL); pqsignal(SIGTTOU, SIG_DFL); @@ -267,28 +272,47 @@ PgArchiverMain(int argc, char *argv[]) static void pgarch_exit(SIGNAL_ARGS) { - /* - * For now, we just nail the doors shut and get out of town. It might - * seem cleaner to finish up any pending archive copies, but there's a - * nontrivial risk that init will kill us partway through. - */ - exit(0); + /* SIGQUIT means curl up and die ... */ + exit(1); } -/* SIGHUP: set flag to re-read config file at next convenient time */ +/* SIGHUP signal handler for archiver process */ static void ArchSigHupHandler(SIGNAL_ARGS) { + /* set flag to re-read config file at next convenient time */ got_SIGHUP = true; } +/* SIGTERM signal handler for archiver process */ +static void +ArchSigTermHandler(SIGNAL_ARGS) +{ + /* + * The postmaster never sends us SIGTERM, so we assume that this means + * that init is trying to shut down the whole system. If we hang around + * too long we'll get SIGKILL'd. Set flag to prevent starting any more + * archive commands. + */ + got_SIGTERM = true; +} + /* SIGUSR1 signal handler for archiver process */ static void pgarch_waken(SIGNAL_ARGS) { + /* set flag that there is work to be done */ wakened = true; } +/* SIGUSR2 signal handler for archiver process */ +static void +pgarch_waken_stop(SIGNAL_ARGS) +{ + /* set flag to do a final cycle and shut down afterwards */ + ready_to_stop = true; +} + /* * pgarch_MainLoop * @@ -298,6 +322,7 @@ static void pgarch_MainLoop(void) { time_t last_copy_time = 0; + bool time_to_stop; /* * We run the copy loop immediately upon entry, in case there are @@ -309,6 +334,9 @@ pgarch_MainLoop(void) do { + /* When we get SIGUSR2, we do one more archive cycle, then exit */ + time_to_stop = ready_to_stop; + /* Check for config update */ if (got_SIGHUP) { @@ -316,8 +344,26 @@ pgarch_MainLoop(void) ProcessConfigFile(PGC_SIGHUP); } + /* + * If we've gotten SIGTERM, we normally just sit and do nothing until + * SIGUSR2 arrives. However, that means a random SIGTERM would + * disable archiving indefinitely, which doesn't seem like a good + * idea. If more than 60 seconds pass since SIGTERM, exit anyway, + * so that the postmaster can start a new archiver if needed. + */ + if (got_SIGTERM) + { + time_t curtime = time(NULL); + + if (last_sigterm_time == 0) + last_sigterm_time = curtime; + else if ((unsigned int) (curtime - last_sigterm_time) >= + (unsigned int) 60) + break; + } + /* Do what we're here for */ - if (wakened) + if (wakened || time_to_stop) { wakened = false; pgarch_ArchiverCopyLoop(); @@ -334,7 +380,8 @@ pgarch_MainLoop(void) * sleep into 1-second increments, and check for interrupts after each * nap. */ - while (!(wakened || got_SIGHUP)) + while (!(wakened || ready_to_stop || got_SIGHUP || + !PostmasterIsAlive(true))) { time_t curtime; @@ -344,7 +391,13 @@ pgarch_MainLoop(void) (unsigned int) PGARCH_AUTOWAKE_INTERVAL) wakened = true; } - } while (PostmasterIsAlive(true)); + + /* + * The archiver quits either when the postmaster dies (not expected) + * or after completing one more archiving cycle after receiving + * SIGUSR2. + */ + } while (PostmasterIsAlive(true) && !time_to_stop); } /* @@ -377,8 +430,14 @@ pgarch_ArchiverCopyLoop(void) for (;;) { - /* Abandon processing if we notice our postmaster has died */ - if (!PostmasterIsAlive(true)) + /* + * Do not initiate any more archive commands after receiving + * SIGTERM, nor after the postmaster has died unexpectedly. + * The first condition is to try to keep from having init + * SIGKILL the command, and the second is to avoid conflicts + * with another archiver spawned by a newer postmaster. + */ + if (got_SIGTERM || !PostmasterIsAlive(true)) return; if (pgarch_archiveXlog(xlog)) |