23
23
#include "lib/stringinfo.h"
24
24
#include "libpq/libpq.h"
25
25
#include "libpq/pqformat.h"
26
+ #include "miscadmin.h"
26
27
#include "nodes/pg_list.h"
27
28
#include "replication/basebackup.h"
28
29
#include "replication/walsender.h"
@@ -44,7 +45,7 @@ typedef struct
44
45
} basebackup_options ;
45
46
46
47
47
- static int64 sendDir (char * path , int basepathlen , bool sizeonly );
48
+ static int64 sendDir (char * path , int basepathlen , bool sizeonly , List * tablespaces );
48
49
static int64 sendTablespace (char * path , bool sizeonly );
49
50
static bool sendFile (char * readfilename , char * tarfilename ,
50
51
struct stat * statbuf , bool missing_ok );
@@ -68,6 +69,7 @@ typedef struct
68
69
{
69
70
char * oid ;
70
71
char * path ;
72
+ char * rpath ; /* relative path within PGDATA, or NULL */
71
73
int64 size ;
72
74
} tablespaceinfo ;
73
75
@@ -94,6 +96,9 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
94
96
XLogRecPtr startptr ;
95
97
XLogRecPtr endptr ;
96
98
char * labelfile ;
99
+ int datadirpathlen ;
100
+
101
+ datadirpathlen = strlen (DataDir );
97
102
98
103
startptr = do_pg_start_backup (opt -> label , opt -> fastcheckpoint , & labelfile );
99
104
SendXlogRecPtrResult (startptr );
@@ -110,6 +115,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
110
115
{
111
116
char fullpath [MAXPGPATH ];
112
117
char linkpath [MAXPGPATH ];
118
+ char * relpath = NULL ;
113
119
int rllen ;
114
120
115
121
/* Skip special stuff */
@@ -136,9 +142,20 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
136
142
}
137
143
linkpath [rllen ] = '\0' ;
138
144
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
+
139
155
ti = palloc (sizeof (tablespaceinfo ));
140
156
ti -> oid = pstrdup (de -> d_name );
141
157
ti -> path = pstrdup (linkpath );
158
+ ti -> rpath = relpath ? pstrdup (relpath ) : NULL ;
142
159
ti -> size = opt -> progress ? sendTablespace (fullpath , true) : -1 ;
143
160
tablespaces = lappend (tablespaces , ti );
144
161
#else
@@ -156,7 +173,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
156
173
157
174
/* Add a node for the base directory at the end */
158
175
ti = palloc0 (sizeof (tablespaceinfo ));
159
- ti -> size = opt -> progress ? sendDir ("." , 1 , true) : -1 ;
176
+ ti -> size = opt -> progress ? sendDir ("." , 1 , true, tablespaces ) : -1 ;
160
177
tablespaces = lappend (tablespaces , ti );
161
178
162
179
/* Send tablespace header */
@@ -182,7 +199,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
182
199
sendFileWithContent (BACKUP_LABEL_FILE , labelfile );
183
200
184
201
/* ... then the bulk of the files ... */
185
- sendDir ("." , 1 , false);
202
+ sendDir ("." , 1 , false, tablespaces );
186
203
187
204
/* ... and pg_control after everything else. */
188
205
if (lstat (XLOG_CONTROL_FILE , & statbuf ) != 0 )
@@ -733,6 +750,8 @@ sendFileWithContent(const char *filename, const char *content)
733
750
* Include the tablespace directory pointed to by 'path' in the output tar
734
751
* stream. If 'sizeonly' is true, we just calculate a total length and return
735
752
* it, without actually sending anything.
753
+ *
754
+ * Only used to send auxiliary tablespaces, not PGDATA.
736
755
*/
737
756
static int64
738
757
sendTablespace (char * path , bool sizeonly )
@@ -767,7 +786,7 @@ sendTablespace(char *path, bool sizeonly)
767
786
size = 512 ; /* Size of the header just added */
768
787
769
788
/* Send all the files in the tablespace version directory */
770
- size += sendDir (pathbuf , strlen (path ), sizeonly );
789
+ size += sendDir (pathbuf , strlen (path ), sizeonly , NIL );
771
790
772
791
return size ;
773
792
}
@@ -776,9 +795,12 @@ sendTablespace(char *path, bool sizeonly)
776
795
* Include all files from the given directory in the output tar stream. If
777
796
* 'sizeonly' is true, we just calculate a total length and return it, without
778
797
* 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.
779
801
*/
780
802
static int64
781
- sendDir (char * path , int basepathlen , bool sizeonly )
803
+ sendDir (char * path , int basepathlen , bool sizeonly , List * tablespaces )
782
804
{
783
805
DIR * dir ;
784
806
struct dirent * de ;
@@ -904,6 +926,9 @@ sendDir(char *path, int basepathlen, bool sizeonly)
904
926
}
905
927
else if (S_ISDIR (statbuf .st_mode ))
906
928
{
929
+ bool skip_this_dir = false;
930
+ ListCell * lc ;
931
+
907
932
/*
908
933
* Store a directory entry in the tar file so we can get the
909
934
* permissions right.
@@ -912,8 +937,29 @@ sendDir(char *path, int basepathlen, bool sizeonly)
912
937
_tarWriteHeader (pathbuf + basepathlen + 1 , NULL , & statbuf );
913
938
size += 512 ; /* Size of the header just added */
914
939
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 );
917
963
}
918
964
else if (S_ISREG (statbuf .st_mode ))
919
965
{
0 commit comments