On 9/6/16 10:25 PM, Michael Paquier wrote:
>
On Wed, Sep 7, 2016 at 12:16 AM, David Steele <da...@pgmasters.net> wrote:

Attached is a new patch that adds sgml documentation.  I can expand on each
directory individually if you think that's necessary, but thought it was
better to lump them into a few categories.

+    be ommitted 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 ommitted.

s/ommitted/omitted/

Fixed.

+#define EXCLUDE_DIR_MAX         8
+#define EXCLUDE_DIR_STAT_TMP     0
+
+const char *excludeDirContents[EXCLUDE_DIR_MAX] =
+{
+    /*
+     * Skip temporary statistics files. The first array position will be
+     * filled with the value of pgstat_stat_directory relative to PGDATA.
+     * PG_STAT_TMP_DIR must be skipped even when stats_temp_directory is set
+     * because PGSS_TEXT_FILE is always created there.
+     */
+    NULL,
I find that ugly. I'd rather use an array with undefined size for the
fixed elements finishing by NULL, remove EXCLUDE_DIR_MAX and
EXCLUDE_DIR_STAT_TMP and use a small routine to do the work done on
_tarWriteHeader...

Done.  Also writing out pg_xlog with the new routine.

--
-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/src/backend/replication/basebackup.c 
b/src/backend/replication/basebackup.c
index da9b7a6..a441ae2 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"
@@ -57,6 +58,8 @@ static bool sendFile(char *readfilename, char *tarfilename,
 static void sendFileWithContent(const char *filename, const char *content);
 static void _tarWriteHeader(const char *filename, const char *linktarget,
                                struct stat * statbuf);
+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,67 @@ 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,
+
+       /* Recreated on startup, see StartupReplicationSlots(). */
+       "pg_replslot",
+
+       /* Removed on startup, see dsm_cleanup_for_mmap(). */
+       PG_DYNSHMEM_DIR,
+
+       /* Recreated/zeroed on startup, see AsyncShmemInit(). */
+       "pg_notify",
+
+       /* Recreated on startup, see OldSerXidInit(). */
+       "pg_serial",
+
+       /* Removed on startup, see DeleteAllExportedSnapshotFiles(). */
+       "pg_snapshots",
+
+       /* Recreated/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!
  */
@@ -889,6 +953,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 +969,88 @@ 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 + 2, excludeFile[excludeIdx]) == 0)
+                       {
+                               ereport(DEBUG1,
+                                               (errmsg("file excluded from 
backup: %s",
+                                                       
excludeFile[excludeIdx])));
 
-               if (strcmp(de->d_name, TABLESPACE_MAP) == 0)
+                               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 + 2, 
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);
+
+                       excludeFound = true;
+               }
+
+               /* If file matched exclusion, continue. */
+               if (excludeFound)
                        continue;
 
                /*
@@ -938,55 +1070,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,18 +1081,8 @@ 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
@@ -1248,6 +1325,31 @@ _tarWriteHeader(const char *filename, const char 
*linktarget,
 }
 
 /*
+ * 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)
+{
+       /* Include the directory entry to preserve permissions. */
+       if (!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;
+
+               _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf);
+       }
+
+       return 512;
+}
+
+/*
  * Increment the network transfer counter by the given number of bytes,
  * and sleep if necessary to comply with the requested network transfer
  * rate.
-- 
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