Skip to content

Commit 24ee8af

Browse files
committed
Rework temp_tablespaces patch so that temp tablespaces are assigned separately
for each temp file, rather than once per sort or hashjoin; this allows spreading the data of a large sort or join across multiple tablespaces. (I remain dubious that this will make any difference in practice, but certain people insisted.) Arrange to cache the results of parsing the GUC variable instead of recomputing from scratch on every demand, and push usage of the cache down to the bottommost fd.c level.
1 parent 2d9d7a6 commit 24ee8af

File tree

14 files changed

+283
-168
lines changed

14 files changed

+283
-168
lines changed

doc/src/sgml/config.sgml

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.125 2007/06/03 17:05:29 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.126 2007/06/07 19:19:56 tgl Exp $ -->
22

33
<chapter Id="runtime-config">
44
<title>Server Configuration</title>
@@ -3510,16 +3510,22 @@ SELECT * FROM parent WHERE key = 2400;
35103510
<para>
35113511
The value is a list of names of tablespaces. When there is more than
35123512
one name in the list, <productname>PostgreSQL</> chooses a random
3513-
member of the list each time a temporary object is to be created.
3513+
member of the list each time a temporary object is to be created;
3514+
except that within a transaction, successively created temporary
3515+
objects are placed in successive tablespaces from the list.
3516+
If any element of the list is an empty string,
3517+
<productname>PostgreSQL</> will automatically use the default
3518+
tablespace of the current database instead.
35143519
</para>
35153520

35163521
<para>
3517-
If any element of the list is an empty string or does not match the
3518-
name of any existing tablespace, <productname>PostgreSQL</> will
3519-
automatically use the default tablespace of the current database
3520-
instead. If a nondefault tablespace
3521-
is specified, the user must have <literal>CREATE</> privilege
3522-
for it, or creation attempts will fail.
3522+
When <varname>temp_tablespaces</> is set interactively, specifying a
3523+
nonexistent tablespace is an error, as is specifying a tablespace for
3524+
which the user does not have <literal>CREATE</> privilege. However,
3525+
when using a previously set value, nonexistent tablespaces are
3526+
ignored, as are tablespaces for which the user lacks
3527+
<literal>CREATE</> privilege. In particular, this rule applies when
3528+
using a value set in <filename>postgresql.conf</>.
35233529
</para>
35243530

35253531
<para>

src/backend/commands/tablespace.c

Lines changed: 130 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
*
3838
*
3939
* IDENTIFICATION
40-
* $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.47 2007/06/03 17:06:59 tgl Exp $
40+
* $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.48 2007/06/07 19:19:56 tgl Exp $
4141
*
4242
*-------------------------------------------------------------------------
4343
*/
@@ -63,6 +63,7 @@
6363
#include "utils/fmgroids.h"
6464
#include "utils/guc.h"
6565
#include "utils/lsyscache.h"
66+
#include "utils/memutils.h"
6667

6768

6869
/* GUC variables */
@@ -72,7 +73,6 @@ char *temp_tablespaces = NULL;
7273

7374
static bool remove_tablespace_directories(Oid tablespaceoid, bool redo);
7475
static void set_short_version(const char *path);
75-
static Oid getTempTablespace(void);
7676

7777

7878
/*
@@ -921,9 +921,12 @@ GetDefaultTablespace(bool forTemp)
921921
{
922922
Oid result;
923923

924-
/* The temp-table case is handled by getTempTablespace() */
924+
/* The temp-table case is handled elsewhere */
925925
if (forTemp)
926-
return getTempTablespace();
926+
{
927+
PrepareTempTablespaces();
928+
return GetNextTempTableSpace();
929+
}
927930

