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