From 7cc2fb70188676406ca883055467aff602438fcd Mon Sep 17 00:00:00 2001 From: Jeevan Chalke Date: Mon, 9 Sep 2019 10:38:01 +0530 Subject: [PATCH v2 1/4] Add support for command line option to pass LSN. This adds [ LSN 'lsn' ] to BASE_BACKUP command and --lsn=LSN to the pg_basebackup binary. Also, add small tests. --- src/backend/replication/basebackup.c | 20 ++++++++++++++++++++ src/backend/replication/repl_gram.y | 6 ++++++ src/backend/replication/repl_scanner.l | 1 + src/bin/pg_basebackup/pg_basebackup.c | 15 +++++++++++++-- src/bin/pg_basebackup/t/010_pg_basebackup.pl | 12 +++++++++++- 5 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c index 6aab8d7..e72bf8e 100644 --- a/src/backend/replication/basebackup.c +++ b/src/backend/replication/basebackup.c @@ -38,6 +38,7 @@ #include "storage/ipc.h" #include "storage/reinit.h" #include "utils/builtins.h" +#include "utils/pg_lsn.h" #include "utils/ps_status.h" #include "utils/relcache.h" #include "utils/timestamp.h" @@ -52,6 +53,7 @@ typedef struct bool includewal; uint32 maxrate; bool sendtblspcmapfile; + XLogRecPtr lsn; } basebackup_options; @@ -652,6 +654,7 @@ parse_basebackup_options(List *options, basebackup_options *opt) bool o_maxrate = false; bool o_tablespace_map = false; bool o_noverify_checksums = false; + bool o_lsn = false; MemSet(opt, 0, sizeof(*opt)); foreach(lopt, options) @@ -740,6 +743,23 @@ parse_basebackup_options(List *options, basebackup_options *opt) noverify_checksums = true; o_noverify_checksums = true; } + else if (strcmp(defel->defname, "lsn") == 0) + { + bool have_error = false; + + if (o_lsn) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("duplicate option \"%s\"", defel->defname))); + o_lsn = true; + + /* Validate given LSN and convert it into XLogRecPtr. */ + opt->lsn = pg_lsn_in_internal(strVal(defel->arg), &have_error); + if (XLogRecPtrIsInvalid(opt->lsn)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid value for LSN"))); + } else elog(ERROR, "option \"%s\" not recognized", defel->defname); diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y index c4e11cc..c24d319 100644 --- a/src/backend/replication/repl_gram.y +++ b/src/backend/replication/repl_gram.y @@ -87,6 +87,7 @@ static SQLCmd *make_sqlcmd(void); %token K_EXPORT_SNAPSHOT %token K_NOEXPORT_SNAPSHOT %token K_USE_SNAPSHOT +%token K_LSN %type command %type base_backup start_replication start_logical_replication @@ -214,6 +215,11 @@ base_backup_opt: $$ = makeDefElem("noverify_checksums", (Node *)makeInteger(true), -1); } + | K_LSN SCONST + { + $$ = makeDefElem("lsn", + (Node *)makeString($2), -1); + } ; create_replication_slot: diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l index 380faeb..77b5af4 100644 --- a/src/backend/replication/repl_scanner.l +++ b/src/backend/replication/repl_scanner.l @@ -107,6 +107,7 @@ EXPORT_SNAPSHOT { return K_EXPORT_SNAPSHOT; } NOEXPORT_SNAPSHOT { return K_NOEXPORT_SNAPSHOT; } USE_SNAPSHOT { return K_USE_SNAPSHOT; } WAIT { return K_WAIT; } +LSN { return K_LSN; } "," { return ','; } ";" { return ';'; } diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c index 7986872..1791853 100644 --- a/src/bin/pg_basebackup/pg_basebackup.c +++ b/src/bin/pg_basebackup/pg_basebackup.c @@ -105,6 +105,7 @@ static bool temp_replication_slot = true; static bool create_slot = false; static bool no_slot = false; static bool verify_checksums = true; +static char *lsn = NULL; static bool success = false; static bool made_new_pgdata = false; @@ -341,6 +342,7 @@ usage(void) " include required WAL files with specified method\n")); printf(_(" -z, --gzip compress tar output\n")); printf(_(" -Z, --compress=0-9 compress tar output with given compression level\n")); + printf(_(" --lsn=LSN incremental backup, using LSN as threshold\n")); printf(_("\nGeneral options:\n")); printf(_(" -c, --checkpoint=fast|spread\n" " set fast or spread checkpointing\n")); @@ -1805,6 +1807,7 @@ BaseBackup(void) maxServerMajor; int serverVersion, serverMajor; + char *lsn_clause = NULL; Assert(conn != NULL); @@ -1871,8 +1874,11 @@ BaseBackup(void) fprintf(stderr, "\n"); } + if (lsn) + lsn_clause = psprintf("LSN '%s'", lsn); + basebkp = - psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s", + psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s %s", escaped_label, showprogress ? "PROGRESS" : "", includewal == FETCH_WAL ? "WAL" : "", @@ -1880,7 +1886,8 @@ BaseBackup(void) includewal == NO_WAL ? "" : "NOWAIT", maxrate_clause ? maxrate_clause : "", format == 't' ? "TABLESPACE_MAP" : "", - verify_checksums ? "" : "NOVERIFY_CHECKSUMS"); + verify_checksums ? "" : "NOVERIFY_CHECKSUMS", + lsn_clause ? lsn_clause : ""); if (PQsendQuery(conn, basebkp) == 0) { @@ -2199,6 +2206,7 @@ main(int argc, char **argv) {"waldir", required_argument, NULL, 1}, {"no-slot", no_argument, NULL, 2}, {"no-verify-checksums", no_argument, NULL, 3}, + {"lsn", required_argument, NULL, 4}, {NULL, 0, NULL, 0} }; int c; @@ -2367,6 +2375,9 @@ main(int argc, char **argv) case 3: verify_checksums = false; break; + case 4: + lsn = pg_strdup(optarg); + break; default: /* diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl index b7d36b6..fd8e187 100644 --- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl +++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl @@ -6,7 +6,7 @@ use File::Basename qw(basename dirname); use File::Path qw(rmtree); use PostgresNode; use TestLib; -use Test::More tests => 106; +use Test::More tests => 108; program_help_ok('pg_basebackup'); program_version_ok('pg_basebackup'); @@ -556,5 +556,15 @@ $node->command_ok( 'pg_basebackup with -k does not report checksum mismatch'); rmtree("$tempdir/backup_corrupt4"); +# check LSN +$node->command_fails( + [ 'pg_basebackup', '-D', "$tempdir/lsn_test", '--lsn', "0/INVALID" ], + 'pg_basebackup with invalid LSN fails'); +$node->command_ok( + [ 'pg_basebackup', '-D', "$tempdir/lsn_test", '--lsn', "0/ABCDEF01", '--no-verify-checksums' ], + 'pg_basebackup with valid LSN'); +rmtree("$tempdir/lsn_test"); + + $node->safe_psql('postgres', "DROP TABLE corrupt1;"); $node->safe_psql('postgres', "DROP TABLE corrupt2;"); -- 1.8.3.1