]> granicus.if.org Git - postgresql/commitdiff
In base backup, only include our own tablespace version directory.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 25 Mar 2013 18:19:22 +0000 (20:19 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 25 Mar 2013 18:19:22 +0000 (20:19 +0200)
If you have clusters of different versions pointing to the same tablespace
location, we would incorrectly include all the data belonging to the other
versions, too.

Fixes bug #7986, reported by Sergey Burladyan.

src/backend/replication/basebackup.c

index 9e1c5d7363b5fc2c39bfae653e1fe151a6c9c81d..ab5262adfbf87323b226f8721f0c13d3cdbb3e37 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "access/xlog_internal.h"              /* for pg_start/stop_backup */
 #include "catalog/pg_type.h"
+#include "common/relpath.h"
 #include "lib/stringinfo.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -45,6 +46,7 @@ typedef struct
 
 
 static int64 sendDir(char *path, int basepathlen, bool sizeonly);
+static int64 sendTablespace(char *path, bool sizeonly);
 static bool sendFile(char *readfilename, char *tarfilename,
                 struct stat * statbuf, bool missing_ok);
 static void sendFileWithContent(const char *filename, const char *content);
@@ -146,7 +148,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
                        ti = palloc(sizeof(tablespaceinfo));
                        ti->oid = pstrdup(de->d_name);
                        ti->path = pstrdup(linkpath);
-                       ti->size = opt->progress ? sendDir(linkpath, strlen(linkpath), true) : -1;
+                       ti->size = opt->progress ? sendTablespace(fullpath, true) : -1;
                        tablespaces = lappend(tablespaces, ti);
 #else
 
@@ -181,29 +183,26 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
                        pq_sendint(&buf, 0, 2);         /* natts */
                        pq_endmessage(&buf);
 
-                       /* In the main tar, include the backup_label first. */
-                       if (ti->path == NULL)
-                               sendFileWithContent(BACKUP_LABEL_FILE, labelfile);
-
-                       sendDir(ti->path == NULL ? "." : ti->path,
-                                       ti->path == NULL ? 1 : strlen(ti->path),
-                                       false);
-
-                       /* In the main tar, include pg_control last. */
                        if (ti->path == NULL)
                        {
                                struct stat statbuf;
 
+                               /* In the main tar, include the backup_label first... */
+                               sendFileWithContent(BACKUP_LABEL_FILE, labelfile);
+
+                               /* ... then the bulk of the files ... */
+                               sendDir(".", 1, false);
+
+                               /* ... and pg_control after everything else. */
                                if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
-                               {
                                        ereport(ERROR,
                                                        (errcode_for_file_access(),
                                                         errmsg("could not stat control file \"%s\": %m",
                                                                        XLOG_CONTROL_FILE)));
-                               }
-
                                sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false);
                        }
+                       else
+                               sendTablespace(ti->path, false);
 
                        /*
                         * If we're including WAL, and this is the main data directory we
@@ -728,6 +727,49 @@ sendFileWithContent(const char *filename, const char *content)
        }
 }
 
+/*
+ * Include the tablespace directory pointed to by 'path' in the output tar
+ * stream.  If 'sizeonly' is true, we just calculate a total length and return
+ * it, without actually sending anything.
+ */
+static int64
+sendTablespace(char *path, bool sizeonly)
+{
+       int64           size;
+       char            pathbuf[MAXPGPATH];
+       struct stat statbuf;
+
+       /*
+        * 'path' points to the tablespace location, but we only want to include
+        * the version directory in it that belongs to us.
+        */
+       snprintf(pathbuf, sizeof(pathbuf), "%s/%s", path,
+                        TABLESPACE_VERSION_DIRECTORY);
+
+       /*
+        * Store a directory entry in the tar file so we get the permissions right.
+        */
+       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 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 */
+
+       /* Send all the files in the tablespace version directory */
+       size += sendDir(pathbuf, strlen(path), sizeonly);
+
+       return size;
+}
+
 /*
  * Include all files from the given directory in the output tar stream. If
  * 'sizeonly' is true, we just calculate a total length and return it, without