On 9/12/16 2:50 PM, Peter Eisentraut wrote:
> The comments on excludeDirContents are somewhat imprecise.  For
> example, none of those directories are actually removed or recreated
> on startup, only the contents are.

Fixed.

> The comment for pg_replslot is incorrect.  I think you can copy
> replication slots just fine, but you usually don't want to.

Fixed.

> What is the 2 for in this code?
> 
>     if (strcmp(pathbuf + 2, excludeFile[excludeIdx]) == 0)

This should be basepathlen + 1 (i.e., $PGDATA/).  Fixed.

> I would keep the signature of _tarWriteDir() similar to
> _tarWriteHeader().  So don't pass sizeonly in there, or do pass in
> sizeonly but do the same with _tarWriteHeader().

I'm not sure how much more similar they can be, but I do agree that
sizeonly logic should be wrapped in _tarWriteHeader().  Done.

> The documentation in pg_basebackup.sgml and protocol.sgml should be
> updated.

Done.  I moved a few things to the protocol docs to avoid repetition.

> Add some tests.  At least test that one entry from the directory list
> and one entry from the files list is not contained in the backup
> result.

Done for all files and directories.

> Testing the symlink handling would also be good.

Done using pg_replslot for the test.

> (The
> pg_basebackup tests claim that Windows doesn't support symlinks and
> therefore skip all the symlink tests.  That seems a bit at odds with
> your code handling symlinks on Windows.)

Hopefully Michael's response down-thread answered your question.

-- 
-David
da...@pgmasters.net
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 0f09d82..a8daa07 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -1090,6 +1090,22 @@ SELECT pg_stop_backup();
    </para>
 
    <para>
+    The contents of the <filename>pg_dynshmem/</>, <filename>pg_stat_tmp/</>,
+    <filename>pg_notify/</>, <filename>pg_serial/</>,
+    <filename>pg_snapshots/</>, and <filename>pg_subtrans/</> directories can
+    be omitted from the backup as they will be initialized on postmaster
+    startup. If the <xref linkend="GUC-STATS-TEMP-DIRECTORY"> is set and is
+    under the database cluster directory then the contents of the directory
+    specified by <xref linkend="GUC-STATS-TEMP-DIRECTORY"> can also be omitted.
+   </para>
+
+   <para>
+    Any file or directory beginning with <filename>pgsql_tmp</filename> can be
+    omitted from the backup.  These files are removed on postmaster start and
+    the directories will be recreated as needed.
+   </para>
+
+   <para>
     The backup label
     file includes the label string you gave to <function>pg_start_backup</>,
     as well as the time at which <function>pg_start_backup</> was run, and
diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index 68b0941..d65687f 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -2059,17 +2059,26 @@ The commands accepted in walsender mode are:
       <itemizedlist spacing="compact" mark="bullet">
        <listitem>
         <para>
-         <filename>postmaster.pid</>
+         <filename>postmaster.pid</> and <filename>postmaster.opts</>
         </para>
        </listitem>
        <listitem>
         <para>
-         <filename>postmaster.opts</>
+         <filename>postgresql.auto.conf.tmp</>
         </para>
        </listitem>
        <listitem>
         <para>
-         various temporary files created during the operation of the 
PostgreSQL server
+         <filename>backup_label</> and <filename>tablespace_map</>.  If these
+         files exist they belong to an exclusive backup and are not applicable
+         to the base backup.
+        </para>
+       </listitem>
+       <listitem>
+        <para>
+         Various temporary files and directories created during the operation 
of
+         the PostgreSQL server, i.e. any file or directory beginning with
+         <filename>pgsql_tmp</>.
         </para>
        </listitem>
        <listitem>
@@ -2082,7 +2091,11 @@ The commands accepted in walsender mode are:
        </listitem>
        <listitem>
         <para>
