Skip to content

Commit 5b41a10

Browse files
committed
Merge branch 'pgpro-2095'
2 parents 4995652 + 6c9dfcf commit 5b41a10

File tree

3 files changed

+182
-30
lines changed

3 files changed

+182
-30
lines changed

Diff for: src/backup.c

+91-30
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,8 @@ do_backup_instance(void)
475475
pgBackup *prev_backup = NULL;
476476
parray *prev_backup_filelist = NULL;
477477

478+
pgFile *pg_control = NULL;
479+
478480
elog(LOG, "Database backup start");
479481

480482
/* Initialize size summary */
@@ -754,9 +756,34 @@ do_backup_instance(void)
754756
parray_free(prev_backup_filelist);
755757
}
756758

759+
/* In case of backup from replica >= 9.6 we must fix minRecPoint,
760+
* First we must find pg_control in backup_files_list.
761+
*/
762+
if (current.from_replica && !exclusive_backup)
763+
{
764+
char pg_control_path[MAXPGPATH];
765+
766+
snprintf(pg_control_path, sizeof(pg_control_path), "%s/%s", pgdata, "global/pg_control");
767+
768+
for (i = 0; i < parray_num(backup_files_list); i++)
769+
{
770+
pgFile *tmp_file = (pgFile *) parray_get(backup_files_list, i);
771+
772+
if (strcmp(tmp_file->path, pg_control_path) == 0)
773+
{
774+
pg_control = tmp_file;
775+
break;
776+
}
777+
}
778+
}
779+
780+
757781
/* Notify end of backup */
758782
pg_stop_backup(&current);
759783

784+
if (current.from_replica && !exclusive_backup)
785+
set_min_recovery_point(pg_control, database_path, current.stop_lsn);
786+
760787
/* Add archived xlog files into the list of files of this backup */
761788
if (stream_wal)
762789
{
@@ -883,7 +910,7 @@ do_backup(time_t start_time)
883910
}
884911
}
885912

886-
if (current.from_replica)
913+
if (current.from_replica && exclusive_backup)
887914
{
888915
/* Check master connection options */
889916
if (master_host == NULL)
@@ -1089,8 +1116,11 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup)
10891116

10901117
params[0] = label;
10911118

1092-
/* For replica we call pg_start_backup() on master */
1093-
conn = (backup->from_replica) ? master_conn : backup_conn;
1119+
/* For 9.5 replica we call pg_start_backup() on master */
1120+
if (backup->from_replica && exclusive_backup)
1121+
conn = master_conn;
1122+
else
1123+
conn = backup_conn;
10941124

10951125
/* 2nd argument is 'fast'*/
10961126
params[1] = smooth ? "false" : "true";
@@ -1118,16 +1148,18 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup)
11181148

11191149
PQclear(res);
11201150

1121-
if (current.backup_mode == BACKUP_MODE_DIFF_PAGE)
1151+
if (current.backup_mode == BACKUP_MODE_DIFF_PAGE &&
1152+
(!(backup->from_replica && !exclusive_backup)))
11221153
/*
11231154
* Switch to a new WAL segment. It is necessary to get archived WAL
11241155
* segment, which includes start LSN of current backup.
1156+
* Don`t do this for replica backups unless it`s PG 9.5
11251157
*/
11261158
pg_switch_wal(conn);
11271159

11281160
if (current.backup_mode == BACKUP_MODE_DIFF_PAGE)
11291161
/* In PAGE mode wait for current segment... */
1130-
wait_wal_lsn(backup->start_lsn, true, false);
1162+
wait_wal_lsn(backup->start_lsn, true, false);
11311163
/*
11321164
* Do not wait start_lsn for stream backup.
11331165
* Because WAL streaming will start after pg_start_backup() in stream
@@ -1137,8 +1169,10 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup)
11371169
/* ...for others wait for previous segment */
11381170
wait_wal_lsn(backup->start_lsn, true, true);
11391171

1140-
/* Wait for start_lsn to be replayed by replica */
1141-
if (backup->from_replica)
1172+
/* In case of backup from replica for PostgreSQL 9.5
1173+
* wait for start_lsn to be replayed by replica
1174+
*/
1175+
if (backup->from_replica && exclusive_backup)
11421176
wait_replica_wal_lsn(backup->start_lsn, true);
11431177
}
11441178

