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-2023, 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;
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 
214  if (set_oldest_commit_ts_xid < 2 &&
216  pg_fatal("transaction ID (-c) must be either 0 or greater than or equal to 2");
217 
218  if (set_newest_commit_ts_xid < 2 &&
220  pg_fatal("transaction ID (-c) must be either 0 or greater than or equal to 2");
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  errno = 0;
294  set_wal_segsize = strtol(optarg, &endptr, 10) * 1024 * 1024;
295  if (endptr == optarg || *endptr != '\0' || errno != 0)
296  pg_fatal("argument of --wal-segsize must be a number");
298  pg_fatal("argument of --wal-segsize must be a power of 2 between 1 and 1024");
299  break;
300 
301  default:
302  /* getopt_long already emitted a complaint */
303  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
304  exit(1);
305  }
306  }
307 
308  if (DataDir == NULL && optind < argc)
309  DataDir = argv[optind++];
310 
311  /* Complain if any arguments remain */
312  if (optind < argc)
313  {
314  pg_log_error("too many command-line arguments (first is \"%s\")",
315  argv[optind]);
316  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
317  exit(1);
318  }
319 
320  if (DataDir == NULL)
321  {
322  pg_log_error("no data directory specified");
323  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
324  exit(1);
325  }
326 
327  /*
328  * Don't allow pg_resetwal to be run as root, to avoid overwriting the
329  * ownership of files in the data directory. We need only check for root
330  * -- any other user won't have sufficient permissions to modify files in
331  * the data directory.
332  */
333 #ifndef WIN32
334  if (geteuid() == 0)
335  {
336  pg_log_error("cannot be executed by \"root\"");
337  pg_log_error_hint("You must run %s as the PostgreSQL superuser.",
338  progname);
339  exit(1);
340  }
341 #endif
342 
344 
345  /* Set mask based on PGDATA permissions */
347  pg_fatal("could not read permissions of directory \"%s\": %m",
348  DataDir);
349 
350  umask(pg_mode_mask);
351 
352  if (chdir(DataDir) < 0)
353  pg_fatal("could not change directory to \"%s\": %m",
354  DataDir);
355 
356  /* Check that data directory matches our server version */
358 
359  /*
360  * Check for a postmaster lock file --- if there is one, refuse to
361  * proceed, on grounds we might be interfering with a live installation.
362  */
363  if ((fd = open("postmaster.pid", O_RDONLY, 0)) < 0)
364  {
365  if (errno != ENOENT)
366  pg_fatal("could not open file \"%s\" for reading: %m",
367  "postmaster.pid");
368  }
369  else
370  {
371  pg_log_error("lock file \"%s\" exists", "postmaster.pid");
372  pg_log_error_hint("Is a server running? If not, delete the lock file and try again.");
373  exit(1);
374  }
375 
376  /*
377  * Attempt to read the existing pg_control file
378  */
379  if (!read_controlfile())
381 
382  /*
383  * If no new WAL segment size was specified, use the control file value.
384  */
385  if (set_wal_segsize != 0)
387  else
389 
390  if (log_fname != NULL)
392 
393  /*
394  * Also look at existing segment files to set up newXlogSegNo
395  */
396  FindEndOfXLOG();
397 
398  /*
399  * If we're not going to proceed with the reset, print the current control
400  * file parameters.
401  */
402  if ((guessed && !force) || noupdate)
404 
405  /*
406  * Adjust fields if required by switches. (Do this now so that printout,
407  * if any, includes these values.)
408  */
409  if (set_xid_epoch != -1)
413 
414  if (set_oldest_xid != 0)
415  {
418  }
419 
420  if (set_xid != 0)
423  set_xid);
424 
425  if (set_oldest_commit_ts_xid != 0)
427  if (set_newest_commit_ts_xid != 0)
429 
430  if (set_oid != 0)
432 
433  if (set_mxid != 0)
434  {
436 
437  ControlFile.checkPointCopy.oldestMulti = set_oldestmxid;
441  }
442 
443  if (set_mxoff != -1)
445 
447  {
450  }
451 
452  if (set_wal_segsize != 0)
454 
457 
458  /*
459  * If we had to guess anything, and -f was not given, just print the
460  * guessed values and exit. Also print if -n is given.
461  */
462  if ((guessed && !force) || noupdate)
463  {
465  if (!noupdate)
466  {
467  printf(_("\nIf these values seem acceptable, use -f to force reset.\n"));
468  exit(1);
469  }
470  else
471  exit(0);
472  }
473 
474  /*
475  * Don't reset from a dirty pg_control without -f, either.
476  */
477  if (ControlFile.state != DB_SHUTDOWNED && !force)
478  {
479  printf(_("The database server was not shut down cleanly.\n"
480  "Resetting the write-ahead log might cause data to be lost.\n"
481  "If you want to proceed anyway, use -f to force reset.\n"));
482  exit(1);
483  }
484 
485  /*
486  * Else, do the dirty deed.
487  */
491  WriteEmptyXLOG();
492 
493  printf(_("Write-ahead log reset\n"));
494  return 0;
495 }
496 
497 
498 /*
499  * Look at the version string stored in PG_VERSION and decide if this utility
500  * can be run safely or not.
501  *
502  * We don't want to inject pg_control and WAL files that are for a different
503  * major version; that can't do anything good. Note that we don't treat
504  * mismatching version info in pg_control as a reason to bail out, because
505  * recovering from a corrupted pg_control is one of the main reasons for this
506  * program to exist at all. However, PG_VERSION is unlikely to get corrupted,
507  * and if it were it would be easy to fix by hand. So let's make this check
508  * to prevent simple user errors.
509  */
510 static void
512 {
513  const char *ver_file = "PG_VERSION";
514  FILE *ver_fd;
515  char rawline[64];
516 
517  if ((ver_fd = fopen(ver_file, "r")) == NULL)
518  pg_fatal("could not open file \"%s\" for reading: %m",
519  ver_file);
520 
521  /* version number has to be the first line read */
522  if (!fgets(rawline, sizeof(rawline), ver_fd))
523  {
524  if (!ferror(ver_fd))
525  pg_fatal("unexpected empty file \"%s\"", ver_file);
526  else
527  pg_fatal("could not read file \"%s\": %m", ver_file);
528  }
529 
530  /* strip trailing newline and carriage return */
531  (void) pg_strip_crlf(rawline);
532 
533  if (strcmp(rawline, PG_MAJORVERSION) != 0)
534  {
535  pg_log_error("data directory is of wrong version");
536  pg_log_error_detail("File \"%s\" contains \"%s\", which is not compatible with this program's version \"%s\".",
537  ver_file, rawline, PG_MAJORVERSION);
538  exit(1);
539  }
540 
541  fclose(ver_fd);
542 }
543 
544 
545 /*
546  * Try to read the existing pg_control file.
547  *
548  * This routine is also responsible for updating old pg_control versions
549  * to the current format. (Currently we don't do anything of the sort.)
550  */
551 static bool
553 {
554  int fd;
555  int len;
556  char *buffer;
557  pg_crc32c crc;
558 
559  if ((fd = open(XLOG_CONTROL_FILE, O_RDONLY | PG_BINARY, 0)) < 0)
560  {
561  /*
562  * If pg_control is not there at all, or we can't read it, the odds
563  * are we've been handed a bad DataDir path, so give up. User can do
564  * "touch pg_control" to force us to proceed.
565  */
566  pg_log_error("could not open file \"%s\" for reading: %m",
568  if (errno == ENOENT)
569  pg_log_error_hint("If you are sure the data directory path is correct, execute\n"
570  " touch %s\n"
571  "and try again.",
573  exit(1);
574  }
575 
576  /* Use malloc to ensure we have a maxaligned buffer */
577  buffer = (char *) pg_malloc(PG_CONTROL_FILE_SIZE);
578 
579  len = read(fd, buffer, PG_CONTROL_FILE_SIZE);
580  if (len < 0)
581  pg_fatal("could not read file \"%s\": %m", XLOG_CONTROL_FILE);
582  close(fd);
583 
584  if (len >= sizeof(ControlFileData) &&
585  ((ControlFileData *) buffer)->pg_control_version == PG_CONTROL_VERSION)
586  {
587  /* Check the CRC. */
588  INIT_CRC32C(crc);
590  buffer,
591  offsetof(ControlFileData, crc));
592  FIN_CRC32C(crc);
593 
594  if (!EQ_CRC32C(crc, ((ControlFileData *) buffer)->crc))
595  {
596  /* We will use the data but treat it as guessed. */
597  pg_log_warning("pg_control exists but has invalid CRC; proceed with caution");
598  guessed = true;
599  }
600 
601  memcpy(&ControlFile, buffer, sizeof(ControlFile));
602 
603  /* return false if WAL segment size is not valid */
605  {
606  pg_log_warning(ngettext("pg_control specifies invalid WAL segment size (%d byte); proceed with caution",
607  "pg_control specifies invalid WAL segment size (%d bytes); proceed with caution",
610  return false;
611  }
612 
613  return true;
614  }
615 
616  /* Looks like it's a mess. */
617  pg_log_warning("pg_control exists but is broken or wrong version; ignoring it");
618  return false;
619 }
620 
621 
622 /*
623  * Guess at pg_control values when we can't read the old ones.
624  */
625 static void
627 {
628  uint64 sysidentifier;
629  struct timeval tv;
630 
631  /*
632  * Set up a completely default set of pg_control values.
633  */
634  guessed = true;
635  memset(&ControlFile, 0, sizeof(ControlFile));
636 
639 
640  /*
641  * Create a new unique installation identifier, since we can no longer use
642  * any old XLOG records. See notes in xlog.c about the algorithm.
643  */
644  gettimeofday(&tv, NULL);
645  sysidentifier = ((uint64) tv.tv_sec) << 32;
646  sysidentifier |= ((uint64) tv.tv_usec) << 12;
647  sysidentifier |= getpid() & 0xFFF;
648 
649  ControlFile.system_identifier = sysidentifier;
650 
664  ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
666 
668  ControlFile.time = (pg_time_t) time(NULL);
671 
672  /* minRecoveryPoint, backupStartPoint and backupEndPoint can be left zero */
673 
675  ControlFile.wal_log_hints = false;
682 
683  ControlFile.maxAlign = MAXIMUM_ALIGNOF;
685  ControlFile.blcksz = BLCKSZ;
686  ControlFile.relseg_size = RELSEG_SIZE;
687  ControlFile.xlog_blcksz = XLOG_BLCKSZ;
694 
695  /*
696  * XXX eventually, should try to grovel through old XLOG to develop more
697  * accurate values for TimeLineID, nextXID, etc.
698  */
699 }
700 
701 
702 /*
703  * Print the guessed pg_control values when we had to guess.
704  *
705  * NB: this display should be just those fields that will not be
706  * reset by RewriteControlFile().
707  */
708 static void
710 {
711  if (guessed)
712  printf(_("Guessed pg_control values:\n\n"));
713  else
714  printf(_("Current pg_control values:\n\n"));
715 
716  printf(_("pg_control version number: %u\n"),
718  printf(_("Catalog version number: %u\n"),
720  printf(_("Database system identifier: %llu\n"),
721  (unsigned long long) ControlFile.system_identifier);
722  printf(_("Latest checkpoint's TimeLineID: %u\n"),
724  printf(_("Latest checkpoint's full_page_writes: %s\n"),
725  ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off"));
726  printf(_("Latest checkpoint's NextXID: %u:%u\n"),
729  printf(_("Latest checkpoint's NextOID: %u\n"),
731  printf(_("Latest checkpoint's NextMultiXactId: %u\n"),
733  printf(_("Latest checkpoint's NextMultiOffset: %u\n"),
735  printf(_("Latest checkpoint's oldestXID: %u\n"),
737  printf(_("Latest checkpoint's oldestXID's DB: %u\n"),
739  printf(_("Latest checkpoint's oldestActiveXID: %u\n"),
741  printf(_("Latest checkpoint's oldestMultiXid: %u\n"),
743  printf(_("Latest checkpoint's oldestMulti's DB: %u\n"),
745  printf(_("Latest checkpoint's oldestCommitTsXid:%u\n"),
747  printf(_("Latest checkpoint's newestCommitTsXid:%u\n"),
749  printf(_("Maximum data alignment: %u\n"),
751  /* we don't print floatFormat since can't say much useful about it */
752  printf(_("Database block size: %u\n"),
754  printf(_("Blocks per segment of large relation: %u\n"),
756  printf(_("WAL block size: %u\n"),
758  printf(_("Bytes per WAL segment: %u\n"),
760  printf(_("Maximum length of identifiers: %u\n"),
762  printf(_("Maximum columns in an index: %u\n"),
764  printf(_("Maximum size of a TOAST chunk: %u\n"),
766  printf(_("Size of a large-object chunk: %u\n"),
768  /* This is no longer configurable, but users may still expect to see it: */
769  printf(_("Date/time type storage: %s\n"),
770  _("64-bit integers"));
771  printf(_("Float8 argument passing: %s\n"),
772  (ControlFile.float8ByVal ? _("by value") : _("by reference")));
773  printf(_("Data page checksum version: %u\n"),
775 }
776 
777 
778 /*
779  * Print the values to be changed.
780  */
781 static void
783 {
784  char fname[MAXFNAMELEN];
785 
786  /* This will be always printed in order to keep format same. */
787  printf(_("\n\nValues to be changed:\n\n"));
788 
791  printf(_("First log segment after reset: %s\n"), fname);
792 
793  if (set_mxid != 0)
794  {
795  printf(_("NextMultiXactId: %u\n"),
797  printf(_("OldestMultiXid: %u\n"),
799  printf(_("OldestMulti's DB: %u\n"),
801  }
802 
803  if (set_mxoff != -1)
804  {
805  printf(_("NextMultiOffset: %u\n"),
807  }
808 
809  if (set_oid != 0)
810  {
811  printf(_("NextOID: %u\n"),
813  }
814 
815  if (set_xid != 0)
816  {
817  printf(_("NextXID: %u\n"),
819  printf(_("OldestXID: %u\n"),
821  printf(_("OldestXID's DB: %u\n"),
823  }
824 
825  if (set_xid_epoch != -1)
826  {
827  printf(_("NextXID epoch: %u\n"),
829  }
830 
831  if (set_oldest_commit_ts_xid != 0)
832  {
833  printf(_("oldestCommitTsXid: %u\n"),
835  }
836  if (set_newest_commit_ts_xid != 0)
837  {
838  printf(_("newestCommitTsXid: %u\n"),
840  }
841 
842  if (set_wal_segsize != 0)
843  {
844  printf(_("Bytes per WAL segment: %u\n"),
846  }
847 }
848 
849 
850 /*
851  * Write out the new pg_control file.
852  */
853 static void
855 {
856  /*
857  * Adjust fields as needed to force an empty XLOG starting at
858  * newXlogSegNo.
859  */
862  ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
863 
871 
872  /*
873  * Force the defaults for max_* settings. The values don't really matter
874  * as long as wal_level='minimal'; the postmaster will reset these fields
875  * anyway at startup.
876  */
878  ControlFile.wal_log_hints = false;
885 
886  /* The control file gets flushed here. */
887  update_controlfile(".", &ControlFile, true);
888 }
889 
890 
891 /*
892  * Scan existing XLOG files and determine the highest existing WAL address
893  *
894  * On entry, ControlFile.checkPointCopy.redo and ControlFile.xlog_seg_size
895  * are assumed valid (note that we allow the old xlog seg size to differ
896  * from what we're using). On exit, newXlogSegNo is set to suitable
897  * value for the beginning of replacement WAL (in our seg size).
898  */
899 static void
901 {
902  DIR *xldir;
903  struct dirent *xlde;
904  uint64 xlogbytepos;
905 
906  /*
907  * Initialize the max() computation using the last checkpoint address from
908  * old pg_control. Note that for the moment we are working with segment
909  * numbering according to the old xlog seg size.
910  */
913 
914  /*
915  * Scan the pg_wal directory to find existing WAL segment files. We assume
916  * any present have been used; in most scenarios this should be
917  * conservative, because of xlog.c's attempts to pre-create files.
918  */
919  xldir = opendir(XLOGDIR);
920  if (xldir == NULL)
921  pg_fatal("could not open directory \"%s\": %m", XLOGDIR);
922 
923  while (errno = 0, (xlde = readdir(xldir)) != NULL)
924  {
925  if (IsXLogFileName(xlde->d_name) ||
927  {
928  TimeLineID tli;
929  XLogSegNo segno;
930 
931  /* Use the segment size from the control file */
932  XLogFromFileName(xlde->d_name, &tli, &segno,
934 
935  /*
936  * Note: we take the max of all files found, regardless of their
937  * timelines. Another possibility would be to ignore files of
938  * timelines other than the target TLI, but this seems safer.
939  * Better too large a result than too small...
940  */
941  if (segno > newXlogSegNo)
942  newXlogSegNo = segno;
943  }
944  }
945 
946  if (errno)
947  pg_fatal("could not read directory \"%s\": %m", XLOGDIR);
948 
949  if (closedir(xldir))
950  pg_fatal("could not close directory \"%s\": %m", XLOGDIR);
951 
952  /*
953  * Finally, convert to new xlog seg size, and advance by one to ensure we
954  * are in virgin territory.
955  */
956  xlogbytepos = newXlogSegNo * ControlFile.xlog_seg_size;
957  newXlogSegNo = (xlogbytepos + ControlFile.xlog_seg_size - 1) / WalSegSz;
958  newXlogSegNo++;
959 }
960 
961 
962 /*
963  * Remove existing XLOG files
964  */
965 static void
967 {
968  DIR *xldir;
969  struct dirent *xlde;
970  char path[MAXPGPATH + sizeof(XLOGDIR)];
971 
972  xldir = opendir(XLOGDIR);
973  if (xldir == NULL)
974  pg_fatal("could not open directory \"%s\": %m", XLOGDIR);
975 
976  while (errno = 0, (xlde = readdir(xldir)) != NULL)
977  {
978  if (IsXLogFileName(xlde->d_name) ||
980  {
981  snprintf(path, sizeof(path), "%s/%s", XLOGDIR, xlde->d_name);
982  if (unlink(path) < 0)
983  pg_fatal("could not delete file \"%s\": %m", path);
984  }
985  }
986 
987  if (errno)
988  pg_fatal("could not read directory \"%s\": %m", XLOGDIR);
989 
990  if (closedir(xldir))
991  pg_fatal("could not close directory \"%s\": %m", XLOGDIR);
992 }
993 
994 
995 /*
996  * Remove existing archive status files
997  */
998 static void
1000 {
1001 #define ARCHSTATDIR XLOGDIR "/archive_status"
1002 
1003  DIR *xldir;
1004  struct dirent *xlde;
1005  char path[MAXPGPATH + sizeof(ARCHSTATDIR)];
1006 
1007  xldir = opendir(ARCHSTATDIR);
1008  if (xldir == NULL)
1009  pg_fatal("could not open directory \"%s\": %m", ARCHSTATDIR);
1010 
1011  while (errno = 0, (xlde = readdir(xldir)) != NULL)
1012  {
1013  if (strspn(xlde->d_name, "0123456789ABCDEF") == XLOG_FNAME_LEN &&
1014  (strcmp(xlde->d_name + XLOG_FNAME_LEN, ".ready") == 0 ||
1015  strcmp(xlde->d_name + XLOG_FNAME_LEN, ".done") == 0 ||
1016  strcmp(xlde->d_name + XLOG_FNAME_LEN, ".partial.ready") == 0 ||
1017  strcmp(xlde->d_name + XLOG_FNAME_LEN, ".partial.done") == 0))
1018  {
1019  snprintf(path, sizeof(path), "%s/%s", ARCHSTATDIR, xlde->d_name);
1020  if (unlink(path) < 0)
1021  pg_fatal("could not delete file \"%s\": %m", path);
1022  }
1023  }
1024 
1025  if (errno)
1026  pg_fatal("could not read directory \"%s\": %m", ARCHSTATDIR);
1027 
1028  if (closedir(xldir))
1029  pg_fatal("could not close directory \"%s\": %m", ARCHSTATDIR);
1030 }
1031 
1032 
1033 /*
1034  * Write an empty XLOG file, containing only the checkpoint record
1035  * already set up in ControlFile.
1036  */
1037 static void
1039 {
1040  PGAlignedXLogBlock buffer;
1041  XLogPageHeader page;
1042  XLogLongPageHeader longpage;
1043  XLogRecord *record;
1044  pg_crc32c crc;
1045  char path[MAXPGPATH];
1046  int fd;
1047  int nbytes;
1048  char *recptr;
1049 
1050  memset(buffer.data, 0, XLOG_BLCKSZ);
1051 
1052  /* Set up the XLOG page header */
1053  page = (XLogPageHeader) buffer.data;
1054  page->xlp_magic = XLOG_PAGE_MAGIC;
1055  page->xlp_info = XLP_LONG_HEADER;
1058  longpage = (XLogLongPageHeader) page;
1060  longpage->xlp_seg_size = WalSegSz;
1061  longpage->xlp_xlog_blcksz = XLOG_BLCKSZ;
1062 
1063  /* Insert the initial checkpoint record */
1064  recptr = (char *) page + SizeOfXLogLongPHD;
1065  record = (XLogRecord *) recptr;
1066  record->xl_prev = 0;
1067  record->xl_xid = InvalidTransactionId;
1070  record->xl_rmid = RM_XLOG_ID;
1071 
1072  recptr += SizeOfXLogRecord;
1073  *(recptr++) = (char) XLR_BLOCK_ID_DATA_SHORT;
1074  *(recptr++) = sizeof(CheckPoint);
1075  memcpy(recptr, &ControlFile.checkPointCopy,
1076  sizeof(CheckPoint));
1077 
1078  INIT_CRC32C(crc);
1079  COMP_CRC32C(crc, ((char *) record) + SizeOfXLogRecord, record->xl_tot_len - SizeOfXLogRecord);
1080  COMP_CRC32C(crc, (char *) record, offsetof(XLogRecord, xl_crc));
1081  FIN_CRC32C(crc);
1082  record->xl_crc = crc;
1083 
1084  /* Write the first page */
1087 
1088  unlink(path);
1089 
1090  fd = open(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
1092  if (fd < 0)
1093  pg_fatal("could not open file \"%s\": %m", path);
1094 
1095  errno = 0;
1096  if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
1097  {
1098  /* if write didn't set errno, assume problem is no disk space */
1099  if (errno == 0)
1100  errno = ENOSPC;
1101  pg_fatal("could not write file \"%s\": %m", path);
1102  }
1103 
1104  /* Fill the rest of the file with zeroes */
1105  memset(buffer.data, 0, XLOG_BLCKSZ);
1106  for (nbytes = XLOG_BLCKSZ; nbytes < WalSegSz; nbytes += XLOG_BLCKSZ)
1107  {
1108  errno = 0;
1109  if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
1110  {
1111  if (errno == 0)
1112  errno = ENOSPC;
1113  pg_fatal("could not write file \"%s\": %m", path);
1114  }
1115  }
1116 
1117  if (fsync(fd) != 0)
1118  pg_fatal("fsync error: %m");
1119 
1120  close(fd);
1121 }
1122 
1123 
1124 static void
1125 usage(void)
1126 {
1127  printf(_("%s resets the PostgreSQL write-ahead log.\n\n"), progname);
1128  printf(_("Usage:\n %s [OPTION]... DATADIR\n\n"), progname);
1129  printf(_("Options:\n"));
1130  printf(_(" -c, --commit-timestamp-ids=XID,XID\n"
1131  " set oldest and newest transactions bearing\n"
1132  " commit timestamp (zero means no change)\n"));
1133  printf(_(" [-D, --pgdata=]DATADIR data directory\n"));
1134  printf(_(" -e, --epoch=XIDEPOCH set next transaction ID epoch\n"));
1135  printf(_(" -f, --force force update to be done\n"));
1136  printf(_(" -l, --next-wal-file=WALFILE set minimum starting location for new WAL\n"));
1137  printf(_(" -m, --multixact-ids=MXID,MXID set next and oldest multitransaction ID\n"));
1138  printf(_(" -n, --dry-run no update, just show what would be done\n"));
1139  printf(_(" -o, --next-oid=OID set next OID\n"));
1140  printf(_(" -O, --multixact-offset=OFFSET set next multitransaction offset\n"));
1141  printf(_(" -u, --oldest-transaction-id=XID set oldest transaction ID\n"));
1142  printf(_(" -V, --version output version information, then exit\n"));
1143  printf(_(" -x, --next-transaction-id=XID set next transaction ID\n"));
1144  printf(_(" --wal-segsize=SIZE size of WAL segments, in megabytes\n"));
1145  printf(_(" -?, --help show this help, then exit\n"));
1146  printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1147  printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
1148 }
unsigned int uint32
Definition: c.h:490
#define ngettext(s, p, n)
Definition: c.h:1189
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1222
#define PG_BINARY
Definition: c.h:1278
uint32 MultiXactOffset
Definition: c.h:648
TransactionId MultiXactId
Definition: c.h:646
#define FLOAT8PASSBYVAL
Definition: c.h:619
uint32 TransactionId
Definition: c.h:636
#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:57
#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
#define pg_fatal(...)
#define INDEX_MAX_KEYS
#define NAMEDATALEN
#define MAXPGPATH
#define DEFAULT_XLOG_SEG_SIZE
#define FLOATFORMAT_VALUE
Definition: pg_control.h:199
#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:248
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
PGDLLIMPORT int optind
Definition: getopt.c:50
PGDLLIMPORT char * optarg
Definition: getopt.c:52
static void FindEndOfXLOG(void)
Definition: pg_resetwal.c:900
static void RewriteControlFile(void)
Definition: pg_resetwal.c:854
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:966
static void CheckDataVersion(void)
Definition: pg_resetwal.c:511
#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:782
static XLogSegNo newXlogSegNo
Definition: pg_resetwal.c:63
static bool read_controlfile(void)
Definition: pg_resetwal.c:552
static void KillExistingArchiveStatus(void)
Definition: pg_resetwal.c:999
static void WriteEmptyXLOG(void)
Definition: pg_resetwal.c:1038
static const char * progname
Definition: pg_resetwal.c:65
static void usage(void)
Definition: pg_resetwal.c:1125
static void PrintControlValues(bool guessed)
Definition: pg_resetwal.c:709
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:626
#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:179
uint32 pg_control_version
Definition: pg_control.h:123
uint32 xlog_seg_size
Definition: pg_control.h:209
XLogRecPtr backupStartPoint
Definition: pg_control.h:168
bool track_commit_timestamp
Definition: pg_control.h:183
bool backupEndRequired
Definition: pg_control.h:170
int max_locks_per_xact
Definition: pg_control.h:182
uint32 nameDataLen
Definition: pg_control.h:211
CheckPoint checkPointCopy
Definition: pg_control.h:133
XLogRecPtr backupEndPoint
Definition: pg_control.h:169
XLogRecPtr minRecoveryPoint
Definition: pg_control.h:166
uint32 data_checksum_version
Definition: pg_control.h:220
XLogRecPtr unloggedLSN
Definition: pg_control.h:135
uint32 indexMaxKeys
Definition: pg_control.h:212
uint32 relseg_size
Definition: pg_control.h:206
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:198
int max_prepared_xacts
Definition: pg_control.h:181
uint32 xlog_blcksz
Definition: pg_control.h:208
TimeLineID minRecoveryPointTLI
Definition: pg_control.h:167
uint32 loblksize
Definition: pg_control.h:215
uint32 toast_max_chunk_size
Definition: pg_control.h:214
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:1156
#define fsync(fd)
Definition: win32_port.h:85
int gettimeofday(struct timeval *tp, void *tzp)
@ WAL_LEVEL_MINIMAL
Definition: xlog.h:69
#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