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