-         <filename>pg_replslot</> is copied as an empty directory.
+         <filename>pg_replslot</>, <filename>pg_dynshmem</>,
+         <filename>pg_stat_tmp</>, <filename>pg_notify</>,
+         <filename>pg_serial</>, <filename>pg_snapshots</>, and
+         <filename>pg_subtrans</> are copied as empty directories (even if they
+         are symbolic links).
         </para>
        </listitem>
        <listitem>
diff --git a/doc/src/sgml/ref/pg_basebackup.sgml 
b/doc/src/sgml/ref/pg_basebackup.sgml
index 9f1eae1..984ea5b 100644
--- a/doc/src/sgml/ref/pg_basebackup.sgml
+++ b/doc/src/sgml/ref/pg_basebackup.sgml
@@ -610,10 +610,8 @@ PostgreSQL documentation
   <para>
    The backup will include all files in the data directory and tablespaces,
    including the configuration files and any additional files placed in the
-   directory by third parties. But only regular files and directories are
-   copied.  Symbolic links (other than those used for tablespaces) and special
-   device files are skipped.  (See <xref linkend="protocol-replication"> for
-   the precise details.)
+   directory by third parties, with certain exceptions.  (See
+   <xref linkend="protocol-replication"> for the complete list of exceptions.)
   </para>
 
   <para>
diff --git a/src/backend/replication/basebackup.c 
b/src/backend/replication/basebackup.c
index da9b7a6..04909ef 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -30,6 +30,7 @@
 #include "replication/basebackup.h"
 #include "replication/walsender.h"
 #include "replication/walsender_private.h"
+#include "storage/dsm_impl.h"
 #include "storage/fd.h"
 #include "storage/ipc.h"
 #include "utils/builtins.h"
@@ -55,8 +56,10 @@ static int64 sendDir(char *path, int basepathlen, bool 
sizeonly,
 static bool sendFile(char *readfilename, char *tarfilename,
                 struct stat * statbuf, bool missing_ok);
 static void sendFileWithContent(const char *filename, const char *content);
-static void _tarWriteHeader(const char *filename, const char *linktarget,
-                               struct stat * statbuf);
+static int64 _tarWriteHeader(const char *filename, const char *linktarget,
+                               struct stat * statbuf, bool sizeonly);
+static int64 _tarWriteDir(char *pathbuf, int basepathlen, struct stat *statbuf,
+                               bool sizeonly);
 static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
 static void base_backup_cleanup(int code, Datum arg);
@@ -95,6 +98,74 @@ static int64 elapsed_min_unit;
 static int64 throttled_last;
 
 /*
+ * The contents of these directories are removed or recreated during server
+ * start so they will not be included in the backup.  The directory entry
+ * will be included to preserve permissions.
+ */
+const char *excludeDirContents[] =
+{
+       /*
+        * Skip temporary statistics files. PG_STAT_TMP_DIR must be skipped even
+        * when stats_temp_directory is set because PGSS_TEXT_FILE is always 
created
+        * there.
+        */
+       PG_STAT_TMP_DIR,
+
+       /*
+        * It is generally not useful to backup the contents of this directory 
even
+        * if the intention is to restore to another master. See backup.sgml 
for a
+        * more detailed description.
+        */
+       "pg_replslot",
+
+       /* Contents removed on startup, see dsm_cleanup_for_mmap(). */
+       PG_DYNSHMEM_DIR,
+
+       /* Contents removed on startup, see AsyncShmemInit(). */
+       "pg_notify",
+
+       /*
+        * Old contents are loaded for possible debugging but are not required 
for
+        * normal operation, see OldSerXidInit().
+        */
+       "pg_serial",
+
+       /* Contents removed on startup, see DeleteAllExportedSnapshotFiles(). */
+       "pg_snapshots",
+
+       /* Contents zeroed on startup, see StartupSUBTRANS(). */
+       "pg_subtrans",
+
+       /* Terminate list. */
+       NULL
+};
+
+/*
+ * Files that should not be included in the backup.
+ */
+const char *excludeFile[] =
+{
+       /* Skip auto conf temporary file. */
+       PG_AUTOCONF_FILENAME ".tmp",
+
+       /*
+        * If there's a backup_label or tablespace_map file, it belongs to a 
backup
+        * started by the user with pg_start_backup(). It is *not* correct for 
this
+        * backup, our backup_label/tablespace_map is injected into the tar
+        * separately.
+        */
+       BACKUP_LABEL_FILE,
+       TABLESPACE_MAP,
+
+       /* Skip postmaster.pid and postmaster.opts. */
+       "postmaster.pid",
+       "postmaster.opts",
+
+       /* Terminate list. */
+       NULL
+};
+
+/*
  * Called when ERROR or FATAL happens in perform_base_backup() after
  * we have started the backup - make sure we end it!
  */
@@ -415,7 +486,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
                        }
 
                        /* send the WAL file itself */
