Skip to content

Commit 2e4acef

Browse files
committed
In base backup, only include our own tablespace version directory.
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.
1 parent aa5d7d5 commit 2e4acef

File tree

1 file changed

+63
-5
lines changed

1 file changed

+63
-5
lines changed

src/backend/replication/basebackup.c

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <time.h>
1919

2020
#include "access/xlog_internal.h" /* for pg_start/stop_backup */
21+
#include "catalog/catalog.h"
2122
#include "catalog/pg_type.h"
2223
#include "lib/stringinfo.h"
2324
#include "libpq/libpq.h"
@@ -43,6 +44,7 @@ typedef struct
4344

4445

4546
static int64 sendDir(char *path, int basepathlen, bool sizeonly);
47+
static int64 sendTablespace(char *path, bool sizeonly);
4648
static bool sendFile(char *readfilename, char *tarfilename,
4749
struct stat * statbuf, bool missing_ok);
4850
static void sendFileWithContent(const char *filename, const char *content);
@@ -137,7 +139,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
137139
ti = palloc(sizeof(tablespaceinfo));
138140
ti->oid = pstrdup(de->d_name);
139141
ti->path = pstrdup(linkpath);
140-
ti->size = opt->progress ? sendDir(linkpath, strlen(linkpath), true) : -1;
142+
ti->size = opt->progress ? sendTablespace(fullpath, true) : -1;
141143
tablespaces = lappend(tablespaces, ti);
142144
#else
143145
/*
@@ -171,13 +173,26 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
171173
pq_sendint(&buf, 0, 2); /* natts */
172174
pq_endmessage(&buf);
173175

174-
/* In the main tar, include the backup_label first. */
175176
if (ti->path == NULL)
177+
{
178+
struct stat statbuf;
179+
180+
/* In the main tar, include the backup_label first... */
176181
sendFileWithContent(BACKUP_LABEL_FILE, labelfile);
177182

178-
sendDir(ti->path == NULL ? "." : ti->path,
179-
ti->path == NULL ? 1 : strlen(ti->path),
180-
false);
183+
/* ... then the bulk of the files ... */
184+
sendDir(".", 1, false);
185+
186+
/* ... and pg_control after everything else. */
187+
if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
188+
ereport(ERROR,
189+
(errcode_for_file_access(),
190+
errmsg("could not stat control file \"%s\": %m",
191+
XLOG_CONTROL_FILE)));
192+
sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false);
193+
}
194+
else
195+
sendTablespace(ti->path, false);
181196

182197
/*
183198
* If we're including WAL, and this is the main data directory we
@@ -552,6 +567,49 @@ sendFileWithContent(const char *filename, const char *content)
552567
}
553568
}
554569

570+
/*
571+
* Include the tablespace directory pointed to by 'path' in the output tar
572+
* stream. If 'sizeonly' is true, we just calculate a total length and return
573+
* it, without actually sending anything.
574+
*/
575+
static int64
576+
sendTablespace(char *path, bool sizeonly)
577+
{
578+
int64 size;
579+
char pathbuf[MAXPGPATH];
580+
struct stat statbuf;
581+
582+
/*
583+
* 'path' points to the tablespace location, but we only want to include
584+
* the version directory in it that belongs to us.
585+
*/
586+
snprintf(pathbuf, sizeof(pathbuf), "%s/%s", path,
587+
TABLESPACE_VERSION_DIRECTORY);
588+
589+
/*
590+
* Store a directory entry in the tar file so we get the permissions right.
591+
*/
592+
if (lstat(pathbuf, &statbuf) != 0)
593+
{
594+
if (errno != ENOENT)
595+
ereport(ERROR,
596+
(errcode_for_file_access(),
597+
errmsg("could not stat file or directory \"%s\": %m",
598+
pathbuf)));
599+
600+
/* If the tablespace went away while scanning, it's no error. */
601+
return 0;
602+
}
603+
if (!sizeonly)
604+
_tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf);
605+
size = 512; /* Size of the header just added */
606+
607+
/* Send all the files in the tablespace version directory */
608+
size += sendDir(pathbuf, strlen(path), sizeonly);
609+
610+
return size;
611+
}
612+
555613
/*
556614
* Include all files from the given directory in the output tar stream. If
557615
* 'sizeonly' is true, we just calculate a total length and return it, without

0 commit comments

Comments
 (0)