Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit caba97a

Browse filesBrowse files
committed
Split out recovery confing-writing code from pg_basebackup
... into a new file, fe_utils/recovery_gen.c. This can later be used by pg_rewind. Authors: Paul Guo, Jimmy Yih, Ashwin Agrawal. A few tweaks by Álvaro Herrera Reviewed-by: Michaël Paquier Discussion: https://postgr.es/m/CAEET0ZEffUkXc48pg2iqARQgGRYDiiVxDu+yYek_bTwJF+q=Uw@mail.gmail.com
1 parent f5daf7f commit caba97a
Copy full SHA for caba97a

File tree

Expand file treeCollapse file tree

5 files changed

+211
-161
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+211
-161
lines changed

‎src/bin/pg_basebackup/pg_basebackup.c

Copy file name to clipboardExpand all lines: src/bin/pg_basebackup/pg_basebackup.c
+3-159Lines changed: 3 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "common/file_utils.h"
3232
#include "common/logging.h"
3333
#include "common/string.h"
34+
#include "fe_utils/recovery_gen.h"
3435
#include "fe_utils/string_utils.h"
3536
#include "getopt_long.h"
3637
#include "libpq-fe.h"
@@ -67,11 +68,6 @@ typedef struct TablespaceList
6768
*/
6869
#define MINIMUM_VERSION_FOR_TEMP_SLOTS 100000
6970

70-
/*
71-
* recovery.conf is integrated into postgresql.conf from version 12.
72-
*/
73-
#define MINIMUM_VERSION_FOR_RECOVERY_GUC 120000
74-
7571
/*
7672
* Different ways to include WAL
7773
*/
@@ -147,8 +143,6 @@ static void progress_report(int tablespacenum, const char *filename, bool force)
147143

148144
static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
149145
static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
150-
static void GenerateRecoveryConf(PGconn *conn);
151-
static void WriteRecoveryConf(void);
152146
static void BaseBackup(void);
153147

154148
static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
@@ -1629,164 +1623,14 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
16291623
PQfreemem(copybuf);
16301624

16311625
if (basetablespace && writerecoveryconf)
1632-
WriteRecoveryConf();
1626+
WriteRecoveryConfig(conn, basedir, recoveryconfcontents);
16331627

16341628
/*
16351629
* No data is synced here, everything is done for all tablespaces at the
16361630
* end.
16371631
*/
16381632
}
16391633

1640-
/*
1641-
* Escape a string so that it can be used as a value in a key-value pair
1642-
* a configuration file.
1643-
*/
1644-
static char *
1645-
escape_quotes(const char *src)
1646-
{
1647-
char *result = escape_single_quotes_ascii(src);
1648-
1649-
if (!result)
1650-
{
1651-
pg_log_error("out of memory");
1652-
exit(1);
1653-
}
1654-
return result;
1655-
}
1656-
1657-
/*
1658-
* Create a configuration file in memory using a PQExpBuffer
1659-
*/
1660-
static void
1661-
GenerateRecoveryConf(PGconn *conn)
1662-
{
1663-
PQconninfoOption *connOptions;
1664-
PQconninfoOption *option;
1665-
PQExpBufferData conninfo_buf;
1666-
char *escaped;
1667-
1668-
recoveryconfcontents = createPQExpBuffer();
1669-
if (!recoveryconfcontents)
1670-
{
1671-
pg_log_error("out of memory");
1672-
exit(1);
1673-
}
1674-
1675-
/*
1676-
* In PostgreSQL 12 and newer versions, standby_mode is gone, replaced by
1677-
* standby.signal to trigger a standby state at recovery.
1678-
*/
1679-
if (PQserverVersion(conn) < MINIMUM_VERSION_FOR_RECOVERY_GUC)
1680-
appendPQExpBufferStr(recoveryconfcontents, "standby_mode = 'on'\n");
1681-
1682-
connOptions = PQconninfo(conn);
1683-
if (connOptions == NULL)
1684-
{
1685-
pg_log_error("out of memory");
1686-
exit(1);
1687-
}
1688-
1689-
initPQExpBuffer(&conninfo_buf);
1690-
for (option = connOptions; option && option->keyword; option++)
1691-
{
1692-
/* Omit empty settings and those libpqwalreceiver overrides. */
1693-
if (strcmp(option->keyword, "replication") == 0 ||
1694-
strcmp(option->keyword, "dbname") == 0 ||
1695-
strcmp(option->keyword, "fallback_application_name") == 0 ||
1696-
(option->val == NULL) ||
1697-
(option->val != NULL && option->val[0] == '\0'))
1698-
continue;
1699-
1700-
/* Separate key-value pairs with spaces */
1701-
if (conninfo_buf.len != 0)
1702-
appendPQExpBufferChar(&conninfo_buf, ' ');
1703-
1704-
/*
1705-
* Write "keyword=value" pieces, the value string is escaped and/or
1706-
* quoted if necessary.
1707-
*/
1708-
appendPQExpBuffer(&conninfo_buf, "%s=", option->keyword);
1709-
appendConnStrVal(&conninfo_buf, option->val);
1710-
}
1711-
1712-
/*
1713-
* Escape the connection string, so that it can be put in the config file.
1714-
* Note that this is different from the escaping of individual connection
1715-
* options above!
1716-
*/
1717-
escaped = escape_quotes(conninfo_buf.data);
1718-
appendPQExpBuffer(recoveryconfcontents, "primary_conninfo = '%s'\n", escaped);
1719-
free(escaped);
1720-
1721-
if (replication_slot)
1722-
{
1723-
/* unescaped: ReplicationSlotValidateName allows [a-z0-9_] only */
1724-
appendPQExpBuffer(recoveryconfcontents, "primary_slot_name = '%s'\n",
1725-
replication_slot);
1726-
}
1727-
1728-
if (PQExpBufferBroken(recoveryconfcontents) ||
1729-
PQExpBufferDataBroken(conninfo_buf))
1730-
{
1731-
pg_log_error("out of memory");
1732-
exit(1);
1733-
}
1734-
1735-
termPQExpBuffer(&conninfo_buf);
1736-
1737-
PQconninfoFree(connOptions);
1738-
}
1739-
1740-
1741-
/*
1742-
* Write the configuration file into the directory specified in basedir,
1743-
* with the contents already collected in memory appended. Then write
1744-
* the signal file into the basedir. If the server does not support
1745-
* recovery parameters as GUCs, the signal file is not necessary, and
1746-
* configuration is written to recovery.conf.
1747-
*/
1748-
static void
1749-
WriteRecoveryConf(void)
1750-
{
1751-
char filename[MAXPGPATH];
1752-
FILE *cf;
1753-
bool is_recovery_guc_supported = true;
1754-
1755-
if (PQserverVersion(conn) < MINIMUM_VERSION_FOR_RECOVERY_GUC)
1756-
is_recovery_guc_supported = false;
1757-
1758-
snprintf(filename, MAXPGPATH, "%s/%s", basedir,
1759-
is_recovery_guc_supported ? "postgresql.auto.conf" : "recovery.conf");
1760-
1761-
cf = fopen(filename, is_recovery_guc_supported ? "a" : "w");
1762-
if (cf == NULL)
1763-
{
1764-
pg_log_error("could not open file \"%s\": %m", filename);
1765-
exit(1);
1766-
}
1767-
1768-
if (fwrite(recoveryconfcontents->data, recoveryconfcontents->len, 1, cf) != 1)
1769-
{
1770-
pg_log_error("could not write to file \"%s\": %m", filename);
1771-
exit(1);
1772-
}
1773-
1774-
fclose(cf);
1775-
1776-
if (is_recovery_guc_supported)
1777-
{
1778-
snprintf(filename, MAXPGPATH, "%s/%s", basedir, "standby.signal");
1779-
cf = fopen(filename, "w");
1780-
if (cf == NULL)
1781-
{
1782-
pg_log_error("could not create file \"%s\": %m", filename);
1783-
exit(1);
1784-
}
1785-
1786-
fclose(cf);
1787-
}
1788-
}
1789-
17901634

17911635
static void
17921636
BaseBackup(void)
@@ -1843,7 +1687,7 @@ BaseBackup(void)
18431687
* Build contents of configuration file if requested
18441688
*/
18451689
if (writerecoveryconf)
1846-
GenerateRecoveryConf(conn);
1690+
recoveryconfcontents = GenerateRecoveryConfig(conn, replication_slot);
18471691

