Coverage Report

Created: 2026-11-12 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/access/transam/xlogarchive.c
Line
Count
Source
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
RestoreArchivedFile(char *path, const char *xlogfname,
56
          const char *recovername, off_t expectedSize,
57
          bool cleanupEnabled)
58
0
{
59
0
  char    xlogpath[MAXPGPATH];
60
0
  char     *xlogRestoreCmd;
61
0
  char    lastRestartPointFname[MAXPGPATH];
62
0
  int     rc;
63
0
  struct stat stat_buf;
64
0
  XLogSegNo restartSegNo;
65
0
  XLogRecPtr  restartRedoPtr;
66
0
  TimeLineID  restartTli;
67
68
  /*
69
   * Ignore restore_command when not in archive recovery (meaning we are in
70
   * crash recovery).
71
   */
72
0
  if (!ArchiveRecoveryRequested)
73
0
    goto not_available;
74
75
  /* In standby mode, restore_command might not be supplied */
76
0
  if (recoveryRestoreCommand == NULL || strcmp(recoveryRestoreCommand, "") == 0)
77
0
    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
0
  snprintf(xlogpath, MAXPGPATH, XLOGDIR "/%s", recovername);
103
104
  /*
105
   * Make sure there is no existing file named recovername.
106
   */
107
0
  if (stat(xlogpath, &stat_buf) != 0)
108
0
  {
109
0
    if (errno != ENOENT)
110
0
      ereport(FATAL,
111
0
          (errcode_for_file_access(),
112
0
           errmsg("could not stat file \"%s\": %m",
113
0
              xlogpath)));
114
0
  }
115
0
  else
116
0
  {
117
0
    if (unlink(xlogpath) != 0)
118
0
      ereport(FATAL,
119
0
          (errcode_for_file_access(),
120
0
           errmsg("could not remove file \"%s\": %m",
121
0
              xlogpath)));
122
0
  }
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
0
  if (cleanupEnabled)
142
0
  {
143
0
    GetOldestRestartPoint(&restartRedoPtr, &restartTli);
144
0
    XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
145
0
    XLogFileName(lastRestartPointFname, restartTli, restartSegNo,
146
0
           wal_segment_size);
147
    /* we shouldn't need anything earlier than last restart point */
148
0
    Assert(strcmp(lastRestartPointFname, xlogfname) <= 0);
149
0
  }
150
0
  else
151
0
    XLogFileName(lastRestartPointFname, 0, 0, wal_segment_size);
152
153
  /* Build the restore command to execute */
154
0
  xlogRestoreCmd = BuildRestoreCommand(recoveryRestoreCommand,
155
0
                     xlogpath, xlogfname,
156
0
                     lastRestartPointFname);
157
158
0
  ereport(DEBUG3,
159
0
      (errmsg_internal("executing restore command \"%s\"",
160
0
               xlogRestoreCmd)));
161
162
0
  fflush(NULL);
163
0
  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
0
  PreRestoreCommand();
174
175
  /*
176
   * Copy xlog from archival storage to XLOGDIR
177
   */
178
0
  rc = system(xlogRestoreCmd);
179
180
0
  PostRestoreCommand();
181
182
0
  pgstat_report_wait_end();
183
0
  pfree(xlogRestoreCmd);
184
185
0
  if (rc == 0)
186
0
  {
187
    /*
188
     * command apparently succeeded, but let's make sure the file is
189
     * really there now and has the correct size.
190
     */
191
0
    if (stat(xlogpath, &stat_buf) == 0)
192
0
    {
193
0
      if (expectedSize > 0 && stat_buf.st_size != expectedSize)
194
0
      {
195
0
        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
0
        else
212
0
          elevel = FATAL;
213
0
        ereport(elevel,
214
0
            (errmsg("archive file \"%s\" has wrong size: %lld instead of %lld",
215
0
                xlogfname,
216
0
                (long long int) stat_buf.st_size,
217
0
                (long long int) expectedSize)));
218
0
        return false;
219
0
      }
220
0
      else
221
0
      {
222
0
        ereport(LOG,
223
0
            (errmsg("restored log file \"%s\" from archive",
224
0
                xlogfname)));
225
0
        strcpy(path, xlogpath);
226
0
        return true;
227
0
      }
228
0
    }
229
0
    else
230
0
    {
231
      /* stat failed */
232
0
      int     elevel = (errno == ENOENT) ? LOG : FATAL;
233
234
0
      ereport(elevel,
235
0
          (errcode_for_file_access(),
236
0
           errmsg("could not stat file \"%s\": %m", xlogpath),
237
0
           errdetail("\"restore_command\" returned a zero exit status, but stat() failed.")));
238
0
    }
239
0
  }
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
0
  if (wait_result_is_signal(rc, SIGTERM))
266
0
    proc_exit(1);
267
268
0
  ereport(wait_result_is_any_signal(rc, true) ? FATAL : DEBUG2,
269
0
      (errmsg("could not restore file \"%s\" from archive: %s",
270
0
          xlogfname, wait_result_to_str(rc))));
271
272
0
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
0
  snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlogfname);
