From 211e4d3f2a63fe5ba3db36661be2bd0375bdab48 Mon Sep 17 00:00:00 2001 From: amit Date: Tue, 2 Oct 2018 15:13:39 +0900 Subject: [PATCH] Added a version numbering system for backup format With this change, pg_rman will write a "version" number to a designated file when initiliazing the backup directory. From now on, every change to the backup file format is to be accompanied by an "increment" of backup_catalog_version. --- catalog.c | 40 ++++++++++++++++++++++++++++++++++++++++ expected/init.out | 3 +++ init.c | 11 +++++++++++ pg_rman.c | 3 +++ pg_rman.h | 31 +++++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+) diff --git a/catalog.c b/catalog.c index 9c529325..ebb7c707 100644 --- a/catalog.c +++ b/catalog.c @@ -29,6 +29,12 @@ static pgBackup *catalog_read_ini(const char *path); static int lock_fd = -1; +/* + * Catalog version as read from the catalog_version file of the backup + * catalog. + */ +uint32 catalog_version_num = 0; + /* * system_identifier as read from the control file of the database cluster */ @@ -666,6 +672,40 @@ catalog_init_config(pgBackup *backup) backup->write_bytes = BYTES_INVALID; } +void +catalog_init_version(void) +{ + char path[MAXPGPATH]; + FILE *fp; + + join_path_components(path, backup_path, CATALOG_VERSION_FILE); + fp = pgut_fopen(path, "rt", true); + + /* + * Not throwing an error on fp == NULL is on purpose. We assume + * catalog versioning is not enabled in that case. + */ + if (fp != NULL) + { + char buf[128], + key[64], + value[64]; + + while (fgets(buf, lengthof(buf), fp) != NULL) + { + size_t i; + for (i = strlen(buf); i > 0 && IsSpace(buf[i - 1]); i--) + buf[i - 1] = '\0'; + if (parse_pair(buf, key, value)) + { + catalog_version_num = strtoul(value, NULL, 10); + elog(DEBUG, "catalog vesion = %u", catalog_version_num); + } + } + fclose(fp); + } +} + void check_system_identifier() { diff --git a/expected/init.out b/expected/init.out index 18993d38..bf36ceb3 100644 --- a/expected/init.out +++ b/expected/init.out @@ -4,6 +4,7 @@ 0 results/init/backup/ results/init/backup/backup/ +results/init/backup/backup_catalog_version results/init/backup/backup/pg_wal/ results/init/backup/backup/srvlog/ results/init/backup/pg_rman.ini @@ -14,6 +15,7 @@ results/init/backup/timeline_history/ 0 results/init/backup/ results/init/backup/backup/ +results/init/backup/backup_catalog_version results/init/backup/backup/pg_wal/ results/init/backup/backup/srvlog/ results/init/backup/pg_rman.ini @@ -27,6 +29,7 @@ HINT: Please set ARCLOG_PATH in pg_rman.ini or environmental variable. 0 results/init/backup/ results/init/backup/backup/ +results/init/backup/backup_catalog_version results/init/backup/backup/pg_wal/ results/init/backup/backup/srvlog/ results/init/backup/pg_rman.ini diff --git a/init.c b/init.c index a2ba3178..772d38d4 100644 --- a/init.c +++ b/init.c @@ -61,6 +61,17 @@ do_init(void) /* create backup catalog root directory */ dir_create_dir(backup_path, DIR_PERMISSION); + /* remember the catalog version number */ + join_path_components(path, backup_path, CATALOG_VERSION_FILE); + fp = fopen(path, "wt"); + if (fp == NULL) + ereport(ERROR, + (errcode(ERROR_SYSTEM), + errmsg("could not create catalog version file: %s", strerror(errno)))); + else + fprintf(fp, "CATALOG_VERSION='%u'", CATALOG_VERSION_NUM); + fclose(fp); + /* create directories for backup of online files */ join_path_components(path, backup_path, RESTORE_WORK_DIR); dir_create_dir(path, DIR_PERMISSION); diff --git a/pg_rman.c b/pg_rman.c index f520950f..e18c89b1 100644 --- a/pg_rman.c +++ b/pg_rman.c @@ -126,6 +126,9 @@ main(int argc, char *argv[]) (errcode(ERROR_ARGS), errmsg("required parameter not specified: BACKUP_PATH (-B, --backup-path)"))); + /* initialize catalog format version (backup_path must be known) */ + catalog_init_version(); + for (; i < argc; i++) { if (cmd == NULL) diff --git a/pg_rman.h b/pg_rman.h index 7044ead1..fd419ee5 100644 --- a/pg_rman.h +++ b/pg_rman.h @@ -44,6 +44,36 @@ #define PG_TBLSPC_MAP_FILE "tablespace_map" #define PG_BLACK_LIST "black_list" +/* + * Catalog versioning: + * + * CATALOG_VERSION_NUM is updated every time we add/remove files to/from + * the backup directory. A valid catalog version number is an integer > 0, + * as far as the code checking the version number is concerned. The exact + * value to set it to when updating the catalog is YYYYMMDDN, where + * YYYY-MM-DD is the date when the change is made and N is equal to the + * number of changes made on that day. + * + * pg_rman init writes the current CATALOG_VERSION_NUM to the file + * CATALOG_VERSION_FILE in the top backup directory. The value contained in + * the file is read at startup into catalog_version_num. If the file is not + * found, catalog_version_num is set to 0, which is to preserve compatibility + * with backup directories created with older pg_rman binaries. (If someone + * deletes the file manually, they should not expect some features of pg_rman + * to work correctly.) + * + * The code that checks the existence of a particular file of the backup + * directory (a file that is part of the backup catalog, not some file + * contained in a backup) must check whether the version number read from + * the catalog version file (if one exists) is >= catalog version number + * that introduced that file; if not, an error is thrown. + */ +#define CATALOG_VERSION_NUM 201810021 + +extern uint32 catalog_version_num; + +#define CATALOG_VERSION_FILE "backup_catalog_version" + /* Snapshot script command */ #define SNAPSHOT_FREEZE "freeze" #define SNAPSHOT_UNFREEZE "unfreeze" @@ -294,6 +324,7 @@ extern int catalog_lock(void); extern void catalog_unlock(void); extern void catalog_init_config(pgBackup *backup); +extern void catalog_init_version(void); extern void check_system_identifier(void); extern TimeLineID get_current_timeline(void);