From 9f2ad9d822951e3558e0554ce9246b16692ae674 Mon Sep 17 00:00:00 2001 From: stalkerg Date: Mon, 31 Oct 2016 18:19:11 +0300 Subject: [PATCH] Remove date range and start use base36 from start_time as backup ID. --- backup.c | 2 +- catalog.c | 79 +++++++++--------------------------- delete.c | 12 +++--- pg_arman.c | 109 +++++--------------------------------------------- pg_arman.h | 21 +++------- restore.c | 2 +- show.c | 21 +++++----- sql/common.sh | 4 +- util.c | 22 +++++++++- validate.c | 4 +- 10 files changed, 78 insertions(+), 198 deletions(-) diff --git a/backup.c b/backup.c index 12b97b1d..326daadc 100644 --- a/backup.c +++ b/backup.c @@ -497,7 +497,7 @@ do_backup(pgBackupOption bkupopt) elog(LOG, "backup destination is initialized"); /* get list of backups already taken */ - backup_list = catalog_get_backup_list(NULL); + backup_list = catalog_get_backup_list(0); if (!backup_list) elog(ERROR, "cannot process any more"); diff --git a/catalog.c b/catalog.c index d7a5370f..9533e93e 100644 --- a/catalog.c +++ b/catalog.c @@ -106,32 +106,14 @@ IsDir(const char *dirpath, const char *entry) * The list is sorted in order of descending start time. */ parray * -catalog_get_backup_list(const pgBackupRange *range) +catalog_get_backup_list(time_t backup_id) { - const pgBackupRange range_all = { 0, 0 }; DIR *date_dir = NULL; struct dirent *date_ent = NULL; DIR *time_dir = NULL; - struct dirent *time_ent = NULL; char date_path[MAXPGPATH]; parray *backups = NULL; pgBackup *backup = NULL; - struct tm *tm; - char begin_date[100]; - char begin_time[100]; - char end_date[100]; - char end_time[100]; - - if (range == NULL) - range = &range_all; - - /* make date/time string */ - tm = localtime(&range->begin); - strftime(begin_date, lengthof(begin_date), "%Y%m%d", tm); - strftime(begin_time, lengthof(begin_time), "%H%M%S", tm); - tm = localtime(&range->end); - strftime(end_date, lengthof(end_date), "%Y%m%d", tm); - strftime(end_time, lengthof(end_time), "%H%M%S", tm); /* open backup root directory */ date_dir = opendir(backup_path); @@ -146,6 +128,8 @@ catalog_get_backup_list(const pgBackupRange *range) backups = parray_new(); for (; (date_ent = readdir(date_dir)) != NULL; errno = 0) { + char ini_path[MAXPGPATH]; + /* skip not-directory entries and hidden entries */ if (!IsDir(backup_path, date_ent->d_name) || date_ent->d_name[0] == '.') continue; @@ -154,46 +138,23 @@ catalog_get_backup_list(const pgBackupRange *range) if (strcmp(date_ent->d_name, RESTORE_WORK_DIR) == 0) continue; - /* If the date is out of range, skip it. */ - if (pgBackupRangeIsValid(range) && - (strcmp(begin_date, date_ent->d_name) > 0 || - strcmp(end_date, date_ent->d_name) < 0)) - continue; - /* open subdirectory (date directory) and search time directory */ join_path_components(date_path, backup_path, date_ent->d_name); - time_dir = opendir(date_path); - if (time_dir == NULL) + + /* read backup information from backup.ini */ + snprintf(ini_path, MAXPGPATH, "%s/%s", date_path, BACKUP_INI_FILE); + backup = catalog_read_ini(ini_path); + + /* ignore corrupted backup */ + if (backup) { - elog(WARNING, "cannot open directory \"%s\": %s", - date_ent->d_name, strerror(errno)); - goto err_proc; - } - for (; (time_ent = readdir(time_dir)) != NULL; errno = 0) - { - char ini_path[MAXPGPATH]; - - /* skip entries that are directories and hidden directories */ - if (!IsDir(date_path, time_ent->d_name) || time_ent->d_name[0] == '.') - continue; - - /* If the time is out of range, skip it. */ - if (pgBackupRangeIsValid(range) && - (strcmp(begin_time, time_ent->d_name) > 0 || - strcmp(end_time, time_ent->d_name) < 0)) - continue; - - /* read backup information from backup.ini */ - snprintf(ini_path, MAXPGPATH, "%s/%s/%s", date_path, - time_ent->d_name, BACKUP_INI_FILE); - backup = catalog_read_ini(ini_path); - - /* ignore corrupted backup */ - if (backup) + if (backup_id != 0 && backup_id != backup->start_time) { - parray_append(backups, backup); - backup = NULL; + pgBackupFree(backup); + continue; } + parray_append(backups, backup); + backup = NULL; } if (errno && errno != ENOENT) { @@ -201,8 +162,6 @@ catalog_get_backup_list(const pgBackupRange *range) date_ent->d_name, strerror(errno)); goto err_proc; } - closedir(time_dir); - time_dir = NULL; } if (errno) { @@ -526,16 +485,14 @@ pgBackupCompareIdDesc(const void *l, const void *r) void pgBackupGetPath(const pgBackup *backup, char *path, size_t len, const char *subdir) { - char datetime[20]; - struct tm *tm; + char *datetime; - /* generate $BACKUP_PATH/date/time path */ - tm = localtime(&backup->start_time); - strftime(datetime, lengthof(datetime), "%Y%m%d/%H%M%S", tm); + datetime = base36enc(backup->start_time); if (subdir) snprintf(path, len, "%s/%s/%s", backup_path, datetime, subdir); else snprintf(path, len, "%s/%s", backup_path, datetime); + free(datetime); } void diff --git a/delete.c b/delete.c index 672d87ac..575f74e9 100644 --- a/delete.c +++ b/delete.c @@ -15,17 +15,17 @@ static int pgBackupDeleteFiles(pgBackup *backup); int -do_delete(pgBackupRange *range) +do_delete(time_t backup_id) { int i; int ret; - parray *backup_list; + parray *backup_list; bool do_delete = false; XLogRecPtr oldest_lsn = InvalidXLogRecPtr; TimeLineID oldest_tli; /* DATE are always required */ - if (!pgBackupRangeIsValid(range)) + if (backup_id == 0) elog(ERROR, "required delete range option not specified: delete DATE"); /* Lock backup catalog */ @@ -37,7 +37,7 @@ do_delete(pgBackupRange *range) "another pg_arman is running, stop delete."); /* Get complete list of backups */ - backup_list = catalog_get_backup_list(NULL); + backup_list = catalog_get_backup_list(0); if (!backup_list) elog(ERROR, "No backup list found, can't process any more."); @@ -60,7 +60,7 @@ do_delete(pgBackupRange *range) /* Found the latest full backup */ if (backup->backup_mode >= BACKUP_MODE_FULL && backup->status == BACKUP_STATUS_OK && - backup->start_time <= range->begin) + backup->start_time <= backup_id) { do_delete = true; oldest_lsn = backup->start_lsn; @@ -192,7 +192,7 @@ pgBackupDelete(int keep_generations, int keep_days) } /* Get a complete list of backups. */ - backup_list = catalog_get_backup_list(NULL); + backup_list = catalog_get_backup_list(0); /* Find target backups to be deleted */ backup_num = 0; diff --git a/pg_arman.c b/pg_arman.c index a9b96745..f21c996d 100644 --- a/pg_arman.c +++ b/pg_arman.c @@ -50,7 +50,6 @@ static TimeLineID target_tli; static bool show_all = false; static void opt_backup_mode(pgut_option *opt, const char *arg); -static void parse_range(pgBackupRange *range, const char *arg1, const char *arg2); static pgut_option options[] = { @@ -87,9 +86,8 @@ int main(int argc, char *argv[]) { const char *cmd = NULL; - const char *range1 = NULL; - const char *range2 = NULL; - pgBackupRange range; + const char *backup_id_string = NULL; + time_t backup_id = 0; int i; /* do not buffer progress messages */ @@ -110,10 +108,8 @@ main(int argc, char *argv[]) strcmp(cmd, "validate") != 0 && strcmp(cmd, "delete") != 0) break; - } else if (range1 == NULL) - range1 = argv[i]; - else if (range2 == NULL) - range2 = argv[i]; + } else if (backup_id_string == NULL) + backup_id_string = argv[i]; else elog(ERROR, "too many arguments"); } @@ -125,13 +121,8 @@ main(int argc, char *argv[]) return 1; } - /* get object range argument if any */ - if (range1 && range2) - parse_range(&range, range1, range2); - else if (range1) - parse_range(&range, range1, ""); - else - range.begin = range.end = 0; + if (backup_id_string != NULL) + backup_id = base36dec(backup_id_string); /* Read default configuration from file. */ if (backup_path) @@ -195,20 +186,17 @@ main(int argc, char *argv[]) if (res != 0) return res; - /* If validation has been requested, do it */ - range.begin = current.start_time; - range.end = current.start_time + 1; - do_validate(&range); + do_validate(current.start_time); } else if (pg_strcasecmp(cmd, "restore") == 0) return do_restore(target_time, target_xid, target_inclusive, target_tli); else if (pg_strcasecmp(cmd, "show") == 0) - return do_show(&range, show_all); + return do_show(backup_id, show_all); else if (pg_strcasecmp(cmd, "validate") == 0) - return do_validate(&range); + return do_validate(backup_id); else if (pg_strcasecmp(cmd, "delete") == 0) - return do_delete(&range); + return do_delete(backup_id); else elog(ERROR, "invalid command \"%s\"", cmd); @@ -253,83 +241,6 @@ pgut_help(bool details) printf(_(" -a, --show-all show deleted backup too\n")); } -/* - * Create range object from one or two arguments. - * All not-digit characters in the argument(s) are ignored. - * Both arg1 and arg2 must be valid pointer. - */ -static void -parse_range(pgBackupRange *range, const char *arg1, const char *arg2) -{ - size_t len = strlen(arg1) + strlen(arg2) + 1; - char *tmp; - int num; - struct tm tm; - - tmp = pgut_malloc(len); - tmp[0] = '\0'; - if (arg1 != NULL) - remove_not_digit(tmp, len, arg1); - if (arg2 != NULL) - remove_not_digit(tmp + strlen(tmp), len - strlen(tmp), arg2); - - memset(&tm, 0, sizeof(tm)); - tm.tm_year = 0; /* tm_year is year - 1900 */ - tm.tm_mon = 0; /* tm_mon is 0 - 11 */ - tm.tm_mday = 1; /* tm_mday is 1 - 31 */ - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - num = sscanf(tmp, "%04d %02d %02d %02d %02d %02d", - &tm.tm_year, &tm.tm_mon, &tm.tm_mday, - &tm.tm_hour, &tm.tm_min, &tm.tm_sec); - - if (num < 1) - { - if (strcmp(tmp,"") != 0) - elog(ERROR, "supplied id(%s) is invalid", tmp); - else - elog(ERROR, "arguments are invalid. near \"%s\"", arg1); - } - - free(tmp); - - /* adjust year and month to convert to time_t */ - tm.tm_year -= 1900; - if (num > 1) - tm.tm_mon -= 1; - tm.tm_isdst = -1; - - if (!IsValidTime(tm)) - elog(ERROR, "supplied time(%s) is invalid.", arg1); - - range->begin = mktime(&tm); - - switch (num) - { - case 1: - tm.tm_year++; - break; - case 2: - tm.tm_mon++; - break; - case 3: - tm.tm_mday++; - break; - case 4: - tm.tm_hour++; - break; - case 5: - tm.tm_min++; - break; - case 6: - tm.tm_sec++; - break; - } - range->end = mktime(&tm); - range->end--; -} - static void opt_backup_mode(pgut_option *opt, const char *arg) { diff --git a/pg_arman.h b/pg_arman.h index d6300a73..2c43e86d 100644 --- a/pg_arman.h +++ b/pg_arman.h @@ -66,17 +66,6 @@ typedef struct pgFile datapagemap_t pagemap; } pgFile; -typedef struct pgBackupRange -{ - time_t begin; - time_t end; /* begin +1 when one backup is target */ -} pgBackupRange; - -#define pgBackupRangeIsValid(range) \ - (((range)->begin != (time_t) 0) || ((range)->end != (time_t) 0)) -#define pgBackupRangeIsSingle(range) \ - (pgBackupRangeIsValid(range) && (range)->begin == ((range)->end)) - #define IsValidTime(tm) \ ((tm.tm_sec >= 0 && tm.tm_sec <= 60) && /* range check for tm_sec (0-60) */ \ (tm.tm_min >= 0 && tm.tm_min <= 59) && /* range check for tm_min (0-59) */ \ @@ -233,10 +222,10 @@ extern int do_restore(const char *target_time, extern int do_init(void); /* in show.c */ -extern int do_show(pgBackupRange *range, bool show_all); +extern int do_show(time_t backup_id, bool show_all); /* in delete.c */ -extern int do_delete(pgBackupRange *range); +extern int do_delete(time_t backup_id); extern void pgBackupDelete(int keep_generations, int keep_days); /* in fetch.c */ @@ -246,14 +235,14 @@ extern char *slurpFile(const char *datadir, bool safe); /* in validate.c */ -extern int do_validate(pgBackupRange *range); +extern int do_validate(time_t backup_id); extern void pgBackupValidate(pgBackup *backup, bool size_only, bool for_get_timeline); /* in catalog.c */ extern pgBackup *catalog_get_backup(time_t timestamp); -extern parray *catalog_get_backup_list(const pgBackupRange *range); +extern parray *catalog_get_backup_list(time_t backup_id); extern pgBackup *catalog_get_last_data_backup(parray *backup_list, TimeLineID tli); @@ -315,6 +304,8 @@ extern void remove_trailing_space(char *buf, int comment_mark); extern void remove_not_digit(char *buf, size_t len, const char *str); extern XLogRecPtr get_last_ptrack_lsn(void); extern uint32 get_data_checksum_version(bool safe); +extern char *base36enc(long unsigned int value); +extern long unsigned int base36dec(const char *text); /* in status.c */ extern bool is_pg_running(void); diff --git a/restore.c b/restore.c index 5936a925..521c7f10 100644 --- a/restore.c +++ b/restore.c @@ -89,7 +89,7 @@ do_restore(const char *target_time, elog(ERROR, "cannot create recovery.conf. specified args are invalid."); /* get list of backups. (index == 0) is the last backup */ - backups = catalog_get_backup_list(NULL); + backups = catalog_get_backup_list(0); if (!backups) elog(ERROR, "cannot process any more."); diff --git a/show.c b/show.c index 94640484..437df632 100644 --- a/show.c +++ b/show.c @@ -18,22 +18,22 @@ static void show_backup_detail(FILE *out, pgBackup *backup); * backup indicated by id. */ int -do_show(pgBackupRange *range, bool show_all) +do_show(time_t backup_id, bool show_all) { /* * Safety check for archive folder, this is necessary to fetch * the parent TLI from history field generated by server after * child timeline is chosen. */ - if (pgBackupRangeIsSingle(range)) + if (backup_id != 0) { pgBackup *backup; - backup = catalog_get_backup(range->begin); + backup = catalog_get_backup(backup_id); if (backup == NULL) { char timestamp[100]; - time2iso(timestamp, lengthof(timestamp), range->begin); + time2iso(timestamp, lengthof(timestamp), backup_id); elog(INFO, "backup taken at \"%s\" does not exist.", timestamp); /* This is not error case */ @@ -48,7 +48,7 @@ do_show(pgBackupRange *range, bool show_all) { parray *backup_list; - backup_list = catalog_get_backup_list(range); + backup_list = catalog_get_backup_list(backup_id); if (backup_list == NULL) elog(ERROR, "can't process any more."); @@ -165,9 +165,9 @@ show_backup_list(FILE *out, parray *backup_list, bool show_all) int i; /* show header */ - fputs("==========================================================================\n", out); - fputs("Start Mode Current TLI Parent TLI Time Data Status \n", out); - fputs("==========================================================================\n", out); + fputs("===================================================================================\n", out); + fputs("ID Stop Mode Current TLI Parent TLI Time Data Status \n", out); + fputs("===================================================================================\n", out); for (i = 0; i < parray_num(backup_list); i++) { @@ -184,7 +184,7 @@ show_backup_list(FILE *out, parray *backup_list, bool show_all) if (backup->status == BACKUP_STATUS_DELETED && !show_all) continue; - time2iso(timestamp, lengthof(timestamp), backup->start_time); + time2iso(timestamp, lengthof(timestamp), backup->end_time); if (backup->end_time != (time_t) 0) snprintf(duration, lengthof(duration), "%lum", (backup->end_time - backup->start_time) / 60); @@ -200,7 +200,8 @@ show_backup_list(FILE *out, parray *backup_list, bool show_all) /* Get parent timeline before printing */ parent_tli = get_parent_tli(backup->tli); - fprintf(out, "%-19s %-6s %10d %10d %5s %6s %s \n", + fprintf(out, "%-8s %-19s %-6s %10d %10d %5s %6s %s \n", + base36enc(backup->start_time), timestamp, modes[backup->backup_mode], backup->tli, diff --git a/sql/common.sh b/sql/common.sh index 5e69d20e..67d8a1d4 100644 --- a/sql/common.sh +++ b/sql/common.sh @@ -95,8 +95,8 @@ function get_time_last_backup() name_os=`uname` if [ "$name_os" == "SunOS" ] then - pg_arman -B ${BACKUP_PATH} show | gtail -n +4 | head -n 1 | awk '{print($1, $2)}' + pg_arman -B ${BACKUP_PATH} show | gtail -n +4 | head -n 1 | awk '{print($1)}' else - pg_arman -B ${BACKUP_PATH} show | tail -n +4 | head -n 1 | awk '{print($1, $2)}' + pg_arman -B ${BACKUP_PATH} show | tail -n +4 | head -n 1 | awk '{print($1)}' fi } diff --git a/util.c b/util.c index f053ac34..be22ac26 100644 --- a/util.c +++ b/util.c @@ -13,6 +13,26 @@ #include "storage/bufpage.h" +char *base36enc(long unsigned int value) +{ + char base36[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + /* log(2**64) / log(36) = 12.38 => max 13 char + '\0' */ + char buffer[14]; + unsigned int offset = sizeof(buffer); + + buffer[--offset] = '\0'; + do { + buffer[--offset] = base36[value % 36]; + } while (value /= 36); + + return strdup(&buffer[offset]); // warning: this must be free-d by the user +} + +long unsigned int base36dec(const char *text) +{ + return strtoul(text, NULL, 36); +} + static void checkControlFile(ControlFileData *ControlFile) { @@ -24,7 +44,7 @@ checkControlFile(ControlFileData *ControlFile) FIN_CRC32C(crc); /* Then compare it */ - if (!EQ_CRC32C(crc, ControlFile->crc)) + if (!EQ_CRC32C(crc, ControlFile->crc)) elog(ERROR, "Calculated CRC checksum does not match value stored in file.\n" "Either the file is corrupt, or it has a different layout than this program\n" "is expecting. The results below are untrustworthy."); diff --git a/validate.c b/validate.c index 7f9cead8..61fe9c68 100644 --- a/validate.c +++ b/validate.c @@ -18,7 +18,7 @@ static bool pgBackupValidateFiles(parray *files, const char *root, bool size_onl * If any of files are corrupted, update its stutus to CORRUPT. */ int -do_validate(pgBackupRange *range) +do_validate(time_t backup_id) { int i; parray *backup_list; @@ -30,7 +30,7 @@ do_validate(pgBackupRange *range) another_pg_arman = true; /* get backup list matches given range */ - backup_list = catalog_get_backup_list(range); + backup_list = catalog_get_backup_list(backup_id); if (!backup_list) elog(ERROR, "cannot process any more.");