|
7 | 7 | * Portions Copyright (c) 1994, Regents of the University of California
|
8 | 8 | *
|
9 | 9 | * IDENTIFICATION
|
10 |
| - * $Header: /cvsroot/pgsql/src/backend/storage/file/fd.c,v 1.80 2001/06/06 17:07:46 tgl Exp $ |
| 10 | + * $Header: /cvsroot/pgsql/src/backend/storage/file/fd.c,v 1.81 2001/06/11 04:12:29 tgl Exp $ |
11 | 11 | *
|
12 | 12 | * NOTES:
|
13 | 13 | *
|
|
44 | 44 | #include<sys/file.h>
|
45 | 45 | #include<sys/param.h>
|
46 | 46 | #include<sys/stat.h>
|
| 47 | +#include<dirent.h> |
47 | 48 | #include<errno.h>
|
48 | 49 | #include<unistd.h>
|
49 | 50 | #include<fcntl.h>
|
50 | 51 |
|
51 | 52 | #include"miscadmin.h"
|
52 | 53 | #include"storage/fd.h"
|
53 | 54 |
|
| 55 | + |
| 56 | +/* Filename components for OpenTemporaryFile */ |
| 57 | +#definePG_TEMP_FILES_DIR "pg_tempfiles" |
| 58 | +#definePG_TEMP_FILE_PREFIX "pg_temp" |
| 59 | + |
| 60 | + |
54 | 61 | /*
|
55 | 62 | * Problem: Postgres does a system(ld...) to do dynamic loading.
|
56 | 63 | * This will open several extra files in addition to those used by
|
@@ -189,7 +196,7 @@ static void FreeVfd(File file);
|
189 | 196 |
|
190 | 197 | staticintFileAccess(Filefile);
|
191 | 198 | staticFilefileNameOpenFile(FileNamefileName,intfileFlags,intfileMode);
|
192 |
| -staticchar*filepath(char*filename); |
| 199 | +staticchar*filepath(constchar*filename); |
193 | 200 | staticlongpg_nofile(void);
|
194 | 201 |
|
195 | 202 | /*
|
@@ -568,28 +575,27 @@ FreeVfd(File file)
|
568 | 575 | /* filepath()
|
569 | 576 | * Convert given pathname to absolute.
|
570 | 577 | *
|
| 578 | + * Result is a palloc'd string. |
| 579 | + * |
571 | 580 | * (Generally, this isn't actually necessary, considering that we
|
572 | 581 | * should be cd'd into the database directory. Presently it is only
|
573 | 582 | * necessary to do it in "bootstrap" mode.Maybe we should change
|
574 | 583 | * bootstrap mode to do the cd, and save a few cycles/bytes here.)
|
575 | 584 | */
|
576 | 585 | staticchar*
|
577 |
| -filepath(char*filename) |
| 586 | +filepath(constchar*filename) |
578 | 587 | {
|
579 | 588 | char*buf;
|
580 |
| -intlen; |
581 | 589 |
|
582 | 590 | /* Not an absolute path name? Then fill in with database path... */
|
583 | 591 | if (*filename!='/')
|
584 | 592 | {
|
585 |
| -len=strlen(DatabasePath)+strlen(filename)+2; |
586 |
| -buf= (char*)palloc(len); |
| 593 | +buf= (char*)palloc(strlen(DatabasePath)+strlen(filename)+2); |
587 | 594 | sprintf(buf,"%s/%s",DatabasePath,filename);
|
588 | 595 | }
|
589 | 596 | else
|
590 | 597 | {
|
591 |
| -buf= (char*)palloc(strlen(filename)+1); |
592 |
| -strcpy(buf,filename); |
| 598 | +buf=pstrdup(filename); |
593 | 599 | }
|
594 | 600 |
|
595 | 601 | #ifdefFILEDEBUG
|
@@ -742,21 +748,46 @@ PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
|
742 | 748 | File
|
743 | 749 | OpenTemporaryFile(void)
|
744 | 750 | {
|
745 |
| -chartempfilename[64]; |
| 751 | +chartempfilepath[128]; |
746 | 752 | Filefile;
|
747 | 753 |
|
748 | 754 | /*
|
749 | 755 | * Generate a tempfile name that's unique within the current
|
750 |
| - * transaction |
| 756 | + * transaction and database instance. |
751 | 757 | */
|
752 |
| -snprintf(tempfilename,sizeof(tempfilename), |
753 |
| -"pg_sorttemp%d.%ld",MyProcPid,tempFileCounter++); |
| 758 | +snprintf(tempfilepath,sizeof(tempfilepath), |
| 759 | +"%s/%s%d.%ld",PG_TEMP_FILES_DIR,PG_TEMP_FILE_PREFIX, |
| 760 | +MyProcPid,tempFileCounter++); |
754 | 761 |
|
755 |
| -/* Open the file */ |
756 |
| -file=FileNameOpenFile(tempfilename, |
757 |
| -O_RDWR |O_CREAT |O_TRUNC |PG_BINARY,0600); |
| 762 | +/* |
| 763 | + * Open the file. Note: we don't use O_EXCL, in case there is an |
| 764 | + * orphaned temp file that can be reused. |
| 765 | + */ |
| 766 | +file=FileNameOpenFile(tempfilepath, |
| 767 | +O_RDWR |O_CREAT |O_TRUNC |PG_BINARY, |
| 768 | +0600); |
758 | 769 | if (file <=0)
|
759 |
| -elog(ERROR,"Failed to create temporary file %s",tempfilename); |
| 770 | +{ |
| 771 | +char*dirpath; |
| 772 | + |
| 773 | +/* |
| 774 | + * We might need to create the pg_tempfiles subdirectory, if |
| 775 | + * no one has yet done so. |
| 776 | + * |
| 777 | + * Don't check for error from mkdir; it could fail if someone else |
| 778 | + * just did the same thing. If it doesn't work then we'll bomb out |
| 779 | + * on the second create attempt, instead. |
| 780 | + */ |
| 781 | +dirpath=filepath(PG_TEMP_FILES_DIR); |
| 782 | +mkdir(dirpath,S_IRWXU); |
| 783 | +pfree(dirpath); |
| 784 | + |
| 785 | +file=FileNameOpenFile(tempfilepath, |
| 786 | +O_RDWR |O_CREAT |O_TRUNC |PG_BINARY, |
| 787 | +0600); |
| 788 | +if (file <=0) |
| 789 | +elog(ERROR,"Failed to create temporary file %s",tempfilepath); |
| 790 | +} |
760 | 791 |
|
761 | 792 | /* Mark it for deletion at close or EOXact */
|
762 | 793 | VfdCache[file].fdstate |=FD_TEMPORARY;
|
@@ -1203,3 +1234,76 @@ AtEOXact_Files(void)
|
1203 | 1234 | */
|
1204 | 1235 | tempFileCounter=0;
|
1205 | 1236 | }
|
| 1237 | + |
| 1238 | + |
| 1239 | +/* |
| 1240 | + * Remove old temporary files |
| 1241 | + * |
| 1242 | + * This should be called during postmaster startup. It will forcibly |
| 1243 | + * remove any leftover files created by OpenTemporaryFile. |
| 1244 | + */ |
| 1245 | +void |
| 1246 | +RemovePgTempFiles(void) |
| 1247 | +{ |
| 1248 | +chardb_path[MAXPGPATH]; |
| 1249 | +chartemp_path[MAXPGPATH]; |
| 1250 | +charrm_path[MAXPGPATH]; |
| 1251 | +DIR*db_dir; |
| 1252 | +DIR*temp_dir; |
| 1253 | +structdirent*db_de; |
| 1254 | +structdirent*temp_de; |
| 1255 | + |
| 1256 | +/* |
| 1257 | + * Cycle through pg_tempfiles for all databases |
| 1258 | + * and remove old temp files. |
| 1259 | + */ |
| 1260 | +snprintf(db_path,sizeof(db_path),"%s/base",DataDir); |
| 1261 | +if ((db_dir=opendir(db_path))!=NULL) |
| 1262 | +{ |
| 1263 | +while ((db_de=readdir(db_dir))!=NULL) |
| 1264 | +{ |
| 1265 | +if (strcmp(db_de->d_name,".")==0|| |
| 1266 | +strcmp(db_de->d_name,"..")==0) |
| 1267 | +continue; |
| 1268 | + |
| 1269 | +snprintf(temp_path,sizeof(temp_path), |
| 1270 | +"%s/%s/%s", |
| 1271 | +db_path,db_de->d_name, |
| 1272 | +PG_TEMP_FILES_DIR); |
| 1273 | +if ((temp_dir=opendir(temp_path))!=NULL) |
| 1274 | +{ |
| 1275 | +while ((temp_de=readdir(temp_dir))!=NULL) |
| 1276 | +{ |
| 1277 | +if (strcmp(temp_de->d_name,".")==0|| |
| 1278 | +strcmp(temp_de->d_name,"..")==0) |
| 1279 | +continue; |
| 1280 | + |
| 1281 | +snprintf(rm_path,sizeof(temp_path), |
| 1282 | +"%s/%s/%s/%s", |
| 1283 | +db_path,db_de->d_name, |
| 1284 | +PG_TEMP_FILES_DIR, |
| 1285 | +temp_de->d_name); |
| 1286 | + |
| 1287 | +if (strncmp(temp_de->d_name, |
| 1288 | +PG_TEMP_FILE_PREFIX, |
| 1289 | +strlen(PG_TEMP_FILE_PREFIX))==0) |
| 1290 | +{ |
| 1291 | +unlink(rm_path); |
| 1292 | +} |
| 1293 | +else |
| 1294 | +{ |
| 1295 | +/* |
| 1296 | + * would prefer to use elog here, but it's not |
| 1297 | + * up and running during postmaster startup... |
| 1298 | + */ |
| 1299 | +fprintf(stderr, |
| 1300 | +"Unexpected file found in temporary-files directory: %s\n", |
| 1301 | +rm_path); |
| 1302 | +} |
| 1303 | +} |
| 1304 | +closedir(temp_dir); |
| 1305 | +} |
| 1306 | +} |
| 1307 | +closedir(db_dir); |
| 1308 | +} |
| 1309 | +} |