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

Commit363e8f9

Browse files
committed
Fix pg_basebackup with in-place tablespaces some more.
Commitc6f2f01 purported to makethis work, but problems remained. In a plain-format backup, thefiles from an in-place tablespace got included in the tar file forthe main tablespace, which is wrong but it's not clear that ithas any user-visible consequences. In a tar-format backup, theTABLESPACE_MAP option is used, and so we never iterated overpg_tblspc and thus never backed up the in-place tablespacesanywhere at all.To fix this, reverse the changes in that commit, so that when we scanpg_tblspc during a backup, we create tablespaceinfo objects even forin-place tablespaces. We set the field that would normally contain theabsolute pathname to the relative path pg_tblspc/${TSOID}, and that'sgood enough to make basebackup.c happy without any further changes.However, pg_basebackup needs a couple of adjustments to make it work.First, it needs to understand that a relative path for a tablespacemeans it's an in-place tablespace. Second, it needs to tolerate thesituation where restoring the main tablespace tries to createpg_tblspc or a subdirectory and finds that it already exists, becausewe restore user-defined tablespaces before the main tablespace.Since in-place tablespaces are only intended for use in developmentand testing, no back-patch.Patch by me, reviewed by Thomas Munro and Michael Paquier.Discussion:http://postgr.es/m/CA+TgmobwvbEp+fLq2PykMYzizcvuNv0a7gPMJtxOTMOuuRLMHg@mail.gmail.com
1 parentf180290 commit363e8f9

File tree

4 files changed

+159
-66
lines changed

4 files changed

+159
-66
lines changed

‎src/backend/access/transam/xlog.c

Lines changed: 63 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8454,76 +8454,92 @@ do_pg_backup_start(const char *backupidstr, bool fast, List **tablespaces,
84548454
charfullpath[MAXPGPATH+10];
84558455
charlinkpath[MAXPGPATH];
84568456
char*relpath=NULL;
8457-
intrllen;
8458-
StringInfoDataescapedpath;
84598457
char*s;
8458+
PGFileTypede_type;
84608459

84618460
/* Skip anything that doesn't look like a tablespace */
84628461
if (strspn(de->d_name,"0123456789")!=strlen(de->d_name))
84638462
continue;
84648463

84658464
snprintf(fullpath,sizeof(fullpath),"pg_tblspc/%s",de->d_name);
84668465

8467-
/*
8468-
* Skip anything that isn't a symlink/junction. For testing only,
8469-
* we sometimes use allow_in_place_tablespaces to create
8470-
* directories directly under pg_tblspc, which would fail below.
8471-
*/
8472-
if (get_dirent_type(fullpath,de, false,ERROR)!=PGFILETYPE_LNK)
8473-
continue;
8466+
de_type=get_dirent_type(fullpath,de, false,ERROR);
84748467

8475-
rllen=readlink(fullpath,linkpath,sizeof(linkpath));
8476-
if (rllen<0)
8468+
if (de_type==PGFILETYPE_LNK)
84778469
{
8478-
ereport(WARNING,
8479-
(errmsg("could not read symbolic link \"%s\": %m",
8480-
fullpath)));
8481-
continue;
8470+
StringInfoDataescapedpath;
8471+
intrllen;
8472+
8473+
rllen=readlink(fullpath,linkpath,sizeof(linkpath));
8474+
if (rllen<0)
8475+
{
8476+
ereport(WARNING,
8477+
(errmsg("could not read symbolic link \"%s\": %m",
8478+
fullpath)));
8479+
continue;
8480+
}
8481+
elseif (rllen >=sizeof(linkpath))
8482+
{
8483+
ereport(WARNING,
8484+
(errmsg("symbolic link \"%s\" target is too long",
8485+
fullpath)));
8486+
continue;
8487+
}
8488+
linkpath[rllen]='\0';
8489+
8490+
/*
8491+
* Relpath holds the relative path of the tablespace directory
8492+
* when it's located within PGDATA, or NULL if it's located
8493+
* elsewhere.
8494+
*/
8495+
if (rllen>datadirpathlen&&
8496+
strncmp(linkpath,DataDir,datadirpathlen)==0&&
8497+
IS_DIR_SEP(linkpath[datadirpathlen]))
8498+
relpath=pstrdup(linkpath+datadirpathlen+1);
8499+
8500+
/*
8501+
* Add a backslash-escaped version of the link path to the
8502+
* tablespace map file.
8503+
*/
8504+
initStringInfo(&escapedpath);
8505+
for (s=linkpath;*s;s++)
8506+
{
8507+
if (*s=='\n'||*s=='\r'||*s=='\\')
8508+
appendStringInfoChar(&escapedpath,'\\');
8509+
appendStringInfoChar(&escapedpath,*s);
8510+
}
8511+
appendStringInfo(tblspcmapfile,"%s %s\n",
8512+
de->d_name,escapedpath.data);
8513+
pfree(escapedpath.data);
84828514
}
8483-
elseif (rllen >=sizeof(linkpath))
8515+
elseif (de_type==PGFILETYPE_DIR)
84848516
{
8485-
ereport(WARNING,
8486-
(errmsg("symbolic link \"%s\" target is too long",
8487-
fullpath)));
8488-
continue;
8517+
/*
8518+
* It's possible to use allow_in_place_tablespaces to create
8519+
* directories directly under pg_tblspc, for testing purposes
8520+
* only.
8521+
*
8522+
* In this case, we store a relative path rather than an
8523+
* absolute path into the tablespaceinfo.
8524+
*/
8525+
snprintf(linkpath,sizeof(linkpath),"pg_tblspc/%s",
8526+
de->d_name);
8527+
relpath=pstrdup(linkpath);
84898528
}
8490-
linkpath[rllen]='\0';
8491-
8492-
/*
8493-
* Build a backslash-escaped version of the link path to include
8494-
* in the tablespace map file.
8495-
*/
8496-
initStringInfo(&escapedpath);
8497-
for (s=linkpath;*s;s++)
8529+
else
84988530
{
8499-
if (*s=='\n'||*s=='\r'||*s=='\\')
8500-
appendStringInfoChar(&escapedpath,'\\');
8501-
appendStringInfoChar(&escapedpath,*s);
8531+
/* Skip any other file type that appears here. */
8532+
continue;
85028533
}
85038534

8504-
/*
8505-
* Relpath holds the relative path of the tablespace directory
8506-
* when it's located within PGDATA, or NULL if it's located
8507-
* elsewhere.
8508-
*/
8509-
if (rllen>datadirpathlen&&
8510-
strncmp(linkpath,DataDir,datadirpathlen)==0&&
8511-
IS_DIR_SEP(linkpath[datadirpathlen]))
8512-
relpath=linkpath+datadirpathlen+1;
8513-
85148535
ti=palloc(sizeof(tablespaceinfo));
85158536
ti->oid=pstrdup(de->d_name);
85168537
ti->path=pstrdup(linkpath);
8517-
ti->rpath=relpath ?pstrdup(relpath) :NULL;
8538+
ti->rpath=relpath;
85188539
ti->size=-1;
85198540

85208541
if (tablespaces)
85218542
*tablespaces=lappend(*tablespaces,ti);
8522-
8523-
appendStringInfo(tblspcmapfile,"%s %s\n",
8524-
ti->oid,escapedpath.data);
8525-
8526-
pfree(escapedpath.data);
85278543
}
85288544
FreeDir(tblspcdir);
85298545