282
0
  return false;
283
0
}
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
ExecuteRecoveryCommand(const char *command, const char *commandName,
297
             bool failOnSignal, uint32 wait_event_info)
298
0
{
299
0
  char     *xlogRecoveryCmd;
300
0
  char    lastRestartPointFname[MAXPGPATH];
301
0
  int     rc;
302
0
  XLogSegNo restartSegNo;
303
0
  XLogRecPtr  restartRedoPtr;
304
0
  TimeLineID  restartTli;
305
306
0
  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
0
  GetOldestRestartPoint(&restartRedoPtr, &restartTli);
314
0
  XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
315
0
  XLogFileName(lastRestartPointFname, restartTli, restartSegNo,
316
0
         wal_segment_size);
317
318
  /*
319
   * construct the command to be executed
320
   */
321
0
  xlogRecoveryCmd = replace_percent_placeholders(command, commandName, "r", lastRestartPointFname);
322
323
0
  ereport(DEBUG3,
324
0
      (errmsg_internal("executing %s \"%s\"", commandName, command)));
325
326
  /*
327
   * execute the constructed command
328
   */
329
0
  fflush(NULL);
330
0
  pgstat_report_wait_start(wait_event_info);
331
0
  rc = system(xlogRecoveryCmd);
332
0
  pgstat_report_wait_end();
333
334
0
  pfree(xlogRecoveryCmd);
335
336
0
  if (rc != 0)
337
0
  {
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
0
    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
0
        (errmsg("%s \"%s\": %s", commandName,
348
0
            command, wait_result_to_str(rc))));
349
0
  }
350
0
}
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
KeepFileRestoredFromArchive(const char *path, const char *xlogfname)
360
0
{
361
0
  char    xlogfpath[MAXPGPATH];
362
0
  bool    reload = false;
363
0
  struct stat statbuf;
364
365
0
  snprintf(xlogfpath, MAXPGPATH, XLOGDIR "/%s", xlogfname);
366
367
0
  if (stat(xlogfpath, &statbuf) == 0)
368
0
  {
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
0
    reload = true;
404
0
  }
405
406
0
  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
0
  if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
413
0
    XLogArchiveForceDone(xlogfname);
414
0
  else
415
0
    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
0
  if (reload)
425
0
    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
0
  WalSndWakeup(true, false);
433
0
}
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
XLogArchiveNotify(const char *xlog)
447
0
{
448
0
  char    archiveStatusPath[MAXPGPATH];
449
0
  FILE     *fd;
450
451
  /* insert an otherwise empty file called <XLOG>.ready */
452
0
  StatusFilePath(archiveStatusPath, xlog, ".ready");
453
0
  fd = AllocateFile(archiveStatusPath, "w");
454
0
  if (fd == NULL)
455
0
  {
456
0
    ereport(LOG,
457
0
        (errcode_for_file_access(),
458
0
         errmsg("could not create archive status file \"%s\": %m",
459
0
            archiveStatusPath)));
460
0
    return;
461
0
  }
462
0
  if (FreeFile(fd))
463
0
  {
464
0
    ereport(LOG,
465
0
        (errcode_for_file_access(),
466
0
         errmsg("could not write archive status file \"%s\": %m",
467
0
            archiveStatusPath)));
468
0
    return;
469
0
  }
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
0
  if (IsTLHistoryFileName(xlog))
483
0
    PgArchForceDirScan();
484
485
  /* Notify archiver that it's got something to do */
486
0
  if (IsUnderPostmaster)
487
0
    PgArchWakeup();
488
0
}
489
490
/*
491
 * Convenience routine to notify using segment number representation of filename
492
 */
493
void
494
XLogArchiveNotifySeg(XLogSegNo segno, TimeLineID tli)
495
0
{
496
0
  char    xlog[MAXFNAMELEN];
497
498
0
  Assert(tli != 0);
499
500
0
  XLogFileName(xlog, tli, segno, wal_segment_size);
501
0
  XLogArchiveNotify(xlog);
502
0
}
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
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
  StatusFilePath(archiveDone, xlog, ".done");
521
  if (stat(archiveDone, &stat_buf) == 0)
522
    return;
523
524
  /* If .ready exists, rename it to .done */
525
  StatusFilePath(archiveReady, xlog, ".ready");
526
  if (stat(archiveReady, &stat_buf) == 0)
527
  {
528
    (void) durable_rename(archiveReady, archiveDone, WARNING);
529
    return;
530
  }
