diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2000-03-31 19:39:22 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2000-03-31 19:39:22 +0000 |
commit | 14bc951d30d9652bec2571fe2dcbe3f3d658a9b0 (patch) | |
tree | 2f796826a88cc66f07928dd8b710d91aa9e3c8de /src/backend/utils/cache/relcache.c | |
parent | dbc9346f75b38095d9cfd28a2d24e4c814afc076 (diff) | |
download | postgresql-14bc951d30d9652bec2571fe2dcbe3f3d658a9b0.tar.gz postgresql-14bc951d30d9652bec2571fe2dcbe3f3d658a9b0.zip |
Fix low-probability bug in relcache startup: write_irels wrote the
pg_internal.init file in-place, which meant that if another backend
started at about the same time, it might read the incomplete file.
init_irels tries to guard against that, but I have now seen a crash
due to reading bad data from a partly-written file. (This may indicate
a kernel bug on my platform? Not sure.) Anyway, clearly the safest
course is to write the new pg_internal.init file under a unique temporary
filename, and rename it into place only after it's all written.
Diffstat (limited to 'src/backend/utils/cache/relcache.c')
-rw-r--r-- | src/backend/utils/cache/relcache.c | 27 |
1 files changed, 23 insertions, 4 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 6ed3b7414ed..97ec7d300d1 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.93 2000/03/17 02:36:27 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.94 2000/03/31 19:39:22 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -33,6 +33,7 @@ #include <errno.h> #include <sys/file.h> #include <fcntl.h> +#include <unistd.h> #include "postgres.h" @@ -2266,14 +2267,26 @@ write_irels(void) int i; int relno; RelationBuildDescInfo bi; + char tempfilename[MAXPGPATH]; + char finalfilename[MAXPGPATH]; + + /* + * We must write a temporary file and rename it into place. Otherwise, + * another backend starting at about the same time might crash trying to + * read the partially-complete file. + */ + snprintf(tempfilename, sizeof(tempfilename), "%s%c%s.%d", + DatabasePath, SEP_CHAR, RELCACHE_INIT_FILENAME, MyProcPid); + snprintf(finalfilename, sizeof(finalfilename), "%s%c%s", + DatabasePath, SEP_CHAR, RELCACHE_INIT_FILENAME); #ifndef __CYGWIN32__ - fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_WRONLY | O_CREAT | O_TRUNC, 0600); + fd = PathNameOpenFile(tempfilename, O_WRONLY | O_CREAT | O_TRUNC, 0600); #else - fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600); + fd = PathNameOpenFile(tempfilename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600); #endif if (fd < 0) - elog(FATAL, "cannot create init file %s", RELCACHE_INIT_FILENAME); + elog(FATAL, "cannot create init file %s", tempfilename); FileSeek(fd, 0L, SEEK_SET); @@ -2397,4 +2410,10 @@ write_irels(void) } FileClose(fd); + + /* + * And rename the temp file to its final name, deleting any previously- + * existing init file. + */ + rename(tempfilename, finalfilename); } |