mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-15 08:20:16 +08:00
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:
parent
dbc9346f75
commit
14bc951d30
27
src/backend/utils/cache/relcache.c
vendored
27
src/backend/utils/cache/relcache.c
vendored
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 <errno.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
@ -2266,14 +2267,26 @@ write_irels(void)
|
|||||||
int i;
|
int i;
|
||||||
int relno;
|
int relno;
|
||||||
RelationBuildDescInfo bi;
|
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__
|
#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
|
#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
|
#endif
|
||||||
if (fd < 0)
|
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);
|
FileSeek(fd, 0L, SEEK_SET);
|
||||||
|
|
||||||
@ -2397,4 +2410,10 @@ write_irels(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
FileClose(fd);
|
FileClose(fd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* And rename the temp file to its final name, deleting any previously-
|
||||||
|
* existing init file.
|
||||||
|
*/
|
||||||
|
rename(tempfilename, finalfilename);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user