531
532
  /* insert an otherwise empty file called <XLOG>.done */
533
  fd = AllocateFile(archiveDone, "w");
534
  if (fd == NULL)
535
  {
536
    ereport(LOG,
537
        (errcode_for_file_access(),
538
         errmsg("could not create archive status file \"%s\": %m",
539
            archiveDone)));
540
    return;
541
  }
542
  if (FreeFile(fd))
543
  {
544
    ereport(LOG,
545
        (errcode_for_file_access(),
546
         errmsg("could not write archive status file \"%s\": %m",
547
            archiveDone)));
548
    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
XLogArchiveCheckDone(const char *xlog)
568
0
{
569
0
  char    archiveStatusPath[MAXPGPATH];
570
0
  struct stat stat_buf;
571
572
  /* The file is always deletable if archive_mode is "off". */
573
0
  if (!XLogArchivingActive())
574
0
    return true;
575
576
  /*
577
   * During archive recovery, the file is deletable if archive_mode is not
578
   * "always".
579
   */
580
0
  if (!XLogArchivingAlways() &&
581
0
    GetRecoveryState() == RECOVERY_STATE_ARCHIVE)
582
0
    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
0
  StatusFilePath(archiveStatusPath, xlog, ".done");
592
0
  if (stat(archiveStatusPath, &stat_buf) == 0)
593
0
    return true;
594
595
  /* check for .ready --- this means archiver is still busy with it */
596
0
  StatusFilePath(archiveStatusPath, xlog, ".ready");
597
0
  if (stat(archiveStatusPath, &stat_buf) == 0)
598
0
    return false;
599
600
  /* Race condition --- maybe archiver just finished, so recheck */
601
0
  StatusFilePath(archiveStatusPath, xlog, ".done");
602
0
  if (stat(archiveStatusPath, &stat_buf) == 0)
603
0
    return true;
604
605
  /* Retry creation of the .ready file */
606
0
  XLogArchiveNotify(xlog);
607
0
  return false;
608
0
}
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
XLogArchiveIsBusy(const char *xlog)
622
0
{
623
0
  char    archiveStatusPath[MAXPGPATH];
624
0
  struct stat stat_buf;
625
626
  /* First check for .done --- this means archiver is done with it */
627
0
  StatusFilePath(archiveStatusPath, xlog, ".done");
628
0
  if (stat(archiveStatusPath, &stat_buf) == 0)
629
0
    return false;
630
631
  /* check for .ready --- this means archiver is still busy with it */
632
0
  StatusFilePath(archiveStatusPath, xlog, ".ready");
633
0
  if (stat(archiveStatusPath, &stat_buf) == 0)
634
0
    return 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
0
}
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
XLogArchiveIsReadyOrDone(const char *xlog)
667
0
{
668
0
  char    archiveStatusPath[MAXPGPATH];
669
0
  struct stat stat_buf;
670
671
  /* First check for .done --- this means archiver is done with it */
672
0
  StatusFilePath(archiveStatusPath, xlog, ".done");
673
0
  if (stat(archiveStatusPath, &stat_buf) == 0)
674
0
    return true;
675
676
  /* check for .ready --- this means archiver is still busy with it */
677
0
  StatusFilePath(archiveStatusPath, xlog, ".ready");
678
0
  if (stat(archiveStatusPath, &stat_buf) == 0)
679
0
    return true;
680
681
  /* Race condition --- maybe archiver just finished, so recheck */
682
0
  StatusFilePath(archiveStatusPath, xlog, ".done");
683
0
  if (stat(archiveStatusPath, &stat_buf) == 0)
684
0
    return true;
685
686
0
  return false;
687
0
}
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
XLogArchiveIsReady(const char *xlog)
697
0
{
698
0
  char    archiveStatusPath[MAXPGPATH];
699
0
  struct stat stat_buf;
700
701
0
  StatusFilePath(archiveStatusPath, xlog, ".ready");
702
0
  if (stat(archiveStatusPath, &stat_buf) == 0)
703
0
    return true;
704
705
0
  return false;
706
0
}
707
708
/*
709
 * XLogArchiveCleanup
710
 *
711
 * Cleanup archive notification file(s) for a particular xlog segment
712
 */
713
void
714
XLogArchiveCleanup(const char *xlog)
715
0
{
716
0
  char    archiveStatusPath[MAXPGPATH];
717
718
  /* Remove the .done file */
719
0
  StatusFilePath(archiveStatusPath, xlog, ".done");
720
0
  unlink(archiveStatusPath);
721
  /* should we complain about failure? */
722
723
  /* Remove the .ready file if present --- normally it shouldn't be */
724
0
  StatusFilePath(archiveStatusPath, xlog, ".ready");
725
0
  unlink(archiveStatusPath);
726
  /* should we complain about failure? */
727
0
}