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