PostgreSQL Source Code  git master
controldata_utils.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * controldata_utils.c
4  * Common code for control data file output.
5  *
6  *
7  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  * src/common/controldata_utils.c
13  *
14  *-------------------------------------------------------------------------
15  */
16 
17 #ifndef FRONTEND
18 #include "postgres.h"
19 #else
20 #include "postgres_fe.h"
21 #endif
22 
23 #include <unistd.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <time.h>
27 
28 #include "access/xlog_internal.h"
29 #include "catalog/pg_control.h"
31 #include "common/file_perm.h"
32 #ifdef FRONTEND
33 #include "common/logging.h"
34 #endif
35 #include "port/pg_crc32c.h"
36 
37 #ifndef FRONTEND
38 #include "pgstat.h"
39 #include "storage/fd.h"
40 #endif
41 
42 /*
43  * get_controlfile()
44  *
45  * Get controlfile values. The result is returned as a palloc'd copy of the
46  * control file data.
47  *
48  * crc_ok_p can be used by the caller to see whether the CRC of the control
49  * file data is correct.
50  */
52 get_controlfile(const char *DataDir, bool *crc_ok_p)
53 {
55  int fd;
56  char ControlFilePath[MAXPGPATH];
57  pg_crc32c crc;
58  int r;
59 #ifdef FRONTEND
60  pg_crc32c last_crc;
61  int retries = 0;
62 #endif
63 
64  Assert(crc_ok_p);
65 
67  snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
68 
69 #ifdef FRONTEND
70  INIT_CRC32C(last_crc);
71 
72 retry:
73 #endif
74 
75 #ifndef FRONTEND
76  if ((fd = OpenTransientFile(ControlFilePath, O_RDONLY | PG_BINARY)) == -1)
77  ereport(ERROR,
79  errmsg("could not open file \"%s\" for reading: %m",
80  ControlFilePath)));
81 #else
82  if ((fd = open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1)
83  pg_fatal("could not open file \"%s\" for reading: %m",
84  ControlFilePath);
85 #endif
86 
87  r = read(fd, ControlFile, sizeof(ControlFileData));
88  if (r != sizeof(ControlFileData))
89  {
90  if (r < 0)
91 #ifndef FRONTEND
92  ereport(ERROR,
94  errmsg("could not read file \"%s\": %m", ControlFilePath)));
95 #else
96  pg_fatal("could not read file \"%s\": %m", ControlFilePath);
97 #endif
98  else
99 #ifndef FRONTEND
100  ereport(ERROR,
102  errmsg("could not read file \"%s\": read %d of %zu",
103  ControlFilePath, r, sizeof(ControlFileData))));
104 #else
105  pg_fatal("could not read file \"%s\": read %d of %zu",
106  ControlFilePath, r, sizeof(ControlFileData));
107 #endif
108  }
109 
110 #ifndef FRONTEND
111  if (CloseTransientFile(fd) != 0)
112  ereport(ERROR,
114  errmsg("could not close file \"%s\": %m",
115  ControlFilePath)));
116 #else
117  if (close(fd) != 0)
118  pg_fatal("could not close file \"%s\": %m", ControlFilePath);
119 #endif
120 
121  /* Check the CRC. */
122  INIT_CRC32C(crc);
124  (char *) ControlFile,
125  offsetof(ControlFileData, crc));
126  FIN_CRC32C(crc);
127 
128  *crc_ok_p = EQ_CRC32C(crc, ControlFile->crc);
129 
130 #ifdef FRONTEND
131 
132  /*
133  * If the server was writing at the same time, it is possible that we read
134  * partially updated contents on some systems. If the CRC doesn't match,
135  * retry a limited number of times until we compute the same bad CRC twice
136  * in a row with a short sleep in between. Then the failure is unlikely
137  * to be due to a concurrent write.
138  */
139  if (!*crc_ok_p &&
140  (retries == 0 || !EQ_CRC32C(crc, last_crc)) &&
141  retries < 10)
142  {
143  retries++;
144  last_crc = crc;
145  pg_usleep(10000);
146  goto retry;
147  }
148 #endif
149 
150  /* Make sure the control file is valid byte order. */
151  if (ControlFile->pg_control_version % 65536 == 0 &&
152  ControlFile->pg_control_version / 65536 != 0)
153 #ifndef FRONTEND
154  elog(ERROR, _("byte ordering mismatch"));
155 #else
156  pg_log_warning("possible byte ordering mismatch\n"
157  "The byte ordering used to store the pg_control file might not match the one\n"
158  "used by this program. In that case the results below would be incorrect, and\n"
159  "the PostgreSQL installation would be incompatible with this data directory.");
160 #endif
161 
162  return ControlFile;
163 }
164 
165 /*
166  * update_controlfile()
167  *
168  * Update controlfile values with the contents given by caller. The
169  * contents to write are included in "ControlFile". "do_sync" can be
170  * optionally used to flush the updated control file. Note that it is up
171  * to the caller to properly lock ControlFileLock when calling this
172  * routine in the backend.
173  */
174 void
177 {
178  int fd;
179  char buffer[PG_CONTROL_FILE_SIZE];
180  char ControlFilePath[MAXPGPATH];
181 
182  /* Update timestamp */
183  ControlFile->time = (pg_time_t) time(NULL);
184 
185  /* Recalculate CRC of control file */
188  (char *) ControlFile,
189  offsetof(ControlFileData, crc));
191 
192  /*
193  * Write out PG_CONTROL_FILE_SIZE bytes into pg_control by zero-padding
194  * the excess over sizeof(ControlFileData), to avoid premature EOF related
195  * errors when reading it.
196  */
197  memset(buffer, 0, PG_CONTROL_FILE_SIZE);
198  memcpy(buffer, ControlFile, sizeof(ControlFileData));
199 
200  snprintf(ControlFilePath, sizeof(ControlFilePath), "%s/%s", DataDir, XLOG_CONTROL_FILE);
201 
202 #ifndef FRONTEND
203 
204  /*
205  * All errors issue a PANIC, so no need to use OpenTransientFile() and to
206  * worry about file descriptor leaks.
207  */
208  if ((fd = BasicOpenFile(ControlFilePath, O_RDWR | PG_BINARY)) < 0)
209  ereport(PANIC,
211  errmsg("could not open file \"%s\": %m",
212  ControlFilePath)));
213 #else
214  if ((fd = open(ControlFilePath, O_WRONLY | PG_BINARY,
215  pg_file_create_mode)) == -1)
216  pg_fatal("could not open file \"%s\": %m", ControlFilePath);
217 #endif
218 
219  errno = 0;
220 #ifndef FRONTEND
221  pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_WRITE_UPDATE);
222 #endif
224  {
225  /* if write didn't set errno, assume problem is no disk space */
226  if (errno == 0)
227  errno = ENOSPC;
228 
229 #ifndef FRONTEND
230  ereport(PANIC,
232  errmsg("could not write file \"%s\": %m",
233  ControlFilePath)));
234 #else
235  pg_fatal("could not write file \"%s\": %m", ControlFilePath);
236 #endif
237  }
238 #ifndef FRONTEND
240 #endif
241 
242  if (do_sync)
243  {
244 #ifndef FRONTEND
245  pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_SYNC_UPDATE);
246  if (pg_fsync(fd) != 0)
247  ereport(PANIC,
249  errmsg("could not fsync file \"%s\": %m",
250  ControlFilePath)));
252 #else
253  if (fsync(fd) != 0)
254  pg_fatal("could not fsync file \"%s\": %m", ControlFilePath);
255 #endif
256  }
257 
258  if (close(fd) != 0)
259  {
260 #ifndef FRONTEND
261  ereport(PANIC,
263  errmsg("could not close file \"%s\": %m",
264  ControlFilePath)));
265 #else
266  pg_fatal("could not close file \"%s\": %m", ControlFilePath);
267 #endif
268  }
269 }
#define PG_BINARY
Definition: c.h:1283
void update_controlfile(const char *DataDir, ControlFileData *ControlFile, bool do_sync)
ControlFileData * get_controlfile(const char *DataDir, bool *crc_ok_p)
int errcode_for_file_access(void)
Definition: elog.c:881
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define _(x)
Definition: elog.c:91
#define PANIC
Definition: elog.h:42
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
int CloseTransientFile(int fd)
Definition: fd.c:2779
int BasicOpenFile(const char *fileName, int fileFlags)
Definition: fd.c:1064
int pg_fsync(int fd)
Definition: fd.c:386
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2603
#define palloc_object(type)
Definition: fe_memutils.h:62
int pg_file_create_mode
Definition: file_perm.c:19
char * DataDir
Definition: globals.c:66
static bool do_sync
Definition: initdb.c:162
#define close(a)
Definition: win32.h:12
#define write(a, b, c)
Definition: win32.h:14
#define read(a, b, c)
Definition: win32.h:13
Assert(fmt[strlen(fmt) - 1] !='\n')
#define pg_fatal(...)
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:41
#define MAXPGPATH
#define PG_CONTROL_FILE_SIZE
Definition: pg_control.h:249
uint32 pg_crc32c
Definition: pg_crc32c.h:38
#define COMP_CRC32C(crc, data, len)
Definition: pg_crc32c.h:98
#define EQ_CRC32C(c1, c2)
Definition: pg_crc32c.h:42
#define INIT_CRC32C(crc)
Definition: pg_crc32c.h:41
#define FIN_CRC32C(crc)
Definition: pg_crc32c.h:103
return crc
#define pg_log_warning(...)
Definition: pgfnames.c:24
int64 pg_time_t
Definition: pgtime.h:23
#define snprintf
Definition: port.h:238
static int fd(const char *x, int i)
Definition: preproc-init.c:105
void pg_usleep(long microsec)
Definition: signal.c:53
uint32 pg_control_version
Definition: pg_control.h:124
pg_time_t time
Definition: pg_control.h:131
pg_crc32c crc
Definition: pg_control.h:231
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:88
static void pgstat_report_wait_end(void)
Definition: wait_event.h:104
#define fsync(fd)
Definition: win32_port.h:85
static ControlFileData * ControlFile
Definition: xlog.c:580
#define XLOG_CONTROL_FILE