Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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