PostgreSQL Source Code  git master
pg_rewind.c File Reference
#include "postgres_fe.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include "pg_rewind.h"
#include "fetch.h"
#include "file_ops.h"
#include "filemap.h"
#include "logging.h"
#include "access/timeline.h"
#include "access/xlog_internal.h"
#include "catalog/catversion.h"
#include "catalog/pg_control.h"
#include "common/file_perm.h"
#include "common/restricted_token.h"
#include "getopt_long.h"
#include "storage/bufpage.h"
Include dependency graph for pg_rewind.c:

Go to the source code of this file.

Macros

#define MAXCMDLEN   (2 * MAXPGPATH)
 

Functions

static void usage (const char *progname)
 
static void createBackupLabel (XLogRecPtr startpoint, TimeLineID starttli, XLogRecPtr checkpointloc)
 
static void digestControlFile (ControlFileData *ControlFile, char *source, size_t size)
 
static void updateControlFile (ControlFileData *ControlFile)
 
static void syncTargetDirectory (const char *argv0)
 
static void sanityChecks (void)
 
static void findCommonAncestorTimeline (XLogRecPtr *recptr, int *tliIndex)
 
int main (int argc, char **argv)
 
static XLogRecPtr MinXLogRecPtr (XLogRecPtr a, XLogRecPtr b)
 
static TimeLineHistoryEntrygetTimelineHistory (ControlFileData *controlFile, int *nentries)
 
static void checkControlFile (ControlFileData *ControlFile)
 

Variables

static ControlFileData ControlFile_target
 
static ControlFileData ControlFile_source
 
const char * progname
 
int WalSegSz
 
char * datadir_target = NULL
 
char * datadir_source = NULL
 
char * connstr_source = NULL
 
bool debug = false
 
bool showprogress = false
 
bool dry_run = false
 
TimeLineHistoryEntrytargetHistory
 
int targetNentries
 

Macro Definition Documentation

◆ MAXCMDLEN

#define MAXCMDLEN   (2 * MAXPGPATH)

Referenced by syncTargetDirectory().

Function Documentation

◆ checkControlFile()

static void checkControlFile ( ControlFileData ControlFile)
static

Definition at line 621 of file pg_rewind.c.

References COMP_CRC32C, EQ_CRC32C, FIN_CRC32C, INIT_CRC32C, offsetof, and pg_fatal().

Referenced by digestControlFile().

622 {
623  pg_crc32c crc;
624 
625  /* Calculate CRC */
626  INIT_CRC32C(crc);
627  COMP_CRC32C(crc, (char *) ControlFile, offsetof(ControlFileData, crc));
628  FIN_CRC32C(crc);
629 
630  /* And simply compare it */
631  if (!EQ_CRC32C(crc, ControlFile->crc))
632  pg_fatal("unexpected control file CRC\n");
633 }
#define INIT_CRC32C(crc)
Definition: pg_crc32c.h:41
uint32 pg_crc32c
Definition: pg_crc32c.h:38
void pg_fatal(const char *fmt,...)
Definition: logging.c:83
#define EQ_CRC32C(c1, c2)
Definition: pg_crc32c.h:42
#define COMP_CRC32C(crc, data, len)
Definition: pg_crc32c.h:89
#define FIN_CRC32C(crc)
Definition: pg_crc32c.h:94
#define offsetof(type, field)
Definition: c.h:622

◆ createBackupLabel()

static void createBackupLabel ( XLogRecPtr  startpoint,
TimeLineID  starttli,
XLogRecPtr  checkpointloc 
)
static

Definition at line 578 of file pg_rewind.c.

References buf, close_target_file(), MAXFNAMELEN, open_target_file(), pg_fatal(), snprintf(), tm, WalSegSz, write_target_range(), XLByteToSeg, and XLogFileName.

Referenced by main().

