Age Owner Branch data TLA 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
4912 heikki.linnakangas@i 55 :CBC 1309 : 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 : : */
2347 fujii@postgresql.org 72 [ + + ]: 1309 : if (!ArchiveRecoveryRequested)
73 : 27 : goto not_available;
74 : :
75 : : /* In standby mode, restore_command might not be supplied */
2667 peter_e@gmx.net 76 [ + - + + ]: 1282 : if (recoveryRestoreCommand == NULL || strcmp(recoveryRestoreCommand, "") == 0)
4912 heikki.linnakangas@i 77 : 765 : 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 : 517 : snprintf(xlogpath, MAXPGPATH, XLOGDIR "/%s", recovername);
103 : :
104 : : /*
105 : : * Make sure there is no existing file named recovername.
106 : : */
107 [ + + ]: 517 : if (stat(xlogpath, &stat_buf) != 0)
108 : : {
109 [ - + ]: 513 : if (errno != ENOENT)
4912 heikki.linnakangas@i 110 [ # # ]:UBC 0 : ereport(FATAL,
111 : : (errcode_for_file_access(),
112 : : errmsg("could not stat file \"%s\": %m",
113 : : xlogpath)));
114 : : }
115 : : else
116 : : {
4912 heikki.linnakangas@i 117 [ - + ]:CBC 4 : if (unlink(xlogpath) != 0)
4912 heikki.linnakangas@i 118 [ # # ]:UBC 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 : : */
4864 heikki.linnakangas@i 141 [ + + ]:CBC 517 : if (cleanupEnabled)
142 : : {
143 : 389 : GetOldestRestartPoint(&restartRedoPtr, &restartTli);
3099 andres@anarazel.de 144 : 389 : XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
145 : 389 : XLogFileName(lastRestartPointFname, restartTli, restartSegNo,
146 : : wal_segment_size);
147 : : /* we shouldn't need anything earlier than last restart point */
4912 heikki.linnakangas@i 148 [ - + ]: 389 : Assert(strcmp(lastRestartPointFname, xlogfname) <= 0);
149 : : }
150 : : else
1082 peter@eisentraut.org 151 : 128 : XLogFileName(lastRestartPointFname, 0, 0, wal_segment_size);
152 : :
153 : : /* Build the restore command to execute */
1133 michael@paquier.xyz 154 : 517 : xlogRestoreCmd = BuildRestoreCommand(recoveryRestoreCommand,
155 : : xlogpath, xlogfname,
156 : : lastRestartPointFname);
157 : :
158 [ - + ]: 517 : ereport(DEBUG3,
159 : : (errmsg_internal("executing restore command \"%s\"",
160 : : xlogRestoreCmd)));
161 : :
881 nathan@postgresql.or 162 : 517 : fflush(NULL);
163 : 517 : 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 : : */
4912 heikki.linnakangas@i 173 : 517 : PreRestoreCommand();
174 : :
175 : : /*
176 : : * Copy xlog from archival storage to XLOGDIR
177 : : */
1133 michael@paquier.xyz 178 : 517 : rc = system(xlogRestoreCmd);
179 : :
4912 heikki.linnakangas@i 180 : 516 : PostRestoreCommand();
181 : :
881 nathan@postgresql.or 182 : 516 : pgstat_report_wait_end();
1133 michael@paquier.xyz 183 : 516 : pfree(xlogRestoreCmd);
184 : :
185 [ + + ]: 516 : 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 : : */
4912 heikki.linnakangas@i 191 [ + - ]: 373 : if (stat(xlogpath, &stat_buf) == 0)
192 : : {
193 [ + + - + ]: 373 : 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 : : */
4912 heikki.linnakangas@i 209 [ # # # # ]:UBC 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 : : {
4912 heikki.linnakangas@i 222 [ + - ]:CBC 373 : ereport(LOG,
223 : : (errmsg("restored log file \"%s\" from archive",
224 : : xlogfname)));
225 : 373 : strcpy(path, xlogpath);
226 : 373 : return true;
227 : : }
228 : : }
229 : : else
230 : : {
231 : : /* stat failed */
1941 fujii@postgresql.org 232 [ # # ]:UBC 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 : : */
1133 michael@paquier.xyz 265 [ - + ]:CBC 143 : if (wait_result_is_signal(rc, SIGTERM))
1133 michael@paquier.xyz 266 :UBC 0 : proc_exit(1);
267 : :
1133 michael@paquier.xyz 268 [ - + + + ]:CBC 143 : 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 : :
4912 heikki.linnakangas@i 272 : 143 : 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 : 935 : snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlogfname);
282 : 935 : 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
1133 michael@paquier.xyz 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 [ + - - + ]: 2 : 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
3057 peter_e@gmx.net 359 : 366 : KeepFileRestoredFromArchive(const char *path, const char *xlogfname)
360 : : {
361 : : char xlogfpath[MAXPGPATH];
4823 heikki.linnakangas@i 362 : 366 : bool reload = false;
363 : : struct stat statbuf;
364 : :
365 : 366 : snprintf(xlogfpath, MAXPGPATH, XLOGDIR "/%s", xlogfname);
366 : :
367 [ + + ]: 366 : 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 */
4227 noah@leadboat.com 395 : 28 : strlcpy(oldpath, xlogfpath, MAXPGPATH);
396 : : #endif
4823 heikki.linnakangas@i 397 [ - + ]: 28 : if (unlink(oldpath) != 0)
4823 heikki.linnakangas@i 398 [ # # ]:UBC 0 : ereport(FATAL,
399 : : (errcode_for_file_access(),
400 : : errmsg("could not remove file \"%s\": %m",
401 : : xlogfpath)));
4823 heikki.linnakangas@i 402 :CBC 28 : reload = true;
403 : : }
404 : :
3658 andres@anarazel.de 405 : 366 : durable_rename(path, xlogfpath, ERROR);
406 : :
407 : : /*
408 : : * Create .done file forcibly to prevent the restored segment from being
409 : : * archived again later.
410 : : */
3957 heikki.linnakangas@i 411 [ + + ]: 366 : if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
412 : 365 : XLogArchiveForceDone(xlogfname);
413 : : else
1653 alvherre@alvh.no-ip. 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 : : */
4823 heikki.linnakangas@i 423 [ + + ]: 366 : if (reload)
424 : 28 : 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 : : */
1072 andres@anarazel.de 431 : 366 : WalSndWakeup(true, false);
4823 heikki.linnakangas@i 432 : 366 : }
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
1653 alvherre@alvh.no-ip. 445 : 465 : XLogArchiveNotify(const char *xlog)
446 : : {
447 : : char archiveStatusPath[MAXPGPATH];
448 : : FILE *fd;
449 : :
450 : : /* insert an otherwise empty file called <XLOG>.ready */
4912 heikki.linnakangas@i 451 : 465 : StatusFilePath(archiveStatusPath, xlog, ".ready");
452 : 465 : fd = AllocateFile(archiveStatusPath, "w");
453 [ - + ]: 465 : if (fd == NULL)
454 : : {
4912 heikki.linnakangas@i 455 [ # # ]:UBC 0 : ereport(LOG,
456 : : (errcode_for_file_access(),
457 : : errmsg("could not create archive status file \"%s\": %m",
458 : : archiveStatusPath)));
459 : 0 : return;
460 : : }
4912 heikki.linnakangas@i 461 [ - + ]:CBC 465 : if (FreeFile(fd))
462 : : {
4912 heikki.linnakangas@i 463 [ # # ]:UBC 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 : : */
1585 rhaas@postgresql.org 481 [ + + ]:CBC 465 : if (IsTLHistoryFileName(xlog))
482 : 14 : PgArchForceDirScan();
483 : :
484 : : /* Notify archiver that it's got something to do */
1653 alvherre@alvh.no-ip. 485 [ + - ]: 465 : if (IsUnderPostmaster)
1826 fujii@postgresql.org 486 : 465 : PgArchWakeup();
487 : : }
488 : :
489 : : /*
490 : : * Convenience routine to notify using segment number representation of filename
491 : : */
492 : : void
1591 rhaas@postgresql.org 493 : 409 : XLogArchiveNotifySeg(XLogSegNo segno, TimeLineID tli)
494 : : {
495 : : char xlog[MAXFNAMELEN];
496 : :
497 [ - + ]: 409 : Assert(tli != 0);
498 : :
499 : 409 : XLogFileName(xlog, tli, segno, wal_segment_size);
1653 alvherre@alvh.no-ip. 500 : 409 : XLogArchiveNotify(xlog);
4912 heikki.linnakangas@i 501 : 409 : }
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
4967 simon@2ndQuadrant.co 511 : 1119 : 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 : 1119 : StatusFilePath(archiveDone, xlog, ".done");
520 [ + + ]: 1119 : if (stat(archiveDone, &stat_buf) == 0)
521 : 14 : return;
522 : :
523 : : /* If .ready exists, rename it to .done */
524 : 1105 : StatusFilePath(archiveReady, xlog, ".ready");
525 [ - + ]: 1105 : if (stat(archiveReady, &stat_buf) == 0)
526 : : {
3658 andres@anarazel.de 527 :UBC 0 : (void) durable_rename(archiveReady, archiveDone, WARNING);
4967 simon@2ndQuadrant.co 528 : 0 : return;
529 : : }
530 : :
531 : : /* insert an otherwise empty file called <XLOG>.done */
4967 simon@2ndQuadrant.co 532 :CBC 1105 : fd = AllocateFile(archiveDone, "w");
533 [ - + ]: 1105 : if (fd == NULL)
534 : : {
4967 simon@2ndQuadrant.co 535 [ # # ]:UBC 0 : ereport(LOG,
536 : : (errcode_for_file_access(),
537 : : errmsg("could not create archive status file \"%s\": %m",
538 : : archiveDone)));
539 : 0 : return;
540 : : }
4967 simon@2ndQuadrant.co 541 [ - + ]:CBC 1105 : if (FreeFile(fd))
542 : : {
4967 simon@2ndQuadrant.co 543 [ # # ]:UBC 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
4912 heikki.linnakangas@i 566 :CBC 28860 : 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". */
2151 michael@paquier.xyz 572 [ + + - + : 28860 : if (!XLogArchivingActive())
+ + ]
573 : 2169 : return true;
574 : :
575 : : /*
576 : : * During archive recovery, the file is deletable if archive_mode is not
577 : : * "always".
578 : : */
579 [ + - - + : 53377 : if (!XLogArchivingAlways() &&
+ + + + ]
580 : 26686 : GetRecoveryState() == RECOVERY_STATE_ARCHIVE)
4912 heikki.linnakangas@i 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 : 26368 : StatusFilePath(archiveStatusPath, xlog, ".done");
591 [ + + ]: 26368 : if (stat(archiveStatusPath, &stat_buf) == 0)
592 : 240 : return true;
593 : :
594 : : /* check for .ready --- this means archiver is still busy with it */
595 : 26128 : StatusFilePath(archiveStatusPath, xlog, ".ready");
596 [ + + ]: 26128 : if (stat(archiveStatusPath, &stat_buf) == 0)
597 : 26091 : return false;
598 : :
599 : : /* Race condition --- maybe archiver just finished, so recheck */
600 : 37 : StatusFilePath(archiveStatusPath, xlog, ".done");
601 [ + + ]: 37 : if (stat(archiveStatusPath, &stat_buf) == 0)
4912 heikki.linnakangas@i 602 :GBC 1 : return true;
603 : :
604 : : /* Retry creation of the .ready file */
1653 alvherre@alvh.no-ip. 605 :CBC 36 : XLogArchiveNotify(xlog);
4912 heikki.linnakangas@i 606 : 36 : 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 : 12 : 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 : 12 : StatusFilePath(archiveStatusPath, xlog, ".done");
627 [ + + ]: 12 : if (stat(archiveStatusPath, &stat_buf) == 0)
628 : 8 : return false;
629 : :
630 : : /* check for .ready --- this means archiver is still busy with it */
631 : 4 : StatusFilePath(archiveStatusPath, xlog, ".ready");
632 [ + - ]: 4 : if (stat(archiveStatusPath, &stat_buf) == 0)
633 : 4 : return true;
634 : :
635 : : /* Race condition --- maybe archiver just finished, so recheck */
4912 heikki.linnakangas@i 636 :UBC 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
3951 heikki.linnakangas@i 665 :CBC 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)
3951 heikki.linnakangas@i 678 :UBC 0 : return true;
679 : :
680 : : /* Race condition --- maybe archiver just finished, so recheck */
3951 heikki.linnakangas@i 681 :CBC 5 : StatusFilePath(archiveStatusPath, xlog, ".done");
682 [ - + ]: 5 : if (stat(archiveStatusPath, &stat_buf) == 0)
3951 heikki.linnakangas@i 683 :UBC 0 : return true;
684 : :
3951 heikki.linnakangas@i 685 :CBC 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
3989 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)
3989 heikki.linnakangas@i 702 :UBC 0 : return true;
703 : :
3989 heikki.linnakangas@i 704 :CBC 16 : return false;
705 : : }
706 : :
707 : : /*
708 : : * XLogArchiveCleanup
709 : : *
710 : : * Cleanup archive notification file(s) for a particular xlog segment
711 : : */
712 : : void
4912 713 : 2809 : XLogArchiveCleanup(const char *xlog)
714 : : {
715 : : char archiveStatusPath[MAXPGPATH];
716 : :
717 : : /* Remove the .done file */
718 : 2809 : StatusFilePath(archiveStatusPath, xlog, ".done");
719 : 2809 : unlink(archiveStatusPath);
720 : : /* should we complain about failure? */
721 : :
722 : : /* Remove the .ready file if present --- normally it shouldn't be */
723 : 2809 : StatusFilePath(archiveStatusPath, xlog, ".ready");
724 : 2809 : unlink(archiveStatusPath);
725 : : /* should we complain about failure? */
726 : 2809 : }
|