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

Generated by: LCOV version 1.11