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-2023, 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 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  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
165  exit(1);
166  }
167  if (set_xid_epoch == -1)
168  pg_fatal("transaction ID epoch (-e) must not be -1");
169  break;
170 
171  case 'u':
172  errno = 0;
173  set_oldest_xid = strtoul(optarg, &endptr, 0);
174  if (endptr == optarg || *endptr != '\0' || errno != 0)
175  {
176  pg_log_error("invalid argument for option %s", "-u");
177  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
178  exit(1);
179  }
181  pg_fatal("oldest transaction ID (-u) must be greater than or equal to %u", FirstNormalTransactionId);
182  break;
183 
184  case 'x':
185  errno = 0;
186  set_xid = strtoul(optarg, &endptr, 0);
187  if (endptr == optarg || *endptr != '\0' || errno != 0)
188  {
189  pg_log_error("invalid argument for option %s", "-x");
190  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
191  exit(1);
192  }
194  pg_fatal("transaction ID (-x) must be greater than or equal to %u", FirstNormalTransactionId);
195  break;
196 
197  case 'c':
198  errno = 0;
199  set_oldest_commit_ts_xid = strtoul(optarg, &endptr, 0);
200  if (endptr == optarg || *endptr != ',' || errno != 0)
201  {
202  pg_log_error("invalid argument for option %s", "-c");
203  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
204  exit(1);
205  }
206  set_newest_commit_ts_xid = strtoul(endptr + 1, &endptr2, 0);
207  if (endptr2 == endptr + 1 || *endptr2 != '\0' || 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 
216  pg_fatal("transaction ID (-c) must be either %u or greater than or equal to %u", InvalidTransactionId, FirstNormalTransactionId);
217 
220  pg_fatal("transaction ID (-c) must be either %u or greater than or equal to %u", InvalidTransactionId, FirstNormalTransactionId);
221  break;
222 
223  case 'o':
224  errno = 0;
225  set_oid = strtoul(optarg, &endptr, 0);
226  if (endptr == optarg || *endptr != '\0' || errno != 0)
227  {
228  pg_log_error("invalid argument for option %s", "-o");
229  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
230  exit(1);
231  }
232  if (set_oid == 0)
233  pg_fatal("OID (-o) must not be 0");
234  break;
235 
236  case 'm':
237  errno = 0;
238  set_mxid = strtoul(optarg, &endptr, 0);
239  if (endptr == optarg || *endptr != ',' || errno != 0)
240  {
241  pg_log_error("invalid argument for option %s", "-m");
242  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
243  exit(1);
244  }
245 
246  set_oldestmxid = strtoul(endptr + 1, &endptr2, 0);
247  if (endptr2 == endptr + 1 || *endptr2 != '\0' || errno != 0)
248  {
249  pg_log_error("invalid argument for option %s", "-m");
250  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
251  exit(1);
252  }
253  if (set_mxid == 0)
254  pg_fatal("multitransaction ID (-m) must not be 0");
255 
256  /*
257  * XXX It'd be nice to have more sanity checks here, e.g. so
258  * that oldest is not wrapped around w.r.t. nextMulti.
259  */
260  if (set_oldestmxid == 0)
261  pg_fatal("oldest multitransaction ID (-m) must not be 0");
262  break;
263 
264  case 'O':
265  errno = 0;
266  set_mxoff = strtoul(optarg, &endptr, 0);
267  if (endptr == optarg || *endptr != '\0' || errno != 0)
268  {
269  pg_log_error("invalid argument for option %s", "-O");
270  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
271  exit(1);
272  }
273  if (set_mxoff == -1)
274  pg_fatal("multitransaction offset (-O) must not be -1");
275  break;
276 
277  case 'l':
278  if (strspn(optarg, "01234567890ABCDEFabcdef") != XLOG_FNAME_LEN)
279  {
280  pg_log_error("invalid argument for option %s", "-l");
281  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
282  exit(1);
283  }
284 
285  /*
286  * XLogFromFileName requires wal segment size which is not yet
287  * set. Hence wal details are set later on.
288  */
289  log_fname = pg_strdup(optarg);
290  break;
291 
292  case 1:
293  {
294  int wal_segsize_mb;
295 
296  if (!option_parse_int(optarg, "--wal-segsize", 1, 1024, &wal_segsize_mb))
297  exit(1);
298  set_wal_segsize = wal_segsize_mb * 1024 * 1024;
300  pg_fatal("argument of %s must be a power of two between 1 and 1024", "--wal-segsize");
301  break;
302  }
303 
304  default:
305  /* getopt_long already emitted a complaint */
306  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
307  exit(1);
308  }
309  }
310 
311  if (DataDir == NULL && optind < argc)
312  DataDir = argv[optind++];
313 
314  /* Complain if any arguments remain */
315  if (optind < argc)
316  {
317  pg_log_error("too many command-line arguments (first is \"%s\")",
318  argv[optind]);
319  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
320  exit(1);
321  }
322 
323  if (DataDir == NULL)
324  {
325  pg_log_error("no data directory specified");
326  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
327  exit(1);
328  }
329 
330  /*
331  * Don't allow pg_resetwal to be run as root, to avoid overwriting the
332  * ownership of files in the data directory. We need only check for root
333  * -- any other user won't have sufficient permissions to modify files in
334  * the data directory.
335  */
336 #ifndef WIN32
337  if (geteuid() == 0)
338  {
339  pg_log_error("cannot be executed by \"root\"");
340  pg_log_error_hint("You must run %s as the PostgreSQL superuser.",
341  progname);
342  exit(1);
343  }
344 #endif
345 
347 
348  /* Set mask based on PGDATA permissions */
350  pg_fatal("could not read permissions of directory \"%s\": %m",
351  DataDir);
352 
353  umask(pg_mode_mask);
354 
355  if (chdir(DataDir) < 0)
356  pg_fatal("could not change directory to \"%s\": %m",
357  DataDir);
358 
359  /* Check that data directory matches our server version */
361 
362  /*
363  * Check for a postmaster lock file --- if there is one, refuse to
364  * proceed, on grounds we might be interfering with a live installation.
365  */
366  if ((fd = open("postmaster.pid", O_RDONLY, 0)) < 0)
367  {
368  if (errno != ENOENT)
369  pg_fatal("could not open file \"%s\" for reading: %m",
370  "postmaster.pid");
371  }
372  else
373  {
374  pg_log_error("lock file \"%s\" exists", "postmaster.pid");
375  pg_log_error_hint("Is a server running? If not, delete the lock file and try again.");
376  exit(1);
377  }
378 
379  /*
380  * Attempt to read the existing pg_control file
381  */
382  if (!read_controlfile())
384 
385  /*
386  * If no new WAL segment size was specified, use the control file value.
387  */
388  if (set_wal_segsize != 0)
390  else
392 
393  if (log_fname != NULL)
395 
396  /*
397  * Also look at existing segment files to set up newXlogSegNo
398  */
399  FindEndOfXLOG();
400 
401  /*
402  * If we're not going to proceed with the reset, print the current control
403  * file parameters.
404  */
405  if ((guessed && !force) || noupdate)
407 
408  /*
409  * Adjust fields if required by switches. (Do this now so that printout,
410  * if any, includes these values.)
411  */
412  if (set_xid_epoch != -1)
416 
417  if (set_oldest_xid != 0)
418  {
421  }
422 
423  if (set_xid != 0)
426  set_xid);
427 
428  if (set_oldest_commit_ts_xid != 0)
430  if (set_newest_commit_ts_xid != 0)
432 
433  if (set_oid != 0)
435 
436  if (set_mxid != 0)
437  {
439 
440  ControlFile.checkPointCopy.oldestMulti = set_oldestmxid;
444  }
445 
446  if (set_mxoff != -1)
448 
450  {
453  }
454 
455  if (set_wal_segsize != 0)
457 
460 
461  if (noupdate)
462  {
464  exit(0);
465  }
466 
467  /*
468  * If we had to guess anything, and -f was not given, just print the
469  * guessed values and exit.
470  */
471  if (guessed && !force)
472  {
474  pg_log_error("not proceeding because control file values were guessed");
475  pg_log_error_hint("If these values seem acceptable, use -f to force reset.");
476  exit(1);
477  }
478 
479  /*
480  * Don't reset from a dirty pg_control without -f, either.
481  */
482  if (ControlFile.state != DB_SHUTDOWNED && !force)
483  {
484  pg_log_error("database server was not shut down cleanly");
485  pg_log_error_detail("Resetting the write-ahead log might cause data to be lost.");
486  pg_log_error_hint("If you want to proceed anyway, use -f to force reset.");
487  exit(1);
488  }
489 
490  /*
491  * Else, do the dirty deed.
492  */
496  WriteEmptyXLOG();
497 
498  printf(_("Write-ahead log reset\n"));
499  return 0;
500 }
501 
502 
503 /*
504  * Look at the version string stored in PG_VERSION and decide if this utility
505  * can be run safely or not.
506  *
507  * We don't want to inject pg_control and WAL files that are for a different
508  * major version; that can't do anything good. Note that we don't treat
509  * mismatching version info in pg_control as a reason to bail out, because
510  * recovering from a corrupted pg_control is one of the main reasons for this
511  * program to exist at all. However, PG_VERSION is unlikely to get corrupted,
512  * and if it were it would be easy to fix by hand. So let's make this check
513  * to prevent simple user errors.
514  */
515 static void
517 {
518  const char *ver_file = "PG_VERSION";
519  FILE *ver_fd;
520  char rawline[64];
521 
522  if ((ver_fd = fopen(ver_file, "r")) == NULL)
523  pg_fatal("could not open file \"%s\" for reading: %m",
524  ver_file);
525 
526  /* version number has to be the first line read */
527  if (!fgets(rawline, sizeof(rawline), ver_fd))
528  {
529  if (!ferror(ver_fd))
530  pg_fatal("unexpected empty file \"%s\"", ver_file);
531  else
532  pg_fatal("could not read file \"%s\": %m", ver_file);
533  }
534 
535  /* strip trailing newline and carriage return */
536  (void) pg_strip_crlf(rawline);
537 
538  if (strcmp(rawline, PG_MAJORVERSION) != 0)
539  {
540  pg_log_error("data directory is of wrong version");
541  pg_log_error_detail("File \"%s\" contains \"%s\", which is not compatible with this program's version \"%s\".",
542  ver_file, rawline, PG_MAJORVERSION);
543  exit(1);
544  }
545 
546  fclose(ver_fd);
547 }
548 
549 
550 /*
551  * Try to read the existing pg_control file.
552  *
553  * This routine is also responsible for updating old pg_control versions
554  * to the current format. (Currently we don't do anything of the sort.)
555  */
556 static bool
558 {
559  int fd;
560  int len;
561  char *buffer;
562  pg_crc32c crc;
563 
564  if ((fd = open(XLOG_CONTROL_FILE, O_RDONLY | PG_BINARY, 0)) < 0)
565  {
566  /*
567  * If pg_control is not there at all, or we can't read it, the odds
568  * are we've been handed a bad DataDir path, so give up. User can do
569  * "touch pg_control" to force us to proceed.
570  */
571  pg_log_error("could not open file \"%s\" for reading: %m",
573  if (errno == ENOENT)
574  pg_log_error_hint("If you are sure the data directory path is correct, execute\n"
575  " touch %s\n"
576  "and try again.",
578  exit(1);
579  }
580 
581  /* Use malloc to ensure we have a maxaligned buffer */
582  buffer = (char *) pg_malloc(PG_CONTROL_FILE_SIZE);
583 
584  len = read(fd, buffer, PG_CONTROL_FILE_SIZE);
585  if (len < 0)
586  pg_fatal("could not read file \"%s\": %m", XLOG_CONTROL_FILE);
587  close(fd);
588 
589  if (len >= sizeof(ControlFileData) &&
590  ((ControlFileData *) buffer)->pg_control_version == PG_CONTROL_VERSION)
591  {
592  /* Check the CRC. */
593  INIT_CRC32C(crc);
595  buffer,
596  offsetof(ControlFileData, crc));
597  FIN_CRC32C(crc);
598 
599  if (!EQ_CRC32C(crc, ((ControlFileData *) buffer)->crc))
600  {
601  /* We will use the data but treat it as guessed. */
602  pg_log_warning("pg_control exists but has invalid CRC; proceed with caution");
603  guessed = true;
604  }
605 
606  memcpy(&ControlFile, buffer, sizeof(ControlFile));
607 
608  /* return false if WAL segment size is not valid */
610  {
611  pg_log_warning(ngettext("pg_control specifies invalid WAL segment size (%d byte); proceed with caution",
612  "pg_control specifies invalid WAL segment size (%d bytes); proceed with caution",
615  return false;
616  }
617 
618  return true;
619  }
620 
621  /* Looks like it's a mess. */
622  pg_log_warning("pg_control exists but is broken or wrong version; ignoring it");
623  return false;
624 }
625 
626 
627 /*
628  * Guess at pg_control values when we can't read the old ones.
629  */
630 static void
632 {
633  uint64 sysidentifier;
634  struct timeval tv;
635 
636  /*
637  * Set up a completely default set of pg_control values.
638  */
639  guessed = true;
640  memset(&ControlFile, 0, sizeof(ControlFile));
641 
644 
645  /*
646  * Create a new unique installation identifier, since we can no longer use
647  * any old XLOG records. See notes in xlog.c about the algorithm.
648  */
649  gettimeofday(&tv, NULL);
650  sysidentifier = ((uint64) tv.tv_sec) << 32;
651  sysidentifier |= ((uint64) tv.tv_usec) << 12;
652  sysidentifier |= getpid() & 0xFFF;
653 
654  ControlFile.system_identifier = sysidentifier;
655 
669  ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
671 
673  ControlFile.time = (pg_time_t) time(NULL);
676 
677  /* minRecoveryPoint, backupStartPoint and backupEndPoint can be left zero */
678 
680  ControlFile.wal_log_hints = false;
687 
688  ControlFile.maxAlign = MAXIMUM_ALIGNOF;
690  ControlFile.blcksz = BLCKSZ;
691  ControlFile.relseg_size = RELSEG_SIZE;
692  ControlFile.xlog_blcksz = XLOG_BLCKSZ;
699 
700  /*
701  * XXX eventually, should try to grovel through old XLOG to develop more
702  * accurate values for TimeLineID, nextXID, etc.
703  */
704 }
705 
706 
707 /*
708  * Print the guessed pg_control values when we had to guess.
709  *
710  * NB: this display should be just those fields that will not be
711  * reset by RewriteControlFile().
712  */
713 static void
715 {
716  if (guessed)
717  printf(_("Guessed pg_control values:\n\n"));
718  else
719  printf(_("Current pg_control values:\n\n"));
720 
721  printf(_("pg_control version number: %u\n"),
723  printf(_("Catalog version number: %u\n"),
725  printf(_("Database system identifier: %llu\n"),
726  (unsigned long long) ControlFile.system_identifier);
727  printf(_("Latest checkpoint's TimeLineID: %u\n"),
729  printf(_("Latest checkpoint's full_page_writes: %s\n"),
730  ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off"));
731  printf(_("Latest checkpoint's NextXID: %u:%u\n"),
734  printf(_("Latest checkpoint's NextOID: %u\n"),
736  printf(_("Latest checkpoint's NextMultiXactId: %u\n"),
738  printf(_("Latest checkpoint's NextMultiOffset: %u\n"),
740  printf(_("Latest checkpoint's oldestXID: %u\n"),
742  printf(_("Latest checkpoint's oldestXID's DB: %u\n"),
744  printf(_("Latest checkpoint's oldestActiveXID: %u\n"),
746  printf(_("Latest checkpoint's oldestMultiXid: %u\n"),
748  printf(_("Latest checkpoint's oldestMulti's DB: %u\n"),
750  printf(_("Latest checkpoint's oldestCommitTsXid:%u\n"),
752  printf(_("Latest checkpoint's newestCommitTsXid:%u\n"),
754  printf(_("Maximum data alignment: %u\n"),
756  /* we don't print floatFormat since can't say much useful about it */
757  printf(_("Database block size: %u\n"),
759  printf(_("Blocks per segment of large relation: %u\n"),
761  printf(_("WAL block size: %u\n"),
763  printf(_("Bytes per WAL segment: %u\n"),
765  printf(_("Maximum length of identifiers: %u\n"),
767  printf(_("Maximum columns in an index: %u\n"),
769  printf(_("Maximum size of a TOAST chunk: %u\n"),
771  printf(_("Size of a large-object chunk: %u\n"),
773  /* This is no longer configurable, but users may still expect to see it: */
774  printf(_("Date/time type storage: %s\n"),
775  _("64-bit integers"));
776  printf(_("Float8 argument passing: %s\n"),
777  (ControlFile.float8ByVal ? _("by value") : _("by reference")));
778  printf(_("Data page checksum version: %u\n"),
780 }
781 
782 
783 /*
784  * Print the values to be changed.
785  */
786 static void
788 {
789  char fname[MAXFNAMELEN];
790 
791  /* This will be always printed in order to keep format same. */
792  printf(_("\n\nValues to be changed:\n\n"));
793 
796  printf(_("First log segment after reset: %s\n"), fname);
797 
798  if (set_mxid != 0)
799  {
800  printf(_("NextMultiXactId: %u\n"),
802  printf(_("OldestMultiXid: %u\n"),
804  printf(_("OldestMulti's DB: %u\n"),
806  }
807 
808  if (set_mxoff != -1)
809  {
810  printf(_("NextMultiOffset: %u\n"),
812  }
813 
814  if (set_oid != 0)
815  {
816  printf(_("NextOID: %u\n"),
818  }
819 
820  if (set_xid != 0)
821  {
822  printf(_("NextXID: %u\n"),
824  printf(_("OldestXID: %u\n"),
826  printf(_("OldestXID's DB: %u\n"),
828  }
829 
830  if (set_xid_epoch != -1)
831  {
832  printf(_("NextXID epoch: %u\n"),
834  }
835 
836  if (set_oldest_commit_ts_xid != 0)
837  {
838  printf(_("oldestCommitTsXid: %u\n"),
840  }
841  if (set_newest_commit_ts_xid != 0)
842  {
843  printf(_("newestCommitTsXid: %u\n"),
845  }
846 
847  if (set_wal_segsize != 0)
848  {
849  printf(_("Bytes per WAL segment: %u\n"),
851  }
852 }
853 
854 
855 /*
856  * Write out the new pg_control file.
857  */
858 static void
860 {
861  /*
862  * Adjust fields as needed to force an empty XLOG starting at
863  * newXlogSegNo.
864  */
867  ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
868 
876 
877  /*
878  * Force the defaults for max_* settings. The values don't really matter
879  * as long as wal_level='minimal'; the postmaster will reset these fields
880  * anyway at startup.
881  */
883  ControlFile.wal_log_hints = false;
890 
891  /* The control file gets flushed here. */
892  update_controlfile(".", &ControlFile, true);
893 }
894 
895 
896 /*
897  * Scan existing XLOG files and determine the highest existing WAL address
898  *
899  * On entry, ControlFile.checkPointCopy.redo and ControlFile.xlog_seg_size
900  * are assumed valid (note that we allow the old xlog seg size to differ
901  * from what we're using). On exit, newXlogSegNo is set to suitable
902  * value for the beginning of replacement WAL (in our seg size).
903  */
904 static void
906 {
907  DIR *xldir;
908  struct dirent *xlde;
909  uint64 xlogbytepos;
910 
911  /*
912  * Initialize the max() computation using the last checkpoint address from
913  * old pg_control. Note that for the moment we are working with segment
914  * numbering according to the old xlog seg size.
915  */
918 
919  /*
920  * Scan the pg_wal directory to find existing WAL segment files. We assume
921  * any present have been used; in most scenarios this should be
922  * conservative, because of xlog.c's attempts to pre-create files.
923  */
924  xldir = opendir(XLOGDIR);
925  if (xldir == NULL)
926  pg_fatal("could not open directory \"%s\": %m", XLOGDIR);
927 
928  while (errno = 0, (xlde = readdir(xldir)) != NULL)
929  {
930  if (IsXLogFileName(xlde->d_name) ||
932  {
933  TimeLineID tli;
934  XLogSegNo segno;
935 
936  /* Use the segment size from the control file */
937  XLogFromFileName(xlde->d_name, &tli, &segno,
939 
940  /*
941  * Note: we take the max of all files found, regardless of their
942  * timelines. Another possibility would be to ignore files of
943  * timelines other than the target TLI, but this seems safer.
944  * Better too large a result than too small...
945  */
946  if (segno > newXlogSegNo)
947  newXlogSegNo = segno;
948  }
949  }
950 
951  if (errno)
952  pg_fatal("could not read directory \"%s\": %m", XLOGDIR);
953 
954  if (closedir(xldir))
955  pg_fatal("could not close directory \"%s\": %m", XLOGDIR);
956 
957  /*
958  * Finally, convert to new xlog seg size, and advance by one to ensure we
959  * are in virgin territory.
960  */
961  xlogbytepos = newXlogSegNo * ControlFile.xlog_seg_size;
962  newXlogSegNo = (xlogbytepos + ControlFile.xlog_seg_size - 1) / WalSegSz;
963  newXlogSegNo++;
964 }
965 
966 
967 /*
968  * Remove existing XLOG files
969  */
970 static void
972 {
973  DIR *xldir;
974  struct dirent *xlde;
975  char path[MAXPGPATH + sizeof(XLOGDIR)];
976 
977  xldir = opendir(XLOGDIR);
978  if (xldir == NULL)
979  pg_fatal("could not open directory \"%s\": %m", XLOGDIR);
980 
981  while (errno = 0, (xlde = readdir(xldir)) != NULL)
982  {
983  if (IsXLogFileName(xlde->d_name) ||
985  {
986  snprintf(path, sizeof(path), "%s/%s", XLOGDIR, xlde->d_name);
987  if (unlink(path) < 0)
988  pg_fatal("could not delete file \"%s\": %m", path);
989  }
990  }
991 
992  if (errno)
993  pg_fatal("could not read directory \"%s\": %m", XLOGDIR);
994 
995  if (closedir(xldir))
996  pg_fatal("could not close directory \"%s\": %m", XLOGDIR);
997 }
998 
999 
1000 /*
1001  * Remove existing archive status files
1002  */
1003 static void
1005 {
1006 #define ARCHSTATDIR XLOGDIR "/archive_status"
1007 
1008  DIR *xldir;
1009  struct dirent *xlde;
1010  char path[MAXPGPATH + sizeof(ARCHSTATDIR)];
1011 
1012  xldir = opendir(ARCHSTATDIR);
1013  if (xldir == NULL)
1014  pg_fatal("could not open directory \"%s\": %m", ARCHSTATDIR);
1015 
1016  while (errno = 0, (xlde = readdir(xldir)) != NULL)
1017  {
1018  if (strspn(xlde->d_name, "0123456789ABCDEF") == XLOG_FNAME_LEN &&
1019  (strcmp(xlde->d_name + XLOG_FNAME_LEN, ".ready") == 0 ||
1020  strcmp(xlde->d_name + XLOG_FNAME_LEN, ".done") == 0 ||
1021  strcmp(xlde->d_name + XLOG_FNAME_LEN, ".partial.ready") == 0 ||
1022  strcmp(xlde->d_name + XLOG_FNAME_LEN, ".partial.done") == 0))
1023  {
1024  snprintf(path, sizeof(path), "%s/%s", ARCHSTATDIR, xlde->d_name);
1025  if (unlink(path) < 0)
1026  pg_fatal("could not delete file \"%s\": %m", path);
1027  }
1028  }
1029 
1030  if (errno)
1031  pg_fatal("could not read directory \"%s\": %m", ARCHSTATDIR);
1032 
1033  if (closedir(xldir))
1034  pg_fatal("could not close directory \"%s\": %m", ARCHSTATDIR);
1035 }
1036 
1037 
1038 /*
1039  * Write an empty XLOG file, containing only the checkpoint record
1040  * already set up in ControlFile.
1041  */
1042 static void
1044 {
1045  PGAlignedXLogBlock buffer;
1046  XLogPageHeader page;
1047  XLogLongPageHeader longpage;
1048  XLogRecord *record;
1049  pg_crc32c crc;
1050  char path[MAXPGPATH];
1051  int fd;
1052  int nbytes;
1053  char *recptr;
1054 
1055  memset(buffer.data, 0, XLOG_BLCKSZ);
1056 
1057  /* Set up the XLOG page header */
1058  page = (XLogPageHeader) buffer.data;
1059  page->xlp_magic = XLOG_PAGE_MAGIC;
1060  page->xlp_info = XLP_LONG_HEADER;
1063  longpage = (XLogLongPageHeader) page;
1065  longpage->xlp_seg_size = WalSegSz;
1066  longpage->xlp_xlog_blcksz = XLOG_BLCKSZ;
1067 
1068  /* Insert the initial checkpoint record */
1069  recptr = (char *) page + SizeOfXLogLongPHD;
1070  record = (XLogRecord *) recptr;
1071  record->xl_prev = 0;
1072  record->xl_xid = InvalidTransactionId;
1075  record->xl_rmid = RM_XLOG_ID;
1076 
1077  recptr += SizeOfXLogRecord;
1078  *(recptr++) = (char) XLR_BLOCK_ID_DATA_SHORT;
1079  *(recptr++) = sizeof(CheckPoint);
1080  memcpy(recptr, &ControlFile.checkPointCopy,
1081  sizeof(CheckPoint));
1082 
1083  INIT_CRC32C(crc);
1084  COMP_CRC32C(crc, ((char *) record) + SizeOfXLogRecord, record->xl_tot_len - SizeOfXLogRecord);
1085  COMP_CRC32C(crc, (char *) record, offsetof(XLogRecord, xl_crc));
1086  FIN_CRC32C(crc);
1087  record->xl_crc = crc;
1088 
1089  /* Write the first page */
1092 
1093  unlink(path);
1094 
1095  fd = open(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
1097  if (fd < 0)
1098  pg_fatal("could not open file \"%s\": %m", path);
1099 
1100  errno = 0;
1101  if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
1102  {
1103  /* if write didn't set errno, assume problem is no disk space */
1104  if (errno == 0)
1105  errno = ENOSPC;
1106  pg_fatal("could not write file \"%s\": %m", path);
1107  }
1108 
1109  /* Fill the rest of the file with zeroes */
1110  memset(buffer.data, 0, XLOG_BLCKSZ);
1111  for (nbytes = XLOG_BLCKSZ; nbytes < WalSegSz; nbytes += XLOG_BLCKSZ)
1112  {
1113  errno = 0;
1114  if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
1115  {
1116  if (errno == 0)
1117  errno = ENOSPC;
1118  pg_fatal("could not write file \"%s\": %m", path);
1119  }
1120  }
1121 
1122  if (fsync(fd) != 0)
1123  pg_fatal("fsync error: %m");
1124 
1125  close(fd);
1126 }
1127 
1128 
1129 static void
1130 usage(void)
1131 {
1132  printf(_("%s resets the PostgreSQL write-ahead log.\n\n"), progname);
1133  printf(_("Usage:\n"));
1134  printf(_(" %s [OPTION]... DATADIR\n"), progname);
1135 
1136  printf(_("\nOptions:\n"));
1137  printf(_(" [-D, --pgdata=]DATADIR data directory\n"));
1138  printf(_(" -f, --force force update to be done even after unclean shutdown or\n"
1139  " if pg_control values had to be guessed\n"));
1140  printf(_(" -n, --dry-run no update, just show what would be done\n"));
1141  printf(_(" -V, --version output version information, then exit\n"));
1142  printf(_(" -?, --help show this help, then exit\n"));
1143 
1144  printf(_("\nOptions to override control file values:\n"));
1145  printf(_(" -c, --commit-timestamp-ids=XID,XID\n"
1146  " set oldest and newest transactions bearing\n"
1147  " commit timestamp (zero means no change)\n"));
1148  printf(_(" -e, --epoch=XIDEPOCH set next transaction ID epoch\n"));
1149  printf(_(" -l, --next-wal-file=WALFILE set minimum starting location for new WAL\n"));
1150  printf(_(" -m, --multixact-ids=MXID,MXID set next and oldest multitransaction ID\n"));
1151  printf(_(" -o, --next-oid=OID set next OID\n"));
1152  printf(_(" -O, --multixact-offset=OFFSET set next multitransaction offset\n"));
1153  printf(_(" -u, --oldest-transaction-id=XID set oldest transaction ID\n"));
1154  printf(_(" -x, --next-transaction-id=XID set next transaction ID\n"));
1155  printf(_(" --wal-segsize=SIZE size of WAL segments, in megabytes\n"));
1156 
1157  printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1158  printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
1159 }
unsigned int uint32
Definition: c.h:495
#define ngettext(s, p, n)
Definition: c.h:1194
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1227
#define PG_BINARY
Definition: c.h:1283
uint32 MultiXactOffset
Definition: c.h:653
TransactionId MultiXactId
Definition: c.h:651
#define FLOAT8PASSBYVAL
Definition: c.h:624
uint32 TransactionId
Definition: c.h:641
#define CATALOG_VERSION_NO
Definition: catversion.h:60
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:436
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
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:66
#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:905
static void RewriteControlFile(void)
Definition: pg_resetwal.c:859
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:971
static void CheckDataVersion(void)
Definition: pg_resetwal.c:516
#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 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:787
static XLogSegNo newXlogSegNo
Definition: pg_resetwal.c:63
static bool read_controlfile(void)
Definition: pg_resetwal.c:557
static void KillExistingArchiveStatus(void)
Definition: pg_resetwal.c:1004
static void WriteEmptyXLOG(void)
Definition: pg_resetwal.c:1043
static const char * progname
Definition: pg_resetwal.c:65
static void usage(void)
Definition: pg_resetwal.c:1130
static void PrintControlValues(bool guessed)
Definition: pg_resetwal.c:714
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:631
#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:1161
#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