928931
/* Fast path for default_tablespace == "" */
929932
if (default_tablespace == NULL || default_tablespace[0] == '\0')
@@ -958,7 +961,6 @@ assign_temp_tablespaces(const char *newval, bool doit, GucSource source)
958961
{
959962
char *rawname;
960963
List *namelist;
961-
ListCell *l;
962964

963965
/* Need a modifiable copy of string */
964966
rawname = pstrdup(newval);
@@ -975,24 +977,79 @@ assign_temp_tablespaces(const char *newval, bool doit, GucSource source)
975977
/*
976978
* If we aren't inside a transaction, we cannot do database access so
977979
* cannot verify the individual names. Must accept the list on faith.
980+
* Fortunately, there's then also no need to pass the data to fd.c.
978981
*/
979-
if (source >= PGC_S_INTERACTIVE && IsTransactionState())
982+
if (IsTransactionState())
980983
{
984+
/*
985+
* If we error out below, or if we are called multiple times in one
986+
* transaction, we'll leak a bit of TopTransactionContext memory.
987+
* Doesn't seem worth worrying about.
988+
*/
989+
Oid *tblSpcs;
990+
int numSpcs;
991+
ListCell *l;
992+
993+
tblSpcs = (Oid *) MemoryContextAlloc(TopTransactionContext,
994+
list_length(namelist) * sizeof(Oid));
995+
numSpcs = 0;
981996
foreach(l, namelist)
982997
{
983998
char *curname = (char *) lfirst(l);
999+
Oid curoid;
1000+
AclResult aclresult;
9841001

9851002
/* Allow an empty string (signifying database default) */
9861003
if (curname[0] == '\0')
1004+
{
1005+
tblSpcs[numSpcs++] = InvalidOid;
9871006
continue;
1007+
}
9881008

9891009
/* Else verify that name is a valid tablespace name */
990-
if (get_tablespace_oid(curname) == InvalidOid)
991-
ereport(ERROR,
992-
(errcode(ERRCODE_UNDEFINED_OBJECT),
993-
errmsg("tablespace \"%s\" does not exist",
994-
curname)));
1010+
curoid = get_tablespace_oid(curname);
1011+
if (curoid == InvalidOid)
1012+
{
1013+
/*
1014+
* In an interactive SET command, we ereport for bad info.
1015+
* Otherwise, silently ignore any bad list elements.
1016+
*/
1017+
if (source >= PGC_S_INTERACTIVE)
1018+
ereport(ERROR,
1019+
(errcode(ERRCODE_UNDEFINED_OBJECT),
1020+
errmsg("tablespace \"%s\" does not exist",
1021+
curname)));
1022+
continue;
1023+
}
1024+
1025+
/*
1026+
* Allow explicit specification of database's default tablespace
1027+
* in temp_tablespaces without triggering permissions checks.
1028+
*/
1029+
if (curoid == MyDatabaseTableSpace)
1030+
{
1031+
tblSpcs[numSpcs++] = InvalidOid;
1032+
continue;
1033+
}
1034+
1035+
/* Check permissions similarly */
1036+
aclresult = pg_tablespace_aclcheck(curoid, GetUserId(),
1037+
ACL_CREATE);
1038+
if (aclresult != ACLCHECK_OK)
1039+
{
1040+
if (source >= PGC_S_INTERACTIVE)
1041+
aclcheck_error(aclresult, ACL_KIND_TABLESPACE, curname);
1042+
continue;
1043+
}
1044+
1045+
tblSpcs[numSpcs++] = curoid;
9951046
}
1047+
1048+
/* If actively "doing it", give the new list to fd.c */
1049+
if (doit)
1050+
SetTempTablespaces(tblSpcs, numSpcs);
1051+
else
1052+
pfree(tblSpcs);
9961053
}
9971054

9981055
pfree(rawname);
@@ -1002,69 +1059,34 @@ assign_temp_tablespaces(const char *newval, bool doit, GucSource source)
10021059
}
10031060

