Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7bdbbb8

Browse files
committed
Allow "in place" tablespaces.
This is a backpatch to branches 10-14 of the following commits: 7170f21 Allow "in place" tablespaces. c6f2f01 Fix pg_basebackup with in-place tablespaces. f6f0db4 Fix pg_tablespace_location() with in-place tablespaces 7a7cd84 doc: Remove mention to in-place tablespaces for pg_tablespace_location() 5344723 Remove unnecessary Windows-specific basebackup code. In-place tablespaces were introduced as a testing helper mechanism, but they are going to be used for a bugfix in WAL replay to be backpatched to all stable branches. I (Álvaro) had to adjust some code to account for lack of get_dirent_type() in branches prior to 14. Author: Thomas Munro <[email protected]> Author: Michaël Paquier <[email protected]> Author: Álvaro Herrera <[email protected]> Discussion: https://postgr.es/m/[email protected]
1 parent 964f42a commit 7bdbbb8

File tree

6 files changed

+114
-7
lines changed

6 files changed

+114
-7
lines changed

doc/src/sgml/config.sgml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8319,6 +8319,25 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
83198319
</para>
83208320

83218321
<variablelist>
8322+
<varlistentry id="guc-allow-in-place-tablespaces" xreflabel="allow_in_place_tablespaces">
8323+
<term><varname>allow_in_place_tablespaces</varname> (<type>boolean</type>)
8324+
<indexterm>
8325+
<primary><varname>allow_in_place_tablespaces</varname> configuration parameter</primary>
8326+
</indexterm>
8327+
</term>
8328+
<listitem>
8329+
<para>
8330+
Allows tablespaces to be created as directories inside
8331+
<filename>pg_tblspc</filename>, when an empty location string
8332+
is provided to the <command>CREATE TABLESPACE</command> command. This
8333+
is intended to allow testing replication scenarios where primary and
8334+
standby servers are running on the same machine. Such directories
8335+
are likely to confuse backup tools that expect to find only symbolic
8336+
links in that location. Only superusers can change this setting.
8337+
</para>
8338+
</listitem>
8339+
</varlistentry>
8340+
83228341
<varlistentry id="guc-allow-system-table-mods" xreflabel="allow_system_table_mods">
83238342
<term><varname>allow_system_table_mods</varname> (<type>boolean</type>)
83248343
<indexterm>

src/backend/access/transam/xlog.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10781,13 +10781,33 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
1078110781
int rllen;
1078210782
StringInfoData buflinkpath;
1078310783
char *s = linkpath;
10784+
#ifndef WIN32
10785+
struct stat st;
10786+
#endif
1078410787

1078510788
/* Skip special stuff */
1078610789
if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
1078710790
continue;
1078810791

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

10794+
/*
10795+
* Skip anything that isn't a symlink/junction. For testing only,
10796+
* we sometimes use allow_in_place_tablespaces to create
10797+
* directories directly under pg_tblspc, which would fail below.
10798+
*/
10799+
#ifndef WIN32
10800+
if (lstat(fullpath, &st) < 0)
10801+
ereport(LOG,
10802+
(errcode_for_file_access(),
10803+
errmsg("could not stat file \"%s\": %m",
10804+
fullpath)));
10805+
else if (!S_ISLNK(st.st_mode))
10806+
#else /* WIN32 */
10807+
if (!pgwin32_is_junction(fullpath))
10808+
#endif
10809+
continue;
10810+
1079110811
#if defined(HAVE_READLINK) || defined(WIN32)
1079210812
rllen = readlink(fullpath, linkpath, sizeof(linkpath));
1079310813
if (rllen < 0)

src/backend/commands/tablespace.c

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
/* GUC variables */
8888
char *default_tablespace = NULL;
8989
char *temp_tablespaces = NULL;
90+
bool allow_in_place_tablespaces = false;
9091

9192

9293
static void create_tablespace_directories(const char *location,
@@ -241,6 +242,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
241242
char *location;
242243
Oid ownerId;
243244
Datum newOptions;
245+
bool in_place;
244246

245247
/* Must be super user */
246248
if (!superuser())
@@ -266,12 +268,15 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
266268
(errcode(ERRCODE_INVALID_NAME),
267269
errmsg("tablespace location cannot contain single quotes")));
268270

271+
in_place = allow_in_place_tablespaces && strlen(location) == 0;
272+
269273
/*
270274
* Allowing relative paths seems risky
271275
*
272-
* this also helps us ensure that location is not empty or whitespace
276+
* This also helps us ensure that location is not empty or whitespace,
277+
* unless specifying a developer-only in-place tablespace.
273278
*/
274-
if (!is_absolute_path(location))
279+
if (!in_place && !is_absolute_path(location))
275280
ereport(ERROR,
276281
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
277282
errmsg("tablespace location must be an absolute path")));
@@ -565,16 +570,36 @@ create_tablespace_directories(const char *location, const Oid tablespaceoid)
565570
char *linkloc;
566571
char *location_with_version_dir;
567572
struct stat st;
573+
bool in_place;
568574

