Branch data 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 : 1484 : 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 [ + + ]: 1484 : if (!ArchiveRecoveryRequested)
73 : 34 : goto not_available;
74 : :
75 : : /* In standby mode, restore_command might not be supplied */
76 [ + - + + ]: 1450 : if (recoveryRestoreCommand == NULL || strcmp(recoveryRestoreCommand, "") == 0)
77 : 888 : 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 : 562 : snprintf(xlogpath, MAXPGPATH, XLOGDIR "/%s", recovername);
103 : :
104 : : /*
105 : : * Make sure there is no existing file named recovername.
106 : : */
107 [ + + ]: 562 : if (stat(xlogpath, &stat_buf) != 0)
108 : : {
109 [ - + ]: 557 : 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 [ - + ]: 5 : 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 [ + + ]: 562 : if (cleanupEnabled)
142 : : {
143 : 407 : GetOldestRestartPoint(&restartRedoPtr, &restartTli);
144 : 407 : XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
145 : 407 : 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 : 155 : XLogFileName(lastRestartPointFname, 0, 0, wal_segment_size);
152 : :
153 : : /* Build the restore command to execute */
154 : 562 : xlogRestoreCmd = BuildRestoreCommand(recoveryRestoreCommand,
155 : : xlogpath, xlogfname,
156 : : lastRestartPointFname);
157 : :
158 [ - + ]: 562 : ereport(DEBUG3,
159 : : (errmsg_internal("executing restore command \"%s\"",
160 : : xlogRestoreCmd)));
161 : :
162 : 562 : fflush(NULL);
163 : 562 : 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 : 562 : PreRestoreCommand();
174 : :
175 : : /*
176 : : * Copy xlog from archival storage to XLOGDIR
177 : : */
178 : 562 : rc = system(xlogRestoreCmd);
179 : :
180 : 562 : PostRestoreCommand();
181 : :
182 : 562 : pgstat_report_wait_end();
183 : 562 : pfree(xlogRestoreCmd);
184 : :
185 [ + + ]: 562 : 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 [ + - ]: 380 : if (stat(xlogpath, &stat_buf) == 0)
192 : : {
193 [ + + - + ]: 380 : 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 [ + - ]: 380 : ereport(LOG,
223 : : (errmsg("restored log file \"%s\" from archive",
224 : : xlogfname)));
225 : 380 : strcpy(path, xlogpath);
226 : 380 : 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 [ - + ]: 182 : if (wait_result_is_signal(rc, SIGTERM))
266 : 0 : proc_exit(1);
267 : :
268 [ + + + + ]: 182 : 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 : 181 : 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 : 1103 : snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlogfname);
282 : 1103 : 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 : 372 : KeepFileRestoredFromArchive(const char *path, const char *xlogfname)
360 : : {
361 : : char xlogfpath[MAXPGPATH];
362 : 372 : bool reload = false;
363 : : struct stat statbuf;
364 : :
365 : 372 : snprintf(xlogfpath, MAXPGPATH, XLOGDIR "/%s", xlogfname);
366 : :
367 [ + + ]: 372 : if (stat(xlogfpath, &statbuf) == 0)
368 : : {
369 : : #ifdef WIN32
370 : : char oldpath[MAXPGPATH];
371 : : static unsigned int deletedcounter = 1;
372 : :
373 : : /*
374 : : * On Windows, if another process (e.g a walsender process) holds the
375 : : * file open in FILE_SHARE_DELETE mode, unlink will succeed, but the
376 : : * file will still show up in directory listing until the last handle
377 : : * is closed, and we cannot rename the new file in its place until
378 : : * that. To avoid that problem, rename the old file to a temporary
379 : : * name first. Use a counter to create a unique filename, because the
380 : : * same file might be restored from the archive multiple times, and a
381 : : * walsender could still be holding onto an old deleted version of it.
382 : : *
383 : : * Note that this leaves a short window where the target name does not
384 : : * exist, during which a concurrent walsender opening the segment
385 : : * could fail.
386 : : */
387 : : snprintf(oldpath, MAXPGPATH, "%s.deleted%u",
388 : : xlogfpath, deletedcounter++);
389 : : if (rename(xlogfpath, oldpath) != 0)
390 : : {
391 : : ereport(ERROR,
392 : : (errcode_for_file_access(),
393 : : errmsg("could not rename file \"%s\" to \"%s\": %m",
394 : : xlogfpath, oldpath)));
395 : : }
396 : :
397 : : if (unlink(oldpath) != 0)
398 : : ereport(FATAL,
399 : : (errcode_for_file_access(),
400 : : errmsg("could not remove file \"%s\": %m",
401 : : oldpath)));
402 : : #endif
403 : 31 : reload = true;
404 : : }
405 : :
406 : 372 : durable_rename(path, xlogfpath, ERROR);
407 : :
408 : : /*
409 : : * Create .done file forcibly to prevent the restored segment from being
410 : : * archived again later.
411 : : */
412 [ + + ]: 372 : if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
413 : 371 : XLogArchiveForceDone(xlogfname);
414 : : else
415 : 1 : XLogArchiveNotify(xlogfname);
416 : :
417 : : /*
418 : : * If the existing file was replaced, since walsenders might have it open,
419 : : * request them to reload a currently-open segment. This is only required
420 : : * for WAL segments, walsenders don't hold other files open, but there's
421 : : * no harm in doing this too often, and we don't know what kind of a file
422 : : * we're dealing with here.
423 : : */
424 [ + + ]: 372 : if (reload)
425 : 31 : WalSndRqstFileReload();
426 : :
427 : : /*
428 : : * Signal walsender that new WAL has arrived. Again, this isn't necessary
429 : : * if we restored something other than a WAL segment, but it does no harm
430 : : * either.
431 : : */
432 : 372 : WalSndWakeup(true, false);
433 : 372 : }
434 : :
435 : : /*
436 : : * XLogArchiveNotify
437 : : *
438 : : * Create an archive notification file
439 : : *
440 : : * The name of the notification file is the message that will be picked up
441 : : * by the archiver, e.g. we write 0000000100000001000000C6.ready
442 : : * and the archiver then knows to archive XLOGDIR/0000000100000001000000C6,
443 : : * then when complete, rename it to 0000000100000001000000C6.done
444 : : */
445 : : void
446 : 485 : XLogArchiveNotify(const char *xlog)
447 : : {
448 : : char archiveStatusPath[MAXPGPATH];
449 : : FILE *fd;
450 : :
451 : : /* insert an otherwise empty file called <XLOG>.ready */
452 : 485 : StatusFilePath(archiveStatusPath, xlog, ".ready");
453 : 485 : fd = AllocateFile(archiveStatusPath, "w");
454 [ - + ]: 485 : if (fd == NULL)
455 : : {
456 [ # # ]: 0 : ereport(LOG,
457 : : (errcode_for_file_access(),
458 : : errmsg("could not create archive status file \"%s\": %m",
459 : : archiveStatusPath)));
460 : 0 : return;
461 : : }
462 [ - + ]: 485 : if (FreeFile(fd))
463 : : {
464 [ # # ]: 0 : ereport(LOG,
465 : : (errcode_for_file_access(),
466 : : errmsg("could not write archive status file \"%s\": %m",
467 : : archiveStatusPath)));
468 : 0 : return;
469 : : }
470 : :
471 : : /*
472 : : * Timeline history files are given the highest archival priority to lower
473 : : * the chance that a promoted standby will choose a timeline that is
474 : : * already in use. However, the archiver ordinarily tries to gather
475 : : * multiple files to archive from each scan of the archive_status
476 : : * directory, which means that newly created timeline history files could
477 : : * be left unarchived for a while. To ensure that the archiver picks up
478 : : * timeline history files as soon as possible, we force the archiver to
479 : : * scan the archive_status directory the next time it looks for a file to
480 : : * archive.
481 : : */
482 [ + + ]: 485 : if (IsTLHistoryFileName(xlog))
483 : 16 : PgArchForceDirScan();
484 : :
485 : : /* Notify archiver that it's got something to do */
486 [ + - ]: 485 : if (IsUnderPostmaster)
487 : 485 : PgArchWakeup();
488 : : }
489 : :
490 : : /*
491 : : * Convenience routine to notify using segment number representation of filename
492 : : */
493 : : void
494 : 421 : XLogArchiveNotifySeg(XLogSegNo segno, TimeLineID tli)
495 : : {
496 : : char xlog[MAXFNAMELEN];
497 : :
498 : : Assert(tli != 0);
499 : :
500 : 421 : XLogFileName(xlog, tli, segno, wal_segment_size);
501 : 421 : XLogArchiveNotify(xlog);
502 : 421 : }
503 : :
504 : : /*
505 : : * XLogArchiveForceDone
506 : : *
507 : : * Emit notification forcibly that an XLOG segment file has been successfully
508 : : * archived, by creating <XLOG>.done regardless of whether <XLOG>.ready
509 : : * exists or not.
510 : : */
511 : : void
512 : 1159 : XLogArchiveForceDone(const char *xlog)
513 : : {
514 : : char archiveReady[MAXPGPATH];
515 : : char archiveDone[MAXPGPATH];
516 : : struct stat stat_buf;
517 : : FILE *fd;
518 : :
519 : : /* Exit if already known done */
520 : 1159 : StatusFilePath(archiveDone, xlog, ".done");
521 [ + + ]: 1159 : if (stat(archiveDone, &stat_buf) == 0)
522 : 16 : return;
523 : :
524 : : /* If .ready exists, rename it to .done */
525 : 1143 : StatusFilePath(archiveReady, xlog, ".ready");
526 [ - + ]: 1143 : if (stat(archiveReady, &stat_buf) == 0)
527 : : {
528 : 0 : (void) durable_rename(archiveReady, archiveDone, WARNING);
529 : 0 : return;
530 : : }
531 : :
532 : : /* insert an otherwise empty file called <XLOG>.done */
533 : 1143 : fd = AllocateFile(archiveDone, "w");
534 [ - + ]: 1143 : if (fd == NULL)
535 : : {
536 [ # # ]: 0 : ereport(LOG,
537 : : (errcode_for_file_access(),
538 : : errmsg("could not create archive status file \"%s\": %m",
539 : : archiveDone)));
540 : 0 : return;
541 : : }
542 [ - + ]: 1143 : if (FreeFile(fd))
543 : : {
544 [ # # ]: 0 : ereport(LOG,
545 : : (errcode_for_file_access(),
546 : : errmsg("could not write archive status file \"%s\": %m",
547 : : archiveDone)));
548 : 0 : return;
549 : : }
550 : : }
551 : :
552 : : /*
553 : : * XLogArchiveCheckDone
554 : : *
555 : : * This is called when we are ready to delete or recycle an old XLOG segment
556 : : * file or backup history file. If it is okay to delete it then return true.
557 : : * If it is not time to delete it, make sure a .ready file exists, and return
558 : : * false.
559 : : *
560 : : * If <XLOG>.done exists, then return true; else if <XLOG>.ready exists,
561 : : * then return false; else create <XLOG>.ready and return false.
562 : : *
563 : : * The reason we do things this way is so that if the original attempt to
564 : : * create <XLOG>.ready fails, we'll retry during subsequent checkpoints.
565 : : */
566 : : bool
567 : 32011 : XLogArchiveCheckDone(const char *xlog)
568 : : {
569 : : char archiveStatusPath[MAXPGPATH];
570 : : struct stat stat_buf;
571 : :
572 : : /* The file is always deletable if archive_mode is "off". */
573 [ + + ]: 32011 : if (!XLogArchivingActive())
574 : 2309 : return true;
575 : :
576 : : /*
577 : : * During archive recovery, the file is deletable if archive_mode is not
578 : : * "always".
579 : : */
580 [ + + + + ]: 59399 : if (!XLogArchivingAlways() &&
581 : 29697 : GetRecoveryState() == RECOVERY_STATE_ARCHIVE)
582 : 323 : return true;
583 : :
584 : : /*
585 : : * At this point of the logic, note that we are either a primary with
586 : : * archive_mode set to "on" or "always", or a standby with archive_mode
587 : : * set to "always".
588 : : */
589 : :
590 : : /* First check for .done --- this means archiver is done with it */
591 : 29379 : StatusFilePath(archiveStatusPath, xlog, ".done");
592 [ + + ]: 29379 : if (stat(archiveStatusPath, &stat_buf) == 0)
593 : 272 : return true;
594 : :
595 : : /* check for .ready --- this means archiver is still busy with it */
596 : 29107 : StatusFilePath(archiveStatusPath, xlog, ".ready");
597 [ + + ]: 29107 : if (stat(archiveStatusPath, &stat_buf) == 0)
598 : 29068 : return false;
599 : :
600 : : /* Race condition --- maybe archiver just finished, so recheck */
601 : 39 : StatusFilePath(archiveStatusPath, xlog, ".done");
602 [ - + ]: 39 : if (stat(archiveStatusPath, &stat_buf) == 0)
603 : 0 : return true;
604 : :
605 : : /* Retry creation of the .ready file */
606 : 39 : XLogArchiveNotify(xlog);
607 : 39 : return false;
608 : : }
609 : :
610 : : /*
611 : : * XLogArchiveIsBusy
612 : : *
613 : : * Check to see if an XLOG segment file is still unarchived.
614 : : * This is almost but not quite the inverse of XLogArchiveCheckDone: in
615 : : * the first place we aren't chartered to recreate the .ready file, and
616 : : * in the second place we should consider that if the file is already gone
617 : : * then it's not busy. (This check is needed to handle the race condition
618 : : * that a checkpoint already deleted the no-longer-needed file.)
619 : : */
620 : : bool
621 : 12 : XLogArchiveIsBusy(const char *xlog)
622 : : {
623 : : char archiveStatusPath[MAXPGPATH];
624 : : struct stat stat_buf;
625 : :
626 : : /* First check for .done --- this means archiver is done with it */
627 : 12 : StatusFilePath(archiveStatusPath, xlog, ".done");
628 [ + + ]: 12 : if (stat(archiveStatusPath, &stat_buf) == 0)
629 : 8 : return false;
630 : :
631 : : /* check for .ready --- this means archiver is still busy with it */
632 : 4 : StatusFilePath(archiveStatusPath, xlog, ".ready");
633 [ + - ]: 4 : if (stat(archiveStatusPath, &stat_buf) == 0)
634 : 4 : return true;
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 false;
640 : :
641 : : /*
642 : : * Check to see if the WAL file has been removed by checkpoint, which
643 : : * implies it has already been archived, and explains why we can't see a
644 : : * status file for it.
645 : : */
646 : 0 : snprintf(archiveStatusPath, MAXPGPATH, XLOGDIR "/%s", xlog);
647 [ # # ]: 0 : if (stat(archiveStatusPath, &stat_buf) != 0 &&
648 [ # # ]: 0 : errno == ENOENT)
649 : 0 : return false;
650 : :
651 : 0 : return true;
652 : : }
653 : :
654 : : /*
655 : : * XLogArchiveIsReadyOrDone
656 : : *
657 : : * Check to see if an XLOG segment file has a .ready or .done file.
658 : : * This is similar to XLogArchiveIsBusy(), but returns true if the file
659 : : * is already archived or is about to be archived.
660 : : *
661 : : * This is currently only used at recovery. During normal operation this
662 : : * would be racy: the file might get removed or marked with .ready as we're
663 : : * checking it, or immediately after we return.
664 : : */
665 : : bool
666 : 12 : XLogArchiveIsReadyOrDone(const char *xlog)
667 : : {
668 : : char archiveStatusPath[MAXPGPATH];
669 : : struct stat stat_buf;
670 : :
671 : : /* First check for .done --- this means archiver is done with it */
672 : 12 : StatusFilePath(archiveStatusPath, xlog, ".done");
673 [ + + ]: 12 : if (stat(archiveStatusPath, &stat_buf) == 0)
674 : 4 : return true;
675 : :
676 : : /* check for .ready --- this means archiver is still busy with it */
677 : 8 : StatusFilePath(archiveStatusPath, xlog, ".ready");
678 [ - + ]: 8 : if (stat(archiveStatusPath, &stat_buf) == 0)
679 : 0 : return true;
680 : :
681 : : /* Race condition --- maybe archiver just finished, so recheck */
682 : 8 : StatusFilePath(archiveStatusPath, xlog, ".done");
683 [ - + ]: 8 : if (stat(archiveStatusPath, &stat_buf) == 0)
684 : 0 : return true;
685 : :
686 : 8 : return false;
687 : : }
688 : :
689 : : /*
690 : : * XLogArchiveIsReady
691 : : *
692 : : * Check to see if an XLOG segment file has an archive notification (.ready)
693 : : * file.
694 : : */
695 : : bool
696 : 16 : XLogArchiveIsReady(const char *xlog)
697 : : {
698 : : char archiveStatusPath[MAXPGPATH];
699 : : struct stat stat_buf;
700 : :
701 : 16 : StatusFilePath(archiveStatusPath, xlog, ".ready");
702 [ - + ]: 16 : if (stat(archiveStatusPath, &stat_buf) == 0)
703 : 0 : return true;
704 : :
705 : 16 : return false;
706 : : }
707 : :
708 : : /*
709 : : * XLogArchiveCleanup
710 : : *
711 : : * Cleanup archive notification file(s) for a particular xlog segment
712 : : */
713 : : void
714 : 2990 : XLogArchiveCleanup(const char *xlog)
715 : : {
716 : : char archiveStatusPath[MAXPGPATH];
717 : :
718 : : /* Remove the .done file */
719 : 2990 : StatusFilePath(archiveStatusPath, xlog, ".done");
720 : 2990 : unlink(archiveStatusPath);
721 : : /* should we complain about failure? */
722 : :
723 : : /* Remove the .ready file if present --- normally it shouldn't be */
724 : 2990 : StatusFilePath(archiveStatusPath, xlog, ".ready");
725 : 2990 : unlink(archiveStatusPath);
726 : : /* should we complain about failure? */
727 : 2990 : }
|