aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorMichael Paquier <michael@paquier.xyz>2019-03-18 12:59:35 +0900
committerMichael Paquier <michael@paquier.xyz>2019-03-18 12:59:35 +0900
commit8b938d36f7446e76436ca4a8ddcebbebaeaab480 (patch)
treed8c076cde25ca1f68e75f752d2f3df1680d35bd4 /src/common
parenta7eadaaaaf089994279488f795bdedd9ded1682a (diff)
downloadpostgresql-8b938d36f7446e76436ca4a8ddcebbebaeaab480.tar.gz
postgresql-8b938d36f7446e76436ca4a8ddcebbebaeaab480.zip
Refactor more code logic to update the control file
ce6afc6 has begun the refactoring work by plugging pg_rewind into a central routine to update the control file, and left around two extra copies, with one in xlog.c for the backend and one in pg_resetwal.c. By adding an extra option to the central routine in controldata_utils.c to control if a flush of the control file needs to be done, it is proving to be straight-forward to make xlog.c and pg_resetwal.c use the central code path at the condition of moving the wait event tracking there. Hence, this allows to have only one central code path to update the control file, shaving the code from the duplicates. This refactoring actually fixes a problem in pg_resetwal. Previously, the control file was first removed before being recreated. So if a crash happened between the moment the file was removed and the moment the file was created, then it would have been possible to not have a control file anymore in the database folder. Author: Fabien Coelho Reviewed-by: Michael Paquier Discussion: https://postgr.es/m/alpine.DEB.2.21.1903170935210.2506@lancre
Diffstat (limited to 'src/common')
-rw-r--r--src/common/controldata_utils.c51
1 files changed, 42 insertions, 9 deletions
diff --git a/src/common/controldata_utils.c b/src/common/controldata_utils.c
index 71e67a2edaa..567281349e0 100644
--- a/src/common/controldata_utils.c
+++ b/src/common/controldata_utils.c
@@ -29,7 +29,9 @@
#include "common/controldata_utils.h"
#include "common/file_perm.h"
#include "port/pg_crc32c.h"
+
#ifndef FRONTEND
+#include "pgstat.h"
#include "storage/fd.h"
#endif
@@ -144,13 +146,14 @@ get_controlfile(const char *DataDir, const char *progname, bool *crc_ok_p)
* update_controlfile()
*
* Update controlfile values with the contents given by caller. The
- * contents to write are included in "ControlFile". Note that it is up
- * to the caller to fsync the updated file, and to properly lock
- * ControlFileLock when calling this routine in the backend.
+ * contents to write are included in "ControlFile". "do_sync" can be
+ * optionally used to flush the updated control file. Note that it is up
+ * to the caller to properly lock ControlFileLock when calling this
+ * routine in the backend.
*/
void
update_controlfile(const char *DataDir, const char *progname,
- ControlFileData *ControlFile)
+ ControlFileData *ControlFile, bool do_sync)
{
int fd;
char buffer[PG_CONTROL_FILE_SIZE];
@@ -182,7 +185,12 @@ update_controlfile(const char *DataDir, const char *progname,
snprintf(ControlFilePath, sizeof(ControlFilePath), "%s/%s", DataDir, XLOG_CONTROL_FILE);
#ifndef FRONTEND
- if ((fd = OpenTransientFile(ControlFilePath, O_WRONLY | PG_BINARY)) == -1)
+
+ /*
+ * All errors issue a PANIC, so no need to use OpenTransientFile() and to
+ * worry about file descriptor leaks.
+ */
+ if ((fd = BasicOpenFile(ControlFilePath, O_RDWR | PG_BINARY)) < 0)
ereport(PANIC,
(errcode_for_file_access(),
errmsg("could not open file \"%s\": %m",
@@ -198,6 +206,9 @@ update_controlfile(const char *DataDir, const char *progname,
#endif
errno = 0;
+#ifndef FRONTEND
+ pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_WRITE_UPDATE);
+#endif
if (write(fd, buffer, PG_CONTROL_FILE_SIZE) != PG_CONTROL_FILE_SIZE)
{
/* if write didn't set errno, assume problem is no disk space */
@@ -215,19 +226,41 @@ update_controlfile(const char *DataDir, const char *progname,
exit(EXIT_FAILURE);
#endif
}
+#ifndef FRONTEND
+ pgstat_report_wait_end();
+#endif
+ if (do_sync)
+ {
+#ifndef FRONTEND
+ pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_SYNC_UPDATE);
+ if (pg_fsync(fd) != 0)
+ ereport(PANIC,
+ (errcode_for_file_access(),
+ errmsg("could not fsync file \"%s\": %m",
+ ControlFilePath)));
+ pgstat_report_wait_end();
+#else
+ if (fsync(fd) != 0)
+ {
+ fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"),
+ progname, ControlFilePath, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+#endif
+ }
+
+ if (close(fd) < 0)
+ {
#ifndef FRONTEND
- if (CloseTransientFile(fd))
ereport(PANIC,
(errcode_for_file_access(),
errmsg("could not close file \"%s\": %m",
ControlFilePath)));
#else
- if (close(fd) < 0)
- {
fprintf(stderr, _("%s: could not close file \"%s\": %s\n"),
progname, ControlFilePath, strerror(errno));
exit(EXIT_FAILURE);
- }
#endif
+ }
}