aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/cache/relcache.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2000-03-31 19:39:22 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2000-03-31 19:39:22 +0000
commit14bc951d30d9652bec2571fe2dcbe3f3d658a9b0 (patch)
tree2f796826a88cc66f07928dd8b710d91aa9e3c8de /src/backend/utils/cache/relcache.c
parentdbc9346f75b38095d9cfd28a2d24e4c814afc076 (diff)
downloadpostgresql-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.c27
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);
}