-                       _tarWriteHeader(pathbuf, NULL, &statbuf);
+                       _tarWriteHeader(pathbuf, NULL, &statbuf, false);
 
                        while ((cnt = fread(buf, 1, Min(sizeof(buf), 
XLogSegSize - len), fp)) > 0)
                        {
@@ -807,7 +878,7 @@ sendFileWithContent(const char *filename, const char 
*content)
        statbuf.st_mode = S_IRUSR | S_IWUSR;
        statbuf.st_size = len;
 
-       _tarWriteHeader(filename, NULL, &statbuf);
+       _tarWriteHeader(filename, NULL, &statbuf, false);
        /* Send the contents as a CopyData message */
        pq_putmessage('d', content, len);
 
@@ -858,9 +929,9 @@ sendTablespace(char *path, bool sizeonly)
                /* If the tablespace went away while scanning, it's no error. */
                return 0;
        }
-       if (!sizeonly)
-               _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf);
-       size = 512;                                     /* Size of the header 
just added */
+
+       size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
+                                                  sizeonly);
 
        /* Send all the files in the tablespace version directory */
        size += sendDir(pathbuf, strlen(path), sizeonly, NIL, true);
@@ -889,6 +960,8 @@ sendDir(char *path, int basepathlen, bool sizeonly, List 
*tablespaces,
        char            pathbuf[MAXPGPATH];
        struct stat statbuf;
        int64           size = 0;
+       int             excludeIdx;
+       bool            excludeFound;
 
        dir = AllocateDir(path);
        while ((de = ReadDir(dir, path)) != NULL)
@@ -903,22 +976,89 @@ sendDir(char *path, int basepathlen, bool sizeonly, List 
*tablespaces,
                                        strlen(PG_TEMP_FILE_PREFIX)) == 0)
                        continue;
 
-               /* skip auto conf temporary file */
-               if (strncmp(de->d_name,
-                                       PG_AUTOCONF_FILENAME ".tmp",
-                                       sizeof(PG_AUTOCONF_FILENAME) + 4) == 0)
+               /* Stat the file */
+               snprintf(pathbuf, MAXPGPATH, "%s/%s", path, de->d_name);
+
+               if (lstat(pathbuf, &statbuf) != 0)
+               {
+                       if (errno != ENOENT)
+                               ereport(ERROR,
+                                               (errcode_for_file_access(),
+                                                errmsg("could not stat file or 
directory \"%s\": %m",
+                                                               pathbuf)));
+
+                       /* If the file went away while scanning, it's not an 
error. */
                        continue;
+               }
 
                /*
-                * If there's a backup_label or tablespace_map file, it belongs 
to a
-                * backup started by the user with pg_start_backup(). It is 
*not*
-                * correct for this backup, our backup_label/tablespace_map is
-                * injected into the tar separately.
+                * Scan for files that should be excluded. See excludeFile[] 
for info
+                * on exclusions.
                 */
