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