From 14bc951d30d9652bec2571fe2dcbe3f3d658a9b0 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 31 Mar 2000 19:39:22 +0000 Subject: [PATCH] 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. --- src/backend/utils/cache/relcache.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 6ed3b7414e..97ec7d300d 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 #include #include +#include #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); }