diff options
Diffstat (limited to 'src/backend/storage')
-rw-r--r-- | src/backend/storage/file/buffile.c | 18 | ||||
-rw-r--r-- | src/backend/storage/file/fd.c | 163 |
2 files changed, 104 insertions, 77 deletions
diff --git a/src/backend/storage/file/buffile.c b/src/backend/storage/file/buffile.c index 4f3a8a311bf..6bb40558961 100644 --- a/src/backend/storage/file/buffile.c +++ b/src/backend/storage/file/buffile.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/file/buffile.c,v 1.26 2007/06/01 23:43:11 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/file/buffile.c,v 1.27 2007/06/03 17:07:30 tgl Exp $ * * NOTES: * @@ -60,6 +60,7 @@ struct BufFile * offsets[i] is the current seek position of files[i]. We use this to * avoid making redundant FileSeek calls. */ + Oid tblspcOid; /* tablespace to use (InvalidOid = default) */ bool isTemp; /* can only add files if this is TRUE */ bool isInterXact; /* keep open over transactions? */ @@ -85,7 +86,7 @@ static int BufFileFlush(BufFile *file); /* * Create a BufFile given the first underlying physical file. - * NOTE: caller must set isTemp true if appropriate. + * NOTE: caller must set tblspcOid, isTemp, isInterXact if appropriate. */ static BufFile * makeBufFile(File firstfile) @@ -97,7 +98,9 @@ makeBufFile(File firstfile) file->files[0] = firstfile; file->offsets = (long *) palloc(sizeof(long)); file->offsets[0] = 0L; + file->tblspcOid = InvalidOid; file->isTemp = false; + file->isInterXact = false; file->dirty = false; file->curFile = 0; file->curOffset = 0L; @@ -116,7 +119,7 @@ extendBufFile(BufFile *file) File pfile; Assert(file->isTemp); - pfile = OpenTemporaryFile(file->isInterXact); + pfile = OpenTemporaryFile(file->isInterXact, file->tblspcOid); Assert(pfile >= 0); file->files = (File *) repalloc(file->files, @@ -133,19 +136,24 @@ extendBufFile(BufFile *file) * multiple temporary files if more than MAX_PHYSICAL_FILESIZE bytes are * written to it). * + * If interXact is true, the temp file will not be automatically deleted + * at end of transaction. If tblspcOid is not InvalidOid, the temp file + * is created in the specified tablespace instead of the default one. + * * Note: if interXact is true, the caller had better be calling us in a * memory context that will survive across transaction boundaries. */ BufFile * -BufFileCreateTemp(bool interXact) +BufFileCreateTemp(bool interXact, Oid tblspcOid) { BufFile *file; File pfile; - pfile = OpenTemporaryFile(interXact); + pfile = OpenTemporaryFile(interXact, tblspcOid); Assert(pfile >= 0); file = makeBufFile(pfile); + file->tblspcOid = tblspcOid; file->isTemp = true; file->isInterXact = interXact; diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index 1d04caad4f2..5c1be83ed04 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.137 2007/03/06 02:06:14 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/storage/file/fd.c,v 1.138 2007/06/03 17:07:31 tgl Exp $ * * NOTES: * @@ -48,6 +48,7 @@ #include "miscadmin.h" #include "access/xact.h" +#include "catalog/pg_tablespace.h" #include "storage/fd.h" #include "storage/ipc.h" #include "utils/guc.h" @@ -225,7 +226,7 @@ static File AllocateVfd(void); static void FreeVfd(File file); static int FileAccess(File file); -static char *make_database_relative(const char *filename); +static File OpenTemporaryFileInTablespace(Oid tblspcOid, bool rejectError); static void AtProcExit_Files(int code, Datum arg); static void CleanupTempFiles(bool isProcExit); static void RemovePgTempFilesInDir(const char *tmpdirname); @@ -721,23 +722,6 @@ FreeVfd(File file) VfdCache[0].nextFree = file; } -/* - * make_database_relative() - * Prepend DatabasePath to the given file name. - * - * Result is a palloc'd string. - */ -static char * -make_database_relative(const char *filename) -{ - char *buf; - - Assert(!is_absolute_path(filename)); - buf = (char *) palloc(strlen(DatabasePath) + strlen(filename) + 2); - sprintf(buf, "%s/%s", DatabasePath, filename); - return buf; -} - /* returns 0 on success, -1 on re-open failure (with errno set) */ static int FileAccess(File file) @@ -845,24 +829,6 @@ PathNameOpenFile(FileName fileName, int fileFlags, int fileMode) } /* - * open a file in the database directory ($PGDATA/base/DIROID/) - * - * The passed name MUST be a relative path. Effectively, this - * prepends DatabasePath to it and then acts like PathNameOpenFile. - */ -File -FileNameOpenFile(FileName fileName, int fileFlags, int fileMode) -{ - File fd; - char *fname; - - fname = make_database_relative(fileName); - fd = PathNameOpenFile(fname, fileFlags, fileMode); - pfree(fname); - return fd; -} - -/* * Open a temporary file that will disappear when we close it. * * This routine takes care of generating an appropriate tempfile name. @@ -874,62 +840,110 @@ FileNameOpenFile(FileName fileName, int fileFlags, int fileMode) * that created them, so this should be false -- but if you need * "somewhat" temporary storage, this might be useful. In either case, * the file is removed when the File is explicitly closed. + * + * tblspcOid: the Oid of the tablespace where the temp file should be created. + * If InvalidOid, or if the tablespace can't be found, we silently fall back + * to the database's default tablespace. */ File -OpenTemporaryFile(bool interXact) +OpenTemporaryFile(bool interXact, Oid tblspcOid) { + File file = 0; + + /* + * If caller specified a tablespace, try to create there. + */ + if (OidIsValid(tblspcOid)) + file = OpenTemporaryFileInTablespace(tblspcOid, false); + + /* + * If not, or if tablespace is bad, create in database's default + * tablespace. MyDatabaseTableSpace should normally be set before we get + * here, but just in case it isn't, fall back to pg_default tablespace. + */ + if (file <= 0) + file = OpenTemporaryFileInTablespace(MyDatabaseTableSpace ? + MyDatabaseTableSpace : + DEFAULTTABLESPACE_OID, + true); + + /* Mark it for deletion at close */ + VfdCache[file].fdstate |= FD_TEMPORARY; + + /* Mark it for deletion at EOXact */ + if (!interXact) + { + VfdCache[file].fdstate |= FD_XACT_TEMPORARY; + VfdCache[file].create_subid = GetCurrentSubTransactionId(); + } + + return file; +} + +/* + * Open a temporary file in a specific tablespace. + * Subroutine for OpenTemporaryFile, which see for details. + */ +static File +OpenTemporaryFileInTablespace(Oid tblspcOid, bool rejectError) +{ + char tempdirpath[MAXPGPATH]; char tempfilepath[MAXPGPATH]; File file; /* + * Identify the tempfile directory for this tablespace. + * + * If someone tries to specify pg_global, use pg_default instead. + */ + if (tblspcOid == DEFAULTTABLESPACE_OID || + tblspcOid == GLOBALTABLESPACE_OID) + { + /* The default tablespace is {datadir}/base */ + snprintf(tempdirpath, sizeof(tempdirpath), "base/%s", + PG_TEMP_FILES_DIR); + } + else + { + /* All other tablespaces are accessed via symlinks */ + snprintf(tempdirpath, sizeof(tempdirpath), "pg_tblspc/%u/%s", + tblspcOid, 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", PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX, - MyProcPid, tempFileCounter++); + snprintf(tempfilepath, sizeof(tempfilepath), "%s/%s%d.%ld", + tempdirpath, PG_TEMP_FILE_PREFIX, MyProcPid, tempFileCounter++); /* * Open the file. Note: we don't use O_EXCL, in case there is an orphaned * temp file that can be reused. */ - file = FileNameOpenFile(tempfilepath, + file = PathNameOpenFile(tempfilepath, O_RDWR | O_CREAT | O_TRUNC | PG_BINARY, 0600); if (file <= 0) { - char *dirpath; - /* - * We might need to create the pg_tempfiles subdirectory, if no one - * has yet done so. + * We might need to create the tablespace's tempfile directory, + * if no one has yet done so. * * Don't check for error from mkdir; it could fail if someone else * just did the same thing. If it doesn't work then we'll bomb out on * the second create attempt, instead. */ - dirpath = make_database_relative(PG_TEMP_FILES_DIR); - mkdir(dirpath, S_IRWXU); - pfree(dirpath); + mkdir(tempdirpath, S_IRWXU); - file = FileNameOpenFile(tempfilepath, + file = PathNameOpenFile(tempfilepath, O_RDWR | O_CREAT | O_TRUNC | PG_BINARY, 0600); - if (file <= 0) + if (file <= 0 && rejectError) elog(ERROR, "could not create temporary file \"%s\": %m", tempfilepath); } - /* Mark it for deletion at close */ - VfdCache[file].fdstate |= FD_TEMPORARY; - - /* Mark it for deletion at EOXact */ - if (!interXact) - { - VfdCache[file].fdstate |= FD_XACT_TEMPORARY; - VfdCache[file].create_subid = GetCurrentSubTransactionId(); - } - return file; } @@ -1643,27 +1657,32 @@ void RemovePgTempFiles(void) { char temp_path[MAXPGPATH]; - DIR *db_dir; - struct dirent *db_de; + DIR *spc_dir; + struct dirent *spc_de; + + /* + * First process temp files in pg_default ($PGDATA/base) + */ + snprintf(temp_path, sizeof(temp_path), "base/%s", PG_TEMP_FILES_DIR); + RemovePgTempFilesInDir(temp_path); /* - * Cycle through pgsql_tmp directories for all databases and remove old - * temp files. + * Cycle through temp directories for all non-default tablespaces. */ - db_dir = AllocateDir("base"); + spc_dir = AllocateDir("pg_tblspc"); - while ((db_de = ReadDir(db_dir, "base")) != NULL) + while ((spc_de = ReadDir(spc_dir, "pg_tblspc")) != NULL) { - if (strcmp(db_de->d_name, ".") == 0 || - strcmp(db_de->d_name, "..") == 0) + if (strcmp(spc_de->d_name, ".") == 0 || + strcmp(spc_de->d_name, "..") == 0) continue; - snprintf(temp_path, sizeof(temp_path), "base/%s/%s", - db_de->d_name, PG_TEMP_FILES_DIR); + snprintf(temp_path, sizeof(temp_path), "pg_tblspc/%s/%s", + spc_de->d_name, PG_TEMP_FILES_DIR); RemovePgTempFilesInDir(temp_path); } - FreeDir(db_dir); + FreeDir(spc_dir); /* * In EXEC_BACKEND case there is a pgsql_tmp directory at the top level of |