0001-Auto-generate-recovery-conf-at-the-end-of-pg_re.patch
application/octet-stream
Filename: 0001-Auto-generate-recovery-conf-at-the-end-of-pg_re.patch
Type: application/octet-stream
Part: 1
Patch
Format: format-patch
Series: patch 0001
Subject: Auto generate recovery conf at the end of pg_rewind
| File | + | − |
|---|---|---|
| src/bin/pg_rewind/fetch.h | 3 | 0 |
| src/bin/pg_rewind/libpq_fetch.c | 138 | 0 |
| src/bin/pg_rewind/Makefile | 1 | 1 |
| src/bin/pg_rewind/pg_rewind.c | 22 | 1 |
| src/bin/pg_rewind/pg_rewind.h | 2 | 0 |
From abb1068b10a5f558623d6fc8f214c29d09f6bb28 Mon Sep 17 00:00:00 2001
From: Jimmy Yih <jyih@pivotal.io>
Date: Sun, 4 Nov 2018 22:54:53 -0800
Subject: [PATCH] Auto generate recovery conf at the end of pg_rewind
---
src/bin/pg_rewind/Makefile | 2 +-
src/bin/pg_rewind/fetch.h | 3 +
src/bin/pg_rewind/libpq_fetch.c | 138 ++++++++++++++++++++++++++++++++
src/bin/pg_rewind/pg_rewind.c | 23 +++++-
src/bin/pg_rewind/pg_rewind.h | 2 +
6 files changed, 166 insertions(+), 3 deletions(-)
diff --git a/src/bin/pg_rewind/Makefile b/src/bin/pg_rewind/Makefile
index 04f3b8f520..3b7f1ce177 100644
--- a/src/bin/pg_rewind/Makefile
+++ b/src/bin/pg_rewind/Makefile
@@ -16,7 +16,7 @@ top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
override CPPFLAGS := -I$(libpq_srcdir) -DFRONTEND $(CPPFLAGS)
-LDFLAGS_INTERNAL += $(libpq_pgport)
+LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport)
OBJS = pg_rewind.o parsexlog.o xlogreader.o datapagemap.o timeline.o \
fetch.o file_ops.o copy_fetch.o libpq_fetch.o filemap.o logging.o \
diff --git a/src/bin/pg_rewind/fetch.h b/src/bin/pg_rewind/fetch.h
index a694e8b157..7db9337ced 100644
--- a/src/bin/pg_rewind/fetch.h
+++ b/src/bin/pg_rewind/fetch.h
@@ -41,4 +41,7 @@ extern void copy_executeFileMap(filemap_t *map);
typedef void (*process_file_callback_t) (const char *path, file_type_t type, size_t size, const char *link_target);
extern void traverse_datadir(const char *datadir, process_file_callback_t callback);
+extern void GenerateRecoveryConf(void);
+extern void WriteRecoveryConf(void);
+
#endif /* FETCH_H */
diff --git a/src/bin/pg_rewind/libpq_fetch.c b/src/bin/pg_rewind/libpq_fetch.c
index d06e277432..47a3f68c93 100644
--- a/src/bin/pg_rewind/libpq_fetch.c
+++ b/src/bin/pg_rewind/libpq_fetch.c
@@ -24,10 +24,15 @@
#include "libpq-fe.h"
#include "catalog/pg_type_d.h"
#include "fe_utils/connect.h"
+#include "fe_utils/string_utils.h"
#include "port/pg_bswap.h"
+#include "pqexpbuffer.h"
static PGconn *conn = NULL;
+/* Contents of configuration to be generated */
+static PQExpBuffer recoveryconfcontents = NULL;
+
/*
* Files are fetched max CHUNKSIZE bytes at a time.
*
@@ -526,3 +531,136 @@ execute_pagemap(datapagemap_t *pagemap, const char *path)
}
pg_free(iter);
}
+
+/*
+ * Escape a string so that it can be used as a value in a key-value pair
+ * a configuration file.
+ */
+static char *
+escape_quotes(const char *src)
+{
+ char *result = escape_single_quotes_ascii(src);
+
+ if (!result)
+ {
+ fprintf(stderr, _("%s: out of memory\n"), progname);
+ exit(1);
+ }
+ return result;
+}
+
+/*
+ * Create a configuration file in memory using a PQExpBuffer
+ */
+void
+GenerateRecoveryConf(void)
+{
+ PQconninfoOption *connOptions;
+ PQconninfoOption *option;
+ PQExpBufferData conninfo_buf;
+ char *escaped;
+
+ recoveryconfcontents = createPQExpBuffer();
+ if (!recoveryconfcontents)
+ {
+ fprintf(stderr, _("%s: out of memory\n"), progname);
+ exit(1);
+ }
+
+ connOptions = PQconninfo(conn);
+ if (connOptions == NULL)
+ {
+ fprintf(stderr, _("%s: out of memory\n"), progname);
+ exit(1);
+ }
+
+ initPQExpBuffer(&conninfo_buf);
+ for (option = connOptions; option && option->keyword; option++)
+ {
+ /*
+ * Do not emit this setting if: - the setting is "replication",
+ * "dbname" or "fallback_application_name", since these would be
+ * overridden by the libpqwalreceiver module anyway. - not set or
+ * empty.
+ */
+ if (strcmp(option->keyword, "replication") == 0 ||
+ strcmp(option->keyword, "dbname") == 0 ||
+ strcmp(option->keyword, "fallback_application_name") == 0 ||
+ (option->val == NULL) ||
+ (option->val != NULL && option->val[0] == '\0'))
+ continue;
+
+ /* Separate key-value pairs with spaces */
+ if (conninfo_buf.len != 0)
+ appendPQExpBufferChar(&conninfo_buf, ' ');
+
+ /*
+ * Write "keyword=value" pieces, the value string is escaped and/or
+ * quoted if necessary.
+ */
+ appendPQExpBuffer(&conninfo_buf, "%s=", option->keyword);
+ appendConnStrVal(&conninfo_buf, option->val);
+ }
+
+ /*
+ * Escape the connection string, so that it can be put in the config file.
+ * Note that this is different from the escaping of individual connection
+ * options above!
+ */
+ escaped = escape_quotes(conninfo_buf.data);
+ appendPQExpBuffer(recoveryconfcontents, "primary_conninfo = '%s'\n", escaped);
+ free(escaped);
+
+ if (PQExpBufferBroken(recoveryconfcontents) ||
+ PQExpBufferDataBroken(conninfo_buf))
+ {
+ fprintf(stderr, _("%s: out of memory\n"), progname);
+ exit(1);
+ }
+
+ termPQExpBuffer(&conninfo_buf);
+
+ PQconninfoFree(connOptions);
+}
+
+
+/*
+ * Write the configuration file into the directory specified in datadir_target,
+ * with the contents already collected in memory.
+ * Then write the signal file into the datadir_target also.
+ */
+void
+WriteRecoveryConf(void)
+{
+ char filename[MAXPGPATH];
+ FILE *cf;
+
+ snprintf(filename, MAXPGPATH, "%s/%s", datadir_target, "postgresql.auto.conf");
+
+ cf = fopen(filename, "a");
+ if (cf == NULL)
+ {
+ fprintf(stderr, _("%s: could not open file \"%s\": %s\n"), progname, filename, strerror(errno));
+ exit(1);
+ }
+
+ if (fwrite(recoveryconfcontents->data, recoveryconfcontents->len, 1, cf) != 1)
+ {
+ fprintf(stderr,
+ _("%s: could not write to file \"%s\": %s\n"),
+ progname, filename, strerror(errno));
+ exit(1);
+ }
+
+ fclose(cf);
+
+ snprintf(filename, MAXPGPATH, "%s/%s", datadir_target, "standby.signal");
+ cf = fopen(filename, "w");
+ if (cf == NULL)
+ {
+ fprintf(stderr, _("%s: could not create file \"%s\": %s\n"), progname, filename, strerror(errno));
+ exit(1);
+ }
+
+ fclose(cf);
+}
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index aa753bb315..b6b288bbfe 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -45,6 +45,8 @@ static void findCommonAncestorTimeline(XLogRecPtr *recptr, int *tliIndex);
static ControlFileData ControlFile_target;
static ControlFileData ControlFile_source;
+static bool writerecoveryconf = false;
+
const char *progname;
int WalSegSz;
@@ -71,6 +73,7 @@ usage(const char *progname)
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"));
+ printf(_(" -R, --write-recovery-conf write configuration for replication\n"));
printf(_(" -n, --dry-run stop before modifying anything\n"));
printf(_(" -N, --no-sync do not wait for changes to be written\n"));
printf(_(" safely to disk\n"));
@@ -88,6 +91,7 @@ main(int argc, char **argv)
static struct option long_options[] = {
{"help", no_argument, NULL, '?'},
{"target-pgdata", required_argument, NULL, 'D'},
+ {"write-recovery-conf", no_argument, NULL, 'R'},
{"source-pgdata", required_argument, NULL, 1},
{"source-server", required_argument, NULL, 2},
{"version", no_argument, NULL, 'V'},
@@ -129,7 +133,7 @@ main(int argc, char **argv)
}
}
- while ((c = getopt_long(argc, argv, "D:nNP", long_options, &option_index)) != -1)
+ while ((c = getopt_long(argc, argv, "D:nNPR", long_options, &option_index)) != -1)
{
switch (c)
{
@@ -149,6 +153,10 @@ main(int argc, char **argv)
do_sync = false;
break;
+ case 'R':
+ writerecoveryconf = true;
+ break;
+
case 3:
debug = true;
break;
@@ -291,6 +299,13 @@ main(int argc, char **argv)
if (!rewind_needed)
{
printf(_("no rewind required\n"));
+
+ if (writerecoveryconf && connstr_source)
+ {
+ GenerateRecoveryConf();
+ WriteRecoveryConf();
+ }
+
exit(0);
}
@@ -382,6 +397,12 @@ main(int argc, char **argv)
pg_log(PG_PROGRESS, "syncing target data directory\n");
syncTargetDirectory();
+ if (writerecoveryconf && connstr_source)
+ {
+ GenerateRecoveryConf();
+ WriteRecoveryConf();
+ }
+
printf(_("Done!\n"));
return 0;
diff --git a/src/bin/pg_rewind/pg_rewind.h b/src/bin/pg_rewind/pg_rewind.h
index 83b2898b8b..0ce9ba0426 100644
--- a/src/bin/pg_rewind/pg_rewind.h
+++ b/src/bin/pg_rewind/pg_rewind.h
@@ -30,6 +30,8 @@ extern int WalSegSz;
extern TimeLineHistoryEntry *targetHistory;
extern int targetNentries;
+extern const char *progname;
+
/* in parsexlog.c */
extern void extractPageMap(const char *datadir, XLogRecPtr startpoint,
int tliIndex, XLogRecPtr endpoint);
--
2.17.2