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 d26df12

Browse filesBrowse files
committed
PBCKP-819: Fixed the recovery-target-timeline command line parameter. It may contain 'current' or 'latest' keywords.
recovery-target can be 'latest' too for compatibility with previous versions
1 parent 1ee26f9 commit d26df12
Copy full SHA for d26df12

File tree

4 files changed

+147
-11
lines changed
Filter options

4 files changed

+147
-11
lines changed

‎src/pg_probackup.c

Copy file name to clipboardExpand all lines: src/pg_probackup.c
+4-4Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ static char *target_time = NULL;
9898
static char *target_xid = NULL;
9999
static char *target_lsn = NULL;
100100
static char *target_inclusive = NULL;
101-
static TimeLineID target_tli;
101+
static char *target_tli_string; /* timeline number, "current" or "latest"*/
102102
static char *target_stop;
103103
static bool target_immediate;
104104
static char *target_name = NULL;
@@ -227,7 +227,7 @@ static ConfigOption cmd_options[] =
227227
{ 's', 137, "recovery-target-xid", &target_xid, SOURCE_CMD_STRICT },
228228
{ 's', 144, "recovery-target-lsn", &target_lsn, SOURCE_CMD_STRICT },
229229
{ 's', 138, "recovery-target-inclusive", &target_inclusive, SOURCE_CMD_STRICT },
230-
{ 'u', 139, "recovery-target-timeline", &target_tli, SOURCE_CMD_STRICT },
230+
{ 's', 139, "recovery-target-timeline", &target_tli_string, SOURCE_CMD_STRICT },
231231
{ 's', 157, "recovery-target", &target_stop, SOURCE_CMD_STRICT },
232232
{ 'f', 'T', "tablespace-mapping", opt_tablespace_map, SOURCE_CMD_STRICT },
233233
{ 'f', 155, "external-mapping", opt_externaldir_map, SOURCE_CMD_STRICT },
@@ -285,7 +285,7 @@ static ConfigOption cmd_options[] =
285285
{ 's', 136, "time", &target_time, SOURCE_CMD_STRICT },
286286
{ 's', 137, "xid", &target_xid, SOURCE_CMD_STRICT },
287287
{ 's', 138, "inclusive", &target_inclusive, SOURCE_CMD_STRICT },
288-
{ 'u', 139, "timeline", &target_tli, SOURCE_CMD_STRICT },
288+
{ 's', 139, "timeline", &target_tli_string, SOURCE_CMD_STRICT },
289289
{ 's', 144, "lsn", &target_lsn, SOURCE_CMD_STRICT },
290290
{ 'b', 140, "immediate", &target_immediate, SOURCE_CMD_STRICT },
291291

@@ -739,7 +739,7 @@ main(int argc, char *argv[])
739739
*/
740740
recovery_target_options =
741741
parseRecoveryTargetOptions(target_time, target_xid,
742-
target_inclusive, target_tli, target_lsn,
742+
target_inclusive, target_tli_string, target_lsn,
743743
(target_stop != NULL) ? target_stop :
744744
(target_immediate) ? "immediate" : NULL,
745745
target_name, target_action);

‎src/pg_probackup.h

Copy file name to clipboardExpand all lines: src/pg_probackup.h
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,7 @@ typedef struct pgRecoveryTarget
564564
const char *target_stop;
565565
const char *target_name;
566566
const char *target_action;
567+
const char *target_tli_string; /* timeline number, "current" or "latest" from recovery_target_timeline option*/
567568
} pgRecoveryTarget;
568569

569570
/* Options needed for restore and validate commands */
@@ -893,7 +894,7 @@ extern bool satisfy_recovery_target(const pgBackup *backup,
893894
const pgRecoveryTarget *rt);
894895
extern pgRecoveryTarget *parseRecoveryTargetOptions(
895896
const char *target_time, const char *target_xid,
896-
const char *target_inclusive, TimeLineID target_tli, const char* target_lsn,
897+
const char *target_inclusive, const char *target_tli_string, const char* target_lsn,
897898
const char *target_stop, const char *target_name,
898899
const char *target_action);
899900

‎src/restore.c

Copy file name to clipboardExpand all lines: src/restore.c
+33-5Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,8 +1332,10 @@ create_recovery_conf(InstanceState *instanceState, time_t backup_id,
13321332
}
13331333

13341334
/* restore-target='latest' support */
1335-
target_latest = rt->target_stop != NULL &&
1336-
strcmp(rt->target_stop, "latest") == 0;
1335+
target_latest = (rt->target_tli_string != NULL &&
1336+
strcmp(rt->target_tli_string, "latest") == 0) ||
1337+
(rt->target_stop != NULL &&
1338+
strcmp(rt->target_stop, "latest") == 0);
13371339

