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