]> granicus.if.org Git - postgresql/commitdiff
Add routine able to update the control file to src/common/
authorMichael Paquier <michael@paquier.xyz>
Tue, 12 Mar 2019 01:03:33 +0000 (10:03 +0900)
committerMichael Paquier <michael@paquier.xyz>
Tue, 12 Mar 2019 01:03:33 +0000 (10:03 +0900)
This adds a new routine to src/common/ which is compatible with both the
frontend and backend code, able to update the control file's contents.
This is now getting used only by pg_rewind, but some upcoming patches
which add more control on checksums for offline instances will make use
of it.  This could also get used more by the backend as xlog.c has its
own flavor of the same logic with some wait events and an additional
flush phase before closing the opened file descriptor, but this is let
as separate work.

Author: Michael Banck, Michael Paquier
Reviewed-by: Fabien Coelho, Sergei Kornilov
Discussion: https://postgr.es/m/20181221201616.GD4974@nighthawk.caipicrew.dd-dns.de

src/bin/pg_rewind/pg_rewind.c
src/common/controldata_utils.c
src/include/common/controldata_utils.h

index aa753bb315f8e70859b4b8cf433de4170b0fd6d6..7f1d6bf48af2134ab78ab4004cf87367043a555a 100644 (file)
@@ -24,6 +24,7 @@
 #include "access/xlog_internal.h"
 #include "catalog/catversion.h"
 #include "catalog/pg_control.h"
+#include "common/controldata_utils.h"
 #include "common/file_perm.h"
 #include "common/file_utils.h"
 #include "common/restricted_token.h"
@@ -37,7 +38,6 @@ static void createBackupLabel(XLogRecPtr startpoint, TimeLineID starttli,
 
 static void digestControlFile(ControlFileData *ControlFile, char *source,
                                  size_t size);
-static void updateControlFile(ControlFileData *ControlFile);
 static void syncTargetDirectory(void);
 static void sanityChecks(void);
 static void findCommonAncestorTimeline(XLogRecPtr *recptr, int *tliIndex);
@@ -377,7 +377,7 @@ main(int argc, char **argv)
        ControlFile_new.minRecoveryPoint = endrec;
        ControlFile_new.minRecoveryPointTLI = endtli;
        ControlFile_new.state = DB_IN_ARCHIVE_RECOVERY;
-       updateControlFile(&ControlFile_new);
+       update_controlfile(datadir_target, progname, &ControlFile_new);
 
        pg_log(PG_PROGRESS, "syncing target data directory\n");
        syncTargetDirectory();
@@ -666,45 +666,6 @@ digestControlFile(ControlFileData *ControlFile, char *src, size_t size)
        checkControlFile(ControlFile);
 }
 
