Commit 2a6f7ac4 authored by Tom Lane's avatar Tom Lane

Move temporary files into 'pg_tempfiles' subdirectory of each database

directory (which can be made a symlink to put temp files on another disk).
Add code to delete leftover temp files during postmaster startup.
Bruce, with some kibitzing from Tom.
parent 6f2182fe
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.217 2001/06/07 04:50:57 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.218 2001/06/11 04:12:29 tgl Exp $
* *
* NOTES * NOTES
* *
...@@ -243,9 +243,14 @@ static void RandomSalt(char *salt); ...@@ -243,9 +243,14 @@ static void RandomSalt(char *salt);
static void SignalChildren(int signal); static void SignalChildren(int signal);
static int CountChildren(void); static int CountChildren(void);
static bool CreateOptsFile(int argc, char *argv[]); static bool CreateOptsFile(int argc, char *argv[]);
static void postmaster_error(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
static pid_t SSDataBase(int xlop); static pid_t SSDataBase(int xlop);
#ifdef __GNUC__
/* This checks the format string for consistency. */
static void postmaster_error(const char *fmt, ...)
__attribute__((format(printf, 1, 2)));
#else
static void postmaster_error(const char *fmt, ...);
#endif
#define StartupDataBase() SSDataBase(BS_XLOG_STARTUP) #define StartupDataBase() SSDataBase(BS_XLOG_STARTUP)
#define CheckPointDataBase() SSDataBase(BS_XLOG_CHECKPOINT) #define CheckPointDataBase() SSDataBase(BS_XLOG_CHECKPOINT)
...@@ -253,7 +258,6 @@ static pid_t SSDataBase(int xlop); ...@@ -253,7 +258,6 @@ static pid_t SSDataBase(int xlop);
#ifdef USE_SSL #ifdef USE_SSL
static void InitSSL(void); static void InitSSL(void);
#endif #endif
...@@ -596,6 +600,12 @@ PostmasterMain(int argc, char *argv[]) ...@@ -596,6 +600,12 @@ PostmasterMain(int argc, char *argv[])
if (!CreateDataDirLockFile(DataDir, true)) if (!CreateDataDirLockFile(DataDir, true))
ExitPostmaster(1); ExitPostmaster(1);
/*
* Remove old temporary files. At this point there can be no other
* Postgres processes running in this directory, so this should be safe.
*/
RemovePgTempFiles();
/* /*
* Establish input sockets. * Establish input sockets.
*/ */
...@@ -613,7 +623,8 @@ PostmasterMain(int argc, char *argv[]) ...@@ -613,7 +623,8 @@ PostmasterMain(int argc, char *argv[])
if (NetServer) if (NetServer)
{ {
status = StreamServerPort(AF_INET, VirtualHost, status = StreamServerPort(AF_INET, VirtualHost,
(unsigned short) PostPortNumber, UnixSocketDir, (unsigned short) PostPortNumber,
UnixSocketDir,
&ServerSock_INET); &ServerSock_INET);
if (status != STATUS_OK) if (status != STATUS_OK)
{ {
...@@ -624,7 +635,8 @@ PostmasterMain(int argc, char *argv[]) ...@@ -624,7 +635,8 @@ PostmasterMain(int argc, char *argv[])
#ifdef HAVE_UNIX_SOCKETS #ifdef HAVE_UNIX_SOCKETS
status = StreamServerPort(AF_UNIX, VirtualHost, status = StreamServerPort(AF_UNIX, VirtualHost,
(unsigned short) PostPortNumber, UnixSocketDir, (unsigned short) PostPortNumber,
UnixSocketDir,
&ServerSock_UNIX); &ServerSock_UNIX);
if (status != STATUS_OK) if (status != STATUS_OK)
{ {
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/file/fd.c,v 1.80 2001/06/06 17:07:46 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/file/fd.c,v 1.81 2001/06/11 04:12:29 tgl Exp $
* *
* NOTES: * NOTES:
* *
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include <sys/file.h> #include <sys/file.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <dirent.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
...@@ -51,6 +52,12 @@ ...@@ -51,6 +52,12 @@
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/fd.h" #include "storage/fd.h"
/* Filename components for OpenTemporaryFile */
#define PG_TEMP_FILES_DIR "pg_tempfiles"
#define PG_TEMP_FILE_PREFIX "pg_temp"
/* /*
* Problem: Postgres does a system(ld...) to do dynamic loading. * Problem: Postgres does a system(ld...) to do dynamic loading.
* This will open several extra files in addition to those used by * This will open several extra files in addition to those used by
...@@ -189,7 +196,7 @@ static void FreeVfd(File file); ...@@ -189,7 +196,7 @@ static void FreeVfd(File file);
static int FileAccess(File file); static int FileAccess(File file);
static File fileNameOpenFile(FileName fileName, int fileFlags, int fileMode); static File fileNameOpenFile(FileName fileName, int fileFlags, int fileMode);
static char *filepath(char *filename); static char *filepath(const char *filename);
static long pg_nofile(void); static long pg_nofile(void);
/* /*
...@@ -568,28 +575,27 @@ FreeVfd(File file) ...@@ -568,28 +575,27 @@ FreeVfd(File file)
/* filepath() /* filepath()
* Convert given pathname to absolute. * Convert given pathname to absolute.
* *
* Result is a palloc'd string.
*
* (Generally, this isn't actually necessary, considering that we * (Generally, this isn't actually necessary, considering that we
* should be cd'd into the database directory. Presently it is only * should be cd'd into the database directory. Presently it is only
* necessary to do it in "bootstrap" mode. Maybe we should change * necessary to do it in "bootstrap" mode. Maybe we should change
* bootstrap mode to do the cd, and save a few cycles/bytes here.) * bootstrap mode to do the cd, and save a few cycles/bytes here.)
*/ */
static char * static char *
filepath(char *filename) filepath(const char *filename)
{ {
char *buf; char *buf;
int len;
/* Not an absolute path name? Then fill in with database path... */ /* Not an absolute path name? Then fill in with database path... */
if (*filename != '/') if (*filename != '/')
{ {
len = strlen(DatabasePath) + strlen(filename) + 2; buf = (char *) palloc(strlen(DatabasePath) + strlen(filename) + 2);
buf = (char *) palloc(len);
sprintf(buf, "%s/%s", DatabasePath, filename); sprintf(buf, "%s/%s", DatabasePath, filename);
} }
else else
{ {
buf = (char *) palloc(strlen(filename) + 1); buf = pstrdup(filename);
strcpy(buf, filename);
} }
#ifdef FILEDEBUG #ifdef FILEDEBUG
...@@ -742,21 +748,46 @@ PathNameOpenFile(FileName fileName, int fileFlags, int fileMode) ...@@ -742,21 +748,46 @@ PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
File File
OpenTemporaryFile(void) OpenTemporaryFile(void)
{ {
char tempfilename[64]; char tempfilepath[128];
File file; File file;
/* /*
* Generate a tempfile name that's unique within the current * Generate a tempfile name that's unique within the current
* transaction * transaction and database instance.
*/ */
snprintf(tempfilename, sizeof(tempfilename), snprintf(tempfilepath, sizeof(tempfilepath),
"pg_sorttemp%d.%ld", MyProcPid, tempFileCounter++); "%s/%s%d.%ld", PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX,
MyProcPid, tempFileCounter++);
/* Open the file */ /*
file = FileNameOpenFile(tempfilename, * Open the file. Note: we don't use O_EXCL, in case there is an
O_RDWR | O_CREAT | O_TRUNC | PG_BINARY, 0600); * orphaned temp file that can be reused.
*/
file = FileNameOpenFile(tempfilepath,
O_RDWR | O_CREAT | O_TRUNC | PG_BINARY,
0600);
if (file <= 0) if (file <= 0)
elog(ERROR, "Failed to create temporary file %s", tempfilename); {
char *dirpath;
/*
* We might need to create the pg_tempfiles subdirectory, 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 = filepath(PG_TEMP_FILES_DIR);
mkdir(dirpath, S_IRWXU);
pfree(dirpath);
file = FileNameOpenFile(tempfilepath,
O_RDWR | O_CREAT | O_TRUNC | PG_BINARY,
0600);
if (file <= 0)
elog(ERROR, "Failed to create temporary file %s", tempfilepath);
}
/* Mark it for deletion at close or EOXact */ /* Mark it for deletion at close or EOXact */
VfdCache[file].fdstate |= FD_TEMPORARY; VfdCache[file].fdstate |= FD_TEMPORARY;
...@@ -1203,3 +1234,76 @@ AtEOXact_Files(void) ...@@ -1203,3 +1234,76 @@ AtEOXact_Files(void)
*/ */
tempFileCounter = 0; tempFileCounter = 0;
} }
/*
* Remove old temporary files
*
* This should be called during postmaster startup. It will forcibly
* remove any leftover files created by OpenTemporaryFile.
*/
void
RemovePgTempFiles(void)
{
char db_path[MAXPGPATH];
char temp_path[MAXPGPATH];
char rm_path[MAXPGPATH];
DIR *db_dir;
DIR *temp_dir;
struct dirent *db_de;
struct dirent *temp_de;
/*
* Cycle through pg_tempfiles for all databases
* and remove old temp files.
*/
snprintf(db_path, sizeof(db_path), "%s/base", DataDir);
if ((db_dir = opendir(db_path)) != NULL)
{
while ((db_de = readdir(db_dir)) != NULL)
{
if (strcmp(db_de->d_name, ".") == 0 ||
strcmp(db_de->d_name, "..") == 0)
continue;
snprintf(temp_path, sizeof(temp_path),
"%s/%s/%s",
db_path, db_de->d_name,
PG_TEMP_FILES_DIR);
if ((temp_dir = opendir(temp_path)) != NULL)
{
while ((temp_de = readdir(temp_dir)) != NULL)
{
if (strcmp(temp_de->d_name, ".") == 0 ||
strcmp(temp_de->d_name, "..") == 0)
continue;
snprintf(rm_path, sizeof(temp_path),
"%s/%s/%s/%s",
db_path, db_de->d_name,
PG_TEMP_FILES_DIR,
temp_de->d_name);
if (strncmp(temp_de->d_name,
PG_TEMP_FILE_PREFIX,
strlen(PG_TEMP_FILE_PREFIX)) == 0)
{
unlink(rm_path);
}
else
{
/*
* would prefer to use elog here, but it's not
* up and running during postmaster startup...
*/
fprintf(stderr,
"Unexpected file found in temporary-files directory: %s\n",
rm_path);
}
}
closedir(temp_dir);
}
}
closedir(db_dir);
}
}
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: fd.h,v 1.29 2001/05/25 15:45:34 momjian Exp $ * $Id: fd.h,v 1.30 2001/06/11 04:12:29 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -70,6 +70,7 @@ extern int BasicOpenFile(FileName fileName, int fileFlags, int fileMode); ...@@ -70,6 +70,7 @@ extern int BasicOpenFile(FileName fileName, int fileFlags, int fileMode);
/* Miscellaneous support routines */ /* Miscellaneous support routines */
extern void closeAllVfds(void); extern void closeAllVfds(void);
extern void AtEOXact_Files(void); extern void AtEOXact_Files(void);
extern void RemovePgTempFiles(void);
extern int pg_fsync(int fd); extern int pg_fsync(int fd);
extern int pg_fdatasync(int fd); extern int pg_fdatasync(int fd);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment