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