579 {
580  XLogSegNo startsegno;
581  time_t stamp_time;
582  char strfbuf[128];
583  char xlogfilename[MAXFNAMELEN];
584  struct tm *tmp;
585  char buf[1000];
586  int len;
587 
588  XLByteToSeg(startpoint, startsegno, WalSegSz);
589  XLogFileName(xlogfilename, starttli, startsegno, WalSegSz);
590 
591  /*
592  * Construct backup label file
593  */
594  stamp_time = time(NULL);
595  tmp = localtime(&stamp_time);
596  strftime(strfbuf, sizeof(strfbuf), "%Y-%m-%d %H:%M:%S %Z", tmp);
597 
598  len = snprintf(buf, sizeof(buf),
599  "START WAL LOCATION: %X/%X (file %s)\n"
600  "CHECKPOINT LOCATION: %X/%X\n"
601  "BACKUP METHOD: pg_rewind\n"
602  "BACKUP FROM: standby\n"
603  "START TIME: %s\n",
604  /* omit LABEL: line */
605  (uint32) (startpoint >> 32), (uint32) startpoint, xlogfilename,
606  (uint32) (checkpointloc >> 32), (uint32) checkpointloc,
607  strfbuf);
608  if (len >= sizeof(buf))
609  pg_fatal("backup label buffer too small\n"); /* shouldn't happen */
610 
611  /* TODO: move old file out of the way, if any. */
612  open_target_file("backup_label", true); /* BACKUP_LABEL_FILE */
613  write_target_range(buf, 0, len);
615 }
void open_target_file(const char *path, bool trunc)
Definition: file_ops.c:43
void write_target_range(char *buf, off_t begin, size_t size)
Definition: file_ops.c:84
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void pg_fatal(const char *fmt,...)
Definition: logging.c:83
static struct pg_tm tm
Definition: localtime.c:106
static char * buf
Definition: pg_test_fsync.c:67
uint64 XLogSegNo
Definition: xlogdefs.h:34
unsigned int uint32
Definition: c.h:325
#define MAXFNAMELEN
int WalSegSz
Definition: pg_rewind.c:48
#define XLogFileName(fname, tli, logSegNo, wal_segsz_bytes)
void close_target_file(void)
Definition: file_ops.c:71
#define XLByteToSeg(xlrp, logSegNo, wal_segsz_bytes)

◆ digestControlFile()

static void digestControlFile ( ControlFileData ControlFile,
char *  source,
size_t  size 
)
static

Definition at line 639 of file pg_rewind.c.

References checkControlFile(), IsValidWalSegSize, ngettext, PG_CONTROL_FILE_SIZE, pg_fatal(), WalSegSz, and ControlFileData::xlog_seg_size.

Referenced by main().

640 {
641  if (size != PG_CONTROL_FILE_SIZE)
642  pg_fatal("unexpected control file size %d, expected %d\n",
643  (int) size, PG_CONTROL_FILE_SIZE);
644 
645  memcpy(ControlFile, src, sizeof(ControlFileData));
646 
647  /* set and validate WalSegSz */
648  WalSegSz = ControlFile->xlog_seg_size;
649 
651  pg_fatal(ngettext("WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d byte\n",
652  "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes\n",
653  WalSegSz),
654  WalSegSz);
655 
656  /* Additional checks on control file */
657  checkControlFile(ControlFile);
658 }
#define IsValidWalSegSize(size)
Definition: xlog_internal.h:97
void pg_fatal(const char *fmt,...)
Definition: logging.c:83
uint32 xlog_seg_size
Definition: pg_control.h:208
static void checkControlFile(ControlFileData *ControlFile)
Definition: pg_rewind.c:621
int WalSegSz
Definition: pg_rewind.c:48
#define ngettext(s, p, n)
Definition: c.h:1022
#define PG_CONTROL_FILE_SIZE
Definition: pg_control.h:249

◆ findCommonAncestorTimeline()

static void findCommonAncestorTimeline ( XLogRecPtr recptr,
int *  tliIndex 
)
static

Definition at line 530 of file pg_rewind.c.

References getTimelineHistory(), i, Min, MinXLogRecPtr(), pg_fatal(), pg_free(), and targetNentries.

Referenced by main().

531 {
532  TimeLineHistoryEntry *sourceHistory;
533  int sourceNentries;
534  int i,
535  n;
536 
537  /* Retrieve timelines for both source and target */
538  sourceHistory = getTimelineHistory(&ControlFile_source, &sourceNentries);
540 
541  /*
542  * Trace the history forward, until we hit the timeline diverge. It may
543  * still be possible that the source and target nodes used the same
544  * timeline number in their history but with different start position
545  * depending on the history files that each node has fetched in previous
546  * recovery processes. Hence check the start position of the new timeline
547  * as well and move down by one extra timeline entry if they do not match.
548  */
549  n = Min(sourceNentries, targetNentries);
550  for (i = 0; i < n; i++)
551  {
552  if (sourceHistory[i].tli != targetHistory[i].tli ||
553  sourceHistory[i].begin != targetHistory[i].begin)
554  break;
555  }
556 
557  if (i > 0)
558  {
559  i--;
560  *recptr = MinXLogRecPtr(sourceHistory[i].end, targetHistory[i].end);
561  *tliIndex = i;
562 
563  pg_free(sourceHistory);
564  return;
565  }
566  else
567  {
568  pg_fatal("could not find common ancestor of the source and target cluster's timelines\n");
569  }
570 }
TimeLineHistoryEntry * targetHistory
Definition: pg_rewind.c:60
#define Min(x, y)
Definition: c.h:857
static XLogRecPtr MinXLogRecPtr(XLogRecPtr a, XLogRecPtr b)
Definition: pg_rewind.c:436
void pg_fatal(const char *fmt,...)
Definition: logging.c:83
int targetNentries
Definition: pg_rewind.c:61
void pg_free(void *ptr)
Definition: fe_memutils.c:105
static TimeLineHistoryEntry * getTimelineHistory(ControlFileData *controlFile, int *nentries)
Definition: pg_rewind.c:451
int i
static ControlFileData ControlFile_target
Definition: pg_rewind.c:44
static ControlFileData ControlFile_source
Definition: pg_rewind.c:45

