mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Add routine able to update the control file to src/common/
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
This commit is contained in:
@ -24,8 +24,10 @@
|
||||
#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
|
||||
}
|
||||
|
Reference in New Issue
Block a user