-               if (strcmp(de->d_name, BACKUP_LABEL_FILE) == 0)
-                       continue;
+               excludeFound = false;
+               excludeIdx = 0;
+
+               while (excludeFile[excludeIdx] != NULL)
+               {
+                       if (strcmp(pathbuf + basepathlen + 1, 
excludeFile[excludeIdx]) == 0)
+                       {
+                               ereport(DEBUG1,
+                                               (errmsg("file excluded from 
backup: %s",
+                                                       
excludeFile[excludeIdx])));
+
+                               excludeFound = true;
+                               break;
+                       }
+
+                       excludeIdx++;
+               }
+
+               /*
+                * Scan for directories whose contents should be excluded.  See
+                * excludeDirContents[] for info on exclusions.
+                */
+               if (!excludeFound)
+               {
+                       excludeIdx = 0;
+
+                       while (excludeDirContents[excludeIdx] != NULL)
+                       {
+                               if (strcmp(pathbuf + basepathlen + 1,
+                                               excludeDirContents[excludeIdx]) 
== 0)
+                               {
+                                       ereport(DEBUG1,
+                                               (errmsg("directory contents 
excluded from backup: %s",
+                                                       
excludeDirContents[excludeIdx])));
+
+                                       size += _tarWriteDir(pathbuf, 
basepathlen, &statbuf,
+                                                                               
 sizeonly);
+
+                                       excludeFound = true;
+                                       break;
+                               }
+
+                               excludeIdx++;
+                       }
+               }
+
+               /*
+                * Exclude contents of directory specified by statrelpath if 
not set
+                * to the default (pg_stat_tmp) which is caught in the loop 
above.
+                */
+               if (!excludeFound && statrelpath != NULL &&
+                       strcmp(pathbuf, statrelpath) == 0)
+               {
+                       ereport(DEBUG1,
+                               (errmsg("stats_temp_directory contents excluded 
from backup: %s",
+                                       statrelpath)));
+
+                       size += _tarWriteDir(pathbuf, basepathlen, &statbuf, 
sizeonly);
 
-               if (strcmp(de->d_name, TABLESPACE_MAP) == 0)
+                       excludeFound = true;
+               }
+
+               /* If file matched exclusion, continue. */
+               if (excludeFound)
                        continue;
 
                /*
@@ -938,55 +1078,10 @@ sendDir(char *path, int basepathlen, bool sizeonly, List 
*tablespaces,
                                                 "and should not be used. "
                                                 "Try taking another online 
backup.")));
 
-               snprintf(pathbuf, MAXPGPATH, "%s/%s", path, de->d_name);
-
-               /* Skip postmaster.pid and postmaster.opts in the data 
directory */
-               if (strcmp(pathbuf, "./postmaster.pid") == 0 ||
-                       strcmp(pathbuf, "./postmaster.opts") == 0)
-                       continue;
-
                /* Skip pg_control here to back up it last */
                if (strcmp(pathbuf, "./global/pg_control") == 0)
                        continue;
 
