Header And Logo

PostgreSQL
| The world's most advanced open source database.

xlogarchive.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * xlogarchive.c
00004  *      Functions for archiving WAL files and restoring from the archive.
00005  *
00006  *
00007  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00008  * Portions Copyright (c) 1994, Regents of the University of California
00009  *
00010  * src/backend/access/transam/xlogarchive.c
00011  *
00012  *-------------------------------------------------------------------------
00013  */
00014 
00015 #include "postgres.h"
00016 
00017 #include <sys/types.h>
00018 #include <sys/stat.h>
00019 #include <sys/wait.h>
00020 #include <signal.h>
00021 #include <unistd.h>
00022 
00023 #include "access/xlog.h"
00024 #include "access/xlog_internal.h"
00025 #include "miscadmin.h"
00026 #include "postmaster/startup.h"
00027 #include "replication/walsender.h"
00028 #include "storage/fd.h"
00029 #include "storage/ipc.h"
00030 #include "storage/lwlock.h"
00031 #include "storage/pmsignal.h"
00032 
00033 /*
00034  * Attempt to retrieve the specified file from off-line archival storage.
00035  * If successful, fill "path" with its complete path (note that this will be
00036  * a temp file name that doesn't follow the normal naming convention), and
00037  * return TRUE.
00038  *
00039  * If not successful, fill "path" with the name of the normal on-line file
00040  * (which may or may not actually exist, but we'll try to use it), and return
00041  * FALSE.
00042  *
00043  * For fixed-size files, the caller may pass the expected size as an
00044  * additional crosscheck on successful recovery.  If the file size is not
00045  * known, set expectedSize = 0.
00046  *
00047  * When 'cleanupEnabled' is false, refrain from deleting any old WAL segments
00048  * in the archive. This is used when fetching the initial checkpoint record,
00049  * when we are not yet sure how far back we need the WAL.
00050  */
00051 bool
00052 RestoreArchivedFile(char *path, const char *xlogfname,
00053                     const char *recovername, off_t expectedSize,
00054                     bool cleanupEnabled)
00055 {
00056     char        xlogpath[MAXPGPATH];
00057     char        xlogRestoreCmd[MAXPGPATH];
00058     char        lastRestartPointFname[MAXPGPATH];
00059     char       *dp;
00060     char       *endp;
00061     const char *sp;
00062     int         rc;
00063     bool        signaled;
00064     struct stat stat_buf;
00065     XLogSegNo   restartSegNo;
00066     XLogRecPtr  restartRedoPtr;
00067     TimeLineID  restartTli;
00068 
00069     /* In standby mode, restore_command might not be supplied */
00070     if (recoveryRestoreCommand == NULL)
00071         goto not_available;
00072 
00073     /*
00074      * When doing archive recovery, we always prefer an archived log file even
00075      * if a file of the same name exists in XLOGDIR.  The reason is that the
00076      * file in XLOGDIR could be an old, un-filled or partly-filled version
00077      * that was copied and restored as part of backing up $PGDATA.
00078      *
00079      * We could try to optimize this slightly by checking the local copy
00080      * lastchange timestamp against the archived copy, but we have no API to
00081      * do this, nor can we guarantee that the lastchange timestamp was
00082      * preserved correctly when we copied to archive. Our aim is robustness,
00083      * so we elect not to do this.
00084      *
00085      * If we cannot obtain the log file from the archive, however, we will try
00086      * to use the XLOGDIR file if it exists.  This is so that we can make use
00087      * of log segments that weren't yet transferred to the archive.
00088      *
00089      * Notice that we don't actually overwrite any files when we copy back
00090      * from archive because the restore_command may inadvertently
00091      * restore inappropriate xlogs, or they may be corrupt, so we may wish to
00092      * fallback to the segments remaining in current XLOGDIR later. The
00093      * copy-from-archive filename is always the same, ensuring that we don't
00094      * run out of disk space on long recoveries.
00095      */
00096     snprintf(xlogpath, MAXPGPATH, XLOGDIR "/%s", recovername);
00097 
00098     /*
00099      * Make sure there is no existing file named recovername.
00100      */
00101     if (stat(xlogpath, &stat_buf) != 0)
00102     {
00103         if (errno != ENOENT)
00104             ereport(FATAL,
00105                     (errcode_for_file_access(),
00106                      errmsg("could not stat file \"%s\": %m",
00107                             xlogpath)));
00108     }
00109     else
00110     {
00111         if (unlink(xlogpath) != 0)
00112             ereport(FATAL,
00113                     (errcode_for_file_access(),
00114                      errmsg("could not remove file \"%s\": %m",
00115                             xlogpath)));
00116     }
00117 
00118     /*
00119      * Calculate the archive file cutoff point for use during log shipping
00120      * replication. All files earlier than this point can be deleted from the
00121      * archive, though there is no requirement to do so.
00122      *
00123      * If cleanup is not enabled, initialise this with the filename of
00124      * InvalidXLogRecPtr, which will prevent the deletion of any WAL files
00125      * from the archive because of the alphabetic sorting property of WAL
00126      * filenames.
00127      *
00128      * Once we have successfully located the redo pointer of the checkpoint
00129      * from which we start recovery we never request a file prior to the redo
00130      * pointer of the last restartpoint. When redo begins we know that we have
00131      * successfully located it, so there is no need for additional status
00132      * flags to signify the point when we can begin deleting WAL files from
00133      * the archive.
00134      */
00135     if (cleanupEnabled)
00136     {
00137         GetOldestRestartPoint(&restartRedoPtr, &restartTli);
00138         XLByteToSeg(restartRedoPtr, restartSegNo);
00139         XLogFileName(lastRestartPointFname, restartTli, restartSegNo);
00140         /* we shouldn't need anything earlier than last restart point */
00141         Assert(strcmp(lastRestartPointFname, xlogfname) <= 0);
00142     }
00143     else
00144         XLogFileName(lastRestartPointFname, 0, 0L);
00145 
00146     /*
00147      * construct the command to be executed
00148      */
00149     dp = xlogRestoreCmd;
00150     endp = xlogRestoreCmd + MAXPGPATH - 1;
00151     *endp = '\0';
00152 
00153     for (sp = recoveryRestoreCommand; *sp; sp++)
00154     {
00155         if (*sp == '%')
00156         {
00157             switch (sp[1])
00158             {
00159                 case 'p':
00160                     /* %p: relative path of target file */
00161                     sp++;
00162                     StrNCpy(dp, xlogpath, endp - dp);
00163                     make_native_path(dp);
00164                     dp += strlen(dp);
00165                     break;
00166                 case 'f':
00167                     /* %f: filename of desired file */
00168                     sp++;
00169                     StrNCpy(dp, xlogfname, endp - dp);
00170                     dp += strlen(dp);
00171                     break;
00172                 case 'r':
00173                     /* %r: filename of last restartpoint */
00174                     sp++;
00175                     StrNCpy(dp, lastRestartPointFname, endp - dp);
00176                     dp += strlen(dp);
00177                     break;
00178                 case '%':
00179                     /* convert %% to a single % */
00180                     sp++;
00181                     if (dp < endp)
00182                         *dp++ = *sp;
00183                     break;
00184                 default:
00185                     /* otherwise treat the % as not special */
00186                     if (dp < endp)
00187                         *dp++ = *sp;
00188                     break;
00189             }
00190         }
00191         else
00192         {
00193             if (dp < endp)
00194                 *dp++ = *sp;
00195         }
00196     }
00197     *dp = '\0';
00198 
00199     ereport(DEBUG3,
00200             (errmsg_internal("executing restore command \"%s\"",
00201                              xlogRestoreCmd)));
00202 
00203     /*
00204      * Check signals before restore command and reset afterwards.
00205      */
00206     PreRestoreCommand();
00207 
00208     /*
00209      * Copy xlog from archival storage to XLOGDIR
00210      */
00211     rc = system(xlogRestoreCmd);
00212 
00213     PostRestoreCommand();
00214 
00215     if (rc == 0)
00216     {
00217         /*
00218          * command apparently succeeded, but let's make sure the file is
00219          * really there now and has the correct size.
00220          */
00221         if (stat(xlogpath, &stat_buf) == 0)
00222         {
00223             if (expectedSize > 0 && stat_buf.st_size != expectedSize)
00224             {
00225                 int         elevel;
00226 
00227                 /*
00228                  * If we find a partial file in standby mode, we assume it's
00229                  * because it's just being copied to the archive, and keep
00230                  * trying.
00231                  *
00232                  * Otherwise treat a wrong-sized file as FATAL to ensure the
00233                  * DBA would notice it, but is that too strong? We could try
00234                  * to plow ahead with a local copy of the file ... but the
00235                  * problem is that there probably isn't one, and we'd
00236                  * incorrectly conclude we've reached the end of WAL and we're
00237                  * done recovering ...
00238                  */
00239                 if (StandbyMode && stat_buf.st_size < expectedSize)
00240                     elevel = DEBUG1;
00241                 else
00242                     elevel = FATAL;
00243                 ereport(elevel,
00244                         (errmsg("archive file \"%s\" has wrong size: %lu instead of %lu",
00245                                 xlogfname,
00246                                 (unsigned long) stat_buf.st_size,
00247                                 (unsigned long) expectedSize)));
00248                 return false;
00249             }
00250             else
00251             {
00252                 ereport(LOG,
00253                         (errmsg("restored log file \"%s\" from archive",
00254                                 xlogfname)));
00255                 strcpy(path, xlogpath);
00256                 return true;
00257             }
00258         }
00259         else
00260         {
00261             /* stat failed */
00262             if (errno != ENOENT)
00263                 ereport(FATAL,
00264                         (errcode_for_file_access(),
00265                          errmsg("could not stat file \"%s\": %m",
00266                                 xlogpath)));
00267         }
00268     }
00269 
00270     /*
00271      * Remember, we rollforward UNTIL the restore fails so failure here is
00272      * just part of the process... that makes it difficult to determine
00273      * whether the restore failed because there isn't an archive to restore,
00274      * or because the administrator has specified the restore program
00275      * incorrectly.  We have to assume the former.
00276      *
00277      * However, if the failure was due to any sort of signal, it's best to
00278      * punt and abort recovery.  (If we "return false" here, upper levels will
00279      * assume that recovery is complete and start up the database!) It's
00280      * essential to abort on child SIGINT and SIGQUIT, because per spec
00281      * system() ignores SIGINT and SIGQUIT while waiting; if we see one of
00282      * those it's a good bet we should have gotten it too.
00283      *
00284      * On SIGTERM, assume we have received a fast shutdown request, and exit
00285      * cleanly. It's pure chance whether we receive the SIGTERM first, or the
00286      * child process. If we receive it first, the signal handler will call
00287      * proc_exit, otherwise we do it here. If we or the child process received
00288      * SIGTERM for any other reason than a fast shutdown request, postmaster
00289      * will perform an immediate shutdown when it sees us exiting
00290      * unexpectedly.
00291      *
00292      * Per the Single Unix Spec, shells report exit status > 128 when a called
00293      * command died on a signal.  Also, 126 and 127 are used to report
00294      * problems such as an unfindable command; treat those as fatal errors
00295      * too.
00296      */
00297     if (WIFSIGNALED(rc) && WTERMSIG(rc) == SIGTERM)
00298         proc_exit(1);
00299 
00300     signaled = WIFSIGNALED(rc) || WEXITSTATUS(rc) > 125;
00301 
00302     ereport(signaled ? FATAL : DEBUG2,
00303         (errmsg("could not restore file \"%s\" from archive: return code %d",
00304                 xlogfname, rc)));
00305 
00306 not_available:
00307 
00308     /*
00309      * if an archived file is not available, there might still be a version of
00310      * this file in XLOGDIR, so return that as the filename to open.
00311      *
00312      * In many recovery scenarios we expect this to fail also, but if so that
00313      * just means we've reached the end of WAL.
00314      */
00315     snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlogfname);
00316     return false;
00317 }
00318 
00319 /*
00320  * Attempt to execute an external shell command during recovery.
00321  *
00322  * 'command' is the shell command to be executed, 'commandName' is a
00323  * human-readable name describing the command emitted in the logs. If
00324  * 'failOnSignal' is true and the command is killed by a signal, a FATAL
00325  * error is thrown. Otherwise a WARNING is emitted.
00326  *
00327  * This is currently used for recovery_end_command and archive_cleanup_command.
00328  */
00329 void
00330 ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal)
00331 {
00332     char        xlogRecoveryCmd[MAXPGPATH];
00333     char        lastRestartPointFname[MAXPGPATH];
00334     char       *dp;
00335     char       *endp;
00336     const char *sp;
00337     int         rc;
00338     bool        signaled;
00339     XLogSegNo   restartSegNo;
00340     XLogRecPtr  restartRedoPtr;
00341     TimeLineID  restartTli;
00342 
00343     Assert(command && commandName);
00344 
00345     /*
00346      * Calculate the archive file cutoff point for use during log shipping
00347      * replication. All files earlier than this point can be deleted from the
00348      * archive, though there is no requirement to do so.
00349      */
00350     GetOldestRestartPoint(&restartRedoPtr, &restartTli);
00351     XLByteToSeg(restartRedoPtr, restartSegNo);
00352     XLogFileName(lastRestartPointFname, restartTli, restartSegNo);
00353 
00354     /*
00355      * construct the command to be executed
00356      */
00357     dp = xlogRecoveryCmd;
00358     endp = xlogRecoveryCmd + MAXPGPATH - 1;
00359     *endp = '\0';
00360 
00361     for (sp = command; *sp; sp++)
00362     {
00363         if (*sp == '%')
00364         {
00365             switch (sp[1])
00366             {
00367                 case 'r':
00368                     /* %r: filename of last restartpoint */
00369                     sp++;
00370                     StrNCpy(dp, lastRestartPointFname, endp - dp);
00371                     dp += strlen(dp);
00372                     break;
00373                 case '%':
00374                     /* convert %% to a single % */
00375                     sp++;
00376                     if (dp < endp)
00377                         *dp++ = *sp;
00378                     break;
00379                 default:
00380                     /* otherwise treat the % as not special */
00381                     if (dp < endp)
00382                         *dp++ = *sp;
00383                     break;
00384             }
00385         }
00386         else
00387         {
00388             if (dp < endp)
00389                 *dp++ = *sp;
00390         }
00391     }
00392     *dp = '\0';
00393 
00394     ereport(DEBUG3,
00395             (errmsg_internal("executing %s \"%s\"", commandName, command)));
00396 
00397     /*
00398      * execute the constructed command
00399      */
00400     rc = system(xlogRecoveryCmd);
00401     if (rc != 0)
00402     {
00403         /*
00404          * If the failure was due to any sort of signal, it's best to punt and
00405          * abort recovery. See also detailed comments on signals in
00406          * RestoreArchivedFile().
00407          */
00408         signaled = WIFSIGNALED(rc) || WEXITSTATUS(rc) > 125;
00409 
00410         ereport((signaled && failOnSignal) ? FATAL : WARNING,
00411         /*------
00412            translator: First %s represents a recovery.conf parameter name like
00413           "recovery_end_command", and the 2nd is the value of that parameter. */
00414                 (errmsg("%s \"%s\": return code %d", commandName,
00415                         command, rc)));
00416     }
00417 }
00418 
00419 
00420 /*
00421  * A file was restored from the archive under a temporary filename (path),
00422  * and now we want to keep it. Rename it under the permanent filename in
00423  * in pg_xlog (xlogfname), replacing any existing file with the same name.
00424  */
00425 void
00426 KeepFileRestoredFromArchive(char *path, char *xlogfname)
00427 {
00428     char        xlogfpath[MAXPGPATH];
00429     bool        reload = false;
00430     struct stat statbuf;
00431 
00432     snprintf(xlogfpath, MAXPGPATH, XLOGDIR "/%s", xlogfname);
00433 
00434     if (stat(xlogfpath, &statbuf) == 0)
00435     {
00436         char oldpath[MAXPGPATH];
00437 #ifdef WIN32
00438         static unsigned int deletedcounter = 1;
00439         /*
00440          * On Windows, if another process (e.g a walsender process) holds
00441          * the file open in FILE_SHARE_DELETE mode, unlink will succeed,
00442          * but the file will still show up in directory listing until the
00443          * last handle is closed, and we cannot rename the new file in its
00444          * place until that. To avoid that problem, rename the old file to
00445          * a temporary name first. Use a counter to create a unique
00446          * filename, because the same file might be restored from the
00447          * archive multiple times, and a walsender could still be holding
00448          * onto an old deleted version of it.
00449          */
00450         snprintf(oldpath, MAXPGPATH, "%s.deleted%u",
00451                  xlogfpath, deletedcounter++);
00452         if (rename(xlogfpath, oldpath) != 0)
00453         {
00454             ereport(ERROR,
00455                     (errcode_for_file_access(),
00456                      errmsg("could not rename file \"%s\" to \"%s\": %m",
00457                             xlogfpath, oldpath)));
00458         }
00459 #else
00460         strncpy(oldpath, xlogfpath, MAXPGPATH);
00461 #endif
00462         if (unlink(oldpath) != 0)
00463             ereport(FATAL,
00464                     (errcode_for_file_access(),
00465                      errmsg("could not remove file \"%s\": %m",
00466                             xlogfpath)));
00467         reload = true;
00468     }
00469 
00470     if (rename(path, xlogfpath) < 0)
00471         ereport(ERROR,
00472                 (errcode_for_file_access(),
00473                  errmsg("could not rename file \"%s\" to \"%s\": %m",
00474                         path, xlogfpath)));
00475 
00476     /*
00477      * Create .done file forcibly to prevent the restored segment from
00478      * being archived again later.
00479      */
00480     XLogArchiveForceDone(xlogfname);
00481 
00482     /*
00483      * If the existing file was replaced, since walsenders might have it
00484      * open, request them to reload a currently-open segment. This is only
00485      * required for WAL segments, walsenders don't hold other files open, but
00486      * there's no harm in doing this too often, and we don't know what kind
00487      * of a file we're dealing with here.
00488      */
00489     if (reload)
00490         WalSndRqstFileReload();
00491 
00492     /*
00493      * Signal walsender that new WAL has arrived. Again, this isn't necessary
00494      * if we restored something other than a WAL segment, but it does no harm
00495      * either.
00496      */
00497     WalSndWakeup();
00498 }
00499 
00500 /*
00501  * XLogArchiveNotify
00502  *
00503  * Create an archive notification file
00504  *
00505  * The name of the notification file is the message that will be picked up
00506  * by the archiver, e.g. we write 0000000100000001000000C6.ready
00507  * and the archiver then knows to archive XLOGDIR/0000000100000001000000C6,
00508  * then when complete, rename it to 0000000100000001000000C6.done
00509  */
00510 void
00511 XLogArchiveNotify(const char *xlog)
00512 {
00513     char        archiveStatusPath[MAXPGPATH];
00514     FILE       *fd;
00515 
00516     /* insert an otherwise empty file called <XLOG>.ready */
00517     StatusFilePath(archiveStatusPath, xlog, ".ready");
00518     fd = AllocateFile(archiveStatusPath, "w");
00519     if (fd == NULL)
00520     {
00521         ereport(LOG,
00522                 (errcode_for_file_access(),
00523                  errmsg("could not create archive status file \"%s\": %m",
00524                         archiveStatusPath)));
00525         return;
00526     }
00527     if (FreeFile(fd))
00528     {
00529         ereport(LOG,
00530                 (errcode_for_file_access(),
00531                  errmsg("could not write archive status file \"%s\": %m",
00532                         archiveStatusPath)));
00533         return;
00534     }
00535 
00536     /* Notify archiver that it's got something to do */
00537     if (IsUnderPostmaster)
00538         SendPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER);
00539 }
00540 
00541 /*
00542  * Convenience routine to notify using segment number representation of filename
00543  */
00544 void
00545 XLogArchiveNotifySeg(XLogSegNo segno)
00546 {
00547     char        xlog[MAXFNAMELEN];
00548 
00549     XLogFileName(xlog, ThisTimeLineID, segno);
00550     XLogArchiveNotify(xlog);
00551 }
00552 
00553 /*
00554  * XLogArchiveForceDone
00555  *
00556  * Emit notification forcibly that an XLOG segment file has been successfully
00557  * archived, by creating <XLOG>.done regardless of whether <XLOG>.ready
00558  * exists or not.
00559  */
00560 void
00561 XLogArchiveForceDone(const char *xlog)
00562 {
00563     char        archiveReady[MAXPGPATH];
00564     char        archiveDone[MAXPGPATH];
00565     struct stat stat_buf;
00566     FILE       *fd;
00567 
00568     /* Exit if already known done */
00569     StatusFilePath(archiveDone, xlog, ".done");
00570     if (stat(archiveDone, &stat_buf) == 0)
00571         return;
00572 
00573     /* If .ready exists, rename it to .done */
00574     StatusFilePath(archiveReady, xlog, ".ready");
00575     if (stat(archiveReady, &stat_buf) == 0)
00576     {
00577         if (rename(archiveReady, archiveDone) < 0)
00578             ereport(WARNING,
00579                     (errcode_for_file_access(),
00580                      errmsg("could not rename file \"%s\" to \"%s\": %m",
00581                             archiveReady, archiveDone)));
00582 
00583         return;
00584     }
00585 
00586     /* insert an otherwise empty file called <XLOG>.done */
00587     fd = AllocateFile(archiveDone, "w");
00588     if (fd == NULL)
00589     {
00590         ereport(LOG,
00591                 (errcode_for_file_access(),
00592                  errmsg("could not create archive status file \"%s\": %m",
00593                         archiveDone)));
00594         return;
00595     }
00596     if (FreeFile(fd))
00597     {
00598         ereport(LOG,
00599                 (errcode_for_file_access(),
00600                  errmsg("could not write archive status file \"%s\": %m",
00601                         archiveDone)));
00602         return;
00603     }
00604 }
00605 
00606 /*
00607  * XLogArchiveCheckDone
00608  *
00609  * This is called when we are ready to delete or recycle an old XLOG segment
00610  * file or backup history file.  If it is okay to delete it then return true.
00611  * If it is not time to delete it, make sure a .ready file exists, and return
00612  * false.
00613  *
00614  * If <XLOG>.done exists, then return true; else if <XLOG>.ready exists,
00615  * then return false; else create <XLOG>.ready and return false.
00616  *
00617  * The reason we do things this way is so that if the original attempt to
00618  * create <XLOG>.ready fails, we'll retry during subsequent checkpoints.
00619  */
00620 bool
00621 XLogArchiveCheckDone(const char *xlog)
00622 {
00623     char        archiveStatusPath[MAXPGPATH];
00624     struct stat stat_buf;
00625 
00626     /* Always deletable if archiving is off */
00627     if (!XLogArchivingActive())
00628         return true;
00629 
00630     /* First check for .done --- this means archiver is done with it */
00631     StatusFilePath(archiveStatusPath, xlog, ".done");
00632     if (stat(archiveStatusPath, &stat_buf) == 0)
00633         return true;
00634 
00635     /* check for .ready --- this means archiver is still busy with it */
00636     StatusFilePath(archiveStatusPath, xlog, ".ready");
00637     if (stat(archiveStatusPath, &stat_buf) == 0)
00638         return false;
00639 
00640     /* Race condition --- maybe archiver just finished, so recheck */
00641     StatusFilePath(archiveStatusPath, xlog, ".done");
00642     if (stat(archiveStatusPath, &stat_buf) == 0)
00643         return true;
00644 
00645     /* Retry creation of the .ready file */
00646     XLogArchiveNotify(xlog);
00647     return false;
00648 }
00649 
00650 /*
00651  * XLogArchiveIsBusy
00652  *
00653  * Check to see if an XLOG segment file is still unarchived.
00654  * This is almost but not quite the inverse of XLogArchiveCheckDone: in
00655  * the first place we aren't chartered to recreate the .ready file, and
00656  * in the second place we should consider that if the file is already gone
00657  * then it's not busy.  (This check is needed to handle the race condition
00658  * that a checkpoint already deleted the no-longer-needed file.)
00659  */
00660 bool
00661 XLogArchiveIsBusy(const char *xlog)
00662 {
00663     char        archiveStatusPath[MAXPGPATH];
00664     struct stat stat_buf;
00665 
00666     /* First check for .done --- this means archiver is done with it */
00667     StatusFilePath(archiveStatusPath, xlog, ".done");
00668     if (stat(archiveStatusPath, &stat_buf) == 0)
00669         return false;
00670 
00671     /* check for .ready --- this means archiver is still busy with it */
00672     StatusFilePath(archiveStatusPath, xlog, ".ready");
00673     if (stat(archiveStatusPath, &stat_buf) == 0)
00674         return true;
00675 
00676     /* Race condition --- maybe archiver just finished, so recheck */
00677     StatusFilePath(archiveStatusPath, xlog, ".done");
00678     if (stat(archiveStatusPath, &stat_buf) == 0)
00679         return false;
00680 
00681     /*
00682      * Check to see if the WAL file has been removed by checkpoint, which
00683      * implies it has already been archived, and explains why we can't see a
00684      * status file for it.
00685      */
00686     snprintf(archiveStatusPath, MAXPGPATH, XLOGDIR "/%s", xlog);
00687     if (stat(archiveStatusPath, &stat_buf) != 0 &&
00688         errno == ENOENT)
00689         return false;
00690 
00691     return true;
00692 }
00693 
00694 /*
00695  * XLogArchiveCleanup
00696  *
00697  * Cleanup archive notification file(s) for a particular xlog segment
00698  */
00699 void
00700 XLogArchiveCleanup(const char *xlog)
00701 {
00702     char        archiveStatusPath[MAXPGPATH];
00703 
00704     /* Remove the .done file */
00705     StatusFilePath(archiveStatusPath, xlog, ".done");
00706     unlink(archiveStatusPath);
00707     /* should we complain about failure? */
00708 
00709     /* Remove the .ready file if present --- normally it shouldn't be */
00710     StatusFilePath(archiveStatusPath, xlog, ".ready");
00711     unlink(archiveStatusPath);
00712     /* should we complain about failure? */
00713 }