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