LCOV - code coverage report
Current view: top level - src/backend/replication - basebackup.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 406 527 77.0 %
Date: 2019-06-18 07:06:57 Functions: 14 16 87.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * basebackup.c
       4             :  *    code for taking a base backup and streaming it to a standby
       5             :  *
       6             :  * Portions Copyright (c) 2010-2019, PostgreSQL Global Development Group
       7             :  *
       8             :  * IDENTIFICATION
       9             :  *    src/backend/replication/basebackup.c
      10             :  *
      11             :  *-------------------------------------------------------------------------
      12             :  */
      13             : #include "postgres.h"
      14             : 
      15             : #include <sys/stat.h>
      16             : #include <unistd.h>
      17             : #include <time.h>
      18             : 
      19             : #include "access/xlog_internal.h" /* for pg_start/stop_backup */
      20             : #include "catalog/pg_type.h"
      21             : #include "common/file_perm.h"
      22             : #include "lib/stringinfo.h"
      23             : #include "libpq/libpq.h"
      24             : #include "libpq/pqformat.h"
      25             : #include "miscadmin.h"
      26             : #include "nodes/pg_list.h"
      27             : #include "pgtar.h"
      28             : #include "pgstat.h"
      29             : #include "port.h"
      30             : #include "postmaster/syslogger.h"
      31             : #include "replication/basebackup.h"
      32             : #include "replication/walsender.h"
      33             : #include "replication/walsender_private.h"
      34             : #include "storage/bufpage.h"
      35             : #include "storage/checksum.h"
      36             : #include "storage/dsm_impl.h"
      37             : #include "storage/fd.h"
      38             : #include "storage/ipc.h"
      39             : #include "storage/reinit.h"
      40             : #include "utils/builtins.h"
      41             : #include "utils/ps_status.h"
      42             : #include "utils/relcache.h"
      43             : #include "utils/timestamp.h"
      44             : 
      45             : 
      46             : typedef struct
      47             : {
      48             :     const char *label;
      49             :     bool        progress;
      50             :     bool        fastcheckpoint;
      51             :     bool        nowait;
      52             :     bool        includewal;
      53             :     uint32      maxrate;
      54             :     bool        sendtblspcmapfile;
      55             : } basebackup_options;
      56             : 
      57             : 
      58             : static int64 sendDir(const char *path, int basepathlen, bool sizeonly,
      59             :                      List *tablespaces, bool sendtblspclinks);
      60             : static bool sendFile(const char *readfilename, const char *tarfilename,
      61             :                      struct stat *statbuf, bool missing_ok, Oid dboid);
      62             : static void sendFileWithContent(const char *filename, const char *content);
      63             : static int64 _tarWriteHeader(const char *filename, const char *linktarget,
      64             :                              struct stat *statbuf, bool sizeonly);
      65             : static int64 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
      66             :                           bool sizeonly);
      67             : static void send_int8_string(StringInfoData *buf, int64 intval);
      68             : static void SendBackupHeader(List *tablespaces);
      69             : static void base_backup_cleanup(int code, Datum arg);
      70             : static void perform_base_backup(basebackup_options *opt);
      71             : static void parse_basebackup_options(List *options, basebackup_options *opt);
      72             : static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli);
      73             : static int  compareWalFileNames(const void *a, const void *b);
      74             : static void throttle(size_t increment);
      75             : static bool is_checksummed_file(const char *fullpath, const char *filename);
      76             : 
      77             : /* Was the backup currently in-progress initiated in recovery mode? */
      78             : static bool backup_started_in_recovery = false;
      79             : 
      80             : /* Relative path of temporary statistics directory */
      81             : static char *statrelpath = NULL;
      82             : 
      83             : /*
      84             :  * Size of each block sent into the tar stream for larger files.
      85             :  */
      86             : #define TAR_SEND_SIZE 32768
      87             : 
      88             : /*
      89             :  * How frequently to throttle, as a fraction of the specified rate-second.
      90             :  */
      91             : #define THROTTLING_FREQUENCY    8
      92             : 
      93             : /* The actual number of bytes, transfer of which may cause sleep. */
      94             : static uint64 throttling_sample;
      95             : 
      96             : /* Amount of data already transferred but not yet throttled.  */
      97             : static int64 throttling_counter;
      98             : 
      99             : /* The minimum time required to transfer throttling_sample bytes. */
     100             : static TimeOffset elapsed_min_unit;
     101             : 
     102             : /* The last check of the transfer rate. */
     103             : static TimestampTz throttled_last;
     104             : 
     105             : /* The starting XLOG position of the base backup. */
     106             : static XLogRecPtr startptr;
     107             : 
     108             : /* Total number of checksum failures during base backup. */
     109             : static int64 total_checksum_failures;
     110             : 
     111             : /* Do not verify checksums. */
     112             : static bool noverify_checksums = false;
     113             : 
     114             : /*
     115             :  * The contents of these directories are removed or recreated during server
     116             :  * start so they are not included in backups.  The directories themselves are
     117             :  * kept and included as empty to preserve access permissions.
     118             :  *
     119             :  * Note: this list should be kept in sync with the filter lists in pg_rewind's
     120             :  * filemap.c.
     121             :  */
     122             : static const char *excludeDirContents[] =
     123             : {
     124             :     /*
     125             :      * Skip temporary statistics files. PG_STAT_TMP_DIR must be skipped even
     126             :      * when stats_temp_directory is set because PGSS_TEXT_FILE is always
     127             :      * created there.
     128             :      */
     129             :     PG_STAT_TMP_DIR,
     130             : 
     131             :     /*
     132             :      * It is generally not useful to backup the contents of this directory
     133             :      * even if the intention is to restore to another master. See backup.sgml
     134             :      * for a more detailed description.
     135             :      */
     136             :     "pg_replslot",
     137             : 
     138             :     /* Contents removed on startup, see dsm_cleanup_for_mmap(). */
     139             :     PG_DYNSHMEM_DIR,
     140             : 
     141             :     /* Contents removed on startup, see AsyncShmemInit(). */
     142             :     "pg_notify",
     143             : 
     144             :     /*
     145             :      * Old contents are loaded for possible debugging but are not required for
     146             :      * normal operation, see OldSerXidInit().
     147             :      */
     148             :     "pg_serial",
     149             : 
     150             :     /* Contents removed on startup, see DeleteAllExportedSnapshotFiles(). */
     151             :     "pg_snapshots",
     152             : 
     153             :     /* Contents zeroed on startup, see StartupSUBTRANS(). */
     154             :     "pg_subtrans",
     155             : 
     156             :     /* end of list */
     157             :     NULL
     158             : };
     159             : 
     160             : /*
     161             :  * List of files excluded from backups.
     162             :  */
     163             : static const char *excludeFiles[] =
     164             : {
     165             :     /* Skip auto conf temporary file. */
     166             :     PG_AUTOCONF_FILENAME ".tmp",
     167             : 
     168             :     /* Skip current log file temporary file */
     169             :     LOG_METAINFO_DATAFILE_TMP,
     170             : 
     171             :     /* Skip relation cache because it is rebuilt on startup */
     172             :     RELCACHE_INIT_FILENAME,
     173             : 
     174             :     /*
     175             :      * If there's a backup_label or tablespace_map file, it belongs to a
     176             :      * backup started by the user with pg_start_backup().  It is *not* correct
     177             :      * for this backup.  Our backup_label/tablespace_map is injected into the
     178             :      * tar separately.
     179             :      */
     180             :     BACKUP_LABEL_FILE,
     181             :     TABLESPACE_MAP,
     182             : 
     183             :     "postmaster.pid",
     184             :     "postmaster.opts",
     185             : 
     186             :     /* end of list */
     187             :     NULL
     188             : };
     189             : 
     190             : /*
     191             :  * List of files excluded from checksum validation.
     192             :  *
     193             :  * Note: this list should be kept in sync with what pg_checksums.c
     194             :  * includes.
     195             :  */
     196             : static const char *const noChecksumFiles[] = {
     197             :     "pg_control",
     198             :     "pg_filenode.map",
     199             :     "pg_internal.init",
     200             :     "PG_VERSION",
     201             : #ifdef EXEC_BACKEND
     202             :     "config_exec_params",
     203             :     "config_exec_params.new",
     204             : #endif
     205             :     NULL,
     206             : };
     207             : 
     208             : 
     209             : /*
     210             :  * Called when ERROR or FATAL happens in perform_base_backup() after
     211             :  * we have started the backup - make sure we end it!
     212             :  */
     213             : static void
     214           6 : base_backup_cleanup(int code, Datum arg)
     215             : {
     216           6 :     do_pg_abort_backup();
     217           6 : }
     218             : 
     219             : /*
     220             :  * Actually do a base backup for the specified tablespaces.
     221             :  *
     222             :  * This is split out mainly to avoid complaints about "variable might be
     223             :  * clobbered by longjmp" from stupider versions of gcc.
     224             :  */
     225             : static void
     226          98 : perform_base_backup(basebackup_options *opt)
     227             : {
     228             :     TimeLineID  starttli;
     229             :     XLogRecPtr  endptr;
     230             :     TimeLineID  endtli;
     231             :     StringInfo  labelfile;
     232          98 :     StringInfo  tblspc_map_file = NULL;
     233             :     int         datadirpathlen;
     234          98 :     List       *tablespaces = NIL;
     235             : 
     236          98 :     datadirpathlen = strlen(DataDir);
     237             : 
     238          98 :     backup_started_in_recovery = RecoveryInProgress();
     239             : 
     240          98 :     labelfile = makeStringInfo();
     241          98 :     tblspc_map_file = makeStringInfo();
     242             : 
     243          98 :     total_checksum_failures = 0;
     244             : 
     245         196 :     startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli,
     246             :                                   labelfile, &tablespaces,
     247             :                                   tblspc_map_file,
     248         196 :                                   opt->progress, opt->sendtblspcmapfile);
     249             : 
     250             :     /*
     251             :      * Once do_pg_start_backup has been called, ensure that any failure causes
     252             :      * us to abort the backup so we don't "leak" a backup counter. For this
     253             :      * reason, *all* functionality between do_pg_start_backup() and the end of
     254             :      * do_pg_stop_backup() should be inside the error cleanup block!
     255             :      */
     256             : 
     257          98 :     PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
     258             :     {
     259             :         ListCell   *lc;
     260             :         tablespaceinfo *ti;
     261             : 
     262          98 :         SendXlogRecPtrResult(startptr, starttli);
     263             : 
     264             :         /*
     265             :          * Calculate the relative path of temporary statistics directory in
     266             :          * order to skip the files which are located in that directory later.
     267             :          */
     268          98 :         if (is_absolute_path(pgstat_stat_directory) &&
     269           0 :             strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
     270           0 :             statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
     271          98 :         else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
     272          98 :             statrelpath = psprintf("./%s", pgstat_stat_directory);
     273             :         else
     274           0 :             statrelpath = pgstat_stat_directory;
     275             : 
     276             :         /* Add a node for the base directory at the end */
     277          98 :         ti = palloc0(sizeof(tablespaceinfo));
     278          98 :         ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
     279          98 :         tablespaces = lappend(tablespaces, ti);
     280             : 
     281             :         /* Send tablespace header */
     282          98 :         SendBackupHeader(tablespaces);
     283             : 
     284             :         /* Setup and activate network throttling, if client requested it */
     285          98 :         if (opt->maxrate > 0)
     286             :         {
     287           0 :             throttling_sample =
     288           0 :                 (int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
     289             : 
     290             :             /*
     291             :              * The minimum amount of time for throttling_sample bytes to be
     292             :              * transferred.
     293             :              */
     294           0 :             elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
     295             : 
     296             :             /* Enable throttling. */
     297           0 :             throttling_counter = 0;
     298             : 
     299             :             /* The 'real data' starts now (header was ignored). */
     300           0 :             throttled_last = GetCurrentTimestamp();
     301             :         }
     302             :         else
     303             :         {
     304             :             /* Disable throttling. */
     305          98 :             throttling_counter = -1;
     306             :         }
     307             : 
     308             :         /* Send off our tablespaces one by one */
     309         200 :         foreach(lc, tablespaces)
     310             :         {
     311         108 :             tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
     312             :             StringInfoData buf;
     313             : 
     314             :             /* Send CopyOutResponse message */
     315         108 :             pq_beginmessage(&buf, 'H');
     316         108 :             pq_sendbyte(&buf, 0);   /* overall format */
     317         108 :             pq_sendint16(&buf, 0);  /* natts */
     318         108 :             pq_endmessage(&buf);
     319             : 
     320         108 :             if (ti->path == NULL)
     321             :             {
     322             :                 struct stat statbuf;
     323             : 
     324             :                 /* In the main tar, include the backup_label first... */
     325          98 :                 sendFileWithContent(BACKUP_LABEL_FILE, labelfile->data);
     326             : 
     327             :                 /*
     328             :                  * Send tablespace_map file if required and then the bulk of
     329             :                  * the files.
     330             :                  */
     331          98 :                 if (tblspc_map_file && opt->sendtblspcmapfile)
     332             :                 {
     333          10 :                     sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data);
     334          10 :                     sendDir(".", 1, false, tablespaces, false);
     335             :                 }
     336             :                 else
     337          88 :                     sendDir(".", 1, false, tablespaces, true);
     338             : 
     339             :                 /* ... and pg_control after everything else. */
     340          92 :                 if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
     341           0 :                     ereport(ERROR,
     342             :                             (errcode_for_file_access(),
     343             :                              errmsg("could not stat file \"%s\": %m",
     344             :                                     XLOG_CONTROL_FILE)));
     345          92 :                 sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
     346             :             }
     347             :             else
     348          10 :                 sendTablespace(ti->path, false);
     349             : 
     350             :             /*
     351             :              * If we're including WAL, and this is the main data directory we
     352             :              * don't terminate the tar stream here. Instead, we will append
     353             :              * the xlog files below and terminate it then. This is safe since
     354             :              * the main data directory is always sent *last*.
     355             :              */
     356         102 :             if (opt->includewal && ti->path == NULL)
     357             :             {
     358             :                 Assert(lnext(lc) == NULL);
     359             :             }
     360             :             else
     361         100 :                 pq_putemptymessage('c');    /* CopyDone */
     362             :         }
     363             : 
     364          92 :         endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
     365             :     }
     366          92 :     PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
     367             : 
     368             : 
     369          92 :     if (opt->includewal)
     370             :     {
     371             :         /*
     372             :          * We've left the last tar file "open", so we can now append the
     373             :          * required WAL files to it.
     374             :          */
     375             :         char        pathbuf[MAXPGPATH];
     376             :         XLogSegNo   segno;
     377             :         XLogSegNo   startsegno;
     378             :         XLogSegNo   endsegno;
     379             :         struct stat statbuf;
     380           2 :         List       *historyFileList = NIL;
     381           2 :         List       *walFileList = NIL;
     382             :         char      **walFiles;
     383             :         int         nWalFiles;
     384             :         char        firstoff[MAXFNAMELEN];
     385             :         char        lastoff[MAXFNAMELEN];
     386             :         DIR        *dir;
     387             :         struct dirent *de;
     388             :         int         i;
     389             :         ListCell   *lc;
     390             :         TimeLineID  tli;
     391             : 
     392             :         /*
     393             :          * I'd rather not worry about timelines here, so scan pg_wal and
     394             :          * include all WAL files in the range between 'startptr' and 'endptr',
     395             :          * regardless of the timeline the file is stamped with. If there are
     396             :          * some spurious WAL files belonging to timelines that don't belong in
     397             :          * this server's history, they will be included too. Normally there
     398             :          * shouldn't be such files, but if there are, there's little harm in
     399             :          * including them.
     400             :          */
     401           2 :         XLByteToSeg(startptr, startsegno, wal_segment_size);
     402           2 :         XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
     403           2 :         XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
     404           2 :         XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
     405             : 
     406           2 :         dir = AllocateDir("pg_wal");
     407          16 :         while ((de = ReadDir(dir, "pg_wal")) != NULL)
     408             :         {
     409             :             /* Does it look like a WAL segment, and is it in the range? */
     410          18 :             if (IsXLogFileName(de->d_name) &&
     411          12 :                 strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
     412           6 :                 strcmp(de->d_name + 8, lastoff + 8) <= 0)
     413             :             {
     414           2 :                 walFileList = lappend(walFileList, pstrdup(de->d_name));
     415             :             }
     416             :             /* Does it look like a timeline history file? */
     417          10 :             else if (IsTLHistoryFileName(de->d_name))
     418             :             {
     419           0 :                 historyFileList = lappend(historyFileList, pstrdup(de->d_name));
     420             :             }
     421             :         }
     422           2 :         FreeDir(dir);
     423             : 
     424             :         /*
     425             :          * Before we go any further, check that none of the WAL segments we
     426             :          * need were removed.
     427             :          */
     428           2 :         CheckXLogRemoved(startsegno, ThisTimeLineID);
     429             : 
     430             :         /*
     431             :          * Put the WAL filenames into an array, and sort. We send the files in
     432             :          * order from oldest to newest, to reduce the chance that a file is
     433             :          * recycled before we get a chance to send it over.
     434             :          */
     435           2 :         nWalFiles = list_length(walFileList);
     436           2 :         walFiles = palloc(nWalFiles * sizeof(char *));
     437           2 :         i = 0;
     438           4 :         foreach(lc, walFileList)
     439             :         {
     440           2 :             walFiles[i++] = lfirst(lc);
     441             :         }
     442           2 :         qsort(walFiles, nWalFiles, sizeof(char *), compareWalFileNames);
     443             : 
     444             :         /*
     445             :          * There must be at least one xlog file in the pg_wal directory, since
     446             :          * we are doing backup-including-xlog.
     447             :          */
     448           2 :         if (nWalFiles < 1)
     449           0 :             ereport(ERROR,
     450             :                     (errmsg("could not find any WAL files")));
     451             : 
     452             :         /*
     453             :          * Sanity check: the first and last segment should cover startptr and
     454             :          * endptr, with no gaps in between.
     455             :          */
     456           2 :         XLogFromFileName(walFiles[0], &tli, &segno, wal_segment_size);
     457           2 :         if (segno != startsegno)
     458             :         {
     459             :             char        startfname[MAXFNAMELEN];
     460             : 
     461           0 :             XLogFileName(startfname, ThisTimeLineID, startsegno,
     462             :                          wal_segment_size);
     463           0 :             ereport(ERROR,
     464             :                     (errmsg("could not find WAL file \"%s\"", startfname)));
     465             :         }
     466           4 :         for (i = 0; i < nWalFiles; i++)
     467             :         {
     468           2 :             XLogSegNo   currsegno = segno;
     469           2 :             XLogSegNo   nextsegno = segno + 1;
     470             : 
     471           2 :             XLogFromFileName(walFiles[i], &tli, &segno, wal_segment_size);
     472           2 :             if (!(nextsegno == segno || currsegno == segno))
     473             :             {
     474             :                 char        nextfname[MAXFNAMELEN];
     475             : 
     476           0 :                 XLogFileName(nextfname, ThisTimeLineID, nextsegno,
     477             :                              wal_segment_size);
     478           0 :                 ereport(ERROR,
     479             :                         (errmsg("could not find WAL file \"%s\"", nextfname)));
     480             :             }
     481             :         }
     482           2 :         if (segno != endsegno)
     483             :         {
     484             :             char        endfname[MAXFNAMELEN];
     485             : 
     486           0 :             XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
     487           0 :             ereport(ERROR,
     488             :                     (errmsg("could not find WAL file \"%s\"", endfname)));
     489             :         }
     490             : 
     491             :         /* Ok, we have everything we need. Send the WAL files. */
     492           4 :         for (i = 0; i < nWalFiles; i++)
     493             :         {
     494             :             FILE       *fp;
     495             :             char        buf[TAR_SEND_SIZE];
     496             :             size_t      cnt;
     497           2 :             pgoff_t     len = 0;
     498             : 
     499           2 :             snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFiles[i]);
     500           2 :             XLogFromFileName(walFiles[i], &tli, &segno, wal_segment_size);
     501             : 
     502           2 :             fp = AllocateFile(pathbuf, "rb");
     503           2 :             if (fp == NULL)
     504             :             {
     505           0 :                 int         save_errno = errno;
     506             : 
     507             :                 /*
     508             :                  * Most likely reason for this is that the file was already
     509             :                  * removed by a checkpoint, so check for that to get a better
     510             :                  * error message.
     511             :                  */
     512           0 :                 CheckXLogRemoved(segno, tli);
     513             : 
     514           0 :                 errno = save_errno;
     515           0 :                 ereport(ERROR,
     516             :                         (errcode_for_file_access(),
     517             :                          errmsg("could not open file \"%s\": %m", pathbuf)));
     518             :             }
     519             : 
     520           2 :             if (fstat(fileno(fp), &statbuf) != 0)
     521           0 :                 ereport(ERROR,
     522             :                         (errcode_for_file_access(),
     523             :                          errmsg("could not stat file \"%s\": %m",
     524             :                                 pathbuf)));
     525           2 :             if (statbuf.st_size != wal_segment_size)
     526             :             {
     527           0 :                 CheckXLogRemoved(segno, tli);
     528           0 :                 ereport(ERROR,
     529             :                         (errcode_for_file_access(),
     530             :                          errmsg("unexpected WAL file size \"%s\"", walFiles[i])));
     531             :             }
     532             : 
     533             :             /* send the WAL file itself */
     534           2 :             _tarWriteHeader(pathbuf, NULL, &statbuf, false);
     535             : 
     536        1026 :             while ((cnt = fread(buf, 1,
     537        1024 :                                 Min(sizeof(buf), wal_segment_size - len),
     538             :                                 fp)) > 0)
     539             :             {
     540        1024 :                 CheckXLogRemoved(segno, tli);
     541             :                 /* Send the chunk as a CopyData message */
     542        1024 :                 if (pq_putmessage('d', buf, cnt))
     543           0 :                     ereport(ERROR,
     544             :                             (errmsg("base backup could not send data, aborting backup")));
     545             : 
     546        1024 :                 len += cnt;
     547        1024 :                 throttle(cnt);
     548             : 
     549        1024 :                 if (len == wal_segment_size)
     550           2 :                     break;
     551             :             }
     552             : 
     553           2 :             if (len != wal_segment_size)
     554             :             {
     555           0 :                 CheckXLogRemoved(segno, tli);
     556           0 :                 ereport(ERROR,
     557             :                         (errcode_for_file_access(),
     558             :                          errmsg("unexpected WAL file size \"%s\"", walFiles[i])));
     559             :             }
     560             : 
     561             :             /* wal_segment_size is a multiple of 512, so no need for padding */
     562             : 
     563           2 :             FreeFile(fp);
     564             : 
     565             :             /*
     566             :              * Mark file as archived, otherwise files can get archived again
     567             :              * after promotion of a new node. This is in line with
     568             :              * walreceiver.c always doing an XLogArchiveForceDone() after a
     569             :              * complete segment.
     570             :              */
     571           2 :             StatusFilePath(pathbuf, walFiles[i], ".done");
     572           2 :             sendFileWithContent(pathbuf, "");
     573             :         }
     574             : 
     575             :         /*
     576             :          * Send timeline history files too. Only the latest timeline history
     577             :          * file is required for recovery, and even that only if there happens
     578             :          * to be a timeline switch in the first WAL segment that contains the
     579             :          * checkpoint record, or if we're taking a base backup from a standby
     580             :          * server and the target timeline changes while the backup is taken.
     581             :          * But they are small and highly useful for debugging purposes, so
     582             :          * better include them all, always.
     583             :          */
     584           2 :         foreach(lc, historyFileList)
     585             :         {
     586           0 :             char       *fname = lfirst(lc);
     587             : 
     588           0 :             snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
     589             : 
     590           0 :             if (lstat(pathbuf, &statbuf) != 0)
     591           0 :                 ereport(ERROR,
     592             :                         (errcode_for_file_access(),
     593             :                          errmsg("could not stat file \"%s\": %m", pathbuf)));
     594             : 
     595           0 :             sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
     596             : 
     597             :             /* unconditionally mark file as archived */
     598           0 :             StatusFilePath(pathbuf, fname, ".done");
     599           0 :             sendFileWithContent(pathbuf, "");
     600             :         }
     601             : 
     602             :         /* Send CopyDone message for the last tar file */
     603           2 :         pq_putemptymessage('c');
     604             :     }
     605          92 :     SendXlogRecPtrResult(endptr, endtli);
     606             : 
     607          92 :     if (total_checksum_failures)
     608             :     {
     609           6 :         if (total_checksum_failures > 1)
     610             :         {
     611             :             char        buf[64];
     612             : 
     613           4 :             snprintf(buf, sizeof(buf), INT64_FORMAT, total_checksum_failures);
     614             : 
     615           4 :             ereport(WARNING,
     616             :                     (errmsg("%s total checksum verification failures", buf)));
     617             :         }
     618           6 :         ereport(ERROR,
     619             :                 (errcode(ERRCODE_DATA_CORRUPTED),
     620             :                  errmsg("checksum verification failure during base backup")));
     621             :     }
     622             : 
     623          86 : }
     624             : 
     625             : /*
     626             :  * qsort comparison function, to compare log/seg portion of WAL segment
     627             :  * filenames, ignoring the timeline portion.
     628             :  */
     629             : static int
     630           0 : compareWalFileNames(const void *a, const void *b)
     631             : {
     632           0 :     char       *fna = *((char **) a);
     633           0 :     char       *fnb = *((char **) b);
     634             : 
     635           0 :     return strcmp(fna + 8, fnb + 8);
     636             : }
     637             : 
     638             : /*
     639             :  * Parse the base backup options passed down by the parser
     640             :  */
     641             : static void
     642          98 : parse_basebackup_options(List *options, basebackup_options *opt)
     643             : {
     644             :     ListCell   *lopt;
     645          98 :     bool        o_label = false;
     646          98 :     bool        o_progress = false;
     647          98 :     bool        o_fast = false;
     648          98 :     bool        o_nowait = false;
     649          98 :     bool        o_wal = false;
     650          98 :     bool        o_maxrate = false;
     651          98 :     bool        o_tablespace_map = false;
     652          98 :     bool        o_noverify_checksums = false;
     653             : 
     654          98 :     MemSet(opt, 0, sizeof(*opt));
     655         306 :     foreach(lopt, options)
     656             :     {
     657         208 :         DefElem    *defel = (DefElem *) lfirst(lopt);
     658             : 
     659         208 :         if (strcmp(defel->defname, "label") == 0)
     660             :         {
     661          98 :             if (o_label)
     662           0 :                 ereport(ERROR,
     663             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     664             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     665          98 :             opt->label = strVal(defel->arg);
     666          98 :             o_label = true;
     667             :         }
     668         110 :         else if (strcmp(defel->defname, "progress") == 0)
     669             :         {
     670           0 :             if (o_progress)
     671           0 :                 ereport(ERROR,
     672             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     673             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     674           0 :             opt->progress = true;
     675           0 :             o_progress = true;
     676             :         }
     677         110 :         else if (strcmp(defel->defname, "fast") == 0)
     678             :         {
     679           0 :             if (o_fast)
     680           0 :                 ereport(ERROR,
     681             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     682             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     683           0 :             opt->fastcheckpoint = true;
     684           0 :             o_fast = true;
     685             :         }
     686         110 :         else if (strcmp(defel->defname, "nowait") == 0)
     687             :         {
     688          96 :             if (o_nowait)
     689           0 :                 ereport(ERROR,
     690             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     691             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     692          96 :             opt->nowait = true;
     693          96 :             o_nowait = true;
     694             :         }
     695          14 :         else if (strcmp(defel->defname, "wal") == 0)
     696             :         {
     697           2 :             if (o_wal)
     698           0 :                 ereport(ERROR,
     699             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     700             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     701           2 :             opt->includewal = true;
     702           2 :             o_wal = true;
     703             :         }
     704          12 :         else if (strcmp(defel->defname, "max_rate") == 0)
     705             :         {
     706             :             long        maxrate;
     707             : 
     708           0 :             if (o_maxrate)
     709           0 :                 ereport(ERROR,
     710             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     711             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     712             : 
     713           0 :             maxrate = intVal(defel->arg);
     714           0 :             if (maxrate < MAX_RATE_LOWER || maxrate > MAX_RATE_UPPER)
     715           0 :                 ereport(ERROR,
     716             :                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     717             :                          errmsg("%d is outside the valid range for parameter \"%s\" (%d .. %d)",
     718             :                                 (int) maxrate, "MAX_RATE", MAX_RATE_LOWER, MAX_RATE_UPPER)));
     719             : 
     720           0 :             opt->maxrate = (uint32) maxrate;
     721           0 :             o_maxrate = true;
     722             :         }
     723          12 :         else if (strcmp(defel->defname, "tablespace_map") == 0)
     724             :         {
     725          10 :             if (o_tablespace_map)
     726           0 :                 ereport(ERROR,
     727             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     728             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     729          10 :             opt->sendtblspcmapfile = true;
     730          10 :             o_tablespace_map = true;
     731             :         }
     732           2 :         else if (strcmp(defel->defname, "noverify_checksums") == 0)
     733             :         {
     734           2 :             if (o_noverify_checksums)
     735           0 :                 ereport(ERROR,
     736             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     737             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     738           2 :             noverify_checksums = true;
     739           2 :             o_noverify_checksums = true;
     740             :         }
     741             :         else
     742           0 :             elog(ERROR, "option \"%s\" not recognized",
     743             :                  defel->defname);
     744             :     }
     745          98 :     if (opt->label == NULL)
     746           0 :         opt->label = "base backup";
     747          98 : }
     748             : 
     749             : 
     750             : /*
     751             :  * SendBaseBackup() - send a complete base backup.
     752             :  *
     753             :  * The function will put the system into backup mode like pg_start_backup()
     754             :  * does, so that the backup is consistent even though we read directly from
     755             :  * the filesystem, bypassing the buffer cache.
     756             :  */
     757             : void
     758          98 : SendBaseBackup(BaseBackupCmd *cmd)
     759             : {
     760             :     basebackup_options opt;
     761             : 
     762          98 :     parse_basebackup_options(cmd->options, &opt);
     763             : 
     764          98 :     WalSndSetState(WALSNDSTATE_BACKUP);
     765             : 
     766          98 :     if (update_process_title)
     767             :     {
     768             :         char        activitymsg[50];
     769             : 
     770          98 :         snprintf(activitymsg, sizeof(activitymsg), "sending backup \"%s\"",
     771             :                  opt.label);
     772          98 :         set_ps_display(activitymsg, false);
     773             :     }
     774             : 
     775          98 :     perform_base_backup(&opt);
     776          86 : }
     777             : 
     778             : static void
     779           0 : send_int8_string(StringInfoData *buf, int64 intval)
     780             : {
     781             :     char        is[32];
     782             : 
     783           0 :     sprintf(is, INT64_FORMAT, intval);
     784           0 :     pq_sendint32(buf, strlen(is));
     785           0 :     pq_sendbytes(buf, is, strlen(is));
     786           0 : }
     787             : 
     788             : static void
     789          98 : SendBackupHeader(List *tablespaces)
     790             : {
     791             :     StringInfoData buf;
     792             :     ListCell   *lc;
     793             : 
     794             :     /* Construct and send the directory information */
     795          98 :     pq_beginmessage(&buf, 'T'); /* RowDescription */
     796          98 :     pq_sendint16(&buf, 3);      /* 3 fields */
     797             : 
     798             :     /* First field - spcoid */
     799          98 :     pq_sendstring(&buf, "spcoid");
     800          98 :     pq_sendint32(&buf, 0);      /* table oid */
     801          98 :     pq_sendint16(&buf, 0);      /* attnum */
     802          98 :     pq_sendint32(&buf, OIDOID); /* type oid */
     803          98 :     pq_sendint16(&buf, 4);      /* typlen */
     804          98 :     pq_sendint32(&buf, 0);      /* typmod */
     805          98 :     pq_sendint16(&buf, 0);      /* format code */
     806             : 
     807             :     /* Second field - spcpath */
     808          98 :     pq_sendstring(&buf, "spclocation");
     809          98 :     pq_sendint32(&buf, 0);
     810          98 :     pq_sendint16(&buf, 0);
     811          98 :     pq_sendint32(&buf, TEXTOID);
     812          98 :     pq_sendint16(&buf, -1);
     813          98 :     pq_sendint32(&buf, 0);
     814          98 :     pq_sendint16(&buf, 0);
     815             : 
     816             :     /* Third field - size */
     817          98 :     pq_sendstring(&buf, "size");
     818          98 :     pq_sendint32(&buf, 0);
     819          98 :     pq_sendint16(&buf, 0);
     820          98 :     pq_sendint32(&buf, INT8OID);
     821          98 :     pq_sendint16(&buf, 8);
     822          98 :     pq_sendint32(&buf, 0);
     823          98 :     pq_sendint16(&buf, 0);
     824          98 :     pq_endmessage(&buf);
     825             : 
     826         206 :     foreach(lc, tablespaces)
     827             :     {
     828         108 :         tablespaceinfo *ti = lfirst(lc);
     829             : 
     830             :         /* Send one datarow message */
     831         108 :         pq_beginmessage(&buf, 'D');
     832         108 :         pq_sendint16(&buf, 3);  /* number of columns */
     833         108 :         if (ti->path == NULL)
     834             :         {
     835          98 :             pq_sendint32(&buf, -1); /* Length = -1 ==> NULL */
     836          98 :             pq_sendint32(&buf, -1);
     837             :         }
     838             :         else
     839             :         {
     840             :             Size        len;
     841             : 
     842          10 :             len = strlen(ti->oid);
     843          10 :             pq_sendint32(&buf, len);
     844          10 :             pq_sendbytes(&buf, ti->oid, len);
     845             : 
     846          10 :             len = strlen(ti->path);
     847          10 :             pq_sendint32(&buf, len);
     848          10 :             pq_sendbytes(&buf, ti->path, len);
     849             :         }
     850         108 :         if (ti->size >= 0)
     851           0 :             send_int8_string(&buf, ti->size / 1024);
     852             :         else
     853         108 :             pq_sendint32(&buf, -1); /* NULL */
     854             : 
     855         108 :         pq_endmessage(&buf);
     856             :     }
     857             : 
     858             :     /* Send a CommandComplete message */
     859          98 :     pq_puttextmessage('C', "SELECT");
     860          98 : }
     861             : 
     862             : /*
     863             :  * Send a single resultset containing just a single
     864             :  * XLogRecPtr record (in text format)
     865             :  */
     866             : static void
     867         190 : SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
     868             : {
     869             :     StringInfoData buf;
     870             :     char        str[MAXFNAMELEN];
     871             :     Size        len;
     872             : 
     873         190 :     pq_beginmessage(&buf, 'T'); /* RowDescription */
     874         190 :     pq_sendint16(&buf, 2);      /* 2 fields */
     875             : 
     876             :     /* Field headers */
     877         190 :     pq_sendstring(&buf, "recptr");
     878         190 :     pq_sendint32(&buf, 0);      /* table oid */
     879         190 :     pq_sendint16(&buf, 0);      /* attnum */
     880         190 :     pq_sendint32(&buf, TEXTOID);    /* type oid */
     881         190 :     pq_sendint16(&buf, -1);
     882         190 :     pq_sendint32(&buf, 0);
     883         190 :     pq_sendint16(&buf, 0);
     884             : 
     885         190 :     pq_sendstring(&buf, "tli");
     886         190 :     pq_sendint32(&buf, 0);      /* table oid */
     887         190 :     pq_sendint16(&buf, 0);      /* attnum */
     888             : 
     889             :     /*
     890             :      * int8 may seem like a surprising data type for this, but in theory int4
     891             :      * would not be wide enough for this, as TimeLineID is unsigned.
     892             :      */
     893         190 :     pq_sendint32(&buf, INT8OID);    /* type oid */
     894         190 :     pq_sendint16(&buf, -1);
     895         190 :     pq_sendint32(&buf, 0);
     896         190 :     pq_sendint16(&buf, 0);
     897         190 :     pq_endmessage(&buf);
     898             : 
     899             :     /* Data row */
     900         190 :     pq_beginmessage(&buf, 'D');
     901         190 :     pq_sendint16(&buf, 2);      /* number of columns */
     902             : 
     903         380 :     len = snprintf(str, sizeof(str),
     904         190 :                    "%X/%X", (uint32) (ptr >> 32), (uint32) ptr);
     905         190 :     pq_sendint32(&buf, len);
     906         190 :     pq_sendbytes(&buf, str, len);
     907             : 
     908         190 :     len = snprintf(str, sizeof(str), "%u", tli);
     909         190 :     pq_sendint32(&buf, len);
     910         190 :     pq_sendbytes(&buf, str, len);
     911             : 
     912         190 :     pq_endmessage(&buf);
     913             : 
     914             :     /* Send a CommandComplete message */
     915         190 :     pq_puttextmessage('C', "SELECT");
     916         190 : }
     917             : 
     918             : /*
     919             :  * Inject a file with given name and content in the output tar stream.
     920             :  */
     921             : static void
     922         110 : sendFileWithContent(const char *filename, const char *content)
     923             : {
     924             :     struct stat statbuf;
     925             :     int         pad,
     926             :                 len;
     927             : 
     928         110 :     len = strlen(content);
     929             : 
     930             :     /*
     931             :      * Construct a stat struct for the backup_label file we're injecting in
     932             :      * the tar.
     933             :      */
     934             :     /* Windows doesn't have the concept of uid and gid */
     935             : #ifdef WIN32
     936             :     statbuf.st_uid = 0;
     937             :     statbuf.st_gid = 0;
     938             : #else
     939         110 :     statbuf.st_uid = geteuid();
     940         110 :     statbuf.st_gid = getegid();
     941             : #endif
     942         110 :     statbuf.st_mtime = time(NULL);
     943         110 :     statbuf.st_mode = pg_file_create_mode;
     944         110 :     statbuf.st_size = len;
     945             : 
     946         110 :     _tarWriteHeader(filename, NULL, &statbuf, false);
     947             :     /* Send the contents as a CopyData message */
     948         110 :     pq_putmessage('d', content, len);
     949             : 
     950             :     /* Pad to 512 byte boundary, per tar format requirements */
     951         110 :     pad = ((len + 511) & ~511) - len;
     952         110 :     if (pad > 0)
     953             :     {
     954             :         char        buf[512];
     955             : 
     956         102 :         MemSet(buf, 0, pad);
     957         102 :         pq_putmessage('d', buf, pad);
     958             :     }
     959         110 : }
     960             : 
     961             : /*
     962             :  * Include the tablespace directory pointed to by 'path' in the output tar
     963             :  * stream.  If 'sizeonly' is true, we just calculate a total length and return
     964             :  * it, without actually sending anything.
     965             :  *
     966             :  * Only used to send auxiliary tablespaces, not PGDATA.
     967             :  */
     968             : int64
     969          10 : sendTablespace(char *path, bool sizeonly)
     970             : {
     971             :     int64       size;
     972             :     char        pathbuf[MAXPGPATH];
     973             :     struct stat statbuf;
     974             : 
     975             :     /*
     976             :      * 'path' points to the tablespace location, but we only want to include
     977             :      * the version directory in it that belongs to us.
     978             :      */
     979          10 :     snprintf(pathbuf, sizeof(pathbuf), "%s/%s", path,
     980             :              TABLESPACE_VERSION_DIRECTORY);
     981             : 
     982             :     /*
     983             :      * Store a directory entry in the tar file so we get the permissions
     984             :      * right.
     985             :      */
     986          10 :     if (lstat(pathbuf, &statbuf) != 0)
     987             :     {
     988           0 :         if (errno != ENOENT)
     989           0 :             ereport(ERROR,
     990             :                     (errcode_for_file_access(),
     991             :                      errmsg("could not stat file or directory \"%s\": %m",
     992             :                             pathbuf)));
     993             : 
     994             :         /* If the tablespace went away while scanning, it's no error. */
     995           0 :         return 0;
     996             :     }
     997             : 
     998          10 :     size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
     999             :                            sizeonly);
    1000             : 
    1001             :     /* Send all the files in the tablespace version directory */
    1002          10 :     size += sendDir(pathbuf, strlen(path), sizeonly, NIL, true);
    1003             : 
    1004          10 :     return size;
    1005             : }
    1006             : 
    1007             : /*
    1008             :  * Include all files from the given directory in the output tar stream. If
    1009             :  * 'sizeonly' is true, we just calculate a total length and return it, without
    1010             :  * actually sending anything.
    1011             :  *
    1012             :  * Omit any directory in the tablespaces list, to avoid backing up
    1013             :  * tablespaces twice when they were created inside PGDATA.
    1014             :  *
    1015             :  * If sendtblspclinks is true, we need to include symlink
    1016             :  * information in the tar file. If not, we can skip that
    1017             :  * as it will be sent separately in the tablespace_map file.
    1018             :  */
    1019             : static int64
    1020        1648 : sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
    1021             :         bool sendtblspclinks)
    1022             : {
    1023             :     DIR        *dir;
    1024             :     struct dirent *de;
    1025             :     char        pathbuf[MAXPGPATH * 2];
    1026             :     struct stat statbuf;
    1027        1648 :     int64       size = 0;
    1028             :     const char *lastDir;        /* Split last dir from parent path. */
    1029        1648 :     bool        isDbDir = false;    /* Does this directory contain relations? */
    1030             : 
    1031             :     /*
    1032             :      * Determine if the current path is a database directory that can contain
    1033             :      * relations.
    1034             :      *
    1035             :      * Start by finding the location of the delimiter between the parent path
    1036             :      * and the current path.
    1037             :      */
    1038        1648 :     lastDir = last_dir_separator(path);
    1039             : 
    1040             :     /* Does this path look like a database path (i.e. all digits)? */
    1041        3198 :     if (lastDir != NULL &&
    1042        1550 :         strspn(lastDir + 1, "0123456789") == strlen(lastDir + 1))
    1043             :     {
    1044             :         /* Part of path that contains the parent directory. */
    1045         286 :         int         parentPathLen = lastDir - path;
    1046             : 
    1047             :         /*
    1048             :          * Mark path as a database directory if the parent path is either
    1049             :          * $PGDATA/base or a tablespace version path.
    1050             :          */
    1051         292 :         if (strncmp(path, "./base", parentPathLen) == 0 ||
    1052          12 :             (parentPathLen >= (sizeof(TABLESPACE_VERSION_DIRECTORY) - 1) &&
    1053           6 :              strncmp(lastDir - (sizeof(TABLESPACE_VERSION_DIRECTORY) - 1),
    1054             :                      TABLESPACE_VERSION_DIRECTORY,
    1055             :                      sizeof(TABLESPACE_VERSION_DIRECTORY) - 1) == 0))
    1056         286 :             isDbDir = true;
    1057             :     }
    1058             : 
    1059        1648 :     dir = AllocateDir(path);
    1060      100842 :     while ((de = ReadDir(dir, path)) != NULL)
    1061             :     {
    1062             :         int         excludeIdx;
    1063             :         bool        excludeFound;
    1064             :         ForkNumber  relForkNum; /* Type of fork if file is a relation */
    1065             :         int         relOidChars;    /* Chars in filename that are the rel oid */
    1066             : 
    1067             :         /* Skip special stuff */
    1068       97556 :         if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
    1069        7868 :             continue;
    1070             : 
    1071             :         /* Skip temporary files */
    1072       94280 :         if (strncmp(de->d_name,
    1073             :                     PG_TEMP_FILE_PREFIX,
    1074             :                     strlen(PG_TEMP_FILE_PREFIX)) == 0)
    1075           0 :             continue;
    1076             : 
    1077             :         /*
    1078             :          * Check if the postmaster has signaled us to exit, and abort with an
    1079             :          * error in that case. The error handler further up will call
    1080             :          * do_pg_abort_backup() for us. Also check that if the backup was
    1081             :          * started while still in recovery, the server wasn't promoted.
    1082             :          * dp_pg_stop_backup() will check that too, but it's better to stop
    1083             :          * the backup early than continue to the end and fail there.
    1084             :          */
    1085       94280 :         CHECK_FOR_INTERRUPTS();
    1086       94280 :         if (RecoveryInProgress() != backup_started_in_recovery)
    1087           0 :             ereport(ERROR,
    1088             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    1089             :                      errmsg("the standby was promoted during online backup"),
    1090             :                      errhint("This means that the backup being taken is corrupt "
    1091             :                              "and should not be used. "
    1092             :                              "Try taking another online backup.")));
    1093             : 
    1094             :         /* Scan for files that should be excluded */
    1095       94280 :         excludeFound = false;
    1096      752788 :         for (excludeIdx = 0; excludeFiles[excludeIdx] != NULL; excludeIdx++)
    1097             :         {
    1098      658906 :             if (strcmp(de->d_name, excludeFiles[excludeIdx]) == 0)
    1099             :             {
    1100         398 :                 elog(DEBUG1, "file \"%s\" excluded from backup", de->d_name);
    1101         398 :                 excludeFound = true;
    1102         398 :                 break;
    1103             :             }
    1104             :         }
    1105             : 
    1106       94280 :         if (excludeFound)
    1107         398 :             continue;
    1108             : 
    1109             :         /* Exclude all forks for unlogged tables except the init fork */
    1110      178644 :         if (isDbDir &&
    1111       84762 :             parse_filename_for_nontemp_relation(de->d_name, &relOidChars,
    1112             :                                                 &relForkNum))
    1113             :         {
    1114             :             /* Never exclude init forks */
    1115       84170 :             if (relForkNum != INIT_FORKNUM)
    1116             :             {
    1117             :                 char        initForkFile[MAXPGPATH];
    1118             :                 char        relOid[OIDCHARS + 1];
    1119             : 
    1120             :                 /*
    1121             :                  * If any other type of fork, check if there is an init fork
    1122             :                  * with the same OID. If so, the file can be excluded.
    1123             :                  */
    1124       84124 :                 memcpy(relOid, de->d_name, relOidChars);
    1125       84124 :                 relOid[relOidChars] = '\0';
    1126       84124 :                 snprintf(initForkFile, sizeof(initForkFile), "%s/%s_init",
    1127             :                          path, relOid);
    1128             : 
    1129       84124 :                 if (lstat(initForkFile, &statbuf) == 0)
    1130             :                 {
    1131          46 :                     elog(DEBUG2,
    1132             :                          "unlogged relation file \"%s\" excluded from backup",
    1133             :                          de->d_name);
    1134             : 
    1135          46 :                     continue;
    1136             :                 }
    1137             :             }
    1138             :         }
    1139             : 
    1140             :         /* Exclude temporary relations */
    1141       93836 :         if (isDbDir && looks_like_temp_rel_name(de->d_name))
    1142             :         {
    1143          32 :             elog(DEBUG2,
    1144             :                  "temporary relation file \"%s\" excluded from backup",
    1145             :                  de->d_name);
    1146             : 
    1147          32 :             continue;
    1148             :         }
    1149             : 
    1150       93804 :         snprintf(pathbuf, sizeof(pathbuf), "%s/%s", path, de->d_name);
    1151             : 
    1152             :         /* Skip pg_control here to back up it last */
    1153       93804 :         if (strcmp(pathbuf, "./global/pg_control") == 0)
    1154          92 :             continue;
    1155             : 
    1156       93712 :         if (lstat(pathbuf, &statbuf) != 0)
    1157             :         {
    1158           0 :             if (errno != ENOENT)
    1159           0 :                 ereport(ERROR,
    1160             :                         (errcode_for_file_access(),
    1161             :                          errmsg("could not stat file or directory \"%s\": %m",
    1162             :                                 pathbuf)));
    1163             : 
    1164             :             /* If the file went away while scanning, it's not an error. */
    1165           0 :             continue;
    1166             :         }
    1167             : 
    1168             :         /* Scan for directories whose contents should be excluded */
    1169       93712 :         excludeFound = false;
    1170      747054 :         for (excludeIdx = 0; excludeDirContents[excludeIdx] != NULL; excludeIdx++)
    1171             :         {
    1172      653998 :             if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
    1173             :             {
    1174         656 :                 elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
    1175         656 :                 size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
    1176         656 :                 excludeFound = true;
    1177         656 :                 break;
    1178             :             }
    1179             :         }
    1180             : 
    1181       93712 :         if (excludeFound)
    1182         656 :             continue;
    1183             : 
    1184             :         /*
    1185             :          * Exclude contents of directory specified by statrelpath if not set
    1186             :          * to the default (pg_stat_tmp) which is caught in the loop above.
    1187             :          */
    1188       93056 :         if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
    1189             :         {
    1190           0 :             elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
    1191           0 :             size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
    1192           0 :             continue;
    1193             :         }
    1194             : 
    1195             :         /*
    1196             :          * We can skip pg_wal, the WAL segments need to be fetched from the
    1197             :          * WAL archive anyway. But include it as an empty directory anyway, so
    1198             :          * we get permissions right.
    1199             :          */
    1200       93056 :         if (strcmp(pathbuf, "./pg_wal") == 0)
    1201             :         {
    1202             :             /* If pg_wal is a symlink, write it as a directory anyway */
    1203          92 :             size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
    1204             : 
    1205             :             /*
    1206             :              * Also send archive_status directory (by hackishly reusing
    1207             :              * statbuf from above ...).
    1208             :              */
    1209          92 :             size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
    1210             :                                     sizeonly);
    1211             : 
    1212          92 :             continue;           /* don't recurse into pg_wal */
    1213             :         }
    1214             : 
    1215             :         /* Allow symbolic links in pg_tblspc only */
    1216       92968 :         if (strcmp(path, "./pg_tblspc") == 0 &&
    1217             : #ifndef WIN32
    1218           4 :             S_ISLNK(statbuf.st_mode)
    1219             : #else
    1220             :             pgwin32_is_junction(pathbuf)
    1221             : #endif
    1222             :             )
    1223           4 :         {
    1224             : #if defined(HAVE_READLINK) || defined(WIN32)
    1225             :             char        linkpath[MAXPGPATH];
    1226             :             int         rllen;
    1227             : 
    1228           4 :             rllen = readlink(pathbuf, linkpath, sizeof(linkpath));
    1229           4 :             if (rllen < 0)
    1230           0 :                 ereport(ERROR,
    1231             :                         (errcode_for_file_access(),
    1232             :                          errmsg("could not read symbolic link \"%s\": %m",
    1233             :                                 pathbuf)));
    1234           4 :             if (rllen >= sizeof(linkpath))
    1235           0 :                 ereport(ERROR,
    1236             :                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1237             :                          errmsg("symbolic link \"%s\" target is too long",
    1238             :                                 pathbuf)));
    1239           4 :             linkpath[rllen] = '\0';
    1240             : 
    1241           4 :             size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
    1242             :                                     &statbuf, sizeonly);
    1243             : #else
    1244             : 
    1245             :             /*
    1246             :              * If the platform does not have symbolic links, it should not be
    1247             :              * possible to have tablespaces - clearly somebody else created
    1248             :              * them. Warn about it and ignore.
    1249             :              */
    1250             :             ereport(WARNING,
    1251             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1252             :                      errmsg("tablespaces are not supported on this platform")));
    1253             :             continue;
    1254             : #endif                          /* HAVE_READLINK */
    1255             :         }
    1256       92960 :         else if (S_ISDIR(statbuf.st_mode))
    1257             :         {
    1258        1548 :             bool        skip_this_dir = false;
    1259             :             ListCell   *lc;
    1260             : 
    1261             :             /*
    1262             :              * Store a directory entry in the tar file so we can get the
    1263             :              * permissions right.
    1264             :              */
    1265        1548 :             size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
    1266             :                                     sizeonly);
    1267             : 
    1268             :             /*
    1269             :              * Call ourselves recursively for a directory, unless it happens
    1270             :              * to be a separate tablespace located within PGDATA.
    1271             :              */
    1272        3238 :             foreach(lc, tablespaces)
    1273             :             {
    1274        1690 :                 tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
    1275             : 
    1276             :                 /*
    1277             :                  * ti->rpath is the tablespace relative path within PGDATA, or
    1278             :                  * NULL if the tablespace has been properly located somewhere
    1279             :                  * else.
    1280             :                  *
    1281             :                  * Skip past the leading "./" in pathbuf when comparing.
    1282             :                  */
    1283        1690 :                 if (ti->rpath && strcmp(ti->rpath, pathbuf + 2) == 0)
    1284             :                 {
    1285           0 :                     skip_this_dir = true;
    1286           0 :                     break;
    1287             :                 }
    1288             :             }
    1289             : 
    1290             :             /*
    1291             :              * skip sending directories inside pg_tblspc, if not required.
    1292             :              */
    1293        1548 :             if (strcmp(pathbuf, "./pg_tblspc") == 0 && !sendtblspclinks)
    1294           8 :                 skip_this_dir = true;
    1295             : 
    1296        1548 :             if (!skip_this_dir)
    1297        1540 :                 size += sendDir(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks);
    1298             :         }
    1299       91412 :         else if (S_ISREG(statbuf.st_mode))
    1300             :         {
    1301       91412 :             bool        sent = false;
    1302             : 
    1303       91412 :             if (!sizeonly)
    1304      176096 :                 sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
    1305       84684 :                                 true, isDbDir ? pg_atoi(lastDir + 1, sizeof(Oid), 0) : InvalidOid);
    1306             : 
    1307       91406 :             if (sent || sizeonly)
    1308             :             {
    1309             :                 /* Add size, rounded up to 512byte block */
    1310       91406 :                 size += ((statbuf.st_size + 511) & ~511);
    1311       91406 :                 size += 512;    /* Size of the header of the file */
    1312             :             }
    1313             :         }
    1314             :         else
    1315           0 :             ereport(WARNING,
    1316             :                     (errmsg("skipping special file \"%s\"", pathbuf)));
    1317             :     }
    1318        1638 :     FreeDir(dir);
    1319        1638 :     return size;
    1320             : }
    1321             : 
    1322             : /*
    1323             :  * Check if a file should have its checksum validated.
    1324             :  * We validate checksums on files in regular tablespaces
    1325             :  * (including global and default) only, and in those there
    1326             :  * are some files that are explicitly excluded.
    1327             :  */
    1328             : static bool
    1329       39348 : is_checksummed_file(const char *fullpath, const char *filename)
    1330             : {
    1331             :     const char *const *f;
    1332             : 
    1333             :     /* Check that the file is in a tablespace */
    1334       76162 :     if (strncmp(fullpath, "./global/", 9) == 0 ||
    1335       37336 :         strncmp(fullpath, "./base/", 7) == 0 ||
    1336         522 :         strncmp(fullpath, "/", 1) == 0)
    1337             :     {
    1338             :         /* Compare file against noChecksumFiles skiplist */
    1339      193580 :         for (f = noChecksumFiles; *f; f++)
    1340      155024 :             if (strcmp(*f, filename) == 0)
    1341         280 :                 return false;
    1342             : 
    1343       38556 :         return true;
    1344             :     }
    1345             :     else
    1346         512 :         return false;
    1347             : }
    1348             : 
    1349             : /*****
    1350             :  * Functions for handling tar file format
    1351             :  *
    1352             :  * Copied from pg_dump, but modified to work with libpq for sending
    1353             :  */
    1354             : 
    1355             : 
    1356             : /*
    1357             :  * Given the member, write the TAR header & send the file.
    1358             :  *
    1359             :  * If 'missing_ok' is true, will not throw an error if the file is not found.
    1360             :  *
    1361             :  * If dboid is anything other than InvalidOid then any checksum failures detected
    1362             :  * will get reported to the stats collector.
    1363             :  *
    1364             :  * Returns true if the file was successfully sent, false if 'missing_ok',
    1365             :  * and the file did not exist.
    1366             :  */
    1367             : static bool
    1368       91504 : sendFile(const char *readfilename, const char *tarfilename, struct stat *statbuf,
    1369             :          bool missing_ok, Oid dboid)
    1370             : {
    1371             :     FILE       *fp;
    1372       91504 :     BlockNumber blkno = 0;
    1373       91504 :     bool        block_retry = false;
    1374             :     char        buf[TAR_SEND_SIZE];
    1375             :     uint16      checksum;
    1376       91504 :     int         checksum_failures = 0;
    1377             :     off_t       cnt;
    1378             :     int         i;
    1379       91504 :     pgoff_t     len = 0;
    1380             :     char       *page;
    1381             :     size_t      pad;
    1382             :     PageHeader  phdr;
    1383       91504 :     int         segmentno = 0;
    1384             :     char       *segmentpath;
    1385       91504 :     bool        verify_checksum = false;
    1386             : 
    1387       91504 :     fp = AllocateFile(readfilename, "rb");
    1388       91504 :     if (fp == NULL)
    1389             :     {
    1390           0 :         if (errno == ENOENT && missing_ok)
    1391           0 :             return false;
    1392           0 :         ereport(ERROR,
    1393             :                 (errcode_for_file_access(),
    1394             :                  errmsg("could not open file \"%s\": %m", readfilename)));
    1395             :     }
    1396             : 
    1397       91504 :     _tarWriteHeader(tarfilename, NULL, statbuf, false);
    1398             : 
    1399       91502 :     if (!noverify_checksums && DataChecksumsEnabled())
    1400             :     {
    1401             :         char       *filename;
    1402             : 
    1403             :         /*
    1404             :          * Get the filename (excluding path).  As last_dir_separator()
    1405             :          * includes the last directory separator, we chop that off by
    1406             :          * incrementing the pointer.
    1407             :          */
    1408       39348 :         filename = last_dir_separator(readfilename) + 1;
    1409             : 
    1410       39348 :         if (is_checksummed_file(readfilename, filename))
    1411             :         {
    1412       38556 :             verify_checksum = true;
    1413             : 
    1414             :             /*
    1415             :              * Cut off at the segment boundary (".") to get the segment number
    1416             :              * in order to mix it into the checksum.
    1417             :              */
    1418       38556 :             segmentpath = strstr(filename, ".");
    1419       38556 :             if (segmentpath != NULL)
    1420             :             {
    1421           0 :                 segmentno = atoi(segmentpath + 1);
    1422           0 :                 if (segmentno == 0)
    1423           0 :                     ereport(ERROR,
    1424             :                             (errmsg("invalid segment number %d in file \"%s\"",
    1425             :                                     segmentno, filename)));
    1426             :             }
    1427             :         }
    1428             :     }
    1429             : 
    1430      218658 :     while ((cnt = fread(buf, 1, Min(sizeof(buf), statbuf->st_size - len), fp)) > 0)
    1431             :     {
    1432             :         /*
    1433             :          * The checksums are verified at block level, so we iterate over the
    1434             :          * buffer in chunks of BLCKSZ, after making sure that
    1435             :          * TAR_SEND_SIZE/buf is divisible by BLCKSZ and we read a multiple of
    1436             :          * BLCKSZ bytes.
    1437             :          */
    1438             :         Assert(TAR_SEND_SIZE % BLCKSZ == 0);
    1439             : 
    1440      110756 :         if (verify_checksum && (cnt % BLCKSZ != 0))
    1441             :         {
    1442           0 :             ereport(WARNING,
    1443             :                     (errmsg("cannot verify checksum in file \"%s\", block "
    1444             :                             "%d: read buffer size %d and page size %d "
    1445             :                             "differ",
    1446             :                             readfilename, blkno, (int) cnt, BLCKSZ)));
    1447           0 :             verify_checksum = false;
    1448             :         }
    1449             : 
    1450      110756 :         if (verify_checksum)
    1451             :         {
    1452      162604 :             for (i = 0; i < cnt / BLCKSZ; i++)
    1453             :             {
    1454      115804 :                 page = buf + BLCKSZ * i;
    1455             : 
    1456             :                 /*
    1457             :                  * Only check pages which have not been modified since the
    1458             :                  * start of the base backup. Otherwise, they might have been
    1459             :                  * written only halfway and the checksum would not be valid.
    1460             :                  * However, replaying WAL would reinstate the correct page in
    1461             :                  * this case. We also skip completely new pages, since they
    1462             :                  * don't have a checksum yet.
    1463             :                  */
    1464      115804 :                 if (!PageIsNew(page) && PageGetLSN(page) < startptr)
    1465             :                 {
    1466      115804 :                     checksum = pg_checksum_page((char *) page, blkno + segmentno * RELSEG_SIZE);
    1467      115804 :                     phdr = (PageHeader) page;
    1468      115804 :                     if (phdr->pd_checksum != checksum)
    1469             :                     {
    1470             :                         /*
    1471             :                          * Retry the block on the first failure.  It's
    1472             :                          * possible that we read the first 4K page of the
    1473             :                          * block just before postgres updated the entire block
    1474             :                          * so it ends up looking torn to us.  We only need to
    1475             :                          * retry once because the LSN should be updated to
    1476             :                          * something we can ignore on the next pass.  If the
    1477             :                          * error happens again then it is a true validation
    1478             :                          * failure.
    1479             :                          */
    1480          56 :                         if (block_retry == false)
    1481             :                         {
    1482             :                             /* Reread the failed block */
    1483          28 :                             if (fseek(fp, -(cnt - BLCKSZ * i), SEEK_CUR) == -1)
    1484             :                             {
    1485           0 :                                 ereport(ERROR,
    1486             :                                         (errcode_for_file_access(),
    1487             :                                          errmsg("could not fseek in file \"%s\": %m",
    1488             :                                                 readfilename)));
    1489             :                             }
    1490             : 
    1491          28 :                             if (fread(buf + BLCKSZ * i, 1, BLCKSZ, fp) != BLCKSZ)
    1492             :                             {
    1493           0 :                                 ereport(ERROR,
    1494             :                                         (errcode_for_file_access(),
    1495             :                                          errmsg("could not reread block %d of file \"%s\": %m",
    1496             :                                                 blkno, readfilename)));
    1497             :                             }
    1498             : 
    1499          28 :                             if (fseek(fp, cnt - BLCKSZ * i - BLCKSZ, SEEK_CUR) == -1)
    1500             :                             {
    1501           0 :                                 ereport(ERROR,
    1502             :                                         (errcode_for_file_access(),
    1503             :                                          errmsg("could not fseek in file \"%s\": %m",
    1504             :                                                 readfilename)));
    1505             :                             }
    1506             : 
    1507             :                             /* Set flag so we know a retry was attempted */
    1508          28 :                             block_retry = true;
    1509             : 
    1510             :                             /* Reset loop to validate the block again */
    1511          28 :                             i--;
    1512          28 :                             continue;
    1513             :                         }
    1514             : 
    1515          28 :                         checksum_failures++;
    1516             : 
    1517          28 :                         if (checksum_failures <= 5)
    1518          24 :                             ereport(WARNING,
    1519             :                                     (errmsg("checksum verification failed in "
    1520             :                                             "file \"%s\", block %d: calculated "
    1521             :                                             "%X but expected %X",
    1522             :                                             readfilename, blkno, checksum,
    1523             :                                             phdr->pd_checksum)));
    1524          28 :                         if (checksum_failures == 5)
    1525           4 :                             ereport(WARNING,
    1526             :                                     (errmsg("further checksum verification "
    1527             :                                             "failures in file \"%s\" will not "
    1528             :                                             "be reported", readfilename)));
    1529             :                     }
    1530             :                 }
    1531      115776 :                 block_retry = false;
    1532      115776 :                 blkno++;
    1533             :             }
    1534             :         }
    1535             : 
    1536             :         /* Send the chunk as a CopyData message */
    1537      110756 :         if (pq_putmessage('d', buf, cnt))
    1538           4 :             ereport(ERROR,
    1539             :                     (errmsg("base backup could not send data, aborting backup")));
    1540             : 
    1541      110752 :         len += cnt;
    1542      110752 :         throttle(cnt);
    1543             : 
    1544      110752 :         if (len >= statbuf->st_size)
    1545             :         {
    1546             :             /*
    1547             :              * Reached end of file. The file could be longer, if it was
    1548             :              * extended while we were sending it, but for a base backup we can
    1549             :              * ignore such extended data. It will be restored from WAL.
    1550             :              */
    1551       75098 :             break;
    1552             :         }
    1553             :     }
    1554             : 
    1555             :     /* If the file was truncated while we were sending it, pad it with zeros */
    1556       91498 :     if (len < statbuf->st_size)
    1557             :     {
    1558           0 :         MemSet(buf, 0, sizeof(buf));
    1559           0 :         while (len < statbuf->st_size)
    1560             :         {
    1561           0 :             cnt = Min(sizeof(buf), statbuf->st_size - len);
    1562           0 :             pq_putmessage('d', buf, cnt);
    1563           0 :             len += cnt;
    1564           0 :             throttle(cnt);
    1565             :         }
    1566             :     }
    1567             : 
    1568             :     /*
    1569             :      * Pad to 512 byte boundary, per tar format requirements. (This small
    1570             :      * piece of data is probably not worth throttling.)
    1571             :      */
    1572       91498 :     pad = ((len + 511) & ~511) - len;
    1573       91498 :     if (pad > 0)
    1574             :     {
    1575         950 :         MemSet(buf, 0, pad);
    1576         950 :         pq_putmessage('d', buf, pad);
    1577             :     }
    1578             : 
    1579       91498 :     FreeFile(fp);
    1580             : 
    1581       91498 :     if (checksum_failures > 1)
    1582             :     {
    1583           4 :         ereport(WARNING,
    1584             :                 (errmsg("file \"%s\" has a total of %d checksum verification "
    1585             :                         "failures", readfilename, checksum_failures)));
    1586             : 
    1587           4 :         pgstat_report_checksum_failures_in_db(dboid, checksum_failures);
    1588             :     }
    1589             : 
    1590       91498 :     total_checksum_failures += checksum_failures;
    1591             : 
    1592       91498 :     return true;
    1593             : }
    1594             : 
    1595             : 
    1596             : static int64
    1597       94018 : _tarWriteHeader(const char *filename, const char *linktarget,
    1598             :                 struct stat *statbuf, bool sizeonly)
    1599             : {
    1600             :     char        h[512];
    1601             :     enum tarError rc;
    1602             : 
    1603       94018 :     if (!sizeonly)
    1604             :     {
    1605       94018 :         rc = tarCreateHeader(h, filename, linktarget, statbuf->st_size,
    1606             :                              statbuf->st_mode, statbuf->st_uid, statbuf->st_gid,
    1607             :                              statbuf->st_mtime);
    1608             : 
    1609       94018 :         switch (rc)
    1610             :         {
    1611             :             case TAR_OK:
    1612       94016 :                 break;
    1613             :             case TAR_NAME_TOO_LONG:
    1614           2 :                 ereport(ERROR,
    1615             :                         (errmsg("file name too long for tar format: \"%s\"",
    1616             :                                 filename)));
    1617             :                 break;
    1618             :             case TAR_SYMLINK_TOO_LONG:
    1619           0 :                 ereport(ERROR,
    1620             :                         (errmsg("symbolic link target too long for tar format: "
    1621             :                                 "file name \"%s\", target \"%s\"",
    1622             :                                 filename, linktarget)));
    1623             :                 break;
    1624             :             default:
    1625           0 :                 elog(ERROR, "unrecognized tar error: %d", rc);
    1626             :         }
    1627             : 
    1628       94016 :         pq_putmessage('d', h, sizeof(h));
    1629             :     }
    1630             : 
    1631       94016 :     return sizeof(h);
    1632             : }
    1633             : 
    1634             : /*
    1635             :  * Write tar header for a directory.  If the entry in statbuf is a link then
    1636             :  * write it as a directory anyway.
    1637             :  */
    1638             : static int64
    1639         748 : _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
    1640             :              bool sizeonly)
    1641             : {
    1642             :     /* If symlink, write it as a directory anyway */
    1643             : #ifndef WIN32
    1644         748 :     if (S_ISLNK(statbuf->st_mode))
    1645             : #else
    1646             :     if (pgwin32_is_junction(pathbuf))
    1647             : #endif
    1648          44 :         statbuf->st_mode = S_IFDIR | pg_dir_create_mode;
    1649             : 
    1650         748 :     return _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf, sizeonly);
    1651             : }
    1652             : 
    1653             : /*
    1654             :  * Increment the network transfer counter by the given number of bytes,
    1655             :  * and sleep if necessary to comply with the requested network transfer
    1656             :  * rate.
    1657             :  */
    1658             : static void
    1659      111776 : throttle(size_t increment)
    1660             : {
    1661             :     TimeOffset  elapsed_min;
    1662             : 
    1663      111776 :     if (throttling_counter < 0)
    1664      111776 :         return;
    1665             : 
    1666           0 :     throttling_counter += increment;
    1667           0 :     if (throttling_counter < throttling_sample)
    1668           0 :         return;
    1669             : 
    1670             :     /* How much time should have elapsed at minimum? */
    1671           0 :     elapsed_min = elapsed_min_unit *
    1672           0 :         (throttling_counter / throttling_sample);
    1673             : 
    1674             :     /*
    1675             :      * Since the latch could be set repeatedly because of concurrently WAL
    1676             :      * activity, sleep in a loop to ensure enough time has passed.
    1677             :      */
    1678             :     for (;;)
    1679           0 :     {
    1680             :         TimeOffset  elapsed,
    1681             :                     sleep;
    1682             :         int         wait_result;
    1683             : 
    1684             :         /* Time elapsed since the last measurement (and possible wake up). */
    1685           0 :         elapsed = GetCurrentTimestamp() - throttled_last;
    1686             : 
    1687             :         /* sleep if the transfer is faster than it should be */
    1688           0 :         sleep = elapsed_min - elapsed;
    1689           0 :         if (sleep <= 0)
    1690           0 :             break;
    1691             : 
    1692           0 :         ResetLatch(MyLatch);
    1693             : 
    1694             :         /* We're eating a potentially set latch, so check for interrupts */
    1695           0 :         CHECK_FOR_INTERRUPTS();
    1696             : 
    1697             :         /*
    1698             :          * (TAR_SEND_SIZE / throttling_sample * elapsed_min_unit) should be
    1699             :          * the maximum time to sleep. Thus the cast to long is safe.
    1700             :          */
    1701           0 :         wait_result = WaitLatch(MyLatch,
    1702             :                                 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
    1703           0 :                                 (long) (sleep / 1000),
    1704             :                                 WAIT_EVENT_BASE_BACKUP_THROTTLE);
    1705             : 
    1706           0 :         if (wait_result & WL_LATCH_SET)
    1707           0 :             CHECK_FOR_INTERRUPTS();
    1708             : 
    1709             :         /* Done waiting? */
    1710           0 :         if (wait_result & WL_TIMEOUT)
    1711           0 :             break;
    1712             :     }
    1713             : 
    1714             :     /*
    1715             :      * As we work with integers, only whole multiple of throttling_sample was
    1716             :      * processed. The rest will be done during the next call of this function.
    1717             :      */
    1718           0 :     throttling_counter %= throttling_sample;
    1719             : 
    1720             :     /*
    1721             :      * Time interval for the remaining amount and possible next increments
    1722             :      * starts now.
    1723             :      */
    1724           0 :     throttled_last = GetCurrentTimestamp();
    1725             : }

Generated by: LCOV version 1.13