]> granicus.if.org Git - postgresql/blob - src/backend/access/transam/xlogarchive.c
Improve detection of child-process SIGPIPE failures.
[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-2018, 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         struct stat stat_buf;
63         XLogSegNo       restartSegNo;
64         XLogRecPtr      restartRedoPtr;
65         TimeLineID      restartTli;
66
67         /* In standby mode, restore_command might not be supplied */
68         if (recoveryRestoreCommand == NULL || strcmp(recoveryRestoreCommand, "") == 0)
69                 goto not_available;
70
71         /*
72          * When doing archive recovery, we always prefer an archived log file even
73          * if a file of the same name exists in XLOGDIR.  The reason is that the
74          * file in XLOGDIR could be an old, un-filled or partly-filled version
75          * that was copied and restored as part of backing up $PGDATA.
76          *
77          * We could try to optimize this slightly by checking the local copy
78          * lastchange timestamp against the archived copy, but we have no API to
79          * do this, nor can we guarantee that the lastchange timestamp was
80          * preserved correctly when we copied to archive. Our aim is robustness,
81          * so we elect not to do this.
82          *
83          * If we cannot obtain the log file from the archive, however, we will try
84          * to use the XLOGDIR file if it exists.  This is so that we can make use
85          * of log segments that weren't yet transferred to the archive.
86          *
87          * Notice that we don't actually overwrite any files when we copy back
88          * from archive because the restore_command may inadvertently restore
89          * inappropriate xlogs, or they may be corrupt, so we may wish to fallback
90          * to the segments remaining in current XLOGDIR later. The
91          * copy-from-archive filename is always the same, ensuring that we don't
92          * run out of disk space on long recoveries.
93          */
94         snprintf(xlogpath, MAXPGPATH, XLOGDIR "/%s", recovername);
95
96         /*
97          * Make sure there is no existing file named recovername.
98          */
99         if (stat(xlogpath, &stat_buf) != 0)
100         {
101                 if (errno != ENOENT)
102                         ereport(FATAL,
103                                         (errcode_for_file_access(),
104                                          errmsg("could not stat file \"%s\": %m",
105                                                         xlogpath)));
106         }
107         else
108         {
109                 if (unlink(xlogpath) != 0)
110                         ereport(FATAL,
111                                         (errcode_for_file_access(),
112                                          errmsg("could not remove file \"%s\": %m",
113                                                         xlogpath)));
114         }
115
116         /*
117          * Calculate the archive file cutoff point for use during log shipping
118          * replication. All files earlier than this point can be deleted from the
119          * archive, though there is no requirement to do so.
120          *
121          * If cleanup is not enabled, initialise this with the filename of
122          * InvalidXLogRecPtr, which will prevent the deletion of any WAL files
123          * from the archive because of the alphabetic sorting property of WAL
124          * filenames.
125          *
126          * Once we have successfully located the redo pointer of the checkpoint
127          * from which we start recovery we never request a file prior to the redo
128          * pointer of the last restartpoint. When redo begins we know that we have
129          * successfully located it, so there is no need for additional status
130          * flags to signify the point when we can begin deleting WAL files from
131          * the archive.
132          */
133         if (cleanupEnabled)
134         {
135                 GetOldestRestartPoint(&restartRedoPtr, &restartTli);
136                 XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
137                 XLogFileName(lastRestartPointFname, restartTli, restartSegNo,
138                                          wal_segment_size);
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, wal_segment_size);
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          * We treat hard shell errors such as "command not found" as fatal, too.
292          */
293         if (wait_result_is_signal(rc, SIGTERM))
294                 proc_exit(1);
295
296         ereport(wait_result_is_any_signal(rc, true) ? FATAL : DEBUG2,
297                         (errmsg("could not restore file \"%s\" from archive: %s",
298                                         xlogfname, wait_result_to_str(rc))));
299
300 not_available:
301
302         /*
303          * if an archived file is not available, there might still be a version of
304          * this file in XLOGDIR, so return that as the filename to open.
305          *
306          * In many recovery scenarios we expect this to fail also, but if so that
307          * just means we've reached the end of WAL.
308          */
309         snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlogfname);
310         return false;
311 }
312
313 /*
314  * Attempt to execute an external shell command during recovery.
315  *
316  * 'command' is the shell command to be executed, 'commandName' is a
317  * human-readable name describing the command emitted in the logs. If
318  * 'failOnSignal' is true and the command is killed by a signal, a FATAL
319  * error is thrown. Otherwise a WARNING is emitted.
320  *
321  * This is currently used for recovery_end_command and archive_cleanup_command.
322  */
323 void
324 ExecuteRecoveryCommand(const char *command, const char *commandName, bool failOnSignal)
325 {
326         char            xlogRecoveryCmd[MAXPGPATH];
327         char            lastRestartPointFname[MAXPGPATH];
328         char       *dp;
329         char       *endp;
330         const char *sp;
331         int                     rc;
332         XLogSegNo       restartSegNo;
333         XLogRecPtr      restartRedoPtr;
334         TimeLineID      restartTli;
335
336         Assert(command && commandName);
337
338         /*
339          * Calculate the archive file cutoff point for use during log shipping
340          * replication. All files earlier than this point can be deleted from the
341          * archive, though there is no requirement to do so.
342          */
343         GetOldestRestartPoint(&restartRedoPtr, &restartTli);
344         XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
345         XLogFileName(lastRestartPointFname, restartTli, restartSegNo,
346                                  wal_segment_size);
347
348         /*
349          * construct the command to be executed
350          */
351         dp = xlogRecoveryCmd;
352         endp = xlogRecoveryCmd + MAXPGPATH - 1;
353         *endp = '\0';
354
355         for (sp = command; *sp; sp++)
356         {
357                 if (*sp == '%')
358                 {
359                         switch (sp[1])
360                         {
361                                 case 'r':
362                                         /* %r: filename of last restartpoint */
363                                         sp++;
364                                         StrNCpy(dp, lastRestartPointFname, endp - dp);
365                                         dp += strlen(dp);
366                                         break;
367                                 case '%':
368                                         /* convert %% to a single % */
369                                         sp++;
370                                         if (dp < endp)
371                                                 *dp++ = *sp;
372                                         break;
373                                 default:
374                                         /* otherwise treat the % as not special */
375                                         if (dp < endp)
376                                                 *dp++ = *sp;
377                                         break;
378                         }
379                 }
380                 else
381                 {
382                         if (dp < endp)
383                                 *dp++ = *sp;
384                 }
385         }
386         *dp = '\0';
387
388         ereport(DEBUG3,
389                         (errmsg_internal("executing %s \"%s\"", commandName, command)));
390
391         /*
392          * execute the constructed command
393          */
394         rc = system(xlogRecoveryCmd);
395         if (rc != 0)
396         {
397                 /*
398                  * If the failure was due to any sort of signal, it's best to punt and
399                  * abort recovery.  See comments in RestoreArchivedFile().
400                  */
401                 ereport((failOnSignal && wait_result_is_any_signal(rc, true)) ? FATAL : WARNING,
402                 /*------
403                    translator: First %s represents a postgresql.conf parameter name like
404                   "recovery_end_command", the 2nd is the value of that parameter, the
405                   third an already translated error message. */
406                                 (errmsg("%s \"%s\": %s", commandName,
407                                                 command, wait_result_to_str(rc))));
408         }
409 }
410
411
412 /*
413  * A file was restored from the archive under a temporary filename (path),
414  * and now we want to keep it. Rename it under the permanent filename in
415  * pg_wal (xlogfname), replacing any existing file with the same name.
416  */
417 void
418 KeepFileRestoredFromArchive(const char *path, const char *xlogfname)
419 {
420         char            xlogfpath[MAXPGPATH];
421         bool            reload = false;
422         struct stat statbuf;
423
424         snprintf(xlogfpath, MAXPGPATH, XLOGDIR "/%s", xlogfname);
425
426         if (stat(xlogfpath, &statbuf) == 0)
427         {
428                 char            oldpath[MAXPGPATH];
429
430 #ifdef WIN32
431                 static unsigned int deletedcounter = 1;
432
433                 /*
434                  * On Windows, if another process (e.g a walsender process) holds the
435                  * file open in FILE_SHARE_DELETE mode, unlink will succeed, but the
436                  * file will still show up in directory listing until the last handle
437                  * is closed, and we cannot rename the new file in its place until
438                  * that. To avoid that problem, rename the old file to a temporary
439                  * name first. Use a counter to create a unique filename, because the
440                  * same file might be restored from the archive multiple times, and a
441                  * walsender could still be holding onto an old deleted version of it.
442                  */
443                 snprintf(oldpath, MAXPGPATH, "%s.deleted%u",
444                                  xlogfpath, deletedcounter++);
445                 if (rename(xlogfpath, oldpath) != 0)
446                 {
447                         ereport(ERROR,
448                                         (errcode_for_file_access(),
449                                          errmsg("could not rename file \"%s\" to \"%s\": %m",
450                                                         xlogfpath, oldpath)));
451                 }
452 #else
453                 /* same-size buffers, so this never truncates */
454                 strlcpy(oldpath, xlogfpath, MAXPGPATH);
455 #endif
456                 if (unlink(oldpath) != 0)
457                         ereport(FATAL,
458                                         (errcode_for_file_access(),
459                                          errmsg("could not remove file \"%s\": %m",
460                                                         xlogfpath)));
461                 reload = true;
462         }
463
464         durable_rename(path, xlogfpath, ERROR);
465
466         /*
467          * Create .done file forcibly to prevent the restored segment from being
468          * archived again later.
469          */
470         if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
471                 XLogArchiveForceDone(xlogfname);
472         else
473                 XLogArchiveNotify(xlogfname);
474
475         /*
476          * If the existing file was replaced, since walsenders might have it open,
477          * request them to reload a currently-open segment. This is only required
478          * for WAL segments, walsenders don't hold other files open, but there's
479          * no harm in doing this too often, and we don't know what kind of a file
480          * we're dealing with here.
481          */
482         if (reload)
483                 WalSndRqstFileReload();
484
485         /*
486          * Signal walsender that new WAL has arrived. Again, this isn't necessary
487          * if we restored something other than a WAL segment, but it does no harm
488          * either.
489          */
490         WalSndWakeup();
491 }
492
493 /*
494  * XLogArchiveNotify
495  *
496  * Create an archive notification file
497  *
498  * The name of the notification file is the message that will be picked up
499  * by the archiver, e.g. we write 0000000100000001000000C6.ready
500  * and the archiver then knows to archive XLOGDIR/0000000100000001000000C6,
501  * then when complete, rename it to 0000000100000001000000C6.done
502  */
503 void
504 XLogArchiveNotify(const char *xlog)
505 {
506         char            archiveStatusPath[MAXPGPATH];
507         FILE       *fd;
508
509         /* insert an otherwise empty file called <XLOG>.ready */
510         StatusFilePath(archiveStatusPath, xlog, ".ready");
511         fd = AllocateFile(archiveStatusPath, "w");
512         if (fd == NULL)
513         {
514                 ereport(LOG,
515                                 (errcode_for_file_access(),
516                                  errmsg("could not create archive status file \"%s\": %m",
517                                                 archiveStatusPath)));
518                 return;
519         }
520         if (FreeFile(fd))
521         {
522                 ereport(LOG,
523                                 (errcode_for_file_access(),
524                                  errmsg("could not write archive status file \"%s\": %m",
525                                                 archiveStatusPath)));
526                 return;
527         }
528
529         /* Notify archiver that it's got something to do */
530         if (IsUnderPostmaster)
531                 SendPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER);
532 }
533
534 /*
535  * Convenience routine to notify using segment number representation of filename
536  */
537 void
538 XLogArchiveNotifySeg(XLogSegNo segno)
539 {
540         char            xlog[MAXFNAMELEN];
541
542         XLogFileName(xlog, ThisTimeLineID, segno, wal_segment_size);
543         XLogArchiveNotify(xlog);
544 }
545
546 /*
547  * XLogArchiveForceDone
548  *
549  * Emit notification forcibly that an XLOG segment file has been successfully
550  * archived, by creating <XLOG>.done regardless of whether <XLOG>.ready
551  * exists or not.
552  */
553 void
554 XLogArchiveForceDone(const char *xlog)
555 {
556         char            archiveReady[MAXPGPATH];
557         char            archiveDone[MAXPGPATH];
558         struct stat stat_buf;
559         FILE       *fd;
560
561         /* Exit if already known done */
562         StatusFilePath(archiveDone, xlog, ".done");
563         if (stat(archiveDone, &stat_buf) == 0)
564                 return;
565
566         /* If .ready exists, rename it to .done */
567         StatusFilePath(archiveReady, xlog, ".ready");
568         if (stat(archiveReady, &stat_buf) == 0)
569         {
570                 (void) durable_rename(archiveReady, archiveDone, WARNING);
571                 return;
572         }
573
574         /* insert an otherwise empty file called <XLOG>.done */
575         fd = AllocateFile(archiveDone, "w");
576         if (fd == NULL)
577         {
578                 ereport(LOG,
579                                 (errcode_for_file_access(),
580                                  errmsg("could not create archive status file \"%s\": %m",
581                                                 archiveDone)));
582                 return;
583         }
584         if (FreeFile(fd))
585         {
586                 ereport(LOG,
587                                 (errcode_for_file_access(),
588                                  errmsg("could not write archive status file \"%s\": %m",
589                                                 archiveDone)));
590                 return;
591         }
592 }
593
594 /*
595  * XLogArchiveCheckDone
596  *
597  * This is called when we are ready to delete or recycle an old XLOG segment
598  * file or backup history file.  If it is okay to delete it then return true.
599  * If it is not time to delete it, make sure a .ready file exists, and return
600  * false.
601  *
602  * If <XLOG>.done exists, then return true; else if <XLOG>.ready exists,
603  * then return false; else create <XLOG>.ready and return false.
604  *
605  * The reason we do things this way is so that if the original attempt to
606  * create <XLOG>.ready fails, we'll retry during subsequent checkpoints.
607  */
608 bool
609 XLogArchiveCheckDone(const char *xlog)
610 {
611         char            archiveStatusPath[MAXPGPATH];
612         struct stat stat_buf;
613         bool            inRecovery = RecoveryInProgress();
614
615         /*
616          * The file is always deletable if archive_mode is "off".  On standbys
617          * archiving is disabled if archive_mode is "on", and enabled with
618          * "always".  On a primary, archiving is enabled if archive_mode is "on"
619          * or "always".
620          */
621         if (!((XLogArchivingActive() && !inRecovery) ||
622                   (XLogArchivingAlways() && inRecovery)))
623                 return true;
624
625         /* First check for .done --- this means archiver is done with it */
626         StatusFilePath(archiveStatusPath, xlog, ".done");
627         if (stat(archiveStatusPath, &stat_buf) == 0)
628                 return true;
629
630         /* check for .ready --- this means archiver is still busy with it */
631         StatusFilePath(archiveStatusPath, xlog, ".ready");
632         if (stat(archiveStatusPath, &stat_buf) == 0)
633                 return false;
634
635         /* Race condition --- maybe archiver just finished, so recheck */
636         StatusFilePath(archiveStatusPath, xlog, ".done");
637         if (stat(archiveStatusPath, &stat_buf) == 0)
638                 return true;
639
640         /* Retry creation of the .ready file */
641         XLogArchiveNotify(xlog);
642         return false;
643 }
644
645 /*
646  * XLogArchiveIsBusy
647  *
648  * Check to see if an XLOG segment file is still unarchived.
649  * This is almost but not quite the inverse of XLogArchiveCheckDone: in
650  * the first place we aren't chartered to recreate the .ready file, and
651  * in the second place we should consider that if the file is already gone
652  * then it's not busy.  (This check is needed to handle the race condition
653  * that a checkpoint already deleted the no-longer-needed file.)
654  */
655 bool
656 XLogArchiveIsBusy(const char *xlog)
657 {
658         char            archiveStatusPath[MAXPGPATH];
659         struct stat stat_buf;
660
661         /* First check for .done --- this means archiver is done with it */
662         StatusFilePath(archiveStatusPath, xlog, ".done");
663         if (stat(archiveStatusPath, &stat_buf) == 0)
664                 return false;
665
666         /* check for .ready --- this means archiver is still busy with it */
667         StatusFilePath(archiveStatusPath, xlog, ".ready");
668         if (stat(archiveStatusPath, &stat_buf) == 0)
669                 return true;
670
671         /* Race condition --- maybe archiver just finished, so recheck */
672         StatusFilePath(archiveStatusPath, xlog, ".done");
673         if (stat(archiveStatusPath, &stat_buf) == 0)
674                 return false;
675
676         /*
677          * Check to see if the WAL file has been removed by checkpoint, which
678          * implies it has already been archived, and explains why we can't see a
679          * status file for it.
680          */
681         snprintf(archiveStatusPath, MAXPGPATH, XLOGDIR "/%s", xlog);
682         if (stat(archiveStatusPath, &stat_buf) != 0 &&
683                 errno == ENOENT)
684                 return false;
685
686         return true;
687 }
688
689 /*
690  * XLogArchiveIsReadyOrDone
691  *
692  * Check to see if an XLOG segment file has a .ready or .done file.
693  * This is similar to XLogArchiveIsBusy(), but returns true if the file
694  * is already archived or is about to be archived.
695  *
696  * This is currently only used at recovery.  During normal operation this
697  * would be racy: the file might get removed or marked with .ready as we're
698  * checking it, or immediately after we return.
699  */
700 bool
701 XLogArchiveIsReadyOrDone(const char *xlog)
702 {
703         char            archiveStatusPath[MAXPGPATH];
704         struct stat stat_buf;
705
706         /* First check for .done --- this means archiver is done with it */
707         StatusFilePath(archiveStatusPath, xlog, ".done");
708         if (stat(archiveStatusPath, &stat_buf) == 0)
709                 return true;
710
711         /* check for .ready --- this means archiver is still busy with it */
712         StatusFilePath(archiveStatusPath, xlog, ".ready");
713         if (stat(archiveStatusPath, &stat_buf) == 0)
714                 return true;
715
716         /* Race condition --- maybe archiver just finished, so recheck */
717         StatusFilePath(archiveStatusPath, xlog, ".done");
718         if (stat(archiveStatusPath, &stat_buf) == 0)
719                 return true;
720
721         return false;
722 }
723
724 /*
725  * XLogArchiveIsReady
726  *
727  * Check to see if an XLOG segment file has an archive notification (.ready)
728  * file.
729  */
730 bool
731 XLogArchiveIsReady(const char *xlog)
732 {
733         char            archiveStatusPath[MAXPGPATH];
734         struct stat stat_buf;
735
736         StatusFilePath(archiveStatusPath, xlog, ".ready");
737         if (stat(archiveStatusPath, &stat_buf) == 0)
738                 return true;
739
740         return false;
741 }
742
743 /*
744  * XLogArchiveCleanup
745  *
746  * Cleanup archive notification file(s) for a particular xlog segment
747  */
748 void
749 XLogArchiveCleanup(const char *xlog)
750 {
751         char            archiveStatusPath[MAXPGPATH];
752
753         /* Remove the .done file */
754         StatusFilePath(archiveStatusPath, xlog, ".done");
755         unlink(archiveStatusPath);
756         /* should we complain about failure? */
757
758         /* Remove the .ready file if present --- normally it shouldn't be */
759         StatusFilePath(archiveStatusPath, xlog, ".ready");
760         unlink(archiveStatusPath);
761         /* should we complain about failure? */
762 }