@@ -45,7 +45,7 @@ typedef struct
4545} basebackup_options ;
4646
4747
48- static int64 sendDir (char * path , int basepathlen , bool sizeonly );
48+ static int64 sendDir (char * path , int basepathlen , bool sizeonly , List * tablespaces );
4949static int64 sendTablespace (char * path , bool sizeonly );
5050static bool sendFile (char * readfilename , char * tarfilename ,
5151 struct stat * statbuf , bool missing_ok );
@@ -72,6 +72,7 @@ typedef struct
7272{
7373 char * oid ;
7474 char * path ;
75+ char * rpath ; /* relative path within PGDATA, or NULL */
7576 int64 size ;
7677} tablespaceinfo ;
7778
@@ -100,6 +101,9 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
100101 XLogRecPtr endptr ;
101102 TimeLineID endtli ;
102103 char * labelfile ;
104+ int datadirpathlen ;
105+
106+ datadirpathlen = strlen (DataDir );
103107
104108 backup_started_in_recovery = RecoveryInProgress ();
105109
@@ -119,6 +123,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
119123 {
120124 char fullpath [MAXPGPATH ];
121125 char linkpath [MAXPGPATH ];
126+ char * relpath = NULL ;
122127 int rllen ;
123128
124129 /* Skip special stuff */
@@ -145,9 +150,20 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
145150 }
146151 linkpath [rllen ] = '\0' ;
147152
153+ /*
154+ * Relpath holds the relative path of the tablespace directory
155+ * when it's located within PGDATA, or NULL if it's located
156+ * elsewhere.
157+ */
158+ if (rllen > datadirpathlen &&
159+ strncmp (linkpath , DataDir , datadirpathlen ) == 0 &&
160+ IS_DIR_SEP (linkpath [datadirpathlen ]))
161+ relpath = linkpath + datadirpathlen + 1 ;
162+
148163 ti = palloc (sizeof (tablespaceinfo ));
149164 ti -> oid = pstrdup (de -> d_name );
150165 ti -> path = pstrdup (linkpath );
166+ ti -> rpath = relpath ? pstrdup (relpath ) : NULL ;
151167 ti -> size = opt -> progress ? sendTablespace (fullpath , true) : -1 ;
152168 tablespaces = lappend (tablespaces , ti );
153169#else
@@ -165,7 +181,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
165181
166182 /* Add a node for the base directory at the end */
167183 ti = palloc0 (sizeof (tablespaceinfo ));
168- ti -> size = opt -> progress ? sendDir ("." , 1 , true) : -1 ;
184+ ti -> size = opt -> progress ? sendDir ("." , 1 , true, tablespaces ) : -1 ;
169185 tablespaces = lappend (tablespaces , ti );
170186
171187 /* Send tablespace header */
@@ -191,7 +207,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
191207 sendFileWithContent (BACKUP_LABEL_FILE , labelfile );
192208
193209 /* ... then the bulk of the files ... */
194- sendDir ("." , 1 , false);
210+ sendDir ("." , 1 , false, tablespaces );
195211
196212 /* ... and pg_control after everything else. */
197213 if (lstat (XLOG_CONTROL_FILE , & statbuf ) != 0 )
@@ -744,6 +760,8 @@ sendFileWithContent(const char *filename, const char *content)
744760 * Include the tablespace directory pointed to by 'path' in the output tar
745761 * stream. If 'sizeonly' is true, we just calculate a total length and return
746762 * it, without actually sending anything.
763+ *
764+ * Only used to send auxiliary tablespaces, not PGDATA.
747765 */
748766static int64
749767sendTablespace (char * path , bool sizeonly )
@@ -779,7 +797,7 @@ sendTablespace(char *path, bool sizeonly)
779797 size = 512 ; /* Size of the header just added */
780798
781799 /* Send all the files in the tablespace version directory */
782- size += sendDir (pathbuf , strlen (path ), sizeonly );
800+ size += sendDir (pathbuf , strlen (path ), sizeonly , NIL );
783801
784802 return size ;
785803}
@@ -788,9 +806,12 @@ sendTablespace(char *path, bool sizeonly)
788806 * Include all files from the given directory in the output tar stream. If
789807 * 'sizeonly' is true, we just calculate a total length and return it, without
790808 * actually sending anything.
809+ *
810+ * Omit any directory in the tablespaces list, to avoid backing up
811+ * tablespaces twice when they were created inside PGDATA.
791812 */
792813static int64
793- sendDir (char * path , int basepathlen , bool sizeonly )
814+ sendDir (char * path , int basepathlen , bool sizeonly , List * tablespaces )
794815{
795816 DIR * dir ;
796817 struct dirent * de ;
@@ -931,6 +952,9 @@ sendDir(char *path, int basepathlen, bool sizeonly)
931952 }
932953 else if (S_ISDIR (statbuf .st_mode ))
933954 {
955+ bool skip_this_dir = false;
956+ ListCell * lc ;
957+
934958 /*
935959 * Store a directory entry in the tar file so we can get the
936960 * permissions right.
@@ -939,8 +963,29 @@ sendDir(char *path, int basepathlen, bool sizeonly)
939963 _tarWriteHeader (pathbuf + basepathlen + 1 , NULL , & statbuf );
940964 size += 512 ; /* Size of the header just added */
941965
942- /* call ourselves recursively for a directory */
943- size += sendDir (pathbuf , basepathlen , sizeonly );
966+ /*
967+ * Call ourselves recursively for a directory, unless it happens
968+ * to be a separate tablespace located within PGDATA.
969+ */
970+ foreach (lc , tablespaces )
971+ {
972+ tablespaceinfo * ti = (tablespaceinfo * ) lfirst (lc );
973+
974+ /*
975+ * ti->rpath is the tablespace relative path within PGDATA, or
976+ * NULL if the tablespace has been properly located somewhere
977+ * else.
978+ *
979+ * Skip past the leading "./" in pathbuf when comparing.
980+ */
981+ if (ti -> rpath && strcmp (ti -> rpath , pathbuf + 2 ) == 0 )
982+ {
983+ skip_this_dir = true;
984+ break ;
985+ }
986+ }
987+ if (!skip_this_dir )
988+ size += sendDir (pathbuf , basepathlen , sizeonly , tablespaces );
944989 }
945990 else if (S_ISREG (statbuf .st_mode ))
946991 {
0 commit comments