LCOV - code coverage report
Current view: top level - src/backend/access/transam - xlogarchive.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 79.4 % 160 127
Test Date: 2026-03-01 17:14:43 Functions: 100.0 % 11 11
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * xlogarchive.c
       4              :  *      Functions for archiving WAL files and restoring from the archive.
       5              :  *
       6              :  *
       7              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8              :  * Portions Copyright (c) 1994, Regents of the University of California
       9              :  *
      10              :  * src/backend/access/transam/xlogarchive.c
      11              :  *
      12              :  *-------------------------------------------------------------------------
      13              :  */
      14              : 
      15              : #include "postgres.h"
      16              : 
      17              : #include <sys/stat.h>
      18              : #include <sys/wait.h>
      19              : #include <signal.h>
      20              : #include <unistd.h>
      21              : 
      22              : #include "access/xlog.h"
      23              : #include "access/xlog_internal.h"
      24              : #include "access/xlogarchive.h"
      25              : #include "common/archive.h"
      26              : #include "common/percentrepl.h"
      27              : #include "miscadmin.h"
      28              : #include "pgstat.h"
      29              : #include "postmaster/pgarch.h"
      30              : #include "postmaster/startup.h"
      31              : #include "replication/walsender.h"
      32              : #include "storage/fd.h"
      33              : #include "storage/ipc.h"
      34              : 
      35              : /*
      36              :  * Attempt to retrieve the specified file from off-line archival storage.
      37              :  * If successful, fill "path" with its complete path (note that this will be
      38              :  * a temp file name that doesn't follow the normal naming convention), and
      39              :  * return true.
      40              :  *
      41              :  * If not successful, fill "path" with the name of the normal on-line file
      42              :  * (which may or may not actually exist, but we'll try to use it), and return
      43              :  * false.
      44              :  *
      45              :  * For fixed-size files, the caller may pass the expected size as an
      46              :  * additional crosscheck on successful recovery.  If the file size is not
      47              :  * known, set expectedSize = 0.
      48              :  *
      49              :  * When 'cleanupEnabled' is false, refrain from deleting any old WAL segments
      50              :  * in the archive. This is used when fetching the initial checkpoint record,
      51              :  * when we are not yet sure how far back we need the WAL.
      52              :  */
      53              : bool
      54         1294 : RestoreArchivedFile(char *path, const char *xlogfname,
      55              :                     const char *recovername, off_t expectedSize,
      56              :                     bool cleanupEnabled)
      57              : {
      58              :     char        xlogpath[MAXPGPATH];
      59              :     char       *xlogRestoreCmd;
      60              :     char        lastRestartPointFname[MAXPGPATH];
      61              :     int         rc;
      62              :     struct stat stat_buf;
      63              :     XLogSegNo   restartSegNo;
      64              :     XLogRecPtr  restartRedoPtr;
      65              :     TimeLineID  restartTli;
      66              : 
      67              :     /*
      68              :      * Ignore restore_command when not in archive recovery (meaning we are in
      69              :      * crash recovery).
      70              :      */
      71         1294 :     if (!ArchiveRecoveryRequested)
      72           27 :         goto not_available;
      73              : 
      74              :     /* In standby mode, restore_command might not be supplied */
      75         1267 :     if (recoveryRestoreCommand == NULL || strcmp(recoveryRestoreCommand, "") == 0)
      76          757 :         goto not_available;
      77              : 
      78              :     /*
      79              :      * When doing archive recovery, we always prefer an archived log file even
      80              :      * if a file of the same name exists in XLOGDIR.  The reason is that the
      81              :      * file in XLOGDIR could be an old, un-filled or partly-filled version
      82              :      * that was copied and restored as part of backing up $PGDATA.
      83              :      *
      84              :      * We could try to optimize this slightly by checking the local copy
      85              :      * lastchange timestamp against the archived copy, but we have no API to
      86              :      * do this, nor can we guarantee that the lastchange timestamp was
      87              :      * preserved correctly when we copied to archive. Our aim is robustness,
      88              :      * so we elect not to do this.
      89              :      *
      90              :      * If we cannot obtain the log file from the archive, however, we will try
      91              :      * to use the XLOGDIR file if it exists.  This is so that we can make use
      92              :      * of log segments that weren't yet transferred to the archive.
      93              :      *
      94              :      * Notice that we don't actually overwrite any files when we copy back
      95              :      * from archive because the restore_command may inadvertently restore
      96              :      * inappropriate xlogs, or they may be corrupt, so we may wish to fallback
      97              :      * to the segments remaining in current XLOGDIR later. The
      98              :      * copy-from-archive filename is always the same, ensuring that we don't
      99              :      * run out of disk space on long recoveries.
     100              :      */
     101          510 :     snprintf(xlogpath, MAXPGPATH, XLOGDIR "/%s", recovername);
     102              : 
     103              :     /*
     104              :      * Make sure there is no existing file named recovername.
     105              :      */
     106          510 :     if (stat(xlogpath, &stat_buf) != 0)
     107              :     {
     108          506 :         if (errno != ENOENT)
     109            0 :             ereport(FATAL,
     110              :                     (errcode_for_file_access(),
     111              :                      errmsg("could not stat file \"%s\": %m",
     112              :                             xlogpath)));
     113              :     }
     114              :     else
     115              :     {
     116            4 :         if (unlink(xlogpath) != 0)
     117            0 :             ereport(FATAL,
     118              :                     (errcode_for_file_access(),
     119              :                      errmsg("could not remove file \"%s\": %m",
     120              :                             xlogpath)));
     121              :     }
     122              : 
     123              :     /*
     124              :      * Calculate the archive file cutoff point for use during log shipping
     125              :      * replication. All files earlier than this point can be deleted from the
     126              :      * archive, though there is no requirement to do so.
     127              :      *
     128              :      * If cleanup is not enabled, initialise this with the filename of
     129              :      * InvalidXLogRecPtr, which will prevent the deletion of any WAL files
     130              :      * from the archive because of the alphabetic sorting property of WAL
     131              :      * filenames.
     132              :      *
     133              :      * Once we have successfully located the redo pointer of the checkpoint
     134              :      * from which we start recovery we never request a file prior to the redo
     135              :      * pointer of the last restartpoint. When redo begins we know that we have
     136              :      * successfully located it, so there is no need for additional status
     137              :      * flags to signify the point when we can begin deleting WAL files from
     138              :      * the archive.
     139              :      */
     140          510 :     if (cleanupEnabled)
     141              :     {
     142          385 :         GetOldestRestartPoint(&restartRedoPtr, &restartTli);
     143          385 :         XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
     144          385 :         XLogFileName(lastRestartPointFname, restartTli, restartSegNo,
     145              :                      wal_segment_size);
     146              :         /* we shouldn't need anything earlier than last restart point */
     147              :         Assert(strcmp(lastRestartPointFname, xlogfname) <= 0);
     148              :     }
     149              :     else
     150          125 :         XLogFileName(lastRestartPointFname, 0, 0, wal_segment_size);
     151              : 
     152              :     /* Build the restore command to execute */
     153          510 :     xlogRestoreCmd = BuildRestoreCommand(recoveryRestoreCommand,
     154              :                                          xlogpath, xlogfname,
     155              :                                          lastRestartPointFname);
     156              : 
     157          510 :     ereport(DEBUG3,
     158              :             (errmsg_internal("executing restore command \"%s\"",
     159              :                              xlogRestoreCmd)));
     160              : 
     161          510 :     fflush(NULL);
     162          510 :     pgstat_report_wait_start(WAIT_EVENT_RESTORE_COMMAND);
     163              : 
     164              :     /*
     165              :      * PreRestoreCommand() informs the SIGTERM handler for the startup process
     166              :      * that it should proc_exit() right away.  This is done for the duration
     167              :      * of the system() call because there isn't a good way to break out while
     168              :      * it is executing.  Since we might call proc_exit() in a signal handler,
     169              :      * it is best to put any additional logic before or after the
     170              :      * PreRestoreCommand()/PostRestoreCommand() section.
     171              :      */
     172          510 :     PreRestoreCommand();
     173              : 
     174              :     /*
     175              :      * Copy xlog from archival storage to XLOGDIR
     176              :      */
     177          510 :     rc = system(xlogRestoreCmd);
     178              : 
     179          510 :     PostRestoreCommand();
     180              : 
     181          510 :     pgstat_report_wait_end();
     182          510 :     pfree(xlogRestoreCmd);
     183              : 
     184          510 :     if (rc == 0)
     185              :     {
     186              :         /*
     187              :          * command apparently succeeded, but let's make sure the file is
     188              :          * really there now and has the correct size.
     189              :          */
     190          373 :         if (stat(xlogpath, &stat_buf) == 0)
     191              :         {
     192          373 :             if (expectedSize > 0 && stat_buf.st_size != expectedSize)
     193              :             {
     194              :                 int         elevel;
     195              : 
     196              :                 /*
     197              :                  * If we find a partial file in standby mode, we assume it's
     198              :                  * because it's just being copied to the archive, and keep
     199              :                  * trying.
     200              :                  *
     201              :                  * Otherwise treat a wrong-sized file as FATAL to ensure the
     202              :                  * DBA would notice it, but is that too strong? We could try
     203              :                  * to plow ahead with a local copy of the file ... but the
     204              :                  * problem is that there probably isn't one, and we'd
     205              :                  * incorrectly conclude we've reached the end of WAL and we're
     206              :                  * done recovering ...
     207              :                  */
     208            0 :                 if (StandbyMode && stat_buf.st_size < expectedSize)
     209            0 :                     elevel = DEBUG1;
     210              :                 else
     211            0 :                     elevel = FATAL;
     212            0 :                 ereport(elevel,
     213              :                         (errmsg("archive file \"%s\" has wrong size: %lld instead of %lld",
     214              :                                 xlogfname,
     215              :                                 (long long int) stat_buf.st_size,
     216              :                                 (long long int) expectedSize)));
     217            0 :                 return false;
     218              :             }
     219              :             else
     220              :             {
     221          373 :                 ereport(LOG,
     222              :                         (errmsg("restored log file \"%s\" from archive",
     223              :                                 xlogfname)));
     224          373 :                 strcpy(path, xlogpath);
     225          373 :                 return true;
     226              :             }
     227              :         }
     228              :         else
     229              :         {
     230              :             /* stat failed */
     231            0 :             int         elevel = (errno == ENOENT) ? LOG : FATAL;
     232              : 
     233            0 :             ereport(elevel,
     234              :                     (errcode_for_file_access(),
     235              :                      errmsg("could not stat file \"%s\": %m", xlogpath),
     236              :                      errdetail("\"restore_command\" returned a zero exit status, but stat() failed.")));
     237              :         }
     238              :     }
     239              : 
     240              :     /*
     241              :      * Remember, we rollforward UNTIL the restore fails so failure here is
     242              :      * just part of the process... that makes it difficult to determine
     243              :      * whether the restore failed because there isn't an archive to restore,
     244              :      * or because the administrator has specified the restore program
     245              :      * incorrectly.  We have to assume the former.
     246              :      *
     247              :      * However, if the failure was due to any sort of signal, it's best to
     248              :      * punt and abort recovery.  (If we "return false" here, upper levels will
     249              :      * assume that recovery is complete and start up the database!) It's
     250              :      * essential to abort on child SIGINT and SIGQUIT, because per spec
     251              :      * system() ignores SIGINT and SIGQUIT while waiting; if we see one of
     252              :      * those it's a good bet we should have gotten it too.
     253              :      *
     254              :      * On SIGTERM, assume we have received a fast shutdown request, and exit
     255              :      * cleanly. It's pure chance whether we receive the SIGTERM first, or the
     256              :      * child process. If we receive it first, the signal handler will call
     257              :      * proc_exit, otherwise we do it here. If we or the child process received
     258              :      * SIGTERM for any other reason than a fast shutdown request, postmaster
     259              :      * will perform an immediate shutdown when it sees us exiting
     260              :      * unexpectedly.
     261              :      *
     262              :      * We treat hard shell errors such as "command not found" as fatal, too.
     263              :      */
     264          137 :     if (wait_result_is_signal(rc, SIGTERM))
     265            0 :         proc_exit(1);
     266              : 
     267          137 :     ereport(wait_result_is_any_signal(rc, true) ? FATAL : DEBUG2,
     268              :             (errmsg("could not restore file \"%s\" from archive: %s",
     269              :                     xlogfname, wait_result_to_str(rc))));
     270              : 
     271          137 : not_available:
     272              : 
     273              :     /*
     274              :      * if an archived file is not available, there might still be a version of
     275              :      * this file in XLOGDIR, so return that as the filename to open.
     276              :      *
     277              :      * In many recovery scenarios we expect this to fail also, but if so that
     278              :      * just means we've reached the end of WAL.
     279              :      */
     280          921 :     snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlogfname);
     281          921 :     return false;
     282              : }
     283              : 
     284              : /*
     285              :  * Attempt to execute an external shell command during recovery.
     286              :  *
     287              :  * 'command' is the shell command to be executed, 'commandName' is a
     288              :  * human-readable name describing the command emitted in the logs. If
     289              :  * 'failOnSignal' is true and the command is killed by a signal, a FATAL
     290              :  * error is thrown. Otherwise a WARNING is emitted.
     291              :  *
     292              :  * This is currently used for recovery_end_command and archive_cleanup_command.
     293              :  */
     294              : void
     295            2 : ExecuteRecoveryCommand(const char *command, const char *commandName,
     296              :                        bool failOnSignal, uint32 wait_event_info)
     297              : {
     298              :     char       *xlogRecoveryCmd;
     299              :     char        lastRestartPointFname[MAXPGPATH];
     300              :     int         rc;
     301              :     XLogSegNo   restartSegNo;
     302              :     XLogRecPtr  restartRedoPtr;
     303              :     TimeLineID  restartTli;
     304              : 
     305              :     Assert(command && commandName);
     306              : 
     307              :     /*
     308              :      * Calculate the archive file cutoff point for use during log shipping
     309              :      * replication. All files earlier than this point can be deleted from the
     310              :      * archive, though there is no requirement to do so.
     311              :      */
     312            2 :     GetOldestRestartPoint(&restartRedoPtr, &restartTli);
     313            2 :     XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
     314            2 :     XLogFileName(lastRestartPointFname, restartTli, restartSegNo,
     315              :                  wal_segment_size);
     316              : 
     317              :     /*
     318              :      * construct the command to be executed
     319              :      */
     320            2 :     xlogRecoveryCmd = replace_percent_placeholders(command, commandName, "r", lastRestartPointFname);
     321              : 
     322            2 :     ereport(DEBUG3,
     323              :             (errmsg_internal("executing %s \"%s\"", commandName, command)));
     324              : 
     325              :     /*
     326              :      * execute the constructed command
     327              :      */
     328            2 :     fflush(NULL);
     329            2 :     pgstat_report_wait_start(wait_event_info);
     330            2 :     rc = system(xlogRecoveryCmd);
     331            2 :     pgstat_report_wait_end();
     332              : 
     333            2 :     pfree(xlogRecoveryCmd);
     334              : 
     335            2 :     if (rc != 0)
     336              :     {
     337              :         /*
     338              :          * If the failure was due to any sort of signal, it's best to punt and
     339              :          * abort recovery.  See comments in RestoreArchivedFile().
     340              :          */
     341            1 :         ereport((failOnSignal && wait_result_is_any_signal(rc, true)) ? FATAL : WARNING,
     342              :         /*------
     343              :            translator: First %s represents a postgresql.conf parameter name like
     344              :           "recovery_end_command", the 2nd is the value of that parameter, the
     345              :           third an already translated error message. */
     346              :                 (errmsg("%s \"%s\": %s", commandName,
     347              :                         command, wait_result_to_str(rc))));
     348              :     }
     349            2 : }
     350              : 
     351              : 
     352              : /*
     353              :  * A file was restored from the archive under a temporary filename (path),
     354              :  * and now we want to keep it. Rename it under the permanent filename in
     355              :  * pg_wal (xlogfname), replacing any existing file with the same name.
     356              :  */
     357              : void
     358          366 : KeepFileRestoredFromArchive(const char *path, const char *xlogfname)
     359              : {
     360              :     char        xlogfpath[MAXPGPATH];
     361          366 :     bool        reload = false;
     362              :     struct stat statbuf;
     363              : 
     364          366 :     snprintf(xlogfpath, MAXPGPATH, XLOGDIR "/%s", xlogfname);
     365              : 
     366          366 :     if (stat(xlogfpath, &statbuf) == 0)
     367              :     {
     368              :         char        oldpath[MAXPGPATH];
     369              : 
     370              : #ifdef WIN32
     371              :         static unsigned int deletedcounter = 1;
     372              : 
     373              :         /*
     374              :          * On Windows, if another process (e.g a walsender process) holds the
     375              :          * file open in FILE_SHARE_DELETE mode, unlink will succeed, but the
     376              :          * file will still show up in directory listing until the last handle
     377              :          * is closed, and we cannot rename the new file in its place until
     378              :          * that. To avoid that problem, rename the old file to a temporary
     379              :          * name first. Use a counter to create a unique filename, because the
     380              :          * same file might be restored from the archive multiple times, and a
     381              :          * walsender could still be holding onto an old deleted version of it.
     382              :          */
     383              :         snprintf(oldpath, MAXPGPATH, "%s.deleted%u",
     384              :                  xlogfpath, deletedcounter++);
     385              :         if (rename(xlogfpath, oldpath) != 0)
     386              :         {
     387              :             ereport(ERROR,
     388              :                     (errcode_for_file_access(),
     389              :                      errmsg("could not rename file \"%s\" to \"%s\": %m",
     390              :                             xlogfpath, oldpath)));
     391              :         }
     392              : #else
     393              :         /* same-size buffers, so this never truncates */
     394           28 :         strlcpy(oldpath, xlogfpath, MAXPGPATH);
     395              : #endif
     396           28 :         if (unlink(oldpath) != 0)
     397            0 :             ereport(FATAL,
     398              :                     (errcode_for_file_access(),
     399              :                      errmsg("could not remove file \"%s\": %m",
     400              :                             xlogfpath)));
     401           28 :         reload = true;
     402              :     }
     403              : 
     404          366 :     durable_rename(path, xlogfpath, ERROR);
     405              : 
     406              :     /*
     407              :      * Create .done file forcibly to prevent the restored segment from being
     408              :      * archived again later.
     409              :      */
     410          366 :     if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
     411          365 :         XLogArchiveForceDone(xlogfname);
     412              :     else
     413            1 :         XLogArchiveNotify(xlogfname);
     414              : 
     415              :     /*
     416              :      * If the existing file was replaced, since walsenders might have it open,
     417              :      * request them to reload a currently-open segment. This is only required
     418              :      * for WAL segments, walsenders don't hold other files open, but there's
     419              :      * no harm in doing this too often, and we don't know what kind of a file
     420              :      * we're dealing with here.
     421              :      */
     422          366 :     if (reload)
     423           28 :         WalSndRqstFileReload();
     424              : 
     425              :     /*
     426              :      * Signal walsender that new WAL has arrived. Again, this isn't necessary
     427              :      * if we restored something other than a WAL segment, but it does no harm
     428              :      * either.
     429              :      */
     430          366 :     WalSndWakeup(true, false);
     431          366 : }
     432              : 
     433              : /*
     434              :  * XLogArchiveNotify
     435              :  *
     436              :  * Create an archive notification file
     437              :  *
     438              :  * The name of the notification file is the message that will be picked up
     439              :  * by the archiver, e.g. we write 0000000100000001000000C6.ready
     440              :  * and the archiver then knows to archive XLOGDIR/0000000100000001000000C6,
     441              :  * then when complete, rename it to 0000000100000001000000C6.done
     442              :  */
     443              : void
     444          467 : XLogArchiveNotify(const char *xlog)
     445              : {
     446              :     char        archiveStatusPath[MAXPGPATH];
     447              :     FILE       *fd;
     448              : 
     449              :     /* insert an otherwise empty file called <XLOG>.ready */
     450          467 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     451          467 :     fd = AllocateFile(archiveStatusPath, "w");
     452          467 :     if (fd == NULL)
     453              :     {
     454            0 :         ereport(LOG,
     455              :                 (errcode_for_file_access(),
     456              :                  errmsg("could not create archive status file \"%s\": %m",
     457              :                         archiveStatusPath)));
     458            0 :         return;
     459              :     }
     460          467 :     if (FreeFile(fd))
     461              :     {
     462            0 :         ereport(LOG,
     463              :                 (errcode_for_file_access(),
     464              :                  errmsg("could not write archive status file \"%s\": %m",
     465              :                         archiveStatusPath)));
     466            0 :         return;
     467              :     }
     468              : 
     469              :     /*
     470              :      * Timeline history files are given the highest archival priority to lower
     471              :      * the chance that a promoted standby will choose a timeline that is
     472              :      * already in use.  However, the archiver ordinarily tries to gather
     473              :      * multiple files to archive from each scan of the archive_status
     474              :      * directory, which means that newly created timeline history files could
     475              :      * be left unarchived for a while.  To ensure that the archiver picks up
     476              :      * timeline history files as soon as possible, we force the archiver to
     477              :      * scan the archive_status directory the next time it looks for a file to
     478              :      * archive.
     479              :      */
     480          467 :     if (IsTLHistoryFileName(xlog))
     481           14 :         PgArchForceDirScan();
     482              : 
     483              :     /* Notify archiver that it's got something to do */
     484          467 :     if (IsUnderPostmaster)
     485          467 :         PgArchWakeup();
     486              : }
     487              : 
     488              : /*
     489              :  * Convenience routine to notify using segment number representation of filename
     490              :  */
     491              : void
     492          410 : XLogArchiveNotifySeg(XLogSegNo segno, TimeLineID tli)
     493              : {
     494              :     char        xlog[MAXFNAMELEN];
     495              : 
     496              :     Assert(tli != 0);
     497              : 
     498          410 :     XLogFileName(xlog, tli, segno, wal_segment_size);
     499          410 :     XLogArchiveNotify(xlog);
     500          410 : }
     501              : 
     502              : /*
     503              :  * XLogArchiveForceDone
     504              :  *
     505              :  * Emit notification forcibly that an XLOG segment file has been successfully
     506              :  * archived, by creating <XLOG>.done regardless of whether <XLOG>.ready
     507              :  * exists or not.
     508              :  */
     509              : void
     510         1118 : XLogArchiveForceDone(const char *xlog)
     511              : {
     512              :     char        archiveReady[MAXPGPATH];
     513              :     char        archiveDone[MAXPGPATH];
     514              :     struct stat stat_buf;
     515              :     FILE       *fd;
     516              : 
     517              :     /* Exit if already known done */
     518         1118 :     StatusFilePath(archiveDone, xlog, ".done");
     519         1118 :     if (stat(archiveDone, &stat_buf) == 0)
     520           14 :         return;
     521              : 
     522              :     /* If .ready exists, rename it to .done */
     523         1104 :     StatusFilePath(archiveReady, xlog, ".ready");
     524         1104 :     if (stat(archiveReady, &stat_buf) == 0)
     525              :     {
     526            0 :         (void) durable_rename(archiveReady, archiveDone, WARNING);
     527            0 :         return;
     528              :     }
     529              : 
     530              :     /* insert an otherwise empty file called <XLOG>.done */
     531         1104 :     fd = AllocateFile(archiveDone, "w");
     532         1104 :     if (fd == NULL)
     533              :     {
     534            0 :         ereport(LOG,
     535              :                 (errcode_for_file_access(),
     536              :                  errmsg("could not create archive status file \"%s\": %m",
     537              :                         archiveDone)));
     538            0 :         return;
     539              :     }
     540         1104 :     if (FreeFile(fd))
     541              :     {
     542            0 :         ereport(LOG,
     543              :                 (errcode_for_file_access(),
     544              :                  errmsg("could not write archive status file \"%s\": %m",
     545              :                         archiveDone)));
     546            0 :         return;
     547              :     }
     548              : }
     549              : 
     550              : /*
     551              :  * XLogArchiveCheckDone
     552              :  *
     553              :  * This is called when we are ready to delete or recycle an old XLOG segment
     554              :  * file or backup history file.  If it is okay to delete it then return true.
     555              :  * If it is not time to delete it, make sure a .ready file exists, and return
     556              :  * false.
     557              :  *
     558              :  * If <XLOG>.done exists, then return true; else if <XLOG>.ready exists,
     559              :  * then return false; else create <XLOG>.ready and return false.
     560              :  *
     561              :  * The reason we do things this way is so that if the original attempt to
     562              :  * create <XLOG>.ready fails, we'll retry during subsequent checkpoints.
     563              :  */
     564              : bool
     565        23003 : XLogArchiveCheckDone(const char *xlog)
     566              : {
     567              :     char        archiveStatusPath[MAXPGPATH];
     568              :     struct stat stat_buf;
     569              : 
     570              :     /* The file is always deletable if archive_mode is "off". */
     571        23003 :     if (!XLogArchivingActive())
     572         2147 :         return true;
     573              : 
     574              :     /*
     575              :      * During archive recovery, the file is deletable if archive_mode is not
     576              :      * "always".
     577              :      */
     578        41707 :     if (!XLogArchivingAlways() &&
     579        20851 :         GetRecoveryState() == RECOVERY_STATE_ARCHIVE)
     580          323 :         return true;
     581              : 
     582              :     /*
     583              :      * At this point of the logic, note that we are either a primary with
     584              :      * archive_mode set to "on" or "always", or a standby with archive_mode
     585              :      * set to "always".
     586              :      */
     587              : 
     588              :     /* First check for .done --- this means archiver is done with it */
     589        20533 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     590        20533 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     591          223 :         return true;
     592              : 
     593              :     /* check for .ready --- this means archiver is still busy with it */
     594        20310 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     595        20310 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     596        20273 :         return false;
     597              : 
     598              :     /* Race condition --- maybe archiver just finished, so recheck */
     599           37 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     600           37 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     601            0 :         return true;
     602              : 
     603              :     /* Retry creation of the .ready file */
     604           37 :     XLogArchiveNotify(xlog);
     605           37 :     return false;
     606              : }
     607              : 
     608              : /*
     609              :  * XLogArchiveIsBusy
     610              :  *
     611              :  * Check to see if an XLOG segment file is still unarchived.
     612              :  * This is almost but not quite the inverse of XLogArchiveCheckDone: in
     613              :  * the first place we aren't chartered to recreate the .ready file, and
     614              :  * in the second place we should consider that if the file is already gone
     615              :  * then it's not busy.  (This check is needed to handle the race condition
     616              :  * that a checkpoint already deleted the no-longer-needed file.)
     617              :  */
     618              : bool
     619           12 : XLogArchiveIsBusy(const char *xlog)
     620              : {
     621              :     char        archiveStatusPath[MAXPGPATH];
     622              :     struct stat stat_buf;
     623              : 
     624              :     /* First check for .done --- this means archiver is done with it */
     625           12 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     626           12 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     627            8 :         return false;
     628              : 
     629              :     /* check for .ready --- this means archiver is still busy with it */
     630            4 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     631            4 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     632            4 :         return true;
     633              : 
     634              :     /* Race condition --- maybe archiver just finished, so recheck */
     635            0 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     636            0 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     637            0 :         return false;
     638              : 
     639              :     /*
     640              :      * Check to see if the WAL file has been removed by checkpoint, which
     641              :      * implies it has already been archived, and explains why we can't see a
     642              :      * status file for it.
     643              :      */
     644            0 :     snprintf(archiveStatusPath, MAXPGPATH, XLOGDIR "/%s", xlog);
     645            0 :     if (stat(archiveStatusPath, &stat_buf) != 0 &&
     646            0 :         errno == ENOENT)
     647            0 :         return false;
     648              : 
     649            0 :     return true;
     650              : }
     651              : 
     652              : /*
     653              :  * XLogArchiveIsReadyOrDone
     654              :  *
     655              :  * Check to see if an XLOG segment file has a .ready or .done file.
     656              :  * This is similar to XLogArchiveIsBusy(), but returns true if the file
     657              :  * is already archived or is about to be archived.
     658              :  *
     659              :  * This is currently only used at recovery.  During normal operation this
     660              :  * would be racy: the file might get removed or marked with .ready as we're
     661              :  * checking it, or immediately after we return.
     662              :  */
     663              : bool
     664            9 : XLogArchiveIsReadyOrDone(const char *xlog)
     665              : {
     666              :     char        archiveStatusPath[MAXPGPATH];
     667              :     struct stat stat_buf;
     668              : 
     669              :     /* First check for .done --- this means archiver is done with it */
     670            9 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     671            9 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     672            4 :         return true;
     673              : 
     674              :     /* check for .ready --- this means archiver is still busy with it */
     675            5 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     676            5 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     677            0 :         return true;
     678              : 
     679              :     /* Race condition --- maybe archiver just finished, so recheck */
     680            5 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     681            5 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     682            0 :         return true;
     683              : 
     684            5 :     return false;
     685              : }
     686              : 
     687              : /*
     688              :  * XLogArchiveIsReady
     689              :  *
     690              :  * Check to see if an XLOG segment file has an archive notification (.ready)
     691              :  * file.
     692              :  */
     693              : bool
     694           16 : XLogArchiveIsReady(const char *xlog)
     695              : {
     696              :     char        archiveStatusPath[MAXPGPATH];
     697              :     struct stat stat_buf;
     698              : 
     699           16 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     700           16 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     701            0 :         return true;
     702              : 
     703           16 :     return false;
     704              : }
     705              : 
     706              : /*
     707              :  * XLogArchiveCleanup
     708              :  *
     709              :  * Cleanup archive notification file(s) for a particular xlog segment
     710              :  */
     711              : void
     712         2768 : XLogArchiveCleanup(const char *xlog)
     713              : {
     714              :     char        archiveStatusPath[MAXPGPATH];
     715              : 
     716              :     /* Remove the .done file */
     717         2768 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     718         2768 :     unlink(archiveStatusPath);
     719              :     /* should we complain about failure? */
     720              : 
     721              :     /* Remove the .ready file if present --- normally it shouldn't be */
     722         2768 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     723         2768 :     unlink(archiveStatusPath);
     724              :     /* should we complain about failure? */
     725         2768 : }
        

Generated by: LCOV version 2.0-1