Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfb05f3c

Browse files
committed
pg_basebackup: Add support for relocating tablespaces
Tablespaces can be relocated in plain backup mode by specifying one ormore -T olddir=newdir options.Author: Steeve Lennmark <steevel@handeldsbanken.se>Reviewed-by: Peter Eisentraut <peter_e@gmx.net>
1 parent77585bc commitfb05f3c

File tree

2 files changed

+204
-8
lines changed

2 files changed

+204
-8
lines changed

‎doc/src/sgml/ref/pg_basebackup.sgml

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,33 @@ PostgreSQL documentation
202202
</listitem>
203203
</varlistentry>
204204

205+
<varlistentry>
206+
<term><option>-T <replaceable class="parameter">olddir</replaceable>=<replaceable class="parameter">newdir</replaceable></option></term>
207+
<term><option>--tablespace-mapping=<replaceable class="parameter">olddir</replaceable>=<replaceable class="parameter">newdir</replaceable></option></term>
208+
<listitem>
209+
<para>
210+
Relocate the tablespace in directory <replaceable>olddir</replaceable>
211+
to <replaceable>newdir</replaceable> during the backup. To be
212+
effective, <replaceable>olddir</replaceable> must exactly match the
213+
path specification of the tablespace as it is currently defined. (But
214+
it is not an error if there is no tablespace
215+
in <replaceable>olddir</replaceable> contained in the backup.)
216+
Both <replaceable>olddir</replaceable>
217+
and <replaceable>newdir</replaceable> must be absolute paths. If a
218+
path happens to contain a <literal>=</literal> sign, escape it with a
219+
backslash. This option can be specified multiple times for multiple
220+
tablespaces. See examples below.
221+
</para>
222+
223+
<para>
224+
If a tablespace is relocated in this way, the symbolic links inside
225+
the main data directory are updated to point to the new location. So
226+
the new data directory is ready to be used for a new server instance
227+
with all tablespaces in the updated locations.
228+
</para>
229+
</listitem>
230+
</varlistentry>
231+
205232
<varlistentry>
206233
<term><option>--xlogdir=<replaceable class="parameter">xlogdir</replaceable></option></term>
207234
<listitem>
@@ -528,9 +555,13 @@ PostgreSQL documentation
528555
</para>
529556

530557
<para>
531-
The way <productname>PostgreSQL</productname> manages tablespaces, the path
532-
for all additional tablespaces must be identical whenever a backup is
533-
restored. The main data directory, however, is relocatable to any location.
558+
Tablespaces will in plain format by default be backed up to the same path
559+
they have on the server, unless the
560+
option <replaceable>--tablespace-mapping</replaceable> is used. Without
561+
this option, running a plain format base backup on the same host as the
562+
server will not work if tablespaces are in use, because the backup would
563+
have to be written to the same directory locations as the original
564+
tablespaces.
534565
</para>
535566

536567
<para>
@@ -570,6 +601,15 @@ PostgreSQL documentation
570601
(This command will fail if there are multiple tablespaces in the
571602
database.)
572603
</para>
604+
605+
<para>
606+
To create a backup of a local database where the tablespace in
607+
<filename>/opt/ts</filename> is relocated
608+
to <filename>./backup/ts</filename>:
609+
<screen>
610+
<prompt>$</prompt> <userinput>pg_basebackup -D backup/data -T /opt/ts=$(pwd)/backup/ts</userinput>
611+
</screen>
612+
</para>
573613
</refsect1>
574614

575615
<refsect1>

‎src/bin/pg_basebackup/pg_basebackup.c

Lines changed: 161 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,24 @@
3535
#include"streamutil.h"
3636

3737

38+
#defineatooid(x) ((Oid) strtoul((x), NULL, 10))
39+
40+
typedefstructTablespaceListCell
41+
{
42+
structTablespaceListCell*next;
43+
charold_dir[MAXPGPATH];
44+
charnew_dir[MAXPGPATH];
45+
}TablespaceListCell;
46+
47+
typedefstructTablespaceList
48+
{
49+
TablespaceListCell*head;
50+
TablespaceListCell*tail;
51+
}TablespaceList;
52+
3853
/* Global options */
3954
staticchar*basedir=NULL;
55+
staticTablespaceListtablespace_dirs= {NULL,NULL};
4056
staticchar*xlog_dir="";
4157
staticcharformat='p';/* p(lain)/t(ar) */
4258
staticchar*label="pg_basebackup base backup";
@@ -90,6 +106,10 @@ static void BaseBackup(void);
90106
staticboolreached_end_position(XLogRecPtrsegendpos,uint32timeline,
91107
boolsegment_finished);
92108

