|
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 | +} |