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.
This commit is contained in:
Tom Lane 2000-03-31 19:39:22 +00:00
parent dbc9346f75
commit 14bc951d30
1 changed files with 23 additions and 4 deletions

View File

@ -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);
}