]> granicus.if.org Git - postgresql/blob - src/backend/access/transam/xlogarchive.c
Remove useless duplicate inclusions of system header files.
[postgresql] / src / backend / access / transam / xlogarchive.c
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 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         if (recoveryRestoreCommand == NULL)
70                 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         snprintf(xlogpath, MAXPGPATH, XLOGDIR "/%s", recovername);
96
97         /*
98          * Make sure there is no existing file named recovername.
99          */
100         if (stat(xlogpath, &stat_buf) != 0)
101         {
102                 if (errno != ENOENT)
103                         ereport(FATAL,
104                                         (errcode_for_file_access(),
105                                          errmsg("could not stat file \"%s\": %m",
106                                                         xlogpath)));
107         }
108         else
109         {
110                 if (unlink(xlogpath) != 0)
111                         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         if (cleanupEnabled)
135         {
136                 GetOldestRestartPoint(&restartRedoPtr, &restartTli);
137                 XLByteToSeg(restartRedoPtr, restartSegNo);
138                 XLogFileName(lastRestartPointFname, restartTli, restartSegNo);
139                 /* we shouldn't need anything earlier than last restart point */
140                 Assert(strcmp(lastRestartPointFname, xlogfname) <= 0);
141         }
142         else
143                 XLogFileName(lastRestartPointFname, 0, 0L);
144
145         /*
146          * construct the command to be executed
147          */
148         dp = xlogRestoreCmd;
149         endp = xlogRestoreCmd + MAXPGPATH - 1;
150         *endp = '\0';
151
152         for (sp = recoveryRestoreCommand; *sp; sp++)
153         {
154                 if (*sp == '%')
155                 {
156                         switch (sp[1])
157                         {
158                                 case 'p':
159                                         /* %p: relative path of target file */
160                                         sp++;
161                                         StrNCpy(dp, xlogpath, endp - dp);
162                                         make_native_path(dp);
163                                         dp += strlen(dp);
164                                         break;
165                                 case 'f':
166                                         /* %f: filename of desired file */
167                                         sp++;
168                                         StrNCpy(dp, xlogfname, endp - dp);
169                                         dp += strlen(dp);
170                                         break;
171                                 case 'r':
172                                         /* %r: filename of last restartpoint */
173                                         sp++;
174                                         StrNCpy(dp, lastRestartPointFname, endp - dp);
175                                         dp += strlen(dp);
176                                         break;
177                                 case '%':
178                                         /* convert %% to a single % */
179                                         sp++;
180                                         if (dp < endp)
181                                                 *dp++ = *sp;
182                                         break;
183                                 default:
184                                         /* otherwise treat the % as not special */
185                                         if (dp < endp)
186                                                 *dp++ = *sp;
187                                         break;
188                         }
189                 }
190                 else
191                 {
192                         if (dp < endp)
193                                 *dp++ = *sp;
194                 }
195         }
196         *dp = '\0';
197
198         ereport(DEBUG3,
199                         (errmsg_internal("executing restore command \"%s\"",
200                                                          xlogRestoreCmd)));
201
202         /*
203          * Check signals before restore command and reset afterwards.
204          */
205         PreRestoreCommand();
206
207         /*
208          * Copy xlog from archival storage to XLOGDIR
209          */
210         rc = system(xlogRestoreCmd);
211
212         PostRestoreCommand();
213
214         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                 if (stat(xlogpath, &stat_buf) == 0)
221                 {
222                         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                                 if (StandbyMode && stat_buf.st_size < expectedSize)
239                                         elevel = DEBUG1;
240                                 else
241                                         elevel = FATAL;
242                                 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                                 return false;
248                         }
249                         else
250                         {
251                                 ereport(LOG,
252                                                 (errmsg("restored log file \"%s\" from archive",
253                                                                 xlogfname)));
254                                 strcpy(path, xlogpath);
255                                 return true;
256                         }
257                 }
258                 else
259                 {
260                         /* stat failed */
261                         if (errno != ENOENT)
262                                 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         if (WIFSIGNALED(rc) && WTERMSIG(rc) == SIGTERM)
297                 proc_exit(1);
298
299         signaled = WIFSIGNALED(rc) || WEXITSTATUS(rc) > 125;
300
301         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         snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlogfname);
315         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 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         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         GetOldestRestartPoint(&restartRedoPtr, &restartTli);
350         XLByteToSeg(restartRedoPtr, restartSegNo);
351         XLogFileName(lastRestartPointFname, restartTli, restartSegNo);
352
353         /*
354          * construct the command to be executed
355          */
356         dp = xlogRecoveryCmd;
357         endp = xlogRecoveryCmd + MAXPGPATH - 1;
358         *endp = '\0';
359
360         for (sp = command; *sp; sp++)
361         {
362                 if (*sp == '%')
363                 {
364                         switch (sp[1])
365                         {
366                                 case 'r':
367                                         /* %r: filename of last restartpoint */
368                                         sp++;
369                                         StrNCpy(dp, lastRestartPointFname, endp - dp);
370                                         dp += strlen(dp);
371                                         break;
372                                 case '%':
373                                         /* convert %% to a single % */
374                                         sp++;
375                                         if (dp < endp)
376                                                 *dp++ = *sp;
377                                         break;
378                                 default:
379                                         /* otherwise treat the % as not special */
380                                         if (dp < endp)
381                                                 *dp++ = *sp;
382                                         break;
383                         }
384                 }
385                 else
386                 {
387                         if (dp < endp)
388                                 *dp++ = *sp;
389                 }
390         }
391         *dp = '\0';
392
393         ereport(DEBUG3,
394                         (errmsg_internal("executing %s \"%s\"", commandName, command)));
395
396         /*
397          * execute the constructed command
398          */
399         rc = system(xlogRecoveryCmd);
400         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                 signaled = WIFSIGNALED(rc) || WEXITSTATUS(rc) > 125;
408
409                 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 }
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 KeepFileRestoredFromArchive(char *path, char *xlogfname)
427 {
428         char            xlogfpath[MAXPGPATH];
429         bool            reload = false;
430         struct stat statbuf;
431
432         snprintf(xlogfpath, MAXPGPATH, XLOGDIR "/%s", xlogfname);
433
434         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                 strlcpy(oldpath, xlogfpath, MAXPGPATH);
463 #endif
464                 if (unlink(oldpath) != 0)
465                         ereport(FATAL,
466                                         (errcode_for_file_access(),
467                                          errmsg("could not remove file \"%s\": %m",
468                                                         xlogfpath)));
469                 reload = true;
470         }
471
472         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         if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
479                 XLogArchiveForceDone(xlogfname);
480         else
481                 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         if (reload)
491                 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         WalSndWakeup();
499 }
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 XLogArchiveNotify(const char *xlog)
513 {
514         char            archiveStatusPath[MAXPGPATH];
515         FILE       *fd;
516
517         /* insert an otherwise empty file called <XLOG>.ready */
518         StatusFilePath(archiveStatusPath, xlog, ".ready");
519         fd = AllocateFile(archiveStatusPath, "w");
520         if (fd == NULL)
521         {
522                 ereport(LOG,
523                                 (errcode_for_file_access(),
524                                  errmsg("could not create archive status file \"%s\": %m",
525                                                 archiveStatusPath)));
526                 return;
527         }
528         if (FreeFile(fd))
529         {
530                 ereport(LOG,
531                                 (errcode_for_file_access(),
532                                  errmsg("could not write archive status file \"%s\": %m",
533                                                 archiveStatusPath)));
534                 return;
535         }
536
537         /* Notify archiver that it's got something to do */
538         if (IsUnderPostmaster)
539                 SendPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER);
540 }
541
542 /*
543  * Convenience routine to notify using segment number representation of filename
544  */
545 void
546 XLogArchiveNotifySeg(XLogSegNo segno)
547 {
548         char            xlog[MAXFNAMELEN];
549
550         XLogFileName(xlog, ThisTimeLineID, segno);
551         XLogArchiveNotify(xlog);
552 }
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 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         StatusFilePath(archiveDone, xlog, ".done");
571         if (stat(archiveDone, &stat_buf) == 0)
572                 return;
573
574         /* If .ready exists, rename it to .done */
575         StatusFilePath(archiveReady, xlog, ".ready");
576         if (stat(archiveReady, &stat_buf) == 0)
577         {
578                 (void) durable_rename(archiveReady, archiveDone, WARNING);
579                 return;
580         }
581
582         /* insert an otherwise empty file called <XLOG>.done */
583         fd = AllocateFile(archiveDone, "w");
584         if (fd == NULL)
585         {
586                 ereport(LOG,
587                                 (errcode_for_file_access(),
588                                  errmsg("could not create archive status file \"%s\": %m",
589                                                 archiveDone)));
590                 return;
591         }
592         if (FreeFile(fd))
593         {
594                 ereport(LOG,
595                                 (errcode_for_file_access(),
596                                  errmsg("could not write archive status file \"%s\": %m",
597                                                 archiveDone)));
598                 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 XLogArchiveCheckDone(const char *xlog)
618 {
619         char            archiveStatusPath[MAXPGPATH];
620         struct stat stat_buf;
621
622         /* Always deletable if archiving is off */
623         if (!XLogArchivingActive())
624                 return true;
625
626         /* First check for .done --- this means archiver is done with it */
627         StatusFilePath(archiveStatusPath, xlog, ".done");
628         if (stat(archiveStatusPath, &stat_buf) == 0)
629                 return true;
630
631         /* check for .ready --- this means archiver is still busy with it */
632         StatusFilePath(archiveStatusPath, xlog, ".ready");
633         if (stat(archiveStatusPath, &stat_buf) == 0)
634                 return false;
635
636         /* Race condition --- maybe archiver just finished, so recheck */
637         StatusFilePath(archiveStatusPath, xlog, ".done");
638         if (stat(archiveStatusPath, &stat_buf) == 0)
639                 return true;
640
641         /* Retry creation of the .ready file */
642         XLogArchiveNotify(xlog);
643         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 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         StatusFilePath(archiveStatusPath, xlog, ".done");
664         if (stat(archiveStatusPath, &stat_buf) == 0)
665                 return false;
666
667         /* check for .ready --- this means archiver is still busy with it */
668         StatusFilePath(archiveStatusPath, xlog, ".ready");
669         if (stat(archiveStatusPath, &stat_buf) == 0)
670                 return true;
671
672         /* Race condition --- maybe archiver just finished, so recheck */
673         StatusFilePath(archiveStatusPath, xlog, ".done");
674         if (stat(archiveStatusPath, &stat_buf) == 0)
675                 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         snprintf(archiveStatusPath, MAXPGPATH, XLOGDIR "/%s", xlog);
683         if (stat(archiveStatusPath, &stat_buf) != 0 &&
684                 errno == ENOENT)
685                 return false;
686
687         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 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         StatusFilePath(archiveStatusPath, xlog, ".done");
709         if (stat(archiveStatusPath, &stat_buf) == 0)
710                 return true;
711
712         /* check for .ready --- this means archiver is still busy with it */
713         StatusFilePath(archiveStatusPath, xlog, ".ready");
714         if (stat(archiveStatusPath, &stat_buf) == 0)
715                 return true;
716
717         /* Race condition --- maybe archiver just finished, so recheck */
718         StatusFilePath(archiveStatusPath, xlog, ".done");
719         if (stat(archiveStatusPath, &stat_buf) == 0)
720                 return true;
721
722         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 XLogArchiveIsReady(const char *xlog)
733 {
734         char            archiveStatusPath[MAXPGPATH];
735         struct stat stat_buf;
736
737         StatusFilePath(archiveStatusPath, xlog, ".ready");
738         if (stat(archiveStatusPath, &stat_buf) == 0)
739                 return true;
740
741         return false;
742 }
743
744 /*
745  * XLogArchiveCleanup
746  *
747  * Cleanup archive notification file(s) for a particular xlog segment
748  */
749 void
750 XLogArchiveCleanup(const char *xlog)
751 {
752         char            archiveStatusPath[MAXPGPATH];
753
754         /* Remove the .done file */
755         StatusFilePath(archiveStatusPath, xlog, ".done");
756         unlink(archiveStatusPath);
757         /* should we complain about failure? */
758
759         /* Remove the .ready file if present --- normally it shouldn't be */
760         StatusFilePath(archiveStatusPath, xlog, ".ready");
761         unlink(archiveStatusPath);
762         /* should we complain about failure? */
763 }