Skip to content

Commit 773e4d5

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 9484982 commit 773e4d5

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"
@@ -43,7 +44,7 @@ typedef struct
4344
} basebackup_options;
4445

4546

46-
static int64 sendDir(char *path, int basepathlen, bool sizeonly);
47+
static int64 sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces);
4748
static int64 sendTablespace(char *path, bool sizeonly);
4849
static bool sendFile(char *readfilename, char *tarfilename,
4950
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
@@ -155,7 +172,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
155172

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

161178
/* Send tablespace header */
@@ -181,7 +198,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
181198
sendFileWithContent(BACKUP_LABEL_FILE, labelfile);
182199

183200
/* ... then the bulk of the files ... */
184-
sendDir(".", 1, false);
201+
sendDir(".", 1, false, tablespaces);
185202

186203
/* ... and pg_control after everything else. */
187204
if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
@@ -571,6 +588,8 @@ sendFileWithContent(const char *filename, const char *content)
571588
* Include the tablespace directory pointed to by 'path' in the output tar
572589
* stream. If 'sizeonly' is true, we just calculate a total length and return
573590
* it, without actually sending anything.
591+
*
592+
* Only used to send auxiliary tablespaces, not PGDATA.
574593
*/
575594
static int64
576595
sendTablespace(char *path, bool sizeonly)
@@ -605,7 +624,7 @@ sendTablespace(char *path, bool sizeonly)
605624
size = 512; /* Size of the header just added */
606625

607626
/* Send all the files in the tablespace version directory */
608-
size += sendDir(pathbuf, strlen(path), sizeonly);
627+
size += sendDir(pathbuf, strlen(path), sizeonly, NIL);
609628

610629
return size;
611630
}
@@ -614,9 +633,12 @@ sendTablespace(char *path, bool sizeonly)
614633
* Include all files from the given directory in the output tar stream. If
615634
* 'sizeonly' is true, we just calculate a total length and return it, without
616635
* actually sending anything.
636+
*
637+
* Omit any directory in the tablespaces list, to avoid backing up
638+
* tablespaces twice when they were created inside PGDATA.
617639
*/
618640
static int64
619-
sendDir(char *path, int basepathlen, bool sizeonly)
641+
sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces)
620642
{
621643
DIR *dir;
622644
struct dirent *de;
@@ -737,6 +759,9 @@ sendDir(char *path, int basepathlen, bool sizeonly)
737759
}
738760
else if (S_ISDIR(statbuf.st_mode))
739761
{
762+
bool skip_this_dir = false;
763+
ListCell *lc;
764+
740765
/*
741766
* Store a directory entry in the tar file so we can get the
742767
* permissions right.
@@ -745,8 +770,29 @@ sendDir(char *path, int basepathlen, bool sizeonly)
745770
_tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf);
746771
size += 512; /* Size of the header just added */
747772

748-
/* call ourselves recursively for a directory */
749-
size += sendDir(pathbuf, basepathlen, sizeonly);
773+
/*
774+
* Call ourselves recursively for a directory, unless it happens
775+
* to be a separate tablespace located within PGDATA.
776+
*/
777+
foreach(lc, tablespaces)
778+
{
779+
tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
780+
781+
/*
782+
* ti->rpath is the tablespace relative path within PGDATA, or
783+
* NULL if the tablespace has been properly located somewhere
784+
* else.
785+
*
786+
* Skip past the leading "./" in pathbuf when comparing.
787+
*/
788+
if (ti->rpath && strcmp(ti->rpath, pathbuf + 2) == 0)
789+
{
790+
skip_this_dir = true;
791+
break;
792+
}
793+
}
794+
if (!skip_this_dir)
795+
size += sendDir(pathbuf, basepathlen, sizeonly, tablespaces);
750796
}
751797
else if (S_ISREG(statbuf.st_mode))
752798
{

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy