aboutsummaryrefslogtreecommitdiff
path: root/src/bin/pg_rewind/pg_rewind.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/pg_rewind/pg_rewind.c')
-rw-r--r--src/bin/pg_rewind/pg_rewind.c87
1 files changed, 82 insertions, 5 deletions
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index bf2d2983e7e..101f0911bec 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -22,6 +22,7 @@
#include "common/file_perm.h"
#include "common/file_utils.h"
#include "common/restricted_token.h"
+#include "common/string.h"
#include "fe_utils/recovery_gen.h"
#include "fetch.h"
#include "file_ops.h"
@@ -38,6 +39,7 @@ static void createBackupLabel(XLogRecPtr startpoint, TimeLineID starttli,
static void digestControlFile(ControlFileData *ControlFile, char *source,
size_t size);
static void syncTargetDirectory(void);
+static void getRestoreCommand(const char *argv0);
static void sanityChecks(void);
static void findCommonAncestorTimeline(XLogRecPtr *recptr, int *tliIndex);
static void ensureCleanShutdown(const char *argv0);
@@ -53,11 +55,13 @@ int WalSegSz;
char *datadir_target = NULL;
char *datadir_source = NULL;
char *connstr_source = NULL;
+char *restore_command = NULL;
static bool debug = false;
bool showprogress = false;
bool dry_run = false;
bool do_sync = true;
+bool restore_wal = false;
/* Target history */
TimeLineHistoryEntry *targetHistory;
@@ -74,6 +78,8 @@ usage(const char *progname)
printf(_("%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n\n"), progname);
printf(_("Usage:\n %s [OPTION]...\n\n"), progname);
printf(_("Options:\n"));
+ printf(_(" -c, --restore-target-wal use restore_command in target config\n"
+ " to retrieve WAL files from archives\n"));
printf(_(" -D, --target-pgdata=DIRECTORY existing data directory to modify\n"));
printf(_(" --source-pgdata=DIRECTORY source data directory to synchronize with\n"));
printf(_(" --source-server=CONNSTR source server to synchronize with\n"));
@@ -103,6 +109,7 @@ main(int argc, char **argv)
{"source-server", required_argument, NULL, 2},
{"no-ensure-shutdown", no_argument, NULL, 4},
{"version", no_argument, NULL, 'V'},
+ {"restore-target-wal", no_argument, NULL, 'c'},
{"dry-run", no_argument, NULL, 'n'},
{"no-sync", no_argument, NULL, 'N'},
{"progress", no_argument, NULL, 'P'},
@@ -144,7 +151,7 @@ main(int argc, char **argv)
}
}
- while ((c = getopt_long(argc, argv, "D:nNPR", long_options, &option_index)) != -1)
+ while ((c = getopt_long(argc, argv, "cD:nNPR", long_options, &option_index)) != -1)
{
switch (c)
{
@@ -152,6 +159,10 @@ main(int argc, char **argv)
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(1);
+ case 'c':
+ restore_wal = true;
+ break;
+
case 'P':
showprogress = true;
break;
@@ -255,6 +266,8 @@ main(int argc, char **argv)
umask(pg_mode_mask);
+ getRestoreCommand(argv[0]);
+
atexit(disconnect_atexit);
/* Connect to remote server */
@@ -350,9 +363,8 @@ main(int argc, char **argv)
exit(0);
}
- findLastCheckpoint(datadir_target, divergerec,
- lastcommontliIndex,
- &chkptrec, &chkpttli, &chkptredo);
+ findLastCheckpoint(datadir_target, divergerec, lastcommontliIndex,
+ &chkptrec, &chkpttli, &chkptredo, restore_command);
pg_log_info("rewinding from last common checkpoint at %X/%X on timeline %u",
(uint32) (chkptrec >> 32), (uint32) chkptrec,
chkpttli);
@@ -378,7 +390,7 @@ main(int argc, char **argv)
if (showprogress)
pg_log_info("reading WAL in target");
extractPageMap(datadir_target, chkptrec, lastcommontliIndex,
- ControlFile_target.checkPoint);
+ ControlFile_target.checkPoint, restore_command);
filemap_finalize();
if (showprogress)
@@ -805,6 +817,71 @@ syncTargetDirectory(void)
}
/*
+ * Get value of GUC parameter restore_command from the target cluster.
+ *
+ * This uses a logic based on "postgres -C" to get the value from the
+ * cluster.
+ */
+static void
+getRestoreCommand(const char *argv0)
+{
+ int rc;
+ char postgres_exec_path[MAXPGPATH],
+ postgres_cmd[MAXPGPATH],
+ cmd_output[MAXPGPATH];
+
+ if (!restore_wal)
+ return;
+
+ /* find postgres executable */
+ rc = find_other_exec(argv0, "postgres",
+ PG_BACKEND_VERSIONSTR,
+ postgres_exec_path);
+
+ if (rc < 0)
+ {
+ char full_path[MAXPGPATH];
+
+ if (find_my_exec(argv0, full_path) < 0)
+ strlcpy(full_path, progname, sizeof(full_path));
+
+ if (rc == -1)
+ pg_log_error("The program \"postgres\" is needed by %s but was not found in the\n"
+ "same directory as \"%s\".\n"
+ "Check your installation.",
+ progname, full_path);
+ else
+ pg_log_error("The program \"postgres\" was found by \"%s\"\n"
+ "but was not the same version as %s.\n"
+ "Check your installation.",
+ full_path, progname);
+ exit(1);
+ }
+
+ /*
+ * Build a command able to retrieve the value of GUC parameter
+ * restore_command, if set.
+ */
+ snprintf(postgres_cmd, sizeof(postgres_cmd),
+ "\"%s\" -D \"%s\" -C restore_command",
+ postgres_exec_path, datadir_target);
+
+ if (!pipe_read_line(postgres_cmd, cmd_output, sizeof(cmd_output)))
+ exit(1);
+
+ (void) pg_strip_crlf(cmd_output);
+
+ if (strcmp(cmd_output, "") == 0)
+ pg_fatal("restore_command is not set on the target cluster");
+
+ restore_command = pg_strdup(cmd_output);
+
+ pg_log_debug("using for rewind restore_command = \'%s\'",
+ restore_command);
+}
+
+
+/*
* Ensure clean shutdown of target instance by launching single-user mode
* postgres to do crash recovery.
*/