aboutsummaryrefslogtreecommitdiff
path: root/src/backend/postmaster/pgarch.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2011-07-08 18:27:49 +0300
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2011-07-08 18:44:07 +0300
commit89fd72cbf26f5d2e3d86ab19c1ead73ab8fac0fe (patch)
treefa0605f7ec1ff3a798b1c22fd847185158288a8b /src/backend/postmaster/pgarch.c
parent9598afa3b0f7a7fdcf3740173346950b2bd5942c (diff)
downloadpostgresql-89fd72cbf26f5d2e3d86ab19c1ead73ab8fac0fe.tar.gz
postgresql-89fd72cbf26f5d2e3d86ab19c1ead73ab8fac0fe.zip
Introduce a pipe between postmaster and each backend, which can be used to
detect postmaster death. Postmaster keeps the write-end of the pipe open, so when it dies, children get EOF in the read-end. That can conveniently be waited for in select(), which allows eliminating some of the polling loops that check for postmaster death. This patch doesn't yet change all the loops to use the new mechanism, expect a follow-on patch to do that. This changes the interface to WaitLatch, so that it takes as argument a bitmask of events that it waits for. Possible events are latch set, timeout, postmaster death, and socket becoming readable or writeable. The pipe method behaves slightly differently from the kill() method previously used in PostmasterIsAlive() in the case that postmaster has died, but its parent has not yet read its exit code with waitpid(). The pipe returns EOF as soon as the process dies, but kill() continues to return true until waitpid() has been called (IOW while the process is a zombie). Because of that, change PostmasterIsAlive() to use the pipe too, otherwise WaitLatch() would return immediately with WL_POSTMASTER_DEATH, while PostmasterIsAlive() would claim it's still alive. That could easily lead to busy-waiting while postmaster is in zombie state. Peter Geoghegan with further changes by me, reviewed by Fujii Masao and Florian Pflug.
Diffstat (limited to 'src/backend/postmaster/pgarch.c')
-rw-r--r--src/backend/postmaster/pgarch.c61
1 files changed, 43 insertions, 18 deletions
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index b40375aaaa5..2070fbb375b 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -40,6 +40,7 @@
#include "postmaster/postmaster.h"
#include "storage/fd.h"
#include "storage/ipc.h"
+#include "storage/latch.h"
#include "storage/pg_shmem.h"
#include "storage/pmsignal.h"
#include "utils/guc.h"
@@ -87,6 +88,11 @@ static volatile sig_atomic_t got_SIGTERM = false;
static volatile sig_atomic_t wakened = false;
static volatile sig_atomic_t ready_to_stop = false;
+/*
+ * Latch used by signal handlers to wake up the sleep in the main loop.
+ */
+static Latch mainloop_latch;
+
/* ----------
* Local function forward declarations
* ----------
@@ -228,6 +234,8 @@ PgArchiverMain(int argc, char *argv[])
MyProcPid = getpid(); /* reset MyProcPid */
+ InitLatch(&mainloop_latch); /* initialize latch used in main loop */
+
MyStartTime = time(NULL); /* record Start Time for logging */
/*
@@ -282,6 +290,8 @@ ArchSigHupHandler(SIGNAL_ARGS)
{
/* set flag to re-read config file at next convenient time */
got_SIGHUP = true;
+ /* let the waiting loop iterate */
+ SetLatch(&mainloop_latch);
}
/* SIGTERM signal handler for archiver process */
@@ -295,6 +305,8 @@ ArchSigTermHandler(SIGNAL_ARGS)
* archive commands.
*/
got_SIGTERM = true;
+ /* let the waiting loop iterate */
+ SetLatch(&mainloop_latch);
}
/* SIGUSR1 signal handler for archiver process */
@@ -303,6 +315,8 @@ pgarch_waken(SIGNAL_ARGS)
{
/* set flag that there is work to be done */
wakened = true;
+ /* let the waiting loop iterate */
+ SetLatch(&mainloop_latch);
}
/* SIGUSR2 signal handler for archiver process */
@@ -311,6 +325,8 @@ pgarch_waken_stop(SIGNAL_ARGS)
{
/* set flag to do a final cycle and shut down afterwards */
ready_to_stop = true;
+ /* let the waiting loop iterate */
+ SetLatch(&mainloop_latch);
}
/*
@@ -321,7 +337,7 @@ pgarch_waken_stop(SIGNAL_ARGS)
static void
pgarch_MainLoop(void)
{
- time_t last_copy_time = 0;
+ pg_time_t last_copy_time = 0;
bool time_to_stop;
/*
@@ -332,8 +348,15 @@ pgarch_MainLoop(void)
*/
wakened = true;
+ /*
+ * There shouldn't be anything for the archiver to do except to wait
+ * for a signal ... however, the archiver exists to protect our data,
+ * so she wakes up occasionally to allow herself to be proactive.
+ */
do
{
+ ResetLatch(&mainloop_latch);
+
/* When we get SIGUSR2, we do one more archive cycle, then exit */
time_to_stop = ready_to_stop;
@@ -371,24 +394,26 @@ pgarch_MainLoop(void)
}
/*
- * There shouldn't be anything for the archiver to do except to wait
- * for a signal ... however, the archiver exists to protect our data,
- * so she wakes up occasionally to allow herself to be proactive.
- *
- * On some platforms, signals won't interrupt the sleep. To ensure we
- * respond reasonably promptly when someone signals us, break down the
- * sleep into 1-second increments, and check for interrupts after each
- * nap.
+ * Sleep until a signal is received, or until a poll is forced by
+ * PGARCH_AUTOWAKE_INTERVAL having passed since last_copy_time, or
+ * until postmaster dies.
*/
- while (!(wakened || ready_to_stop || got_SIGHUP ||
- !PostmasterIsAlive(true)))
+ if (!time_to_stop) /* Don't wait during last iteration */
{
- time_t curtime;
+ pg_time_t curtime = (pg_time_t) time(NULL);
+ int timeout;
- pg_usleep(1000000L);
- curtime = time(NULL);
- if ((unsigned int) (curtime - last_copy_time) >=
- (unsigned int) PGARCH_AUTOWAKE_INTERVAL)
+ timeout = PGARCH_AUTOWAKE_INTERVAL - (curtime - last_copy_time);
+ if (timeout > 0)
+ {
+ int rc;
+ rc = WaitLatch(&mainloop_latch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ timeout * 1000000L);
+ if (rc & WL_TIMEOUT)
+ wakened = true;
+ }
+ else
wakened = true;
}
@@ -397,7 +422,7 @@ pgarch_MainLoop(void)
* or after completing one more archiving cycle after receiving
* SIGUSR2.
*/
- } while (PostmasterIsAlive(true) && !time_to_stop);
+ } while (PostmasterIsAlive() && !time_to_stop);
}
/*
@@ -429,7 +454,7 @@ pgarch_ArchiverCopyLoop(void)
* command, and the second is to avoid conflicts with another
* archiver spawned by a newer postmaster.
*/
- if (got_SIGTERM || !PostmasterIsAlive(true))
+ if (got_SIGTERM || !PostmasterIsAlive())
return;
/*