18481692
/*
18491693
* Run IDENTIFY_SYSTEM so we can get the timeline

‎src/fe_utils/Makefile

Copy file name to clipboardExpand all lines: src/fe_utils/Makefile
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ include $(top_builddir)/src/Makefile.global
1919

2020
override CPPFLAGS := -DFRONTEND -I$(libpq_srcdir) $(CPPFLAGS)
2121

22-
OBJS = mbprint.o print.o psqlscan.o simple_list.o string_utils.o conditional.o
22+
OBJS = conditional.o mbprint.o print.o psqlscan.o recovery_gen.o \
23+
simple_list.o string_utils.o
2324

2425
all: libpgfeutils.a
2526

‎src/fe_utils/recovery_gen.c

Copy file name to clipboard
+176Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* recovery_gen.c
4+
* Generator for recovery configuration
5+
*
6+
* Portions Copyright (c) 2011-2019, PostgreSQL Global Development Group
7+
*
8+
*-------------------------------------------------------------------------
9+
*/
10+
#include "postgres_fe.h"
11+
12+
#include "common/logging.h"
13+
#include "fe_utils/string_utils.h"
14+
#include "fe_utils/recovery_gen.h"
15+
16+
17+
static char *escape_quotes(const char *src);
18+
19+
/*
20+
* Write recovery configuration contents into a fresh PQExpBuffer, and
21+
* return it.
22+
*/
23+
PQExpBuffer
24+
GenerateRecoveryConfig(PGconn *pgconn, char *replication_slot)
25+
{
26+
PQconninfoOption *connOptions;
27+
PQExpBufferData conninfo_buf;
28+
char *escaped;
29+
PQExpBuffer contents;
30+
31+
Assert(pgconn != NULL);
32+
33+
contents = createPQExpBuffer();
34+
if (!contents)
35+
{
36+
pg_log_error("out of memory");
37+
exit(1);
38+
}
39+
40+
/*
41+
* In PostgreSQL 12 and newer versions, standby_mode is gone, replaced by
42+
* standby.signal to trigger a standby state at recovery.
43+
*/
44+
if (PQserverVersion(pgconn) < MINIMUM_VERSION_FOR_RECOVERY_GUC)
45+
appendPQExpBufferStr(contents, "standby_mode = 'on'\n");
46+
47+
connOptions = PQconninfo(pgconn);
48+
if (connOptions == NULL)
49+
{
50+
pg_log_error("out of memory");
51+
exit(1);
52+
}
53+
54+
initPQExpBuffer(&conninfo_buf);
55+
for (PQconninfoOption *opt = connOptions; opt && opt->keyword; opt++)
56+
{
57+
/* Omit empty settings and those libpqwalreceiver overrides. */
58+
if (strcmp(opt->keyword, "replication") == 0 ||
59+
strcmp(opt->keyword, "dbname") == 0 ||
60+
strcmp(opt->keyword, "fallback_application_name") == 0 ||
61+
(opt->val == NULL) ||
62+
(opt->val != NULL && opt->val[0] == '\0'))
63+
continue;
64+
65+
/* Separate key-value pairs with spaces */
66+
if (conninfo_buf.len != 0)
67+
appendPQExpBufferChar(&conninfo_buf, ' ');
68+
69+
/*
70+
* Write "keyword=value" pieces, the value string is escaped and/or
71+
* quoted if necessary.
72+
*/
73+
appendPQExpBuffer(&conninfo_buf, "%s=", opt->keyword);
74+
appendConnStrVal(&conninfo_buf, opt->val);
75+
}
76+
if (PQExpBufferDataBroken(conninfo_buf))
77+
{
78+
pg_log_error("out of memory");
79+
exit(1);
80+
}
81+
82+
/*
83+
* Escape the connection string, so that it can be put in the config file.
84+
* Note that this is different from the escaping of individual connection
85+
* options above!
86+
*/
87+
escaped = escape_quotes(conninfo_buf.data);
88+
termPQExpBuffer(&conninfo_buf);
89+
appendPQExpBuffer(contents, "primary_conninfo = '%s'\n", escaped);
90+
free(escaped);
91+
92+
if (replication_slot)
93+
{
94+
/* unescaped: ReplicationSlotValidateName allows [a-z0-9_] only */
95+
appendPQExpBuffer(contents, "primary_slot_name = '%s'\n",
96+
replication_slot);
97+
}
98+
99+
if (PQExpBufferBroken(contents))
100+
{
101+
pg_log_error("out of memory");
102+
exit(1);
103+
}
104+
105+
PQconninfoFree(connOptions);
106+
107+
return contents;
108+
}
109+
110+
/*
111+
* Write the configuration file in the directory specified in target_dir,
112+
* with the contents already collected in memory appended. Then write
113+
* the signal file into the target_dir. If the server does not support
114+
* recovery parameters as GUCs, the signal file is not necessary, and
115+
* configuration is written to recovery.conf.
116+
*/
117+
void
118+
WriteRecoveryConfig(PGconn *pgconn, char *target_dir, PQExpBuffer contents)
119+
{
120+
char filename[MAXPGPATH];
121+
FILE *cf;
122+
bool use_recovery_conf;
123+
124+
Assert(pgconn != NULL);
125+
126+
use_recovery_conf =
127+
PQserverVersion(pgconn) < MINIMUM_VERSION_FOR_RECOVERY_GUC;
128+
129+
snprintf(filename, MAXPGPATH, "%s/%s", target_dir,
130+
use_recovery_conf ? "recovery.conf" : "postgresql.auto.conf");
131+
132+
cf = fopen(filename, use_recovery_conf ? "a" : "w");
133+
if (cf == NULL)
134+
{
135+
pg_log_error("could not open file \"%s\": %m", filename);
136+
exit(1);
137+
}
138+
139+
if (fwrite(contents->data, contents->len, 1, cf) != 1)
140+
{
141+
pg_log_error("could not write to file \"%s\": %m", filename);
142+
exit(1);
143+
}
144+
145+
fclose(cf);
146+
147+
if (!use_recovery_conf)
148+
{
149+
snprintf(filename, MAXPGPATH, "%s/%s", target_dir, "standby.signal");
150+
cf = fopen(filename, "w");
151+
if (cf == NULL)
152+
{
153+
pg_log_error("could not create file \"%s\": %m", filename);
154+
exit(1);
155+
}
156+
157+
fclose(cf);
158+
}
159+
}
160+
161+
/*
162+
* Escape a string so that it can be used as a value in a key-value pair
163+
* a configuration file.
164+
*/
165+
static char *
166+
escape_quotes(const char *src)
167+
{
168+
char *result = escape_single_quotes_ascii(src);
169+
170+
if (!result)
171+
{
172+
pg_log_error("out of memory");
173+
exit(1);
174+
}
175+
return result;
176+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.