aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2022-07-27 11:12:15 -0400
committerRobert Haas <rhaas@postgresql.org>2022-07-27 11:12:15 -0400
commita2e97cb2b6fb64c3ca3198f5c5f31190bc14c703 (patch)
tree6c9137da8f587ff8028cfa9975a693581b2945b6 /src
parentce3049b0215b63744d11c0ce3ac6afdb67fc2ff0 (diff)
downloadpostgresql-a2e97cb2b6fb64c3ca3198f5c5f31190bc14c703.tar.gz
postgresql-a2e97cb2b6fb64c3ca3198f5c5f31190bc14c703.zip
Fix read_relmap_file() concurrency on Windows.
Commit d8cd0c6c95c0120168df93aae095df4e0682a08a introduced a file rename that could fail on Windows, probably due to other backends having an open file handle to the old file of the same name. Re-arrange the locking slightly to prevent that, by making sure the open() and close() run while we hold the lock. Thomas Munro. I added an explanatory comment. Discussion: https://postgr.es/m/CA%2BhUKGLZtCTgp4NTWV-wGbR2Nyag71%3DEfYTKjDKnk%2BfkhuFMHw%40mail.gmail.com
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/cache/relmapper.c34
1 files changed, 21 insertions, 13 deletions
diff --git a/src/backend/utils/cache/relmapper.c b/src/backend/utils/cache/relmapper.c
index 79e09181b6b..e7345e1410f 100644
--- a/src/backend/utils/cache/relmapper.c
+++ b/src/backend/utils/cache/relmapper.c
@@ -788,16 +788,6 @@ read_relmap_file(RelMapFile *map, char *dbpath, bool lock_held, int elevel)
Assert(elevel >= ERROR);
- /* Open the target file. */
- snprintf(mapfilename, sizeof(mapfilename), "%s/%s", dbpath,
- RELMAPPER_FILENAME);
- fd = OpenTransientFile(mapfilename, O_RDONLY | PG_BINARY);
- if (fd < 0)
- ereport(elevel,
- (errcode_for_file_access(),
- errmsg("could not open file \"%s\": %m",
- mapfilename)));
-
/*
* Grab the lock to prevent the file from being updated while we read it,
* unless the caller is already holding the lock. If the file is updated
@@ -808,6 +798,24 @@ read_relmap_file(RelMapFile *map, char *dbpath, bool lock_held, int elevel)
if (!lock_held)
LWLockAcquire(RelationMappingLock, LW_SHARED);
+ /*
+ * Open the target file.
+ *
+ * Because Windows isn't happy about the idea of renaming over a file
+ * that someone has open, we only open this file after acquiring the lock,
+ * and for the same reason, we close it before releasing the lock. That
+ * way, by the time write_relmap_file() acquires an exclusive lock, no
+ * one else will have it open.
+ */
+ snprintf(mapfilename, sizeof(mapfilename), "%s/%s", dbpath,
+ RELMAPPER_FILENAME);
+ fd = OpenTransientFile(mapfilename, O_RDONLY | PG_BINARY);
+ if (fd < 0)
+ ereport(elevel,
+ (errcode_for_file_access(),
+ errmsg("could not open file \"%s\": %m",
+ mapfilename)));
+
/* Now read the data. */
pgstat_report_wait_start(WAIT_EVENT_RELATION_MAP_READ);
r = read(fd, map, sizeof(RelMapFile));
@@ -825,15 +833,15 @@ read_relmap_file(RelMapFile *map, char *dbpath, bool lock_held, int elevel)
}
pgstat_report_wait_end();
- if (!lock_held)
- LWLockRelease(RelationMappingLock);
-
if (CloseTransientFile(fd) != 0)
ereport(elevel,
(errcode_for_file_access(),
errmsg("could not close file \"%s\": %m",
mapfilename)));
+ if (!lock_held)
+ LWLockRelease(RelationMappingLock);
+
/* check for correct magic number, etc */
if (map->magic != RELMAPPER_FILEMAGIC ||
map->num_mappings < 0 ||