aboutsummaryrefslogtreecommitdiff
path: root/src/backend/postmaster/pgarch.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/postmaster/pgarch.c')
-rw-r--r--src/backend/postmaster/pgarch.c239
1 files changed, 98 insertions, 141 deletions
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index edec311f12e..746c836d420 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -38,16 +38,13 @@
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "pgstat.h"
-#include "postmaster/fork_process.h"
#include "postmaster/interrupt.h"
#include "postmaster/pgarch.h"
-#include "postmaster/postmaster.h"
-#include "storage/dsm.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/latch.h"
-#include "storage/pg_shmem.h"
#include "storage/pmsignal.h"
+#include "storage/procsignal.h"
#include "utils/guc.h"
#include "utils/ps_status.h"
@@ -73,153 +70,99 @@
*/
#define NUM_ORPHAN_CLEANUP_RETRIES 3
+/* Shared memory area for archiver process */
+typedef struct PgArchData
+{
+ int pgprocno; /* pgprocno of archiver process */
+} PgArchData;
+
/* ----------
* Local data
* ----------
*/
-static time_t last_pgarch_start_time;
static time_t last_sigterm_time = 0;
+static PgArchData *PgArch = NULL;
/*
* Flags set by interrupt handlers for later service in the main loop.
*/
-static volatile sig_atomic_t wakened = false;
static volatile sig_atomic_t ready_to_stop = false;
/* ----------
* Local function forward declarations
* ----------
*/
-#ifdef EXEC_BACKEND
-static pid_t pgarch_forkexec(void);
-#endif
-
-NON_EXEC_STATIC void PgArchiverMain(int argc, char *argv[]) pg_attribute_noreturn();
-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);
static bool pgarch_readyXlog(char *xlog);
static void pgarch_archiveDone(char *xlog);
+static void pgarch_die(int code, Datum arg);
-
-/* ------------------------------------------------------------
- * Public functions called from postmaster follow
- * ------------------------------------------------------------
- */
-
-/*
- * pgarch_start
- *
- * Called from postmaster at startup or after an existing archiver
- * died. Attempt to fire up a fresh archiver process.
- *
- * Returns PID of child process, or 0 if fail.
- *
- * Note: if fail, we will be called again from the postmaster main loop.
- */
-int
-pgarch_start(void)
+/* Report shared memory space needed by PgArchShmemInit */
+Size
+PgArchShmemSize(void)
{
- time_t curtime;
- pid_t pgArchPid;
-
- /*
- * Do nothing if no archiver needed
- */
- if (!XLogArchivingActive())
- return 0;
+ Size size = 0;
- /*
- * Do nothing if too soon since last archiver start. This is a safety
- * valve to protect against continuous respawn attempts if the archiver is
- * dying immediately at launch. Note that since we will be re-called from
- * the postmaster main loop, we will get another chance later.
- */
- curtime = time(NULL);
- if ((unsigned int) (curtime - last_pgarch_start_time) <
- (unsigned int) PGARCH_RESTART_INTERVAL)
- return 0;
- last_pgarch_start_time = curtime;
+ size = add_size(size, sizeof(PgArchData));
-#ifdef EXEC_BACKEND
- switch ((pgArchPid = pgarch_forkexec()))
-#else
- switch ((pgArchPid = fork_process()))
-#endif
- {
- case -1:
- ereport(LOG,
- (errmsg("could not fork archiver: %m")));
- return 0;
-
-#ifndef EXEC_BACKEND
- case 0:
- /* in postmaster child ... */
- InitPostmasterChild();
-
- /* Close the postmaster's sockets */
- ClosePostmasterPorts(false);
+ return size;
+}
- /* Drop our connection to postmaster's shared memory, as well */
- dsm_detach_all();
- PGSharedMemoryDetach();
+/* Allocate and initialize archiver-related shared memory */
+void
+PgArchShmemInit(void)
+{
+ bool found;
- PgArchiverMain(0, NULL);
- break;
-#endif
+ PgArch = (PgArchData *)
+ ShmemInitStruct("Archiver Data", PgArchShmemSize(), &found);
- default:
- return (int) pgArchPid;
+ if (!found)
+ {
+ /* First time through, so initialize */
+ MemSet(PgArch, 0, PgArchShmemSize());
+ PgArch->pgprocno = INVALID_PGPROCNO;
}
-
- /* shouldn't get here */
- return 0;
}
-/* ------------------------------------------------------------
- * Local functions called by archiver follow
- * ------------------------------------------------------------
- */
-
-
-#ifdef EXEC_BACKEND
-
/*
- * pgarch_forkexec() -
+ * PgArchCanRestart
+ *
+ * Return true and archiver is allowed to restart if enough time has
+ * passed since it was launched last to reach PGARCH_RESTART_INTERVAL.
+ * Otherwise return false.
*
- * Format up the arglist for, then fork and exec, archive process
+ * This is a safety valve to protect against continuous respawn attempts if the
+ * archiver is dying immediately at launch. Note that since we will retry to
+ * launch the archiver from the postmaster main loop, we will get another
+ * chance later.
*/
-static pid_t
-pgarch_forkexec(void)
+bool
+PgArchCanRestart(void)
{
- char *av[10];
- int ac = 0;
+ static time_t last_pgarch_start_time = 0;
+ time_t curtime = time(NULL);
- av[ac++] = "postgres";
-
- av[ac++] = "--forkarch";
-
- av[ac++] = NULL; /* filled in by postmaster_forkexec */
-
- av[ac] = NULL;
- Assert(ac < lengthof(av));
+ /*
+ * Return false and don't restart archiver if too soon since last archiver
+ * start.
+ */
+ if ((unsigned int) (curtime - last_pgarch_start_time) <
+ (unsigned int) PGARCH_RESTART_INTERVAL)
+ return false;
- return postmaster_forkexec(ac, av);
+ last_pgarch_start_time = curtime;
+ return true;
}
-#endif /* EXEC_BACKEND */
-/*
- * PgArchiverMain
- *
- * The argc/argv parameters are valid only in EXEC_BACKEND case. However,
- * since we don't use 'em, it hardly matters...
- */
-NON_EXEC_STATIC void
-PgArchiverMain(int argc, char *argv[])
+/* Main entry point for archiver process */
+void
+PgArchiverMain(void)
{
/*
* Ignore all signals usually bound to some action in the postmaster,
@@ -231,33 +174,51 @@ PgArchiverMain(int argc, char *argv[])
/* SIGQUIT handler was already set up by InitPostmasterChild */
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
- pqsignal(SIGUSR1, pgarch_waken);
+ pqsignal(SIGUSR1, procsignal_sigusr1_handler);
pqsignal(SIGUSR2, pgarch_waken_stop);
+
/* Reset some signals that are accepted by postmaster but not here */
pqsignal(SIGCHLD, SIG_DFL);
+
+ /* Unblock signals (they were blocked when the postmaster forked us) */
PG_SETMASK(&UnBlockSig);
- MyBackendType = B_ARCHIVER;
- init_ps_display(NULL);
+ /* We shouldn't be launched unnecessarily. */
+ Assert(XLogArchivingActive());
+
+ /* Arrange to clean up at archiver exit */
+ on_shmem_exit(pgarch_die, 0);
+
+ /*
+ * Advertise our pgprocno so that backends can use our latch to wake us up
+ * while we're sleeping.
+ */
+ PgArch->pgprocno = MyProc->pgprocno;
pgarch_MainLoop();
- exit(0);
+ proc_exit(0);
}
-/* SIGUSR1 signal handler for archiver process */
-static void
-pgarch_waken(SIGNAL_ARGS)
+/*
+ * Wake up the archiver
+ */
+void
+PgArchWakeup(void)
{
- int save_errno = errno;
+ int arch_pgprocno = PgArch->pgprocno;
- /* set flag that there is work to be done */
- wakened = true;
- SetLatch(MyLatch);
-
- errno = save_errno;
+ /*
+ * We don't acquire ProcArrayLock here. It's actually fine because
+ * procLatch isn't ever freed, so we just can potentially set the wrong
+ * process' (or no process') latch. Even in that case the archiver will
+ * be relaunched shortly and will start archiving.
+ */
+ if (arch_pgprocno != INVALID_PGPROCNO)
+ SetLatch(&ProcGlobal->allProcs[arch_pgprocno].procLatch);
}
+
/* SIGUSR2 signal handler for archiver process */
static void
pgarch_waken_stop(SIGNAL_ARGS)
@@ -283,14 +244,6 @@ pgarch_MainLoop(void)
bool time_to_stop;
/*
- * We run the copy loop immediately upon entry, in case there are
- * unarchived files left over from a previous database run (or maybe the
- * archiver died unexpectedly). After that we wait for a signal or
- * timeout before doing more.
- */
- 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.
@@ -328,12 +281,8 @@ pgarch_MainLoop(void)
}
/* Do what we're here for */
- if (wakened || time_to_stop)
- {
- wakened = false;
- pgarch_ArchiverCopyLoop();
- last_copy_time = time(NULL);
- }
+ pgarch_ArchiverCopyLoop();
+ last_copy_time = time(NULL);
/*
* Sleep until a signal is received, or until a poll is forced by
@@ -354,13 +303,9 @@ pgarch_MainLoop(void)
WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
timeout * 1000L,
WAIT_EVENT_ARCHIVER_MAIN);
- if (rc & WL_TIMEOUT)
- wakened = true;
if (rc & WL_POSTMASTER_DEATH)
time_to_stop = true;
}
- else
- wakened = true;
}
/*
@@ -744,3 +689,15 @@ pgarch_archiveDone(char *xlog)
StatusFilePath(rlogdone, xlog, ".done");
(void) durable_rename(rlogready, rlogdone, WARNING);
}
+
+
+/*
+ * pgarch_die
+ *
+ * Exit-time cleanup handler
+ */
+static void
+pgarch_die(int code, Datum arg)
+{
+ PgArch->pgprocno = INVALID_PGPROCNO;
+}