109+
staticconstchar*get_tablespace_mapping(constchar*dir);
110+
staticvoidupdate_tablespace_symlink(Oidoid,constchar*old_dir);
111+
staticvoidtablespace_list_append(constchar*arg);
112+
93113

94114
staticvoiddisconnect_and_exit(intcode)
95115
{
@@ -110,6 +130,77 @@ static void disconnect_and_exit(int code)
110130
}
111131

112132

133+
/*
134+
* Split argument into old_dir and new_dir and append to tablespace mapping
135+
* list.
136+
*/
137+
staticvoid
138+
tablespace_list_append(constchar*arg)
139+
{
140+
TablespaceListCell*cell= (TablespaceListCell*)pg_malloc0(sizeof(TablespaceListCell));
141+
char*dst;
142+
char*dst_ptr;
143+
constchar*arg_ptr;
144+
145+
dst_ptr=dst=cell->old_dir;
146+
for (arg_ptr=arg;*arg_ptr;arg_ptr++)
147+
{
148+
if (dst_ptr-dst >=MAXPGPATH)
149+
{
150+
fprintf(stderr,_("%s: directory name too long\n"),progname);
151+
exit(1);
152+
}
153+
154+
if (*arg_ptr=='\\'&&*(arg_ptr+1)=='=')
155+
;/* skip backslash escaping = */
156+
elseif (*arg_ptr=='='&& (arg_ptr==arg||*(arg_ptr-1)!='\\'))
157+
{
158+
if (*cell->new_dir)
159+
{
160+
fprintf(stderr,_("%s: multiple \"=\" signs in tablespace mapping\n"),progname);
161+
exit(1);
162+
}
163+
else
164+
dst=dst_ptr=cell->new_dir;
165+
}
166+
else
167+
*dst_ptr++=*arg_ptr;
168+
}
169+
170+
if (!*cell->old_dir|| !*cell->new_dir)
171+
{
172+
fprintf(stderr,
173+
_("%s: invalid tablespace mapping format \"%s\", must be \"OLDDIR=NEWDIR\"\n"),
174+
progname,arg);
175+
exit(1);
176+
}
177+
178+
/* This check isn't absolutely necessary. But all tablespaces are created
179+
* with absolute directories, so specifying a non-absolute path here would
180+
* just never match, possibly confusing users. It's also good to be
181+
* consistent with the new_dir check. */
182+
if (!is_absolute_path(cell->old_dir))
183+
{
184+
fprintf(stderr,_("%s: old directory not absolute in tablespace mapping: %s\n"),
185+
progname,cell->old_dir);
186+
exit(1);
187+
}
188+
189+
if (!is_absolute_path(cell->new_dir))
190+
{
191+
fprintf(stderr,_("%s: new directory not absolute in tablespace mapping: %s\n"),
192+
progname,cell->new_dir);
193+
exit(1);
194+
}
195+
196+
if (tablespace_dirs.tail)
197+
tablespace_dirs.tail->next=cell;
198+
else
199+
tablespace_dirs.head=cell;
200+
tablespace_dirs.tail=cell;
201+
}
202+
203+
113204
#ifdefHAVE_LIBZ
114205
staticconstchar*
115206
get_gz_error(gzFilegzf)
@@ -137,6 +228,8 @@ usage(void)
137228
printf(_(" -F, --format=p|t output format (plain (default), tar)\n"));
138229
printf(_(" -R, --write-recovery-conf\n"
139230
" write recovery.conf after backup\n"));
231+
printf(_(" -T, --tablespace-mapping=OLDDIR=NEWDIR\n"
232+
" relocate tablespace in OLDDIR to NEWDIR\n"));
140233
printf(_(" -x, --xlog include required WAL files in backup (fetch mode)\n"));
141234
printf(_(" -X, --xlog-method=fetch|stream\n"
142235
" include required WAL files with specified method\n"));
@@ -899,15 +992,60 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
899992
PQfreemem(copybuf);
900993
}
901994

