From 148ea5cbeae1681ef06e7f3ccb554b8db728b45e Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Thu, 25 Jan 2007 04:35:11 +0000 Subject: [PATCH] Add GUC temp_tablespaces to provide a default location for temporary objects. Jaime Casanova --- doc/src/sgml/config.sgml | 31 +++- src/backend/commands/indexcmds.c | 10 +- src/backend/commands/tablecmds.c | 6 +- src/backend/commands/tablespace.c | 143 +++++++++++++++++- src/backend/executor/execMain.c | 6 +- src/backend/storage/file/fd.c | 68 ++++++++- src/backend/utils/misc/guc.c | 13 +- src/backend/utils/misc/postgresql.conf.sample | 2 + src/include/commands/tablespace.h | 3 +- src/include/utils/guc.h | 6 +- 10 files changed, 272 insertions(+), 16 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 7088c5e9d8..94fc8fd79a 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -1,4 +1,4 @@ - + Server Configuration @@ -3398,6 +3398,35 @@ SELECT * FROM parent WHERE key = 2400; + + temp_tablespaces (string) + + temp_tablespaces configuration parameter + + tablespacetemp + + + This variable specifies tablespaces in which to create temp + objects (temp tables and indexes on temp tables) when a + CREATE command does not explicitly specify a tablespace + and temp files when necessary (eg. for sorting operations). + + + + The value is either a list of names of tablespaces, or an empty + string to specify using the default tablespace of the current database. + If the value does not match the name of any existing tablespace, + PostgreSQL will automatically use the default + tablespace of the current database. + + + + For more information on tablespaces, + see . + + + + check_function_bodies (boolean) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 2d51dfb11f..a718312711 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.153 2007/01/20 23:13:01 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.154 2007/01/25 04:35:10 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -209,7 +209,13 @@ DefineIndex(RangeVar *heapRelation, } else { - tablespaceId = GetDefaultTablespace(); + /* + * if the target table is temporary then use a temp_tablespace + */ + if (!rel->rd_istemp) + tablespaceId = GetDefaultTablespace(); + else + tablespaceId = GetTempTablespace(); /* note InvalidOid is OK in this case */ } diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index ced08506bc..a11cde3647 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.211 2007/01/25 04:17:45 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.212 2007/01/25 04:35:10 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -334,6 +334,10 @@ DefineRelation(CreateStmt *stmt, char relkind) errmsg("tablespace \"%s\" does not exist", stmt->tablespacename))); } + else if (stmt->relation->istemp) + { + tablespaceId = GetTempTablespace(); + } else { tablespaceId = GetDefaultTablespace(); diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index cd86aef401..d2cb245f15 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.40 2007/01/05 22:19:26 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.41 2007/01/25 04:35:10 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -65,9 +65,12 @@ #include "utils/lsyscache.h" -/* GUC variable */ +/* GUC variables */ char *default_tablespace = NULL; +char *temp_tablespaces = NULL; +int next_temp_tablespace; +int num_temp_tablespaces; static bool remove_tablespace_directories(Oid tablespaceoid, bool redo); static void set_short_version(const char *path); @@ -930,6 +933,142 @@ GetDefaultTablespace(void) return result; } +/* + * Routines for handling the GUC variable 'temp_tablespaces'. + */ + +/* assign_hook: validate new temp_tablespaces, do extra actions as needed */ +const char * +assign_temp_tablespaces(const char *newval, bool doit, GucSource source) +{ + char *rawname; + List *namelist; + ListCell *l; + + /* Need a modifiable copy of string */ + rawname = pstrdup(newval); + + /* Parse string into list of identifiers */ + if (!SplitIdentifierString(rawname, ',', &namelist)) + { + /* syntax error in name list */ + pfree(rawname); + list_free(namelist); + return NULL; + } + + num_temp_tablespaces = 0; + foreach(l, namelist) + { + char *curname = (char *) lfirst(l); + + /* + * If we aren't inside a transaction, we cannot do database access so + * cannot verify the individual names. Must accept the list on faith. + */ + if (source >= PGC_S_INTERACTIVE && IsTransactionState()) + { + /* + * Verify that all the names are valid tablspace names + * We do not check for USAGE rights should we? + */ + if (get_tablespace_oid(curname) == InvalidOid) + ereport((source == PGC_S_TEST) ? NOTICE : ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tablespace \"%s\" does not exist", curname))); + } + num_temp_tablespaces++; + } + + /* + * Select the first tablespace to use + */ + next_temp_tablespace = MyProcPid % num_temp_tablespaces; + + pfree(rawname); + list_free(namelist); + return newval; +} + +/* + * GetTempTablespace -- get the OID of the tablespace for temporary objects + * + * May return InvalidOid to indicate "use the database's default tablespace" + * + * This exists to hide the temp_tablespace GUC variable. + */ +Oid +GetTempTablespace(void) +{ + Oid result; + char *curname = NULL; + char *rawname; + List *namelist; + ListCell *l; + int i = 0; + + if ( temp_tablespaces == NULL ) + return InvalidOid; + + /* Need a modifiable version of temp_tablespaces */ + rawname = pstrdup(temp_tablespaces); + + /* Parse string into list of identifiers */ + if (!SplitIdentifierString(rawname, ',', &namelist)) + { + /* syntax error in name list */ + pfree(rawname); + list_free(namelist); + return InvalidOid; + } + + /* + * Iterate through the list of namespaces until the one we need + * (next_temp_tablespace) + */ + foreach(l, namelist) + { + curname = (char *) lfirst(l); + if ( i == next_temp_tablespace ) + break; + i++; + } + + + /* Prepare for the next time the function is called */ + next_temp_tablespace++; + if (next_temp_tablespace == num_temp_tablespaces) + next_temp_tablespace = 0; + + /* Fast path for temp_tablespaces == "" */ + if ( curname == NULL || curname[0] == '\0') { + list_free(namelist); + pfree(rawname); + return InvalidOid; + } + + /* + * It is tempting to cache this lookup for more speed, but then we would + * fail to detect the case where the tablespace was dropped since the GUC + * variable was set. Note also that we don't complain if the value fails + * to refer to an existing tablespace; we just silently return InvalidOid, + * causing the new object to be created in the database's tablespace. + */ + result = get_tablespace_oid(curname); + + /* We don't free rawname before because curname points to a part of it */ + pfree(rawname); + + /* + * Allow explicit specification of database's default tablespace in + * default_tablespace without triggering permissions checks. + */ + if (result == MyDatabaseTableSpace) + result = InvalidOid; + + list_free(namelist); + return result; +} /* * get_tablespace_oid - given a tablespace name, look up the OID diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 06bc519dde..29916550af 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -26,7 +26,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.284 2007/01/25 02:17:26 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.285 2007/01/25 04:35:10 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -2409,6 +2409,10 @@ OpenIntoRel(QueryDesc *queryDesc) errmsg("tablespace \"%s\" does not exist", parseTree->intoTableSpaceName))); } + else if (parseTree->into->istemp) + { + tablespaceId = GetTempTablespace(); + } else { tablespaceId = GetDefaultTablespace(); diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index 53ba25115a..486dd06bdc 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/file/fd.c,v 1.134 2007/01/09 22:03:51 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/storage/file/fd.c,v 1.135 2007/01/25 04:35:10 momjian Exp $ * * NOTES: * @@ -46,6 +46,8 @@ #include #include +#include "commands/tablespace.h" + #include "miscadmin.h" #include "access/xact.h" #include "storage/fd.h" @@ -76,6 +78,7 @@ */ #define FD_MINFREE 10 +#define OIDCHARS 10 /* max chars printed by %u */ /* * A number of platforms allow individual processes to open many more files @@ -880,13 +883,51 @@ OpenTemporaryFile(bool interXact) { char tempfilepath[MAXPGPATH]; File file; + Oid oid; + char *path; + int pathlen; /* - * Generate a tempfile name that should be unique within the current - * database instance. + * Take a look what should be the path of the temporary file */ - snprintf(tempfilepath, sizeof(tempfilepath), - "%s/%s%d.%ld", PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX, + oid = GetTempTablespace(); + if (oid != InvalidOid) + { + /* + * As we got a valid tablespace, try to create the + * file there + */ + + pathlen = strlen("pg_tblspc/") + OIDCHARS + 1; + path = (char *) palloc(pathlen); + snprintf(path, pathlen, "pg_tblspc/%u", oid ); + + /* + * Generate a tempfile name that should be unique within the current + * database instance. + */ + snprintf(tempfilepath, sizeof(tempfilepath), + "%s/%s%d.%ld", path, PG_TEMP_FILE_PREFIX, + MyProcPid, tempFileCounter++); + pfree(path); + file = PathNameOpenFile(tempfilepath, + O_RDWR | O_CREAT | O_TRUNC | PG_BINARY, + 0600); + } + + /* + * Create a normal temporary file if no tablespace returned or + * couldn't create the file in the tablespace "oid" + */ + if (oid == InvalidOid || file <= 0) + { + path = PG_TEMP_FILES_DIR; + /* + * Generate a tempfile name that should be unique within the current + * database instance. + */ + snprintf(tempfilepath, sizeof(tempfilepath), + "%s/%s%d.%ld", path, PG_TEMP_FILE_PREFIX, MyProcPid, tempFileCounter++); /* @@ -918,7 +959,8 @@ OpenTemporaryFile(bool interXact) if (file <= 0) elog(ERROR, "could not create temporary file \"%s\": %m", tempfilepath); - } + } + } /* Mark it for deletion at close */ VfdCache[file].fdstate |= FD_TEMPORARY; @@ -1292,6 +1334,20 @@ TryAgain: errno = save_errno; } + /* + * TEMPORARY hack to log the Windows error code on fopen failures, in + * hopes of diagnosing some hard-to-reproduce problems. + */ +#ifdef WIN32 + { + int save_errno = errno; + + elog(LOG, "Windows fopen(\"%s\",\"%s\") failed: code %lu, errno %d", + name, mode, GetLastError(), save_errno); + errno = save_errno; + } +#endif + return NULL; } diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 7962c992ac..9f2cdc43f7 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut . * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.369 2007/01/19 16:58:46 petere Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.370 2007/01/25 04:35:11 momjian Exp $ * *-------------------------------------------------------------------- */ @@ -99,6 +99,7 @@ extern bool Log_disconnections; extern int CommitDelay; extern int CommitSiblings; extern char *default_tablespace; +extern char *temp_tablespaces; extern bool fullPageWrites; #ifdef TRACE_SORT @@ -2291,6 +2292,16 @@ static struct config_string ConfigureNamesString[] = "base64", assign_xmlbinary, NULL }, + { + {"temp_tablespaces", PGC_USERSET, PGC_S_FILE, + gettext_noop("Sets the tablespaces suitable for creating new objects and sort files."), + NULL, + GUC_LIST_INPUT | GUC_LIST_QUOTE + }, + &temp_tablespaces, + NULL, assign_temp_tablespaces, NULL + }, + /* End-of-list marker */ { {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 5e6ecacb74..3b9730c75b 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -399,6 +399,8 @@ #search_path = '"$user",public' # schema names #default_tablespace = '' # a tablespace name, '' uses # the default +#temp_tablespaces = '' # a list of tablespace names, + # '' uses default_tablespace #check_function_bodies = on #default_transaction_isolation = 'read committed' #default_transaction_read_only = off diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h index 7456eb2445..6d3a333cf2 100644 --- a/src/include/commands/tablespace.h +++ b/src/include/commands/tablespace.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/commands/tablespace.h,v 1.14 2007/01/05 22:19:54 momjian Exp $ + * $PostgreSQL: pgsql/src/include/commands/tablespace.h,v 1.15 2007/01/25 04:35:11 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -41,6 +41,7 @@ extern void AlterTableSpaceOwner(const char *name, Oid newOwnerId); extern void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo); extern Oid GetDefaultTablespace(void); +extern Oid GetTempTablespace(void); extern Oid get_tablespace_oid(const char *tablespacename); extern char *get_tablespace_name(Oid spc_oid); diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index d324d66c22..51cc05a7a7 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -7,7 +7,7 @@ * Copyright (c) 2000-2007, PostgreSQL Global Development Group * Written by Peter Eisentraut . * - * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.78 2007/01/09 21:31:17 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.79 2007/01/25 04:35:11 momjian Exp $ *-------------------------------------------------------------------- */ #ifndef GUC_H @@ -238,4 +238,8 @@ extern const char *assign_search_path(const char *newval, extern const char *assign_xlog_sync_method(const char *method, bool doit, GucSource source); +/* in commands/tablespace.c */ +extern const char *assign_temp_tablespaces(const char *newval, + bool doit, GucSource source); + #endif /* GUC_H */