◆ getTimelineHistory()

static TimeLineHistoryEntry* getTimelineHistory ( ControlFileData controlFile,
int *  nentries 
)
static

Definition at line 451 of file pg_rewind.c.

References Assert, TimeLineHistoryEntry::begin, ControlFileData::checkPointCopy, datadir_target, debug, TimeLineHistoryEntry::end, fetchFile(), i, InvalidXLogRecPtr, MAXPGPATH, PG_DEBUG, pg_fatal(), pg_free(), pg_log(), pg_malloc(), rewind_parseTimeLineHistory(), slurpFile(), targetNentries, CheckPoint::ThisTimeLineID, TLHistoryFilePath, and TimeLineHistoryEntry::tli.

Referenced by findCommonAncestorTimeline().

452 {
453  TimeLineHistoryEntry *history;
454  TimeLineID tli;
455 
456  tli = controlFile->checkPointCopy.ThisTimeLineID;
457 
458  /*
459  * Timeline 1 does not have a history file, so there is no need to check
460  * and fake an entry with infinite start and end positions.
461  */
462  if (tli == 1)
463  {
464  history = (TimeLineHistoryEntry *) pg_malloc(sizeof(TimeLineHistoryEntry));
465  history->tli = tli;
466  history->begin = history->end = InvalidXLogRecPtr;
467  *nentries = 1;
468  }
469  else
470  {
471  char path[MAXPGPATH];
472  char *histfile;
473 
474  TLHistoryFilePath(path, tli);
475 
476  /* Get history file from appropriate source */
477  if (controlFile == &ControlFile_source)
478  histfile = fetchFile(path, NULL);
479  else if (controlFile == &ControlFile_target)
480  histfile = slurpFile(datadir_target, path, NULL);
481  else
482  pg_fatal("invalid control file");
483 
484  history = rewind_parseTimeLineHistory(histfile, tli, nentries);
485  pg_free(histfile);
486  }
487 
488  if (debug)
489  {
490  int i;
491 
492  if (controlFile == &ControlFile_source)
493  pg_log(PG_DEBUG, "Source timeline history:\n");
494  else if (controlFile == &ControlFile_target)
495  pg_log(PG_DEBUG, "Target timeline history:\n");
496  else
497  Assert(false);
498 
499  /*
500  * Print the target timeline history.
501  */
502  for (i = 0; i < targetNentries; i++)
503  {
504  TimeLineHistoryEntry *entry;
505 
506  entry = &history[i];
508  /* translator: %d is a timeline number, others are LSN positions */
509  "%d: %X/%X - %X/%X\n", entry->tli,
510  (uint32) (entry->begin >> 32), (uint32) (entry->begin),
511  (uint32) (entry->end >> 32), (uint32) (entry->end));
512  }
513  }
514 
515  return history;
516 }
char * datadir_target
Definition: pg_rewind.c:51
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
uint32 TimeLineID
Definition: xlogdefs.h:45
bool debug
Definition: pg_rewind.c:55
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
void pg_fatal(const char *fmt,...)
Definition: logging.c:83
TimeLineID tli
Definition: timeline.h:27
CheckPoint checkPointCopy
Definition: pg_control.h:131
char * fetchFile(const char *filename, size_t *filesize)
Definition: fetch.c:54
#define MAXPGPATH
unsigned int uint32
Definition: c.h:325
void pg_log(eLogType type, const char *fmt,...)
Definition: logging.c:69
int targetNentries
Definition: pg_rewind.c:61
XLogRecPtr end
Definition: timeline.h:29
#define Assert(condition)
Definition: c.h:699
void pg_free(void *ptr)
Definition: fe_memutils.c:105
TimeLineID ThisTimeLineID
Definition: pg_control.h:38
XLogRecPtr begin
Definition: timeline.h:28
int i
TimeLineHistoryEntry * rewind_parseTimeLineHistory(char *buffer, TimeLineID targetTLI, int *nentries)
Definition: timeline.c:30
static ControlFileData ControlFile_target
Definition: pg_rewind.c:44
static ControlFileData ControlFile_source
Definition: pg_rewind.c:45
char * slurpFile(const char *datadir, const char *path, size_t *filesize)
Definition: file_ops.c:285
#define TLHistoryFilePath(path, tli)

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 82 of file pg_rewind.c.

