#include "postgres.h"#include <fcntl.h>#include <signal.h>#include <time.h>#include <sys/wait.h>#include <unistd.h>#include "access/xlog.h"#include "access/xlog_internal.h"#include "libpq/pqsignal.h"#include "miscadmin.h"#include "postmaster/fork_process.h"#include "postmaster/pgarch.h"#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"#include "utils/ps_status.h"
Go to the source code of this file.
Defines | |
| #define | PGARCH_AUTOWAKE_INTERVAL 60 |
| #define | PGARCH_RESTART_INTERVAL 10 |
| #define | MIN_XFN_CHARS 16 |
| #define | MAX_XFN_CHARS 40 |
| #define | VALID_XFN_CHARS "0123456789ABCDEF.history.backup" |
| #define | NUM_ARCHIVE_RETRIES 3 |
Functions | |
| NON_EXEC_STATIC void | PgArchiverMain (int argc, char *argv[]) __attribute__((noreturn)) |
| 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) |
| static bool | pgarch_readyXlog (char *xlog) |
| static void | pgarch_archiveDone (char *xlog) |
| int | pgarch_start (void) |
Variables | |
| static time_t | last_pgarch_start_time |
| static time_t | last_sigterm_time = 0 |
| 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 |
| static Latch | mainloop_latch |
| #define MAX_XFN_CHARS 40 |
Definition at line 71 of file pgarch.c.
Referenced by pgarch_ArchiverCopyLoop(), and pgarch_readyXlog().
| #define MIN_XFN_CHARS 16 |
Definition at line 70 of file pgarch.c.
Referenced by pgarch_readyXlog().
| #define NUM_ARCHIVE_RETRIES 3 |
Definition at line 74 of file pgarch.c.
Referenced by pgarch_ArchiverCopyLoop().
| #define PGARCH_AUTOWAKE_INTERVAL 60 |
Definition at line 55 of file pgarch.c.
Referenced by pgarch_MainLoop().
| #define PGARCH_RESTART_INTERVAL 10 |
Definition at line 58 of file pgarch.c.
Referenced by pgarch_start().
| #define VALID_XFN_CHARS "0123456789ABCDEF.history.backup" |
Definition at line 72 of file pgarch.c.
Referenced by pgarch_readyXlog().
| static void ArchSigHupHandler | ( | SIGNAL_ARGS | ) | [static] |
Definition at line 292 of file pgarch.c.
References got_SIGHUP, and SetLatch().
Referenced by PgArchiverMain().
{
int save_errno = errno;
/* set flag to re-read config file at next convenient time */
got_SIGHUP = true;
SetLatch(&mainloop_latch);
errno = save_errno;
}
| static void ArchSigTermHandler | ( | SIGNAL_ARGS | ) | [static] |
Definition at line 305 of file pgarch.c.
References got_SIGTERM, and SetLatch().
Referenced by PgArchiverMain().
{
int save_errno = errno;
/*
* 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;
SetLatch(&mainloop_latch);
errno = save_errno;
}
| static void pgarch_archiveDone | ( | char * | xlog | ) | [static] |
Definition at line 746 of file pgarch.c.
References ereport, errcode_for_file_access(), errmsg(), StatusFilePath, and WARNING.
Referenced by pgarch_ArchiverCopyLoop().
{
char rlogready[MAXPGPATH];
char rlogdone[MAXPGPATH];
StatusFilePath(rlogready, xlog, ".ready");
StatusFilePath(rlogdone, xlog, ".done");
if (rename(rlogready, rlogdone) < 0)
ereport(WARNING,
(errcode_for_file_access(),
errmsg("could not rename file \"%s\" to \"%s\": %m",
rlogready, rlogdone)));
}
| static void pgarch_ArchiverCopyLoop | ( | void | ) | [static] |
Definition at line 450 of file pgarch.c.
References ereport, errmsg(), got_SIGHUP, got_SIGTERM, MAX_XFN_CHARS, NUM_ARCHIVE_RETRIES, pg_usleep(), pgarch_archiveDone(), pgarch_archiveXlog(), pgarch_readyXlog(), PGC_SIGHUP, PostmasterIsAlive(), ProcessConfigFile(), WARNING, and XLogArchiveCommandSet.
Referenced by pgarch_MainLoop().
{
char xlog[MAX_XFN_CHARS + 1];
/*
* loop through all xlogs with archive_status of .ready and archive
* them...mostly we expect this to be a single file, though it is possible
* some backend will add files onto the list of those that need archiving
* while we are still copying earlier archives
*/
while (pgarch_readyXlog(xlog))
{
int failures = 0;
for (;;)
{
/*
* 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())
return;
/*
* Check for config update. This is so that we'll adopt a new
* setting for archive_command as soon as possible, even if there
* is a backlog of files to be archived.
*/
if (got_SIGHUP)
{
got_SIGHUP = false;
ProcessConfigFile(PGC_SIGHUP);
}
/* can't do anything if no command ... */
if (!XLogArchiveCommandSet())
{
ereport(WARNING,
(errmsg("archive_mode enabled, yet archive_command is not set")));
return;
}
if (pgarch_archiveXlog(xlog))
{
/* successful */
pgarch_archiveDone(xlog);
break; /* out of inner retry loop */
}
else
{
if (++failures >= NUM_ARCHIVE_RETRIES)
{
ereport(WARNING,
(errmsg("archiving transaction log file \"%s\" failed too many times, will try again later",
xlog)));
return; /* give up archiving for now */
}
pg_usleep(1000000L); /* wait a bit before retrying */
}
}
}
}
| static bool pgarch_archiveXlog | ( | char * | xlog | ) | [static] |
Definition at line 524 of file pgarch.c.
References DEBUG1, DEBUG3, ereport, errdetail(), errhint(), errmsg(), errmsg_internal(), FATAL, LOG, make_native_path(), MAXFNAMELEN, MAXPGPATH, set_ps_display(), snprintf(), strlcpy(), system(), WEXITSTATUS, WIFEXITED, WIFSIGNALED, WTERMSIG, XLogArchiveCommand, and XLOGDIR.
Referenced by pgarch_ArchiverCopyLoop().
{
char xlogarchcmd[MAXPGPATH];
char pathname[MAXPGPATH];
char activitymsg[MAXFNAMELEN + 16];
char *dp;
char *endp;
const char *sp;
int rc;
snprintf(pathname, MAXPGPATH, XLOGDIR "/%s", xlog);
/*
* construct the command to be executed
*/
dp = xlogarchcmd;
endp = xlogarchcmd + MAXPGPATH - 1;
*endp = '\0';
for (sp = XLogArchiveCommand; *sp; sp++)
{
if (*sp == '%')
{
switch (sp[1])
{
case 'p':
/* %p: relative path of source file */
sp++;
strlcpy(dp, pathname, endp - dp);
make_native_path(dp);
dp += strlen(dp);
break;
case 'f':
/* %f: filename of source file */
sp++;
strlcpy(dp, xlog, endp - dp);
dp += strlen(dp);
break;
case '%':
/* convert %% to a single % */
sp++;
if (dp < endp)
*dp++ = *sp;
break;
default:
/* otherwise treat the % as not special */
if (dp < endp)
*dp++ = *sp;
break;
}
}
else
{
if (dp < endp)
*dp++ = *sp;
}
}
*dp = '\0';
ereport(DEBUG3,
(errmsg_internal("executing archive command \"%s\"",
xlogarchcmd)));
/* Report archive activity in PS display */
snprintf(activitymsg, sizeof(activitymsg), "archiving %s", xlog);
set_ps_display(activitymsg, false);
rc = system(xlogarchcmd);
if (rc != 0)
{
/*
* If either the shell itself, or a called command, died on a signal,
* abort the archiver. We do this because system() ignores SIGINT and
* SIGQUIT while waiting; so a signal is very likely something that
* should have interrupted us too. If we overreact it's no big deal,
* the postmaster will just start the archiver again.
*
* Per the Single Unix Spec, shells report exit status > 128 when a
* called command died on a signal.
*/
int lev = (WIFSIGNALED(rc) || WEXITSTATUS(rc) > 128) ? FATAL : LOG;
if (WIFEXITED(rc))
{
ereport(lev,
(errmsg("archive command failed with exit code %d",
WEXITSTATUS(rc)),
errdetail("The failed archive command was: %s",
xlogarchcmd)));
}
else if (WIFSIGNALED(rc))
{
#if defined(WIN32)
ereport(lev,
(errmsg("archive command was terminated by exception 0x%X",
WTERMSIG(rc)),
errhint("See C include file \"ntstatus.h\" for a description of the hexadecimal value."),
errdetail("The failed archive command was: %s",
xlogarchcmd)));
#elif defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST
ereport(lev,
(errmsg("archive command was terminated by signal %d: %s",
WTERMSIG(rc),
WTERMSIG(rc) < NSIG ? sys_siglist[WTERMSIG(rc)] : "(unknown)"),
errdetail("The failed archive command was: %s",
xlogarchcmd)));
#else
ereport(lev,
(errmsg("archive command was terminated by signal %d",
WTERMSIG(rc)),
errdetail("The failed archive command was: %s",
xlogarchcmd)));
#endif
}
else
{
ereport(lev,
(errmsg("archive command exited with unrecognized status %d",
rc),
errdetail("The failed archive command was: %s",
xlogarchcmd)));
}
snprintf(activitymsg, sizeof(activitymsg), "failed on %s", xlog);
set_ps_display(activitymsg, false);
return false;
}
ereport(DEBUG1,
(errmsg("archived transaction log file \"%s\"", xlog)));
snprintf(activitymsg, sizeof(activitymsg), "last was %s", xlog);
set_ps_display(activitymsg, false);
return true;
}
| static void pgarch_exit | ( | SIGNAL_ARGS | ) | [static] |
Definition at line 284 of file pgarch.c.
Referenced by PgArchiverMain().
{
/* SIGQUIT means curl up and die ... */
exit(1);
}
| static void pgarch_MainLoop | ( | void | ) | [static] |
Definition at line 353 of file pgarch.c.
References got_SIGHUP, got_SIGTERM, last_sigterm_time, NULL, pgarch_ArchiverCopyLoop(), PGARCH_AUTOWAKE_INTERVAL, PGC_SIGHUP, PostmasterIsAlive(), ProcessConfigFile(), ready_to_stop, ResetLatch(), WaitLatch(), wakened, WL_LATCH_SET, WL_POSTMASTER_DEATH, and WL_TIMEOUT.
Referenced by PgArchiverMain().
{
pg_time_t last_copy_time = 0;
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.
*/
do
{
ResetLatch(&mainloop_latch);
/* 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)
{
got_SIGHUP = false;
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 || time_to_stop)
{
wakened = false;
pgarch_ArchiverCopyLoop();
last_copy_time = time(NULL);
}
/*
* 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.
*/
if (!time_to_stop) /* Don't wait during last iteration */
{
pg_time_t curtime = (pg_time_t) time(NULL);
int timeout;
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 * 1000L);
if (rc & WL_TIMEOUT)
wakened = true;
}
else
wakened = true;
}
/*
* The archiver quits either when the postmaster dies (not expected)
* or after completing one more archiving cycle after receiving
* SIGUSR2.
*/
} while (PostmasterIsAlive() && !time_to_stop);
}
| static bool pgarch_readyXlog | ( | char * | xlog | ) | [static] |
Definition at line 683 of file pgarch.c.
References AllocateDir(), dirent::d_name, ereport, errcode_for_file_access(), errmsg(), ERROR, FreeDir(), MAX_XFN_CHARS, MAXPGPATH, MIN_XFN_CHARS, NULL, ReadDir(), snprintf(), VALID_XFN_CHARS, and XLOGDIR.
Referenced by pgarch_ArchiverCopyLoop().
{
/*
* open xlog status directory and read through list of xlogs that have the
* .ready suffix, looking for earliest file. It is possible to optimise
* this code, though only a single file is expected on the vast majority
* of calls, so....
*/
char XLogArchiveStatusDir[MAXPGPATH];
char newxlog[MAX_XFN_CHARS + 6 + 1];
DIR *rldir;
struct dirent *rlde;
bool found = false;
snprintf(XLogArchiveStatusDir, MAXPGPATH, XLOGDIR "/archive_status");
rldir = AllocateDir(XLogArchiveStatusDir);
if (rldir == NULL)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open archive status directory \"%s\": %m",
XLogArchiveStatusDir)));
while ((rlde = ReadDir(rldir, XLogArchiveStatusDir)) != NULL)
{
int basenamelen = (int) strlen(rlde->d_name) - 6;
if (basenamelen >= MIN_XFN_CHARS &&
basenamelen <= MAX_XFN_CHARS &&
strspn(rlde->d_name, VALID_XFN_CHARS) >= basenamelen &&
strcmp(rlde->d_name + basenamelen, ".ready") == 0)
{
if (!found)
{
strcpy(newxlog, rlde->d_name);
found = true;
}
else
{
if (strcmp(rlde->d_name, newxlog) < 0)
strcpy(newxlog, rlde->d_name);
}
}
}
FreeDir(rldir);
if (found)
{
/* truncate off the .ready */
newxlog[strlen(newxlog) - 6] = '\0';
strcpy(xlog, newxlog);
}
return found;
}
| int pgarch_start | ( | void | ) |
Definition at line 134 of file pgarch.c.
References ClosePostmasterPorts(), ereport, errmsg(), fork_process(), last_pgarch_start_time, LOG, NULL, on_exit_reset(), PGARCH_RESTART_INTERVAL, PgArchiverMain(), PGSharedMemoryDetach(), and XLogArchivingActive.
Referenced by reaper(), and ServerLoop().
{
time_t curtime;
pid_t pgArchPid;
/*
* Do nothing if no archiver needed
*/
if (!XLogArchivingActive())
return 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;
#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 ... */
/* Close the postmaster's sockets */
ClosePostmasterPorts(false);
/* Lose the postmaster's on-exit routines */
on_exit_reset();
/* Drop our connection to postmaster's shared memory, as well */
PGSharedMemoryDetach();
PgArchiverMain(0, NULL);
break;
#endif
default:
return (int) pgArchPid;
}
/* shouldn't get here */
return 0;
}
| static void pgarch_waken | ( | SIGNAL_ARGS | ) | [static] |
Definition at line 323 of file pgarch.c.
References SetLatch(), and wakened.
Referenced by PgArchiverMain().
{
int save_errno = errno;
/* set flag that there is work to be done */
wakened = true;
SetLatch(&mainloop_latch);
errno = save_errno;
}
| static void pgarch_waken_stop | ( | SIGNAL_ARGS | ) | [static] |
Definition at line 336 of file pgarch.c.
References ready_to_stop, and SetLatch().
Referenced by PgArchiverMain().
{
int save_errno = errno;
/* set flag to do a final cycle and shut down afterwards */
ready_to_stop = true;
SetLatch(&mainloop_latch);
errno = save_errno;
}
| NON_EXEC_STATIC void PgArchiverMain | ( | int | argc, | |
| char * | argv[] | |||
| ) |
Definition at line 232 of file pgarch.c.
References ArchSigHupHandler(), ArchSigTermHandler(), elog, FATAL, init_ps_display(), InitializeLatchSupport(), InitLatch(), IsUnderPostmaster, MyProcPid, MyStartTime, NULL, PG_SETMASK, pgarch_exit(), pgarch_MainLoop(), pgarch_waken(), pgarch_waken_stop(), pqsignal(), SIG_DFL, SIG_IGN, SIGALRM, SIGCHLD, SIGCONT, SIGHUP, SIGPIPE, SIGQUIT, SIGTTIN, SIGTTOU, SIGUSR1, SIGUSR2, SIGWINCH, and UnBlockSig.
Referenced by pgarch_start().
{
IsUnderPostmaster = true; /* we are a postmaster subprocess now */
MyProcPid = getpid(); /* reset MyProcPid */
MyStartTime = time(NULL); /* record Start Time for logging */
/*
* 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
InitializeLatchSupport(); /* needed for latch waits */
InitLatch(&mainloop_latch); /* initialize latch used in main loop */
/*
* Ignore all signals usually bound to some action in the postmaster,
* except for SIGHUP, SIGTERM, SIGUSR1, SIGUSR2, and SIGQUIT.
*/
pqsignal(SIGHUP, ArchSigHupHandler);
pqsignal(SIGINT, SIG_IGN);
pqsignal(SIGTERM, ArchSigTermHandler);
pqsignal(SIGQUIT, pgarch_exit);
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, pgarch_waken);
pqsignal(SIGUSR2, pgarch_waken_stop);
pqsignal(SIGCHLD, SIG_DFL);
pqsignal(SIGTTIN, SIG_DFL);
pqsignal(SIGTTOU, SIG_DFL);
pqsignal(SIGCONT, SIG_DFL);
pqsignal(SIGWINCH, SIG_DFL);
PG_SETMASK(&UnBlockSig);
/*
* Identify myself via ps
*/
init_ps_display("archiver process", "", "", "");
pgarch_MainLoop();
exit(0);
}
volatile sig_atomic_t got_SIGHUP = false [static] |
Definition at line 87 of file pgarch.c.
Referenced by ArchSigHupHandler(), pgarch_ArchiverCopyLoop(), and pgarch_MainLoop().
volatile sig_atomic_t got_SIGTERM = false [static] |
Definition at line 88 of file pgarch.c.
Referenced by ArchSigTermHandler(), pgarch_ArchiverCopyLoop(), and pgarch_MainLoop().
time_t last_pgarch_start_time [static] |
Definition at line 81 of file pgarch.c.
Referenced by pgarch_start().
time_t last_sigterm_time = 0 [static] |
Definition at line 82 of file pgarch.c.
Referenced by pgarch_MainLoop().
Latch mainloop_latch [static] |
volatile sig_atomic_t ready_to_stop = false [static] |
Definition at line 90 of file pgarch.c.
Referenced by pgarch_MainLoop(), and pgarch_waken_stop().
volatile sig_atomic_t wakened = false [static] |
Definition at line 89 of file pgarch.c.
Referenced by pgarch_MainLoop(), and pgarch_waken().
1.7.1