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"
@@ -43,7 +44,7 @@ typedef struct
43
44
}basebackup_options ;
44
45
45
46
46
- static int64 sendDir (char * path ,int basepathlen ,bool sizeonly );
47
+ static int64 sendDir (char * path ,int basepathlen ,bool sizeonly , List * tablespaces );
47
48
static int64 sendTablespace (char * path ,bool sizeonly );
48
49
static bool sendFile (char * readfilename ,char * tarfilename ,
49
50
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
@@ -155,7 +172,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
155
172
156
173
/* Add a node for the base directory at the end */
157
174
ti = palloc0 (sizeof (tablespaceinfo ));
158
- ti -> size = opt -> progress ?sendDir ("." ,1 , true) :-1 ;
175
+ ti -> size = opt -> progress ?sendDir ("." ,1 , true, tablespaces ) :-1 ;
159
176
tablespaces = lappend (tablespaces ,ti );
160
177
161
178
/* Send tablespace header */
@@ -181,7 +198,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
181
198
sendFileWithContent (BACKUP_LABEL_FILE ,labelfile );
182
199
183
200
/* ... then the bulk of the files ... */
184
- sendDir ("." ,1 , false);
201
+ sendDir ("." ,1 , false, tablespaces );
185
202
186
203
/* ... and pg_control after everything else. */
187
204
if (lstat (XLOG_CONTROL_FILE ,& statbuf )!= 0 )
@@ -571,6 +588,8 @@ sendFileWithContent(const char *filename, const char *content)
571
588
* Include the tablespace directory pointed to by 'path' in the output tar
572
589
* stream. If 'sizeonly' is true, we just calculate a total length and return
573
590
* it, without actually sending anything.
591
+ *
592
+ * Only used to send auxiliary tablespaces, not PGDATA.
574
593
*/
575
594
static int64
576
595
sendTablespace (char * path ,bool sizeonly )
@@ -605,7 +624,7 @@ sendTablespace(char *path, bool sizeonly)
605
624
size = 512 ;/* Size of the header just added */
606
625
607
626
/* Send all the files in the tablespace version directory */
608
- size += sendDir (pathbuf ,strlen (path ),sizeonly );
627
+ size += sendDir (pathbuf ,strlen (path ),sizeonly , NIL );
609
628
610
629
return size ;
611
630
}
@@ -614,9 +633,12 @@ sendTablespace(char *path, bool sizeonly)
614
633
* Include all files from the given directory in the output tar stream. If
615
634
* 'sizeonly' is true, we just calculate a total length and return it, without
616
635
* 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.
617
639
*/
618
640
static int64
619
- sendDir (char * path ,int basepathlen ,bool sizeonly )
641
+ sendDir (char * path ,int basepathlen ,bool sizeonly , List * tablespaces )
620
642
{
621
643
DIR * dir ;
622
644
struct dirent * de ;
@@ -737,6 +759,9 @@ sendDir(char *path, int basepathlen, bool sizeonly)
737
759
}
738
760
else if (S_ISDIR (statbuf .st_mode ))
739
761
{
762
+ bool skip_this_dir = false;
763
+ ListCell * lc ;
764
+
740
765
/*
741
766
* Store a directory entry in the tar file so we can get the
742
767
* permissions right.
@@ -745,8 +770,29 @@ sendDir(char *path, int basepathlen, bool sizeonly)
745
770
_tarWriteHeader (pathbuf + basepathlen + 1 ,NULL ,& statbuf );
746
771
size += 512 ;/* Size of the header just added */
747
772
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 );
750
796
}
751
797
else if (S_ISREG (statbuf .st_mode ))
752
798
{