Skip to content

Commit 2edf3e8

Browse files
committed
Avoid including tablespaces inside PGDATA twice in base backups
If a tablespace was crated inside PGDATA it was backed up both as part of the PGDATA backup and as the backup of the tablespace. Avoid this by skipping any directory inside PGDATA that contains one of the active tablespaces. Dimitri Fontaine and Magnus Hagander
1 parent fa28f9c commit 2edf3e8

File tree

1 file changed

+53
-7
lines changed

1 file changed

+53
-7
lines changed

src/backend/replication/basebackup.c

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "lib/stringinfo.h"
2424
#include "libpq/libpq.h"
2525
#include "libpq/pqformat.h"
26+
#include "miscadmin.h"
2627
#include "nodes/pg_list.h"
2728
#include "replication/basebackup.h"
2829
#include "replication/walsender.h"
@@ -44,7 +45,7 @@ typedef struct
4445
} basebackup_options;
4546

4647

47-
static int64 sendDir(char *path, int basepathlen, bool sizeonly);
48+
static int64 sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces);
4849
static int64 sendTablespace(char *path, bool sizeonly);
4950
static bool sendFile(char *readfilename, char *tarfilename,
5051
struct stat * statbuf, bool missing_ok);
@@ -68,6 +69,7 @@ typedef struct
6869
{
6970
char *oid;
7071
char *path;
72+
char *rpath; /* relative path within PGDATA, or NULL */
7173
int64 size;
7274
} tablespaceinfo;
7375

@@ -94,6 +96,9 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
9496
XLogRecPtr startptr;
9597
XLogRecPtr endptr;
9698
char *labelfile;
99+
int datadirpathlen;
100+
101+
datadirpathlen = strlen(DataDir);
97102

98103
startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &labelfile);
99104
SendXlogRecPtrResult(startptr);
@@ -110,6 +115,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
110115
{
111116
char fullpath[MAXPGPATH];
112117
char linkpath[MAXPGPATH];
118+
char *relpath = NULL;
113119
int rllen;
114120

115121
/* Skip special stuff */
@@ -136,9 +142,20 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
136142
}
137143
linkpath[rllen] = '\0';
138144

145+
/*
146+
* Relpath holds the relative path of the tablespace directory
147+
* when it's located within PGDATA, or NULL if it's located
148+
* elsewhere.
149+
*/
150+
if (rllen > datadirpathlen &&
151+
strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
152+
IS_DIR_SEP(linkpath[datadirpathlen]))
153+
relpath = linkpath + datadirpathlen + 1;
154+
139155
ti = palloc(sizeof(tablespaceinfo));
140156
ti->oid = pstrdup(de->d_name);
141157
ti->path = pstrdup(linkpath);
158+
ti->rpath = relpath ? pstrdup(relpath) : NULL;
142159
ti->size = opt->progress ? sendTablespace(fullpath, true) : -1;
143160
tablespaces = lappend(tablespaces, ti);
144161
#else
@@ -156,7 +173,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
156173

157174
/* Add a node for the base directory at the end */
158175
ti = palloc0(sizeof(tablespaceinfo));
159-
ti->size = opt->progress ? sendDir(".", 1, true) : -1;
176+
ti->size = opt->progress ? sendDir(".", 1, true, tablespaces) : -1;
160177
tablespaces = lappend(tablespaces, ti);
161178

162179
/* Send tablespace header */
@@ -182,7 +199,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
182199
sendFileWithContent(BACKUP_LABEL_FILE, labelfile);
183200

184201
/* ... then the bulk of the files ... */
185-
sendDir(".", 1, false);
202+
sendDir(".", 1, false, tablespaces);
186203

187204
/* ... and pg_control after everything else. */
188205
if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
@@ -733,6 +750,8 @@ sendFileWithContent(const char *filename, const char *content)
733750
* Include the tablespace directory pointed to by 'path' in the output tar
734751
* stream. If 'sizeonly' is true, we just calculate a total length and return
735752
* it, without actually sending anything.
753+
*
754+
* Only used to send auxiliary tablespaces, not PGDATA.
736755
*/
737756
static int64
738757
sendTablespace(char *path, bool sizeonly)
@@ -767,7 +786,7 @@ sendTablespace(char *path, bool sizeonly)
767786
size = 512; /* Size of the header just added */
768787

769788
/* Send all the files in the tablespace version directory */
770-
size += sendDir(pathbuf, strlen(path), sizeonly);
789+
size += sendDir(pathbuf, strlen(path), sizeonly, NIL);
771790

772791
return size;
773792
}
@@ -776,9 +795,12 @@ sendTablespace(char *path, bool sizeonly)
776795
* Include all files from the given directory in the output tar stream. If
777796
* 'sizeonly' is true, we just calculate a total length and return it, without
778797
* actually sending anything.
798+
*
799+
* Omit any directory in the tablespaces list, to avoid backing up
800+
* tablespaces twice when they were created inside PGDATA.
779801
*/
780802
static int64
781-
sendDir(char *path, int basepathlen, bool sizeonly)
803+
sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces)
782804
{
783805
DIR *dir;
784806
struct dirent *de;
@@ -904,6 +926,9 @@ sendDir(char *path, int basepathlen, bool sizeonly)
904926
}
905927
else if (S_ISDIR(statbuf.st_mode))
906928
{
929+
bool skip_this_dir = false;
930+
ListCell *lc;
931+
907932
/*
908933
* Store a directory entry in the tar file so we can get the
909934
* permissions right.
@@ -912,8 +937,29 @@ sendDir(char *path, int basepathlen, bool sizeonly)
912937
_tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf);
913938
size += 512; /* Size of the header just added */
914939

915-
/* call ourselves recursively for a directory */
916-
size += sendDir(pathbuf, basepathlen, sizeonly);
940+
/*
941+
* Call ourselves recursively for a directory, unless it happens
942+
* to be a separate tablespace located within PGDATA.
943+
*/
944+
foreach(lc, tablespaces)
945+
{
946+
tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
947+
948+
/*
949+
* ti->rpath is the tablespace relative path within PGDATA, or
950+
* NULL if the tablespace has been properly located somewhere
951+
* else.
952+
*
953+
* Skip past the leading "./" in pathbuf when comparing.
954+
*/
955+
if (ti->rpath && strcmp(ti->rpath, pathbuf + 2) == 0)
956+
{
957+
skip_this_dir = true;
958+
break;
959+
}
960+
}
961+
if (!skip_this_dir)
962+
size += sendDir(pathbuf, basepathlen, sizeonly, tablespaces);
917963
}
918964
else if (S_ISREG(statbuf.st_mode))
919965
{

0 commit comments

Comments
 (0)