Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_resetwal.c
4 : * A utility to "zero out" the xlog when it's corrupt beyond recovery.
5 : * Can also rebuild pg_control if needed.
6 : *
7 : * The theory of operation is fairly simple:
8 : * 1. Read the existing pg_control (which will include the last
9 : * checkpoint record).
10 : * 2. If pg_control is corrupt, attempt to intuit reasonable values,
11 : * by scanning the old xlog if necessary.
12 : * 3. Modify pg_control to reflect a "shutdown" state with a checkpoint
13 : * record at the start of xlog.
14 : * 4. Flush the existing xlog files and write a new segment with
15 : * just a checkpoint record in it. The new segment is positioned
16 : * just past the end of the old xlog, so that existing LSNs in
17 : * data pages will appear to be "in the past".
18 : * This is all pretty straightforward except for the intuition part of
19 : * step 2 ...
20 : *
21 : *
22 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
23 : * Portions Copyright (c) 1994, Regents of the University of California
24 : *
25 : * src/bin/pg_resetwal/pg_resetwal.c
26 : *
27 : *-------------------------------------------------------------------------
28 : */
29 :
30 : /*
31 : * We have to use postgres.h not postgres_fe.h here, because there's so much
32 : * backend-only stuff in the XLOG include files we need. But we need a
33 : * frontend-ish environment otherwise. Hence this ugly hack.
34 : */
35 : #define FRONTEND 1
36 :
37 : #include "postgres.h"
38 :
39 : #include <dirent.h>
40 : #include <fcntl.h>
41 : #include <sys/stat.h>
42 : #include <sys/time.h>
43 : #include <time.h>
44 : #include <unistd.h>
45 :
46 : #include "access/heaptoast.h"
47 : #include "access/multixact.h"
48 : #include "access/transam.h"
49 : #include "access/xlog.h"
50 : #include "access/xlog_internal.h"
51 : #include "common/controldata_utils.h"
52 : #include "common/fe_memutils.h"
53 : #include "common/file_perm.h"
54 : #include "common/logging.h"
55 : #include "common/restricted_token.h"
56 : #include "common/string.h"
57 : #include "fe_utils/option_utils.h"
58 : #include "fe_utils/version.h"
59 : #include "getopt_long.h"
60 : #include "pg_getopt.h"
61 : #include "storage/large_object.h"
62 :
63 : static ControlFileData ControlFile; /* pg_control values */
64 : static XLogSegNo newXlogSegNo; /* new XLOG segment # */
65 : static bool guessed = false; /* T if we had to guess at any values */
66 : static const char *progname;
67 : static uint32 set_xid_epoch = (uint32) -1;
68 : static TransactionId set_oldest_xid = 0;
69 : static TransactionId set_xid = 0;
70 : static TransactionId set_oldest_commit_ts_xid = 0;
71 : static TransactionId set_newest_commit_ts_xid = 0;
72 : static Oid set_oid = 0;
73 : static bool mxid_given = false;
74 : static MultiXactId set_mxid = 0;
75 : static bool mxoff_given = false;
76 : static MultiXactOffset set_mxoff = 0;
77 : static TimeLineID minXlogTli = 0;
78 : static XLogSegNo minXlogSegNo = 0;
79 : static int WalSegSz;
80 : static int set_wal_segsize;
81 : static int set_char_signedness = -1;
82 :
83 : static void CheckDataVersion(void);
84 : static bool read_controlfile(void);
85 : static void GuessControlValues(void);
86 : static void PrintControlValues(bool guessed);
87 : static void PrintNewControlValues(void);
88 : static void RewriteControlFile(void);
89 : static void FindEndOfXLOG(void);
90 : static void KillExistingXLOG(void);
91 : static void KillExistingArchiveStatus(void);
92 : static void KillExistingWALSummaries(void);
93 : static void WriteEmptyXLOG(void);
94 : static void usage(void);
95 :
96 :
97 : int
98 356 : main(int argc, char *argv[])
99 : {
100 : static struct option long_options[] = {
101 : {"commit-timestamp-ids", required_argument, NULL, 'c'},
102 : {"pgdata", required_argument, NULL, 'D'},
103 : {"epoch", required_argument, NULL, 'e'},
104 : {"force", no_argument, NULL, 'f'},
105 : {"next-wal-file", required_argument, NULL, 'l'},
106 : {"multixact-ids", required_argument, NULL, 'm'},
107 : {"dry-run", no_argument, NULL, 'n'},
108 : {"next-oid", required_argument, NULL, 'o'},
109 : {"multixact-offset", required_argument, NULL, 'O'},
110 : {"oldest-transaction-id", required_argument, NULL, 'u'},
111 : {"next-transaction-id", required_argument, NULL, 'x'},
112 : {"wal-segsize", required_argument, NULL, 1},
113 : {"char-signedness", required_argument, NULL, 2},
114 : {NULL, 0, NULL, 0}
115 : };
116 :
117 : int c;
118 356 : bool force = false;
119 356 : bool noupdate = false;
120 356 : MultiXactId set_oldestmxid = 0;
121 : char *endptr;
122 : char *endptr2;
123 : int64 tmpi64;
124 356 : char *DataDir = NULL;
125 356 : char *log_fname = NULL;
126 : int fd;
127 :
128 356 : pg_logging_init(argv[0]);
129 356 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_resetwal"));
130 356 : progname = get_progname(argv[0]);
131 :
132 356 : if (argc > 1)
133 : {
134 354 : if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
135 : {
136 2 : usage();
137 2 : exit(0);
138 : }
139 352 : if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
140 : {
141 90 : puts("pg_resetwal (PostgreSQL) " PG_VERSION);
142 90 : exit(0);
143 : }
144 : }
145 :
146 :
147 592 : while ((c = getopt_long(argc, argv, "c:D:e:fl:m:no:O:u:x:", long_options, NULL)) != -1)
148 : {
149 372 : switch (c)
150 : {
151 8 : case 'D':
152 8 : DataDir = optarg;
153 8 : break;
154 :
155 70 : case 'f':
156 70 : force = true;
157 70 : break;
158 :
159 76 : case 'n':
160 76 : noupdate = true;
161 76 : break;
162 :
163 26 : case 'e':
164 26 : errno = 0;
165 26 : set_xid_epoch = strtoul(optarg, &endptr, 0);
166 26 : if (endptr == optarg || *endptr != '\0' || errno != 0)
167 : {
168 : /*------
169 : translator: the second %s is a command line argument (-e, etc) */
170 2 : pg_log_error("invalid argument for option %s", "-e");
171 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
172 2 : exit(1);
173 : }
174 24 : if (set_xid_epoch == -1)
175 2 : pg_fatal("transaction ID epoch (-e) must not be -1");
176 22 : break;
177 :
178 24 : case 'u':
179 24 : errno = 0;
180 24 : set_oldest_xid = strtoul(optarg, &endptr, 0);
181 24 : if (endptr == optarg || *endptr != '\0' || errno != 0)
182 : {
183 2 : pg_log_error("invalid argument for option %s", "-u");
184 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
185 2 : exit(1);
186 : }
187 22 : if (!TransactionIdIsNormal(set_oldest_xid))
188 2 : pg_fatal("oldest transaction ID (-u) must be greater than or equal to %u", FirstNormalTransactionId);
189 20 : break;
190 :
191 24 : case 'x':
192 24 : errno = 0;
193 24 : set_xid = strtoul(optarg, &endptr, 0);
194 24 : if (endptr == optarg || *endptr != '\0' || errno != 0)
195 : {
196 2 : pg_log_error("invalid argument for option %s", "-x");
197 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
198 2 : exit(1);
199 : }
200 22 : if (!TransactionIdIsNormal(set_xid))
201 2 : pg_fatal("transaction ID (-x) must be greater than or equal to %u", FirstNormalTransactionId);
202 20 : break;
203 :
204 28 : case 'c':
205 28 : errno = 0;
206 28 : set_oldest_commit_ts_xid = strtoul(optarg, &endptr, 0);
207 28 : if (endptr == optarg || *endptr != ',' || errno != 0)
208 : {
209 2 : pg_log_error("invalid argument for option %s", "-c");
210 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
211 2 : exit(1);
212 : }
213 26 : set_newest_commit_ts_xid = strtoul(endptr + 1, &endptr2, 0);
214 26 : if (endptr2 == endptr + 1 || *endptr2 != '\0' || errno != 0)
215 : {
216 2 : pg_log_error("invalid argument for option %s", "-c");
217 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
218 2 : exit(1);
219 : }
220 :
221 24 : if (set_oldest_commit_ts_xid < FirstNormalTransactionId &&
222 2 : set_oldest_commit_ts_xid != InvalidTransactionId)
223 2 : pg_fatal("transaction ID (-c) must be either %u or greater than or equal to %u", InvalidTransactionId, FirstNormalTransactionId);
224 :
225 22 : if (set_newest_commit_ts_xid < FirstNormalTransactionId &&
226 6 : set_newest_commit_ts_xid != InvalidTransactionId)
227 2 : pg_fatal("transaction ID (-c) must be either %u or greater than or equal to %u", InvalidTransactionId, FirstNormalTransactionId);
228 20 : break;
229 :
230 24 : case 'o':
231 24 : errno = 0;
232 24 : set_oid = strtoul(optarg, &endptr, 0);
233 24 : if (endptr == optarg || *endptr != '\0' || errno != 0)
234 : {
235 2 : pg_log_error("invalid argument for option %s", "-o");
236 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
237 2 : exit(1);
238 : }
239 22 : if (set_oid == 0)
240 2 : pg_fatal("OID (-o) must not be 0");
241 20 : break;
242 :
243 30 : case 'm':
244 30 : errno = 0;
245 30 : set_mxid = strtoul(optarg, &endptr, 0);
246 30 : if (endptr == optarg || *endptr != ',' || errno != 0)
247 : {
248 2 : pg_log_error("invalid argument for option %s", "-m");
249 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
250 2 : exit(1);
251 : }
252 :
253 28 : set_oldestmxid = strtoul(endptr + 1, &endptr2, 0);
254 28 : if (endptr2 == endptr + 1 || *endptr2 != '\0' || errno != 0)
255 : {
256 2 : pg_log_error("invalid argument for option %s", "-m");
257 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
258 2 : exit(1);
259 : }
260 :
261 : /*
262 : * XXX It'd be nice to have more sanity checks here, e.g. so
263 : * that oldest is not wrapped around w.r.t. nextMulti.
264 : */
265 26 : if (set_oldestmxid == 0)
266 2 : pg_fatal("oldest multitransaction ID (-m) must not be 0");
267 24 : mxid_given = true;
268 24 : break;
269 :
270 24 : case 'O':
271 24 : errno = 0;
272 24 : tmpi64 = strtoi64(optarg, &endptr, 0);
273 24 : if (endptr == optarg || *endptr != '\0' || errno != 0)
274 : {
275 2 : pg_log_error("invalid argument for option %s", "-O");
276 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
277 2 : exit(1);
278 : }
279 22 : if (tmpi64 < 0 || tmpi64 > (int64) MaxMultiXactOffset)
280 2 : pg_fatal("multitransaction offset (-O) must be between 0 and %u", MaxMultiXactOffset);
281 :
282 20 : set_mxoff = (MultiXactOffset) tmpi64;
283 20 : mxoff_given = true;
284 20 : break;
285 :
286 22 : case 'l':
287 22 : if (strspn(optarg, "01234567890ABCDEFabcdef") != XLOG_FNAME_LEN)
288 : {
289 2 : pg_log_error("invalid argument for option %s", "-l");
290 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
291 2 : exit(1);
292 : }
293 :
294 : /*
295 : * XLogFromFileName requires wal segment size which is not yet
296 : * set. Hence wal details are set later on.
297 : */
298 20 : log_fname = pg_strdup(optarg);
299 20 : break;
300 :
301 8 : case 1:
302 : {
303 : int wal_segsize_mb;
304 :
305 8 : if (!option_parse_int(optarg, "--wal-segsize", 1, 1024, &wal_segsize_mb))
306 2 : exit(1);
307 6 : set_wal_segsize = wal_segsize_mb * 1024 * 1024;
308 6 : if (!IsValidWalSegSize(set_wal_segsize))
309 2 : pg_fatal("argument of %s must be a power of two between 1 and 1024", "--wal-segsize");
310 4 : break;
311 : }
312 :
313 6 : case 2:
314 : {
315 6 : errno = 0;
316 :
317 6 : if (pg_strcasecmp(optarg, "signed") == 0)
318 0 : set_char_signedness = 1;
319 6 : else if (pg_strcasecmp(optarg, "unsigned") == 0)
320 4 : set_char_signedness = 0;
321 : else
322 : {
323 2 : pg_log_error("invalid argument for option %s", "--char-signedness");
324 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
325 2 : exit(1);
326 : }
327 4 : break;
328 : }
329 :
330 2 : default:
331 : /* getopt_long already emitted a complaint */
332 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
333 2 : exit(1);
334 : }
335 : }
336 :
337 220 : if (DataDir == NULL && optind < argc)
338 210 : DataDir = argv[optind++];
339 :
340 : /* Complain if any arguments remain */
341 220 : if (optind < argc)
342 : {
343 2 : pg_log_error("too many command-line arguments (first is \"%s\")",
344 : argv[optind]);
345 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
346 2 : exit(1);
347 : }
348 :
349 218 : if (DataDir == NULL)
350 : {
351 2 : pg_log_error("no data directory specified");
352 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
353 2 : exit(1);
354 : }
355 :
356 : /*
357 : * Don't allow pg_resetwal to be run as root, to avoid overwriting the
358 : * ownership of files in the data directory. We need only check for root
359 : * -- any other user won't have sufficient permissions to modify files in
360 : * the data directory.
361 : */
362 : #ifndef WIN32
363 216 : if (geteuid() == 0)
364 : {
365 0 : pg_log_error("cannot be executed by \"root\"");
366 0 : pg_log_error_hint("You must run %s as the PostgreSQL superuser.",
367 : progname);
368 0 : exit(1);
369 : }
370 : #endif
371 :
372 216 : get_restricted_token();
373 :
374 : /* Set mask based on PGDATA permissions */
375 216 : if (!GetDataDirectoryCreatePerm(DataDir))
376 2 : pg_fatal("could not read permissions of directory \"%s\": %m",
377 : DataDir);
378 :
379 214 : umask(pg_mode_mask);
380 :
381 214 : if (chdir(DataDir) < 0)
382 0 : pg_fatal("could not change directory to \"%s\": %m",
383 : DataDir);
384 :
385 : /* Check that data directory matches our server version */
386 214 : CheckDataVersion();
387 :
388 : /*
389 : * Check for a postmaster lock file --- if there is one, refuse to
390 : * proceed, on grounds we might be interfering with a live installation.
391 : */
392 214 : if ((fd = open("postmaster.pid", O_RDONLY, 0)) < 0)
393 : {
394 212 : if (errno != ENOENT)
395 0 : pg_fatal("could not open file \"%s\" for reading: %m",
396 : "postmaster.pid");
397 : }
398 : else
399 : {
400 2 : pg_log_error("lock file \"%s\" exists", "postmaster.pid");
401 2 : pg_log_error_hint("Is a server running? If not, delete the lock file and try again.");
402 2 : exit(1);
403 : }
404 :
405 : /*
406 : * Attempt to read the existing pg_control file
407 : */
408 212 : if (!read_controlfile())
409 8 : GuessControlValues();
410 :
411 : /*
412 : * If no new WAL segment size was specified, use the control file value.
413 : */
414 212 : if (set_wal_segsize != 0)
415 4 : WalSegSz = set_wal_segsize;
416 : else
417 208 : WalSegSz = ControlFile.xlog_seg_size;
418 :
419 212 : if (log_fname != NULL)
420 20 : XLogFromFileName(log_fname, &minXlogTli, &minXlogSegNo, WalSegSz);
421 :
422 : /*
423 : * Also look at existing segment files to set up newXlogSegNo
424 : */
425 212 : FindEndOfXLOG();
426 :
427 : /*
428 : * If we're not going to proceed with the reset, print the current control
429 : * file parameters.
430 : */
431 212 : if ((guessed && !force) || noupdate)
432 78 : PrintControlValues(guessed);
433 :
434 : /*
435 : * Adjust fields if required by switches. (Do this now so that printout,
436 : * if any, includes these values.)
437 : */
438 212 : if (set_xid_epoch != -1)
439 : ControlFile.checkPointCopy.nextXid =
440 22 : FullTransactionIdFromEpochAndXid(set_xid_epoch,
441 22 : XidFromFullTransactionId(ControlFile.checkPointCopy.nextXid));
442 :
443 212 : if (set_oldest_xid != 0)
444 : {
445 20 : ControlFile.checkPointCopy.oldestXid = set_oldest_xid;
446 20 : ControlFile.checkPointCopy.oldestXidDB = InvalidOid;
447 : }
448 :
449 212 : if (set_xid != 0)
450 : ControlFile.checkPointCopy.nextXid =
451 20 : FullTransactionIdFromEpochAndXid(EpochFromFullTransactionId(ControlFile.checkPointCopy.nextXid),
452 : set_xid);
453 :
454 212 : if (set_oldest_commit_ts_xid != 0)
455 20 : ControlFile.checkPointCopy.oldestCommitTsXid = set_oldest_commit_ts_xid;
456 212 : if (set_newest_commit_ts_xid != 0)
457 16 : ControlFile.checkPointCopy.newestCommitTsXid = set_newest_commit_ts_xid;
458 :
459 212 : if (set_oid != 0)
460 20 : ControlFile.checkPointCopy.nextOid = set_oid;
461 :
462 212 : if (mxid_given)
463 : {
464 24 : ControlFile.checkPointCopy.nextMulti = set_mxid;
465 :
466 24 : ControlFile.checkPointCopy.oldestMulti = set_oldestmxid;
467 24 : if (ControlFile.checkPointCopy.oldestMulti < FirstMultiXactId)
468 0 : ControlFile.checkPointCopy.oldestMulti += FirstMultiXactId;
469 24 : ControlFile.checkPointCopy.oldestMultiDB = InvalidOid;
470 : }
471 :
472 212 : if (mxoff_given)
473 20 : ControlFile.checkPointCopy.nextMultiOffset = set_mxoff;
474 :
475 212 : if (minXlogTli > ControlFile.checkPointCopy.ThisTimeLineID)
476 : {
477 0 : ControlFile.checkPointCopy.ThisTimeLineID = minXlogTli;
478 0 : ControlFile.checkPointCopy.PrevTimeLineID = minXlogTli;
479 : }
480 :
481 212 : if (set_wal_segsize != 0)
482 4 : ControlFile.xlog_seg_size = WalSegSz;
483 :
484 212 : if (set_char_signedness != -1)
485 4 : ControlFile.default_char_signedness = (set_char_signedness == 1);
486 :
487 212 : if (minXlogSegNo > newXlogSegNo)
488 6 : newXlogSegNo = minXlogSegNo;
489 :
490 212 : if (noupdate)
491 : {
492 76 : PrintNewControlValues();
493 76 : exit(0);
494 : }
495 :
496 : /*
497 : * If we had to guess anything, and -f was not given, just print the
498 : * guessed values and exit.
499 : */
500 136 : if (guessed && !force)
501 : {
502 2 : PrintNewControlValues();
503 2 : pg_log_error("not proceeding because control file values were guessed");
504 2 : pg_log_error_hint("If these values seem acceptable, use -f to force reset.");
505 2 : exit(1);
506 : }
507 :
508 : /*
509 : * Don't reset from a dirty pg_control without -f, either.
510 : */
511 134 : if (ControlFile.state != DB_SHUTDOWNED && !force)
512 : {
513 2 : pg_log_error("database server was not shut down cleanly");
514 2 : pg_log_error_detail("Resetting the write-ahead log might cause data to be lost.");
515 2 : pg_log_error_hint("If you want to proceed anyway, use -f to force reset.");
516 2 : exit(1);
517 : }
518 :
519 : /*
520 : * Else, do the dirty deed.
521 : */
522 132 : RewriteControlFile();
523 132 : KillExistingXLOG();
524 132 : KillExistingArchiveStatus();
525 132 : KillExistingWALSummaries();
526 132 : WriteEmptyXLOG();
527 :
528 132 : printf(_("Write-ahead log reset\n"));
529 132 : return 0;
530 : }
531 :
532 :
533 : /*
534 : * Look at the version string stored in PG_VERSION and decide if this utility
535 : * can be run safely or not.
536 : *
537 : * We don't want to inject pg_control and WAL files that are for a different
538 : * major version; that can't do anything good. Note that we don't treat
539 : * mismatching version info in pg_control as a reason to bail out, because
540 : * recovering from a corrupted pg_control is one of the main reasons for this
541 : * program to exist at all. However, PG_VERSION is unlikely to get corrupted,
542 : * and if it were it would be easy to fix by hand. So let's make this check
543 : * to prevent simple user errors.
544 : */
545 : static void
546 214 : CheckDataVersion(void)
547 : {
548 : char *version_str;
549 214 : uint32 version = get_pg_version(".", &version_str);
550 :
551 214 : if (GET_PG_MAJORVERSION_NUM(version) != PG_MAJORVERSION_NUM)
552 : {
553 0 : pg_log_error("data directory is of wrong version");
554 0 : pg_log_error_detail("File \"%s\" contains \"%s\", which is not compatible with this program's version \"%s\".",
555 : "PG_VERSION",
556 : version_str,
557 : PG_MAJORVERSION);
558 0 : exit(1);
559 : }
560 214 : }
561 :
562 :
563 : /*
564 : * Try to read the existing pg_control file.
565 : *
566 : * This routine is also responsible for updating old pg_control versions
567 : * to the current format. (Currently we don't do anything of the sort.)
568 : */
569 : static bool
570 212 : read_controlfile(void)
571 : {
572 : int fd;
573 : int len;
574 : char *buffer;
575 : pg_crc32c crc;
576 :
577 212 : if ((fd = open(XLOG_CONTROL_FILE, O_RDONLY | PG_BINARY, 0)) < 0)
578 : {
579 : /*
580 : * If pg_control is not there at all, or we can't read it, the odds
581 : * are we've been handed a bad DataDir path, so give up. User can do
582 : * "touch pg_control" to force us to proceed.
583 : */
584 0 : pg_log_error("could not open file \"%s\" for reading: %m",
585 : XLOG_CONTROL_FILE);
586 0 : if (errno == ENOENT)
587 0 : pg_log_error_hint("If you are sure the data directory path is correct, execute\n"
588 : " touch %s\n"
589 : "and try again.",
590 : XLOG_CONTROL_FILE);
591 0 : exit(1);
592 : }
593 :
594 : /* Use malloc to ensure we have a maxaligned buffer */
595 212 : buffer = (char *) pg_malloc(PG_CONTROL_FILE_SIZE);
596 :
597 212 : len = read(fd, buffer, PG_CONTROL_FILE_SIZE);
598 212 : if (len < 0)
599 0 : pg_fatal("could not read file \"%s\": %m", XLOG_CONTROL_FILE);
600 212 : close(fd);
601 :
602 212 : if (len >= sizeof(ControlFileData) &&
603 212 : ((ControlFileData *) buffer)->pg_control_version == PG_CONTROL_VERSION)
604 : {
605 : /* Check the CRC. */
606 210 : INIT_CRC32C(crc);
607 210 : COMP_CRC32C(crc,
608 : buffer,
609 : offsetof(ControlFileData, crc));
610 210 : FIN_CRC32C(crc);
611 :
612 210 : if (!EQ_CRC32C(crc, ((ControlFileData *) buffer)->crc))
613 : {
614 : /* We will use the data but treat it as guessed. */
615 6 : pg_log_warning("pg_control exists but has invalid CRC; proceed with caution");
616 6 : guessed = true;
617 : }
618 :
619 210 : memcpy(&ControlFile, buffer, sizeof(ControlFile));
620 :
621 : /* return false if WAL segment size is not valid */
622 210 : if (!IsValidWalSegSize(ControlFile.xlog_seg_size))
623 : {
624 6 : pg_log_warning(ngettext("pg_control specifies invalid WAL segment size (%d byte); proceed with caution",
625 : "pg_control specifies invalid WAL segment size (%d bytes); proceed with caution",
626 : ControlFile.xlog_seg_size),
627 : ControlFile.xlog_seg_size);
628 6 : return false;
629 : }
630 :
631 204 : return true;
632 : }
633 :
634 : /* Looks like it's a mess. */
635 2 : pg_log_warning("pg_control exists but is broken or wrong version; ignoring it");
636 2 : return false;
637 : }
638 :
639 :
640 : /*
641 : * Guess at pg_control values when we can't read the old ones.
642 : */
643 : static void
644 8 : GuessControlValues(void)
645 : {
646 : uint64 sysidentifier;
647 : struct timeval tv;
648 :
649 : /*
650 : * Set up a completely default set of pg_control values.
651 : */
652 8 : guessed = true;
653 8 : memset(&ControlFile, 0, sizeof(ControlFile));
654 :
655 8 : ControlFile.pg_control_version = PG_CONTROL_VERSION;
656 8 : ControlFile.catalog_version_no = CATALOG_VERSION_NO;
657 :
658 : /*
659 : * Create a new unique installation identifier, since we can no longer use
660 : * any old XLOG records. See notes in xlog.c about the algorithm.
661 : */
662 8 : gettimeofday(&tv, NULL);
663 8 : sysidentifier = ((uint64) tv.tv_sec) << 32;
664 8 : sysidentifier |= ((uint64) tv.tv_usec) << 12;
665 8 : sysidentifier |= getpid() & 0xFFF;
666 :
667 8 : ControlFile.system_identifier = sysidentifier;
668 :
669 8 : ControlFile.checkPointCopy.redo = SizeOfXLogLongPHD;
670 8 : ControlFile.checkPointCopy.ThisTimeLineID = 1;
671 8 : ControlFile.checkPointCopy.PrevTimeLineID = 1;
672 8 : ControlFile.checkPointCopy.fullPageWrites = false;
673 : ControlFile.checkPointCopy.nextXid =
674 8 : FullTransactionIdFromEpochAndXid(0, FirstNormalTransactionId);
675 8 : ControlFile.checkPointCopy.nextOid = FirstGenbkiObjectId;
676 8 : ControlFile.checkPointCopy.nextMulti = FirstMultiXactId;
677 8 : ControlFile.checkPointCopy.nextMultiOffset = 0;
678 8 : ControlFile.checkPointCopy.oldestXid = FirstNormalTransactionId;
679 8 : ControlFile.checkPointCopy.oldestXidDB = InvalidOid;
680 8 : ControlFile.checkPointCopy.oldestMulti = FirstMultiXactId;
681 8 : ControlFile.checkPointCopy.oldestMultiDB = InvalidOid;
682 8 : ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
683 8 : ControlFile.checkPointCopy.oldestActiveXid = InvalidTransactionId;
684 :
685 8 : ControlFile.state = DB_SHUTDOWNED;
686 8 : ControlFile.time = (pg_time_t) time(NULL);
687 8 : ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
688 8 : ControlFile.unloggedLSN = FirstNormalUnloggedLSN;
689 :
690 : /* minRecoveryPoint, backupStartPoint and backupEndPoint can be left zero */
691 :
692 8 : ControlFile.wal_level = WAL_LEVEL_MINIMAL;
693 8 : ControlFile.wal_log_hints = false;
694 8 : ControlFile.track_commit_timestamp = false;
695 8 : ControlFile.MaxConnections = 100;
696 8 : ControlFile.max_wal_senders = 10;
697 8 : ControlFile.max_worker_processes = 8;
698 8 : ControlFile.max_prepared_xacts = 0;
699 8 : ControlFile.max_locks_per_xact = 64;
700 :
701 8 : ControlFile.maxAlign = MAXIMUM_ALIGNOF;
702 8 : ControlFile.floatFormat = FLOATFORMAT_VALUE;
703 8 : ControlFile.blcksz = BLCKSZ;
704 8 : ControlFile.relseg_size = RELSEG_SIZE;
705 8 : ControlFile.slru_pages_per_segment = SLRU_PAGES_PER_SEGMENT;
706 8 : ControlFile.xlog_blcksz = XLOG_BLCKSZ;
707 8 : ControlFile.xlog_seg_size = DEFAULT_XLOG_SEG_SIZE;
708 8 : ControlFile.nameDataLen = NAMEDATALEN;
709 8 : ControlFile.indexMaxKeys = INDEX_MAX_KEYS;
710 8 : ControlFile.toast_max_chunk_size = TOAST_MAX_CHUNK_SIZE;
711 8 : ControlFile.loblksize = LOBLKSIZE;
712 8 : ControlFile.float8ByVal = true; /* vestigial */
713 :
714 : /*
715 : * XXX eventually, should try to grovel through old XLOG to develop more
716 : * accurate values for TimeLineID, nextXID, etc.
717 : */
718 8 : }
719 :
720 :
721 : /*
722 : * Print the guessed pg_control values when we had to guess.
723 : *
724 : * NB: this display should be just those fields that will not be
725 : * reset by RewriteControlFile().
726 : */
727 : static void
728 78 : PrintControlValues(bool guessed)
729 : {
730 78 : if (guessed)
731 6 : printf(_("Guessed pg_control values:\n\n"));
732 : else
733 72 : printf(_("Current pg_control values:\n\n"));
734 :
735 78 : printf(_("pg_control version number: %u\n"),
736 : ControlFile.pg_control_version);
737 78 : printf(_("Catalog version number: %u\n"),
738 : ControlFile.catalog_version_no);
739 78 : printf(_("Database system identifier: %" PRIu64 "\n"),
740 : ControlFile.system_identifier);
741 78 : printf(_("Latest checkpoint's TimeLineID: %u\n"),
742 : ControlFile.checkPointCopy.ThisTimeLineID);
743 78 : printf(_("Latest checkpoint's full_page_writes: %s\n"),
744 : ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off"));
745 78 : printf(_("Latest checkpoint's NextXID: %u:%u\n"),
746 : EpochFromFullTransactionId(ControlFile.checkPointCopy.nextXid),
747 : XidFromFullTransactionId(ControlFile.checkPointCopy.nextXid));
748 78 : printf(_("Latest checkpoint's NextOID: %u\n"),
749 : ControlFile.checkPointCopy.nextOid);
750 78 : printf(_("Latest checkpoint's NextMultiXactId: %u\n"),
751 : ControlFile.checkPointCopy.nextMulti);
752 78 : printf(_("Latest checkpoint's NextMultiOffset: %u\n"),
753 : ControlFile.checkPointCopy.nextMultiOffset);
754 78 : printf(_("Latest checkpoint's oldestXID: %u\n"),
755 : ControlFile.checkPointCopy.oldestXid);
756 78 : printf(_("Latest checkpoint's oldestXID's DB: %u\n"),
757 : ControlFile.checkPointCopy.oldestXidDB);
758 78 : printf(_("Latest checkpoint's oldestActiveXID: %u\n"),
759 : ControlFile.checkPointCopy.oldestActiveXid);
760 78 : printf(_("Latest checkpoint's oldestMultiXid: %u\n"),
761 : ControlFile.checkPointCopy.oldestMulti);
762 78 : printf(_("Latest checkpoint's oldestMulti's DB: %u\n"),
763 : ControlFile.checkPointCopy.oldestMultiDB);
764 78 : printf(_("Latest checkpoint's oldestCommitTsXid:%u\n"),
765 : ControlFile.checkPointCopy.oldestCommitTsXid);
766 78 : printf(_("Latest checkpoint's newestCommitTsXid:%u\n"),
767 : ControlFile.checkPointCopy.newestCommitTsXid);
768 78 : printf(_("Maximum data alignment: %u\n"),
769 : ControlFile.maxAlign);
770 : /* we don't print floatFormat since can't say much useful about it */
771 78 : printf(_("Database block size: %u\n"),
772 : ControlFile.blcksz);
773 78 : printf(_("Blocks per segment of large relation: %u\n"),
774 : ControlFile.relseg_size);
775 78 : printf(_("Pages per SLRU segment: %u\n"),
776 : ControlFile.slru_pages_per_segment);
777 78 : printf(_("WAL block size: %u\n"),
778 : ControlFile.xlog_blcksz);
779 78 : printf(_("Bytes per WAL segment: %u\n"),
780 : ControlFile.xlog_seg_size);
781 78 : printf(_("Maximum length of identifiers: %u\n"),
782 : ControlFile.nameDataLen);
783 78 : printf(_("Maximum columns in an index: %u\n"),
784 : ControlFile.indexMaxKeys);
785 78 : printf(_("Maximum size of a TOAST chunk: %u\n"),
786 : ControlFile.toast_max_chunk_size);
787 78 : printf(_("Size of a large-object chunk: %u\n"),
788 : ControlFile.loblksize);
789 : /* This is no longer configurable, but users may still expect to see it: */
790 78 : printf(_("Date/time type storage: %s\n"),
791 : _("64-bit integers"));
792 78 : printf(_("Float8 argument passing: %s\n"),
793 : (ControlFile.float8ByVal ? _("by value") : _("by reference")));
794 78 : printf(_("Data page checksum version: %u\n"),
795 : ControlFile.data_checksum_version);
796 78 : printf(_("Default char data signedness: %s\n"),
797 : (ControlFile.default_char_signedness ? _("signed") : _("unsigned")));
798 78 : }
799 :
800 :
801 : /*
802 : * Print the values to be changed.
803 : */
804 : static void
805 78 : PrintNewControlValues(void)
806 : {
807 : char fname[MAXFNAMELEN];
808 :
809 : /* This will be always printed in order to keep format same. */
810 78 : printf(_("\n\nValues to be changed:\n\n"));
811 :
812 78 : XLogFileName(fname, ControlFile.checkPointCopy.ThisTimeLineID,
813 : newXlogSegNo, WalSegSz);
814 78 : printf(_("First log segment after reset: %s\n"), fname);
815 :
816 78 : if (mxid_given)
817 : {
818 2 : printf(_("NextMultiXactId: %u\n"),
819 : ControlFile.checkPointCopy.nextMulti);
820 2 : printf(_("OldestMultiXid: %u\n"),
821 : ControlFile.checkPointCopy.oldestMulti);
822 2 : printf(_("OldestMulti's DB: %u\n"),
823 : ControlFile.checkPointCopy.oldestMultiDB);
824 : }
825 :
826 78 : if (mxoff_given)
827 : {
828 2 : printf(_("NextMultiOffset: %u\n"),
829 : ControlFile.checkPointCopy.nextMultiOffset);
830 : }
831 :
832 78 : if (set_oid != 0)
833 : {
834 2 : printf(_("NextOID: %u\n"),
835 : ControlFile.checkPointCopy.nextOid);
836 : }
837 :
838 78 : if (set_xid != 0)
839 : {
840 2 : printf(_("NextXID: %u\n"),
841 : XidFromFullTransactionId(ControlFile.checkPointCopy.nextXid));
842 : }
843 :
844 78 : if (set_oldest_xid != 0)
845 : {
846 2 : printf(_("OldestXID: %u\n"),
847 : ControlFile.checkPointCopy.oldestXid);
848 2 : printf(_("OldestXID's DB: %u\n"),
849 : ControlFile.checkPointCopy.oldestXidDB);
850 : }
851 :
852 78 : if (set_xid_epoch != -1)
853 : {
854 2 : printf(_("NextXID epoch: %u\n"),
855 : EpochFromFullTransactionId(ControlFile.checkPointCopy.nextXid));
856 : }
857 :
858 78 : if (set_oldest_commit_ts_xid != 0)
859 : {
860 2 : printf(_("oldestCommitTsXid: %u\n"),
861 : ControlFile.checkPointCopy.oldestCommitTsXid);
862 : }
863 78 : if (set_newest_commit_ts_xid != 0)
864 : {
865 0 : printf(_("newestCommitTsXid: %u\n"),
866 : ControlFile.checkPointCopy.newestCommitTsXid);
867 : }
868 :
869 78 : if (set_wal_segsize != 0)
870 : {
871 2 : printf(_("Bytes per WAL segment: %u\n"),
872 : ControlFile.xlog_seg_size);
873 : }
874 78 : }
875 :
876 :
877 : /*
878 : * Write out the new pg_control file.
879 : */
880 : static void
881 132 : RewriteControlFile(void)
882 : {
883 : /*
884 : * Adjust fields as needed to force an empty XLOG starting at
885 : * newXlogSegNo.
886 : */
887 132 : XLogSegNoOffsetToRecPtr(newXlogSegNo, SizeOfXLogLongPHD, WalSegSz,
888 : ControlFile.checkPointCopy.redo);
889 132 : ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
890 :
891 132 : ControlFile.state = DB_SHUTDOWNED;
892 132 : ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
893 132 : ControlFile.minRecoveryPoint = 0;
894 132 : ControlFile.minRecoveryPointTLI = 0;
895 132 : ControlFile.backupStartPoint = 0;
896 132 : ControlFile.backupEndPoint = 0;
897 132 : ControlFile.backupEndRequired = false;
898 :
899 : /*
900 : * Force the defaults for max_* settings. The values don't really matter
901 : * as long as wal_level='minimal'; the postmaster will reset these fields
902 : * anyway at startup.
903 : */
904 132 : ControlFile.wal_level = WAL_LEVEL_MINIMAL;
905 132 : ControlFile.wal_log_hints = false;
906 132 : ControlFile.track_commit_timestamp = false;
907 132 : ControlFile.MaxConnections = 100;
908 132 : ControlFile.max_wal_senders = 10;
909 132 : ControlFile.max_worker_processes = 8;
910 132 : ControlFile.max_prepared_xacts = 0;
911 132 : ControlFile.max_locks_per_xact = 64;
912 :
913 : /* The control file gets flushed here. */
914 132 : update_controlfile(".", &ControlFile, true);
915 132 : }
916 :
917 :
918 : /*
919 : * Scan existing XLOG files and determine the highest existing WAL address
920 : *
921 : * On entry, ControlFile.checkPointCopy.redo and ControlFile.xlog_seg_size
922 : * are assumed valid (note that we allow the old xlog seg size to differ
923 : * from what we're using). On exit, newXlogSegNo is set to suitable
924 : * value for the beginning of replacement WAL (in our seg size).
925 : */
926 : static void
927 212 : FindEndOfXLOG(void)
928 : {
929 : DIR *xldir;
930 : struct dirent *xlde;
931 : uint64 xlogbytepos;
932 :
933 : /*
934 : * Initialize the max() computation using the last checkpoint address from
935 : * old pg_control. Note that for the moment we are working with segment
936 : * numbering according to the old xlog seg size.
937 : */
938 212 : XLByteToSeg(ControlFile.checkPointCopy.redo, newXlogSegNo,
939 : ControlFile.xlog_seg_size);
940 :
941 : /*
942 : * Scan the pg_wal directory to find existing WAL segment files. We assume
943 : * any present have been used; in most scenarios this should be
944 : * conservative, because of xlog.c's attempts to pre-create files.
945 : */
946 212 : xldir = opendir(XLOGDIR);
947 212 : if (xldir == NULL)
948 0 : pg_fatal("could not open directory \"%s\": %m", XLOGDIR);
949 :
950 1598 : while (errno = 0, (xlde = readdir(xldir)) != NULL)
951 : {
952 2236 : if (IsXLogFileName(xlde->d_name) ||
953 850 : IsPartialXLogFileName(xlde->d_name))
954 : {
955 : TimeLineID tli;
956 : XLogSegNo segno;
957 :
958 : /* Use the segment size from the control file */
959 536 : XLogFromFileName(xlde->d_name, &tli, &segno,
960 536 : ControlFile.xlog_seg_size);
961 :
962 : /*
963 : * Note: we take the max of all files found, regardless of their
964 : * timelines. Another possibility would be to ignore files of
965 : * timelines other than the target TLI, but this seems safer.
966 : * Better too large a result than too small...
967 : */
968 536 : if (segno > newXlogSegNo)
969 90 : newXlogSegNo = segno;
970 : }
971 : }
972 :
973 212 : if (errno)
974 0 : pg_fatal("could not read directory \"%s\": %m", XLOGDIR);
975 :
976 212 : if (closedir(xldir))
977 0 : pg_fatal("could not close directory \"%s\": %m", XLOGDIR);
978 :
979 : /*
980 : * Finally, convert to new xlog seg size, and advance by one to ensure we
981 : * are in virgin territory.
982 : */
983 212 : xlogbytepos = newXlogSegNo * ControlFile.xlog_seg_size;
984 212 : newXlogSegNo = (xlogbytepos + ControlFile.xlog_seg_size - 1) / WalSegSz;
985 212 : newXlogSegNo++;
986 212 : }
987 :
988 :
989 : /*
990 : * Remove existing XLOG files
991 : */
992 : static void
993 132 : KillExistingXLOG(void)
994 : {
995 : DIR *xldir;
996 : struct dirent *xlde;
997 : char path[MAXPGPATH + sizeof(XLOGDIR)];
998 :
999 132 : xldir = opendir(XLOGDIR);
1000 132 : if (xldir == NULL)
1001 0 : pg_fatal("could not open directory \"%s\": %m", XLOGDIR);
1002 :
1003 838 : while (errno = 0, (xlde = readdir(xldir)) != NULL)
1004 : {
1005 1236 : if (IsXLogFileName(xlde->d_name) ||
1006 530 : IsPartialXLogFileName(xlde->d_name))
1007 : {
1008 176 : snprintf(path, sizeof(path), "%s/%s", XLOGDIR, xlde->d_name);
1009 176 : if (unlink(path) < 0)
1010 0 : pg_fatal("could not delete file \"%s\": %m", path);
1011 : }
1012 : }
1013 :
1014 132 : if (errno)
1015 0 : pg_fatal("could not read directory \"%s\": %m", XLOGDIR);
1016 :
1017 132 : if (closedir(xldir))
1018 0 : pg_fatal("could not close directory \"%s\": %m", XLOGDIR);
1019 132 : }
1020 :
1021 :
1022 : /*
1023 : * Remove existing archive status files
1024 : */
1025 : static void
1026 132 : KillExistingArchiveStatus(void)
1027 : {
1028 : #define ARCHSTATDIR XLOGDIR "/archive_status"
1029 :
1030 : DIR *xldir;
1031 : struct dirent *xlde;
1032 : char path[MAXPGPATH + sizeof(ARCHSTATDIR)];
1033 :
1034 132 : xldir = opendir(ARCHSTATDIR);
1035 132 : if (xldir == NULL)
1036 0 : pg_fatal("could not open directory \"%s\": %m", ARCHSTATDIR);
1037 :
1038 396 : while (errno = 0, (xlde = readdir(xldir)) != NULL)
1039 : {
1040 264 : if (strspn(xlde->d_name, "0123456789ABCDEF") == XLOG_FNAME_LEN &&
1041 0 : (strcmp(xlde->d_name + XLOG_FNAME_LEN, ".ready") == 0 ||
1042 0 : strcmp(xlde->d_name + XLOG_FNAME_LEN, ".done") == 0 ||
1043 0 : strcmp(xlde->d_name + XLOG_FNAME_LEN, ".partial.ready") == 0 ||
1044 0 : strcmp(xlde->d_name + XLOG_FNAME_LEN, ".partial.done") == 0))
1045 : {
1046 0 : snprintf(path, sizeof(path), "%s/%s", ARCHSTATDIR, xlde->d_name);
1047 0 : if (unlink(path) < 0)
1048 0 : pg_fatal("could not delete file \"%s\": %m", path);
1049 : }
1050 : }
1051 :
1052 132 : if (errno)
1053 0 : pg_fatal("could not read directory \"%s\": %m", ARCHSTATDIR);
1054 :
1055 132 : if (closedir(xldir))
1056 0 : pg_fatal("could not close directory \"%s\": %m", ARCHSTATDIR);
1057 132 : }
1058 :
1059 : /*
1060 : * Remove existing WAL summary files
1061 : */
1062 : static void
1063 132 : KillExistingWALSummaries(void)
1064 : {
1065 : #define WALSUMMARYDIR XLOGDIR "/summaries"
1066 : #define WALSUMMARY_NHEXCHARS 40
1067 :
1068 : DIR *xldir;
1069 : struct dirent *xlde;
1070 : char path[MAXPGPATH + sizeof(WALSUMMARYDIR)];
1071 :
1072 132 : xldir = opendir(WALSUMMARYDIR);
1073 132 : if (xldir == NULL)
1074 0 : pg_fatal("could not open directory \"%s\": %m", WALSUMMARYDIR);
1075 :
1076 396 : while (errno = 0, (xlde = readdir(xldir)) != NULL)
1077 : {
1078 264 : if (strspn(xlde->d_name, "0123456789ABCDEF") == WALSUMMARY_NHEXCHARS &&
1079 0 : strcmp(xlde->d_name + WALSUMMARY_NHEXCHARS, ".summary") == 0)
1080 : {
1081 0 : snprintf(path, sizeof(path), "%s/%s", WALSUMMARYDIR, xlde->d_name);
1082 0 : if (unlink(path) < 0)
1083 0 : pg_fatal("could not delete file \"%s\": %m", path);
1084 : }
1085 : }
1086 :
1087 132 : if (errno)
1088 0 : pg_fatal("could not read directory \"%s\": %m", WALSUMMARYDIR);
1089 :
1090 132 : if (closedir(xldir))
1091 0 : pg_fatal("could not close directory \"%s\": %m", ARCHSTATDIR);
1092 132 : }
1093 :
1094 : /*
1095 : * Write an empty XLOG file, containing only the checkpoint record
1096 : * already set up in ControlFile.
1097 : */
1098 : static void
1099 132 : WriteEmptyXLOG(void)
1100 : {
1101 : PGAlignedXLogBlock buffer;
1102 : XLogPageHeader page;
1103 : XLogLongPageHeader longpage;
1104 : XLogRecord *record;
1105 : pg_crc32c crc;
1106 : char path[MAXPGPATH];
1107 : int fd;
1108 : int nbytes;
1109 : char *recptr;
1110 :
1111 132 : memset(buffer.data, 0, XLOG_BLCKSZ);
1112 :
1113 : /* Set up the XLOG page header */
1114 132 : page = (XLogPageHeader) buffer.data;
1115 132 : page->xlp_magic = XLOG_PAGE_MAGIC;
1116 132 : page->xlp_info = XLP_LONG_HEADER;
1117 132 : page->xlp_tli = ControlFile.checkPointCopy.ThisTimeLineID;
1118 132 : page->xlp_pageaddr = ControlFile.checkPointCopy.redo - SizeOfXLogLongPHD;
1119 132 : longpage = (XLogLongPageHeader) page;
1120 132 : longpage->xlp_sysid = ControlFile.system_identifier;
1121 132 : longpage->xlp_seg_size = WalSegSz;
1122 132 : longpage->xlp_xlog_blcksz = XLOG_BLCKSZ;
1123 :
1124 : /* Insert the initial checkpoint record */
1125 132 : recptr = (char *) page + SizeOfXLogLongPHD;
1126 132 : record = (XLogRecord *) recptr;
1127 132 : record->xl_prev = 0;
1128 132 : record->xl_xid = InvalidTransactionId;
1129 132 : record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(CheckPoint);
1130 132 : record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
1131 132 : record->xl_rmid = RM_XLOG_ID;
1132 :
1133 132 : recptr += SizeOfXLogRecord;
1134 132 : *(recptr++) = (char) XLR_BLOCK_ID_DATA_SHORT;
1135 132 : *(recptr++) = sizeof(CheckPoint);
1136 132 : memcpy(recptr, &ControlFile.checkPointCopy,
1137 : sizeof(CheckPoint));
1138 :
1139 132 : INIT_CRC32C(crc);
1140 132 : COMP_CRC32C(crc, ((char *) record) + SizeOfXLogRecord, record->xl_tot_len - SizeOfXLogRecord);
1141 132 : COMP_CRC32C(crc, (char *) record, offsetof(XLogRecord, xl_crc));
1142 132 : FIN_CRC32C(crc);
1143 132 : record->xl_crc = crc;
1144 :
1145 : /* Write the first page */
1146 132 : XLogFilePath(path, ControlFile.checkPointCopy.ThisTimeLineID,
1147 : newXlogSegNo, WalSegSz);
1148 :
1149 132 : unlink(path);
1150 :
1151 132 : fd = open(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
1152 : pg_file_create_mode);
1153 132 : if (fd < 0)
1154 0 : pg_fatal("could not open file \"%s\": %m", path);
1155 :
1156 132 : errno = 0;
1157 132 : if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
1158 : {
1159 : /* if write didn't set errno, assume problem is no disk space */
1160 0 : if (errno == 0)
1161 0 : errno = ENOSPC;
1162 0 : pg_fatal("could not write file \"%s\": %m", path);
1163 : }
1164 :
1165 : /* Fill the rest of the file with zeroes */
1166 132 : memset(buffer.data, 0, XLOG_BLCKSZ);
1167 239616 : for (nbytes = XLOG_BLCKSZ; nbytes < WalSegSz; nbytes += XLOG_BLCKSZ)
1168 : {
1169 239484 : errno = 0;
1170 239484 : if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
1171 : {
1172 0 : if (errno == 0)
1173 0 : errno = ENOSPC;
1174 0 : pg_fatal("could not write file \"%s\": %m", path);
1175 : }
1176 : }
1177 :
1178 132 : if (fsync(fd) != 0)
1179 0 : pg_fatal("fsync error: %m");
1180 :
1181 132 : close(fd);
1182 132 : }
1183 :
1184 :
1185 : static void
1186 2 : usage(void)
1187 : {
1188 2 : printf(_("%s resets the PostgreSQL write-ahead log.\n\n"), progname);
1189 2 : printf(_("Usage:\n"));
1190 2 : printf(_(" %s [OPTION]... DATADIR\n"), progname);
1191 :
1192 2 : printf(_("\nOptions:\n"));
1193 2 : printf(_(" [-D, --pgdata=]DATADIR data directory\n"));
1194 2 : printf(_(" -f, --force force update to be done even after unclean shutdown or\n"
1195 : " if pg_control values had to be guessed\n"));
1196 2 : printf(_(" -n, --dry-run no update, just show what would be done\n"));
1197 2 : printf(_(" -V, --version output version information, then exit\n"));
1198 2 : printf(_(" -?, --help show this help, then exit\n"));
1199 :
1200 2 : printf(_("\nOptions to override control file values:\n"));
1201 2 : printf(_(" -c, --commit-timestamp-ids=XID,XID\n"
1202 : " set oldest and newest transactions bearing\n"
1203 : " commit timestamp (zero means no change)\n"));
1204 2 : printf(_(" -e, --epoch=XIDEPOCH set next transaction ID epoch\n"));
1205 2 : printf(_(" -l, --next-wal-file=WALFILE set minimum starting location for new WAL\n"));
1206 2 : printf(_(" -m, --multixact-ids=MXID,MXID set next and oldest multitransaction ID\n"));
1207 2 : printf(_(" -o, --next-oid=OID set next OID\n"));
1208 2 : printf(_(" -O, --multixact-offset=OFFSET set next multitransaction offset\n"));
1209 2 : printf(_(" -u, --oldest-transaction-id=XID set oldest transaction ID\n"));
1210 2 : printf(_(" -x, --next-transaction-id=XID set next transaction ID\n"));
1211 2 : printf(_(" --char-signedness=OPTION set char signedness to \"signed\" or \"unsigned\"\n"));
1212 2 : printf(_(" --wal-segsize=SIZE size of WAL segments, in megabytes\n"));
1213 :
1214 2 : printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1215 2 : printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
1216 2 : }
|