References _, buffer, calculate_totals(), ControlFileData::checkPoint, ControlFileData::checkPointCopy, connstr_source, createBackupLabel(), datadir_source, datadir_target, DB_IN_ARCHIVE_RECOVERY, debug, digestControlFile(), dry_run, executeFileMap(), extractPageMap(), fetch_done, fetch_size, filemap_t::fetch_size, fetchFile(), fetchSourceFileList(), filemap, filemap_create(), filemap_finalize(), findCommonAncestorTimeline(), findLastCheckpoint(), get_progname(), get_restricted_token(), GetDataDirectoryCreatePerm(), getopt_long(), libpqConnect(), libpqGetCurrentXlogInsertLocation(), ControlFileData::minRecoveryPoint, ControlFileData::minRecoveryPointTLI, no_argument, optarg, optind, pg_free(), pg_log(), pg_mode_mask, PG_PROGRESS, pg_strdup(), PG_TEXTDOMAIN, print_filemap(), process_target_file(), progname, progress_report(), readOneRecord(), required_argument, sanityChecks(), set_pglocale_pgservice(), showprogress, slurpFile(), ControlFileData::state, strerror(), syncTargetDirectory(), targetNentries, CheckPoint::ThisTimeLineID, filemap_t::total_size, traverse_datadir(), updateControlFile(), and usage().

