]> granicus.if.org Git - postgresql/blob - src/backend/access/transam/xlogarchive.c
Reduce pinning and buffer content locking for btree scans.
[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-2015, 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                 /* same-size buffers, so this never truncates */
463                 strlcpy(oldpath, xlogfpath, MAXPGPATH);
464 #endif
465                 if (unlink(oldpath) != 0)
466                         ereport(FATAL,
467                                         (errcode_for_file_access(),
468                                          errmsg("could not remove file \"%s\": %m",
469                                                         xlogfpath)));
470                 reload = true;
471         }
472
473         if (rename(path, xlogfpath) < 0)
474                 ereport(ERROR,
475                                 (errcode_for_file_access(),
476                                  errmsg("could not rename file \"%s\" to \"%s\": %m",
477                                                 path, xlogfpath)));
478
479         /*
480          * Create .done file forcibly to prevent the restored segment from being
481          * archived again later.
482          */
483         XLogArchiveForceDone(xlogfname);
484
485         /*
486          * If the existing file was replaced, since walsenders might have it open,
487          * request them to reload a currently-open segment. This is only required
488          * for WAL segments, walsenders don't hold other files open, but there's
489          * no harm in doing this too often, and we don't know what kind of a file
490          * we're dealing with here.
491          */
492         if (reload)
493                 WalSndRqstFileReload();
494
495         /*
496          * Signal walsender that new WAL has arrived. Again, this isn't necessary
497          * if we restored something other than a WAL segment, but it does no harm
498          * either.
499          */
500         WalSndWakeup();
501 }
502
503 /*
504  * XLogArchiveNotify
505  *
506  * Create an archive notification file
507  *
508  * The name of the notification file is the message that will be picked up
509  * by the archiver, e.g. we write 0000000100000001000000C6.ready
510  * and the archiver then knows to archive XLOGDIR/0000000100000001000000C6,
511  * then when complete, rename it to 0000000100000001000000C6.done
512  */
513 void
514 XLogArchiveNotify(const char *xlog)
515 {
516         char            archiveStatusPath[MAXPGPATH];
517         FILE       *fd;
518
519         /* insert an otherwise empty file called <XLOG>.ready */
520         StatusFilePath(archiveStatusPath, xlog, ".ready");
521         fd = AllocateFile(archiveStatusPath, "w");
522         if (fd == NULL)
523         {
524                 ereport(LOG,
525                                 (errcode_for_file_access(),
526                                  errmsg("could not create archive status file \"%s\": %m",
527                                                 archiveStatusPath)));
528                 return;
529         }
530         if (FreeFile(fd))
531         {
532                 ereport(LOG,
533                                 (errcode_for_file_access(),
534                                  errmsg("could not write archive status file \"%s\": %m",
535                                                 archiveStatusPath)));
536                 return;
537         }
538
539         /* Notify archiver that it's got something to do */
540         if (IsUnderPostmaster)
541                 SendPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER);
542 }
543
544 /*
545  * Convenience routine to notify using segment number representation of filename
546  */
547 void
548 XLogArchiveNotifySeg(XLogSegNo segno)
549 {
550         char            xlog[MAXFNAMELEN];
551
552         XLogFileName(xlog, ThisTimeLineID, segno);
553         XLogArchiveNotify(xlog);
554 }
555
556 /*
557  * XLogArchiveForceDone
558  *
559  * Emit notification forcibly that an XLOG segment file has been successfully
560  * archived, by creating <XLOG>.done regardless of whether <XLOG>.ready
561  * exists or not.
562  */
563 void
564 XLogArchiveForceDone(const char *xlog)
565 {
566         char            archiveReady[MAXPGPATH];
567         char            archiveDone[MAXPGPATH];
568         struct stat stat_buf;
569         FILE       *fd;
570
571         /* Exit if already known done */
572         StatusFilePath(archiveDone, xlog, ".done");
573         if (stat(archiveDone, &stat_buf) == 0)
574                 return;
575
576         /* If .ready exists, rename it to .done */
577         StatusFilePath(archiveReady, xlog, ".ready");
578         if (stat(archiveReady, &stat_buf) == 0)
579         {
580                 if (rename(archiveReady, archiveDone) < 0)
581                         ereport(WARNING,
582                                         (errcode_for_file_access(),
583                                          errmsg("could not rename file \"%s\" to \"%s\": %m",
584                                                         archiveReady, archiveDone)));
585
586                 return;
587         }
588
589         /* insert an otherwise empty file called <XLOG>.done */
590         fd = AllocateFile(archiveDone, "w");
591         if (fd == NULL)
592         {
593                 ereport(LOG,
594                                 (errcode_for_file_access(),
595                                  errmsg("could not create archive status file \"%s\": %m",
596                                                 archiveDone)));
597                 return;
598         }
599         if (FreeFile(fd))
600         {
601                 ereport(LOG,
602                                 (errcode_for_file_access(),
603                                  errmsg("could not write archive status file \"%s\": %m",
604                                                 archiveDone)));
605                 return;
606         }
607 }
608
609 /*
610  * XLogArchiveCheckDone
611  *
612  * This is called when we are ready to delete or recycle an old XLOG segment
613  * file or backup history file.  If it is okay to delete it then return true.
614  * If it is not time to delete it, make sure a .ready file exists, and return
615  * false.
616  *
617  * If <XLOG>.done exists, then return true; else if <XLOG>.ready exists,
618  * then return false; else create <XLOG>.ready and return false.
619  *
620  * The reason we do things this way is so that if the original attempt to
621  * create <XLOG>.ready fails, we'll retry during subsequent checkpoints.
622  */
623 bool
624 XLogArchiveCheckDone(const char *xlog)
625 {
626         char            archiveStatusPath[MAXPGPATH];
627         struct stat stat_buf;
628
629         /* Always deletable if archiving is off */
630         if (!XLogArchivingActive())
631                 return true;
632
633         /* First check for .done --- this means archiver is done with it */
634         StatusFilePath(archiveStatusPath, xlog, ".done");
635         if (stat(archiveStatusPath, &stat_buf) == 0)
636                 return true;
637
638         /* check for .ready --- this means archiver is still busy with it */
639         StatusFilePath(archiveStatusPath, xlog, ".ready");
640         if (stat(archiveStatusPath, &stat_buf) == 0)
641                 return false;
642
643         /* Race condition --- maybe archiver just finished, so recheck */
644         StatusFilePath(archiveStatusPath, xlog, ".done");
645         if (stat(archiveStatusPath, &stat_buf) == 0)
646                 return true;
647
648         /* Retry creation of the .ready file */
649         XLogArchiveNotify(xlog);
650         return false;
651 }
652
653 /*
654  * XLogArchiveIsBusy
655  *
656  * Check to see if an XLOG segment file is still unarchived.
657  * This is almost but not quite the inverse of XLogArchiveCheckDone: in
658  * the first place we aren't chartered to recreate the .ready file, and
659  * in the second place we should consider that if the file is already gone
660  * then it's not busy.  (This check is needed to handle the race condition
661  * that a checkpoint already deleted the no-longer-needed file.)
662  */
663 bool
664 XLogArchiveIsBusy(const char *xlog)
665 {
666         char            archiveStatusPath[MAXPGPATH];
667         struct stat stat_buf;
668
669         /* First check for .done --- this means archiver is done with it */
670         StatusFilePath(archiveStatusPath, xlog, ".done");
671         if (stat(archiveStatusPath, &stat_buf) == 0)
672                 return false;
673
674         /* check for .ready --- this means archiver is still busy with it */
675         StatusFilePath(archiveStatusPath, xlog, ".ready");
676         if (stat(archiveStatusPath, &stat_buf) == 0)
677                 return true;
678
679         /* Race condition --- maybe archiver just finished, so recheck */
680         StatusFilePath(archiveStatusPath, xlog, ".done");
681         if (stat(archiveStatusPath, &stat_buf) == 0)
682                 return false;
683
684         /*
685          * Check to see if the WAL file has been removed by checkpoint, which
686          * implies it has already been archived, and explains why we can't see a
687          * status file for it.
688          */
689         snprintf(archiveStatusPath, MAXPGPATH, XLOGDIR "/%s", xlog);
690         if (stat(archiveStatusPath, &stat_buf) != 0 &&
691                 errno == ENOENT)
692                 return false;
693
694         return true;
695 }
696
697 /*
698  * XLogArchiveCleanup
699  *
700  * Cleanup archive notification file(s) for a particular xlog segment
701  */
702 void
703 XLogArchiveCleanup(const char *xlog)
704 {
705         char            archiveStatusPath[MAXPGPATH];
706
707         /* Remove the .done file */
708         StatusFilePath(archiveStatusPath, xlog, ".done");
709         unlink(archiveStatusPath);
710         /* should we complain about failure? */
711
712         /* Remove the .ready file if present --- normally it shouldn't be */
713         StatusFilePath(archiveStatusPath, xlog, ".ready");
714         unlink(archiveStatusPath);
715         /* should we complain about failure? */
716 }