-               if (lstat(pathbuf, &statbuf) != 0)
-               {
-                       if (errno != ENOENT)
-                               ereport(ERROR,
-                                               (errcode_for_file_access(),
-                                                errmsg("could not stat file or 
directory \"%s\": %m",
-                                                               pathbuf)));
-
-                       /* If the file went away while scanning, it's no error. 
*/
-                       continue;
-               }
-
-               /*
-                * Skip temporary statistics files. PG_STAT_TMP_DIR must be 
skipped
-                * even when stats_temp_directory is set because PGSS_TEXT_FILE 
is
-                * always created there.
-                */
-               if ((statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0) 
||
-                 strncmp(de->d_name, PG_STAT_TMP_DIR, strlen(PG_STAT_TMP_DIR)) 
== 0)
-               {
-                       if (!sizeonly)
-                               _tarWriteHeader(pathbuf + basepathlen + 1, 
NULL, &statbuf);
-                       size += 512;
-                       continue;
-               }
-
-               /*
-                * Skip pg_replslot, not useful to copy. But include it as an 
empty
-                * directory anyway, so we get permissions right.
-                */
-               if (strcmp(de->d_name, "pg_replslot") == 0)
-               {
-                       if (!sizeonly)
-                               _tarWriteHeader(pathbuf + basepathlen + 1, 
NULL, &statbuf);
-                       size += 512;            /* Size of the header just 
added */
-                       continue;
-               }
-
                /*
                 * We can skip pg_xlog, the WAL segments need to be fetched 
from the
                 * WAL archive anyway. But include it as an empty directory 
anyway, so
@@ -994,26 +1089,15 @@ sendDir(char *path, int basepathlen, bool sizeonly, List 
*tablespaces,
                 */
                if (strcmp(pathbuf, "./pg_xlog") == 0)
                {
-                       if (!sizeonly)
-                       {
-                               /* If pg_xlog is a symlink, write it as a 
directory anyway */
-#ifndef WIN32
-                               if (S_ISLNK(statbuf.st_mode))
-#else
-                               if (pgwin32_is_junction(pathbuf))
-#endif
-                                       statbuf.st_mode = S_IFDIR | S_IRWXU;
-                               _tarWriteHeader(pathbuf + basepathlen + 1, 
NULL, &statbuf);
-                       }
-                       size += 512;            /* Size of the header just 
added */
+                       /* If pg_xlog is a symlink, write it as a directory 
anyway */
+                       size += _tarWriteDir(pathbuf, basepathlen, &statbuf, 
sizeonly);
 
                        /*
                         * Also send archive_status directory (by hackishly 
reusing
                         * statbuf from above ...).
                         */
-                       if (!sizeonly)
-                               _tarWriteHeader("./pg_xlog/archive_status", 
NULL, &statbuf);
-                       size += 512;            /* Size of the header just 
added */
+                       size += _tarWriteHeader("./pg_xlog/archive_status", 
NULL, &statbuf,
+                                                                       
sizeonly);
 
                        continue;                       /* don't recurse into 
pg_xlog */
                }
@@ -1044,9 +1128,8 @@ sendDir(char *path, int basepathlen, bool sizeonly, List 
*tablespaces,
                                                                pathbuf)));
                        linkpath[rllen] = '\0';
 
-                       if (!sizeonly)
-                               _tarWriteHeader(pathbuf + basepathlen + 1, 
linkpath, &statbuf);
-                       size += 512;            /* Size of the header just 
added */
+                       size += _tarWriteHeader(pathbuf + basepathlen + 1, 
linkpath,
+                                                                       
&statbuf, sizeonly);
 #else
 
                        /*
@@ -1069,9 +1152,8 @@ sendDir(char *path, int basepathlen, bool sizeonly, List 
*tablespaces,
                         * Store a directory entry in the tar file so we can 
get the
                         * permissions right.
                         */