83 {
84  static struct option long_options[] = {
85  {"help", no_argument, NULL, '?'},
86  {"target-pgdata", required_argument, NULL, 'D'},
87  {"source-pgdata", required_argument, NULL, 1},
88  {"source-server", required_argument, NULL, 2},
89  {"version", no_argument, NULL, 'V'},
90  {"dry-run", no_argument, NULL, 'n'},
91  {"progress", no_argument, NULL, 'P'},
92  {"debug", no_argument, NULL, 3},
93  {NULL, 0, NULL, 0}
94  };
95  int option_index;
96  int c;
97  XLogRecPtr divergerec;
98  int lastcommontliIndex;
99  XLogRecPtr chkptrec;
100  TimeLineID chkpttli;
101  XLogRecPtr chkptredo;
102  size_t size;
103  char *buffer;
104  bool rewind_needed;
105  XLogRecPtr endrec;
106  TimeLineID endtli;
107  ControlFileData ControlFile_new;
108 
109  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_rewind"));
110  progname = get_progname(argv[0]);
111 
112  /* Process command-line arguments */
113  if (argc > 1)
114  {
115  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
116  {
117  usage(progname);
118  exit(0);
119  }
120  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
121  {
122  puts("pg_rewind (PostgreSQL) " PG_VERSION);
123  exit(0);
124  }
125  }
126 
127  while ((c = getopt_long(argc, argv, "D:nP", long_options, &option_index)) != -1)
128  {
129  switch (c)
130  {
131  case '?':
132  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
133  exit(1);
134 
135  case 'P':
136  showprogress = true;
137  break;
138 
139  case 'n':
140  dry_run = true;
141  break;
142 
143  case 3:
144  debug = true;
145  break;
146 
147  case 'D': /* -D or --target-pgdata */
149  break;
150 
151  case 1: /* --source-pgdata */
153  break;
154  case 2: /* --source-server */
156  break;
157  }
158  }
159 
160  if (datadir_source == NULL && connstr_source == NULL)
161  {
162  fprintf(stderr, _("%s: no source specified (--source-pgdata or --source-server)\n"), progname);
163  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
164  exit(1);
165  }
166 
167  if (datadir_source != NULL && connstr_source != NULL)
168  {
169  fprintf(stderr, _("%s: only one of --source-pgdata or --source-server can be specified\n"), progname);
170  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
171  exit(1);
172  }
173 
174  if (datadir_target == NULL)
175  {
176  fprintf(stderr, _("%s: no target data directory specified (--target-pgdata)\n"), progname);
177  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
178  exit(1);
179  }
180 
181  if (optind < argc)
182  {
183  fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
184  progname, argv[optind]);
185  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
186  exit(1);
187  }
188 
189  /*
190  * Don't allow pg_rewind to be run as root, to avoid overwriting the
191  * ownership of files in the data directory. We need only check for root
192  * -- any other user won't have sufficient permissions to modify files in
193  * the data directory.
194  */
195 #ifndef WIN32
196  if (geteuid() == 0)
197  {
198  fprintf(stderr, _("cannot be executed by \"root\"\n"));
199  fprintf(stderr, _("You must run %s as the PostgreSQL superuser.\n"),
200  progname);
201  exit(1);
202  }
203 #endif
204 
206 
207  /* Set mask based on PGDATA permissions */
209  {
210  fprintf(stderr, _("%s: could not read permissions of directory \"%s\": %s\n"),
211  progname, datadir_target, strerror(errno));
212  exit(1);
213  }
214 
215  umask(pg_mode_mask);
216 
217  /* Connect to remote server */
218  if (connstr_source)
220 
221  /*
222  * Ok, we have all the options and we're ready to start. Read in all the
223  * information we need from both clusters.
224  */
225  buffer = slurpFile(datadir_target, "global/pg_control", &size);
226  digestControlFile(&ControlFile_target, buffer, size);
227  pg_free(buffer);
228 
229  buffer = fetchFile("global/pg_control", &size);
230  digestControlFile(&ControlFile_source, buffer, size);
231  pg_free(buffer);
232 
233  sanityChecks();
234 
235  /*
236  * If both clusters are already on the same timeline, there's nothing to
237  * do.
238  */
240  {
241  printf(_("source and target cluster are on the same timeline\n"));
242  rewind_needed = false;
243  }
244  else
245  {
246  findCommonAncestorTimeline(&divergerec, &lastcommontliIndex);
247  printf(_("servers diverged at WAL location %X/%X on timeline %u\n"),
248  (uint32) (divergerec >> 32), (uint32) divergerec,
249  targetHistory[lastcommontliIndex].tli);
250 
251  /*
252  * Check for the possibility that the target is in fact a direct
253  * ancestor of the source. In that case, there is no divergent history
254  * in the target that needs rewinding.
255  */
256  if (ControlFile_target.checkPoint >= divergerec)
257  {
258  rewind_needed = true;
259  }
260  else
261  {
262  XLogRecPtr chkptendrec;
263 
264  /* Read the checkpoint record on the target to see where it ends. */
265  chkptendrec = readOneRecord(datadir_target,
267  targetNentries - 1);
268 
269  /*
270  * If the histories diverged exactly at the end of the shutdown
271  * checkpoint record on the target, there are no WAL records in
272  * the target that don't belong in the source's history, and no
273  * rewind is needed.
274  */
275  if (chkptendrec == divergerec)
276  rewind_needed = false;
277  else
278  rewind_needed = true;
279  }
280  }
281 
282  if (!rewind_needed)
283  {
284  printf(_("no rewind required\n"));
285  exit(0);
286  }
287 
289  lastcommontliIndex,
290  &chkptrec, &chkpttli, &chkptredo);
291  printf(_("rewinding from last common checkpoint at %X/%X on timeline %u\n"),
292  (uint32) (chkptrec >> 32), (uint32) chkptrec,
293  chkpttli);
294 
295  /*
296  * Build the filemap, by comparing the source and target data directories.
297  */
298  filemap_create();
299  pg_log(PG_PROGRESS, "reading source file list\n");
301  pg_log(PG_PROGRESS, "reading target file list\n");
303 
304  /*
305  * Read the target WAL from last checkpoint before the point of fork, to
306  * extract all the pages that were modified on the target cluster after
307  * the fork. We can stop reading after reaching the final shutdown record.
308  * XXX: If we supported rewinding a server that was not shut down cleanly,
309  * we would need to replay until the end of WAL here.
310  */
311  pg_log(PG_PROGRESS, "reading WAL in target\n");
312  extractPageMap(datadir_target, chkptrec, lastcommontliIndex,
315 
316  if (showprogress)
318 
319  /* this is too verbose even for verbose mode */
320  if (debug)
321  print_filemap();
322 
323  /*
324  * Ok, we're ready to start copying things over.
325  */
326  if (showprogress)
327  {
328  pg_log(PG_PROGRESS, "need to copy %lu MB (total source directory size is %lu MB)\n",
329  (unsigned long) (filemap->fetch_size / (1024 * 1024)),
330  (unsigned long) (filemap->total_size / (1024 * 1024)));
331 
333  fetch_done = 0;
334  }
335 
336  /*
337  * This is the point of no return. Once we start copying things, we have
338  * modified the target directory and there is no turning back!
339  */
340 
341  executeFileMap();
342 
343  progress_report(true);
344 
345  pg_log(PG_PROGRESS, "\ncreating backup label and updating control file\n");
346  createBackupLabel(chkptredo, chkpttli, chkptrec);
347 
348  /*
349  * Update control file of target. Make it ready to perform archive
350  * recovery when restarting.
351  *
352  * minRecoveryPoint is set to the current WAL insert location in the
353  * source server. Like in an online backup, it's important that we recover
354  * all the WAL that was generated while we copied the files over.
355  */
356  memcpy(&ControlFile_new, &ControlFile_source, sizeof(ControlFileData));
357 
358  if (connstr_source)
359  {
362  }
363  else
364  {
367  }
368  ControlFile_new.minRecoveryPoint = endrec;
369  ControlFile_new.minRecoveryPointTLI = endtli;
370  ControlFile_new.state = DB_IN_ARCHIVE_RECOVERY;
371  updateControlFile(&ControlFile_new);
372 
373  pg_log(PG_PROGRESS, "syncing target data directory\n");
374  syncTargetDirectory(argv[0]);
375 
376  printf(_("Done!\n"));
377 
378  return 0;
379 }
void calculate_totals(void)
Definition: filemap.c:599
char * datadir_target
Definition: pg_rewind.c:51
uint32 TimeLineID
Definition: xlogdefs.h:45
bool debug
Definition: pg_rewind.c:55
TimeLineID minRecoveryPointTLI
Definition: pg_control.h:167
uint64 fetch_done
Definition: logging.c:22
TimeLineHistoryEntry * targetHistory
Definition: pg_rewind.c:60
bool dry_run
Definition: pg_rewind.c:57
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:325
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:57
void extractPageMap(const char *datadir, XLogRecPtr startpoint, int tliIndex, XLogRecPtr endpoint)
Definition: parsexlog.c:62
uint64 fetch_size
Definition: logging.c:21
CheckPoint checkPointCopy
Definition: pg_control.h:131
void fetchSourceFileList(void)
Definition: fetch.c:28
void filemap_create(void)
Definition: filemap.c:115
char * fetchFile(const char *filename, size_t *filesize)
Definition: fetch.c:54
void filemap_finalize(void)
Definition: filemap.c:563
void executeFileMap(void)
Definition: fetch.c:40
uint64 fetch_size
Definition: filemap.h:87
void get_restricted_token(const char *progname)
bool showprogress
Definition: pg_rewind.c:56
#define required_argument
Definition: getopt_long.h:25
int optind
Definition: getopt.c:51
XLogRecPtr libpqGetCurrentXlogInsertLocation(void)
Definition: libpq_fetch.c:129
char * c
static void usage(const char *progname)
Definition: pg_rewind.c:64
XLogRecPtr readOneRecord(const char *datadir, XLogRecPtr ptr, int tliIndex)
Definition: parsexlog.c:116
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:325
void pg_log(eLogType type, const char *fmt,...)
Definition: logging.c:69
static void progress_report(int tablespacenum, const char *filename, bool force)
void print_filemap(void)
Definition: filemap.c:641
static void findCommonAncestorTimeline(XLogRecPtr *recptr, int *tliIndex)
Definition: pg_rewind.c:530
void traverse_datadir(const char *datadir, process_file_callback_t callback)
Definition: copy_fetch.c:34
char * connstr_source
Definition: pg_rewind.c:53
#define no_argument
Definition: getopt_long.h:24
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1054
int targetNentries
Definition: pg_rewind.c:61
char * datadir_source
Definition: pg_rewind.c:52
uint64 XLogRecPtr
Definition: xlogdefs.h:21
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
static void updateControlFile(ControlFileData *ControlFile)
Definition: pg_rewind.c:664
void pg_free(void *ptr)
Definition: fe_memutils.c:105
static void sanityChecks(void)
Definition: pg_rewind.c:382
static void syncTargetDirectory(const char *argv0)
Definition: pg_rewind.c:709
bool GetDataDirectoryCreatePerm(const char *dataDir)
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
char * optarg
Definition: getopt.c:53
const char * strerror(int errnum)
Definition: strerror.c:19
static ControlFileData ControlFile_target
Definition: pg_rewind.c:44
static ControlFileData ControlFile_source
Definition: pg_rewind.c:45
static void createBackupLabel(XLogRecPtr startpoint, TimeLineID starttli, XLogRecPtr checkpointloc)
Definition: pg_rewind.c:578
static void digestControlFile(ControlFileData *ControlFile, char *source, size_t size)
Definition: pg_rewind.c:639
#define _(x)
Definition: elog.c:84
int pg_mode_mask
Definition: file_perm.c:25
XLogRecPtr checkPoint
Definition: pg_control.h:129
const char * progname
Definition: pg_rewind.c:47
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:285

