Allow "in place" tablespaces.

Provide a developer-only GUC allow_in_place_tablespaces, disabled by
default.  When enabled, tablespaces can be created with an empty
LOCATION string, meaning that they should be created as a directory
directly beneath pg_tblspc.  This can be used for new testing scenarios,
in a follow-up patch.  Not intended for end-user usage, since it might
confuse backup tools that expect symlinks.

Reviewed-by: Andres Freund <andres@anarazel.de>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/CA%2BhUKGKpRWQ9SxdxxDmTBCJoR0YnFpMBe7kyzY8SUQk%2BHeskxg%40mail.gmail.com
This commit is contained in:
Thomas Munro 2022-01-14 21:27:44 +13:00
parent c4cc2850f4
commit 7170f2159f
4 changed files with 65 additions and 7 deletions

View File

@ -10433,6 +10433,25 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</para>
<variablelist>
<varlistentry id="guc-allow-in-place-tablespaces" xreflabel="allow_in_place_tablespaces">
<term><varname>allow_in_place_tablespaces</varname> (<type>boolean</type>)
<indexterm>
<primary><varname>allow_in_place_tablespaces</varname> configuration parameter</primary>
</indexterm>
</term>
<listitem>
<para>
Allows tablespaces to be created as directories inside
<filename>pg_tblspc</filename>, when an empty location string
is provided to the <command>CREATE TABLESPACE</command> command. This
is intended to allow testing replication scenarios where primary and
standby servers are running on the same machine. Such directories
are likely to confuse backup tools that expect to find only symbolic
links in that location. Only superusers can change this setting.
</para>
</listitem>
</varlistentry>
<varlistentry id="guc-allow-system-table-mods" xreflabel="allow_system_table_mods">
<term><varname>allow_system_table_mods</varname> (<type>boolean</type>)
<indexterm>

View File

@ -87,6 +87,7 @@
/* GUC variables */
char *default_tablespace = NULL;
char *temp_tablespaces = NULL;
bool allow_in_place_tablespaces = false;
static void create_tablespace_directories(const char *location,
@ -241,6 +242,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
char *location;
Oid ownerId;
Datum newOptions;
bool in_place;
/* Must be superuser */
if (!superuser())
@ -266,12 +268,15 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
(errcode(ERRCODE_INVALID_NAME),
errmsg("tablespace location cannot contain single quotes")));
in_place = allow_in_place_tablespaces && strlen(location) == 0;
/*
* Allowing relative paths seems risky
*
* this also helps us ensure that location is not empty or whitespace
* This also helps us ensure that location is not empty or whitespace,
* unless specifying a developer-only in-place tablespace.
*/
if (!is_absolute_path(location))
if (!in_place && !is_absolute_path(location))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("tablespace location must be an absolute path")));
@ -590,16 +595,36 @@ create_tablespace_directories(const char *location, const Oid tablespaceoid)
char *linkloc;
char *location_with_version_dir;
struct stat st;
bool in_place;
linkloc = psprintf("pg_tblspc/%u", tablespaceoid);
location_with_version_dir = psprintf("%s/%s", location,
/*
* If we're asked to make an 'in place' tablespace, create the directory
* directly where the symlink would normally go. This is a developer-only
* option for now, to facilitate regression testing.
*/
in_place = strlen(location) == 0;
if (in_place)
{
if (MakePGDirectory(linkloc) < 0 && errno != EEXIST)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not create directory \"%s\": %m",
linkloc)));
}
location_with_version_dir = psprintf("%s/%s", in_place ? linkloc : location,
TABLESPACE_VERSION_DIRECTORY);
/*
* Attempt to coerce target directory to safe permissions. If this fails,
* it doesn't exist or has the wrong owner.
* it doesn't exist or has the wrong owner. Not needed for in-place mode,
* because in that case we created the directory with the desired
* permissions.
*/
if (chmod(location, pg_dir_create_mode) != 0)
if (!in_place && chmod(location, pg_dir_create_mode) != 0)
{
if (errno == ENOENT)
ereport(ERROR,
@ -648,13 +673,13 @@ create_tablespace_directories(const char *location, const Oid tablespaceoid)
/*
* In recovery, remove old symlink, in case it points to the wrong place.
*/
if (InRecovery)
if (!in_place && InRecovery)
remove_tablespace_symlink(linkloc);
/*
* Create the symlink under PGDATA
*/
if (symlink(location, linkloc) < 0)
if (!in_place && symlink(location, linkloc) < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not create symbolic link \"%s\": %m",

View File

@ -46,6 +46,7 @@
#include "catalog/storage.h"
#include "commands/async.h"
#include "commands/prepare.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
#include "commands/user.h"
#include "commands/vacuum.h"
@ -1961,6 +1962,17 @@ static struct config_bool ConfigureNamesBool[] =
NULL, NULL, NULL
},
{
{"allow_in_place_tablespaces", PGC_SUSET, DEVELOPER_OPTIONS,
gettext_noop("Allows tablespaces directly inside pg_tblspc, for testing."),
NULL,
GUC_NOT_IN_SAMPLE
},
&allow_in_place_tablespaces,
false,
NULL, NULL, NULL
},
{
{"lo_compat_privileges", PGC_SUSET, COMPAT_OPTIONS_PREVIOUS,
gettext_noop("Enables backward compatibility mode for privilege checks on large objects."),

View File

@ -19,6 +19,8 @@
#include "lib/stringinfo.h"
#include "nodes/parsenodes.h"
extern bool allow_in_place_tablespaces;
/* XLOG stuff */
#define XLOG_TBLSPC_CREATE 0x00
#define XLOG_TBLSPC_DROP 0x10