@@ -1488,7 +1522,7 @@ wait_wal_lsn(XLogRecPtr lsn, bool is_start_lsn, bool wait_prev_segment)
14881522
GetXLogFileName(wal_segment, tli, targetSegNo, xlog_seg_size);
14891523

14901524
/*
1491-
* In pg_start_backup we wait for 'lsn' in 'pg_wal' directory iff it is
1525+
* In pg_start_backup we wait for 'lsn' in 'pg_wal' directory if it is
14921526
* stream and non-page backup. Page backup needs archived WAL files, so we
14931527
* wait for 'lsn' in archive 'wal' directory for page backups.
14941528
*
@@ -1509,7 +1543,12 @@ wait_wal_lsn(XLogRecPtr lsn, bool is_start_lsn, bool wait_prev_segment)
15091543
{
15101544
join_path_components(wal_segment_path, arclog_path, wal_segment);
15111545
wal_segment_dir = arclog_path;
1512-
timeout = archive_timeout;
1546+
1547+
if (archive_timeout > 0)
1548+
timeout = archive_timeout;
1549+
else
1550+
timeout = ARCHIVE_TIMEOUT_DEFAULT;
1551+
15131552
}
15141553

15151554
if (wait_prev_segment)
@@ -1669,7 +1708,7 @@ pg_stop_backup(pgBackup *backup)
16691708
PGresult *tablespace_map_content = NULL;
16701709
uint32 lsn_hi;
16711710
uint32 lsn_lo;
1672-
XLogRecPtr restore_lsn = InvalidXLogRecPtr;
1711+
//XLogRecPtr restore_lsn = InvalidXLogRecPtr;
16731712
int pg_stop_backup_timeout = 0;
16741713
char path[MAXPGPATH];
16751714
char backup_label[MAXPGPATH];
@@ -1689,16 +1728,21 @@ pg_stop_backup(pgBackup *backup)
16891728
if (!backup_in_progress)
16901729
elog(ERROR, "backup is not in progress");
16911730

1692-
/* For replica we call pg_stop_backup() on master */
1693-
conn = (current.from_replica) ? master_conn : backup_conn;
1731+
/* For 9.5 replica we call pg_stop_backup() on master */
1732+
if (current.from_replica && exclusive_backup)
1733+
conn = master_conn;
1734+
else
1735+
conn = backup_conn;
16941736

16951737
/* Remove annoying NOTICE messages generated by backend */
16961738
res = pgut_execute(conn, "SET client_min_messages = warning;",
16971739
0, NULL);
16981740
PQclear(res);
16991741

1700-
/* Create restore point */
1701-
if (backup != NULL)
1742+
/* Create restore point
1743+
* only if it`s backup from master, or exclusive replica(wich connects to master)
1744+
*/
1745+
if (backup != NULL && (!current.from_replica || (current.from_replica && exclusive_backup)))
17021746
{
17031747
const char *params[1];
17041748
char name[1024];
@@ -1716,7 +1760,7 @@ pg_stop_backup(pgBackup *backup)
17161760
/* Extract timeline and LSN from the result */
17171761
XLogDataFromLSN(PQgetvalue(res, 0, 0), &lsn_hi, &lsn_lo);
17181762
/* Calculate LSN */
1719-
restore_lsn = ((uint64) lsn_hi) << 32 | lsn_lo;
1763+
//restore_lsn = ((uint64) lsn_hi) << 32 | lsn_lo;
17201764
PQclear(res);
17211765
}
17221766

@@ -1737,14 +1781,29 @@ pg_stop_backup(pgBackup *backup)
17371781
* Stop the non-exclusive backup. Besides stop_lsn it returns from
17381782
* pg_stop_backup(false) copy of the backup label and tablespace map
17391783
* so they can be written to disk by the caller.
1784+
* In case of backup from replica >= 9.6 we do not trust minRecPoint
1785+
* and stop_backup LSN, so we use latest replayed LSN as STOP LSN.
17401786
*/
1741-
stop_backup_query = "SELECT"
1742-
" pg_catalog.txid_snapshot_xmax(pg_catalog.txid_current_snapshot()),"
1743-
" current_timestamp(0)::timestamptz,"
1744-
" lsn,"
1745-
" labelfile,"
1746-
" spcmapfile"
1747-
" FROM pg_catalog.pg_stop_backup(false)";
1787+
if (current.from_replica)
1788+
stop_backup_query = "SELECT"
1789+
" pg_catalog.txid_snapshot_xmax(pg_catalog.txid_current_snapshot()),"
1790+
" current_timestamp(0)::timestamptz,"
1791+
#if PG_VERSION_NUM >= 100000
1792+
" pg_catalog.pg_last_wal_replay_lsn(),"
1793+
#else
1794+
" pg_catalog.pg_last_xlog_replay_location(),"
1795+
#endif
1796+
" labelfile,"
1797+
" spcmapfile"
1798+
" FROM pg_catalog.pg_stop_backup(false)";
1799+
else
1800+
stop_backup_query = "SELECT"
1801+
" pg_catalog.txid_snapshot_xmax(pg_catalog.txid_current_snapshot()),"
1802+
" current_timestamp(0)::timestamptz,"
1803+
" lsn,"
1804+
" labelfile,"
1805+
" spcmapfile"
1806+
" FROM pg_catalog.pg_stop_backup(false)";
17481807

