Skip to content
Snippets Groups Projects
Commit 2a6f7ac4 authored by Tom Lane's avatar Tom Lane
Browse files

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
Branches
Tags
No related merge requests found
......@@ -28,7 +28,7 @@
*
*
* 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
*
......@@ -243,9 +243,14 @@ static void RandomSalt(char *salt);
static void SignalChildren(int signal);
static int CountChildren(void);
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);
#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 CheckPointDataBase() SSDataBase(BS_XLOG_CHECKPOINT)
......@@ -253,7 +258,6 @@ static pid_t SSDataBase(int xlop);
#ifdef USE_SSL
static void InitSSL(void);
#endif
......@@ -596,6 +600,12 @@ PostmasterMain(int argc, char *argv[])
if (!CreateDataDirLockFile(DataDir, true))
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.
*/
......@@ -613,7 +623,8 @@ PostmasterMain(int argc, char *argv[])
if (NetServer)
{
status = StreamServerPort(AF_INET, VirtualHost,
(unsigned short) PostPortNumber, UnixSocketDir,
(unsigned short) PostPortNumber,
UnixSocketDir,
&ServerSock_INET);
if (status != STATUS_OK)
{
......@@ -624,7 +635,8 @@ PostmasterMain(int argc, char *argv[])
#ifdef HAVE_UNIX_SOCKETS
status = StreamServerPort(AF_UNIX, VirtualHost,
(unsigned short) PostPortNumber, UnixSocketDir,
(unsigned short) PostPortNumber,
UnixSocketDir,
&ServerSock_UNIX);
if (status != STATUS_OK)
{
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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:
*
......@@ -44,6 +44,7 @@
#include <sys/file.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
......@@ -51,6 +52,12 @@
#include "miscadmin.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.
* This will open several extra files in addition to those used by
......@@ -189,7 +196,7 @@ static void FreeVfd(File file);
static int FileAccess(File file);
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);
/*
......@@ -568,28 +575,27 @@ FreeVfd(File file)
/* filepath()
* Convert given pathname to absolute.
*
* Result is a palloc'd string.
*
* (Generally, this isn't actually necessary, considering that we
* should be cd'd into the database directory. Presently it is only
* necessary to do it in "bootstrap" mode. Maybe we should change
* bootstrap mode to do the cd, and save a few cycles/bytes here.)
*/
static char *
filepath(char *filename)
filepath(const char *filename)
{
char *buf;
int len;
/* Not an absolute path name? Then fill in with database path... */
if (*filename != '/')
{
len = strlen(DatabasePath) + strlen(filename) + 2;
buf = (char *) palloc(len);
buf = (char *) palloc(strlen(DatabasePath) + strlen(filename) + 2);
sprintf(buf, "%s/%s", DatabasePath, filename);
}
else
{
buf = (char *) palloc(strlen(filename) + 1);
strcpy(buf, filename);
buf = pstrdup(filename);
}
#ifdef FILEDEBUG
......@@ -742,21 +748,46 @@ PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
File
OpenTemporaryFile(void)
{
char tempfilename[64];
char tempfilepath[128];
File file;
/*
* Generate a tempfile name that's unique within the current
* transaction
* transaction and database instance.
*/
snprintf(tempfilepath, sizeof(tempfilepath),
"%s/%s%d.%ld", PG_TEMP_FILES_DIR, 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,
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.
*
* 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.
*/
snprintf(tempfilename, sizeof(tempfilename),
"pg_sorttemp%d.%ld", MyProcPid, tempFileCounter++);
dirpath = filepath(PG_TEMP_FILES_DIR);
mkdir(dirpath, S_IRWXU);
pfree(dirpath);
/* Open the file */
file = FileNameOpenFile(tempfilename,
O_RDWR | O_CREAT | O_TRUNC | PG_BINARY, 0600);
file = FileNameOpenFile(tempfilepath,
O_RDWR | O_CREAT | O_TRUNC | PG_BINARY,
0600);
if (file <= 0)
elog(ERROR, "Failed to create temporary file %s", tempfilename);
elog(ERROR, "Failed to create temporary file %s", tempfilepath);
}
/* Mark it for deletion at close or EOXact */
VfdCache[file].fdstate |= FD_TEMPORARY;
......@@ -1203,3 +1234,76 @@ AtEOXact_Files(void)
*/
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 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* 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);
/* Miscellaneous support routines */
extern void closeAllVfds(void);
extern void AtEOXact_Files(void);
extern void RemovePgTempFiles(void);
extern int pg_fsync(int fd);
extern int pg_fdatasync(int fd);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment