LCOV - code coverage report
Current view: top level - src/backend/replication - basebackup.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 0 438 0.0 %
Date: 2017-09-29 15:12:54 Functions: 0 15 0.0 %
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-2017, 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/catalog.h"
      21             : #include "catalog/pg_type.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 "postmaster/syslogger.h"
      30             : #include "replication/basebackup.h"
      31             : #include "replication/walsender.h"
      32             : #include "replication/walsender_private.h"
      33             : #include "storage/dsm_impl.h"
      34             : #include "storage/fd.h"
      35             : #include "storage/ipc.h"
      36             : #include "utils/builtins.h"
      37             : #include "utils/elog.h"
      38             : #include "utils/ps_status.h"
      39             : #include "utils/timestamp.h"
      40             : 
      41             : 
      42             : typedef struct
      43             : {
      44             :     const char *label;
      45             :     bool        progress;
      46             :     bool        fastcheckpoint;
      47             :     bool        nowait;
      48             :     bool        includewal;
      49             :     uint32      maxrate;
      50             :     bool        sendtblspcmapfile;
      51             : } basebackup_options;
      52             : 
      53             : 
      54             : static int64 sendDir(char *path, int basepathlen, bool sizeonly,
      55             :         List *tablespaces, bool sendtblspclinks);
      56             : static bool sendFile(char *readfilename, char *tarfilename,
      57             :          struct stat *statbuf, bool missing_ok);
      58             : static void sendFileWithContent(const char *filename, const char *content);
      59             : static int64 _tarWriteHeader(const char *filename, const char *linktarget,
      60             :                 struct stat *statbuf, bool sizeonly);
      61             : static int64 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
      62             :              bool sizeonly);
      63             : static void send_int8_string(StringInfoData *buf, int64 intval);
      64             : static void SendBackupHeader(List *tablespaces);
      65             : static void base_backup_cleanup(int code, Datum arg);
      66             : static void perform_base_backup(basebackup_options *opt, DIR *tblspcdir);
      67             : static void parse_basebackup_options(List *options, basebackup_options *opt);
      68             : static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli);
      69             : static int  compareWalFileNames(const void *a, const void *b);
      70             : static void throttle(size_t increment);
      71             : 
      72             : /* Was the backup currently in-progress initiated in recovery mode? */
      73             : static bool backup_started_in_recovery = false;
      74             : 
      75             : /* Relative path of temporary statistics directory */
      76             : static char *statrelpath = NULL;
      77             : 
      78             : /*
      79             :  * Size of each block sent into the tar stream for larger files.
      80             :  */
      81             : #define TAR_SEND_SIZE 32768
      82             : 
      83             : /*
      84             :  * How frequently to throttle, as a fraction of the specified rate-second.
      85             :  */
      86             : #define THROTTLING_FREQUENCY    8
      87             : 
      88             : /* The actual number of bytes, transfer of which may cause sleep. */
      89             : static uint64 throttling_sample;
      90             : 
      91             : /* Amount of data already transferred but not yet throttled.  */
      92             : static int64 throttling_counter;
      93             : 
      94             : /* The minimum time required to transfer throttling_sample bytes. */
      95             : static TimeOffset elapsed_min_unit;
      96             : 
      97             : /* The last check of the transfer rate. */
      98             : static TimestampTz throttled_last;
      99             : 
     100             : /*
     101             :  * The contents of these directories are removed or recreated during server
     102             :  * start so they are not included in backups.  The directories themselves are
     103             :  * kept and included as empty to preserve access permissions.
     104             :  */
     105             : static const char *excludeDirContents[] =
     106             : {
     107             :     /*
     108             :      * Skip temporary statistics files. PG_STAT_TMP_DIR must be skipped even
     109             :      * when stats_temp_directory is set because PGSS_TEXT_FILE is always
     110             :      * created there.
     111             :      */
     112             :     PG_STAT_TMP_DIR,
     113             : 
     114             :     /*
     115             :      * It is generally not useful to backup the contents of this directory
     116             :      * even if the intention is to restore to another master. See backup.sgml
     117             :      * for a more detailed description.
     118             :      */
     119             :     "pg_replslot",
     120             : 
     121             :     /* Contents removed on startup, see dsm_cleanup_for_mmap(). */
     122             :     PG_DYNSHMEM_DIR,
     123             : 
     124             :     /* Contents removed on startup, see AsyncShmemInit(). */
     125             :     "pg_notify",
     126             : 
     127             :     /*
     128             :      * Old contents are loaded for possible debugging but are not required for
     129             :      * normal operation, see OldSerXidInit().
     130             :      */
     131             :     "pg_serial",
     132             : 
     133             :     /* Contents removed on startup, see DeleteAllExportedSnapshotFiles(). */
     134             :     "pg_snapshots",
     135             : 
     136             :     /* Contents zeroed on startup, see StartupSUBTRANS(). */
     137             :     "pg_subtrans",
     138             : 
     139             :     /* end of list */
     140             :     NULL
     141             : };
     142             : 
     143             : /*
     144             :  * List of files excluded from backups.
     145             :  */
     146             : static const char *excludeFiles[] =
     147             : {
     148             :     /* Skip auto conf temporary file. */
     149             :     PG_AUTOCONF_FILENAME ".tmp",
     150             : 
     151             :     /* Skip current log file temporary file */
     152             :     LOG_METAINFO_DATAFILE_TMP,
     153             : 
     154             :     /*
     155             :      * If there's a backup_label or tablespace_map file, it belongs to a
     156             :      * backup started by the user with pg_start_backup().  It is *not* correct
     157             :      * for this backup.  Our backup_label/tablespace_map is injected into the
     158             :      * tar separately.
     159             :      */
     160             :     BACKUP_LABEL_FILE,
     161             :     TABLESPACE_MAP,
     162             : 
     163             :     "postmaster.pid",
     164             :     "postmaster.opts",
     165             : 
     166             :     /* end of list */
     167             :     NULL
     168             : };
     169             : 
     170             : /*
     171             :  * Called when ERROR or FATAL happens in perform_base_backup() after
     172             :  * we have started the backup - make sure we end it!
     173             :  */
     174             : static void
     175           0 : base_backup_cleanup(int code, Datum arg)
     176             : {
     177           0 :     do_pg_abort_backup();
     178           0 : }
     179             : 
     180             : /*
     181             :  * Actually do a base backup for the specified tablespaces.
     182             :  *
     183             :  * This is split out mainly to avoid complaints about "variable might be
     184             :  * clobbered by longjmp" from stupider versions of gcc.
     185             :  */
     186             : static void
     187           0 : perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
     188             : {
     189             :     XLogRecPtr  startptr;
     190             :     TimeLineID  starttli;
     191             :     XLogRecPtr  endptr;
     192             :     TimeLineID  endtli;
     193             :     StringInfo  labelfile;
     194           0 :     StringInfo  tblspc_map_file = NULL;
     195             :     int         datadirpathlen;
     196           0 :     List       *tablespaces = NIL;
     197             : 
     198           0 :     datadirpathlen = strlen(DataDir);
     199             : 
     200           0 :     backup_started_in_recovery = RecoveryInProgress();
     201             : 
     202           0 :     labelfile = makeStringInfo();
     203           0 :     tblspc_map_file = makeStringInfo();
     204             : 
     205           0 :     startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli,
     206             :                                   labelfile, tblspcdir, &tablespaces,
     207             :                                   tblspc_map_file,
     208           0 :                                   opt->progress, opt->sendtblspcmapfile);
     209             : 
     210             :     /*
     211             :      * Once do_pg_start_backup has been called, ensure that any failure causes
     212             :      * us to abort the backup so we don't "leak" a backup counter. For this
     213             :      * reason, *all* functionality between do_pg_start_backup() and
     214             :      * do_pg_stop_backup() should be inside the error cleanup block!
     215             :      */
     216             : 
     217           0 :     PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
     218             :     {
     219             :         ListCell   *lc;
     220             :         tablespaceinfo *ti;
     221             : 
     222           0 :         SendXlogRecPtrResult(startptr, starttli);
     223             : 
     224             :         /*
     225             :          * Calculate the relative path of temporary statistics directory in
     226             :          * order to skip the files which are located in that directory later.
     227             :          */
     228           0 :         if (is_absolute_path(pgstat_stat_directory) &&
     229           0 :             strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
     230           0 :             statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
     231           0 :         else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
     232           0 :             statrelpath = psprintf("./%s", pgstat_stat_directory);
     233             :         else
     234           0 :             statrelpath = pgstat_stat_directory;
     235             : 
     236             :         /* Add a node for the base directory at the end */
     237           0 :         ti = palloc0(sizeof(tablespaceinfo));
     238           0 :         ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
     239           0 :         tablespaces = lappend(tablespaces, ti);
     240             : 
     241             :         /* Send tablespace header */
     242           0 :         SendBackupHeader(tablespaces);
     243             : 
     244             :         /* Setup and activate network throttling, if client requested it */
     245           0 :         if (opt->maxrate > 0)
     246             :         {
     247           0 :             throttling_sample =
     248           0 :                 (int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
     249             : 
     250             :             /*
     251             :              * The minimum amount of time for throttling_sample bytes to be
     252             :              * transferred.
     253             :              */
     254           0 :             elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
     255             : 
     256             :             /* Enable throttling. */
     257           0 :             throttling_counter = 0;
     258             : 
     259             :             /* The 'real data' starts now (header was ignored). */
     260           0 :             throttled_last = GetCurrentTimestamp();
     261             :         }
     262             :         else
     263             :         {
     264             :             /* Disable throttling. */
     265           0 :             throttling_counter = -1;
     266             :         }
     267             : 
     268             :         /* Send off our tablespaces one by one */
     269           0 :         foreach(lc, tablespaces)
     270             :         {
     271           0 :             tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
     272             :             StringInfoData buf;
     273             : 
     274             :             /* Send CopyOutResponse message */
     275           0 :             pq_beginmessage(&buf, 'H');
     276           0 :             pq_sendbyte(&buf, 0);   /* overall format */
     277           0 :             pq_sendint(&buf, 0, 2); /* natts */
     278           0 :             pq_endmessage(&buf);
     279             : 
     280           0 :             if (ti->path == NULL)
     281             :             {
     282             :                 struct stat statbuf;
     283             : 
     284             :                 /* In the main tar, include the backup_label first... */
     285           0 :                 sendFileWithContent(BACKUP_LABEL_FILE, labelfile->data);
     286             : 
     287             :                 /*
     288             :                  * Send tablespace_map file if required and then the bulk of
     289             :                  * the files.
     290             :                  */
     291           0 :                 if (tblspc_map_file && opt->sendtblspcmapfile)
     292             :                 {
     293           0 :                     sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data);
     294           0 :                     sendDir(".", 1, false, tablespaces, false);
     295             :                 }
     296             :                 else
     297           0 :                     sendDir(".", 1, false, tablespaces, true);
     298             : 
     299             :                 /* ... and pg_control after everything else. */
     300           0 :                 if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
     301           0 :                     ereport(ERROR,
     302             :                             (errcode_for_file_access(),
     303             :                              errmsg("could not stat control file \"%s\": %m",
     304             :                                     XLOG_CONTROL_FILE)));
     305           0 :                 sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false);
     306             :             }
     307             :             else
     308           0 :                 sendTablespace(ti->path, false);
     309             : 
     310             :             /*
     311             :              * If we're including WAL, and this is the main data directory we
     312             :              * don't terminate the tar stream here. Instead, we will append
     313             :              * the xlog files below and terminate it then. This is safe since
     314             :              * the main data directory is always sent *last*.
     315             :              */
     316           0 :             if (opt->includewal && ti->path == NULL)
     317             :             {
     318           0 :                 Assert(lnext(lc) == NULL);
     319             :             }
     320             :             else
     321           0 :                 pq_putemptymessage('c');    /* CopyDone */
     322             :         }
     323             :     }
     324           0 :     PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
     325             : 
     326           0 :     endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
     327             : 
     328           0 :     if (opt->includewal)
     329             :     {
     330             :         /*
     331             :          * We've left the last tar file "open", so we can now append the
     332             :          * required WAL files to it.
     333             :          */
     334             :         char        pathbuf[MAXPGPATH];
     335             :         XLogSegNo   segno;
     336             :         XLogSegNo   startsegno;
     337             :         XLogSegNo   endsegno;
     338             :         struct stat statbuf;
     339           0 :         List       *historyFileList = NIL;
     340           0 :         List       *walFileList = NIL;
     341             :         char      **walFiles;
     342             :         int         nWalFiles;
     343             :         char        firstoff[MAXFNAMELEN];
     344             :         char        lastoff[MAXFNAMELEN];
     345             :         DIR        *dir;
     346             :         struct dirent *de;
     347             :         int         i;
     348             :         ListCell   *lc;
     349             :         TimeLineID  tli;
     350             : 
     351             :         /*
     352             :          * I'd rather not worry about timelines here, so scan pg_wal and
     353             :          * include all WAL files in the range between 'startptr' and 'endptr',
     354             :          * regardless of the timeline the file is stamped with. If there are
     355             :          * some spurious WAL files belonging to timelines that don't belong in
     356             :          * this server's history, they will be included too. Normally there
     357             :          * shouldn't be such files, but if there are, there's little harm in
     358             :          * including them.
     359             :          */
     360           0 :         XLByteToSeg(startptr, startsegno);
     361           0 :         XLogFileName(firstoff, ThisTimeLineID, startsegno);
     362           0 :         XLByteToPrevSeg(endptr, endsegno);
     363           0 :         XLogFileName(lastoff, ThisTimeLineID, endsegno);
     364             : 
     365           0 :         dir = AllocateDir("pg_wal");
     366           0 :         if (!dir)
     367           0 :             ereport(ERROR,
     368             :                     (errmsg("could not open directory \"%s\": %m", "pg_wal")));
     369           0 :         while ((de = ReadDir(dir, "pg_wal")) != NULL)
     370             :         {
     371             :             /* Does it look like a WAL segment, and is it in the range? */
     372           0 :             if (IsXLogFileName(de->d_name) &&
     373           0 :                 strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
     374           0 :                 strcmp(de->d_name + 8, lastoff + 8) <= 0)
     375             :             {
     376           0 :                 walFileList = lappend(walFileList, pstrdup(de->d_name));
     377             :             }
     378             :             /* Does it look like a timeline history file? */
     379           0 :             else if (IsTLHistoryFileName(de->d_name))
     380             :             {
     381           0 :                 historyFileList = lappend(historyFileList, pstrdup(de->d_name));
     382             :             }
     383             :         }
     384           0 :         FreeDir(dir);
     385             : 
     386             :         /*
     387             :          * Before we go any further, check that none of the WAL segments we
     388             :          * need were removed.
     389             :          */
     390           0 :         CheckXLogRemoved(startsegno, ThisTimeLineID);
     391             : 
     392             :         /*
     393             :          * Put the WAL filenames into an array, and sort. We send the files in
     394             :          * order from oldest to newest, to reduce the chance that a file is
     395             :          * recycled before we get a chance to send it over.
     396             :          */
     397           0 :         nWalFiles = list_length(walFileList);
     398           0 :         walFiles = palloc(nWalFiles * sizeof(char *));
     399           0 :         i = 0;
     400           0 :         foreach(lc, walFileList)
     401             :         {
     402           0 :             walFiles[i++] = lfirst(lc);
     403             :         }
     404           0 :         qsort(walFiles, nWalFiles, sizeof(char *), compareWalFileNames);
     405             : 
     406             :         /*
     407             :          * There must be at least one xlog file in the pg_wal directory, since
     408             :          * we are doing backup-including-xlog.
     409             :          */
     410           0 :         if (nWalFiles < 1)
     411           0 :             ereport(ERROR,
     412             :                     (errmsg("could not find any WAL files")));
     413             : 
     414             :         /*
     415             :          * Sanity check: the first and last segment should cover startptr and
     416             :          * endptr, with no gaps in between.
     417             :          */
     418           0 :         XLogFromFileName(walFiles[0], &tli, &segno);
     419           0 :         if (segno != startsegno)
     420             :         {
     421             :             char        startfname[MAXFNAMELEN];
     422             : 
     423           0 :             XLogFileName(startfname, ThisTimeLineID, startsegno);
     424           0 :             ereport(ERROR,
     425             :                     (errmsg("could not find WAL file \"%s\"", startfname)));
     426             :         }
     427           0 :         for (i = 0; i < nWalFiles; i++)
     428             :         {
     429           0 :             XLogSegNo   currsegno = segno;
     430           0 :             XLogSegNo   nextsegno = segno + 1;
     431             : 
     432           0 :             XLogFromFileName(walFiles[i], &tli, &segno);
     433           0 :             if (!(nextsegno == segno || currsegno == segno))
     434             :             {
     435             :                 char        nextfname[MAXFNAMELEN];
     436             : 
     437           0 :                 XLogFileName(nextfname, ThisTimeLineID, nextsegno);
     438           0 :                 ereport(ERROR,
     439             :                         (errmsg("could not find WAL file \"%s\"", nextfname)));
     440             :             }
     441             :         }
     442           0 :         if (segno != endsegno)
     443             :         {
     444             :             char        endfname[MAXFNAMELEN];
     445             : 
     446           0 :             XLogFileName(endfname, ThisTimeLineID, endsegno);
     447           0 :             ereport(ERROR,
     448             :                     (errmsg("could not find WAL file \"%s\"", endfname)));
     449             :         }
     450             : 
     451             :         /* Ok, we have everything we need. Send the WAL files. */
     452           0 :         for (i = 0; i < nWalFiles; i++)
     453             :         {
     454             :             FILE       *fp;
     455             :             char        buf[TAR_SEND_SIZE];
     456             :             size_t      cnt;
     457           0 :             pgoff_t     len = 0;
     458             : 
     459           0 :             snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFiles[i]);
     460           0 :             XLogFromFileName(walFiles[i], &tli, &segno);
     461             : 
     462           0 :             fp = AllocateFile(pathbuf, "rb");
     463           0 :             if (fp == NULL)
     464             :             {
     465             :                 /*
     466             :                  * Most likely reason for this is that the file was already
     467             :                  * removed by a checkpoint, so check for that to get a better
     468             :                  * error message.
     469             :                  */
     470           0 :                 CheckXLogRemoved(segno, tli);
     471             : 
     472           0 :                 ereport(ERROR,
     473             :                         (errcode_for_file_access(),
     474             :                          errmsg("could not open file \"%s\": %m", pathbuf)));
     475             :             }
     476             : 
     477           0 :             if (fstat(fileno(fp), &statbuf) != 0)
     478           0 :                 ereport(ERROR,
     479             :                         (errcode_for_file_access(),
     480             :                          errmsg("could not stat file \"%s\": %m",
     481             :                                 pathbuf)));
     482           0 :             if (statbuf.st_size != XLogSegSize)
     483             :             {
     484           0 :                 CheckXLogRemoved(segno, tli);
     485           0 :                 ereport(ERROR,
     486             :                         (errcode_for_file_access(),
     487             :                          errmsg("unexpected WAL file size \"%s\"", walFiles[i])));
     488             :             }
     489             : 
     490             :             /* send the WAL file itself */
     491           0 :             _tarWriteHeader(pathbuf, NULL, &statbuf, false);
     492             : 
     493           0 :             while ((cnt = fread(buf, 1, Min(sizeof(buf), XLogSegSize - len), fp)) > 0)
     494             :             {
     495           0 :                 CheckXLogRemoved(segno, tli);
     496             :                 /* Send the chunk as a CopyData message */
     497           0 :                 if (pq_putmessage('d', buf, cnt))
     498           0 :                     ereport(ERROR,
     499             :                             (errmsg("base backup could not send data, aborting backup")));
     500             : 
     501           0 :                 len += cnt;
     502           0 :                 throttle(cnt);
     503             : 
     504           0 :                 if (len == XLogSegSize)
     505           0 :                     break;
     506             :             }
     507             : 
     508           0 :             if (len != XLogSegSize)
     509             :             {
     510           0 :                 CheckXLogRemoved(segno, tli);
     511           0 :                 ereport(ERROR,
     512             :                         (errcode_for_file_access(),
     513             :                          errmsg("unexpected WAL file size \"%s\"", walFiles[i])));
     514             :             }
     515             : 
     516             :             /* XLogSegSize is a multiple of 512, so no need for padding */
     517             : 
     518           0 :             FreeFile(fp);
     519             : 
     520             :             /*
     521             :              * Mark file as archived, otherwise files can get archived again
     522             :              * after promotion of a new node. This is in line with
     523             :              * walreceiver.c always doing an XLogArchiveForceDone() after a
     524             :              * complete segment.
     525             :              */
     526           0 :             StatusFilePath(pathbuf, walFiles[i], ".done");
     527           0 :             sendFileWithContent(pathbuf, "");
     528             :         }
     529             : 
     530             :         /*
     531             :          * Send timeline history files too. Only the latest timeline history
     532             :          * file is required for recovery, and even that only if there happens
     533             :          * to be a timeline switch in the first WAL segment that contains the
     534             :          * checkpoint record, or if we're taking a base backup from a standby
     535             :          * server and the target timeline changes while the backup is taken.
     536             :          * But they are small and highly useful for debugging purposes, so
     537             :          * better include them all, always.
     538             :          */
     539           0 :         foreach(lc, historyFileList)
     540             :         {
     541           0 :             char       *fname = lfirst(lc);
     542             : 
     543           0 :             snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
     544             : 
     545           0 :             if (lstat(pathbuf, &statbuf) != 0)
     546           0 :                 ereport(ERROR,
     547             :                         (errcode_for_file_access(),
     548             :                          errmsg("could not stat file \"%s\": %m", pathbuf)));
     549             : 
     550           0 :             sendFile(pathbuf, pathbuf, &statbuf, false);
     551             : 
     552             :             /* unconditionally mark file as archived */
     553           0 :             StatusFilePath(pathbuf, fname, ".done");
     554           0 :             sendFileWithContent(pathbuf, "");
     555             :         }
     556             : 
     557             :         /* Send CopyDone message for the last tar file */
     558           0 :         pq_putemptymessage('c');
     559             :     }
     560           0 :     SendXlogRecPtrResult(endptr, endtli);
     561           0 : }
     562             : 
     563             : /*
     564             :  * qsort comparison function, to compare log/seg portion of WAL segment
     565             :  * filenames, ignoring the timeline portion.
     566             :  */
     567             : static int
     568           0 : compareWalFileNames(const void *a, const void *b)
     569             : {
     570           0 :     char       *fna = *((char **) a);
     571           0 :     char       *fnb = *((char **) b);
     572             : 
     573           0 :     return strcmp(fna + 8, fnb + 8);
     574             : }
     575             : 
     576             : /*
     577             :  * Parse the base backup options passed down by the parser
     578             :  */
     579             : static void
     580           0 : parse_basebackup_options(List *options, basebackup_options *opt)
     581             : {
     582             :     ListCell   *lopt;
     583           0 :     bool        o_label = false;
     584           0 :     bool        o_progress = false;
     585           0 :     bool        o_fast = false;
     586           0 :     bool        o_nowait = false;
     587           0 :     bool        o_wal = false;
     588           0 :     bool        o_maxrate = false;
     589           0 :     bool        o_tablespace_map = false;
     590             : 
     591           0 :     MemSet(opt, 0, sizeof(*opt));
     592           0 :     foreach(lopt, options)
     593             :     {
     594           0 :         DefElem    *defel = (DefElem *) lfirst(lopt);
     595             : 
     596           0 :         if (strcmp(defel->defname, "label") == 0)
     597             :         {
     598           0 :             if (o_label)
     599           0 :                 ereport(ERROR,
     600             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     601             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     602           0 :             opt->label = strVal(defel->arg);
     603           0 :             o_label = true;
     604             :         }
     605           0 :         else if (strcmp(defel->defname, "progress") == 0)
     606             :         {
     607           0 :             if (o_progress)
     608           0 :                 ereport(ERROR,
     609             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     610             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     611           0 :             opt->progress = true;
     612           0 :             o_progress = true;
     613             :         }
     614           0 :         else if (strcmp(defel->defname, "fast") == 0)
     615             :         {
     616           0 :             if (o_fast)
     617           0 :                 ereport(ERROR,
     618             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     619             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     620           0 :             opt->fastcheckpoint = true;
     621           0 :             o_fast = true;
     622             :         }
     623           0 :         else if (strcmp(defel->defname, "nowait") == 0)
     624             :         {
     625           0 :             if (o_nowait)
     626           0 :                 ereport(ERROR,
     627             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     628             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     629           0 :             opt->nowait = true;
     630           0 :             o_nowait = true;
     631             :         }
     632           0 :         else if (strcmp(defel->defname, "wal") == 0)
     633             :         {
     634           0 :             if (o_wal)
     635           0 :                 ereport(ERROR,
     636             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     637             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     638           0 :             opt->includewal = true;
     639           0 :             o_wal = true;
     640             :         }
     641           0 :         else if (strcmp(defel->defname, "max_rate") == 0)
     642             :         {
     643             :             long        maxrate;
     644             : 
     645           0 :             if (o_maxrate)
     646           0 :                 ereport(ERROR,
     647             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     648             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     649             : 
     650           0 :             maxrate = intVal(defel->arg);
     651           0 :             if (maxrate < MAX_RATE_LOWER || maxrate > MAX_RATE_UPPER)
     652           0 :                 ereport(ERROR,
     653             :                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     654             :                          errmsg("%d is outside the valid range for parameter \"%s\" (%d .. %d)",
     655             :                                 (int) maxrate, "MAX_RATE", MAX_RATE_LOWER, MAX_RATE_UPPER)));
     656             : 
     657           0 :             opt->maxrate = (uint32) maxrate;
     658           0 :             o_maxrate = true;
     659             :         }
     660           0 :         else if (strcmp(defel->defname, "tablespace_map") == 0)
     661             :         {
     662           0 :             if (o_tablespace_map)
     663           0 :                 ereport(ERROR,
     664             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     665             :                          errmsg("duplicate option \"%s\"", defel->defname)));
     666           0 :             opt->sendtblspcmapfile = true;
     667           0 :             o_tablespace_map = true;
     668             :         }
     669             :         else
     670           0 :             elog(ERROR, "option \"%s\" not recognized",
     671             :                  defel->defname);
     672             :     }
     673           0 :     if (opt->label == NULL)
     674           0 :         opt->label = "base backup";
     675           0 : }
     676             : 
     677             : 
     678             : /*
     679             :  * SendBaseBackup() - send a complete base backup.
     680             :  *
     681             :  * The function will put the system into backup mode like pg_start_backup()
     682             :  * does, so that the backup is consistent even though we read directly from
     683             :  * the filesystem, bypassing the buffer cache.
     684             :  */
     685             : void
     686           0 : SendBaseBackup(BaseBackupCmd *cmd)
     687             : {
     688             :     DIR        *dir;
     689             :     basebackup_options opt;
     690             : 
     691           0 :     parse_basebackup_options(cmd->options, &opt);
     692             : 
     693           0 :     WalSndSetState(WALSNDSTATE_BACKUP);
     694             : 
     695           0 :     if (update_process_title)
     696             :     {
     697             :         char        activitymsg[50];
     698             : 
     699           0 :         snprintf(activitymsg, sizeof(activitymsg), "sending backup \"%s\"",
     700             :                  opt.label);
     701           0 :         set_ps_display(activitymsg, false);
     702             :     }
     703             : 
     704             :     /* Make sure we can open the directory with tablespaces in it */
     705           0 :     dir = AllocateDir("pg_tblspc");
     706           0 :     if (!dir)
     707           0 :         ereport(ERROR,
     708             :                 (errmsg("could not open directory \"%s\": %m", "pg_tblspc")));
     709             : 
     710           0 :     perform_base_backup(&opt, dir);
     711             : 
     712           0 :     FreeDir(dir);
     713           0 : }
     714             : 
     715             : static void
     716           0 : send_int8_string(StringInfoData *buf, int64 intval)
     717             : {
     718             :     char        is[32];
     719             : 
     720           0 :     sprintf(is, INT64_FORMAT, intval);
     721           0 :     pq_sendint(buf, strlen(is), 4);
     722           0 :     pq_sendbytes(buf, is, strlen(is));
     723           0 : }
     724             : 
     725             : static void
     726           0 : SendBackupHeader(List *tablespaces)
     727             : {
     728             :     StringInfoData buf;
     729             :     ListCell   *lc;
     730             : 
     731             :     /* Construct and send the directory information */
     732           0 :     pq_beginmessage(&buf, 'T'); /* RowDescription */
     733           0 :     pq_sendint(&buf, 3, 2);     /* 3 fields */
     734             : 
     735             :     /* First field - spcoid */
     736           0 :     pq_sendstring(&buf, "spcoid");
     737           0 :     pq_sendint(&buf, 0, 4);     /* table oid */
     738           0 :     pq_sendint(&buf, 0, 2);     /* attnum */
     739           0 :     pq_sendint(&buf, OIDOID, 4);    /* type oid */
     740           0 :     pq_sendint(&buf, 4, 2);     /* typlen */
     741           0 :     pq_sendint(&buf, 0, 4);     /* typmod */
     742           0 :     pq_sendint(&buf, 0, 2);     /* format code */
     743             : 
     744             :     /* Second field - spcpath */
     745           0 :     pq_sendstring(&buf, "spclocation");
     746           0 :     pq_sendint(&buf, 0, 4);
     747           0 :     pq_sendint(&buf, 0, 2);
     748           0 :     pq_sendint(&buf, TEXTOID, 4);
     749           0 :     pq_sendint(&buf, -1, 2);
     750           0 :     pq_sendint(&buf, 0, 4);
     751           0 :     pq_sendint(&buf, 0, 2);
     752             : 
     753             :     /* Third field - size */
     754           0 :     pq_sendstring(&buf, "size");
     755           0 :     pq_sendint(&buf, 0, 4);
     756           0 :     pq_sendint(&buf, 0, 2);
     757           0 :     pq_sendint(&buf, INT8OID, 4);
     758           0 :     pq_sendint(&buf, 8, 2);
     759           0 :     pq_sendint(&buf, 0, 4);
     760           0 :     pq_sendint(&buf, 0, 2);
     761           0 :     pq_endmessage(&buf);
     762             : 
     763           0 :     foreach(lc, tablespaces)
     764             :     {
     765           0 :         tablespaceinfo *ti = lfirst(lc);
     766             : 
     767             :         /* Send one datarow message */
     768           0 :         pq_beginmessage(&buf, 'D');
     769           0 :         pq_sendint(&buf, 3, 2); /* number of columns */
     770           0 :         if (ti->path == NULL)
     771             :         {
     772           0 :             pq_sendint(&buf, -1, 4);    /* Length = -1 ==> NULL */
     773           0 :             pq_sendint(&buf, -1, 4);
     774             :         }
     775             :         else
     776             :         {
     777             :             Size        len;
     778             : 
     779           0 :             len = strlen(ti->oid);
     780           0 :             pq_sendint(&buf, len, 4);
     781           0 :             pq_sendbytes(&buf, ti->oid, len);
     782             : 
     783           0 :             len = strlen(ti->path);
     784           0 :             pq_sendint(&buf, len, 4);
     785           0 :             pq_sendbytes(&buf, ti->path, len);
     786             :         }
     787           0 :         if (ti->size >= 0)
     788           0 :             send_int8_string(&buf, ti->size / 1024);
     789             :         else
     790           0 :             pq_sendint(&buf, -1, 4);    /* NULL */
     791             : 
     792           0 :         pq_endmessage(&buf);
     793             :     }
     794             : 
     795             :     /* Send a CommandComplete message */
     796           0 :     pq_puttextmessage('C', "SELECT");
     797           0 : }
     798             : 
     799             : /*
     800             :  * Send a single resultset containing just a single
     801             :  * XLogRecPtr record (in text format)
     802             :  */
     803             : static void
     804           0 : SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
     805             : {
     806             :     StringInfoData buf;
     807             :     char        str[MAXFNAMELEN];
     808             :     Size        len;
     809             : 
     810           0 :     pq_beginmessage(&buf, 'T'); /* RowDescription */
     811           0 :     pq_sendint(&buf, 2, 2);     /* 2 fields */
     812             : 
     813             :     /* Field headers */
     814           0 :     pq_sendstring(&buf, "recptr");
     815           0 :     pq_sendint(&buf, 0, 4);     /* table oid */
     816           0 :     pq_sendint(&buf, 0, 2);     /* attnum */
     817           0 :     pq_sendint(&buf, TEXTOID, 4);   /* type oid */
     818           0 :     pq_sendint(&buf, -1, 2);
     819           0 :     pq_sendint(&buf, 0, 4);
     820           0 :     pq_sendint(&buf, 0, 2);
     821             : 
     822           0 :     pq_sendstring(&buf, "tli");
     823           0 :     pq_sendint(&buf, 0, 4);     /* table oid */
     824           0 :     pq_sendint(&buf, 0, 2);     /* attnum */
     825             : 
     826             :     /*
     827             :      * int8 may seem like a surprising data type for this, but in theory int4
     828             :      * would not be wide enough for this, as TimeLineID is unsigned.
     829             :      */
     830           0 :     pq_sendint(&buf, INT8OID, 4);   /* type oid */
     831           0 :     pq_sendint(&buf, -1, 2);
     832           0 :     pq_sendint(&buf, 0, 4);
     833           0 :     pq_sendint(&buf, 0, 2);
     834           0 :     pq_endmessage(&buf);
     835             : 
     836             :     /* Data row */
     837           0 :     pq_beginmessage(&buf, 'D');
     838           0 :     pq_sendint(&buf, 2, 2);     /* number of columns */
     839             : 
     840           0 :     len = snprintf(str, sizeof(str),
     841           0 :                    "%X/%X", (uint32) (ptr >> 32), (uint32) ptr);
     842           0 :     pq_sendint(&buf, len, 4);
     843           0 :     pq_sendbytes(&buf, str, len);
     844             : 
     845           0 :     len = snprintf(str, sizeof(str), "%u", tli);
     846           0 :     pq_sendint(&buf, len, 4);
     847           0 :     pq_sendbytes(&buf, str, len);
     848             : 
     849           0 :     pq_endmessage(&buf);
     850             : 
     851             :     /* Send a CommandComplete message */
     852           0 :     pq_puttextmessage('C', "SELECT");
     853           0 : }
     854             : 
     855             : /*
     856             :  * Inject a file with given name and content in the output tar stream.
     857             :  */
     858             : static void
     859           0 : sendFileWithContent(const char *filename, const char *content)
     860             : {
     861             :     struct stat statbuf;
     862             :     int         pad,
     863             :                 len;
     864             : 
     865           0 :     len = strlen(content);
     866             : 
     867             :     /*
     868             :      * Construct a stat struct for the backup_label file we're injecting in
     869             :      * the tar.
     870             :      */
     871             :     /* Windows doesn't have the concept of uid and gid */
     872             : #ifdef WIN32
     873             :     statbuf.st_uid = 0;
     874             :     statbuf.st_gid = 0;
     875             : #else
     876           0 :     statbuf.st_uid = geteuid();
     877           0 :     statbuf.st_gid = getegid();
     878             : #endif
     879           0 :     statbuf.st_mtime = time(NULL);
     880           0 :     statbuf.st_mode = S_IRUSR | S_IWUSR;
     881           0 :     statbuf.st_size = len;
     882             : 
     883           0 :     _tarWriteHeader(filename, NULL, &statbuf, false);
     884             :     /* Send the contents as a CopyData message */
     885           0 :     pq_putmessage('d', content, len);
     886             : 
     887             :     /* Pad to 512 byte boundary, per tar format requirements */
     888           0 :     pad = ((len + 511) & ~511) - len;
     889           0 :     if (pad > 0)
     890             :     {
     891             :         char        buf[512];
     892             : 
     893           0 :         MemSet(buf, 0, pad);
     894           0 :         pq_putmessage('d', buf, pad);
     895             :     }
     896           0 : }
     897             : 
     898             : /*
     899             :  * Include the tablespace directory pointed to by 'path' in the output tar
     900             :  * stream.  If 'sizeonly' is true, we just calculate a total length and return
     901             :  * it, without actually sending anything.
     902             :  *
     903             :  * Only used to send auxiliary tablespaces, not PGDATA.
     904             :  */
     905             : int64
     906           0 : sendTablespace(char *path, bool sizeonly)
     907             : {
     908             :     int64       size;
     909             :     char        pathbuf[MAXPGPATH];
     910             :     struct stat statbuf;
     911             : 
     912             :     /*
     913             :      * 'path' points to the tablespace location, but we only want to include
     914             :      * the version directory in it that belongs to us.
     915             :      */
     916           0 :     snprintf(pathbuf, sizeof(pathbuf), "%s/%s", path,
     917             :              TABLESPACE_VERSION_DIRECTORY);
     918             : 
     919             :     /*
     920             :      * Store a directory entry in the tar file so we get the permissions
     921             :      * right.
     922             :      */
     923           0 :     if (lstat(pathbuf, &statbuf) != 0)
     924             :     {
     925           0 :         if (errno != ENOENT)
     926           0 :             ereport(ERROR,
     927             :                     (errcode_for_file_access(),
     928             :                      errmsg("could not stat file or directory \"%s\": %m",
     929             :                             pathbuf)));
     930             : 
     931             :         /* If the tablespace went away while scanning, it's no error. */
     932           0 :         return 0;
     933             :     }
     934             : 
     935           0 :     size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
     936             :                            sizeonly);
     937             : 
     938             :     /* Send all the files in the tablespace version directory */
     939           0 :     size += sendDir(pathbuf, strlen(path), sizeonly, NIL, true);
     940             : 
     941           0 :     return size;
     942             : }
     943             : 
     944             : /*
     945             :  * Include all files from the given directory in the output tar stream. If
     946             :  * 'sizeonly' is true, we just calculate a total length and return it, without
     947             :  * actually sending anything.
     948             :  *
     949             :  * Omit any directory in the tablespaces list, to avoid backing up
     950             :  * tablespaces twice when they were created inside PGDATA.
     951             :  *
     952             :  * If sendtblspclinks is true, we need to include symlink
     953             :  * information in the tar file. If not, we can skip that
     954             :  * as it will be sent separately in the tablespace_map file.
     955             :  */
     956             : static int64
     957           0 : sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces,
     958             :         bool sendtblspclinks)
     959             : {
     960             :     DIR        *dir;
     961             :     struct dirent *de;
     962             :     char        pathbuf[MAXPGPATH * 2];
     963             :     struct stat statbuf;
     964           0 :     int64       size = 0;
     965             : 
     966           0 :     dir = AllocateDir(path);
     967           0 :     while ((de = ReadDir(dir, path)) != NULL)
     968             :     {
     969             :         int         excludeIdx;
     970             :         bool        excludeFound;
     971             : 
     972             :         /* Skip special stuff */
     973           0 :         if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
     974           0 :             continue;
     975             : 
     976             :         /* Skip temporary files */
     977           0 :         if (strncmp(de->d_name,
     978             :                     PG_TEMP_FILE_PREFIX,
     979             :                     strlen(PG_TEMP_FILE_PREFIX)) == 0)
     980           0 :             continue;
     981             : 
     982             :         /*
     983             :          * Check if the postmaster has signaled us to exit, and abort with an
     984             :          * error in that case. The error handler further up will call
     985             :          * do_pg_abort_backup() for us. Also check that if the backup was
     986             :          * started while still in recovery, the server wasn't promoted.
     987             :          * dp_pg_stop_backup() will check that too, but it's better to stop
     988             :          * the backup early than continue to the end and fail there.
     989             :          */
     990           0 :         CHECK_FOR_INTERRUPTS();
     991           0 :         if (RecoveryInProgress() != backup_started_in_recovery)
     992           0 :             ereport(ERROR,
     993             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     994             :                      errmsg("the standby was promoted during online backup"),
     995             :                      errhint("This means that the backup being taken is corrupt "
     996             :                              "and should not be used. "
     997             :                              "Try taking another online backup.")));
     998             : 
     999             :         /* Scan for files that should be excluded */
    1000           0 :         excludeFound = false;
    1001           0 :         for (excludeIdx = 0; excludeFiles[excludeIdx] != NULL; excludeIdx++)
    1002             :         {
    1003           0 :             if (strcmp(de->d_name, excludeFiles[excludeIdx]) == 0)
    1004             :             {
    1005           0 :                 elog(DEBUG1, "file \"%s\" excluded from backup", de->d_name);
    1006           0 :                 excludeFound = true;
    1007           0 :                 break;
    1008             :             }
    1009             :         }
    1010             : 
    1011           0 :         if (excludeFound)
    1012           0 :             continue;
    1013             : 
    1014           0 :         snprintf(pathbuf, sizeof(pathbuf), "%s/%s", path, de->d_name);
    1015             : 
    1016             :         /* Skip pg_control here to back up it last */
    1017           0 :         if (strcmp(pathbuf, "./global/pg_control") == 0)
    1018           0 :             continue;
    1019             : 
    1020           0 :         if (lstat(pathbuf, &statbuf) != 0)
    1021             :         {
    1022           0 :             if (errno != ENOENT)
    1023           0 :                 ereport(ERROR,
    1024             :                         (errcode_for_file_access(),
    1025             :                          errmsg("could not stat file or directory \"%s\": %m",
    1026             :                                 pathbuf)));
    1027             : 
    1028             :             /* If the file went away while scanning, it's not an error. */
    1029           0 :             continue;
    1030             :         }
    1031             : 
    1032             :         /* Scan for directories whose contents should be excluded */
    1033           0 :         excludeFound = false;
    1034           0 :         for (excludeIdx = 0; excludeDirContents[excludeIdx] != NULL; excludeIdx++)
    1035             :         {
    1036           0 :             if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
    1037             :             {
    1038           0 :                 elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
    1039           0 :                 size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
    1040           0 :                 excludeFound = true;
    1041           0 :                 break;
    1042             :             }
    1043             :         }
    1044             : 
    1045           0 :         if (excludeFound)
    1046           0 :             continue;
    1047             : 
    1048             :         /*
    1049             :          * Exclude contents of directory specified by statrelpath if not set
    1050             :          * to the default (pg_stat_tmp) which is caught in the loop above.
    1051             :          */
    1052           0 :         if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
    1053             :         {
    1054           0 :             elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
    1055           0 :             size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
    1056           0 :             continue;
    1057             :         }
    1058             : 
    1059             :         /*
    1060             :          * We can skip pg_wal, the WAL segments need to be fetched from the
    1061             :          * WAL archive anyway. But include it as an empty directory anyway, so
    1062             :          * we get permissions right.
    1063             :          */
    1064           0 :         if (strcmp(pathbuf, "./pg_wal") == 0)
    1065             :         {
    1066             :             /* If pg_wal is a symlink, write it as a directory anyway */
    1067           0 :             size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
    1068             : 
    1069             :             /*
    1070             :              * Also send archive_status directory (by hackishly reusing
    1071             :              * statbuf from above ...).
    1072             :              */
    1073           0 :             size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
    1074             :                                     sizeonly);
    1075             : 
    1076           0 :             continue;           /* don't recurse into pg_wal */
    1077             :         }
    1078             : 
    1079             :         /* Allow symbolic links in pg_tblspc only */
    1080           0 :         if (strcmp(path, "./pg_tblspc") == 0 &&
    1081             : #ifndef WIN32
    1082           0 :             S_ISLNK(statbuf.st_mode)
    1083             : #else
    1084             :             pgwin32_is_junction(pathbuf)
    1085             : #endif
    1086             :             )
    1087           0 :         {
    1088             : #if defined(HAVE_READLINK) || defined(WIN32)
    1089             :             char        linkpath[MAXPGPATH];
    1090             :             int         rllen;
    1091             : 
    1092           0 :             rllen = readlink(pathbuf, linkpath, sizeof(linkpath));
    1093           0 :             if (rllen < 0)
    1094           0 :                 ereport(ERROR,
    1095             :                         (errcode_for_file_access(),
    1096             :                          errmsg("could not read symbolic link \"%s\": %m",
    1097             :                                 pathbuf)));
    1098           0 :             if (rllen >= sizeof(linkpath))
    1099           0 :                 ereport(ERROR,
    1100             :                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1101             :                          errmsg("symbolic link \"%s\" target is too long",
    1102             :                                 pathbuf)));
    1103           0 :             linkpath[rllen] = '\0';
    1104             : 
    1105           0 :             size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
    1106             :                                     &statbuf, sizeonly);
    1107             : #else
    1108             : 
    1109             :             /*
    1110             :              * If the platform does not have symbolic links, it should not be
    1111             :              * possible to have tablespaces - clearly somebody else created
    1112             :              * them. Warn about it and ignore.
    1113             :              */
    1114             :             ereport(WARNING,
    1115             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1116             :                      errmsg("tablespaces are not supported on this platform")));
    1117             :             continue;
    1118             : #endif                          /* HAVE_READLINK */
    1119             :         }
    1120           0 :         else if (S_ISDIR(statbuf.st_mode))
    1121             :         {
    1122           0 :             bool        skip_this_dir = false;
    1123             :             ListCell   *lc;
    1124             : 
    1125             :             /*
    1126             :              * Store a directory entry in the tar file so we can get the
    1127             :              * permissions right.
    1128             :              */
    1129           0 :             size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
    1130             :                                     sizeonly);
    1131             : 
    1132             :             /*
    1133             :              * Call ourselves recursively for a directory, unless it happens
    1134             :              * to be a separate tablespace located within PGDATA.
    1135             :              */
    1136           0 :             foreach(lc, tablespaces)
    1137             :             {
    1138           0 :                 tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
    1139             : 
    1140             :                 /*
    1141             :                  * ti->rpath is the tablespace relative path within PGDATA, or
    1142             :                  * NULL if the tablespace has been properly located somewhere
    1143             :                  * else.
    1144             :                  *
    1145             :                  * Skip past the leading "./" in pathbuf when comparing.
    1146             :                  */
    1147           0 :                 if (ti->rpath && strcmp(ti->rpath, pathbuf + 2) == 0)
    1148             :                 {
    1149           0 :                     skip_this_dir = true;
    1150           0 :                     break;
    1151             :                 }
    1152             :             }
    1153             : 
    1154             :             /*
    1155             :              * skip sending directories inside pg_tblspc, if not required.
    1156             :              */
    1157           0 :             if (strcmp(pathbuf, "./pg_tblspc") == 0 && !sendtblspclinks)
    1158           0 :                 skip_this_dir = true;
    1159             : 
    1160           0 :             if (!skip_this_dir)
    1161           0 :                 size += sendDir(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks);
    1162             :         }
    1163           0 :         else if (S_ISREG(statbuf.st_mode))
    1164             :         {
    1165           0 :             bool        sent = false;
    1166             : 
    1167           0 :             if (!sizeonly)
    1168           0 :                 sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
    1169             :                                 true);
    1170             : 
    1171           0 :             if (sent || sizeonly)
    1172             :             {
    1173             :                 /* Add size, rounded up to 512byte block */
    1174           0 :                 size += ((statbuf.st_size + 511) & ~511);
    1175           0 :                 size += 512;    /* Size of the header of the file */
    1176             :             }
    1177             :         }
    1178             :         else
    1179           0 :             ereport(WARNING,
    1180             :                     (errmsg("skipping special file \"%s\"", pathbuf)));
    1181             :     }
    1182           0 :     FreeDir(dir);
    1183           0 :     return size;
    1184             : }
    1185             : 
    1186             : /*****
    1187             :  * Functions for handling tar file format
    1188             :  *
    1189             :  * Copied from pg_dump, but modified to work with libpq for sending
    1190             :  */
    1191             : 
    1192             : 
    1193             : /*
    1194             :  * Given the member, write the TAR header & send the file.
    1195             :  *
    1196             :  * If 'missing_ok' is true, will not throw an error if the file is not found.
    1197             :  *
    1198             :  * Returns true if the file was successfully sent, false if 'missing_ok',
    1199             :  * and the file did not exist.
    1200             :  */
    1201             : static bool
    1202           0 : sendFile(char *readfilename, char *tarfilename, struct stat *statbuf,
    1203             :          bool missing_ok)
    1204             : {
    1205             :     FILE       *fp;
    1206             :     char        buf[TAR_SEND_SIZE];
    1207             :     size_t      cnt;
    1208           0 :     pgoff_t     len = 0;
    1209             :     size_t      pad;
    1210             : 
    1211           0 :     fp = AllocateFile(readfilename, "rb");
    1212           0 :     if (fp == NULL)
    1213             :     {
    1214           0 :         if (errno == ENOENT && missing_ok)
    1215           0 :             return false;
    1216           0 :         ereport(ERROR,
    1217             :                 (errcode_for_file_access(),
    1218             :                  errmsg("could not open file \"%s\": %m", readfilename)));
    1219             :     }
    1220             : 
    1221           0 :     _tarWriteHeader(tarfilename, NULL, statbuf, false);
    1222             : 
    1223           0 :     while ((cnt = fread(buf, 1, Min(sizeof(buf), statbuf->st_size - len), fp)) > 0)
    1224             :     {
    1225             :         /* Send the chunk as a CopyData message */
    1226           0 :         if (pq_putmessage('d', buf, cnt))
    1227           0 :             ereport(ERROR,
    1228             :                     (errmsg("base backup could not send data, aborting backup")));
    1229             : 
    1230           0 :         len += cnt;
    1231           0 :         throttle(cnt);
    1232             : 
    1233           0 :         if (len >= statbuf->st_size)
    1234             :         {
    1235             :             /*
    1236             :              * Reached end of file. The file could be longer, if it was
    1237             :              * extended while we were sending it, but for a base backup we can
    1238             :              * ignore such extended data. It will be restored from WAL.
    1239             :              */
    1240           0 :             break;
    1241             :         }
    1242             :     }
    1243             : 
    1244             :     /* If the file was truncated while we were sending it, pad it with zeros */
    1245           0 :     if (len < statbuf->st_size)
    1246             :     {
    1247           0 :         MemSet(buf, 0, sizeof(buf));
    1248           0 :         while (len < statbuf->st_size)
    1249             :         {
    1250           0 :             cnt = Min(sizeof(buf), statbuf->st_size - len);
    1251           0 :             pq_putmessage('d', buf, cnt);
    1252           0 :             len += cnt;
    1253           0 :             throttle(cnt);
    1254             :         }
    1255             :     }
    1256             : 
    1257             :     /*
    1258             :      * Pad to 512 byte boundary, per tar format requirements. (This small
    1259             :      * piece of data is probably not worth throttling.)
    1260             :      */
    1261           0 :     pad = ((len + 511) & ~511) - len;
    1262           0 :     if (pad > 0)
    1263             :     {
    1264           0 :         MemSet(buf, 0, pad);
    1265           0 :         pq_putmessage('d', buf, pad);
    1266             :     }
    1267             : 
    1268           0 :     FreeFile(fp);
    1269             : 
    1270           0 :     return true;
    1271             : }
    1272             : 
    1273             : 
    1274             : static int64
    1275           0 : _tarWriteHeader(const char *filename, const char *linktarget,
    1276             :                 struct stat *statbuf, bool sizeonly)
    1277             : {
    1278             :     char        h[512];
    1279             :     enum tarError rc;
    1280             : 
    1281           0 :     if (!sizeonly)
    1282             :     {
    1283           0 :         rc = tarCreateHeader(h, filename, linktarget, statbuf->st_size,
    1284             :                              statbuf->st_mode, statbuf->st_uid, statbuf->st_gid,
    1285             :                              statbuf->st_mtime);
    1286             : 
    1287           0 :         switch (rc)
    1288             :         {
    1289             :             case TAR_OK:
    1290           0 :                 break;
    1291             :             case TAR_NAME_TOO_LONG:
    1292           0 :                 ereport(ERROR,
    1293             :                         (errmsg("file name too long for tar format: \"%s\"",
    1294             :                                 filename)));
    1295             :                 break;
    1296             :             case TAR_SYMLINK_TOO_LONG:
    1297           0 :                 ereport(ERROR,
    1298             :                         (errmsg("symbolic link target too long for tar format: "
    1299             :                                 "file name \"%s\", target \"%s\"",
    1300             :                                 filename, linktarget)));
    1301             :                 break;
    1302             :             default:
    1303           0 :                 elog(ERROR, "unrecognized tar error: %d", rc);
    1304             :         }
    1305             : 
    1306           0 :         pq_putmessage('d', h, sizeof(h));
    1307             :     }
    1308             : 
    1309           0 :     return sizeof(h);
    1310             : }
    1311             : 
    1312             : /*
    1313             :  * Write tar header for a directory.  If the entry in statbuf is a link then
    1314             :  * write it as a directory anyway.
    1315             :  */
    1316             : static int64
    1317           0 : _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
    1318             :              bool sizeonly)
    1319             : {
    1320             :     /* If symlink, write it as a directory anyway */
    1321             : #ifndef WIN32
    1322           0 :     if (S_ISLNK(statbuf->st_mode))
    1323             : #else
    1324             :     if (pgwin32_is_junction(pathbuf))
    1325             : #endif
    1326           0 :         statbuf->st_mode = S_IFDIR | S_IRWXU;
    1327             : 
    1328           0 :     return _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf, sizeonly);
    1329             : }
    1330             : 
    1331             : /*
    1332             :  * Increment the network transfer counter by the given number of bytes,
    1333             :  * and sleep if necessary to comply with the requested network transfer
    1334             :  * rate.
    1335             :  */
    1336             : static void
    1337           0 : throttle(size_t increment)
    1338             : {
    1339             :     TimeOffset  elapsed,
    1340             :                 elapsed_min,
    1341             :                 sleep;
    1342             :     int         wait_result;
    1343             : 
    1344           0 :     if (throttling_counter < 0)
    1345           0 :         return;
    1346             : 
    1347           0 :     throttling_counter += increment;
    1348           0 :     if (throttling_counter < throttling_sample)
    1349           0 :         return;
    1350             : 
    1351             :     /* Time elapsed since the last measurement (and possible wake up). */
    1352           0 :     elapsed = GetCurrentTimestamp() - throttled_last;
    1353             :     /* How much should have elapsed at minimum? */
    1354           0 :     elapsed_min = elapsed_min_unit * (throttling_counter / throttling_sample);
    1355           0 :     sleep = elapsed_min - elapsed;
    1356             :     /* Only sleep if the transfer is faster than it should be. */
    1357           0 :     if (sleep > 0)
    1358             :     {
    1359           0 :         ResetLatch(MyLatch);
    1360             : 
    1361             :         /* We're eating a potentially set latch, so check for interrupts */
    1362           0 :         CHECK_FOR_INTERRUPTS();
    1363             : 
    1364             :         /*
    1365             :          * (TAR_SEND_SIZE / throttling_sample * elapsed_min_unit) should be
    1366             :          * the maximum time to sleep. Thus the cast to long is safe.
    1367             :          */
    1368           0 :         wait_result = WaitLatch(MyLatch,
    1369             :                                 WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
    1370           0 :                                 (long) (sleep / 1000),
    1371             :                                 WAIT_EVENT_BASE_BACKUP_THROTTLE);
    1372             : 
    1373           0 :         if (wait_result & WL_LATCH_SET)
    1374           0 :             CHECK_FOR_INTERRUPTS();
    1375             :     }
    1376             : 
    1377             :     /*
    1378             :      * As we work with integers, only whole multiple of throttling_sample was
    1379             :      * processed. The rest will be done during the next call of this function.
    1380             :      */
    1381           0 :     throttling_counter %= throttling_sample;
    1382             : 
    1383             :     /*
    1384             :      * Time interval for the remaining amount and possible next increments
    1385             :      * starts now.
    1386             :      */
    1387           0 :     throttled_last = GetCurrentTimestamp();
    1388             : }

Generated by: LCOV version 1.11