17491808
}
17501809
else
@@ -1832,13 +1891,13 @@ pg_stop_backup(pgBackup *backup)
18321891

18331892
if (!XRecOffIsValid(stop_backup_lsn))
18341893
{
1835-
stop_backup_lsn = restore_lsn;
1894+
if (XRecOffIsNull(stop_backup_lsn))
1895+
stop_backup_lsn = stop_backup_lsn + SizeOfXLogLongPHD;
1896+
else
1897+
elog(ERROR, "Invalid stop_backup_lsn value %X/%X",
1898+
(uint32) (stop_backup_lsn >> 32), (uint32) (stop_backup_lsn));
18361899
}
18371900

1838-
if (!XRecOffIsValid(stop_backup_lsn))
1839-
elog(ERROR, "Invalid stop_backup_lsn value %X/%X",
1840-
(uint32) (stop_backup_lsn >> 32), (uint32) (stop_backup_lsn));
1841-
18421901
/* Write backup_label and tablespace_map */
18431902
if (!exclusive_backup)
18441903
{
@@ -1939,7 +1998,7 @@ pg_stop_backup(pgBackup *backup)
19391998
stream_xlog_path[MAXPGPATH];
19401999

19412000
/* Wait for stop_lsn to be received by replica */
1942-
if (backup->from_replica)
2001+
if (current.from_replica)
19432002
wait_replica_wal_lsn(stop_backup_lsn, false);
19442003
/*
19452004
* Wait for stop_lsn to be archived or streamed.
@@ -1962,10 +2021,12 @@ pg_stop_backup(pgBackup *backup)
19622021

19632022
elog(LOG, "Getting the Recovery Time from WAL");
19642023

2024+
/* iterate over WAL from stop_backup lsn to start_backup lsn */
19652025
if (!read_recovery_info(xlog_path, backup->tli, xlog_seg_size,
19662026
backup->start_lsn, backup->stop_lsn,
19672027
&backup->recovery_time, &backup->recovery_xid))
19682028
{
2029+
elog(LOG, "Failed to find Recovery Time in WAL. Forced to trust current_timestamp");
19692030
backup->recovery_time = recovery_time;
19702031
backup->recovery_xid = recovery_xid;
19712032
}
@@ -2074,7 +2135,7 @@ backup_files(void *arg)
20742135
elog(ERROR, "interrupted during backup");
20752136

20762137
if (progress)
2077-
elog(LOG, "Progress: (%d/%d). Process file \"%s\"",
2138+
elog(INFO, "Progress: (%d/%d). Process file \"%s\"",
20782139
i + 1, n_backup_files_list, file->path);
20792140

20802141
/* stat file to check its current state */
@@ -2168,7 +2229,7 @@ backup_files(void *arg)
21682229
file->path, file->write_size);
21692230
}
21702231
else
2171-
elog(LOG, "unexpected file type %d", buf.st_mode);
2232+
elog(WARNING, "unexpected file type %d", buf.st_mode);
21722233
}
21732234

21742235
/* Close connection */

Diff for: src/pg_probackup.h

+5
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@
5757
#define XID_FMT "%u"
5858
#endif
5959

