LCOV - code coverage report
Current view: top level - src/backend/access/transam - xlogarchive.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 120 194 61.9 %
Date: 2019-11-13 22:07:24 Functions: 10 11 90.9 %
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-2019, 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 "miscadmin.h"
      25             : #include "postmaster/startup.h"
      26             : #include "replication/walsender.h"
      27             : #include "storage/fd.h"
      28             : #include "storage/ipc.h"
      29             : #include "storage/lwlock.h"
      30             : #include "storage/pmsignal.h"
      31             : 
      32             : /*
      33             :  * Attempt to retrieve the specified file from off-line archival storage.
      34             :  * If successful, fill "path" with its complete path (note that this will be
      35             :  * a temp file name that doesn't follow the normal naming convention), and
      36             :  * return true.
      37             :  *
      38             :  * If not successful, fill "path" with the name of the normal on-line file
      39             :  * (which may or may not actually exist, but we'll try to use it), and return
      40             :  * false.
      41             :  *
      42             :  * For fixed-size files, the caller may pass the expected size as an
      43             :  * additional crosscheck on successful recovery.  If the file size is not
      44             :  * known, set expectedSize = 0.
      45             :  *
      46             :  * When 'cleanupEnabled' is false, refrain from deleting any old WAL segments
      47             :  * in the archive. This is used when fetching the initial checkpoint record,
      48             :  * when we are not yet sure how far back we need the WAL.
      49             :  */
      50             : bool
      51         698 : RestoreArchivedFile(char *path, const char *xlogfname,
      52             :                     const char *recovername, off_t expectedSize,
      53             :                     bool cleanupEnabled)
      54             : {
      55             :     char        xlogpath[MAXPGPATH];
      56             :     char        xlogRestoreCmd[MAXPGPATH];
      57             :     char        lastRestartPointFname[MAXPGPATH];
      58             :     char       *dp;
      59             :     char       *endp;
      60             :     const char *sp;
      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
      69             :      * we are in crash recovery).
      70             :      */
      71         698 :     if (!ArchiveRecoveryRequested)
      72           0 :         goto not_available;
      73             : 
      74             :     /* In standby mode, restore_command might not be supplied */
      75         698 :     if (recoveryRestoreCommand == NULL || strcmp(recoveryRestoreCommand, "") == 0)
      76             :         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         116 :     snprintf(xlogpath, MAXPGPATH, XLOGDIR "/%s", recovername);
     102             : 
     103             :     /*
     104             :      * Make sure there is no existing file named recovername.
     105             :      */
     106         116 :     if (stat(xlogpath, &stat_buf) != 0)
     107             :     {
     108         112 :         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         116 :     if (cleanupEnabled)
     141             :     {
     142          48 :         GetOldestRestartPoint(&restartRedoPtr, &restartTli);
     143          48 :         XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
     144          48 :         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          68 :         XLogFileName(lastRestartPointFname, 0, 0L, wal_segment_size);
     151             : 
     152             :     /*
     153             :      * construct the command to be executed
     154             :      */
     155         116 :     dp = xlogRestoreCmd;
     156         116 :     endp = xlogRestoreCmd + MAXPGPATH - 1;
     157         116 :     *endp = '\0';
     158             : 
     159       12288 :     for (sp = recoveryRestoreCommand; *sp; sp++)
     160             :     {
     161       12172 :         if (*sp == '%')
     162             :         {
     163         232 :             switch (sp[1])
     164             :             {
     165             :                 case 'p':
     166             :                     /* %p: relative path of target file */
     167         116 :                     sp++;
     168         116 :                     StrNCpy(dp, xlogpath, endp - dp);
     169         116 :                     make_native_path(dp);
     170         116 :                     dp += strlen(dp);
     171         116 :                     break;
     172             :                 case 'f':
     173             :                     /* %f: filename of desired file */
     174         116 :                     sp++;
     175         116 :                     StrNCpy(dp, xlogfname, endp - dp);
     176         116 :                     dp += strlen(dp);
     177         116 :                     break;
     178             :                 case 'r':
     179             :                     /* %r: filename of last restartpoint */
     180           0 :                     sp++;
     181           0 :                     StrNCpy(dp, lastRestartPointFname, endp - dp);
     182           0 :                     dp += strlen(dp);
     183           0 :                     break;
     184             :                 case '%':
     185             :                     /* convert %% to a single % */
     186           0 :                     sp++;
     187           0 :                     if (dp < endp)
     188           0 :                         *dp++ = *sp;
     189           0 :                     break;
     190             :                 default:
     191             :                     /* otherwise treat the % as not special */
     192           0 :                     if (dp < endp)
     193           0 :                         *dp++ = *sp;
     194           0 :                     break;
     195             :             }
     196             :         }
     197             :         else
     198             :         {
     199       11940 :             if (dp < endp)
     200       11940 :                 *dp++ = *sp;
     201             :         }
     202             :     }
     203         116 :     *dp = '\0';
     204             : 
     205         116 :     ereport(DEBUG3,
     206             :             (errmsg_internal("executing restore command \"%s\"",
     207             :                              xlogRestoreCmd)));
     208             : 
     209             :     /*
     210             :      * Check signals before restore command and reset afterwards.
     211             :      */
     212         116 :     PreRestoreCommand();
     213             : 
     214             :     /*
     215             :      * Copy xlog from archival storage to XLOGDIR
     216             :      */
     217         116 :     rc = system(xlogRestoreCmd);
     218             : 
     219         116 :     PostRestoreCommand();
     220             : 
     221         116 :     if (rc == 0)
     222             :     {
     223             :         /*
     224             :          * command apparently succeeded, but let's make sure the file is
     225             :          * really there now and has the correct size.
     226             :          */
     227          22 :         if (stat(xlogpath, &stat_buf) == 0)
     228             :         {
     229          22 :             if (expectedSize > 0 && stat_buf.st_size != expectedSize)
     230             :             {
     231             :                 int         elevel;
     232             : 
     233             :                 /*
     234             :                  * If we find a partial file in standby mode, we assume it's
     235             :                  * because it's just being copied to the archive, and keep
     236             :                  * trying.
     237             :                  *
     238             :                  * Otherwise treat a wrong-sized file as FATAL to ensure the
     239             :                  * DBA would notice it, but is that too strong? We could try
     240             :                  * to plow ahead with a local copy of the file ... but the
     241             :                  * problem is that there probably isn't one, and we'd
     242             :                  * incorrectly conclude we've reached the end of WAL and we're
     243             :                  * done recovering ...
     244             :                  */
     245           2 :                 if (StandbyMode && stat_buf.st_size < expectedSize)
     246           2 :                     elevel = DEBUG1;
     247             :                 else
     248           0 :                     elevel = FATAL;
     249           2 :                 ereport(elevel,
     250             :                         (errmsg("archive file \"%s\" has wrong size: %lu instead of %lu",
     251             :                                 xlogfname,
     252             :                                 (unsigned long) stat_buf.st_size,
     253             :                                 (unsigned long) expectedSize)));
     254           2 :                 return false;
     255             :             }
     256             :             else
     257             :             {
     258          20 :                 ereport(LOG,
     259             :                         (errmsg("restored log file \"%s\" from archive",
     260             :                                 xlogfname)));
     261          20 :                 strcpy(path, xlogpath);
     262          20 :                 return true;
     263             :             }
     264             :         }
     265             :         else
     266             :         {
     267             :             /* stat failed */
     268           0 :             if (errno != ENOENT)
     269           0 :                 ereport(FATAL,
     270             :                         (errcode_for_file_access(),
     271             :                          errmsg("could not stat file \"%s\": %m",
     272             :                                 xlogpath)));
     273             :         }
     274             :     }
     275             : 
     276             :     /*
     277             :      * Remember, we rollforward UNTIL the restore fails so failure here is
     278             :      * just part of the process... that makes it difficult to determine
     279             :      * whether the restore failed because there isn't an archive to restore,
     280             :      * or because the administrator has specified the restore program
     281             :      * incorrectly.  We have to assume the former.
     282             :      *
     283             :      * However, if the failure was due to any sort of signal, it's best to
     284             :      * punt and abort recovery.  (If we "return false" here, upper levels will
     285             :      * assume that recovery is complete and start up the database!) It's
     286             :      * essential to abort on child SIGINT and SIGQUIT, because per spec
     287             :      * system() ignores SIGINT and SIGQUIT while waiting; if we see one of
     288             :      * those it's a good bet we should have gotten it too.
     289             :      *
     290             :      * On SIGTERM, assume we have received a fast shutdown request, and exit
     291             :      * cleanly. It's pure chance whether we receive the SIGTERM first, or the
     292             :      * child process. If we receive it first, the signal handler will call
     293             :      * proc_exit, otherwise we do it here. If we or the child process received
     294             :      * SIGTERM for any other reason than a fast shutdown request, postmaster
     295             :      * will perform an immediate shutdown when it sees us exiting
     296             :      * unexpectedly.
     297             :      *
     298             :      * We treat hard shell errors such as "command not found" as fatal, too.
     299             :      */
     300          94 :     if (wait_result_is_signal(rc, SIGTERM))
     301           0 :         proc_exit(1);
     302             : 
     303          94 :     ereport(wait_result_is_any_signal(rc, true) ? FATAL : DEBUG2,
     304             :             (errmsg("could not restore file \"%s\" from archive: %s",
     305             :                     xlogfname, wait_result_to_str(rc))));
     306             : 
     307             : not_available:
     308             : 
     309             :     /*
     310             :      * if an archived file is not available, there might still be a version of
     311             :      * this file in XLOGDIR, so return that as the filename to open.
     312             :      *
     313             :      * In many recovery scenarios we expect this to fail also, but if so that
     314             :      * just means we've reached the end of WAL.
     315             :      */
     316         676 :     snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlogfname);
     317         676 :     return false;
     318             : }
     319             : 
     320             : /*
     321             :  * Attempt to execute an external shell command during recovery.
     322             :  *
     323             :  * 'command' is the shell command to be executed, 'commandName' is a
     324             :  * human-readable name describing the command emitted in the logs. If
     325             :  * 'failOnSignal' is true and the command is killed by a signal, a FATAL
     326             :  * error is thrown. Otherwise a WARNING is emitted.
     327             :  *
     328             :  * This is currently used for recovery_end_command and archive_cleanup_command.
     329             :  */
     330             : void
     331           0 : ExecuteRecoveryCommand(const char *command, const char *commandName, bool failOnSignal)
     332             : {
     333             :     char        xlogRecoveryCmd[MAXPGPATH];
     334             :     char        lastRestartPointFname[MAXPGPATH];
     335             :     char       *dp;
     336             :     char       *endp;
     337             :     const char *sp;
     338             :     int         rc;
     339             :     XLogSegNo   restartSegNo;
     340             :     XLogRecPtr  restartRedoPtr;
     341             :     TimeLineID  restartTli;
     342             : 
     343             :     Assert(command && commandName);
     344             : 
     345             :     /*
     346             :      * Calculate the archive file cutoff point for use during log shipping
     347             :      * replication. All files earlier than this point can be deleted from the
     348             :      * archive, though there is no requirement to do so.
     349             :      */
     350           0 :     GetOldestRestartPoint(&restartRedoPtr, &restartTli);
     351           0 :     XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
     352           0 :     XLogFileName(lastRestartPointFname, restartTli, restartSegNo,
     353             :                  wal_segment_size);
     354             : 
     355             :     /*
     356             :      * construct the command to be executed
     357             :      */
     358           0 :     dp = xlogRecoveryCmd;
     359           0 :     endp = xlogRecoveryCmd + MAXPGPATH - 1;
     360           0 :     *endp = '\0';
     361             : 
     362           0 :     for (sp = command; *sp; sp++)
     363             :     {
     364           0 :         if (*sp == '%')
     365             :         {
     366           0 :             switch (sp[1])
     367             :             {
     368             :                 case 'r':
     369             :                     /* %r: filename of last restartpoint */
     370           0 :                     sp++;
     371           0 :                     StrNCpy(dp, lastRestartPointFname, endp - dp);
     372           0 :                     dp += strlen(dp);
     373           0 :                     break;
     374             :                 case '%':
     375             :                     /* convert %% to a single % */
     376           0 :                     sp++;
     377           0 :                     if (dp < endp)
     378           0 :                         *dp++ = *sp;
     379           0 :                     break;
     380             :                 default:
     381             :                     /* otherwise treat the % as not special */
     382           0 :                     if (dp < endp)
     383           0 :                         *dp++ = *sp;
     384           0 :                     break;
     385             :             }
     386             :         }
     387             :         else
     388             :         {
     389           0 :             if (dp < endp)
     390           0 :                 *dp++ = *sp;
     391             :         }
     392             :     }
     393           0 :     *dp = '\0';
     394             : 
     395           0 :     ereport(DEBUG3,
     396             :             (errmsg_internal("executing %s \"%s\"", commandName, command)));
     397             : 
     398             :     /*
     399             :      * execute the constructed command
     400             :      */
     401           0 :     rc = system(xlogRecoveryCmd);
     402           0 :     if (rc != 0)
     403             :     {
     404             :         /*
     405             :          * If the failure was due to any sort of signal, it's best to punt and
     406             :          * abort recovery.  See comments in RestoreArchivedFile().
     407             :          */
     408           0 :         ereport((failOnSignal && wait_result_is_any_signal(rc, true)) ? FATAL : WARNING,
     409             :         /*------
     410             :            translator: First %s represents a postgresql.conf parameter name like
     411             :           "recovery_end_command", the 2nd is the value of that parameter, the
     412             :           third an already translated error message. */
     413             :                 (errmsg("%s \"%s\": %s", commandName,
     414             :                         command, wait_result_to_str(rc))));
     415             :     }
     416           0 : }
     417             : 
     418             : 
     419             : /*
     420             :  * A file was restored from the archive under a temporary filename (path),
     421             :  * and now we want to keep it. Rename it under the permanent filename in
     422             :  * pg_wal (xlogfname), replacing any existing file with the same name.
     423             :  */
     424             : void
     425          16 : KeepFileRestoredFromArchive(const char *path, const char *xlogfname)
     426             : {
     427             :     char        xlogfpath[MAXPGPATH];
     428          16 :     bool        reload = false;
     429             :     struct stat statbuf;
     430             : 
     431          16 :     snprintf(xlogfpath, MAXPGPATH, XLOGDIR "/%s", xlogfname);
     432             : 
     433          16 :     if (stat(xlogfpath, &statbuf) == 0)
     434             :     {
     435             :         char        oldpath[MAXPGPATH];
     436             : 
     437             : #ifdef WIN32
     438             :         static unsigned int deletedcounter = 1;
     439             : 
     440             :         /*
     441             :          * On Windows, if another process (e.g a walsender process) holds the
     442             :          * file open in FILE_SHARE_DELETE mode, unlink will succeed, but the
     443             :          * file will still show up in directory listing until the last handle
     444             :          * is closed, and we cannot rename the new file in its place until
     445             :          * that. To avoid that problem, rename the old file to a temporary
     446             :          * name first. Use a counter to create a unique filename, because the
     447             :          * same file might be restored from the archive multiple times, and a
     448             :          * walsender could still be holding onto an old deleted version of it.
     449             :          */
     450             :         snprintf(oldpath, MAXPGPATH, "%s.deleted%u",
     451             :                  xlogfpath, deletedcounter++);
     452             :         if (rename(xlogfpath, oldpath) != 0)
     453             :         {
     454             :             ereport(ERROR,
     455             :                     (errcode_for_file_access(),
     456             :                      errmsg("could not rename file \"%s\" to \"%s\": %m",
     457             :                             xlogfpath, oldpath)));
     458             :         }
     459             : #else
     460             :         /* same-size buffers, so this never truncates */
     461          10 :         strlcpy(oldpath, xlogfpath, MAXPGPATH);
     462             : #endif
     463          10 :         if (unlink(oldpath) != 0)
     464           0 :             ereport(FATAL,
     465             :                     (errcode_for_file_access(),
     466             :                      errmsg("could not remove file \"%s\": %m",
     467             :                             xlogfpath)));
     468          10 :         reload = true;
     469             :     }
     470             : 
     471          16 :     durable_rename(path, xlogfpath, ERROR);
     472             : 
     473             :     /*
     474             :      * Create .done file forcibly to prevent the restored segment from being
     475             :      * archived again later.
     476             :      */
     477          16 :     if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
     478          16 :         XLogArchiveForceDone(xlogfname);
     479             :     else
     480           0 :         XLogArchiveNotify(xlogfname);
     481             : 
     482             :     /*
     483             :      * If the existing file was replaced, since walsenders might have it open,
     484             :      * request them to reload a currently-open segment. This is only required
     485             :      * for WAL segments, walsenders don't hold other files open, but there's
     486             :      * no harm in doing this too often, and we don't know what kind of a file
     487             :      * we're dealing with here.
     488             :      */
     489          16 :     if (reload)
     490          10 :         WalSndRqstFileReload();
     491             : 
     492             :     /*
     493             :      * Signal walsender that new WAL has arrived. Again, this isn't necessary
     494             :      * if we restored something other than a WAL segment, but it does no harm
     495             :      * either.
     496             :      */
     497          16 :     WalSndWakeup();
     498          16 : }
     499             : 
     500             : /*
     501             :  * XLogArchiveNotify
     502             :  *
     503             :  * Create an archive notification file
     504             :  *
     505             :  * The name of the notification file is the message that will be picked up
     506             :  * by the archiver, e.g. we write 0000000100000001000000C6.ready
     507             :  * and the archiver then knows to archive XLOGDIR/0000000100000001000000C6,
     508             :  * then when complete, rename it to 0000000100000001000000C6.done
     509             :  */
     510             : void
     511          30 : XLogArchiveNotify(const char *xlog)
     512             : {
     513             :     char        archiveStatusPath[MAXPGPATH];
     514             :     FILE       *fd;
     515             : 
     516             :     /* insert an otherwise empty file called <XLOG>.ready */
     517          30 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     518          30 :     fd = AllocateFile(archiveStatusPath, "w");
     519          30 :     if (fd == NULL)
     520             :     {
     521           0 :         ereport(LOG,
     522             :                 (errcode_for_file_access(),
     523             :                  errmsg("could not create archive status file \"%s\": %m",
     524             :                         archiveStatusPath)));
     525           0 :         return;
     526             :     }
     527          30 :     if (FreeFile(fd))
     528             :     {
     529           0 :         ereport(LOG,
     530             :                 (errcode_for_file_access(),
     531             :                  errmsg("could not write archive status file \"%s\": %m",
     532             :                         archiveStatusPath)));
     533           0 :         return;
     534             :     }
     535             : 
     536             :     /* Notify archiver that it's got something to do */
     537          30 :     if (IsUnderPostmaster)
     538          30 :         SendPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER);
     539             : }
     540             : 
     541             : /*
     542             :  * Convenience routine to notify using segment number representation of filename
     543             :  */
     544             : void
     545          16 : XLogArchiveNotifySeg(XLogSegNo segno)
     546             : {
     547             :     char        xlog[MAXFNAMELEN];
     548             : 
     549          16 :     XLogFileName(xlog, ThisTimeLineID, segno, wal_segment_size);
     550          16 :     XLogArchiveNotify(xlog);
     551          16 : }
     552             : 
     553             : /*
     554             :  * XLogArchiveForceDone
     555             :  *
     556             :  * Emit notification forcibly that an XLOG segment file has been successfully
     557             :  * archived, by creating <XLOG>.done regardless of whether <XLOG>.ready
     558             :  * exists or not.
     559             :  */
     560             : void
     561          26 : XLogArchiveForceDone(const char *xlog)
     562             : {
     563             :     char        archiveReady[MAXPGPATH];
     564             :     char        archiveDone[MAXPGPATH];
     565             :     struct stat stat_buf;
     566             :     FILE       *fd;
     567             : 
     568             :     /* Exit if already known done */
     569          26 :     StatusFilePath(archiveDone, xlog, ".done");
     570          26 :     if (stat(archiveDone, &stat_buf) == 0)
     571           8 :         return;
     572             : 
     573             :     /* If .ready exists, rename it to .done */
     574          22 :     StatusFilePath(archiveReady, xlog, ".ready");
     575          22 :     if (stat(archiveReady, &stat_buf) == 0)
     576             :     {
     577           0 :         (void) durable_rename(archiveReady, archiveDone, WARNING);
     578           0 :         return;
     579             :     }
     580             : 
     581             :     /* insert an otherwise empty file called <XLOG>.done */
     582          22 :     fd = AllocateFile(archiveDone, "w");
     583          22 :     if (fd == NULL)
     584             :     {
     585           0 :         ereport(LOG,
     586             :                 (errcode_for_file_access(),
     587             :                  errmsg("could not create archive status file \"%s\": %m",
     588             :                         archiveDone)));
     589           0 :         return;
     590             :     }
     591          22 :     if (FreeFile(fd))
     592             :     {
     593           0 :         ereport(LOG,
     594             :                 (errcode_for_file_access(),
     595             :                  errmsg("could not write archive status file \"%s\": %m",
     596             :                         archiveDone)));
     597           0 :         return;
     598             :     }
     599             : }
     600             : 
     601             : /*
     602             :  * XLogArchiveCheckDone
     603             :  *
     604             :  * This is called when we are ready to delete or recycle an old XLOG segment
     605             :  * file or backup history file.  If it is okay to delete it then return true.
     606             :  * If it is not time to delete it, make sure a .ready file exists, and return
     607             :  * false.
     608             :  *
     609             :  * If <XLOG>.done exists, then return true; else if <XLOG>.ready exists,
     610             :  * then return false; else create <XLOG>.ready and return false.
     611             :  *
     612             :  * The reason we do things this way is so that if the original attempt to
     613             :  * create <XLOG>.ready fails, we'll retry during subsequent checkpoints.
     614             :  */
     615             : bool
     616         710 : XLogArchiveCheckDone(const char *xlog)
     617             : {
     618             :     char        archiveStatusPath[MAXPGPATH];
     619             :     struct stat stat_buf;
     620         710 :     bool        inRecovery = RecoveryInProgress();
     621             : 
     622             :     /*
     623             :      * The file is always deletable if archive_mode is "off".  On standbys
     624             :      * archiving is disabled if archive_mode is "on", and enabled with
     625             :      * "always".  On a primary, archiving is enabled if archive_mode is "on"
     626             :      * or "always".
     627             :      */
     628        1414 :     if (!((XLogArchivingActive() && !inRecovery) ||
     629         704 :           (XLogArchivingAlways() && inRecovery)))
     630         704 :         return true;
     631             : 
     632             :     /* First check for .done --- this means archiver is done with it */
     633           6 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     634           6 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     635           0 :         return true;
     636             : 
     637             :     /* check for .ready --- this means archiver is still busy with it */
     638           6 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     639           6 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     640           0 :         return false;
     641             : 
     642             :     /* Race condition --- maybe archiver just finished, so recheck */
     643           6 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     644           6 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     645           0 :         return true;
     646             : 
     647             :     /* Retry creation of the .ready file */
     648           6 :     XLogArchiveNotify(xlog);
     649           6 :     return false;
     650             : }
     651             : 
     652             : /*
     653             :  * XLogArchiveIsBusy
     654             :  *
     655             :  * Check to see if an XLOG segment file is still unarchived.
     656             :  * This is almost but not quite the inverse of XLogArchiveCheckDone: in
     657             :  * the first place we aren't chartered to recreate the .ready file, and
     658             :  * in the second place we should consider that if the file is already gone
     659             :  * then it's not busy.  (This check is needed to handle the race condition
     660             :  * that a checkpoint already deleted the no-longer-needed file.)
     661             :  */
     662             : bool
     663           6 : XLogArchiveIsBusy(const char *xlog)
     664             : {
     665             :     char        archiveStatusPath[MAXPGPATH];
     666             :     struct stat stat_buf;
     667             : 
     668             :     /* First check for .done --- this means archiver is done with it */
     669           6 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     670           6 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     671           4 :         return false;
     672             : 
     673             :     /* check for .ready --- this means archiver is still busy with it */
     674           2 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     675           2 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     676           2 :         return true;
     677             : 
     678             :     /* Race condition --- maybe archiver just finished, so recheck */
     679           0 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     680           0 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     681           0 :         return false;
     682             : 
     683             :     /*
     684             :      * Check to see if the WAL file has been removed by checkpoint, which
     685             :      * implies it has already been archived, and explains why we can't see a
     686             :      * status file for it.
     687             :      */
     688           0 :     snprintf(archiveStatusPath, MAXPGPATH, XLOGDIR "/%s", xlog);
     689           0 :     if (stat(archiveStatusPath, &stat_buf) != 0 &&
     690           0 :         errno == ENOENT)
     691           0 :         return false;
     692             : 
     693           0 :     return true;
     694             : }
     695             : 
     696             : /*
     697             :  * XLogArchiveIsReadyOrDone
     698             :  *
     699             :  * Check to see if an XLOG segment file has a .ready or .done file.
     700             :  * This is similar to XLogArchiveIsBusy(), but returns true if the file
     701             :  * is already archived or is about to be archived.
     702             :  *
     703             :  * This is currently only used at recovery.  During normal operation this
     704             :  * would be racy: the file might get removed or marked with .ready as we're
     705             :  * checking it, or immediately after we return.
     706             :  */
     707             : bool
     708           2 : XLogArchiveIsReadyOrDone(const char *xlog)
     709             : {
     710             :     char        archiveStatusPath[MAXPGPATH];
     711             :     struct stat stat_buf;
     712             : 
     713             :     /* First check for .done --- this means archiver is done with it */
     714           2 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     715           2 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     716           0 :         return true;
     717             : 
     718             :     /* check for .ready --- this means archiver is still busy with it */
     719           2 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     720           2 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     721           0 :         return true;
     722             : 
     723             :     /* Race condition --- maybe archiver just finished, so recheck */
     724           2 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     725           2 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     726           0 :         return true;
     727             : 
     728           2 :     return false;
     729             : }
     730             : 
     731             : /*
     732             :  * XLogArchiveIsReady
     733             :  *
     734             :  * Check to see if an XLOG segment file has an archive notification (.ready)
     735             :  * file.
     736             :  */
     737             : bool
     738          22 : XLogArchiveIsReady(const char *xlog)
     739             : {
     740             :     char        archiveStatusPath[MAXPGPATH];
     741             :     struct stat stat_buf;
     742             : 
     743          22 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     744          22 :     if (stat(archiveStatusPath, &stat_buf) == 0)
     745           0 :         return true;
     746             : 
     747          22 :     return false;
     748             : }
     749             : 
     750             : /*
     751             :  * XLogArchiveCleanup
     752             :  *
     753             :  * Cleanup archive notification file(s) for a particular xlog segment
     754             :  */
     755             : void
     756         774 : XLogArchiveCleanup(const char *xlog)
     757             : {
     758             :     char        archiveStatusPath[MAXPGPATH];
     759             : 
     760             :     /* Remove the .done file */
     761         774 :     StatusFilePath(archiveStatusPath, xlog, ".done");
     762         774 :     unlink(archiveStatusPath);
     763             :     /* should we complain about failure? */
     764             : 
     765             :     /* Remove the .ready file if present --- normally it shouldn't be */
     766         774 :     StatusFilePath(archiveStatusPath, xlog, ".ready");
     767         774 :     unlink(archiveStatusPath);
     768             :     /* should we complain about failure? */
     769         774 : }

Generated by: LCOV version 1.13