LCOV - code coverage report
Current view: top level - src/backend/postmaster - pgarch.c (source / functions) Hit Total Coverage
Test: PostgreSQL 15beta1 Lines: 156 218 71.6 %
Date: 2022-05-19 15:10:49 Functions: 16 17 94.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pgarch.c
       4             :  *
       5             :  *  PostgreSQL WAL archiver
       6             :  *
       7             :  *  All functions relating to archiver are included here
       8             :  *
       9             :  *  - All functions executed by archiver process
      10             :  *
      11             :  *  - archiver is forked from postmaster, and the two
      12             :  *  processes then communicate using signals. All functions
      13             :  *  executed by postmaster are included in this file.
      14             :  *
      15             :  *  Initial author: Simon Riggs     simon@2ndquadrant.com
      16             :  *
      17             :  * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
      18             :  * Portions Copyright (c) 1994, Regents of the University of California
      19             :  *
      20             :  *
      21             :  * IDENTIFICATION
      22             :  *    src/backend/postmaster/pgarch.c
      23             :  *
      24             :  *-------------------------------------------------------------------------
      25             :  */
      26             : #include "postgres.h"
      27             : 
      28             : #include <time.h>
      29             : #include <sys/stat.h>
      30             : #include <unistd.h>
      31             : 
      32             : #include "access/xlog.h"
      33             : #include "access/xlog_internal.h"
      34             : #include "lib/binaryheap.h"
      35             : #include "libpq/pqsignal.h"
      36             : #include "pgstat.h"
      37             : #include "postmaster/interrupt.h"
      38             : #include "postmaster/pgarch.h"
      39             : #include "storage/fd.h"
      40             : #include "storage/ipc.h"
      41             : #include "storage/latch.h"
      42             : #include "storage/pmsignal.h"
      43             : #include "storage/proc.h"
      44             : #include "storage/procsignal.h"
      45             : #include "storage/shmem.h"
      46             : #include "storage/spin.h"
      47             : #include "utils/guc.h"
      48             : #include "utils/memutils.h"
      49             : #include "utils/ps_status.h"
      50             : 
      51             : 
      52             : /* ----------
      53             :  * Timer definitions.
      54             :  * ----------
      55             :  */
      56             : #define PGARCH_AUTOWAKE_INTERVAL 60 /* How often to force a poll of the
      57             :                                      * archive status directory; in seconds. */
      58             : #define PGARCH_RESTART_INTERVAL 10  /* How often to attempt to restart a
      59             :                                      * failed archiver; in seconds. */
      60             : 
      61             : /*
      62             :  * Maximum number of retries allowed when attempting to archive a WAL
      63             :  * file.
      64             :  */
      65             : #define NUM_ARCHIVE_RETRIES 3
      66             : 
      67             : /*
      68             :  * Maximum number of retries allowed when attempting to remove an
      69             :  * orphan archive status file.
      70             :  */
      71             : #define NUM_ORPHAN_CLEANUP_RETRIES 3
      72             : 
      73             : /*
      74             :  * Maximum number of .ready files to gather per directory scan.
      75             :  */
      76             : #define NUM_FILES_PER_DIRECTORY_SCAN 64
      77             : 
      78             : /* Shared memory area for archiver process */
      79             : typedef struct PgArchData
      80             : {
      81             :     int         pgprocno;       /* pgprocno of archiver process */
      82             : 
      83             :     /*
      84             :      * Forces a directory scan in pgarch_readyXlog().  Protected by arch_lck.
      85             :      */
      86             :     bool        force_dir_scan;
      87             : 
      88             :     slock_t     arch_lck;
      89             : } PgArchData;
      90             : 
      91             : char       *XLogArchiveLibrary = "";
      92             : 
      93             : 
      94             : /* ----------
      95             :  * Local data
      96             :  * ----------
      97             :  */
      98             : static time_t last_sigterm_time = 0;
      99             : static PgArchData *PgArch = NULL;
     100             : static ArchiveModuleCallbacks ArchiveContext;
     101             : 
     102             : 
     103             : /*
     104             :  * Stuff for tracking multiple files to archive from each scan of
     105             :  * archive_status.  Minimizing the number of directory scans when there are
     106             :  * many files to archive can significantly improve archival rate.
     107             :  *
     108             :  * arch_heap is a max-heap that is used during the directory scan to track
     109             :  * the highest-priority files to archive.  After the directory scan
     110             :  * completes, the file names are stored in ascending order of priority in
     111             :  * arch_files.  pgarch_readyXlog() returns files from arch_files until it
     112             :  * is empty, at which point another directory scan must be performed.
     113             :  *
     114             :  * We only need this data in the archiver process, so make it a palloc'd
     115             :  * struct rather than a bunch of static arrays.
     116             :  */
     117             : struct arch_files_state
     118             : {
     119             :     binaryheap *arch_heap;
     120             :     int         arch_files_size;    /* number of live entries in arch_files[] */
     121             :     char       *arch_files[NUM_FILES_PER_DIRECTORY_SCAN];
     122             :     /* buffers underlying heap, and later arch_files[], entries: */
     123             :     char        arch_filenames[NUM_FILES_PER_DIRECTORY_SCAN][MAX_XFN_CHARS + 1];
     124             : };
     125             : 
     126             : static struct arch_files_state *arch_files = NULL;
     127             : 
     128             : /*
     129             :  * Flags set by interrupt handlers for later service in the main loop.
     130             :  */
     131             : static volatile sig_atomic_t ready_to_stop = false;
     132             : 
     133             : /* ----------
     134             :  * Local function forward declarations
     135             :  * ----------
     136             :  */
     137             : static void pgarch_waken_stop(SIGNAL_ARGS);
     138             : static void pgarch_MainLoop(void);
     139             : static void pgarch_ArchiverCopyLoop(void);
     140             : static bool pgarch_archiveXlog(char *xlog);
     141             : static bool pgarch_readyXlog(char *xlog);
     142             : static void pgarch_archiveDone(char *xlog);
     143             : static void pgarch_die(int code, Datum arg);
     144             : static void HandlePgArchInterrupts(void);
     145             : static int  ready_file_comparator(Datum a, Datum b, void *arg);
     146             : static void LoadArchiveLibrary(void);
     147             : static void call_archive_module_shutdown_callback(int code, Datum arg);
     148             : 
     149             : /* Report shared memory space needed by PgArchShmemInit */
     150             : Size
     151       10646 : PgArchShmemSize(void)
     152             : {
     153       10646 :     Size        size = 0;
     154             : 
     155       10646 :     size = add_size(size, sizeof(PgArchData));
     156             : 
     157       10646 :     return size;
     158             : }
     159             : 
     160             : /* Allocate and initialize archiver-related shared memory */
     161             : void
     162        3198 : PgArchShmemInit(void)
     163             : {
     164             :     bool        found;
     165             : 
     166        3198 :     PgArch = (PgArchData *)
     167        3198 :         ShmemInitStruct("Archiver Data", PgArchShmemSize(), &found);
     168             : 
     169        3198 :     if (!found)
     170             :     {
     171             :         /* First time through, so initialize */
     172        6396 :         MemSet(PgArch, 0, PgArchShmemSize());
     173        3198 :         PgArch->pgprocno = INVALID_PGPROCNO;
     174        3198 :         SpinLockInit(&PgArch->arch_lck);
     175             :     }
     176        3198 : }
     177             : 
     178             : /*
     179             :  * PgArchCanRestart
     180             :  *
     181             :  * Return true and archiver is allowed to restart if enough time has
     182             :  * passed since it was launched last to reach PGARCH_RESTART_INTERVAL.
     183             :  * Otherwise return false.
     184             :  *
     185             :  * This is a safety valve to protect against continuous respawn attempts if the
     186             :  * archiver is dying immediately at launch. Note that since we will retry to
     187             :  * launch the archiver from the postmaster main loop, we will get another
     188             :  * chance later.
     189             :  */
     190             : bool
     191          48 : PgArchCanRestart(void)
     192             : {
     193             :     static time_t last_pgarch_start_time = 0;
     194          48 :     time_t      curtime = time(NULL);
     195             : 
     196             :     /*
     197             :      * Return false and don't restart archiver if too soon since last archiver
     198             :      * start.
     199             :      */
     200          48 :     if ((unsigned int) (curtime - last_pgarch_start_time) <
     201             :         (unsigned int) PGARCH_RESTART_INTERVAL)
     202           0 :         return false;
     203             : 
     204          48 :     last_pgarch_start_time = curtime;
     205          48 :     return true;
     206             : }
     207             : 
     208             : 
     209             : /* Main entry point for archiver process */
     210             : void
     211          14 : PgArchiverMain(void)
     212             : {
     213             :     /*
     214             :      * Ignore all signals usually bound to some action in the postmaster,
     215             :      * except for SIGHUP, SIGTERM, SIGUSR1, SIGUSR2, and SIGQUIT.
     216             :      */
     217          14 :     pqsignal(SIGHUP, SignalHandlerForConfigReload);
     218          14 :     pqsignal(SIGINT, SIG_IGN);
     219          14 :     pqsignal(SIGTERM, SignalHandlerForShutdownRequest);
     220             :     /* SIGQUIT handler was already set up by InitPostmasterChild */
     221          14 :     pqsignal(SIGALRM, SIG_IGN);
     222          14 :     pqsignal(SIGPIPE, SIG_IGN);
     223          14 :     pqsignal(SIGUSR1, procsignal_sigusr1_handler);
     224          14 :     pqsignal(SIGUSR2, pgarch_waken_stop);
     225             : 
     226             :     /* Reset some signals that are accepted by postmaster but not here */
     227          14 :     pqsignal(SIGCHLD, SIG_DFL);
     228             : 
     229             :     /* Unblock signals (they were blocked when the postmaster forked us) */
     230          14 :     PG_SETMASK(&UnBlockSig);
     231             : 
     232             :     /* We shouldn't be launched unnecessarily. */
     233             :     Assert(XLogArchivingActive());
     234             : 
     235             :     /* Arrange to clean up at archiver exit */
     236          14 :     on_shmem_exit(pgarch_die, 0);
     237             : 
     238             :     /*
     239             :      * Advertise our pgprocno so that backends can use our latch to wake us up
     240             :      * while we're sleeping.
     241             :      */
     242          14 :     PgArch->pgprocno = MyProc->pgprocno;
     243             : 
     244             :     /* Create workspace for pgarch_readyXlog() */
     245          14 :     arch_files = palloc(sizeof(struct arch_files_state));
     246          14 :     arch_files->arch_files_size = 0;
     247             : 
     248             :     /* Initialize our max-heap for prioritizing files to archive. */
     249          14 :     arch_files->arch_heap = binaryheap_allocate(NUM_FILES_PER_DIRECTORY_SCAN,
     250             :                                                 ready_file_comparator, NULL);
     251             : 
     252             :     /* Load the archive_library. */
     253          14 :     LoadArchiveLibrary();
     254             : 
     255          14 :     PG_ENSURE_ERROR_CLEANUP(call_archive_module_shutdown_callback, 0);
     256             :     {
     257          14 :         pgarch_MainLoop();
     258             :     }
     259          14 :     PG_END_ENSURE_ERROR_CLEANUP(call_archive_module_shutdown_callback, 0);
     260             : 
     261          14 :     call_archive_module_shutdown_callback(0, 0);
     262             : 
     263          14 :     proc_exit(0);
     264             : }
     265             : 
     266             : /*
     267             :  * Wake up the archiver
     268             :  */
     269             : void
     270          94 : PgArchWakeup(void)
     271             : {
     272          94 :     int         arch_pgprocno = PgArch->pgprocno;
     273             : 
     274             :     /*
     275             :      * We don't acquire ProcArrayLock here.  It's actually fine because
     276             :      * procLatch isn't ever freed, so we just can potentially set the wrong
     277             :      * process' (or no process') latch.  Even in that case the archiver will
     278             :      * be relaunched shortly and will start archiving.
     279             :      */
     280          94 :     if (arch_pgprocno != INVALID_PGPROCNO)
     281          74 :         SetLatch(&ProcGlobal->allProcs[arch_pgprocno].procLatch);
     282          94 : }
     283             : 
     284             : 
     285             : /* SIGUSR2 signal handler for archiver process */
     286             : static void
     287          14 : pgarch_waken_stop(SIGNAL_ARGS)
     288             : {
     289          14 :     int         save_errno = errno;
     290             : 
     291             :     /* set flag to do a final cycle and shut down afterwards */
     292          14 :     ready_to_stop = true;
     293          14 :     SetLatch(MyLatch);
     294             : 
     295          14 :     errno = save_errno;
     296          14 : }
     297             : 
     298             : /*
     299             :  * pgarch_MainLoop
     300             :  *
     301             :  * Main loop for archiver
     302             :  */
     303             : static void
     304          14 : pgarch_MainLoop(void)
     305             : {
     306          14 :     pg_time_t   last_copy_time = 0;
     307             :     bool        time_to_stop;
     308             : 
     309             :     /*
     310             :      * There shouldn't be anything for the archiver to do except to wait for a
     311             :      * signal ... however, the archiver exists to protect our data, so she
     312             :      * wakes up occasionally to allow herself to be proactive.
     313             :      */
     314             :     do
     315             :     {
     316          58 :         ResetLatch(MyLatch);
     317             : 
     318             :         /* When we get SIGUSR2, we do one more archive cycle, then exit */
     319          58 :         time_to_stop = ready_to_stop;
     320             : 
     321             :         /* Check for barrier events and config update */
     322          58 :         HandlePgArchInterrupts();
     323             : 
     324             :         /*
     325             :          * If we've gotten SIGTERM, we normally just sit and do nothing until
     326             :          * SIGUSR2 arrives.  However, that means a random SIGTERM would
     327             :          * disable archiving indefinitely, which doesn't seem like a good
     328             :          * idea.  If more than 60 seconds pass since SIGTERM, exit anyway, so
     329             :          * that the postmaster can start a new archiver if needed.
     330             :          */
     331          58 :         if (ShutdownRequestPending)
     332             :         {
     333           0 :             time_t      curtime = time(NULL);
     334             : 
     335           0 :             if (last_sigterm_time == 0)
     336           0 :                 last_sigterm_time = curtime;
     337           0 :             else if ((unsigned int) (curtime - last_sigterm_time) >=
     338             :                      (unsigned int) 60)
     339           0 :                 break;
     340             :         }
     341             : 
     342             :         /* Do what we're here for */
     343          58 :         pgarch_ArchiverCopyLoop();
     344          58 :         last_copy_time = time(NULL);
     345             : 
     346             :         /*
     347             :          * Sleep until a signal is received, or until a poll is forced by
     348             :          * PGARCH_AUTOWAKE_INTERVAL having passed since last_copy_time, or
     349             :          * until postmaster dies.
     350             :          */
     351          58 :         if (!time_to_stop)      /* Don't wait during last iteration */
     352             :         {
     353          44 :             pg_time_t   curtime = (pg_time_t) time(NULL);
     354             :             int         timeout;
     355             : 
     356          44 :             timeout = PGARCH_AUTOWAKE_INTERVAL - (curtime - last_copy_time);
     357          44 :             if (timeout > 0)
     358             :             {
     359             :                 int         rc;
     360             : 
     361          44 :                 rc = WaitLatch(MyLatch,
     362             :                                WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
     363             :                                timeout * 1000L,
     364             :                                WAIT_EVENT_ARCHIVER_MAIN);
     365          44 :                 if (rc & WL_POSTMASTER_DEATH)
     366           0 :                     time_to_stop = true;
     367             :             }
     368             :         }
     369             : 
     370             :         /*
     371             :          * The archiver quits either when the postmaster dies (not expected)
     372             :          * or after completing one more archiving cycle after receiving
     373             :          * SIGUSR2.
     374             :          */
     375          58 :     } while (!time_to_stop);
     376          14 : }
     377             : 
     378             : /*
     379             :  * pgarch_ArchiverCopyLoop
     380             :  *
     381             :  * Archives all outstanding xlogs then returns
     382             :  */
     383             : static void
     384          58 : pgarch_ArchiverCopyLoop(void)
     385             : {
     386             :     char        xlog[MAX_XFN_CHARS + 1];
     387             : 
     388             :     /* force directory scan in the first call to pgarch_readyXlog() */
     389          58 :     arch_files->arch_files_size = 0;
     390             : 
     391             :     /*
     392             :      * loop through all xlogs with archive_status of .ready and archive
     393             :      * them...mostly we expect this to be a single file, though it is possible
     394             :      * some backend will add files onto the list of those that need archiving
     395             :      * while we are still copying earlier archives
     396             :      */
     397          92 :     while (pgarch_readyXlog(xlog))
     398             :     {
     399          34 :         int         failures = 0;
     400          34 :         int         failures_orphan = 0;
     401             : 
     402             :         for (;;)
     403           0 :         {
     404             :             struct stat stat_buf;
     405             :             char        pathname[MAXPGPATH];
     406             : 
     407             :             /*
     408             :              * Do not initiate any more archive commands after receiving
     409             :              * SIGTERM, nor after the postmaster has died unexpectedly. The
     410             :              * first condition is to try to keep from having init SIGKILL the
     411             :              * command, and the second is to avoid conflicts with another
     412             :              * archiver spawned by a newer postmaster.
     413             :              */
     414          34 :             if (ShutdownRequestPending || !PostmasterIsAlive())
     415           0 :                 return;
     416             : 
     417             :             /*
     418             :              * Check for barrier events and config update.  This is so that
     419             :              * we'll adopt a new setting for archive_command as soon as
     420             :              * possible, even if there is a backlog of files to be archived.
     421             :              */
     422          34 :             HandlePgArchInterrupts();
     423             : 
     424             :             /* can't do anything if not configured ... */
     425          34 :             if (ArchiveContext.check_configured_cb != NULL &&
     426          34 :                 !ArchiveContext.check_configured_cb())
     427             :             {
     428           0 :                 ereport(WARNING,
     429             :                         (errmsg("archive_mode enabled, yet archiving is not configured")));
     430           0 :                 return;
     431             :             }
     432             : 
     433             :             /*
     434             :              * Since archive status files are not removed in a durable manner,
     435             :              * a system crash could leave behind .ready files for WAL segments
     436             :              * that have already been recycled or removed.  In this case,
     437             :              * simply remove the orphan status file and move on.  unlink() is
     438             :              * used here as even on subsequent crashes the same orphan files
     439             :              * would get removed, so there is no need to worry about
     440             :              * durability.
     441             :              */
     442          34 :             snprintf(pathname, MAXPGPATH, XLOGDIR "/%s", xlog);
     443          34 :             if (stat(pathname, &stat_buf) != 0 && errno == ENOENT)
     444             :             {
     445             :                 char        xlogready[MAXPGPATH];
     446             : 
     447           0 :                 StatusFilePath(xlogready, xlog, ".ready");
     448           0 :                 if (unlink(xlogready) == 0)
     449             :                 {
     450           0 :                     ereport(WARNING,
     451             :                             (errmsg("removed orphan archive status file \"%s\"",
     452             :                                     xlogready)));
     453             : 
     454             :                     /* leave loop and move to the next status file */
     455           0 :                     break;
     456             :                 }
     457             : 
     458           0 :                 if (++failures_orphan >= NUM_ORPHAN_CLEANUP_RETRIES)
     459             :                 {
     460           0 :                     ereport(WARNING,
     461             :                             (errmsg("removal of orphan archive status file \"%s\" failed too many times, will try again later",
     462             :                                     xlogready)));
     463             : 
     464             :                     /* give up cleanup of orphan status files */
     465           0 :                     return;
     466             :                 }
     467             : 
     468             :                 /* wait a bit before retrying */
     469           0 :                 pg_usleep(1000000L);
     470           0 :                 continue;
     471             :             }
     472             : 
     473          34 :             if (pgarch_archiveXlog(xlog))
     474             :             {
     475             :                 /* successful */
     476          34 :                 pgarch_archiveDone(xlog);
     477             : 
     478             :                 /*
     479             :                  * Tell the cumulative stats system about the WAL file that we
     480             :                  * successfully archived
     481             :                  */
     482          34 :                 pgstat_report_archiver(xlog, false);
     483             : 
     484          34 :                 break;          /* out of inner retry loop */
     485             :             }
     486             :             else
     487             :             {
     488             :                 /*
     489             :                  * Tell the cumulative stats system about the WAL file that we
     490             :                  * failed to archive
     491             :                  */
     492           0 :                 pgstat_report_archiver(xlog, true);
     493             : 
     494           0 :                 if (++failures >= NUM_ARCHIVE_RETRIES)
     495             :                 {
     496           0 :                     ereport(WARNING,
     497             :                             (errmsg("archiving write-ahead log file \"%s\" failed too many times, will try again later",
     498             :                                     xlog)));
     499           0 :                     return;     /* give up archiving for now */
     500             :                 }
     501           0 :                 pg_usleep(1000000L);    /* wait a bit before retrying */
     502             :             }
     503             :         }
     504             :     }
     505             : }
     506             : 
     507             : /*
     508             :  * pgarch_archiveXlog
     509             :  *
     510             :  * Invokes archive_file_cb to copy one archive file to wherever it should go
     511             :  *
     512             :  * Returns true if successful
     513             :  */
     514             : static bool
     515          34 : pgarch_archiveXlog(char *xlog)
     516             : {
     517             :     char        pathname[MAXPGPATH];
     518             :     char        activitymsg[MAXFNAMELEN + 16];
     519             :     bool        ret;
     520             : 
     521          34 :     snprintf(pathname, MAXPGPATH, XLOGDIR "/%s", xlog);
     522             : 
     523             :     /* Report archive activity in PS display */
     524          34 :     snprintf(activitymsg, sizeof(activitymsg), "archiving %s", xlog);
     525          34 :     set_ps_display(activitymsg);
     526             : 
     527          34 :     ret = ArchiveContext.archive_file_cb(xlog, pathname);
     528          34 :     if (ret)
     529          34 :         snprintf(activitymsg, sizeof(activitymsg), "last was %s", xlog);
     530             :     else
     531           0 :         snprintf(activitymsg, sizeof(activitymsg), "failed on %s", xlog);
     532          34 :     set_ps_display(activitymsg);
     533             : 
     534          34 :     return ret;
     535             : }
     536             : 
     537             : /*
     538             :  * pgarch_readyXlog
     539             :  *
     540             :  * Return name of the oldest xlog file that has not yet been archived.
     541             :  * No notification is set that file archiving is now in progress, so
     542             :  * this would need to be extended if multiple concurrent archival
     543             :  * tasks were created. If a failure occurs, we will completely
     544             :  * re-copy the file at the next available opportunity.
     545             :  *
     546             :  * It is important that we return the oldest, so that we archive xlogs
     547             :  * in order that they were written, for two reasons:
     548             :  * 1) to maintain the sequential chain of xlogs required for recovery
     549             :  * 2) because the oldest ones will sooner become candidates for
     550             :  * recycling at time of checkpoint
     551             :  *
     552             :  * NOTE: the "oldest" comparison will consider any .history file to be older
     553             :  * than any other file except another .history file.  Segments on a timeline
     554             :  * with a smaller ID will be older than all segments on a timeline with a
     555             :  * larger ID; the net result being that past timelines are given higher
     556             :  * priority for archiving.  This seems okay, or at least not obviously worth
     557             :  * changing.
     558             :  */
     559             : static bool
     560          92 : pgarch_readyXlog(char *xlog)
     561             : {
     562             :     char        XLogArchiveStatusDir[MAXPGPATH];
     563             :     DIR        *rldir;
     564             :     struct dirent *rlde;
     565             :     bool        force_dir_scan;
     566             : 
     567             :     /*
     568             :      * If a directory scan was requested, clear the stored file names and
     569             :      * proceed.
     570             :      */
     571          92 :     SpinLockAcquire(&PgArch->arch_lck);
     572          92 :     force_dir_scan = PgArch->force_dir_scan;
     573          92 :     PgArch->force_dir_scan = false;
     574          92 :     SpinLockRelease(&PgArch->arch_lck);
     575             : 
     576          92 :     if (force_dir_scan)
     577           4 :         arch_files->arch_files_size = 0;
     578             : 
     579             :     /*
     580             :      * If we still have stored file names from the previous directory scan,
     581             :      * try to return one of those.  We check to make sure the status file is
     582             :      * still present, as the archive_command for a previous file may have
     583             :      * already marked it done.
     584             :      */
     585          92 :     while (arch_files->arch_files_size > 0)
     586             :     {
     587             :         struct stat st;
     588             :         char        status_file[MAXPGPATH];
     589             :         char       *arch_file;
     590             : 
     591           0 :         arch_files->arch_files_size--;
     592           0 :         arch_file = arch_files->arch_files[arch_files->arch_files_size];
     593           0 :         StatusFilePath(status_file, arch_file, ".ready");
     594             : 
     595           0 :         if (stat(status_file, &st) == 0)
     596             :         {
     597           0 :             strcpy(xlog, arch_file);
     598           0 :             return true;
     599             :         }
     600           0 :         else if (errno != ENOENT)
     601           0 :             ereport(ERROR,
     602             :                     (errcode_for_file_access(),
     603             :                      errmsg("could not stat file \"%s\": %m", status_file)));
     604             :     }
     605             : 
     606             :     /* arch_heap is probably empty, but let's make sure */
     607          92 :     binaryheap_reset(arch_files->arch_heap);
     608             : 
     609             :     /*
     610             :      * Open the archive status directory and read through the list of files
     611             :      * with the .ready suffix, looking for the earliest files.
     612             :      */
     613          92 :     snprintf(XLogArchiveStatusDir, MAXPGPATH, XLOGDIR "/archive_status");
     614          92 :     rldir = AllocateDir(XLogArchiveStatusDir);
     615             : 
     616         450 :     while ((rlde = ReadDir(rldir, XLogArchiveStatusDir)) != NULL)
     617             :     {
     618         358 :         int         basenamelen = (int) strlen(rlde->d_name) - 6;
     619             :         char        basename[MAX_XFN_CHARS + 1];
     620             :         char       *arch_file;
     621             : 
     622             :         /* Ignore entries with unexpected number of characters */
     623         358 :         if (basenamelen < MIN_XFN_CHARS ||
     624             :             basenamelen > MAX_XFN_CHARS)
     625         324 :             continue;
     626             : 
     627             :         /* Ignore entries with unexpected characters */
     628         138 :         if (strspn(rlde->d_name, VALID_XFN_CHARS) < basenamelen)
     629           0 :             continue;
     630             : 
     631             :         /* Ignore anything not suffixed with .ready */
     632         138 :         if (strcmp(rlde->d_name + basenamelen, ".ready") != 0)
     633         104 :             continue;
     634             : 
     635             :         /* Truncate off the .ready */
     636          34 :         memcpy(basename, rlde->d_name, basenamelen);
     637          34 :         basename[basenamelen] = '\0';
     638             : 
     639             :         /*
     640             :          * Store the file in our max-heap if it has a high enough priority.
     641             :          */
     642          34 :         if (arch_files->arch_heap->bh_size < NUM_FILES_PER_DIRECTORY_SCAN)
     643             :         {
     644             :             /* If the heap isn't full yet, quickly add it. */
     645          34 :             arch_file = arch_files->arch_filenames[arch_files->arch_heap->bh_size];
     646          34 :             strcpy(arch_file, basename);
     647          34 :             binaryheap_add_unordered(arch_files->arch_heap, CStringGetDatum(arch_file));
     648             : 
     649             :             /* If we just filled the heap, make it a valid one. */
     650          34 :             if (arch_files->arch_heap->bh_size == NUM_FILES_PER_DIRECTORY_SCAN)
     651           0 :                 binaryheap_build(arch_files->arch_heap);
     652             :         }
     653           0 :         else if (ready_file_comparator(binaryheap_first(arch_files->arch_heap),
     654             :                                        CStringGetDatum(basename), NULL) > 0)
     655             :         {
     656             :             /*
     657             :              * Remove the lowest priority file and add the current one to the
     658             :              * heap.
     659             :              */
     660           0 :             arch_file = DatumGetCString(binaryheap_remove_first(arch_files->arch_heap));
     661           0 :             strcpy(arch_file, basename);
     662           0 :             binaryheap_add(arch_files->arch_heap, CStringGetDatum(arch_file));
     663             :         }
     664             :     }
     665          92 :     FreeDir(rldir);
     666             : 
     667             :     /* If no files were found, simply return. */
     668          92 :     if (arch_files->arch_heap->bh_size == 0)
     669          58 :         return false;
     670             : 
     671             :     /*
     672             :      * If we didn't fill the heap, we didn't make it a valid one.  Do that
     673             :      * now.
     674             :      */
     675          34 :     if (arch_files->arch_heap->bh_size < NUM_FILES_PER_DIRECTORY_SCAN)
     676          34 :         binaryheap_build(arch_files->arch_heap);
     677             : 
     678             :     /*
     679             :      * Fill arch_files array with the files to archive in ascending order of
     680             :      * priority.
     681             :      */
     682          34 :     arch_files->arch_files_size = arch_files->arch_heap->bh_size;
     683          68 :     for (int i = 0; i < arch_files->arch_files_size; i++)
     684          34 :         arch_files->arch_files[i] = DatumGetCString(binaryheap_remove_first(arch_files->arch_heap));
     685             : 
     686             :     /* Return the highest priority file. */
     687          34 :     arch_files->arch_files_size--;
     688          34 :     strcpy(xlog, arch_files->arch_files[arch_files->arch_files_size]);
     689             : 
     690          34 :     return true;
     691             : }
     692             : 
     693             : /*
     694             :  * ready_file_comparator
     695             :  *
     696             :  * Compares the archival priority of the given files to archive.  If "a"
     697             :  * has a higher priority than "b", a negative value will be returned.  If
     698             :  * "b" has a higher priority than "a", a positive value will be returned.
     699             :  * If "a" and "b" have equivalent values, 0 will be returned.
     700             :  */
     701             : static int
     702           0 : ready_file_comparator(Datum a, Datum b, void *arg)
     703             : {
     704           0 :     char       *a_str = DatumGetCString(a);
     705           0 :     char       *b_str = DatumGetCString(b);
     706           0 :     bool        a_history = IsTLHistoryFileName(a_str);
     707           0 :     bool        b_history = IsTLHistoryFileName(b_str);
     708             : 
     709             :     /* Timeline history files always have the highest priority. */
     710           0 :     if (a_history != b_history)
     711           0 :         return a_history ? -1 : 1;
     712             : 
     713             :     /* Priority is given to older files. */
     714           0 :     return strcmp(a_str, b_str);
     715             : }
     716             : 
     717             : /*
     718             :  * PgArchForceDirScan
     719             :  *
     720             :  * When called, the next call to pgarch_readyXlog() will perform a
     721             :  * directory scan.  This is useful for ensuring that important files such
     722             :  * as timeline history files are archived as quickly as possible.
     723             :  */
     724             : void
     725          18 : PgArchForceDirScan(void)
     726             : {
     727          18 :     SpinLockAcquire(&PgArch->arch_lck);
     728          18 :     PgArch->force_dir_scan = true;
     729          18 :     SpinLockRelease(&PgArch->arch_lck);
     730          18 : }
     731             : 
     732             : /*
     733             :  * pgarch_archiveDone
     734             :  *
     735             :  * Emit notification that an xlog file has been successfully archived.
     736             :  * We do this by renaming the status file from NNN.ready to NNN.done.
     737             :  * Eventually, a checkpoint process will notice this and delete both the
     738             :  * NNN.done file and the xlog file itself.
     739             :  */
     740             : static void
     741          34 : pgarch_archiveDone(char *xlog)
     742             : {
     743             :     char        rlogready[MAXPGPATH];
     744             :     char        rlogdone[MAXPGPATH];
     745             : 
     746          34 :     StatusFilePath(rlogready, xlog, ".ready");
     747          34 :     StatusFilePath(rlogdone, xlog, ".done");
     748          34 :     (void) durable_rename(rlogready, rlogdone, WARNING);
     749          34 : }
     750             : 
     751             : 
     752             : /*
     753             :  * pgarch_die
     754             :  *
     755             :  * Exit-time cleanup handler
     756             :  */
     757             : static void
     758          14 : pgarch_die(int code, Datum arg)
     759             : {
     760          14 :     PgArch->pgprocno = INVALID_PGPROCNO;
     761          14 : }
     762             : 
     763             : /*
     764             :  * Interrupt handler for WAL archiver process.
     765             :  *
     766             :  * This is called in the loops pgarch_MainLoop and pgarch_ArchiverCopyLoop.
     767             :  * It checks for barrier events, config update and request for logging of
     768             :  * memory contexts, but not shutdown request because how to handle
     769             :  * shutdown request is different between those loops.
     770             :  */
     771             : static void
     772          92 : HandlePgArchInterrupts(void)
     773             : {
     774          92 :     if (ProcSignalBarrierPending)
     775           0 :         ProcessProcSignalBarrier();
     776             : 
     777             :     /* Perform logging of memory contexts of this process */
     778          92 :     if (LogMemoryContextPending)
     779           0 :         ProcessLogMemoryContextInterrupt();
     780             : 
     781          92 :     if (ConfigReloadPending)
     782             :     {
     783           0 :         char       *archiveLib = pstrdup(XLogArchiveLibrary);
     784             :         bool        archiveLibChanged;
     785             : 
     786           0 :         ConfigReloadPending = false;
     787           0 :         ProcessConfigFile(PGC_SIGHUP);
     788             : 
     789           0 :         archiveLibChanged = strcmp(XLogArchiveLibrary, archiveLib) != 0;
     790           0 :         pfree(archiveLib);
     791             : 
     792           0 :         if (archiveLibChanged)
     793             :         {
     794             :             /*
     795             :              * Call the currently loaded archive module's shutdown callback,
     796             :              * if one is defined.
     797             :              */
     798           0 :             call_archive_module_shutdown_callback(0, 0);
     799             : 
     800             :             /*
     801             :              * Ideally, we would simply unload the previous archive module and
     802             :              * load the new one, but there is presently no mechanism for
     803             :              * unloading a library (see the comment above
     804             :              * internal_load_library()).  To deal with this, we simply restart
     805             :              * the archiver.  The new archive module will be loaded when the
     806             :              * new archiver process starts up.
     807             :              */
     808           0 :             ereport(LOG,
     809             :                     (errmsg("restarting archiver process because value of "
     810             :                             "\"archive_library\" was changed")));
     811             : 
     812           0 :             proc_exit(0);
     813             :         }
     814             :     }
     815          92 : }
     816             : 
     817             : /*
     818             :  * LoadArchiveLibrary
     819             :  *
     820             :  * Loads the archiving callbacks into our local ArchiveContext.
     821             :  */
     822             : static void
     823          14 : LoadArchiveLibrary(void)
     824             : {
     825             :     ArchiveModuleInit archive_init;
     826             : 
     827          14 :     memset(&ArchiveContext, 0, sizeof(ArchiveModuleCallbacks));
     828             : 
     829             :     /*
     830             :      * If shell archiving is enabled, use our special initialization function.
     831             :      * Otherwise, load the library and call its _PG_archive_module_init().
     832             :      */
     833          14 :     if (XLogArchiveLibrary[0] == '\0')
     834          12 :         archive_init = shell_archive_init;
     835             :     else
     836           2 :         archive_init = (ArchiveModuleInit)
     837           2 :             load_external_function(XLogArchiveLibrary,
     838             :                                    "_PG_archive_module_init", false, NULL);
     839             : 
     840          14 :     if (archive_init == NULL)
     841           0 :         ereport(ERROR,
     842             :                 (errmsg("archive modules have to declare the _PG_archive_module_init symbol")));
     843             : 
     844          14 :     (*archive_init) (&ArchiveContext);
     845             : 
     846          14 :     if (ArchiveContext.archive_file_cb == NULL)
     847           0 :         ereport(ERROR,
     848             :                 (errmsg("archive modules must register an archive callback")));
     849          14 : }
     850             : 
     851             : /*
     852             :  * call_archive_module_shutdown_callback
     853             :  *
     854             :  * Calls the loaded archive module's shutdown callback, if one is defined.
     855             :  */
     856             : static void
     857          14 : call_archive_module_shutdown_callback(int code, Datum arg)
     858             : {
     859          14 :     if (ArchiveContext.shutdown_cb != NULL)
     860           0 :         ArchiveContext.shutdown_cb();
     861          14 : }

Generated by: LCOV version 1.14