60+
/* Check if an XLogRecPtr value is pointed to 0 offset */
61+
#define XRecOffIsNull(xlrp) \
62+
((xlrp) % XLOG_BLCKSZ == 0)
63+
6064
typedef enum CompressAlg
6165
{
6266
NOT_DEFINED_COMPRESS = 0,
@@ -579,6 +583,7 @@ extern uint64 get_system_identifier(char *pgdata);
579583
extern uint64 get_remote_system_identifier(PGconn *conn);
580584
extern uint32 get_data_checksum_version(bool safe);
581585
extern uint32 get_xlog_seg_size(char *pgdata_path);
586+
extern void set_min_recovery_point(pgFile *file, const char *backup_path, XLogRecPtr stop_backup_lsn);
582587

583588
extern void sanityChecks(void);
584589
extern void time2iso(char *buf, size_t len, time_t time);

Diff for: src/util.c

+86
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
#include <time.h>
1616

17+
#include <unistd.h>
18+
1719
const char *
1820
base36enc(long unsigned int value)
1921
{
@@ -100,6 +102,44 @@ digestControlFile(ControlFileData *ControlFile, char *src, size_t size)
100102
checkControlFile(ControlFile);
101103
}
102104

105+
/*
106+
* Write ControlFile to pg_control
107+
*/
108+
static void
109+
writeControlFile(ControlFileData *ControlFile, char *path)
110+
{
111+
int fd;
112+
char *buffer = NULL;
113+
114+
#if PG_VERSION_NUM >= 100000
115+
int ControlFileSize = PG_CONTROL_FILE_SIZE;
116+
#else
117+
int ControlFileSize = PG_CONTROL_SIZE;
118+
#endif
119+
120+
/* copy controlFileSize */
121+
buffer = pg_malloc(ControlFileSize);
122+
memcpy(buffer, ControlFile, sizeof(ControlFileData));
123+
124+
/* Write pg_control */
125+
unlink(path);
126+
fd = open(path,
127+
O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
128+
S_IRUSR | S_IWUSR);
129+
130+
if (fd < 0)
131+
elog(ERROR, "Failed to open file: %s", path);
132+
133+
if (write(fd, buffer, ControlFileSize) != ControlFileSize)
134+
elog(ERROR, "Failed to overwrite file: %s", path);
135+
136+
if (fsync(fd) != 0)
137+
elog(ERROR, "Failed to fsync file: %s", path);
138+
139+
close(fd);
140+
pg_free(buffer);
141+
}
142+
103143
/*
104144
* Utility shared by backup and restore to fetch the current timeline
105145
* used by a node.
@@ -250,6 +290,52 @@ get_data_checksum_version(bool safe)
250290
return ControlFile.data_checksum_version;
251291
}
252292

293+
/* MinRecoveryPoint 'as-is' is not to be trusted */
294+
void
295+
set_min_recovery_point(pgFile *file, const char *backup_path, XLogRecPtr stop_backup_lsn)
296+
{
297+
ControlFileData ControlFile;
298+
char *buffer;
299+
size_t size;
300+
char fullpath[MAXPGPATH];
301+
302+
/* First fetch file content */
303+
buffer = slurpFile(pgdata, XLOG_CONTROL_FILE, &size, false);
304+
if (buffer == NULL)
305+
elog(ERROR, "ERROR");
306+
307+
digestControlFile(&ControlFile, buffer, size);
308+
309+
elog(LOG, "Current minRecPoint %X/%X",
310+
(uint32) (ControlFile.minRecoveryPoint >> 32),
311+
(uint32) ControlFile.minRecoveryPoint);
312+
313+
elog(LOG, "Setting minRecPoint to %X/%X",
314+
(uint32) (stop_backup_lsn >> 32),
315+
(uint32) stop_backup_lsn);
316+
317+
ControlFile.minRecoveryPoint = stop_backup_lsn;
318+
319+
/* Update checksum in pg_control header */
320+
INIT_CRC32C(ControlFile.crc);
321+
COMP_CRC32C(ControlFile.crc,
322+
(char *) &ControlFile,
323+
offsetof(ControlFileData, crc));
324+
FIN_CRC32C(ControlFile.crc);
325+
326+
/* paranoia */
327+
checkControlFile(&ControlFile);
328+
329+
/* overwrite pg_control */
330+
snprintf(fullpath, sizeof(fullpath), "%s/%s", backup_path, XLOG_CONTROL_FILE);
331+
writeControlFile(&ControlFile, fullpath);
332+
333+
/* Update pg_control checksum in backup_list */
334+
file->crc = pgFileGetCRC(fullpath, false);
335+
336+
pg_free(buffer);
337+
}
338+
253339

254340
/*
255341
* Convert time_t value to ISO-8601 format string. Always set timezone offset.

0 commit comments

Comments
 (0)