LCOV - differential code coverage report
Current view: top level - src/backend/access/transam - xlogarchive.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 79.8 % 163 130 9 20 4 8 91 6 25 20 86 1 10
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 11 11 11 10 1
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a