PostgreSQL Source Code  git master
pg_rewind.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pg_rewind.c
4  * Synchronizes a PostgreSQL data directory to a new timeline
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  *
8  *-------------------------------------------------------------------------
9  */
10 #include "postgres_fe.h"
11 
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <time.h>
15 #include <unistd.h>
16 
17 #include "pg_rewind.h"
18 #include "fetch.h"
19 #include "file_ops.h"
20 #include "filemap.h"
21 #include "logging.h"
22 
23 #include "access/timeline.h"
24 #include "access/xlog_internal.h"
25 #include "catalog/catversion.h"
26 #include "catalog/pg_control.h"
28 #include "getopt_long.h"
29 #include "storage/bufpage.h"
30 
31 static void usage(const char *progname);
32 
33 static void createBackupLabel(XLogRecPtr startpoint, TimeLineID starttli,
34  XLogRecPtr checkpointloc);
35 
36 static void digestControlFile(ControlFileData *ControlFile, char *source,
37  size_t size);
39 static void syncTargetDirectory(const char *argv0);
40 static void sanityChecks(void);
41 static void findCommonAncestorTimeline(XLogRecPtr *recptr, int *tliIndex);
42 
45 
46 const char *progname;
48 
49 /* Configuration options */
50 char *datadir_target = NULL;
51 char *datadir_source = NULL;
52 char *connstr_source = NULL;
53 
54 bool debug = false;
55 bool showprogress = false;
56 bool dry_run = false;
57 
58 /* Target history */
61 
62 static void
63 usage(const char *progname)
64 {
65  printf(_("%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n\n"), progname);
66  printf(_("Usage:\n %s [OPTION]...\n\n"), progname);
67  printf(_("Options:\n"));
68  printf(_(" -D, --target-pgdata=DIRECTORY existing data directory to modify\n"));
69  printf(_(" --source-pgdata=DIRECTORY source data directory to synchronize with\n"));
70  printf(_(" --source-server=CONNSTR source server to synchronize with\n"));
71  printf(_(" -n, --dry-run stop before modifying anything\n"));
72  printf(_(" -P, --progress write progress messages\n"));
73  printf(_(" --debug write a lot of debug messages\n"));
74  printf(_(" -V, --version output version information, then exit\n"));
75  printf(_(" -?, --help show this help, then exit\n"));
76  printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
77 }
78 
79 
80 int
81 main(int argc, char **argv)
82 {
83  static struct option long_options[] = {
84  {"help", no_argument, NULL, '?'},
85  {"target-pgdata", required_argument, NULL, 'D'},
86  {"source-pgdata", required_argument, NULL, 1},
87  {"source-server", required_argument, NULL, 2},
88  {"version", no_argument, NULL, 'V'},
89  {"dry-run", no_argument, NULL, 'n'},
90  {"progress", no_argument, NULL, 'P'},
91  {"debug", no_argument, NULL, 3},
92  {NULL, 0, NULL, 0}
93  };
94  int option_index;
95  int c;
96  XLogRecPtr divergerec;
97  int lastcommontliIndex;
98  XLogRecPtr chkptrec;
99  TimeLineID chkpttli;
100  XLogRecPtr chkptredo;
101  size_t size;
102  char *buffer;
103  bool rewind_needed;
104  XLogRecPtr endrec;
105  TimeLineID endtli;
106  ControlFileData ControlFile_new;
107 
108  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_rewind"));
109  progname = get_progname(argv[0]);
110 
111  /* Process command-line arguments */
112  if (argc > 1)
113  {
114  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
115  {
116  usage(progname);
117  exit(0);
118  }
119  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
120  {
121  puts("pg_rewind (PostgreSQL) " PG_VERSION);
122  exit(0);
123  }
124  }
125 
126  while ((c = getopt_long(argc, argv, "D:nP", long_options, &option_index)) != -1)
127  {
128  switch (c)
129  {
130  case '?':
131  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
132  exit(1);
133 
134  case 'P':
135  showprogress = true;
136  break;
137 
138  case 'n':
139  dry_run = true;
140  break;
141 
142  case 3:
143  debug = true;
144  break;
145 
146  case 'D': /* -D or --target-pgdata */
148  break;
149 
150  case 1: /* --source-pgdata */
152  break;
153  case 2: /* --source-server */
155  break;
156  }
157  }
158 
159  if (datadir_source == NULL && connstr_source == NULL)
160  {
161  fprintf(stderr, _("%s: no source specified (--source-pgdata or --source-server)\n"), progname);
162  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
163  exit(1);
164  }
165 
166  if (datadir_source != NULL && connstr_source != NULL)
167  {
168  fprintf(stderr, _("%s: only one of --source-pgdata or --source-server can be specified\n"), progname);
169  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
170  exit(1);
171  }
172 
173  if (datadir_target == NULL)
174  {
175  fprintf(stderr, _("%s: no target data directory specified (--target-pgdata)\n"), progname);
176  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
177  exit(1);
178  }
179 
180  if (optind < argc)
181  {
182  fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
183  progname, argv[optind]);
184  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
185  exit(1);
186  }
187 
188  /*
189  * Don't allow pg_rewind to be run as root, to avoid overwriting the
190  * ownership of files in the data directory. We need only check for root
191  * -- any other user won't have sufficient permissions to modify files in
192  * the data directory.
193  */
194 #ifndef WIN32
195  if (geteuid() == 0)
196  {
197  fprintf(stderr, _("cannot be executed by \"root\"\n"));
198  fprintf(stderr, _("You must run %s as the PostgreSQL superuser.\n"),
199  progname);
200  }
201 #endif
202 
204 
205  /* Connect to remote server */
206  if (connstr_source)
208 
209  /*
210  * Ok, we have all the options and we're ready to start. Read in all the
211  * information we need from both clusters.
212  */
213  buffer = slurpFile(datadir_target, "global/pg_control", &size);
214  digestControlFile(&ControlFile_target, buffer, size);
215  pg_free(buffer);
216 
217  buffer = fetchFile("global/pg_control", &size);
218  digestControlFile(&ControlFile_source, buffer, size);
219  pg_free(buffer);
220 
221  sanityChecks();
222 
223  /*
224  * If both clusters are already on the same timeline, there's nothing to
225  * do.
226  */
227  if (ControlFile_target.checkPointCopy.ThisTimeLineID == ControlFile_source.checkPointCopy.ThisTimeLineID)
228  {
229  printf(_("source and target cluster are on the same timeline\n"));
230  rewind_needed = false;
231  }
232  else
233  {
234  findCommonAncestorTimeline(&divergerec, &lastcommontliIndex);
235  printf(_("servers diverged at WAL location %X/%X on timeline %u\n"),
236  (uint32) (divergerec >> 32), (uint32) divergerec,
237  targetHistory[lastcommontliIndex].tli);
238 
239  /*
240  * Check for the possibility that the target is in fact a direct
241  * ancestor of the source. In that case, there is no divergent history
242  * in the target that needs rewinding.
243  */
244  if (ControlFile_target.checkPoint >= divergerec)
245  {
246  rewind_needed = true;
247  }
248  else
249  {
250  XLogRecPtr chkptendrec;
251 
252  /* Read the checkpoint record on the target to see where it ends. */
253  chkptendrec = readOneRecord(datadir_target,
254  ControlFile_target.checkPoint,
255  targetNentries - 1);
256 
257  /*
258  * If the histories diverged exactly at the end of the shutdown
259  * checkpoint record on the target, there are no WAL records in
260  * the target that don't belong in the source's history, and no
261  * rewind is needed.
262  */
263  if (chkptendrec == divergerec)
264  rewind_needed = false;
265  else
266  rewind_needed = true;
267  }
268  }
269 
270  if (!rewind_needed)
271  {
272  printf(_("no rewind required\n"));
273  exit(0);
274  }
275 
277  lastcommontliIndex,
278  &chkptrec, &chkpttli, &chkptredo);
279  printf(_("rewinding from last common checkpoint at %X/%X on timeline %u\n"),
280  (uint32) (chkptrec >> 32), (uint32) chkptrec,
281  chkpttli);
282 
283  /*
284  * Build the filemap, by comparing the source and target data directories.
285  */
286  filemap_create();
287  pg_log(PG_PROGRESS, "reading source file list\n");
289  pg_log(PG_PROGRESS, "reading target file list\n");
291 
292  /*
293  * Read the target WAL from last checkpoint before the point of fork, to
294  * extract all the pages that were modified on the target cluster after
295  * the fork. We can stop reading after reaching the final shutdown record.
296  * XXX: If we supported rewinding a server that was not shut down cleanly,
297  * we would need to replay until the end of WAL here.
298  */
299  pg_log(PG_PROGRESS, "reading WAL in target\n");
300  extractPageMap(datadir_target, chkptrec, lastcommontliIndex,
301  ControlFile_target.checkPoint);
303 
304  if (showprogress)
306 
307  /* this is too verbose even for verbose mode */
308  if (debug)
309  print_filemap();
310 
311  /*
312  * Ok, we're ready to start copying things over.
313  */
314  if (showprogress)
315  {
316  pg_log(PG_PROGRESS, "need to copy %lu MB (total source directory size is %lu MB)\n",
317  (unsigned long) (filemap->fetch_size / (1024 * 1024)),
318  (unsigned long) (filemap->total_size / (1024 * 1024)));
319 
321  fetch_done = 0;
322  }
323 
324  /*
325  * This is the point of no return. Once we start copying things, we have
326  * modified the target directory and there is no turning back!
327  */
328 
329  executeFileMap();
330 
331  progress_report(true);
332 
333  pg_log(PG_PROGRESS, "\ncreating backup label and updating control file\n");
334  createBackupLabel(chkptredo, chkpttli, chkptrec);
335 
336  /*
337  * Update control file of target. Make it ready to perform archive
338  * recovery when restarting.
339  *
340  * minRecoveryPoint is set to the current WAL insert location in the
341  * source server. Like in an online backup, it's important that we recover
342  * all the WAL that was generated while we copied the files over.
343  */
344  memcpy(&ControlFile_new, &ControlFile_source, sizeof(ControlFileData));
345 
346  if (connstr_source)
347  {
349  endtli = ControlFile_source.checkPointCopy.ThisTimeLineID;
350  }
351  else
352  {
353  endrec = ControlFile_source.checkPoint;
354  endtli = ControlFile_source.checkPointCopy.ThisTimeLineID;
355  }
356  ControlFile_new.minRecoveryPoint = endrec;
357  ControlFile_new.minRecoveryPointTLI = endtli;
358  ControlFile_new.state = DB_IN_ARCHIVE_RECOVERY;
359  updateControlFile(&ControlFile_new);
360 
361  pg_log(PG_PROGRESS, "syncing target data directory\n");
362  syncTargetDirectory(argv[0]);
363 
364  printf(_("Done!\n"));
365 
366  return 0;
367 }
368 
369 static void
371 {
372  /* TODO Check that there's no backup_label in either cluster */
373 
374  /* Check system_id match */
375  if (ControlFile_target.system_identifier != ControlFile_source.system_identifier)
376  pg_fatal("source and target clusters are from different systems\n");
377 
378  /* check version */
379  if (ControlFile_target.pg_control_version != PG_CONTROL_VERSION ||
380  ControlFile_source.pg_control_version != PG_CONTROL_VERSION ||
381  ControlFile_target.catalog_version_no != CATALOG_VERSION_NO ||
382  ControlFile_source.catalog_version_no != CATALOG_VERSION_NO)
383  {
384  pg_fatal("clusters are not compatible with this version of pg_rewind\n");
385  }
386 
387  /*
388  * Target cluster need to use checksums or hint bit wal-logging, this to
389  * prevent from data corruption that could occur because of hint bits.
390  */
391  if (ControlFile_target.data_checksum_version != PG_DATA_CHECKSUM_VERSION &&
392  !ControlFile_target.wal_log_hints)
393  {
394  pg_fatal("target server needs to use either data checksums or \"wal_log_hints = on\"\n");
395  }
396 
397  /*
398  * Target cluster better not be running. This doesn't guard against
399  * someone starting the cluster concurrently. Also, this is probably more
400  * strict than necessary; it's OK if the target node was not shut down
401  * cleanly, as long as it isn't running at the moment.
402  */
403  if (ControlFile_target.state != DB_SHUTDOWNED &&
404  ControlFile_target.state != DB_SHUTDOWNED_IN_RECOVERY)
405  pg_fatal("target server must be shut down cleanly\n");
406 
407  /*
408  * When the source is a data directory, also require that the source
409  * server is shut down. There isn't any very strong reason for this
410  * limitation, but better safe than sorry.
411  */
412  if (datadir_source &&
413  ControlFile_source.state != DB_SHUTDOWNED &&
414  ControlFile_source.state != DB_SHUTDOWNED_IN_RECOVERY)
415  pg_fatal("source data directory must be shut down cleanly\n");
416 }
417 
418 /*
419  * Find minimum from two WAL locations assuming InvalidXLogRecPtr means
420  * infinity as src/include/access/timeline.h states. This routine should
421  * be used only when comparing WAL locations related to history files.
422  */
423 static XLogRecPtr
425 {
426  if (XLogRecPtrIsInvalid(a))
427  return b;
428  else if (XLogRecPtrIsInvalid(b))
429  return a;
430  else
431  return Min(a, b);
432 }
433 
434 /*
435  * Retrieve timeline history for given control file which should behold
436  * either source or target.
437  */
438 static TimeLineHistoryEntry *
439 getTimelineHistory(ControlFileData *controlFile, int *nentries)
440 {
441  TimeLineHistoryEntry *history;
442  TimeLineID tli;
443 
444  tli = controlFile->checkPointCopy.ThisTimeLineID;
445 
446  /*
447  * Timeline 1 does not have a history file, so there is no need to check
448  * and fake an entry with infinite start and end positions.
449  */
450  if (tli == 1)
451  {
452  history = (TimeLineHistoryEntry *) pg_malloc(sizeof(TimeLineHistoryEntry));
453  history->tli = tli;
454  history->begin = history->end = InvalidXLogRecPtr;
455  *nentries = 1;
456  }
457  else
458  {
459  char path[MAXPGPATH];
460  char *histfile;
461 
462  TLHistoryFilePath(path, tli);
463 
464  /* Get history file from appropriate source */
465  if (controlFile == &ControlFile_source)
466  histfile = fetchFile(path, NULL);
467  else if (controlFile == &ControlFile_target)
468  histfile = slurpFile(datadir_target, path, NULL);
469  else
470  pg_fatal("invalid control file");
471 
472  history = rewind_parseTimeLineHistory(histfile, tli, nentries);
473  pg_free(histfile);
474  }
475 
476  if (debug)
477  {
478  int i;
479 
480  if (controlFile == &ControlFile_source)
481  pg_log(PG_DEBUG, "Source timeline history:\n");
482  else if (controlFile == &ControlFile_target)
483  pg_log(PG_DEBUG, "Target timeline history:\n");
484  else
485  Assert(false);
486 
487  /*
488  * Print the target timeline history.
489  */
490  for (i = 0; i < targetNentries; i++)
491  {
492  TimeLineHistoryEntry *entry;
493 
494  entry = &history[i];
496  /* translator: %d is a timeline number, others are LSN positions */
497  "%d: %X/%X - %X/%X\n", entry->tli,
498  (uint32) (entry->begin >> 32), (uint32) (entry->begin),
499  (uint32) (entry->end >> 32), (uint32) (entry->end));
500  }
501  }
502 
503  return history;
504 }
505 
506 /*
507  * Determine the TLI of the last common timeline in the timeline history of the
508  * two clusters. targetHistory is filled with target timeline history and
509  * targetNentries is number of items in targetHistory. *tliIndex is set to the
510  * index of last common timeline in targetHistory array, and *recptr is set to
511  * the position where the timeline history diverged (ie. the first WAL record
512  * that's not the same in both clusters).
513  *
514  * Control files of both clusters must be read into ControlFile_target/source
515  * before calling this routine.
516  */
517 static void
518 findCommonAncestorTimeline(XLogRecPtr *recptr, int *tliIndex)
519 {
520  TimeLineHistoryEntry *sourceHistory;
521  int sourceNentries;
522  int i,
523  n;
524 
525  /* Retrieve timelines for both source and target */
526  sourceHistory = getTimelineHistory(&ControlFile_source, &sourceNentries);
527  targetHistory = getTimelineHistory(&ControlFile_target, &targetNentries);
528 
529  /*
530  * Trace the history forward, until we hit the timeline diverge. It may
531  * still be possible that the source and target nodes used the same
532  * timeline number in their history but with different start position
533  * depending on the history files that each node has fetched in previous
534  * recovery processes. Hence check the start position of the new timeline
535  * as well and move down by one extra timeline entry if they do not match.
536  */
537  n = Min(sourceNentries, targetNentries);
538  for (i = 0; i < n; i++)
539  {
540  if (sourceHistory[i].tli != targetHistory[i].tli ||
541  sourceHistory[i].begin != targetHistory[i].begin)
542  break;
543  }
544 
545  if (i > 0)
546  {
547  i--;
548  *recptr = MinXLogRecPtr(sourceHistory[i].end, targetHistory[i].end);
549  *tliIndex = i;
550 
551  pg_free(sourceHistory);
552  return;
553  }
554  else
555  {
556  pg_fatal("could not find common ancestor of the source and target cluster's timelines\n");
557  }
558 }
559 
560 
561 /*
562  * Create a backup_label file that forces recovery to begin at the last common
563  * checkpoint.
564  */
565 static void
566 createBackupLabel(XLogRecPtr startpoint, TimeLineID starttli, XLogRecPtr checkpointloc)
567 {
568  XLogSegNo startsegno;
569  time_t stamp_time;
570  char strfbuf[128];
571  char xlogfilename[MAXFNAMELEN];
572  struct tm *tmp;
573  char buf[1000];
574  int len;
575 
576  XLByteToSeg(startpoint, startsegno, WalSegSz);
577  XLogFileName(xlogfilename, starttli, startsegno, WalSegSz);
578 
579  /*
580  * Construct backup label file
581  */
582  stamp_time = time(NULL);
583  tmp = localtime(&stamp_time);
584  strftime(strfbuf, sizeof(strfbuf), "%Y-%m-%d %H:%M:%S %Z", tmp);
585 
586  len = snprintf(buf, sizeof(buf),
587  "START WAL LOCATION: %X/%X (file %s)\n"
588  "CHECKPOINT LOCATION: %X/%X\n"
589  "BACKUP METHOD: pg_rewind\n"
590  "BACKUP FROM: standby\n"
591  "START TIME: %s\n",
592  /* omit LABEL: line */
593  (uint32) (startpoint >> 32), (uint32) startpoint, xlogfilename,
594  (uint32) (checkpointloc >> 32), (uint32) checkpointloc,
595  strfbuf);
596  if (len >= sizeof(buf))
597  pg_fatal("backup label buffer too small\n"); /* shouldn't happen */
598 
599  /* TODO: move old file out of the way, if any. */
600  open_target_file("backup_label", true); /* BACKUP_LABEL_FILE */
601  write_target_range(buf, 0, len);
603 }
604 
605 /*
606  * Check CRC of control file
607  */
608 static void
610 {
611  pg_crc32c crc;
612 
613  /* Calculate CRC */
614  INIT_CRC32C(crc);
615  COMP_CRC32C(crc, (char *) ControlFile, offsetof(ControlFileData, crc));
616  FIN_CRC32C(crc);
617 
618  /* And simply compare it */
619  if (!EQ_CRC32C(crc, ControlFile->crc))
620  pg_fatal("unexpected control file CRC\n");
621 }
622 
623 /*
624  * Verify control file contents in the buffer src, and copy it to *ControlFile.
625  */
626 static void
628 {
629  if (size != PG_CONTROL_FILE_SIZE)
630  pg_fatal("unexpected control file size %d, expected %d\n",
631  (int) size, PG_CONTROL_FILE_SIZE);
632 
633  memcpy(ControlFile, src, sizeof(ControlFileData));
634 
635  /* set and validate WalSegSz */
636  WalSegSz = ControlFile->xlog_seg_size;
637 
639  pg_fatal("WAL segment size must be a power of two between 1MB and 1GB, but the control file specifies %d bytes\n",
640  WalSegSz);
641 
642  /* Additional checks on control file */
643  checkControlFile(ControlFile);
644 }
645 
646 /*
647  * Update the target's control file.
648  */
649 static void
651 {
653 
654  /*
655  * For good luck, apply the same static assertions as in backend's
656  * WriteControlFile().
657  */
659  "pg_control is too large for atomic disk writes");
661  "sizeof(ControlFileData) exceeds PG_CONTROL_FILE_SIZE");
662 
663  /* Recalculate CRC of control file */
664  INIT_CRC32C(ControlFile->crc);
665  COMP_CRC32C(ControlFile->crc,
666  (char *) ControlFile,
667  offsetof(ControlFileData, crc));
668  FIN_CRC32C(ControlFile->crc);
669 
670  /*
671  * Write out PG_CONTROL_FILE_SIZE bytes into pg_control by zero-padding
672  * the excess over sizeof(ControlFileData), to avoid premature EOF related
673  * errors when reading it.
674  */
675  memset(buffer, 0, PG_CONTROL_FILE_SIZE);
676  memcpy(buffer, ControlFile, sizeof(ControlFileData));
677 
678  open_target_file("global/pg_control", false);
679 
681 
683 }
684 
685 /*
686  * Sync target data directory to ensure that modifications are safely on disk.
687  *
688  * We do this once, for the whole data directory, for performance reasons. At
689  * the end of pg_rewind's run, the kernel is likely to already have flushed
690  * most dirty buffers to disk. Additionally initdb -S uses a two-pass approach
691  * (only initiating writeback in the first pass), which often reduces the
692  * overall amount of IO noticeably.
693  */
694 static void
696 {
697  int ret;
698 #define MAXCMDLEN (2 * MAXPGPATH)
699  char exec_path[MAXPGPATH];
700  char cmd[MAXCMDLEN];
701 
702  /* locate initdb binary */
703  if ((ret = find_other_exec(argv0, "initdb",
704  "initdb (PostgreSQL) " PG_VERSION "\n",
705  exec_path)) < 0)
706  {
707  char full_path[MAXPGPATH];
708 
709  if (find_my_exec(argv0, full_path) < 0)
710  strlcpy(full_path, progname, sizeof(full_path));
711 
712  if (ret == -1)
713  pg_fatal("The program \"initdb\" is needed by %s but was\n"
714  "not found in the same directory as \"%s\".\n"
715  "Check your installation.\n", progname, full_path);
716  else
717  pg_fatal("The program \"initdb\" was found by \"%s\"\n"
718  "but was not the same version as %s.\n"
719  "Check your installation.\n", full_path, progname);
720  }
721 
722  /* only skip processing after ensuring presence of initdb */
723  if (dry_run)
724  return;
725 
726  /* finally run initdb -S */
727  if (debug)
728  snprintf(cmd, MAXCMDLEN, "\"%s\" -D \"%s\" -S",
729  exec_path, datadir_target);
730  else
731  snprintf(cmd, MAXCMDLEN, "\"%s\" -D \"%s\" -S > \"%s\"",
732  exec_path, datadir_target, DEVNULL);
733 
734  if (system(cmd) != 0)
735  pg_fatal("sync of target directory failed\n");
736 }
#define INIT_CRC32C(crc)
Definition: pg_crc32c.h:41
#define IsValidWalSegSize(size)
Definition: xlog_internal.h:97
void calculate_totals(void)
Definition: filemap.c:479
int find_other_exec(const char *argv0, const char *target, const char *versionstr, char *retpath)
Definition: exec.c:307
char * datadir_target
Definition: pg_rewind.c:50
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
void open_target_file(const char *path, bool trunc)
Definition: file_ops.c:43
static char * argv0
Definition: pg_ctl.c:93
void write_target_range(char *buf, off_t begin, size_t size)
Definition: file_ops.c:84
uint32 TimeLineID
Definition: xlogdefs.h:45
bool debug
Definition: pg_rewind.c:54
#define MAXCMDLEN
int main(int argc, char **argv)
Definition: pg_rewind.c:81
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
TimeLineID minRecoveryPointTLI
Definition: pg_control.h:167
uint64 fetch_done
Definition: logging.c:22
TimeLineHistoryEntry * targetHistory
Definition: pg_rewind.c:59
bool dry_run
Definition: pg_rewind.c:56
const char * get_progname(const char *argv0)
Definition: path.c:453
void process_target_file(const char *path, file_type_t type, size_t oldsize, const char *link_target)
Definition: filemap.c:251
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:57
uint32 pg_crc32c
Definition: pg_crc32c.h:38
#define Min(x, y)
Definition: c.h:802
void extractPageMap(const char *datadir, XLogRecPtr startpoint, int tliIndex, XLogRecPtr endpoint)
Definition: parsexlog.c:62
uint64 fetch_size
Definition: logging.c:21
static XLogRecPtr MinXLogRecPtr(XLogRecPtr a, XLogRecPtr b)
Definition: pg_rewind.c:424
#define CATALOG_VERSION_NO
Definition: catversion.h:56
#define PG_CONTROL_VERSION
Definition: pg_control.h:24
uint32 pg_control_version
Definition: pg_control.h:121
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void pg_fatal(const char *fmt,...)
Definition: logging.c:83
TimeLineID tli
Definition: timeline.h:27
CheckPoint checkPointCopy
Definition: pg_control.h:131
void fetchSourceFileList(void)
Definition: fetch.c:28
void filemap_create(void)
Definition: filemap.c:38
#define PG_CONTROL_MAX_SAFE_SIZE
Definition: pg_control.h:240
char * fetchFile(const char *filename, size_t *filesize)
Definition: fetch.c:54
void filemap_finalize(void)
Definition: filemap.c:443
void executeFileMap(void)
Definition: fetch.c:40
uint64 fetch_size
Definition: filemap.h:87
static struct pg_tm tm
Definition: localtime.c:107
void get_restricted_token(const char *progname)
bool showprogress
Definition: pg_rewind.c:55
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:753
#define required_argument
Definition: getopt_long.h:25
uint32 xlog_seg_size
Definition: pg_control.h:208
int optind
Definition: getopt.c:51
uint64 system_identifier
Definition: pg_control.h:106
static void checkControlFile(ControlFileData *ControlFile)
Definition: pg_rewind.c:609
XLogRecPtr libpqGetCurrentXlogInsertLocation(void)
Definition: libpq_fetch.c:123
#define MAXPGPATH
int find_my_exec(const char *argv0, char *retpath)
Definition: exec.c:119
uint32 data_checksum_version
Definition: pg_control.h:221
char * c
static void usage(const char *progname)
Definition: pg_rewind.c:63
static char * buf
Definition: pg_test_fsync.c:67
XLogRecPtr readOneRecord(const char *datadir, XLogRecPtr ptr, int tliIndex)
Definition: parsexlog.c:116
uint64 XLogSegNo
Definition: xlogdefs.h:34
filemap_t * filemap
Definition: filemap.c:25
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
uint64 total_size
Definition: filemap.h:86
unsigned int uint32
Definition: c.h:296
pg_crc32c crc
Definition: pg_control.h:231
void pg_log(eLogType type, const char *fmt,...)
Definition: logging.c:69
#define EQ_CRC32C(c1, c2)
Definition: pg_crc32c.h:42
#define DEVNULL
Definition: port.h:123
static void progress_report(int tablespacenum, const char *filename, bool force)
void print_filemap(void)
Definition: filemap.c:521
static void findCommonAncestorTimeline(XLogRecPtr *recptr, int *tliIndex)
Definition: pg_rewind.c:518
void traverse_datadir(const char *datadir, process_file_callback_t callback)
Definition: copy_fetch.c:36
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
char * connstr_source
Definition: pg_rewind.c:52
#define MAXFNAMELEN
int WalSegSz
Definition: pg_rewind.c:47
#define no_argument
Definition: getopt_long.h:24
#define PG_TEXTDOMAIN(domain)
Definition: c.h:999
int targetNentries
Definition: pg_rewind.c:60
char * datadir_source
Definition: pg_rewind.c:51
static ControlFileData * ControlFile
Definition: xlog.c:715
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
XLogRecPtr end
Definition: timeline.h:29
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:670
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
static void updateControlFile(ControlFileData *ControlFile)
Definition: pg_rewind.c:650
#define XLogFileName(fname, tli, logSegNo, wal_segsz_bytes)
static char * exec_path
Definition: pg_ctl.c:88
uint32 catalog_version_no
Definition: pg_control.h:122
void pg_free(void *ptr)
Definition: fe_memutils.c:105
#define PG_CONTROL_FILE_SIZE
Definition: pg_control.h:249
static TimeLineHistoryEntry * getTimelineHistory(ControlFileData *controlFile, int *nentries)
Definition: pg_rewind.c:439
static void sanityChecks(void)
Definition: pg_rewind.c:370
void close_target_file(void)
Definition: file_ops.c:71
#define PG_DATA_CHECKSUM_VERSION
Definition: bufpage.h:196
static void syncTargetDirectory(const char *argv0)
Definition: pg_rewind.c:695
TimeLineID ThisTimeLineID
Definition: pg_control.h:38
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:550
void findLastCheckpoint(const char *datadir, XLogRecPtr forkptr, int tliIndex, XLogRecPtr *lastchkptrec, TimeLineID *lastchkpttli, XLogRecPtr *lastchkptredo)
Definition: parsexlog.c:157
XLogRecPtr begin
Definition: timeline.h:28
char * optarg
Definition: getopt.c:53
int i
TimeLineHistoryEntry * rewind_parseTimeLineHistory(char *buffer, TimeLineID targetTLI, int *nentries)
Definition: timeline.c:30
static ControlFileData ControlFile_target
Definition: pg_rewind.c:43
static ControlFileData ControlFile_source
Definition: pg_rewind.c:44
static void createBackupLabel(XLogRecPtr startpoint, TimeLineID starttli, XLogRecPtr checkpointloc)
Definition: pg_rewind.c:566
static void digestControlFile(ControlFileData *ControlFile, char *source, size_t size)
Definition: pg_rewind.c:627
#define COMP_CRC32C(crc, data, len)
Definition: pg_crc32c.h:73
#define FIN_CRC32C(crc)
Definition: pg_crc32c.h:78
#define _(x)
Definition: elog.c:84
XLogRecPtr checkPoint
Definition: pg_control.h:129
#define offsetof(type, field)
Definition: c.h:593
const char * progname
Definition: pg_rewind.c:46
XLogRecPtr minRecoveryPoint
Definition: pg_control.h:166
void libpqConnect(const char *connstr)
Definition: libpq_fetch.c:45
char * slurpFile(const char *datadir, const char *path, size_t *filesize)
Definition: file_ops.c:276
#define TLHistoryFilePath(path, tli)
#define XLByteToSeg(xlrp, logSegNo, wal_segsz_bytes)