45 const char *content,
size_t size);
92 printf(
_(
"%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n\n"),
progname);
95 printf(
_(
" -c, --restore-target-wal use restore_command in target configuration to\n"
96 " retrieve WAL files from archives\n"));
97 printf(
_(
" -D, --target-pgdata=DIRECTORY existing data directory to modify\n"));
98 printf(
_(
" --source-pgdata=DIRECTORY source data directory to synchronize with\n"));
99 printf(
_(
" --source-server=CONNSTR source server to synchronize with\n"));
100 printf(
_(
" -n, --dry-run stop before modifying anything\n"));
101 printf(
_(
" -N, --no-sync do not wait for changes to be written\n"
102 " safely to disk\n"));
103 printf(
_(
" -P, --progress write progress messages\n"));
104 printf(
_(
" -R, --write-recovery-conf write configuration for replication\n"
105 " (requires --source-server)\n"));
106 printf(
_(
" --config-file=FILENAME use specified main server configuration\n"
107 " file when running target cluster\n"));
108 printf(
_(
" --debug write a lot of debug messages\n"));
109 printf(
_(
" --no-ensure-shutdown do not automatically fix unclean shutdown\n"));
110 printf(
_(
" -V, --version output version information, then exit\n"));
111 printf(
_(
" -?, --help show this help, then exit\n"));
112 printf(
_(
"\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
113 printf(
_(
"%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
120 static struct option long_options[] = {
139 int lastcommontliIndex;
148 bool no_ensure_shutdown =
false;
160 if (strcmp(argv[1],
"--help") == 0 || strcmp(argv[1],
"-?") == 0)
165 if (strcmp(argv[1],
"--version") == 0 || strcmp(argv[1],
"-V") == 0)
167 puts(
"pg_rewind (PostgreSQL) " PG_VERSION);
172 while ((
c =
getopt_long(argc, argv,
"cD:nNPR", long_options, &option_index)) != -1)
214 no_ensure_shutdown =
true;
230 pg_log_error(
"no source specified (--source-pgdata or --source-server)");
237 pg_log_error(
"only one of --source-pgdata or --source-server can be specified");
244 pg_log_error(
"no target data directory specified (--target-pgdata)");
251 pg_log_error(
"no source server information (--source-server) specified for --write-recovery-conf");
258 pg_log_error(
"too many command-line arguments (first is \"%s\")",
284 pg_fatal(
"could not read permissions of directory \"%s\": %m",
326 if (!no_ensure_shutdown &&
364 if (target_tli == source_tli)
366 pg_log_info(
"source and target cluster are on the same timeline");
367 rewind_needed =
false;
368 target_wal_endrec = 0;
385 &divergerec, &lastcommontliIndex);
387 pg_log_info(
"servers diverged at WAL location %X/%X on timeline %u",
395 pfree(sourceHistory);
419 target_wal_endrec = chkptendrec;
427 if (target_wal_endrec > divergerec)
429 rewind_needed =
true;
434 Assert(target_wal_endrec == divergerec);
436 rewind_needed =
false;
451 pg_log_info(
"rewinding from last common checkpoint at %X/%X on timeline %u",
495 pg_log_info(
"need to copy %lu MB (total source directory size is %lu MB)",
496 (
unsigned long) (filemap->
fetch_size / (1024 * 1024)),
497 (
unsigned long) (filemap->
total_size / (1024 * 1024)));
574 offset = blkno * BLCKSZ;
609 pg_fatal(
"no action decided for file \"%s\"", entry->
path);
641 pg_fatal(
"source system was modified while pg_rewind was running");
645 pg_log_info(
"creating backup label and updating control file");
695 pg_fatal(
"source system was in unexpected state at end of rewind");
727 pg_fatal(
"source and target clusters are from different systems");
735 pg_fatal(
"clusters are not compatible with this version of pg_rewind");
745 pg_fatal(
"target server needs to use either data checksums or \"wal_log_hints = on\"");
756 pg_fatal(
"target server must be shut down cleanly");
766 pg_fatal(
"source data directory must be shut down cleanly");
783 char fetch_done_str[32];
784 char fetch_size_str[32];
813 fprintf(stderr,
_(
"%*s/%s kB (%d%%) copied"),
814 (
int) strlen(fetch_size_str), fetch_done_str, fetch_size_str,
821 fputc((!finished && isatty(fileno(stderr))) ?
'\r' :
'\n', stderr);
924 n =
Min(a_nentries, b_nentries);
925 for (
i = 0;
i < n;
i++)
927 if (a_history[
i].tli != b_history[
i].tli ||
928 a_history[
i].begin != b_history[
i].begin)
941 pg_fatal(
"could not find common ancestor of the source and target cluster's timelines");
967 stamp_time = time(NULL);
968 tmp = localtime(&stamp_time);
969 strftime(strfbuf,
sizeof(strfbuf),
"%Y-%m-%d %H:%M:%S %Z", tmp);
972 "START WAL LOCATION: %X/%X (file %s)\n"
973 "CHECKPOINT LOCATION: %X/%X\n"
974 "BACKUP METHOD: pg_rewind\n"
975 "BACKUP FROM: standby\n"
982 pg_fatal(
"backup label buffer too small");
1005 pg_fatal(
"unexpected control file CRC");
1017 pg_fatal(
"unexpected control file size %d, expected %d",
1026 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",
1027 "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes",
1055 postgres_exec_path);
1065 pg_fatal(
"program \"%s\" is needed by %s but was not found in the same directory as \"%s\"",
1068 pg_fatal(
"program \"%s\" was found by \"%s\" but was not the same version as %s",
1100 if (strcmp(cmd_output,
"") == 0)
1101 pg_fatal(
"restore_command is not set in the target cluster");
1105 pg_log_debug(
"using for rewind restore_command = \'%s\'",
1120 #define MAXCMDLEN (2 * MAXPGPATH)
1135 pg_fatal(
"program \"%s\" is needed by %s but was not found in the same directory as \"%s\"",
1138 pg_fatal(
"program \"%s\" was found by \"%s\" but was not the same version as %s",
1142 pg_log_info(
"executing \"%s\" for target server to complete crash recovery",
1178 if (system(postgres_cmd->
data) != 0)
1180 pg_log_error(
"postgres single-user mode in target cluster failed");
Datum now(PG_FUNCTION_ARGS)
#define PG_DATA_CHECKSUM_VERSION
#define ngettext(s, p, n)
#define PG_TEXTDOMAIN(domain)
#define CATALOG_VERSION_NO
int find_my_exec(const char *argv0, char *retpath)
char * pipe_read_line(char *cmd, char *line, int maxsize)
void set_pglocale_pgservice(const char *argv0, const char *app)
int find_other_exec(const char *argv0, const char *target, const char *versionstr, char *retpath)
void update_controlfile(const char *DataDir, ControlFileData *ControlFile, bool do_sync)
bool datapagemap_next(datapagemap_iterator_t *iter, BlockNumber *blkno)
datapagemap_iterator_t * datapagemap_iterate(datapagemap_t *map)
char * PQerrorMessage(const PGconn *conn)
ConnStatusType PQstatus(const PGconn *conn)
void PQfinish(PGconn *conn)
PGconn * PQconnectdb(const char *conninfo)
char * pg_strdup(const char *in)
void * pg_malloc(size_t size)
void traverse_datadir(const char *datadir, process_file_callback_t callback)
char * slurpFile(const char *datadir, const char *path, size_t *filesize)
void close_target_file(void)
void truncate_target_file(const char *path, off_t newsize)
void remove_target(file_entry_t *entry)
void sync_target_dir(void)
void create_target(file_entry_t *entry)
void open_target_file(const char *path, bool trunc)
void write_target_range(char *buf, off_t begin, size_t size)
bool GetDataDirectoryCreatePerm(const char *dataDir)
void process_source_file(const char *path, file_type_t type, size_t size, const char *link_target)
void print_filemap(filemap_t *filemap)
void process_target_file(const char *path, file_type_t type, size_t size, const char *link_target)
filemap_t * decide_file_actions(void)
void calculate_totals(filemap_t *filemap)
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
#define required_argument
static void const char fflush(stdout)
Assert(fmt[strlen(fmt) - 1] !='\n')
rewind_source * init_libpq_source(PGconn *conn)
rewind_source * init_local_source(const char *datadir)
void pg_logging_increase_verbosity(void)
void pg_logging_init(const char *argv0)
#define pg_log_error(...)
#define pg_log_error_hint(...)
#define pg_log_error_detail(...)
#define pg_log_debug(...)
void pfree(void *pointer)
void extractPageMap(const char *datadir, XLogRecPtr startpoint, int tliIndex, XLogRecPtr endpoint, const char *restoreCommand)
void findLastCheckpoint(const char *datadir, XLogRecPtr forkptr, int tliIndex, XLogRecPtr *lastchkptrec, TimeLineID *lastchkpttli, XLogRecPtr *lastchkptredo, const char *restoreCommand)
XLogRecPtr readOneRecord(const char *datadir, XLogRecPtr ptr, int tliIndex, const char *restoreCommand)
static pg_time_t last_progress_report
static bool writerecoveryconf
#define PG_CONTROL_VERSION
@ DB_SHUTDOWNED_IN_RECOVERY
#define PG_CONTROL_FILE_SIZE
#define COMP_CRC32C(crc, data, len)
#define EQ_CRC32C(c1, c2)
PGDLLIMPORT char * optarg
static ControlFileData ControlFile_source
static void createBackupLabel(XLogRecPtr startpoint, TimeLineID starttli, XLogRecPtr checkpointloc)
static void usage(const char *progname)
static void sanityChecks(void)
static void findCommonAncestorTimeline(TimeLineHistoryEntry *a_history, int a_nentries, TimeLineHistoryEntry *b_history, int b_nentries, XLogRecPtr *recptr, int *tliIndex)
static ControlFileData ControlFile_source_after
int main(int argc, char **argv)
static XLogRecPtr MinXLogRecPtr(XLogRecPtr a, XLogRecPtr b)
static void ensureCleanShutdown(const char *argv0)
TimeLineHistoryEntry * targetHistory
static rewind_source * source
static ControlFileData ControlFile_target
void progress_report(bool finished)
static TimeLineHistoryEntry * getTimelineHistory(TimeLineID tli, bool is_source, int *nentries)
static void digestControlFile(ControlFileData *ControlFile, const char *content, size_t size)
static void checkControlFile(ControlFileData *ControlFile)
static void getRestoreCommand(const char *argv0)
static void perform_rewind(filemap_t *filemap, rewind_source *source, XLogRecPtr chkptrec, TimeLineID chkpttli, XLogRecPtr chkptredo)
static void disconnect_atexit(void)
TimeLineHistoryEntry * rewind_parseTimeLineHistory(char *buffer, TimeLineID targetTLI, int *nentries)
const char * get_progname(const char *argv0)
#define PG_BACKEND_VERSIONSTR
size_t strlcpy(char *dst, const char *src, size_t siz)
PQExpBuffer createPQExpBuffer(void)
void destroyPQExpBuffer(PQExpBuffer str)
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
void WriteRecoveryConfig(PGconn *pgconn, char *target_dir, PQExpBuffer contents)
PQExpBuffer GenerateRecoveryConfig(PGconn *pgconn, char *replication_slot)
void get_restricted_token(void)
int pg_strip_crlf(char *str)
void appendShellString(PQExpBuffer buf, const char *str)
TimeLineID ThisTimeLineID
uint32 pg_control_version
CheckPoint checkPointCopy
XLogRecPtr minRecoveryPoint
uint32 data_checksum_version
uint32 catalog_version_no
TimeLineID minRecoveryPointTLI
datapagemap_t target_pages_to_overwrite
file_entry_t * entries[FLEXIBLE_ARRAY_MEMBER]
void(* queue_fetch_file)(struct rewind_source *, const char *path, size_t len)
void(* traverse_files)(struct rewind_source *, process_file_callback_t callback)
void(* finish_fetch)(struct rewind_source *)
XLogRecPtr(* get_current_wal_insert_lsn)(struct rewind_source *)
void(* queue_fetch_range)(struct rewind_source *, const char *path, off_t offset, size_t len)
char *(* fetch_file)(struct rewind_source *, const char *path, size_t *filesize)
void(* destroy)(struct rewind_source *)
static ControlFileData * ControlFile
#define IsValidWalSegSize(size)
#define XLByteToSeg(xlrp, logSegNo, wal_segsz_bytes)
static void XLogFileName(char *fname, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes)
static void TLHistoryFilePath(char *path, TimeLineID tli)
#define LSN_FORMAT_ARGS(lsn)
#define XLogRecPtrIsInvalid(r)
#define InvalidXLogRecPtr