10041061
/*
1005-
* GetTempTablespace -- get the OID of the next temp tablespace to use
1006-
*
1007-
* May return InvalidOid to indicate "use the database's default tablespace".
1062+
* PrepareTempTablespaces -- prepare to use temp tablespaces
10081063
*
1009-
* This is different from GetDefaultTablespace(true) in just two ways:
1010-
* 1. We check privileges here instead of leaving it to the caller.
1011-
* 2. It's safe to call this outside a transaction (we just return InvalidOid).
1012-
* The transaction state check is used so that this can be called from
1013-
* low-level places that might conceivably run outside a transaction.
1064+
* If we have not already done so in the current transaction, parse the
1065+
* temp_tablespaces GUC variable and tell fd.c which tablespace(s) to use
1066+
* for temp files.
10141067
*/
1015-
Oid
1016-
GetTempTablespace(void)
1017-
{
1018-
Oid result;
1019-
1020-
/* Can't do catalog access unless within a transaction */
1021-
if (!IsTransactionState())
1022-
return InvalidOid;
1023-
1024-
/* OK, select a temp tablespace */
1025-
result = getTempTablespace();
1026-
1027-
/* Check permissions except when using database's default */
1028-
if (OidIsValid(result))
1029-
{
1030-
AclResult aclresult;
1031-
1032-
aclresult = pg_tablespace_aclcheck(result, GetUserId(),
1033-
ACL_CREATE);
1034-
if (aclresult != ACLCHECK_OK)
1035-
aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
1036-
get_tablespace_name(result));
1037-
}
1038-
1039-
return result;
1040-
}
1041-
1042-
/*
1043-
* getTempTablespace -- get the OID of the next temp tablespace to use
1044-
*
1045-
* This has exactly the API defined for GetDefaultTablespace(true),
1046-
* in particular that caller is responsible for permissions checks.
1047-
*
1048-
* This exists to hide (and possibly optimize the use of) the
1049-
* temp_tablespaces GUC variable.
1050-
*/
1051-
static Oid
1052-
getTempTablespace(void)
1068+
void
1069+
PrepareTempTablespaces(void)
10531070
{
1054-
Oid result;
10551071
char *rawname;
10561072
List *namelist;
1057-
int nnames;
1058-
char *curname;
1073+
Oid *tblSpcs;
1074+
int numSpcs;
1075+
ListCell *l;
10591076

1060-
if (temp_tablespaces == NULL)
1061-
return InvalidOid;
1077+
/* No work if already done in current transaction */
1078+
if (TempTablespacesAreSet())
1079+
return;
10621080

10631081
/*
1064-
* We re-parse the string on each call; this is a bit expensive, but
1065-
* we don't expect this function will be called many times per query,
1066-
* so it's probably not worth being tenser.
1082+
* Can't do catalog access unless within a transaction. This is just
1083+
* a safety check in case this function is called by low-level code that
1084+
* could conceivably execute outside a transaction. Note that in such
1085+
* a scenario, fd.c will fall back to using the current database's default
1086+
* tablespace, which should always be OK.
10671087
*/
1088+
if (!IsTransactionState())
1089+
return;
10681090

10691091
/* Need a modifiable copy of string */
10701092
rawname = pstrdup(temp_tablespaces);
@@ -1073,51 +1095,60 @@ getTempTablespace(void)
10731095
if (!SplitIdentifierString(rawname, ',', &namelist))
10741096
{
10751097
/* syntax error in name list */
1098+
SetTempTablespaces(NULL, 0);
10761099
pfree(rawname);
10771100
list_free(namelist);
1078-
return InvalidOid;
1101+
return;
10791102
}
1080-
nnames = list_length(namelist);
10811103

1082-
/* Fast path for temp_tablespaces == "" */
1083-
if (nnames == 0)
1104+
/* Store tablespace OIDs in an array in TopTransactionContext */
1105+
tblSpcs = (Oid *) MemoryContextAlloc(TopTransactionContext,
1106+
list_length(namelist) * sizeof(Oid));
1107+
numSpcs = 0;
1108+
foreach(l, namelist)
10841109
{
1085-
pfree(rawname);
1086-
list_free(namelist);
1087-
return InvalidOid;
1088-
}
1110+
char *curname = (char *) lfirst(l);
1111+
Oid curoid;
1112+
AclResult aclresult;
10891113

1090-
/* Select a random element */
1091-
if (nnames == 1) /* no need for a random() call */
1092-
curname = (char *) linitial(namelist);
1093-
else
1094-
curname = (char *) list_nth(namelist, random() % nnames);
1114+
/* Allow an empty string (signifying database default) */
1115+
if (curname[0] == '\0')
1116+
{
1117+
tblSpcs[numSpcs++] = InvalidOid;
1118+
continue;
1119+
}
10951120

1096-
/*
1097-
* Empty string means "database's default", else look up the tablespace.
1098-
*
1099-
* It is tempting to cache this lookup for more speed, but then we would
1100-
* fail to detect the case where the tablespace was dropped since the GUC
1101-
* variable was set. Note also that we don't complain if the value fails
1102-
* to refer to an existing tablespace; we just silently return InvalidOid,
1103-
* causing the new object to be created in the database's tablespace.
1104-
*/
1105-
if (curname[0] == '\0')
1106-
result = InvalidOid;
1107-
else
1108-
result = get_tablespace_oid(curname);
1121+
/* Else verify that name is a valid tablespace name */
1122+
curoid = get_tablespace_oid(curname);
1123+
if (curoid == InvalidOid)
1124+
{
1125+
/* Silently ignore any bad list elements */
1126+
continue;
1127+
}
11091128

1110-
/*
1111-
* Allow explicit specification of database's default tablespace in
1112-
* temp_tablespaces without triggering permissions checks.
1113-
*/
1114-
if (result == MyDatabaseTableSpace)
1115-
result = InvalidOid;
1129+
/*
1130+
* Allow explicit specification of database's default tablespace
1131+
* in temp_tablespaces without triggering permissions checks.
1132+
*/
1133+
if (curoid == MyDatabaseTableSpace)
1134+
{
1135+
tblSpcs[numSpcs++] = InvalidOid;
1136+
continue;
1137+
}
1138+
1139+
/* Check permissions similarly */
1140+
aclresult = pg_tablespace_aclcheck(curoid, GetUserId(),
1141+
ACL_CREATE);
1142+
if (aclresult != ACLCHECK_OK)
1143+
continue;
1144+
1145+
tblSpcs[numSpcs++] = curoid;
1146+
}
1147+
1148+
SetTempTablespaces(tblSpcs, numSpcs);
11161149

11171150
pfree(rawname);
11181151
list_free(namelist);
1119-
1120-
return result;
11211152
}
11221153

11231154

0 commit comments

Comments
 (0)