‎src/bin/pg_basebackup/bbstreamer_file.c

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -276,28 +276,49 @@ bbstreamer_extractor_content(bbstreamer *streamer, bbstreamer_member *member,
276276
}
277277
}
278278

279+
/*
280+
* Should we tolerate an already-existing directory?
281+
*
282+
* When streaming WAL, pg_wal (or pg_xlog for pre-9.6 clusters) will have been
283+
* created by the wal receiver process. Also, when the WAL directory location
284+
* was specified, pg_wal (or pg_xlog) has already been created as a symbolic
285+
* link before starting the actual backup. So just ignore creation failures
286+
* on related directories.
287+
*
288+
* If in-place tablespaces are used, pg_tblspc and subdirectories may already
289+
* exist when we get here. So tolerate that case, too.
290+
*/
291+
staticbool
292+
should_allow_existing_directory(constchar*pathname)
293+
{
294+
constchar*filename=last_dir_separator(pathname)+1;
295+
296+
if (strcmp(filename,"pg_wal")==0||
297+
strcmp(filename,"pg_xlog")==0||
298+
strcmp(filename,"archive_status")==0||
299+
strcmp(filename,"pg_tblspc")==0)
300+
return true;
301+
302+
if (strspn(filename,"0123456789")==strlen(filename))
303+
{
304+
constchar*pg_tblspc=strstr(pathname,"/pg_tblspc/");
305+
306+
returnpg_tblspc!=NULL&&pg_tblspc+11==filename;
307+
}
308+
309+
return false;
310+
}
311+
279312
/*
280313
* Create a directory.
281314
*/
282315
staticvoid
283316
extract_directory(constchar*filename,mode_tmode)
284317
{
285-
if (mkdir(filename,pg_dir_create_mode)!=0)
286-
{
287-
/*
288-
* When streaming WAL, pg_wal (or pg_xlog for pre-9.6 clusters) will
289-
* have been created by the wal receiver process. Also, when the WAL
290-
* directory location was specified, pg_wal (or pg_xlog) has already
291-
* been created as a symbolic link before starting the actual backup.
292-
* So just ignore creation failures on related directories.
293-
*/
294-
if (!((pg_str_endswith(filename,"/pg_wal")||
295-
pg_str_endswith(filename,"/pg_xlog")||
296-
pg_str_endswith(filename,"/archive_status"))&&
297-
errno==EEXIST))
298-
pg_fatal("could not create directory \"%s\": %m",
299-
filename);
300-
}
318+
if (mkdir(filename,pg_dir_create_mode)!=0&&
319+
(errno!=EEXIST|| !should_allow_existing_directory(filename)))
320+
pg_fatal("could not create directory \"%s\": %m",
321+
filename);
301322

302323
#ifndefWIN32
303324
if (chmod(filename,mode))

‎src/bin/pg_basebackup/pg_basebackup.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,9 +1122,17 @@ CreateBackupStreamer(char *archive_name, char *spclocation,
11221122
* other tablespaces will be written to the directory where they're
11231123
* located on the server, after applying any user-specified tablespace
11241124
* mappings.
1125+
*
1126+
* In the case of an in-place tablespace, spclocation will be a
1127+
* relative path. We just convert it to an absolute path by prepending
1128+
* basedir.
11251129
*/
1126-
directory=spclocation==NULL ?basedir
1127-
:get_tablespace_mapping(spclocation);
1130+
if (spclocation==NULL)
1131+
directory=basedir;
1132+
elseif (!is_absolute_path(spclocation))
1133+
directory=psprintf("%s/%s",basedir,spclocation);
1134+
else
1135+
directory=get_tablespace_mapping(spclocation);
11281136
streamer=bbstreamer_extractor_new(directory,
11291137
get_tablespace_mapping,
11301138
progress_update_filename);
@@ -1955,7 +1963,15 @@ BaseBackup(char *compression_algorithm, char *compression_detail,
19551963
*/
19561964
if (backup_target==NULL&&format=='p'&& !PQgetisnull(res,i,1))
19571965
{
1958-
char*path=unconstify(char*,get_tablespace_mapping(PQgetvalue(res,i,1)));
1966+
char*path=PQgetvalue(res,i,1);
1967+
1968+
if (is_absolute_path(path))
1969+
path=unconstify(char*,get_tablespace_mapping(path));
1970+
else
1971+
{
1972+
/* This is an in-place tablespace, so prepend basedir. */
1973+
path=psprintf("%s/%s",basedir,path);
1974+
}
19591975

19601976
verify_dir_is_empty_or_create(path,&made_tablespace_dirs,&found_tablespace_dirs);
19611977
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Copyright (c) 2021-2023, PostgreSQL Global Development Group
2+
3+
use strict;
4+
use warnings;
5+
use PostgreSQL::Test::Cluster;
6+
use PostgreSQL::Test::Utils;
7+
use Test::More;
8+
9+
my$tempdir = PostgreSQL::Test::Utils::tempdir;
10+
11+
# For nearly all pg_basebackup invocations some options should be specified,
12+
# to keep test times reasonable. Using @pg_basebackup_defs as the first
13+
# element of the array passed to IPC::Run interpolate the array (as it is
14+
# not a reference to an array)...
15+
my@pg_basebackup_defs = ('pg_basebackup','--no-sync','-cfast');
16+
17+
# Set up an instance.
18+
my$node = PostgreSQL::Test::Cluster->new('main');
19+
$node->init('allows_streaming'=> 1);
20+
$node->start();
21+
22+
# Create an in-place tablespace.
23+
$node->safe_psql('postgres',<<EOM);
24+
SET allow_in_place_tablespaces = on;
25+
CREATE TABLESPACE inplace LOCATION '';
26+
EOM
27+
28+
# Back it up.
29+
my$backupdir =$tempdir .'/backup';
30+
$node->command_ok(
31+
[@pg_basebackup_defs,'-D',$backupdir,'-Ft','-X','none' ],
32+
'pg_basebackup runs');
33+
34+
# Make sure we got base.tar and one tablespace.
35+
ok(-f"$backupdir/base.tar",'backup tar was created');
36+
my@tblspc_tars =glob"$backupdir/[0-9]*.tar";
37+
is(scalar(@tblspc_tars), 1,'one tablespace tar was created');
38+
39+
# All good.
40+
done_testing();

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp