Re: [HACKERS] [COMMITTERS] pgsql: Add GUC temp_tablespaces to provide a default location for - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: [HACKERS] [COMMITTERS] pgsql: Add GUC temp_tablespaces to provide a default location for
Date
Msg-id 200703060208.l2628sl08031@momjian.us
Whole thread Raw
Responses Re: Re: [HACKERS] [COMMITTERS] pgsql: Add GUC temp_tablespaces to provide a default location for  (Bruce Momjian <bruce@momjian.us>)
List pgsql-patches
OK, patch reverted.  Authors, would you please resubmit with fixes?
Thanks.

---------------------------------------------------------------------------

Tom Lane wrote:
> momjian@postgresql.org (Bruce Momjian) writes:
> > Add GUC temp_tablespaces to provide a default location for temporary
> > objects.
> > Jaime Casanova
>
> I hadn't looked at this patch before, but now that I have, it is
> rather broken.
>
> In the first place, it makes no provision for RemovePgTempFiles() to
> clean up leftover temp files that are in non-default places.
>
> In the second place, it's a serious violation of what little modularity
> and layering we have for fd.c to be calling into commands/tablespace.c.
> This is not merely cosmetic but has real consequences: one being that
> it's now unsafe to call OpenTemporaryFile outside a transaction.
>
> Please revert until the submitter can come up with a better-designed
> patch.
>
>             regards, tom lane
>
> ---------------------------(end of broadcast)---------------------------
> TIP 4: Have you searched our list archives?
>
>                http://archives.postgresql.org

--
  Bruce Momjian  <bruce@momjian.us>          http://momjian.us
  EnterpriseDB                               http://www.enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +
Index: doc/src/sgml/config.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/config.sgml,v
retrieving revision 1.104
retrieving revision 1.105
diff -c -r1.104 -r1.105
*** doc/src/sgml/config.sgml    20 Jan 2007 21:30:26 -0000    1.104
--- doc/src/sgml/config.sgml    25 Jan 2007 04:35:10 -0000    1.105
***************
*** 3398,3403 ****
--- 3398,3432 ----
        </listitem>
       </varlistentry>

+      <varlistentry id="guc-temp-tablespaces" xreflabel="temp_tablespaces">
+       <term><varname>temp_tablespaces</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>temp_tablespaces</> configuration parameter</primary>
+       </indexterm>
+       <indexterm><primary>tablespace</><secondary>temp</></>
+       <listitem>
+        <para>
+         This variable specifies tablespaces in which to create temp
+         objects (temp tables and indexes on temp tables) when a
+         <command>CREATE</> command does not explicitly specify a tablespace
+         and temp files when necessary (eg. for sorting operations).
+        </para>
+
+        <para>
+         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,
+         <productname>PostgreSQL</> will automatically use the default
+         tablespace of the current database.
+        </para>
+
+        <para>
+         For more information on tablespaces,
+         see <xref linkend="manage-ag-tablespaces">.
+        </para>
+       </listitem>
+      </varlistentry>
+
       <varlistentry id="guc-check-function-bodies" xreflabel="check_function_bodies">
        <term><varname>check_function_bodies</varname> (<type>boolean</type>)</term>
        <indexterm>
Index: src/backend/commands/indexcmds.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v
retrieving revision 1.153
retrieving revision 1.154
diff -c -r1.153 -r1.154
*** src/backend/commands/indexcmds.c    20 Jan 2007 23:13:01 -0000    1.153
--- src/backend/commands/indexcmds.c    25 Jan 2007 04:35:10 -0000    1.154
***************
*** 209,215 ****
      }
      else
      {
!         tablespaceId = GetDefaultTablespace();
          /* note InvalidOid is OK in this case */
      }

--- 209,221 ----
      }
      else
      {
!          /*
!           * 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 */
      }

Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v
retrieving revision 1.211
retrieving revision 1.212
diff -c -r1.211 -r1.212
*** src/backend/commands/tablecmds.c    25 Jan 2007 04:17:45 -0000    1.211
--- src/backend/commands/tablecmds.c    25 Jan 2007 04:35:10 -0000    1.212
***************
*** 334,339 ****
--- 334,343 ----
                       errmsg("tablespace \"%s\" does not exist",
                              stmt->tablespacename)));
      }