◆ MinXLogRecPtr()

static XLogRecPtr MinXLogRecPtr ( XLogRecPtr  a,
XLogRecPtr  b 
)
static

Definition at line 436 of file pg_rewind.c.

References Min, and XLogRecPtrIsInvalid.

Referenced by findCommonAncestorTimeline().

437 {
438  if (XLogRecPtrIsInvalid(a))
439  return b;
440  else if (XLogRecPtrIsInvalid(b))
441  return a;
442  else
443  return Min(a, b);
444 }
#define Min(x, y)
Definition: c.h:857
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29

◆ sanityChecks()

static void sanityChecks ( void  )
static

Definition at line 382 of file pg_rewind.c.

References CATALOG_VERSION_NO, ControlFileData::catalog_version_no, ControlFileData::data_checksum_version, datadir_source, DB_SHUTDOWNED, DB_SHUTDOWNED_IN_RECOVERY, PG_CONTROL_VERSION, ControlFileData::pg_control_version, PG_DATA_CHECKSUM_VERSION, pg_fatal(), ControlFileData::state, ControlFileData::system_identifier, and ControlFileData::wal_log_hints.

Referenced by main().

383 {
384  /* TODO Check that there's no backup_label in either cluster */
385 
386  /* Check system_id match */
388  pg_fatal("source and target clusters are from different systems\n");
389 
390  /* check version */
395  {
396  pg_fatal("clusters are not compatible with this version of pg_rewind\n");
397  }
398 
399  /*
400  * Target cluster need to use checksums or hint bit wal-logging, this to
401  * prevent from data corruption that could occur because of hint bits.
402  */
405  {
406  pg_fatal("target server needs to use either data checksums or \"wal_log_hints = on\"\n");
407  }
408 
409  /*
410  * Target cluster better not be running. This doesn't guard against
411  * someone starting the cluster concurrently. Also, this is probably more
412  * strict than necessary; it's OK if the target node was not shut down
413  * cleanly, as long as it isn't running at the moment.
414  */
417  pg_fatal("target server must be shut down cleanly\n");
418 
419  /*
420  * When the source is a data directory, also require that the source
421  * server is shut down. There isn't any very strong reason for this
422  * limitation, but better safe than sorry.
423  */
424  if (datadir_source &&
427  pg_fatal("source data directory must be shut down cleanly\n");
428 }
#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
void pg_fatal(const char *fmt,...)
Definition: logging.c:83
uint64 system_identifier
Definition: pg_control.h:106
uint32 data_checksum_version
Definition: pg_control.h:221
char * datadir_source
Definition: pg_rewind.c:52
uint32 catalog_version_no
Definition: pg_control.h:122
#define PG_DATA_CHECKSUM_VERSION
Definition: bufpage.h:196
static ControlFileData ControlFile_target
Definition: pg_rewind.c:44
static ControlFileData ControlFile_source
Definition: pg_rewind.c:45

◆ syncTargetDirectory()

static void syncTargetDirectory ( const char *  argv0)
static

Definition at line 709 of file pg_rewind.c.

References datadir_target, debug, DEVNULL, dry_run, exec_path, find_my_exec(), find_other_exec(), MAXCMDLEN, MAXPGPATH, pg_fatal(), progname, snprintf(), and strlcpy().

Referenced by main().

710 {
711  int ret;
712 #define MAXCMDLEN (2 * MAXPGPATH)
713  char exec_path[MAXPGPATH];
714  char cmd[MAXCMDLEN];
715 
716  /* locate initdb binary */
717  if ((ret = find_other_exec(argv0, "initdb",
718  "initdb (PostgreSQL) " PG_VERSION "\n",
719  exec_path)) < 0)
720  {
721  char full_path[MAXPGPATH];
722 
723  if (find_my_exec(argv0, full_path) < 0)
724  strlcpy(full_path, progname, sizeof(full_path));
725 
726  if (ret == -1)
727  pg_fatal("The program \"initdb\" is needed by %s but was\n"
728  "not found in the same directory as \"%s\".\n"
729  "Check your installation.\n", progname, full_path);
730  else
731  pg_fatal("The program \"initdb\" was found by \"%s\"\n"
732  "but was not the same version as %s.\n"
733  "Check your installation.\n", full_path, progname);
734  }
735 
736  /* only skip processing after ensuring presence of initdb */
737  if (dry_run)
738  return;
739 
740  /* finally run initdb -S */
741  if (debug)
742  snprintf(cmd, MAXCMDLEN, "\"%s\" -D \"%s\" -S",
743  exec_path, datadir_target);
744  else
745  snprintf(cmd, MAXCMDLEN, "\"%s\" -D \"%s\" -S > \"%s\"",
746  exec_path, datadir_target, DEVNULL);
747 
748  if (system(cmd) != 0)
749  pg_fatal("sync of target directory failed\n");
750 }
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:51
static char * argv0
Definition: pg_ctl.c:94
bool debug
Definition: pg_rewind.c:55
#define MAXCMDLEN
bool dry_run
Definition: pg_rewind.c:57
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void pg_fatal(const char *fmt,...)
Definition: logging.c:83
#define MAXPGPATH
int find_my_exec(const char *argv0, char *retpath)
Definition: exec.c:119
#define DEVNULL
Definition: port.h:123
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
static char * exec_path
Definition: pg_ctl.c:89
const char * progname
Definition: pg_rewind.c:47

◆ updateControlFile()

static void updateControlFile ( ControlFileData ControlFile)
static

Definition at line 664 of file pg_rewind.c.

References buffer, close_target_file(), COMP_CRC32C, ControlFileData::crc, FIN_CRC32C, INIT_CRC32C, offsetof, open_target_file(), PG_CONTROL_FILE_SIZE, PG_CONTROL_MAX_SAFE_SIZE, StaticAssertStmt, and write_target_range().

Referenced by main().

665 {
667 
668  /*
669  * For good luck, apply the same static assertions as in backend's
670  * WriteControlFile().
671  */
673  "pg_control is too large for atomic disk writes");
675  "sizeof(ControlFileData) exceeds PG_CONTROL_FILE_SIZE");
676 
677  /* Recalculate CRC of control file */
678  INIT_CRC32C(ControlFile->crc);
679  COMP_CRC32C(ControlFile->crc,
680  (char *) ControlFile,
681  offsetof(ControlFileData, crc));
682  FIN_CRC32C(ControlFile->crc);
683 
684  /*
685  * Write out PG_CONTROL_FILE_SIZE bytes into pg_control by zero-padding
686  * the excess over sizeof(ControlFileData), to avoid premature EOF related
687  * errors when reading it.
688  */
689  memset(buffer, 0, PG_CONTROL_FILE_SIZE);
690  memcpy(buffer, ControlFile, sizeof(ControlFileData));
691 
692  open_target_file("global/pg_control", false);
693 
695 
697 }
#define INIT_CRC32C(crc)
Definition: pg_crc32c.h:41
void open_target_file(const char *path, bool trunc)
Definition: file_ops.c:43
void write_target_range(char *buf, off_t begin, size_t size)
Definition: file_ops.c:84
#define PG_CONTROL_MAX_SAFE_SIZE
Definition: pg_control.h:240
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:795
pg_crc32c crc
Definition: pg_control.h:231
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
#define PG_CONTROL_FILE_SIZE
Definition: pg_control.h:249
void close_target_file(void)
Definition: file_ops.c:71
#define COMP_CRC32C(crc, data, len)
Definition: pg_crc32c.h:89
#define FIN_CRC32C(crc)
Definition: pg_crc32c.h:94
#define offsetof(type, field)
Definition: c.h:622

◆ usage()

static void usage ( const char *  progname)
static

Definition at line 64 of file pg_rewind.c.

References _.

Referenced by main().

65 {
66  printf(_("%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n\n"), progname);
67  printf(_("Usage:\n %s [OPTION]...\n\n"), progname);
68  printf(_("Options:\n"));
69  printf(_(" -D, --target-pgdata=DIRECTORY existing data directory to modify\n"));
70  printf(_(" --source-pgdata=DIRECTORY source data directory to synchronize with\n"));
71  printf(_(" --source-server=CONNSTR source server to synchronize with\n"));
72  printf(_(" -n, --dry-run stop before modifying anything\n"));
73  printf(_(" -P, --progress write progress messages\n"));
74  printf(_(" --debug write a lot of debug messages\n"));
75  printf(_(" -V, --version output version information, then exit\n"));
76  printf(_(" -?, --help show this help, then exit\n"));
77  printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
78 }
#define _(x)
Definition: elog.c:84
const char * progname
Definition: pg_rewind.c:47

Variable Documentation

◆ connstr_source

char* connstr_source = NULL

Definition at line 53 of file pg_rewind.c.

Referenced by main().

◆ ControlFile_source

ControlFileData ControlFile_source
static

Definition at line 45 of file pg_rewind.c.

◆ ControlFile_target

ControlFileData ControlFile_target
static

Definition at line 44 of file pg_rewind.c.

◆ datadir_source

char* datadir_source = NULL

◆ datadir_target

◆ debug

bool debug = false

Definition at line 55 of file pg_rewind.c.

Referenced by getTimelineHistory(), main(), and syncTargetDirectory().

◆ dry_run

◆ progname

const char* progname

Definition at line 47 of file pg_rewind.c.

Referenced by main(), and syncTargetDirectory().

◆ showprogress

bool showprogress = false

Definition at line 56 of file pg_rewind.c.

Referenced by main().

◆ targetHistory

TimeLineHistoryEntry* targetHistory

Definition at line 60 of file pg_rewind.c.

Referenced by SimpleXLogPageRead().

◆ targetNentries

int targetNentries

◆ WalSegSz

int WalSegSz

Definition at line 48 of file pg_rewind.c.

Referenced by createBackupLabel(), and digestControlFile().