-                       if (!sizeonly)
-                               _tarWriteHeader(pathbuf + basepathlen + 1, 
NULL, &statbuf);
-                       size += 512;            /* Size of the header just 
added */
+                       size += _tarWriteHeader(pathbuf + basepathlen + 1, 
NULL, &statbuf,
+                                                                       
sizeonly);
 
                        /*
                         * Call ourselves recursively for a directory, unless 
it happens
@@ -1162,7 +1244,7 @@ sendFile(char *readfilename, char *tarfilename, struct 
stat * statbuf,
                                 errmsg("could not open file \"%s\": %m", 
readfilename)));
        }
 
-       _tarWriteHeader(tarfilename, NULL, statbuf);
+       _tarWriteHeader(tarfilename, NULL, statbuf, false);
 
        while ((cnt = fread(buf, 1, Min(sizeof(buf), statbuf->st_size - len), 
fp)) > 0)
        {
@@ -1215,36 +1297,62 @@ sendFile(char *readfilename, char *tarfilename, struct 
stat * statbuf,
 }
 
 
-static void
+static int64
 _tarWriteHeader(const char *filename, const char *linktarget,
-                               struct stat * statbuf)
+                               struct stat * statbuf, bool sizeonly)
 {
        char            h[512];
        enum tarError rc;
 
-       rc = tarCreateHeader(h, filename, linktarget, statbuf->st_size,
-                                                statbuf->st_mode, 
statbuf->st_uid, statbuf->st_gid,
-                                                statbuf->st_mtime);
-
-       switch (rc)
+       if (!sizeonly)
        {
-               case TAR_OK:
-                       break;
-               case TAR_NAME_TOO_LONG:
-                       ereport(ERROR,
-                                       (errmsg("file name too long for tar 
format: \"%s\"",
-                                                       filename)));
-                       break;
-               case TAR_SYMLINK_TOO_LONG:
-                       ereport(ERROR,
-                                       (errmsg("symbolic link target too long 
for tar format: file name \"%s\", target \"%s\"",
-                                                       filename, linktarget)));
-                       break;
-               default:
-                       elog(ERROR, "unrecognized tar error: %d", rc);
+               rc = tarCreateHeader(h, filename, linktarget, statbuf->st_size,
+                                                        statbuf->st_mode, 
statbuf->st_uid, statbuf->st_gid,
+                                                        statbuf->st_mtime);
+
+               switch (rc)
+               {
+                       case TAR_OK:
+                               break;
+                       case TAR_NAME_TOO_LONG:
+                               ereport(ERROR,
+                                               (errmsg("file name too long for 
tar format: \"%s\"",
+                                                               filename)));
+                               break;
+                       case TAR_SYMLINK_TOO_LONG:
+                               ereport(ERROR,
+                                               (errmsg("symbolic link target 
too long for tar format: "
+                                                               "file name 
\"%s\", target \"%s\"",
+                                                               filename, 
linktarget)));
+                               break;
+                       default:
+                               elog(ERROR, "unrecognized tar error: %d", rc);
+               }
+
+               pq_putmessage('d', h, sizeof(h));
        }
 
-       pq_putmessage('d', h, 512);
+       return sizeof(h);
+}
+
+/*
+ * Write tar header for a directory.  If the entry in statbuf is a link then
+ * write it as a directory anyway.
+ */
+static int64
+_tarWriteDir(char *pathbuf, int basepathlen, struct stat *statbuf,
+                        bool sizeonly)
+{
+       /* If symlink, write it as a directory anyway */
+#ifndef WIN32
+       if (S_ISLNK(statbuf->st_mode))
+#else
+       if (pgwin32_is_junction(pathbuf))
+#endif
+
+       statbuf->st_mode = S_IFDIR | S_IRWXU;
+
+       return _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf, 
sizeonly);
 }
 
 /*
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl 
b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
index fd9857d..714d84b 100644
--- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl
+++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
@@ -4,7 +4,7 @@ use Cwd;
 use Config;
 use PostgresNode;
 use TestLib;
-use Test::More tests => 54;
+use Test::More tests => 69;
 
 program_help_ok('pg_basebackup');
 program_version_ok('pg_basebackup');
@@ -48,22 +48,95 @@ $node->command_fails(
 
 ok(-d "$tempdir/backup", 'backup directory was created and left behind');
 
+$node->stop;
+
 open CONF, ">>$pgdata/postgresql.conf";
 print CONF "max_replication_slots = 10\n";
 print CONF "max_wal_senders = 10\n";
 print CONF "wal_level = replica\n";
 close CONF;
-$node->restart;
+
+# Move pg_replslot out of $pgdata and create a symlink to it
+rename("$pgdata/pg_replslot", "$tempdir/pg_replslot")
+       or die "unable to move $pgdata/pg_replslot";
+symlink("$tempdir/pg_replslot", "$pgdata/pg_replslot");
+
+$node->start;
+
+# Write backup_label to be sure it is not copied
+open BACKUP_LABEL, ">>$pgdata/backup_label";
+print BACKUP_LABEL "DONOTCOPY";
+close BACKUP_LABEL;
+
+# Write tablespace_map to be sure it is not copied
+open BACKUP_LABEL, ">>$pgdata/tablespace_map";
+print BACKUP_LABEL "DONOTCOPY";
+close BACKUP_LABEL;
+
+# Write postgresql.auto.conf.tmp to be sure it is not copied
+open BACKUP_LABEL, ">>$pgdata/postgresql.auto.conf.tmp";
+print BACKUP_LABEL "DONOTCOPY";
+close BACKUP_LABEL;
 
 $node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backup" ],
        'pg_basebackup runs');
 ok(-f "$tempdir/backup/PG_VERSION", 'backup was created');
 
+# Only archive_status directory should be copied in pg_xlog/
 is_deeply(
        [ sort(slurp_dir("$tempdir/backup/pg_xlog/")) ],
        [ sort qw(. .. archive_status) ],
        'no WAL files copied');
 
+# Contents of these directories should not be copied
+is_deeply(
+       [ sort(slurp_dir("$tempdir/backup/pg_stat_tmp/")) ],
+       [ sort qw(. ..) ],
+       'contents of pg_stat_tmp/ not copied');
+is_deeply(
+       [ sort(slurp_dir("$tempdir/backup/pg_replslot/")) ],
+       [ sort qw(. ..) ],
+       'contents of pg_replslot/ not copied');
+is_deeply(
+       [ sort(slurp_dir("$tempdir/backup/pg_replslot/")) ],
+       [ sort qw(. ..) ],
+       'contents of pg_replslot/ not copied');
+is_deeply(
+       [ sort(slurp_dir("$tempdir/backup/pg_dynshmem/")) ],
+       [ sort qw(. ..) ],
+       'contents of pg_dynshmem/ not copied');
+is_deeply(
+       [ sort(slurp_dir("$tempdir/backup/pg_notify/")) ],
+       [ sort qw(. ..) ],
+       'contents of pg_notify/ not copied');
+is_deeply(
+       [ sort(slurp_dir("$tempdir/backup/pg_serial/")) ],
+       [ sort qw(. ..) ],
+       'contents of pg_serial/ not copied');
+is_deeply(
+       [ sort(slurp_dir("$tempdir/backup/pg_snapshots/")) ],
+       [ sort qw(. ..) ],
+       'contents of pg_snapshots/ not copied');
+is_deeply(
+       [ sort(slurp_dir("$tempdir/backup/pg_subtrans/")) ],
+       [ sort qw(. ..) ],
+       'contents of pg_subtrans/ not copied');
+
+# These files should not be copied
+ok(!-f "$tempdir/backup/postmaster.pid", 'postmaster.pid not copied');
+ok(!-f "$tempdir/backup/postmaster.opts", 'postmaster.opts not copied');
+ok(!-f "$tempdir/backup/postgresql.auto.conf.tmp",
+       'postgresql.auto.conf.tmp not copied');
+ok(!-f "$tempdir/backup/tablespace_map", 'tablespace_map not copied');
+
+# The pg_replslot symlink should have been copied as a directory
+ok(-l "$pgdata/pg_replslot", 'pg_replslot is a symlink in pgdata');
+ok(-d "$tempdir/backup/pg_replslot", 'pg_replslot symlink copied as 
directory');
+
+# Make sure existing backup_label was ignored
+ok(slurp_file("$tempdir/backup/backup_label") ne 'DONOTCOPY',
+       'existing backup_label not copied');
+
 $node->command_ok(
        [   'pg_basebackup', '-D', "$tempdir/backup2", '--xlogdir',
                "$tempdir/xlog2" ],
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to