995+
996+
/*
997+
* Retrieve tablespace path, either relocated or original depending on whether
998+
* -T was passed or not.
999+
*/
1000+
staticconstchar*
1001+
get_tablespace_mapping(constchar*dir)
1002+
{
1003+
TablespaceListCell*cell;
1004+
1005+
for (cell=tablespace_dirs.head;cell;cell=cell->next)
1006+
if (strcmp(dir,cell->old_dir)==0)
1007+
returncell->new_dir;
1008+
1009+
returndir;
1010+
}
1011+
1012+
1013+
/*
1014+
* Update symlinks to reflect relocated tablespace.
1015+
*/
1016+
staticvoid
1017+
update_tablespace_symlink(Oidoid,constchar*old_dir)
1018+
{
1019+
constchar*new_dir=get_tablespace_mapping(old_dir);
1020+
1021+
if (strcmp(old_dir,new_dir)!=0)
1022+
{
1023+
char*linkloc=psprintf("%s/pg_tblspc/%d",basedir,oid);
1024+
1025+
if (unlink(linkloc)!=0&&errno!=ENOENT)
1026+
{
1027+
fprintf(stderr,_("%s: could not remove symbolic link \"%s\": %s"),
1028+
progname,linkloc,strerror(errno));
1029+
disconnect_and_exit(1);
1030+
}
1031+
if (symlink(new_dir,linkloc)!=0)
1032+
{
1033+
fprintf(stderr,_("%s: could not create symbolic link \"%s\": %s"),
1034+
progname,linkloc,strerror(errno));
1035+
disconnect_and_exit(1);
1036+
}
1037+
}
1038+
}
1039+
1040+
9021041
/*
9031042
* Receive a tar format stream from the connection to the server, and unpack
9041043
* the contents of it into a directory. Only files, directories and
9051044
* symlinks are supported, no other kinds of special files.
9061045
*
9071046
* If the data is for the main data directory, it will be restored in the
9081047
* specified directory. If it's for another tablespace, it will be restored
909-
* in the original directory, since relocation of tablespaces is not
910-
* supported.
1048+
* in the original or mapped directory.
9111049
*/
9121050
staticvoid
9131051
ReceiveAndUnpackTarFile(PGconn*conn,PGresult*res,intrownum)
@@ -923,7 +1061,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
9231061
if (basetablespace)
9241062
strlcpy(current_path,basedir,sizeof(current_path));
9251063
else
926-
strlcpy(current_path,PQgetvalue(res,rownum,1),sizeof(current_path));
1064+
strlcpy(current_path,get_tablespace_mapping(PQgetvalue(res,rownum,1)),sizeof(current_path));
9271065

9281066
/*
9291067
* Get the COPY data
@@ -1503,7 +1641,10 @@ BaseBackup(void)
15031641
* we do anything anyway.
15041642
*/
15051643
if (format=='p'&& !PQgetisnull(res,i,1))
1506-
verify_dir_is_empty_or_create(PQgetvalue(res,i,1));
1644+
{
1645+
char*path= (char*)get_tablespace_mapping(PQgetvalue(res,i,1));
1646+
verify_dir_is_empty_or_create(path);
1647+
}
15071648
}
15081649

15091650
/*
@@ -1545,6 +1686,17 @@ BaseBackup(void)
15451686
progress_report(PQntuples(res),NULL, true);
15461687
fprintf(stderr,"\n");/* Need to move to next line */
15471688
}
1689+
1690+
if (format=='p'&&tablespace_dirs.head!=NULL)
1691+
{
1692+
for (i=0;i<PQntuples(res);i++)
1693+
{
1694+
Oidtblspc_oid=atooid(PQgetvalue(res,i,0));
1695+
if (tblspc_oid)
1696+
update_tablespace_symlink(tblspc_oid,PQgetvalue(res,i,1));
1697+
}
1698+
}
1699+
15481700
PQclear(res);
15491701

15501702
/*
@@ -1696,6 +1848,7 @@ main(int argc, char **argv)
16961848
{"format",required_argument,NULL,'F'},
16971849
{"checkpoint",required_argument,NULL,'c'},
16981850
{"write-recovery-conf",no_argument,NULL,'R'},
1851+
{"tablespace-mapping",required_argument,NULL,'T'},
16991852
{"xlog",no_argument,NULL,'x'},
17001853
{"xlog-method",required_argument,NULL,'X'},
17011854
{"gzip",no_argument,NULL,'z'},
@@ -1735,7 +1888,7 @@ main(int argc, char **argv)
17351888
}
17361889
}
17371890

1738-
while ((c=getopt_long(argc,argv,"D:F:RxX:l:zZ:d:c:h:p:U:s:wWvP",
1891+
while ((c=getopt_long(argc,argv,"D:F:RT:xX:l:zZ:d:c:h:p:U:s:wWvP",
17391892
long_options,&option_index))!=-1)
17401893
{
17411894
switch (c)
@@ -1759,6 +1912,9 @@ main(int argc, char **argv)
17591912
case'R':
17601913
writerecoveryconf= true;
17611914
break;
1915+
case'T':
1916+
tablespace_list_append(optarg);
1917+
break;
17621918
case'x':
17631919
if (includewal)
17641920
{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp