PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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/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
 
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

#define MAXCMDLEN   (2 * MAXPGPATH)

Referenced by syncTargetDirectory().

Function Documentation

static void checkControlFile ( ControlFileData ControlFile)
static

Definition at line 608 of file pg_rewind.c.

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

Referenced by digestControlFile().

609 {
610  pg_crc32c crc;
611 
612  /* Calculate CRC */
613  INIT_CRC32C(crc);
614  COMP_CRC32C(crc, (char *) ControlFile, offsetof(ControlFileData, crc));
615  FIN_CRC32C(crc);
616 
617  /* And simply compare it */
618  if (!EQ_CRC32C(crc, ControlFile->crc))
619  pg_fatal("unexpected control file CRC\n");
620 }
#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
pg_crc32c crc
Definition: pg_control.h:226
#define EQ_CRC32C(c1, c2)
Definition: pg_crc32c.h:42
#define COMP_CRC32C(crc, data, len)
Definition: pg_crc32c.h:73
#define FIN_CRC32C(crc)
Definition: pg_crc32c.h:78
#define offsetof(type, field)
Definition: c.h:551
static void createBackupLabel ( XLogRecPtr  startpoint,
TimeLineID  starttli,
XLogRecPtr  checkpointloc 
)
static

Definition at line 565 of file pg_rewind.c.

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

Referenced by main().

566 {
567  XLogSegNo startsegno;
568  time_t stamp_time;
569  char strfbuf[128];
570  char xlogfilename[MAXFNAMELEN];
571  struct tm *tmp;
572  char buf[1000];
573  int len;
574 
575  XLByteToSeg(startpoint, startsegno);
576  XLogFileName(xlogfilename, starttli, startsegno);
577 
578  /*
579  * Construct backup label file
580  */
581  stamp_time = time(NULL);
582  tmp = localtime(&stamp_time);
583  strftime(strfbuf, sizeof(strfbuf), "%Y-%m-%d %H:%M:%S %Z", tmp);
584 
585  len = snprintf(buf, sizeof(buf),
586  "START WAL LOCATION: %X/%X (file %s)\n"
587  "CHECKPOINT LOCATION: %X/%X\n"
588  "BACKUP METHOD: pg_rewind\n"
589  "BACKUP FROM: standby\n"
590  "START TIME: %s\n",
591  /* omit LABEL: line */
592  (uint32) (startpoint >> 32), (uint32) startpoint, xlogfilename,
593  (uint32) (checkpointloc >> 32), (uint32) checkpointloc,
594  strfbuf);
595  if (len >= sizeof(buf))
596  pg_fatal("backup label buffer too small\n"); /* shouldn't happen */
597 
598  /* TODO: move old file out of the way, if any. */
599  open_target_file("backup_label", true); /* BACKUP_LABEL_FILE */
600  write_target_range(buf, 0, len);
602 }
void open_target_file(const char *path, bool trunc)
Definition: file_ops.c:44
void write_target_range(char *buf, off_t begin, size_t size)
Definition: file_ops.c:85
#define XLogFileName(fname, tli, logSegNo)
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:103
static char * buf
Definition: pg_test_fsync.c:65
uint64 XLogSegNo
Definition: xlogdefs.h:34
unsigned int uint32
Definition: c.h:265
#define MAXFNAMELEN
#define XLByteToSeg(xlrp, logSegNo)
#define NULL
Definition: c.h:226
void close_target_file(void)
Definition: file_ops.c:72
static void digestControlFile ( ControlFileData ControlFile,
char *  source,
size_t  size 
)
static

Definition at line 626 of file pg_rewind.c.

References checkControlFile(), PG_CONTROL_SIZE, and pg_fatal().

Referenced by main().

627 {
628  if (size != PG_CONTROL_SIZE)
629  pg_fatal("unexpected control file size %d, expected %d\n",
630  (int) size, PG_CONTROL_SIZE);
631 
632  memcpy(ControlFile, src, sizeof(ControlFileData));
633 
634  /* Additional checks on control file */
635  checkControlFile(ControlFile);
636 }
#define PG_CONTROL_SIZE
Definition: pg_control.h:236
void pg_fatal(const char *fmt,...)
Definition: logging.c:83
static void checkControlFile(ControlFileData *ControlFile)
Definition: pg_rewind.c:608
static void findCommonAncestorTimeline ( XLogRecPtr recptr,
int *  tliIndex 
)
static

Definition at line 517 of file pg_rewind.c.

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

Referenced by main().

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

Definition at line 438 of file pg_rewind.c.

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

Referenced by findCommonAncestorTimeline().

439 {
440  TimeLineHistoryEntry *history;
441  TimeLineID tli;
442 
443  tli = controlFile->checkPointCopy.ThisTimeLineID;
444 
445  /*
446  * Timeline 1 does not have a history file, so there is no need to check
447  * and fake an entry with infinite start and end positions.
448  */
449  if (tli == 1)
450  {
451  history = (TimeLineHistoryEntry *) pg_malloc(sizeof(TimeLineHistoryEntry));
452  history->tli = tli;
453  history->begin = history->end = InvalidXLogRecPtr;
454  *nentries = 1;
455  }
456  else
457  {
458  char path[MAXPGPATH];
459  char *histfile;
460 
461  TLHistoryFilePath(path, tli);
462 
463  /* Get history file from appropriate source */
464  if (controlFile == &ControlFile_source)
465  histfile = fetchFile(path, NULL);
466  else if (controlFile == &ControlFile_target)
467  histfile = slurpFile(datadir_target, path, NULL);
468  else
469  pg_fatal("invalid control file");
470 
471  history = rewind_parseTimeLineHistory(histfile, tli, nentries);
472  pg_free(histfile);
473  }
474 
475  if (debug)
476  {
477  int i;
478 
479  if (controlFile == &ControlFile_source)
480  pg_log(PG_DEBUG, "Source timeline history:\n");
481  else if (controlFile == &ControlFile_target)
482  pg_log(PG_DEBUG, "Target timeline history:\n");
483  else
484  Assert(false);
485 
486  /*
487  * Print the target timeline history.
488  */
489  for (i = 0; i < targetNentries; i++)
490  {
491  TimeLineHistoryEntry *entry;
492 
493  entry = &history[i];
495  /* translator: %d is a timeline number, others are LSN positions */
496  "%d: %X/%X - %X/%X\n", entry->tli,
497  (uint32) (entry->begin >> 32), (uint32) (entry->begin),
498  (uint32) (entry->end >> 32), (uint32) (entry->end));
499  }
500  }
501 
502  return history;
503 }
char * datadir_target
Definition: pg_rewind.c:49
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
uint32 TimeLineID
Definition: xlogdefs.h:45
bool debug
Definition: pg_rewind.c:53
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:133
char * fetchFile(char *filename, size_t *filesize)
Definition: fetch.c:55
#define MAXPGPATH
unsigned int uint32
Definition: c.h:265
void pg_log(eLogType type, const char *fmt,...)
Definition: logging.c:69
int targetNentries
Definition: pg_rewind.c:59
#define NULL
Definition: c.h:226
XLogRecPtr end
Definition: timeline.h:29
#define Assert(condition)
Definition: c.h:671
void pg_free(void *ptr)
Definition: fe_memutils.c:105
TimeLineID ThisTimeLineID
Definition: pg_control.h:35
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:43
static ControlFileData ControlFile_source
Definition: pg_rewind.c:44
char * slurpFile(const char *datadir, const char *path, size_t *filesize)
Definition: file_ops.c:277
#define TLHistoryFilePath(path, tli)
int main ( int  argc,
char **  argv 
)

Definition at line 80 of file pg_rewind.c.

References _, 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(), getopt_long(), libpqConnect(), libpqGetCurrentXlogInsertLocation(), ControlFileData::minRecoveryPoint, ControlFileData::minRecoveryPointTLI, no_argument, NULL, optarg, optind, pg_free(), pg_log(), 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, syncTargetDirectory(), targetNentries, CheckPoint::ThisTimeLineID, filemap_t::total_size, traverse_datadir(), updateControlFile(), and usage().

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

Definition at line 423 of file pg_rewind.c.

References Min, and XLogRecPtrIsInvalid.

Referenced by findCommonAncestorTimeline().

424 {
425  if (XLogRecPtrIsInvalid(a))
426  return b;
427  else if (XLogRecPtrIsInvalid(b))
428  return a;
429  else
430  return Min(a, b);
431 }
#define Min(x, y)
Definition: c.h:802
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
static void sanityChecks ( void  )
static

Definition at line 369 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().

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

Definition at line 678 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().

679 {
680  int ret;
681 #define MAXCMDLEN (2 * MAXPGPATH)
682  char exec_path[MAXPGPATH];
683  char cmd[MAXCMDLEN];
684 
685  /* locate initdb binary */
686  if ((ret = find_other_exec(argv0, "initdb",
687  "initdb (PostgreSQL) " PG_VERSION "\n",
688  exec_path)) < 0)
689  {
690  char full_path[MAXPGPATH];
691 
692  if (find_my_exec(argv0, full_path) < 0)
693  strlcpy(full_path, progname, sizeof(full_path));
694 
695  if (ret == -1)
696  pg_fatal("The program \"initdb\" is needed by %s but was\n"
697  "not found in the same directory as \"%s\".\n"
698  "Check your installation.\n", progname, full_path);
699  else
700  pg_fatal("The program \"initdb\" was found by \"%s\"\n"
701  "but was not the same version as %s.\n"
702  "Check your installation.\n", full_path, progname);
703  }
704 
705  /* only skip processing after ensuring presence of initdb */
706  if (dry_run)
707  return;
708 
709  /* finally run initdb -S */
710  if (debug)
711  snprintf(cmd, MAXCMDLEN, "\"%s\" -D \"%s\" -S",
712  exec_path, datadir_target);
713  else
714  snprintf(cmd, MAXCMDLEN, "\"%s\" -D \"%s\" -S > \"%s\"",
715  exec_path, datadir_target, DEVNULL);
716 
717  if (system(cmd) != 0)
718  pg_fatal("sync of target directory failed\n");
719 }
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:49
static char * argv0
Definition: pg_ctl.c:92
bool debug
Definition: pg_rewind.c:53
#define MAXCMDLEN
bool dry_run
Definition: pg_rewind.c:55
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:116
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
static char * exec_path
Definition: pg_ctl.c:87
const char * progname
Definition: pg_rewind.c:46
static void updateControlFile ( ControlFileData ControlFile)
static

Definition at line 642 of file pg_rewind.c.

References close_target_file(), COMP_CRC32C, ControlFileData::crc, FIN_CRC32C, INIT_CRC32C, offsetof, open_target_file(), PG_CONTROL_SIZE, and write_target_range().

Referenced by main().

643 {
644  char buffer[PG_CONTROL_SIZE];
645 
646  /* Recalculate CRC of control file */
647  INIT_CRC32C(ControlFile->crc);
648  COMP_CRC32C(ControlFile->crc,
649  (char *) ControlFile,
650  offsetof(ControlFileData, crc));
651  FIN_CRC32C(ControlFile->crc);
652 
653  /*
654  * Write out PG_CONTROL_SIZE bytes into pg_control by zero-padding the
655  * excess over sizeof(ControlFileData) to avoid premature EOF related
656  * errors when reading it.
657  */
658  memset(buffer, 0, PG_CONTROL_SIZE);
659  memcpy(buffer, ControlFile, sizeof(ControlFileData));
660 
661  open_target_file("global/pg_control", false);
662 
664 
666 }
#define INIT_CRC32C(crc)
Definition: pg_crc32c.h:41
void open_target_file(const char *path, bool trunc)
Definition: file_ops.c:44
void write_target_range(char *buf, off_t begin, size_t size)
Definition: file_ops.c:85
#define PG_CONTROL_SIZE
Definition: pg_control.h:236
pg_crc32c crc
Definition: pg_control.h:226
void close_target_file(void)
Definition: file_ops.c:72
#define COMP_CRC32C(crc, data, len)
Definition: pg_crc32c.h:73
#define FIN_CRC32C(crc)
Definition: pg_crc32c.h:78
#define offsetof(type, field)
Definition: c.h:551
static void usage ( const char *  progname)
static

Definition at line 62 of file pg_rewind.c.

References _.

Referenced by main().

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

Variable Documentation

char* connstr_source = NULL

Definition at line 51 of file pg_rewind.c.

Referenced by main().

ControlFileData ControlFile_source
static

Definition at line 44 of file pg_rewind.c.

ControlFileData ControlFile_target
static

Definition at line 43 of file pg_rewind.c.

char* datadir_source = NULL
bool debug = false

Definition at line 53 of file pg_rewind.c.

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

const char* progname

Definition at line 46 of file pg_rewind.c.

Referenced by main(), and syncTargetDirectory().

bool showprogress = false

Definition at line 54 of file pg_rewind.c.

Referenced by main().

TimeLineHistoryEntry* targetHistory

Definition at line 58 of file pg_rewind.c.

Referenced by SimpleXLogPageRead().

int targetNentries