569575
linkloc = psprintf("pg_tblspc/%u", tablespaceoid);
570-
location_with_version_dir = psprintf("%s/%s", location,
576+
577+
/*
578+
* If we're asked to make an 'in place' tablespace, create the directory
579+
* directly where the symlink would normally go. This is a developer-only
580+
* option for now, to facilitate regression testing.
581+
*/
582+
in_place = strlen(location) == 0;
583+
584+
if (in_place)
585+
{
586+
if (mkdir(linkloc, S_IRWXU) < 0 && errno != EEXIST)
587+
ereport(ERROR,
588+
(errcode_for_file_access(),
589+
errmsg("could not create directory \"%s\": %m",
590+
linkloc)));
591+
}
592+
593+
location_with_version_dir = psprintf("%s/%s", in_place ? linkloc : location,
571594
TABLESPACE_VERSION_DIRECTORY);
572595

573596
/*
574597
* Attempt to coerce target directory to safe permissions. If this fails,
575-
* it doesn't exist or has the wrong owner.
598+
* it doesn't exist or has the wrong owner. Not needed for in-place mode,
599+
* because in that case we created the directory with the desired
600+
* permissions.
576601
*/
577-
if (chmod(location, S_IRWXU) != 0)
602+
if (!in_place && chmod(location, S_IRWXU) != 0)
578603
{
579604
if (errno == ENOENT)
580605
ereport(ERROR,
@@ -623,13 +648,13 @@ create_tablespace_directories(const char *location, const Oid tablespaceoid)
623648
/*
624649
* In recovery, remove old symlink, in case it points to the wrong place.
625650
*/
626-
if (InRecovery)
651+
if (!in_place && InRecovery)
627652
remove_tablespace_symlink(linkloc);
628653

629654
/*
630655
* Create the symlink under PGDATA
631656
*/
632-
if (symlink(location, linkloc) < 0)
657+
if (!in_place && symlink(location, linkloc) < 0)
633658
ereport(ERROR,
634659
(errcode_for_file_access(),
635660
errmsg("could not create symbolic link \"%s\": %m",

src/backend/utils/adt/misc.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include <sys/file.h>
1818
#include <signal.h>
19+
#include <sys/stat.h>
1920
#include <dirent.h>
2021
#include <fcntl.h>
2122
#include <math.h>
@@ -480,6 +481,9 @@ pg_tablespace_location(PG_FUNCTION_ARGS)
480481
char sourcepath[MAXPGPATH];
481482
char targetpath[MAXPGPATH];
482483
int rllen;
484+
#ifndef WIN32
485+
struct stat st;
486+
#endif
483487

484488
/*
485489
* It's useful to apply this function to pg_class.reltablespace, wherein
@@ -504,6 +508,31 @@ pg_tablespace_location(PG_FUNCTION_ARGS)
504508
*/
505509
snprintf(sourcepath, sizeof(sourcepath), "pg_tblspc/%u", tablespaceOid);
506510

511+
/*
512+
* Before reading the link, check if the source path is a link or a
513+
* junction point. Note that a directory is possible for a tablespace
514+
* created with allow_in_place_tablespaces enabled. If a directory is
515+
* found, a relative path to the data directory is returned.
516+
*/
517+
#ifdef WIN32
518+
if (!pgwin32_is_junction(sourcepath))
519+
PG_RETURN_TEXT_P(cstring_to_text(sourcepath));
520+
#else
521+
if (lstat(sourcepath, &st) < 0)
522+
{
523+
ereport(ERROR,
524+
(errcode_for_file_access(),
525+
errmsg("could not stat file \"%s\": %m",
526+
sourcepath)));
527+
}
528+
529+
if (!S_ISLNK(st.st_mode))
530+
PG_RETURN_TEXT_P(cstring_to_text(sourcepath));
531+
#endif
532+
533+
/*
534+
* In presence of a link or a junction point, return the path pointing to.
535+
*/
507536
rllen = readlink(sourcepath, targetpath, sizeof(targetpath));
508537
if (rllen < 0)
509538
ereport(ERROR,

src/backend/utils/misc/guc.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "catalog/pg_authid.h"
3838
#include "commands/async.h"
3939
#include "commands/prepare.h"
40+
#include "commands/tablespace.h"
4041
#include "commands/user.h"
4142
#include "commands/vacuum.h"
4243
#include "commands/variable.h"
@@ -1605,6 +1606,17 @@ static struct config_bool ConfigureNamesBool[] =
16051606
NULL, NULL, NULL
16061607
},
16071608

1609+
{
1610+
{"allow_in_place_tablespaces", PGC_SUSET, DEVELOPER_OPTIONS,
1611+
gettext_noop("Allows tablespaces directly inside pg_tblspc, for testing."),
1612+
NULL,
1613+
GUC_NOT_IN_SAMPLE
1614+
},
1615+
&allow_in_place_tablespaces,
1616+
false,
1617+
NULL, NULL, NULL
1618+
},
1619+
16081620
{
16091621
{"lo_compat_privileges", PGC_SUSET, COMPAT_OPTIONS_PREVIOUS,
16101622
gettext_noop("Enables backward compatibility mode for privilege checks on large objects."),

src/include/commands/tablespace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include "lib/stringinfo.h"
2020
#include "nodes/parsenodes.h"
2121

22+
extern bool allow_in_place_tablespaces;
23+
2224
/* XLOG stuff */
2325
#define XLOG_TBLSPC_CREATE 0x00
2426
#define XLOG_TBLSPC_DROP 0x10

0 commit comments

Comments
 (0)