13381340
target_immediate = rt->target_stop != NULL &&
13391341
strcmp(rt->target_stop, "immediate") == 0;
@@ -1359,6 +1361,13 @@ create_recovery_conf(InstanceState *instanceState, time_t backup_id,
13591361
rt->xid_string || rt->lsn_string || rt->target_name ||
13601362
target_immediate || target_latest || restore_command_provided)
13611363
params->recovery_settings_mode = PITR_REQUESTED;
1364+
/*
1365+
* The recovery-target-timeline option can be 'latest' for streaming backups.
1366+
* This operation requires a WAL archive for PITR.
1367+
*/
1368+
if (rt->target_tli && backup->stream && params->recovery_settings_mode != PITR_REQUESTED)
1369+
elog(WARNING, "The '--recovery-target-timeline' option applied for STREAM backup. "
1370+
"The timeline number will be ignored.");
13621371

13631372
elog(LOG, "----------------------------------------");
13641373

@@ -1438,14 +1447,20 @@ print_recovery_settings(InstanceState *instanceState, FILE *fp, pgBackup *backup
14381447
fio_fprintf(fp, "recovery_target_timeline = '%u'\n", rt->target_tli);
14391448
else
14401449
{
1450+
if (rt->target_tli_string)
1451+
fio_fprintf(fp, "recovery_target_timeline = '%s'\n", rt->target_tli_string);
1452+
else if (rt->target_stop && (strcmp(rt->target_stop, "latest") == 0))
1453+
fio_fprintf(fp, "recovery_target_timeline = 'latest'\n");
14411454
#if PG_VERSION_NUM >= 120000
1442-
1455+
else
1456+
{
14431457
/*
14441458
* In PG12 default recovery target timeline was changed to 'latest', which
14451459
* is extremely risky. Explicitly preserve old behavior of recovering to current
14461460
* timneline for PG12.
14471461
*/
14481462
fio_fprintf(fp, "recovery_target_timeline = 'current'\n");
1463+
}
14491464
#endif
14501465
}
14511466

@@ -1877,7 +1892,7 @@ pgRecoveryTarget *
18771892
parseRecoveryTargetOptions(const char *target_time,
18781893
const char *target_xid,
18791894
const char *target_inclusive,
1880-
TimeLineID target_tli,
1895+
const char *target_tli_string,
18811896
const char *target_lsn,
18821897
const char *target_stop,
18831898
const char *target_name,
@@ -1950,7 +1965,20 @@ parseRecoveryTargetOptions(const char *target_time,
19501965
target_inclusive);
19511966
}
19521967

1953-
rt->target_tli = target_tli;
1968+
rt->target_tli_string = target_tli_string;
1969+
rt->target_tli = 0;
1970+
/* target_tli can contains timeline number, "current" or "latest" */
1971+
if(target_tli_string && strcmp(target_tli_string, "current") != 0 && strcmp(target_tli_string, "latest") != 0)
1972+
{
1973+
errno = 0;
1974+
rt->target_tli = strtoul(target_tli_string, NULL, 10);
1975+
if (errno == EINVAL || errno == ERANGE || !rt->target_tli)
1976+
{
1977+
elog(ERROR, "Invalid value for '--recovery-target-timeline' option '%s'",
1978+
target_tli_string);
1979+
}
1980+
}
1981+
19541982
if (target_stop)
19551983
{
19561984
if ((strcmp(target_stop, "immediate") != 0)

‎tests/restore_test.py

Copy file name to clipboardExpand all lines: tests/restore_test.py
+108-1Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1916,7 +1916,9 @@ def test_restore_target_immediate_archive(self):
19161916
with open(recovery_conf, 'r') as f:
19171917
self.assertIn("recovery_target = 'immediate'", f.read())
19181918

1919-
# @unittest.skip("skip")
1919+
# Skipped, because default recovery_target_timeline is 'current'
1920+
# Before PBCKP-598 the --recovery-target=latest' option did not work and this test allways passed
1921+
@unittest.skip("skip")
19201922
def test_restore_target_latest_archive(self):
19211923
"""
19221924
make sure that recovery_target 'latest'
@@ -3818,3 +3820,108 @@ def test_restore_with_waldir(self):
38183820
wal_path=os.path.join(node.data_dir, "pg_xlog")
38193821

38203822
self.assertEqual(os.path.islink(wal_path), True)
3823+
3824+
# @unittest.skip("skip")
3825+
def test_restore_to_latest_timeline(self):
3826+
"""recovery to latest timeline"""
3827+
node = self.make_simple_node(
3828+
base_dir=os.path.join(self.module_name, self.fname, 'node'),
3829+
initdb_params=['--data-checksums'])
3830+
3831+
backup_dir = os.path.join(self.tmp_path, self.module_name, self.fname, 'backup')
3832+
self.init_pb(backup_dir)
3833+
self.add_instance(backup_dir, 'node', node)
3834+
self.set_archiving(backup_dir, 'node', node)
3835+
node.slow_start()
3836+
3837+
3838+
node.pgbench_init(scale=2)
3839+
3840+
before1 = node.table_checksum("pgbench_branches")
3841+
backup_id = self.backup_node(backup_dir, 'node', node)
3842+
3843+
node.stop()
3844+
node.cleanup()
3845+
3846+
self.assertIn(
3847+
"INFO: Restore of backup {0} completed.".format(backup_id),
3848+
self.restore_node(
3849+
backup_dir, 'node', node, options=["-j", "4"]),
3850+
'\n Unexpected Error Message: {0}\n CMD: {1}'.format(
3851+
repr(self.output), self.cmd))
3852+
3853+
3854+
3855+
node.slow_start()
3856+
pgbench = node.pgbench(
3857+
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
3858+
options=['-T', '10', '-c', '2', '--no-vacuum'])
3859+
pgbench.wait()
3860+
pgbench.stdout.close()
3861+
3862+
before2 = node.table_checksum("pgbench_branches")
3863+
self.backup_node(backup_dir, 'node', node)
3864+
3865+
node.stop()
3866+
node.cleanup()
3867+
# restore from first backup
3868+
restore_result = self.restore_node(backup_dir, 'node', node,
3869+
options=[
3870+
"-j", "4", "--recovery-target-timeline=latest", "-i", backup_id]
3871+
)
3872+
self.assertIn(
3873+
"INFO: Restore of backup {0} completed.".format(backup_id), restore_result,
3874+
'\n Unexpected Error Message: {0}\n CMD: {1}'.format(
3875+
repr(self.output), self.cmd))
3876+
3877+
# check recovery_target_timeline option in the recovery_conf
3878+
recovery_target_timeline = self.get_recovery_conf(node)["recovery_target_timeline"]
3879+
self.assertEqual(recovery_target_timeline, "latest")
3880+
# check recovery-target=latest option for compatibility with previous versions
3881+
node.cleanup()
3882+
restore_result = self.restore_node(backup_dir, 'node', node,
3883+
options=[
3884+
"-j", "4", "--recovery-target=latest", "-i", backup_id]
3885+
)
3886+
self.assertIn(
3887+
"INFO: Restore of backup {0} completed.".format(backup_id), restore_result,
3888+
'\n Unexpected Error Message: {0}\n CMD: {1}'.format(
3889+
repr(self.output), self.cmd))
3890+
3891+
# check recovery_target_timeline option in the recovery_conf
3892+
recovery_target_timeline = self.get_recovery_conf(node)["recovery_target_timeline"]
3893+
self.assertEqual(recovery_target_timeline, "latest")
3894+
3895+
# start postgres and promote wal files to latest timeline
3896+
node.slow_start()
3897+
3898+
# check for the latest updates
3899+
after = node.table_checksum("pgbench_branches")
3900+
self.assertEqual(before2, after)
3901+
3902+
# checking recovery_target_timeline=current is the default option
3903+
if self.pg_config_version >= self.version_to_num('12.0'):
3904+
node.stop()
3905+
node.cleanup()
3906+
3907+
# restore from first backup
3908+
restore_result = self.restore_node(backup_dir, 'node', node,
3909+
options=[
3910+
"-j", "4", "-i", backup_id]
3911+
)
3912+
3913+
self.assertIn(
3914+
"INFO: Restore of backup {0} completed.".format(backup_id), restore_result,
3915+
'\n Unexpected Error Message: {0}\n CMD: {1}'.format(
3916+
repr(self.output), self.cmd))
3917+
3918+
# check recovery_target_timeline option in the recovery_conf
3919+
recovery_target_timeline = self.get_recovery_conf(node)["recovery_target_timeline"]
3920+
self.assertEqual(recovery_target_timeline, "current")
3921+
3922+
# start postgres with current timeline
3923+
node.slow_start()
3924+
3925+
# check for the current updates
3926+
after = node.table_checksum("pgbench_branches")
3927+
self.assertEqual(before1, after)

0 commit comments

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