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

Generated by: LCOV version 2.0-1