From d87149c68f930efc1105259bb583d20176d8b1af Mon Sep 17 00:00:00 2001 From: Arthur Zakirov Date: Wed, 10 Apr 2019 15:57:32 +0300 Subject: [PATCH] PBCKP-36: Create recovery.conf if --latest specified --- src/help.c | 7 ++++--- src/pg_probackup.c | 5 ++++- src/pg_probackup.h | 3 ++- src/restore.c | 12 +++++++----- tests/expected/option_help.out | 16 ++++++++++------ tests/option_test.py | 2 +- 6 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/help.c b/src/help.c index 214a15ed..8e8e3f70 100644 --- a/src/help.c +++ b/src/help.c @@ -123,7 +123,7 @@ help_pg_probackup(void) printf(_("\n %s restore -B backup-path --instance=instance_name\n"), PROGRAM_NAME); printf(_(" [-D pgdata-path] [-i backup-id] [-j num-threads]\n")); - printf(_(" [--time=time|--xid=xid|--lsn=lsn [--inclusive=boolean]]\n")); + printf(_(" [--time=time|--xid=xid|--lsn=lsn|--latest [--inclusive=boolean]]\n")); printf(_(" [--timeline=timeline] [-T OLDDIR=NEWDIR] [--progress]\n")); printf(_(" [--external-mapping=OLDDIR=NEWDIR]\n")); printf(_(" [--immediate] [--recovery-target-name=target-name]\n")); @@ -292,7 +292,7 @@ help_restore(void) { printf(_("%s restore -B backup-path --instance=instance_name\n"), PROGRAM_NAME); printf(_(" [-D pgdata-path] [-i backup-id] [-j num-threads] [--progress]\n")); - printf(_(" [--time=time|--xid=xid|--lsn=lsn [--inclusive=boolean]]\n")); + printf(_(" [--time=time|--xid=xid|--lsn=lsn|--latest [--inclusive=boolean]]\n")); printf(_(" [--timeline=timeline] [-T OLDDIR=NEWDIR]\n")); printf(_(" [--external-mapping=OLDDIR=NEWDIR]\n")); printf(_(" [--immediate] [--recovery-target-name=target-name]\n")); @@ -312,7 +312,8 @@ help_restore(void) printf(_(" --time=time time stamp up to which recovery will proceed\n")); printf(_(" --xid=xid transaction ID up to which recovery will proceed\n")); printf(_(" --lsn=lsn LSN of the write-ahead log location up to which recovery will proceed\n")); - printf(_(" --inclusive=boolean whether we stop just after the recovery target\n")); + printf(_(" --lsn=lsn LSN of the write-ahead log location up to which recovery will proceed\n")); + printf(_(" --latest recovery into a latest possible state\n")); printf(_(" --timeline=timeline recovering into a particular timeline\n")); printf(_(" -T, --tablespace-mapping=OLDDIR=NEWDIR\n")); printf(_(" relocate the tablespace from directory OLDDIR to NEWDIR\n")); diff --git a/src/pg_probackup.c b/src/pg_probackup.c index 24ba2759..e07a280c 100644 --- a/src/pg_probackup.c +++ b/src/pg_probackup.c @@ -81,6 +81,7 @@ static TimeLineID target_tli; static bool target_immediate; static char *target_name = NULL; static char *target_action = NULL; +static bool target_latest = false; static pgRecoveryTarget *recovery_target_options = NULL; @@ -152,6 +153,7 @@ static ConfigOption cmd_options[] = { 's', 137, "xid", &target_xid, SOURCE_CMD_STRICT }, { 's', 138, "inclusive", &target_inclusive, SOURCE_CMD_STRICT }, { 'u', 139, "timeline", &target_tli, SOURCE_CMD_STRICT }, + { 'b', 157, "latest", &target_latest, SOURCE_CMD_STRICT }, { 'f', 'T', "tablespace-mapping", opt_tablespace_map, SOURCE_CMD_STRICT }, { 'f', 155, "external-mapping", opt_externaldir_map, SOURCE_CMD_STRICT }, { 'b', 140, "immediate", &target_immediate, SOURCE_CMD_STRICT }, @@ -474,7 +476,8 @@ main(int argc, char *argv[]) /* parse all recovery target options into recovery_target_options structure */ recovery_target_options = parseRecoveryTargetOptions(target_time, target_xid, target_inclusive, target_tli, target_lsn, target_immediate, - target_name, target_action, restore_no_validate); + target_name, target_action, restore_no_validate, + target_latest); } if (num_threads < 1) diff --git a/src/pg_probackup.h b/src/pg_probackup.h index ff4ae866..c50e1a8d 100644 --- a/src/pg_probackup.h +++ b/src/pg_probackup.h @@ -292,6 +292,7 @@ typedef struct pgRecoveryTarget const char *recovery_target_name; const char *recovery_target_action; bool restore_no_validate; + bool latest; } pgRecoveryTarget; typedef struct @@ -427,7 +428,7 @@ extern pgRecoveryTarget *parseRecoveryTargetOptions( const char *target_time, const char *target_xid, const char *target_inclusive, TimeLineID target_tli, const char* target_lsn, bool target_immediate, const char *target_name, - const char *target_action, bool restore_no_validate); + const char *target_action, bool restore_no_validate, bool latest); /* in merge.c */ extern void do_merge(time_t backup_id); diff --git a/src/restore.c b/src/restore.c index bd8f5b72..e1a65dd7 100644 --- a/src/restore.c +++ b/src/restore.c @@ -769,11 +769,11 @@ create_recovery_conf(time_t backup_id, { char path[MAXPGPATH]; FILE *fp; - bool need_restore_conf = false; + bool need_restore_conf; - if (!backup->stream - || (rt->time_specified || rt->xid_specified)) - need_restore_conf = true; + need_restore_conf = !backup->stream || + (rt->time_specified || rt->xid_specified || rt->lsn_specified) || + rt->latest; /* No need to generate recovery.conf at all. */ if (!(need_restore_conf || restore_as_replica)) @@ -993,7 +993,7 @@ parseRecoveryTargetOptions(const char *target_time, bool target_immediate, const char *target_name, const char *target_action, - bool restore_no_validate) + bool restore_no_validate, bool latest) { time_t dummy_time; TransactionId dummy_xid; @@ -1085,6 +1085,8 @@ parseRecoveryTargetOptions(const char *target_time, rt->restore_no_validate = restore_no_validate; } + rt->latest = latest; + if (target_name) { recovery_target_specified++; diff --git a/tests/expected/option_help.out b/tests/expected/option_help.out index a83c3905..23f3cf91 100644 --- a/tests/expected/option_help.out +++ b/tests/expected/option_help.out @@ -39,7 +39,7 @@ pg_probackup - utility to manage backup/recovery of PostgreSQL database. [--log-directory=log-directory] [--log-rotation-size=log-rotation-size] [--log-rotation-age=log-rotation-age] - [--delete-expired] [--delete-wal] + [--delete-expired] [--delete-wal] [--merge-expired] [--retention-redundancy=retention-redundancy] [--retention-window=retention-window] [--compress] @@ -51,16 +51,19 @@ pg_probackup - utility to manage backup/recovery of PostgreSQL database. [--master-port=port] [--master-user=user_name] [--replica-timeout=timeout] [--skip-block-validation] + [--external-dirs=external-directory-path] pg_probackup restore -B backup-path --instance=instance_name - [-D pgdata-path] [-i backup-id] [--progress] - [--time=time|--xid=xid|--lsn=lsn [--inclusive=boolean]] - [--timeline=timeline] [-T OLDDIR=NEWDIR] + [-D pgdata-path] [-i backup-id] [-j num-threads] + [--time=time|--xid=xid|--lsn=lsn|--latest [--inclusive=boolean]] + [--timeline=timeline] [-T OLDDIR=NEWDIR] [--progress] + [--external-mapping=OLDDIR=NEWDIR] [--immediate] [--recovery-target-name=target-name] [--recovery-target-action=pause|promote|shutdown] [--restore-as-replica] [--no-validate] [--skip-block-validation] + [--skip-external-dirs] pg_probackup validate -B backup-path [--instance=instance_name] [-i backup-id] [--progress] [-j num-threads] @@ -74,10 +77,11 @@ pg_probackup - utility to manage backup/recovery of PostgreSQL database. [--format=format] pg_probackup delete -B backup-path --instance=instance_name - [--wal] [-i backup-id | --expired] + [--wal] [-i backup-id | --expired | --merge-expired] + [--dry-run] pg_probackup merge -B backup-path --instance=instance_name - -i backup-id + -i backup-id [--progress] [-j num-threads] pg_probackup add-instance -B backup-path -D pgdata-path --instance=instance_name diff --git a/tests/option_test.py b/tests/option_test.py index 5a64a8b6..092c79d9 100644 --- a/tests/option_test.py +++ b/tests/option_test.py @@ -95,7 +95,7 @@ class OptionTest(ProbackupTest, unittest.TestCase): repr(self.output), self.cmd)) except ProbackupException as e: self.assertEqual(e.message, - 'ERROR: You must specify at least one of the delete options: --expired |--wal |--backup_id\n', + 'ERROR: You must specify at least one of the delete options: --expired |--wal |--merge-expired |--delete-invalid |--backup_id\n', '\n Unexpected Error Message: {0}\n CMD: {1}'.format(repr(e.message), self.cmd))