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 );
4849static int64 sendTablespace (char * path ,bool sizeonly );
4950static bool sendFile (char * readfilename ,char * tarfilename ,
5051struct stat * statbuf ,bool missing_ok );
@@ -68,6 +69,7 @@ typedef struct
6869{
6970char * oid ;
7071char * path ;
72+ char * rpath ;/* relative path within PGDATA, or NULL */
7173int64 size ;
7274}tablespaceinfo ;
7375
@@ -94,6 +96,9 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
9496XLogRecPtr startptr ;
9597XLogRecPtr endptr ;
9698char * labelfile ;
99+ int datadirpathlen ;
100+
101+ datadirpathlen = strlen (DataDir );
97102
98103startptr = do_pg_start_backup (opt -> label ,opt -> fastcheckpoint ,& labelfile );
99104SendXlogRecPtrResult (startptr );
@@ -110,6 +115,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
110115{
111116char fullpath [MAXPGPATH ];
112117char linkpath [MAXPGPATH ];
118+ char * relpath = NULL ;
113119int rllen ;
114120
115121/* Skip special stuff */
@@ -136,9 +142,20 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
136142}
137143linkpath [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+
139155ti = palloc (sizeof (tablespaceinfo ));
140156ti -> oid = pstrdup (de -> d_name );
141157ti -> path = pstrdup (linkpath );
158+ ti -> rpath = relpath ?pstrdup (relpath ) :NULL ;
142159ti -> size = opt -> progress ?sendTablespace (fullpath , true) :-1 ;
143160tablespaces = 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 */
158175ti = palloc0 (sizeof (tablespaceinfo ));
159- ti -> size = opt -> progress ?sendDir ("." ,1 , true) :-1 ;
176+ ti -> size = opt -> progress ?sendDir ("." ,1 , true, tablespaces ) :-1 ;
160177tablespaces = lappend (tablespaces ,ti );
161178
162179/* Send tablespace header */
@@ -182,7 +199,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
182199sendFileWithContent (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. */
188205if (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 */
737756static int64
738757sendTablespace (char * path ,bool sizeonly )
@@ -767,7 +786,7 @@ sendTablespace(char *path, bool sizeonly)
767786size = 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
772791return 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 */
780802static int64
781- sendDir (char * path ,int basepathlen ,bool sizeonly )
803+ sendDir (char * path ,int basepathlen ,bool sizeonly , List * tablespaces )
782804{
783805DIR * dir ;
784806struct dirent * de ;
@@ -904,6 +926,9 @@ sendDir(char *path, int basepathlen, bool sizeonly)
904926}
905927else 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 );
913938size += 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}
918964else if (S_ISREG (statbuf .st_mode ))
919965{