-/*
- * Update the target's control file.
- */
-static void
-updateControlFile(ControlFileData *ControlFile)
-{
-       char            buffer[PG_CONTROL_FILE_SIZE];
-
-       /*
-        * For good luck, apply the same static assertions as in backend's
-        * WriteControlFile().
-        */
-       StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_MAX_SAFE_SIZE,
-                                        "pg_control is too large for atomic disk writes");
-       StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_FILE_SIZE,
-                                        "sizeof(ControlFileData) exceeds PG_CONTROL_FILE_SIZE");
-
-       /* Recalculate CRC of control file */
-       INIT_CRC32C(ControlFile->crc);
-       COMP_CRC32C(ControlFile->crc,
-                               (char *) ControlFile,
-                               offsetof(ControlFileData, crc));
-       FIN_CRC32C(ControlFile->crc);
-
-       /*
-        * Write out PG_CONTROL_FILE_SIZE bytes into pg_control by zero-padding
-        * the excess over sizeof(ControlFileData), to avoid premature EOF related
-        * errors when reading it.
-        */
-       memset(buffer, 0, PG_CONTROL_FILE_SIZE);
-       memcpy(buffer, ControlFile, sizeof(ControlFileData));
-
-       open_target_file("global/pg_control", false);
-
-       write_target_range(buffer, 0, PG_CONTROL_FILE_SIZE);
-
-       close_target_file();
-}
-
 /*
  * Sync target data directory to ensure that modifications are safely on disk.
  *
index 6289a4343adba12f5377d4d91bea3d28ac1f464e..71e67a2edaa822df9f7c7c1627cb35629313093d 100644 (file)
 #include <sys/stat.h>
 #include <fcntl.h>
 
+#include "access/xlog_internal.h"
 #include "catalog/pg_control.h"
 #include "common/controldata_utils.h"
+#include "common/file_perm.h"
 #include "port/pg_crc32c.h"
 #ifndef FRONTEND
 #include "storage/fd.h"
@@ -137,3 +139,95 @@ get_controlfile(const char *DataDir, const char *progname, bool *crc_ok_p)
 
        return ControlFile;
 }
+
+/*
+ * 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.
+ */
+void
+update_controlfile(const char *DataDir, const char *progname,
+                                  ControlFileData *ControlFile)
+{
+       int                     fd;
+       char            buffer[PG_CONTROL_FILE_SIZE];
+       char            ControlFilePath[MAXPGPATH];
+
+       /*
+        * Apply the same static assertions as in backend's WriteControlFile().
+        */
+       StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_MAX_SAFE_SIZE,
+                                        "pg_control is too large for atomic disk writes");
+       StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_FILE_SIZE,
+                                        "sizeof(ControlFileData) exceeds PG_CONTROL_FILE_SIZE");
+
+       /* Recalculate CRC of control file */
+       INIT_CRC32C(ControlFile->crc);
+       COMP_CRC32C(ControlFile->crc,
+                               (char *) ControlFile,
+                               offsetof(ControlFileData, crc));
+       FIN_CRC32C(ControlFile->crc);
+
+       /*
+        * Write out PG_CONTROL_FILE_SIZE bytes into pg_control by zero-padding
+        * the excess over sizeof(ControlFileData), to avoid premature EOF related
+        * errors when reading it.
+        */
+       memset(buffer, 0, PG_CONTROL_FILE_SIZE);
+       memcpy(buffer, ControlFile, sizeof(ControlFileData));
+
+       snprintf(ControlFilePath, sizeof(ControlFilePath), "%s/%s", DataDir, XLOG_CONTROL_FILE);
+
+#ifndef FRONTEND
+       if ((fd = OpenTransientFile(ControlFilePath, O_WRONLY | PG_BINARY)) == -1)
+               ereport(PANIC,
+                               (errcode_for_file_access(),
+                                errmsg("could not open file \"%s\": %m",
+                                               ControlFilePath)));
+#else
+       if ((fd = open(ControlFilePath, O_WRONLY | PG_BINARY,
+                                  pg_file_create_mode)) == -1)
+       {
+               fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
+                               progname, ControlFilePath, strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+#endif
+
+       errno = 0;
+       if (write(fd, buffer, PG_CONTROL_FILE_SIZE) != PG_CONTROL_FILE_SIZE)
+       {
+               /* if write didn't set errno, assume problem is no disk space */
+               if (errno == 0)
+                       errno = ENOSPC;
+
+#ifndef FRONTEND
+               ereport(PANIC,
+                               (errcode_for_file_access(),
+                                errmsg("could not write file \"%s\": %m",
+                                               ControlFilePath)));
+#else
+               fprintf(stderr, _("%s: could not write \"%s\": %s\n"),
+                               progname, ControlFilePath, strerror(errno));
+               exit(EXIT_FAILURE);
+#endif
+       }
+
+#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
+}
index 0ffa2000fc26a14d6908983f2f4996102306d956..95317ebacf293fc3d7d4904483895d62d531c8af 100644 (file)
 
 #include "catalog/pg_control.h"
 
-extern ControlFileData *get_controlfile(const char *DataDir, const char *progname, bool *crc_ok_p);
+extern ControlFileData *get_controlfile(const char *DataDir,
+                                                                               const char *progname,
+                                                                               bool *crc_ok_p);
+extern void update_controlfile(const char *DataDir, const char *progname,
+                                                          ControlFileData *ControlFile);
 
 #endif                                                 /* COMMON_CONTROLDATA_UTILS_H */