PostgreSQL Source Code git master
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 "fe_utils/version.h"
59#include "getopt_long.h"
60#include "pg_getopt.h"
62
63static ControlFileData ControlFile; /* pg_control values */
64static XLogSegNo newXlogSegNo; /* new XLOG segment # */
65static bool guessed = false; /* T if we had to guess at any values */
66static const char *progname;
72static Oid set_oid = 0;
73static bool mxid_given = false;
75static bool mxoff_given = false;
79static int WalSegSz;
80static int set_wal_segsize;
81static int set_char_signedness = -1;
82
83static void CheckDataVersion(void);
84static bool read_controlfile(void);
85static void GuessControlValues(void);
86static void PrintControlValues(bool guessed);
87static void PrintNewControlValues(void);
88static void RewriteControlFile(void);
89static void FindEndOfXLOG(void);
90static void KillExistingXLOG(void);
91static void KillExistingArchiveStatus(void);
92static void KillExistingWALSummaries(void);
93static void WriteEmptyXLOG(void);
94static void usage(void);
95
96
97int
98main(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 bool force = false;
119 bool noupdate = false;
120 MultiXactId set_oldestmxid = 0;
121 char *endptr;
122 char *endptr2;
123 int64 tmpi64;
124 char *DataDir = NULL;
125 char *log_fname = NULL;
126 int fd;
127
128 pg_logging_init(argv[0]);
129 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_resetwal"));
130 progname = get_progname(argv[0]);
131
132 if (argc > 1)
133 {
134 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
135 {
136 usage();
137 exit(0);
138 }
139 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
140 {
141 puts("pg_resetwal (PostgreSQL) " PG_VERSION);
142 exit(0);
143 }
144 }
145
146
147 while ((c = getopt_long(argc, argv, "c:D:e:fl:m:no:O:u:x:", long_options, NULL)) != -1)
148 {
149 switch (c)
150 {
151 case 'D':
152 DataDir = optarg;
153 break;
154
155 case 'f':
156 force = true;
157 break;
158
159 case 'n':
160 noupdate = true;
161 break;
162
163 case 'e':
164 errno = 0;
165 set_xid_epoch = strtoul(optarg, &endptr, 0);
166 if (endptr == optarg || *endptr != '\0' || errno != 0)
167 {
168 /*------
169 translator: the second %s is a command line argument (-e, etc) */
170 pg_log_error("invalid argument for option %s", "-e");
171 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
172 exit(1);
173 }
174 if (set_xid_epoch == -1)
175 pg_fatal("transaction ID epoch (-e) must not be -1");
176 break;
177
178 case 'u':
179 errno = 0;
180 set_oldest_xid = strtoul(optarg, &endptr, 0);
181 if (endptr == optarg || *endptr != '\0' || errno != 0)
182 {
183 pg_log_error("invalid argument for option %s", "-u");
184 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
185 exit(1);
186 }
188 pg_fatal("oldest transaction ID (-u) must be greater than or equal to %u", FirstNormalTransactionId);
189 break;
190
191 case 'x':
192 errno = 0;
193 set_xid = strtoul(optarg, &endptr, 0);
194 if (endptr == optarg || *endptr != '\0' || errno != 0)
195 {
196 pg_log_error("invalid argument for option %s", "-x");
197 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
198 exit(1);
199 }
201 pg_fatal("transaction ID (-x) must be greater than or equal to %u", FirstNormalTransactionId);
202 break;
203
204 case 'c':
205 errno = 0;
206 set_oldest_commit_ts_xid = strtoul(optarg, &endptr, 0);
207 if (endptr == optarg || *endptr != ',' || errno != 0)
208 {
209 pg_log_error("invalid argument for option %s", "-c");
210 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
211 exit(1);
212 }
213 set_newest_commit_ts_xid = strtoul(endptr + 1, &endptr2, 0);
214 if (endptr2 == endptr + 1 || *endptr2 != '\0' || errno != 0)
215 {
216 pg_log_error("invalid argument for option %s", "-c");
217 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
218 exit(1);
219 }
220
223 pg_fatal("transaction ID (-c) must be either %u or greater than or equal to %u", InvalidTransactionId, FirstNormalTransactionId);
224
227 pg_fatal("transaction ID (-c) must be either %u or greater than or equal to %u", InvalidTransactionId, FirstNormalTransactionId);
228 break;
229
230 case 'o':
231 errno = 0;
232 set_oid = strtoul(optarg, &endptr, 0);
233 if (endptr == optarg || *endptr != '\0' || errno != 0)
234 {
235 pg_log_error("invalid argument for option %s", "-o");
236 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
237 exit(1);
238 }
239 if (set_oid == 0)
240 pg_fatal("OID (-o) must not be 0");
241 break;
242
243 case 'm':
244 errno = 0;
245 set_mxid = strtoul(optarg, &endptr, 0);
246 if (endptr == optarg || *endptr != ',' || errno != 0)
247 {
248 pg_log_error("invalid argument for option %s", "-m");
249 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
250 exit(1);
251 }
252
253 set_oldestmxid = strtoul(endptr + 1, &endptr2, 0);
254 if (endptr2 == endptr + 1 || *endptr2 != '\0' || errno != 0)
255 {
256 pg_log_error("invalid argument for option %s", "-m");
257 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
258 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 if (set_oldestmxid == 0)
266 pg_fatal("oldest multitransaction ID (-m) must not be 0");
267 mxid_given = true;
268 break;
269
270 case 'O':
271 errno = 0;
272 tmpi64 = strtoi64(optarg, &endptr, 0);
273 if (endptr == optarg || *endptr != '\0' || errno != 0)
274 {
275 pg_log_error("invalid argument for option %s", "-O");
276 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
277 exit(1);
278 }
279 if (tmpi64 < 0 || tmpi64 > (int64) MaxMultiXactOffset)
280 pg_fatal("multitransaction offset (-O) must be between 0 and %u", MaxMultiXactOffset);
281
282 set_mxoff = (MultiXactOffset) tmpi64;
283 mxoff_given = true;
284 break;
285
286 case 'l':
287 if (strspn(optarg, "01234567890ABCDEFabcdef") != XLOG_FNAME_LEN)
288 {
289 pg_log_error("invalid argument for option %s", "-l");
290 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
291 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 log_fname = pg_strdup(optarg);
299 break;
300
301 case 1:
302 {
303 int wal_segsize_mb;
304
305 if (!option_parse_int(optarg, "--wal-segsize", 1, 1024, &wal_segsize_mb))
306 exit(1);
307 set_wal_segsize = wal_segsize_mb * 1024 * 1024;
309 pg_fatal("argument of %s must be a power of two between 1 and 1024", "--wal-segsize");
310 break;
311 }
312
313 case 2:
314 {
315 errno = 0;
316
317 if (pg_strcasecmp(optarg, "signed") == 0)
319 else if (pg_strcasecmp(optarg, "unsigned") == 0)
321 else
322 {
323 pg_log_error("invalid argument for option %s", "--char-signedness");
324 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
325 exit(1);
326 }
327 break;
328 }
329
330 default:
331 /* getopt_long already emitted a complaint */
332 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
333 exit(1);
334 }
335 }
336
337 if (DataDir == NULL && optind < argc)
338 DataDir = argv[optind++];
339
340 /* Complain if any arguments remain */
341 if (optind < argc)
342 {
343 pg_log_error("too many command-line arguments (first is \"%s\")",
344 argv[optind]);
345 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
346 exit(1);
347 }
348
349 if (DataDir == NULL)
350 {
351 pg_log_error("no data directory specified");
352 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
353 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 if (geteuid() == 0)
364 {
365 pg_log_error("cannot be executed by \"root\"");
366 pg_log_error_hint("You must run %s as the PostgreSQL superuser.",
367 progname);
368 exit(1);
369 }
370#endif
371
373
374 /* Set mask based on PGDATA permissions */
376 pg_fatal("could not read permissions of directory \"%s\": %m",
377 DataDir);
378
379 umask(pg_mode_mask);
380
381 if (chdir(DataDir) < 0)
382 pg_fatal("could not change directory to \"%s\": %m",
383 DataDir);
384
385 /* Check that data directory matches our server version */
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 if ((fd = open("postmaster.pid", O_RDONLY, 0)) < 0)
393 {
394 if (errno != ENOENT)
395 pg_fatal("could not open file \"%s\" for reading: %m",
396 "postmaster.pid");
397 }
398 else
399 {
400 pg_log_error("lock file \"%s\" exists", "postmaster.pid");
401 pg_log_error_hint("Is a server running? If not, delete the lock file and try again.");
402 exit(1);
403 }
404
405 /*
406 * Attempt to read the existing pg_control file
407 */
408 if (!read_controlfile())
410
411 /*
412 * If no new WAL segment size was specified, use the control file value.
413 */
414 if (set_wal_segsize != 0)
416 else
418
419 if (log_fname != NULL)
421
422 /*
423 * Also look at existing segment files to set up newXlogSegNo
424 */
426
427 /*
428 * If we're not going to proceed with the reset, print the current control
429 * file parameters.
430 */
431 if ((guessed && !force) || noupdate)
433
434 /*
435 * Adjust fields if required by switches. (Do this now so that printout,
436 * if any, includes these values.)
437 */
438 if (set_xid_epoch != -1)
442
443 if (set_oldest_xid != 0)
444 {
447 }
448
449 if (set_xid != 0)
452 set_xid);
453
458
459 if (set_oid != 0)
461
462 if (mxid_given)
463 {
465
466 ControlFile.checkPointCopy.oldestMulti = set_oldestmxid;
470 }
471
472 if (mxoff_given)
474
476 {
479 }
480
481 if (set_wal_segsize != 0)
483
484 if (set_char_signedness != -1)
486
489
490 if (noupdate)
491 {
493 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 if (guessed && !force)
501 {
503 pg_log_error("not proceeding because control file values were guessed");
504 pg_log_error_hint("If these values seem acceptable, use -f to force reset.");
505 exit(1);
506 }
507
508 /*
509 * Don't reset from a dirty pg_control without -f, either.
510 */
511 if (ControlFile.state != DB_SHUTDOWNED && !force)
512 {
513 pg_log_error("database server was not shut down cleanly");
514 pg_log_error_detail("Resetting the write-ahead log might cause data to be lost.");
515 pg_log_error_hint("If you want to proceed anyway, use -f to force reset.");
516 exit(1);
517 }
518
519 /*
520 * Else, do the dirty deed.
521 */
527
528 printf(_("Write-ahead log reset\n"));
529 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 */
545static void
547{
548 char *version_str;
549 uint32 version = get_pg_version(".", &version_str);
550
551 if (GET_PG_MAJORVERSION_NUM(version) != PG_MAJORVERSION_NUM)
552 {
553 pg_log_error("data directory is of wrong version");
554 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 exit(1);
559 }
560}
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 */
569static bool
571{
572 int fd;
573 int len;
574 char *buffer;
576
577 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 pg_log_error("could not open file \"%s\" for reading: %m",
586 if (errno == ENOENT)
587 pg_log_error_hint("If you are sure the data directory path is correct, execute\n"
588 " touch %s\n"
589 "and try again.",
591 exit(1);
592 }
593
594 /* Use malloc to ensure we have a maxaligned buffer */
595 buffer = (char *) pg_malloc(PG_CONTROL_FILE_SIZE);
596
597 len = read(fd, buffer, PG_CONTROL_FILE_SIZE);
598 if (len < 0)
599 pg_fatal("could not read file \"%s\": %m", XLOG_CONTROL_FILE);
600 close(fd);
601
602 if (len >= sizeof(ControlFileData) &&
603 ((ControlFileData *) buffer)->pg_control_version == PG_CONTROL_VERSION)
604 {
605 /* Check the CRC. */
608 buffer,
609 offsetof(ControlFileData, crc));
611
612 if (!EQ_CRC32C(crc, ((ControlFileData *) buffer)->crc))
613 {
614 /* We will use the data but treat it as guessed. */
615 pg_log_warning("pg_control exists but has invalid CRC; proceed with caution");
616 guessed = true;
617 }
618
619 memcpy(&ControlFile, buffer, sizeof(ControlFile));
620
621 /* return false if WAL segment size is not valid */
623 {
624 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",
628 return false;
629 }
630
631 return true;
632 }
633
634 /* Looks like it's a mess. */
635 pg_log_warning("pg_control exists but is broken or wrong version; ignoring it");
636 return false;
637}
638
639
640/*
641 * Guess at pg_control values when we can't read the old ones.
642 */
643static void
645{
646 uint64 sysidentifier;
647 struct timeval tv;
648
649 /*
650 * Set up a completely default set of pg_control values.
651 */
652 guessed = true;
653 memset(&ControlFile, 0, sizeof(ControlFile));
654
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 gettimeofday(&tv, NULL);
663 sysidentifier = ((uint64) tv.tv_sec) << 32;
664 sysidentifier |= ((uint64) tv.tv_usec) << 12;
665 sysidentifier |= getpid() & 0xFFF;
666
667 ControlFile.system_identifier = sysidentifier;
668
684
686 ControlFile.time = (pg_time_t) time(NULL);
689
690 /* minRecoveryPoint, backupStartPoint and backupEndPoint can be left zero */
691
700
701 ControlFile.maxAlign = MAXIMUM_ALIGNOF;
703 ControlFile.blcksz = BLCKSZ;
704 ControlFile.relseg_size = RELSEG_SIZE;
706 ControlFile.xlog_blcksz = XLOG_BLCKSZ;
712 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}
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 */
727static void
729{
730 if (guessed)
731 printf(_("Guessed pg_control values:\n\n"));
732 else
733 printf(_("Current pg_control values:\n\n"));
734
735 printf(_("pg_control version number: %u\n"),
737 printf(_("Catalog version number: %u\n"),
739 printf(_("Database system identifier: %" PRIu64 "\n"),
741 printf(_("Latest checkpoint's TimeLineID: %u\n"),
743 printf(_("Latest checkpoint's full_page_writes: %s\n"),
744 ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off"));
745 printf(_("Latest checkpoint's NextXID: %u:%u\n"),
748 printf(_("Latest checkpoint's NextOID: %u\n"),
750 printf(_("Latest checkpoint's NextMultiXactId: %u\n"),
752 printf(_("Latest checkpoint's NextMultiOffset: %u\n"),
754 printf(_("Latest checkpoint's oldestXID: %u\n"),
756 printf(_("Latest checkpoint's oldestXID's DB: %u\n"),
758 printf(_("Latest checkpoint's oldestActiveXID: %u\n"),
760 printf(_("Latest checkpoint's oldestMultiXid: %u\n"),
762 printf(_("Latest checkpoint's oldestMulti's DB: %u\n"),
764 printf(_("Latest checkpoint's oldestCommitTsXid:%u\n"),
766 printf(_("Latest checkpoint's newestCommitTsXid:%u\n"),
768 printf(_("Maximum data alignment: %u\n"),
770 /* we don't print floatFormat since can't say much useful about it */
771 printf(_("Database block size: %u\n"),
773 printf(_("Blocks per segment of large relation: %u\n"),
775 printf(_("Pages per SLRU segment: %u\n"),
777 printf(_("WAL block size: %u\n"),
779 printf(_("Bytes per WAL segment: %u\n"),
781 printf(_("Maximum length of identifiers: %u\n"),
783 printf(_("Maximum columns in an index: %u\n"),
785 printf(_("Maximum size of a TOAST chunk: %u\n"),
787 printf(_("Size of a large-object chunk: %u\n"),
789 /* This is no longer configurable, but users may still expect to see it: */
790 printf(_("Date/time type storage: %s\n"),
791 _("64-bit integers"));
792 printf(_("Float8 argument passing: %s\n"),
793 (ControlFile.float8ByVal ? _("by value") : _("by reference")));
794 printf(_("Data page checksum version: %u\n"),
796 printf(_("Default char data signedness: %s\n"),
797 (ControlFile.default_char_signedness ? _("signed") : _("unsigned")));
798}
799
800
801/*
802 * Print the values to be changed.
803 */
804static void
806{
807 char fname[MAXFNAMELEN];
808
809 /* This will be always printed in order to keep format same. */
810 printf(_("\n\nValues to be changed:\n\n"));
811
814 printf(_("First log segment after reset: %s\n"), fname);
815
816 if (mxid_given)
817 {
818 printf(_("NextMultiXactId: %u\n"),
820 printf(_("OldestMultiXid: %u\n"),
822 printf(_("OldestMulti's DB: %u\n"),
824 }
825
826 if (mxoff_given)
827 {
828 printf(_("NextMultiOffset: %u\n"),
830 }
831
832 if (set_oid != 0)
833 {
834 printf(_("NextOID: %u\n"),
836 }
837
838 if (set_xid != 0)
839 {
840 printf(_("NextXID: %u\n"),
842 }
843
844 if (set_oldest_xid != 0)
845 {
846 printf(_("OldestXID: %u\n"),
848 printf(_("OldestXID's DB: %u\n"),
850 }
851
852 if (set_xid_epoch != -1)
853 {
854 printf(_("NextXID epoch: %u\n"),
856 }
857
859 {
860 printf(_("oldestCommitTsXid: %u\n"),
862 }
864 {
865 printf(_("newestCommitTsXid: %u\n"),
867 }
868
869 if (set_wal_segsize != 0)
870 {
871 printf(_("Bytes per WAL segment: %u\n"),
873 }
874}
875
876
877/*
878 * Write out the new pg_control file.
879 */
880static void
882{
883 /*
884 * Adjust fields as needed to force an empty XLOG starting at
885 * newXlogSegNo.
886 */
890
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 */
912
913 /* The control file gets flushed here. */
914 update_controlfile(".", &ControlFile, true);
915}
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 */
926static 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 */
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 xldir = opendir(XLOGDIR);
947 if (xldir == NULL)
948 pg_fatal("could not open directory \"%s\": %m", XLOGDIR);
949
950 while (errno = 0, (xlde = readdir(xldir)) != NULL)
951 {
952 if (IsXLogFileName(xlde->d_name) ||
954 {
955 TimeLineID tli;
956 XLogSegNo segno;
957
958 /* Use the segment size from the control file */
959 XLogFromFileName(xlde->d_name, &tli, &segno,
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 if (segno > newXlogSegNo)
969 newXlogSegNo = segno;
970 }
971 }
972
973 if (errno)
974 pg_fatal("could not read directory \"%s\": %m", XLOGDIR);
975
976 if (closedir(xldir))
977 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 xlogbytepos = newXlogSegNo * ControlFile.xlog_seg_size;
984 newXlogSegNo = (xlogbytepos + ControlFile.xlog_seg_size - 1) / WalSegSz;
985 newXlogSegNo++;
986}
987
988
989/*
990 * Remove existing XLOG files
991 */
992static void
994{
995 DIR *xldir;
996 struct dirent *xlde;
997 char path[MAXPGPATH + sizeof(XLOGDIR)];
998
999 xldir = opendir(XLOGDIR);
1000 if (xldir == NULL)
1001 pg_fatal("could not open directory \"%s\": %m", XLOGDIR);
1002
1003 while (errno = 0, (xlde = readdir(xldir)) != NULL)
1004 {
1005 if (IsXLogFileName(xlde->d_name) ||
1007 {
1008 snprintf(path, sizeof(path), "%s/%s", XLOGDIR, xlde->d_name);
1009 if (unlink(path) < 0)
1010 pg_fatal("could not delete file \"%s\": %m", path);
1011 }
1012 }
1013
1014 if (errno)
1015 pg_fatal("could not read directory \"%s\": %m", XLOGDIR);
1016
1017 if (closedir(xldir))
1018 pg_fatal("could not close directory \"%s\": %m", XLOGDIR);
1019}
1020
1021
1022/*
1023 * Remove existing archive status files
1024 */
1025static void
1027{
1028#define ARCHSTATDIR XLOGDIR "/archive_status"
1029
1030 DIR *xldir;
1031 struct dirent *xlde;
1032 char path[MAXPGPATH + sizeof(ARCHSTATDIR)];
1033
1034 xldir = opendir(ARCHSTATDIR);
1035 if (xldir == NULL)
1036 pg_fatal("could not open directory \"%s\": %m", ARCHSTATDIR);
1037
1038 while (errno = 0, (xlde = readdir(xldir)) != NULL)
1039 {
1040 if (strspn(xlde->d_name, "0123456789ABCDEF") == XLOG_FNAME_LEN &&
1041 (strcmp(xlde->d_name + XLOG_FNAME_LEN, ".ready") == 0 ||
1042 strcmp(xlde->d_name + XLOG_FNAME_LEN, ".done") == 0 ||
1043 strcmp(xlde->d_name + XLOG_FNAME_LEN, ".partial.ready") == 0 ||
1044 strcmp(xlde->d_name + XLOG_FNAME_LEN, ".partial.done") == 0))
1045 {
1046 snprintf(path, sizeof(path), "%s/%s", ARCHSTATDIR, xlde->d_name);
1047 if (unlink(path) < 0)
1048 pg_fatal("could not delete file \"%s\": %m", path);
1049 }
1050 }
1051
1052 if (errno)
1053 pg_fatal("could not read directory \"%s\": %m", ARCHSTATDIR);
1054
1055 if (closedir(xldir))
1056 pg_fatal("could not close directory \"%s\": %m", ARCHSTATDIR);
1057}
1058
1059/*
1060 * Remove existing WAL summary files
1061 */
1062static 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 xldir = opendir(WALSUMMARYDIR);
1073 if (xldir == NULL)
1074 pg_fatal("could not open directory \"%s\": %m", WALSUMMARYDIR);
1075
1076 while (errno = 0, (xlde = readdir(xldir)) != NULL)
1077 {
1078 if (strspn(xlde->d_name, "0123456789ABCDEF") == WALSUMMARY_NHEXCHARS &&
1079 strcmp(xlde->d_name + WALSUMMARY_NHEXCHARS, ".summary") == 0)
1080 {
1081 snprintf(path, sizeof(path), "%s/%s", WALSUMMARYDIR, xlde->d_name);
1082 if (unlink(path) < 0)
1083 pg_fatal("could not delete file \"%s\": %m", path);
1084 }
1085 }
1086
1087 if (errno)
1088 pg_fatal("could not read directory \"%s\": %m", WALSUMMARYDIR);
1089
1090 if (closedir(xldir))
1091 pg_fatal("could not close directory \"%s\": %m", ARCHSTATDIR);
1092}
1093
1094/*
1095 * Write an empty XLOG file, containing only the checkpoint record
1096 * already set up in ControlFile.
1097 */
1098static 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 memset(buffer.data, 0, XLOG_BLCKSZ);
1112
1113 /* Set up the XLOG page header */
1114 page = (XLogPageHeader) buffer.data;
1115 page->xlp_magic = XLOG_PAGE_MAGIC;
1116 page->xlp_info = XLP_LONG_HEADER;
1119 longpage = (XLogLongPageHeader) page;
1121 longpage->xlp_seg_size = WalSegSz;
1122 longpage->xlp_xlog_blcksz = XLOG_BLCKSZ;
1123
1124 /* Insert the initial checkpoint record */
1125 recptr = (char *) page + SizeOfXLogLongPHD;
1126 record = (XLogRecord *) recptr;
1127 record->xl_prev = 0;
1128 record->xl_xid = InvalidTransactionId;
1131 record->xl_rmid = RM_XLOG_ID;
1132
1133 recptr += SizeOfXLogRecord;
1134 *(recptr++) = (char) XLR_BLOCK_ID_DATA_SHORT;
1135 *(recptr++) = sizeof(CheckPoint);
1136 memcpy(recptr, &ControlFile.checkPointCopy,
1137 sizeof(CheckPoint));
1138
1140 COMP_CRC32C(crc, ((char *) record) + SizeOfXLogRecord, record->xl_tot_len - SizeOfXLogRecord);
1141 COMP_CRC32C(crc, (char *) record, offsetof(XLogRecord, xl_crc));
1142 FIN_CRC32C(crc);
1143 record->xl_crc = crc;
1144
1145 /* Write the first page */
1148
1149 unlink(path);
1150
1151 fd = open(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
1153 if (fd < 0)
1154 pg_fatal("could not open file \"%s\": %m", path);
1155
1156 errno = 0;
1157 if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
1158 {
1159 /* if write didn't set errno, assume problem is no disk space */
1160 if (errno == 0)
1161 errno = ENOSPC;
1162 pg_fatal("could not write file \"%s\": %m", path);
1163 }
1164
1165 /* Fill the rest of the file with zeroes */
1166 memset(buffer.data, 0, XLOG_BLCKSZ);
1167 for (nbytes = XLOG_BLCKSZ; nbytes < WalSegSz; nbytes += XLOG_BLCKSZ)
1168 {
1169 errno = 0;
1170 if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
1171 {
1172 if (errno == 0)
1173 errno = ENOSPC;
1174 pg_fatal("could not write file \"%s\": %m", path);
1175 }
1176 }
1177
1178 if (fsync(fd) != 0)
1179 pg_fatal("fsync error: %m");
1180
1181 close(fd);
1182}
1183
1184
1185static void
1187{
1188 printf(_("%s resets the PostgreSQL write-ahead log.\n\n"), progname);
1189 printf(_("Usage:\n"));
1190 printf(_(" %s [OPTION]... DATADIR\n"), progname);
1191
1192 printf(_("\nOptions:\n"));
1193 printf(_(" [-D, --pgdata=]DATADIR data directory\n"));
1194 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 printf(_(" -n, --dry-run no update, just show what would be done\n"));
1197 printf(_(" -V, --version output version information, then exit\n"));
1198 printf(_(" -?, --help show this help, then exit\n"));
1199
1200 printf(_("\nOptions to override control file values:\n"));
1201 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 printf(_(" -e, --epoch=XIDEPOCH set next transaction ID epoch\n"));
1205 printf(_(" -l, --next-wal-file=WALFILE set minimum starting location for new WAL\n"));
1206 printf(_(" -m, --multixact-ids=MXID,MXID set next and oldest multitransaction ID\n"));
1207 printf(_(" -o, --next-oid=OID set next OID\n"));
1208 printf(_(" -O, --multixact-offset=OFFSET set next multitransaction offset\n"));
1209 printf(_(" -u, --oldest-transaction-id=XID set oldest transaction ID\n"));
1210 printf(_(" -x, --next-transaction-id=XID set next transaction ID\n"));
1211 printf(_(" --char-signedness=OPTION set char signedness to \"signed\" or \"unsigned\"\n"));
1212 printf(_(" --wal-segsize=SIZE size of WAL segments, in megabytes\n"));
1213
1214 printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1215 printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
1216}
#define ngettext(s, p, n)
Definition: c.h:1181
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1214
int64_t int64
Definition: c.h:540
#define PG_BINARY
Definition: c.h:1273
uint32 MultiXactOffset
Definition: c.h:674
TransactionId MultiXactId
Definition: c.h:672
uint64_t uint64
Definition: c.h:544
uint32_t uint32
Definition: c.h:543
uint32 TransactionId
Definition: c.h:662
#define CATALOG_VERSION_NO
Definition: catversion.h:60
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:430
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
uint32 get_pg_version(const char *datadir, char **version_str)
Definition: version.c:44
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:71
#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:26
#define MaxMultiXactOffset
Definition: multixact.h:31
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 SLRU_PAGES_PER_SEGMENT
#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:258
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:927
static void RewriteControlFile(void)
Definition: pg_resetwal.c:881
int main(int argc, char *argv[])
Definition: pg_resetwal.c:98
static void KillExistingWALSummaries(void)
Definition: pg_resetwal.c:1063
#define WALSUMMARY_NHEXCHARS
static int WalSegSz
Definition: pg_resetwal.c:79
static ControlFileData ControlFile
Definition: pg_resetwal.c:63
static void KillExistingXLOG(void)
Definition: pg_resetwal.c:993
static void CheckDataVersion(void)
Definition: pg_resetwal.c:546
static int set_char_signedness
Definition: pg_resetwal.c:81
#define ARCHSTATDIR
static XLogSegNo minXlogSegNo
Definition: pg_resetwal.c:78
static bool mxoff_given
Definition: pg_resetwal.c:75
static int set_wal_segsize
Definition: pg_resetwal.c:80
static MultiXactOffset set_mxoff
Definition: pg_resetwal.c:76
static MultiXactId set_mxid
Definition: pg_resetwal.c:74
#define WALSUMMARYDIR
static TimeLineID minXlogTli
Definition: pg_resetwal.c:77
static TransactionId set_oldest_xid
Definition: pg_resetwal.c:68
static TransactionId set_oldest_commit_ts_xid
Definition: pg_resetwal.c:70
static TransactionId set_xid
Definition: pg_resetwal.c:69
static Oid set_oid
Definition: pg_resetwal.c:72
static void PrintNewControlValues(void)
Definition: pg_resetwal.c:805
static XLogSegNo newXlogSegNo
Definition: pg_resetwal.c:64
static bool mxid_given
Definition: pg_resetwal.c:73
static bool read_controlfile(void)
Definition: pg_resetwal.c:570
static void KillExistingArchiveStatus(void)
Definition: pg_resetwal.c:1026
static void WriteEmptyXLOG(void)
Definition: pg_resetwal.c:1099
static const char * progname
Definition: pg_resetwal.c:66
static void usage(void)
Definition: pg_resetwal.c:1186
static void PrintControlValues(bool guessed)
Definition: pg_resetwal.c:728
static TransactionId set_newest_commit_ts_xid
Definition: pg_resetwal.c:71
static bool guessed
Definition: pg_resetwal.c:65
static uint32 set_xid_epoch
Definition: pg_resetwal.c:67
static void GuessControlValues(void)
Definition: pg_resetwal.c:644
#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:37
unsigned int Oid
Definition: postgres_ext.h:32
char * c
static int fd(const char *x, int i)
Definition: preproc-init.c:105
void get_restricted_token(void)
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:213
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:215
CheckPoint checkPointCopy
Definition: pg_control.h:135
uint32 slru_pages_per_segment
Definition: pg_control.h:210
XLogRecPtr backupEndPoint
Definition: pg_control.h:171
XLogRecPtr minRecoveryPoint
Definition: pg_control.h:168
uint32 data_checksum_version
Definition: pg_control.h:224
XLogRecPtr unloggedLSN
Definition: pg_control.h:137
uint32 indexMaxKeys
Definition: pg_control.h:216
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:230
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:212
TimeLineID minRecoveryPointTLI
Definition: pg_control.h:169
uint32 loblksize
Definition: pg_control.h:219
uint32 toast_max_chunk_size
Definition: pg_control.h:218
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:1148
#define GET_PG_MAJORVERSION_NUM(v)
Definition: version.h:19
#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:37
uint32 TimeLineID
Definition: xlogdefs.h:63
uint64 XLogSegNo
Definition: xlogdefs.h:52
#define SizeOfXLogRecordDataHeaderShort
Definition: xlogrecord.h:217
#define XLR_BLOCK_ID_DATA_SHORT
Definition: xlogrecord.h:241
#define SizeOfXLogRecord
Definition: xlogrecord.h:55