LCOV - code coverage report
Current view: top level - src/backend/access/transam - xlogarchive.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 127 160 79.4 %
Date: 2024-12-12 20:14:52 Functions: 11 11 100.0 %
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-2024, 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        1634 : 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        1634 :     if (!ArchiveRecoveryRequested)
      72          46 :         goto not_available;
      73             : 
      74             :     /* In standby mode, restore_command might not be supplied */
      75        1588 :     if (recoveryRestoreCommand == NULL || strcmp(recoveryRestoreCommand, "") == 0)
      76        1216 :         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         372 :     snprintf(xlogpath, MAXPGPATH, XLOGDIR "/%s", recovername);
     102             : 
     103             :     /*
     104             :      * Make sure there is no existing file named recovername.
     105             :      */
     106         372 :     if (stat(xlogpath, &stat_buf) != 0)
     107             :     {
     108         364 :         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           8 :         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         372 :     if (cleanupEnabled)
     141             :     {
     142         136 :         GetOldestRestartPoint(&restartRedoPtr, &restartTli);
     143         136 :         XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
     144         136 :         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         236 :         XLogFileName(lastRestartPointFname, 0, 0, wal_segment_size);
     151             : 
     152             :     /* Build the restore command to execute */
     153         372 :     xlogRestoreCmd = BuildRestoreCommand(recoveryRestoreCommand,
     154             :                                          xlogpath, xlogfname,
     155             :                                          lastRestartPointFname);
     156             : 
     157         372 :     ereport(DEBUG3,
     158             :             (errmsg_internal("executing restore command \"%s\"",
     159             :                              xlogRestoreCmd)));
     160             : 
     161         372 :     fflush(NULL);
     162         372 :     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         372 :     PreRestoreCommand();
     173             : 
     174             :     /*
     175             :      * Copy xlog from archival storage to XLOGDIR
     176             :      */
     177         372 :     rc = system(xlogRestoreCmd);
     178             : 
     179         372 :     PostRestoreCommand();
     180             : 
     181         372 :     pgstat_report_wait_end();
     182         372 :     pfree(xlogRestoreCmd);
     183             : 
     184         372 :     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          88 :         if (stat(xlogpath, &stat_buf) == 0)
     191             :         {
     192          88 :             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          88 :                 ereport(LOG,
     222             :                         (errmsg("restored log file \"%s\" from archive",
     223             :                                 xlogfname)));
     224          88 :                 strcpy(path, xlogpath);
     225          88 :                 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         284 :     if (wait_result_is_signal(rc, SIGTERM))
     265           0 :         proc_exit(1);
     266             : 
     267         284 :     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         284 : 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        1546 :     snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlogfname);
     281        1546 :     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           4 : 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           4 :     GetOldestRestartPoint(&restartRedoPtr, &restartTli);
     313           4 :     XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
     314           4 :     XLogFileName(lastRestartPointFname, restartTli, restartSegNo,
     315             :                  wal_segment_size);
     316             : 
     317             :     /*
     318             :      * construct the command to be executed
     319             :      */
     320           4 :     xlogRecoveryCmd = replace_percent_placeholders(command, commandName, "r", lastRestartPointFname);
     321             : 
     322           4 :     ereport(DEBUG3,
     323             :             (errmsg_internal("executing %s \"%s\"", commandName, command)));
     324             : 
     325             :     /*
     326             :      * execute the constructed command
     327             :      */
     328           4 :     fflush(NULL);
     329           4 :     pgstat_report_wait_start(wait_event_info);
     330           4 :     rc = system(xlogRecoveryCmd);
     331           4 :     pgstat_report_wait_end();
     332             : 
     333           4 :     pfree(xlogRecoveryCmd);
     334             : 
     335           4 :     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           2 :         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           4 : }
     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          74 : KeepFileRestoredFromArchive(const char *path, const char *xlogfname)
     359             : {
     360             :     char        xlogfpath[MAXPGPATH];
     361          74 :     bool        reload = false;
     362             :     struct stat statbuf;
     363             : 
     364          74 :     snprintf(xlogfpath, MAXPGPATH, XLOGDIR "/%s", xlogfname);
     365             : 
     366          74 :     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          40 :         strlcpy(oldpath, xlogfpath, MAXPGPATH);
     395             : #endif
     396          40 :         if (unlink(oldpath) != 0)
     397           0 :             ereport(FATAL,
     398             :                     (errcode_for_file_access(),
     399             :                      errmsg("could not remove file \"%s\": %m",
     400             :                             xlogfpath)));
     401          40 :         reload = true;
     402             :     }
     403             : 
     404          74 :     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          74 :     if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
     411          72 :         XLogArchiveForceDone(xlogfname);
     412             :     else
     413           2 :         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          74 :     if (reload)
     423          40 :         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          74 :     WalSndWakeup(true, false);
     431          74 : }
     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         256 : XLogArchiveNotify(const char *xlog)
     445             : {
     446             :     char        archiveStatusPath[MAXPGPATH];
     447             :     FILE       *fd;
     448             : 
     449             :     /* insert an otherwise empty file called <XLOG>.ready */
     450         256 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     451         256 :     fd = AllocateFile(archiveStatusPath, "w");
     452         256 :     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         256 :     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         256 :     if (IsTLHistoryFileName(xlog))
     481          26 :         PgArchForceDirScan();
     482             : 
     483             :     /* Notify archiver that it's got something to do */
     484         256 :     if (IsUnderPostmaster)
     485         256 :         PgArchWakeup();
     486             : }
     487             : 
     488             : /*
     489             :  * Convenience routine to notify using segment number representation of filename
     490             :  */
     491             : void
     492         156 : XLogArchiveNotifySeg(XLogSegNo segno, TimeLineID tli)
     493             : {
     494             :     char        xlog[MAXFNAMELEN];
     495             : 
     496             :     Assert(tli != 0);
     497             : 
     498         156 :     XLogFileName(xlog, tli, segno, wal_segment_size);
     499         156 :     XLogArchiveNotify(xlog);
     500         156 : }
     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        1484 : 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        1484 :     StatusFilePath(archiveDone, xlog, ".done");
     519        1484 :     if (stat(archiveDone, &stat_buf) == 0)
     520          16 :         return;
     521             : 
     522             :     /* If .ready exists, rename it to .done */
     523        1468 :     StatusFilePath(archiveReady, xlog, ".ready");
     524        1468 :     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        1468 :     fd = AllocateFile(archiveDone, "w");
     532        1468 :     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        1468 :     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        4104 : 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        4104 :     if (!XLogArchivingActive())
     572        3982 :         return true;
     573             : 
     574             :     /*
     575             :      * During archive recovery, the file is deletable if archive_mode is not
     576             :      * "always".
     577             :      */
     578         234 :     if (!XLogArchivingAlways() &&
     579         112 :         GetRecoveryState() == RECOVERY_STATE_ARCHIVE)
     580           6 :         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         116 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     590         116 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     591          40 :         return true;
     592             : 
     593             :     /* check for .ready --- this means archiver is still busy with it */
     594          76 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     595          76 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     596          14 :         return false;
     597             : 
     598             :     /* Race condition --- maybe archiver just finished, so recheck */
     599          62 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     600          62 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     601           0 :         return true;
     602             : 
     603             :     /* Retry creation of the .ready file */
     604          62 :     XLogArchiveNotify(xlog);
     605          62 :     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          18 : 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          18 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     626          18 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     627          12 :         return false;
     628             : 
     629             :     /* check for .ready --- this means archiver is still busy with it */
     630           6 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     631           6 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     632           6 :         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          16 : 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          16 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     671          16 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     672           6 :         return true;
     673             : 
     674             :     /* check for .ready --- this means archiver is still busy with it */
     675          10 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     676          10 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     677           0 :         return true;
     678             : 
     679             :     /* Race condition --- maybe archiver just finished, so recheck */
     680          10 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     681          10 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     682           0 :         return true;
     683             : 
     684          10 :     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          32 : XLogArchiveIsReady(const char *xlog)
     695             : {
     696             :     char        archiveStatusPath[MAXPGPATH];
     697             :     struct stat stat_buf;
     698             : 
     699          32 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     700          32 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     701           0 :         return true;
     702             : 
     703          32 :     return false;
     704             : }
     705             : 
     706             : /*
     707             :  * XLogArchiveCleanup
     708             :  *
     709             :  * Cleanup archive notification file(s) for a particular xlog segment
     710             :  */
     711             : void
     712        4166 : XLogArchiveCleanup(const char *xlog)
     713             : {
     714             :     char        archiveStatusPath[MAXPGPATH];
     715             : 
     716             :     /* Remove the .done file */
     717        4166 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     718        4166 :     unlink(archiveStatusPath);
     719             :     /* should we complain about failure? */
     720             : 
     721             :     /* Remove the .ready file if present --- normally it shouldn't be */
     722        4166 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     723        4166 :     unlink(archiveStatusPath);
     724             :     /* should we complain about failure? */
     725        4166 : }

Generated by: LCOV version 1.14