LCOV - code coverage report
Current view: top level - src/backend/access/transam - xlogarchive.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 79.4 % 160 127
Test Date: 2026-07-07 08:15:41 Functions: 100.0 % 11 11
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 54.2 % 120 65

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

Generated by: LCOV version 2.0-1