+     else if (stmt->relation->istemp)
+     {
+         tablespaceId = GetTempTablespace();
+     }
      else
      {
          tablespaceId = GetDefaultTablespace();
Index: src/backend/commands/tablespace.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/tablespace.c,v
retrieving revision 1.40
retrieving revision 1.41
diff -c -r1.40 -r1.41
*** src/backend/commands/tablespace.c    5 Jan 2007 22:19:26 -0000    1.40
--- src/backend/commands/tablespace.c    25 Jan 2007 04:35:10 -0000    1.41
***************
*** 65,73 ****
  #include "utils/lsyscache.h"


! /* GUC variable */
  char       *default_tablespace = NULL;


  static bool remove_tablespace_directories(Oid tablespaceoid, bool redo);
  static void set_short_version(const char *path);
--- 65,76 ----
  #include "utils/lsyscache.h"


! /* 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,935 ****
--- 933,1074 ----
      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
Index: src/backend/executor/execMain.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/executor/execMain.c,v
retrieving revision 1.284
retrieving revision 1.285
diff -c -r1.284 -r1.285
*** src/backend/executor/execMain.c    25 Jan 2007 02:17:26 -0000    1.284
--- src/backend/executor/execMain.c    25 Jan 2007 04:35:10 -0000    1.285
***************
*** 2409,2414 ****
--- 2409,2418 ----
                       errmsg("tablespace \"%s\" does not exist",
                              parseTree->intoTableSpaceName)));
      }
+     else if (parseTree->into->istemp)
+     {
+         tablespaceId = GetTempTablespace();
+     }
      else
      {
          tablespaceId = GetDefaultTablespace();
Index: src/backend/storage/file/fd.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/storage/file/fd.c,v
retrieving revision 1.134
retrieving revision 1.135
diff -c -r1.134 -r1.135
*** src/backend/storage/file/fd.c    9 Jan 2007 22:03:51 -0000    1.134
--- src/backend/storage/file/fd.c    25 Jan 2007 04:35:10 -0000    1.135
***************
*** 46,51 ****
--- 46,53 ----
  #include <unistd.h>
  #include <fcntl.h>

+ #include "commands/tablespace.h"
+
  #include "miscadmin.h"
  #include "access/xact.h"
  #include "storage/fd.h"
***************
*** 76,81 ****
--- 78,84 ----
   */
  #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,892 ****
  {
      char        tempfilepath[MAXPGPATH];
      File        file;

      /*
!      * Generate a tempfile name that should be unique within the current
!      * database instance.
       */
!     snprintf(tempfilepath, sizeof(tempfilepath),
!              "%s/%s%d.%ld", PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX,
               MyProcPid, tempFileCounter++);

      /*
--- 883,933 ----
  {
      char        tempfilepath[MAXPGPATH];
      File        file;
+     Oid        oid;
+     char        *path;
+     int        pathlen;

      /*
!      * Take a look what should be the path of the temporary file
       */
!     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,924 ****
          if (file <= 0)
              elog(ERROR, "could not create temporary file \"%s\": %m",
                   tempfilepath);
!     }

      /* Mark it for deletion at close */
      VfdCache[file].fdstate |= FD_TEMPORARY;
--- 959,966 ----
          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,1297 ****
--- 1334,1353 ----
          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;
  }

Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.369
retrieving revision 1.370
diff -c -r1.369 -r1.370
*** src/backend/utils/misc/guc.c    19 Jan 2007 16:58:46 -0000    1.369
--- src/backend/utils/misc/guc.c    25 Jan 2007 04:35:11 -0000    1.370
***************
*** 99,104 ****
--- 99,105 ----
  extern int    CommitDelay;
  extern int    CommitSiblings;
  extern char *default_tablespace;
+ extern char *temp_tablespaces;
  extern bool fullPageWrites;

  #ifdef TRACE_SORT
***************
*** 2291,2296 ****
--- 2292,2307 ----
          "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
Index: src/backend/utils/misc/postgresql.conf.sample
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/misc/postgresql.conf.sample,v
retrieving revision 1.204
retrieving revision 1.205
diff -c -r1.204 -r1.205
*** src/backend/utils/misc/postgresql.conf.sample    20 Jan 2007 21:42:03 -0000    1.204
--- src/backend/utils/misc/postgresql.conf.sample    25 Jan 2007 04:35:11 -0000    1.205
***************
*** 399,404 ****
--- 399,406 ----
  #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
Index: src/include/commands/tablespace.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/commands/tablespace.h,v
retrieving revision 1.14
retrieving revision 1.15
diff -c -r1.14 -r1.15
*** src/include/commands/tablespace.h    5 Jan 2007 22:19:54 -0000    1.14
--- src/include/commands/tablespace.h    25 Jan 2007 04:35:11 -0000    1.15
***************
*** 41,46 ****
--- 41,47 ----
  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);
Index: src/include/utils/guc.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/utils/guc.h,v
retrieving revision 1.78
retrieving revision 1.79
diff -c -r1.78 -r1.79
*** src/include/utils/guc.h    9 Jan 2007 21:31:17 -0000    1.78
--- src/include/utils/guc.h    25 Jan 2007 04:35:11 -0000    1.79
***************
*** 238,241 ****
--- 238,245 ----
  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 */

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: [HACKERS] [CORE] GPL Source and Copyright Questions
Next
From: "Marc G. Fournier"
Date:
Subject: Re: [HACKERS]