Header And Logo

PostgreSQL
| The world's most advanced open source database.

Defines | Functions | Variables

pgarch.c File Reference

#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"
Include dependency graph for pgarch.c:

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 Documentation

#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().


Function Documentation

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);
}


Variable Documentation

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().

Definition at line 95 of file pgarch.c.

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().