1
0
mirror of https://github.com/postgrespro/pg_probackup.git synced 2025-02-08 14:28:36 +02:00

- Fix possible broken backup which is getting from standby.

Use --standby-host and --standby-port, if backup is getting from standby.
- Add --hard-copy restore option.
  The option can be used to copy archive WAL to archive directory instead of symlink.



git-svn-id: http://pg-rman.googlecode.com/svn/trunk@77 182aca00-e38e-11de-a668-6fd11605f5ce
This commit is contained in:
otsuka.knj@gmail.com 2013-09-09 09:00:13 +00:00
parent 40fb3560e5
commit 0144cc4fd9
15 changed files with 345 additions and 95 deletions

View File

@ -1,5 +1,5 @@
# SPEC file for pg_rman
# Copyright(C) 2009-2010 NIPPON TELEGRAPH AND TELEPHONE CORPORATION
# Copyright(C) 2009-2013 NIPPON TELEGRAPH AND TELEPHONE CORPORATION
%define _pgdir /usr/pgsql-9.0
%define _bindir %{_pgdir}/bin
@ -9,7 +9,7 @@
## Set general information for pg_rman.
Summary: Backup and Recovery Tool for PostgreSQL
Name: pg_rman
Version: 1.2.5
Version: 1.2.6
Release: 1%{?dist}
License: BSD
Group: Applications/Databases
@ -58,7 +58,8 @@ rm -rf %{buildroot}
# History of pg_rman.
%changelog
* Mon Sep 2 2013 - NTT OSS Center <otsuka.kenji@lab.ntt.co.jp> 1.2.6-1
- Update to 1.2.6
* Wed Nov 10 2010 - NTT OSS Center <tomonari.katsumata@oss.ntt.co.jp> 1.2.0-1
* Wed Dec 9 2009 - NTT OSS Center <itagaki.takahiro@oss.ntt.co.jp> 1.1.1-1
- Initial cut for 1.1.1

View File

@ -1,5 +1,5 @@
# SPEC file for pg_rman
# Copyright(C) 2009-2011 NIPPON TELEGRAPH AND TELEPHONE CORPORATION
# Copyright(C) 2009-2013 NIPPON TELEGRAPH AND TELEPHONE CORPORATION
%define _pgdir /usr/pgsql-9.1
%define _bindir %{_pgdir}/bin
@ -9,7 +9,7 @@
## Set general information for pg_rman.
Summary: Backup and Recovery Tool for PostgreSQL
Name: pg_rman
Version: 1.2.5
Version: 1.2.6
Release: 1%{?dist}
License: BSD
Group: Applications/Databases
@ -58,7 +58,8 @@ rm -rf %{buildroot}
# History of pg_rman.
%changelog
* Mon Sep 2 2013 - NTT OSS Center <otsuka.kenji@lab.ntt.co.jp> 1.2.6-1
- Update to 1.2.6
* Wed Nov 10 2010 - NTT OSS Center <tomonari.katsumata@oss.ntt.co.jp> 1.2.0-1
* Wed Dec 9 2009 - NTT OSS Center <itagaki.takahiro@oss.ntt.co.jp> 1.1.1-1
- Initial cut for 1.1.1

View File

@ -1,5 +1,5 @@
# SPEC file for pg_rman
# Copyright(C) 2009-2012 NIPPON TELEGRAPH AND TELEPHONE CORPORATION
# Copyright(C) 2009-2013 NIPPON TELEGRAPH AND TELEPHONE CORPORATION
%define _pgdir /usr/pgsql-9.2
%define _bindir %{_pgdir}/bin
@ -9,7 +9,7 @@
## Set general information for pg_rman.
Summary: Backup and Recovery Tool for PostgreSQL
Name: pg_rman
Version: 1.2.5
Version: 1.2.6
Release: 1%{?dist}
License: BSD
Group: Applications/Databases
@ -58,7 +58,8 @@ rm -rf %{buildroot}
# History of pg_rman.
%changelog
* Mon Sep 2 2013 - NTT OSS Center <otsuka.kenji@lab.ntt.co.jp> 1.2.6-1
- Update to 1.2.6
* Wed Nov 10 2010 - NTT OSS Center <tomonari.katsumata@oss.ntt.co.jp> 1.2.0-1
* Wed Dec 9 2009 - NTT OSS Center <itagaki.takahiro@oss.ntt.co.jp> 1.1.1-1
- Initial cut for 1.1.1

170
backup.c
View File

@ -2,7 +2,7 @@
*
* backup.c: backup DB cluster, archived WAL, serverlog.
*
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2013, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -33,20 +33,22 @@ static void delete_old_files(const char *root, parray *files, int keep_files,
int keep_days, int server_version, bool is_arclog);
static void backup_files(const char *from_root, const char *to_root,
parray *files, parray *prev_files, const XLogRecPtr *lsn, bool compress, const char *prefix);
static parray *do_backup_database(parray *backup_list, bool smooth_checkpoint);
static parray *do_backup_database(parray *backup_list, pgBackupOption bkupopt);
static parray *do_backup_arclog(parray *backup_list);
static parray *do_backup_srvlog(parray *backup_list);
static void remove_stopinfo_from_backup_label(char *history_file, char *bkup_label);
static void make_backup_label(parray *backup_list);
static void confirm_block_size(const char *name, int blcksz);
static void pg_start_backup(const char *label, bool smooth, pgBackup *backup);
static void pg_stop_backup(pgBackup *backup);
static void pg_switch_xlog(pgBackup *backup);
static void get_lsn(PGresult *res, TimeLineID *timeline, XLogRecPtr *lsn);
static void get_xid(PGresult *res, uint32 *xid);
static bool execute_restartpoint(pgBackupOption bkupopt);
static void delete_arclog_link(void);
static void delete_online_wal_backup(void);
static bool fileExists(const char *path);
static bool dirExists(const char *path);
static void execute_freeze(void);
@ -65,7 +67,7 @@ static void create_file_list(parray *files, const char *root, const char *prefix
* Take a backup of database.
*/
static parray *
do_backup_database(parray *backup_list, bool smooth_checkpoint)
do_backup_database(parray *backup_list, pgBackupOption bkupopt)
{
int i;
parray *files; /* backup file list from non-snapshot */
@ -75,6 +77,11 @@ do_backup_database(parray *backup_list, bool smooth_checkpoint)
char label[1024];
XLogRecPtr *lsn = NULL;
char prev_file_txt[MAXPGPATH]; /* path of the previous backup list file */
bool has_backup_label = true; /* flag if backup_label is there */
bool has_recovery_conf = false; /* flag if recovery.conf is there */
/* repack the options */
bool smooth_checkpoint = bkupopt.smooth_checkpoint;
if (!HAVE_DATABASE(&current)) {
/* check if arclog backup. if arclog backup and no suitable full backup, */
@ -112,14 +119,34 @@ do_backup_database(parray *backup_list, bool smooth_checkpoint)
snprintf(path, lengthof(path), "%s/backup_label", pgdata);
make_native_path(path);
if (!fileExists(path)) {
snprintf(path, lengthof(path), "%s/recovery.conf", pgdata);
make_native_path(path);
if (!fileExists(path)) {
if (verbose)
printf(_("backup_label does not exist, stop backup\n"));
has_backup_label = false;
}
snprintf(path, lengthof(path), "%s/recovery.conf", pgdata);
make_native_path(path);
if (fileExists(path)) {
has_recovery_conf = true;
}
if (!has_backup_label && !has_recovery_conf)
{
if (verbose)
printf(_("backup_label does not exist, stop backup\n"));
pg_stop_backup(NULL);
elog(ERROR_SYSTEM, _("backup_label does not exist in PGDATA."));
}
else if (has_recovery_conf)
{
if (!bkupopt.standby_host || !bkupopt.standby_port)
{
pg_stop_backup(NULL);
elog(ERROR_SYSTEM, _("backup_label does not exist in PGDATA."));
elog(ERROR_SYSTEM, _("could not specified standby host or port."));
}
if (!execute_restartpoint(bkupopt))
{
pg_stop_backup(NULL);
elog(ERROR_SYSTEM, _("could not execute restartpoint."));
}
current.is_from_standby = true;
}
/*
@ -411,6 +438,11 @@ do_backup_database(parray *backup_list, bool smooth_checkpoint)
/* notify end of backup */
pg_stop_backup(&current);
/* if backup is from standby, making backup_label from */
/* backup.history file. */
if (current.is_from_standby)
make_backup_label(files);
/* create file list */
create_file_list(files, pgdata, NULL, false);
}
@ -437,6 +469,25 @@ do_backup_database(parray *backup_list, bool smooth_checkpoint)
return files;
}
static bool
execute_restartpoint(pgBackupOption bkupopt)
{
PGconn *sby_conn = NULL;
const char *tmp_host;
const char *tmp_port;
tmp_host = pgut_get_host();
tmp_port = pgut_get_port();
pgut_set_host(bkupopt.standby_host);
pgut_set_port(bkupopt.standby_port);
sby_conn = reconnect_elevel(ERROR_PG_CONNECT);
if (!sby_conn)
return false;
command("CHECKPOINT", 0, NULL);
pgut_set_host(tmp_host);
pgut_set_port(tmp_port);
return true;
}
/*
* backup archived WAL incrementally.
*/
@ -653,13 +704,7 @@ do_backup_srvlog(parray *backup_list)
}
int
do_backup(bool smooth_checkpoint,
int keep_arclog_files,
int keep_arclog_days,
int keep_srvlog_files,
int keep_srvlog_days,
int keep_data_generations,
int keep_data_days)
do_backup(pgBackupOption bkupopt)
{
parray *backup_list;
parray *files_database;
@ -668,6 +713,14 @@ do_backup(bool smooth_checkpoint,
int server_version;
int ret;
/* repack the necesary options */
int keep_arclog_files = bkupopt.keep_arclog_files;
int keep_arclog_days = bkupopt.keep_arclog_days;
int keep_srvlog_files = bkupopt.keep_srvlog_files;
int keep_srvlog_days = bkupopt.keep_srvlog_days;
int keep_data_generations = bkupopt.keep_data_generations;
int keep_data_days = bkupopt.keep_data_days;
/* PGDATA and BACKUP_MODE are always required */
if (pgdata == NULL)
elog(ERROR_ARGS, _("required parameter not specified: PGDATA (-D, --pgdata)"));
@ -731,8 +784,9 @@ do_backup(bool smooth_checkpoint,
current.write_bytes = 0; /* write_bytes is valid always */
current.block_size = BLCKSZ;
current.wal_block_size = XLOG_BLCKSZ;
current.recovery_xid = 0;
current.recovery_time = (time_t) 0;
current.recovery_xid = 0;
current.recovery_time = (time_t) 0;
current.is_from_standby = false;
/* create backup directory and backup.ini */
if (!check)
@ -754,7 +808,7 @@ current.recovery_time = (time_t) 0;
pgut_atexit_push(backup_cleanup, NULL);
/* backup data */
files_database = do_backup_database(backup_list, smooth_checkpoint);
files_database = do_backup_database(backup_list, bkupopt);
/* backup archived WAL */
files_arclog = do_backup_arclog(backup_list);
@ -822,6 +876,80 @@ current.recovery_time = (time_t) 0;
return 0;
}
void
remove_stopinfo_from_backup_label(char *history_file, char *bkup_label)
{
FILE *read;
FILE *write;
char buf[MAXPGPATH * 2];
if ((read = fopen(history_file, "r")) == NULL)
elog(ERROR_SYSTEM,
_("can't open backup history file for standby backup."));
if ((write = fopen(bkup_label, "w")) == NULL)
elog(ERROR_SYSTEM,
_("can't open backup_label file for standby backup."));
while (fgets(buf, lengthof(buf), read) != NULL)
{
if (strstr(buf, "STOP") - buf == 0)
continue;
fputs(buf, write);
}
fclose(write);
fclose(read);
}
/*
* creating backup_label from backup.history for standby backup.
*/
void
make_backup_label(parray *backup_list)
{
char dest_path[MAXPGPATH];
char src_bkup_history_file[MAXPGPATH];
char dst_bkup_label_file[MAXPGPATH];
char original_bkup_label_file[MAXPGPATH];
parray *bkuped_arc_files = NULL;
int i;
pgBackupGetPath(&current, dest_path, lengthof(dest_path), DATABASE_DIR);
bkuped_arc_files = parray_new();
dir_list_file(bkuped_arc_files, arclog_path, NULL, true, false);
for (i = parray_num(bkuped_arc_files) - 1; i >= 0; i--)
{
char *current_arc_fname;
pgFile *current_arc_file;
current_arc_file = (pgFile *) parray_get(bkuped_arc_files, i);
current_arc_fname = last_dir_separator(current_arc_file->path) + 1;
if(strlen(current_arc_fname) <= 24) continue;
copy_file(arclog_path, dest_path, current_arc_file, NO_COMPRESSION);
join_path_components(src_bkup_history_file, dest_path, current_arc_fname);
join_path_components(dst_bkup_label_file, dest_path, PG_BACKUP_LABEL_FILE);
join_path_components(original_bkup_label_file, pgdata, PG_BACKUP_LABEL_FILE);
remove_stopinfo_from_backup_label(src_bkup_history_file, dst_bkup_label_file);
dir_list_file(backup_list, dst_bkup_label_file, NULL, false, true);
for (i = 0; i < parray_num(backup_list); i++)
{
pgFile *file = (pgFile *)parray_get(backup_list, i);
if (strcmp(file->path, dst_bkup_label_file) == 0)
{
struct stat st;
stat(dst_bkup_label_file, &st);
file->write_size = st.st_size;
file->crc = pgFileGetCRC(file);
strcpy(file->path, original_bkup_label_file);
}
}
parray_qsort(backup_list, pgFileComparePath);
break;
}
}
/*
* get server version and confirm block sizes.
*/
@ -1030,7 +1158,7 @@ get_xid(PGresult *res, uint32 *xid)
/*
* Return true if the path is a existing regular file.
*/
static bool
bool
fileExists(const char *path)
{
struct stat buf;

18
data.c
View File

@ -2,7 +2,7 @@
*
* data.c: compress / uncompress data pages
*
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2013, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -755,14 +755,6 @@ restore_data_file(const char *from_root,
elog(ERROR_SYSTEM, _("can't change mode of \"%s\": %s"), to_path,
strerror(errno_tmp));
}
//aaa if (chown(to_path, file->uid, file->gid) == -1)
//aaa {
//aaa int errno_tmp = errno;
//aaa fclose(in);
//aaa fclose(out);
//aaa elog(ERROR_SYSTEM, _("can't change owner of \"%s\": %s"), to_path,
//aaa strerror(errno_tmp));
//aaa }
fclose(in);
fclose(out);
@ -998,14 +990,6 @@ copy_file(const char *from_root, const char *to_root, pgFile *file,
elog(ERROR_SYSTEM, _("can't change mode of \"%s\": %s"), to_path,
strerror(errno_tmp));
}
//aaa if (chown(to_path, file->uid, file->gid) == -1)
//aaa {
//aaa errno_tmp = errno;
//aaa fclose(in);
//aaa fclose(out);
//aaa elog(ERROR_SYSTEM, _("can't change owner of \"%s\": %s"), to_path,
//aaa strerror(errno_tmp));
//aaa }
fclose(in);
fclose(out);

View File

@ -2,7 +2,7 @@
*
* delete.c: delete backup files.
*
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2013, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -13,7 +13,6 @@ static int pgBackupDeleteFiles(pgBackup *backup);
static bool checkIfDeletable(pgBackup *backup);
int
//do_delete(pgBackupRange *range)
do_delete(pgBackupRange *range, bool force)
{
int i;

54
dir.c
View File

@ -2,7 +2,7 @@
*
* dir.c: directory operation utility.
*
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2013, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -31,6 +31,7 @@ const char *pgdata_exclude[] =
};
static pgFile *pgFileNew(const char *path, bool omit_symlink);
static int BlackListCompare(const void *str1, const void *str2);
/* create directory, also create parent directories if necessary */
int
@ -205,6 +206,12 @@ pgFileCompareMtimeDesc(const void *f1, const void *f2)
return -pgFileCompareMtime(f1, f2);
}
static int
BlackListCompare(const void *str1, const void *str2)
{
return strcmp(*(char **) str1, *(char **) str2);
}
/*
* List files, symbolic links and directories in the directory "root" and add
* pgFile objects to "files". We add "root" to "files" if add_root is true.
@ -217,6 +224,42 @@ pgFileCompareMtimeDesc(const void *f1, const void *f2)
*/
void
dir_list_file(parray *files, const char *root, const char *exclude[], bool omit_symlink, bool add_root)
{
char path[MAXPGPATH];
char buf[MAXPGPATH * 2];
char black_item[MAXPGPATH * 2];
parray *black_list = NULL;
join_path_components(path, backup_path, PG_BLACK_LIST);
if (root && pgdata && strcmp(root, pgdata) == 0 &&
fileExists(path))
{
FILE *black_list_file = NULL;
black_list = parray_new();
black_list_file = fopen(path, "r");
if (black_list_file == NULL)
elog(ERROR_SYSTEM, _("can't open black_list: %s"),
strerror(errno));
while (fgets(buf, lengthof(buf), black_list_file) != NULL)
{
join_path_components(black_item, pgdata, buf);
if (black_item[strlen(black_item) - 1] == '\n')
black_item[strlen(black_item) - 1] = '\0';
if (black_item[0] == '#' || black_item[0] == '\0')
continue;
parray_append(black_list, black_item);
}
fclose(black_list_file);
parray_qsort(black_list, BlackListCompare);
dir_list_file_internal(files, root, exclude, omit_symlink, add_root, black_list);
}
else
dir_list_file_internal(files, root, exclude, omit_symlink, add_root, NULL);
}
void
dir_list_file_internal(parray *files, const char *root, const char *exclude[],
bool omit_symlink, bool add_root, parray *black_list)
{
pgFile *file;
@ -224,6 +267,13 @@ dir_list_file(parray *files, const char *root, const char *exclude[], bool omit_
if (file == NULL)
return;
/* skip if the file is in black_list defined by user */
if (black_list && parray_bsearch(black_list, root, BlackListCompare))
{
/* found in black_list. skip this item */
return;
}
if (add_root)
parray_append(files, file);
@ -335,7 +385,7 @@ dir_list_file(parray *files, const char *root, const char *exclude[], bool omit_
continue;
join_path_components(child, file->path, dent->d_name);
dir_list_file(files, child, exclude, omit_symlink, true);
dir_list_file_internal(files, child, exclude, omit_symlink, true, black_list);
}
if (errno && errno != ENOENT)
{

View File

@ -28,12 +28,15 @@ Backup options:
--keep-arclog-days=DAY keep archived WAL modified in DAY days
--keep-srvlog-files=NUM keep NUM of serverlogs
--keep-srvlog-days=DAY keep serverlog modified in DAY days
--standby-host=HOSTNAME standby host when taking backup from standby
--standby-port=PORT standby port when taking backup from standby
Restore options:
--recovery-target-time time stamp up to which recovery will proceed
--recovery-target-xid transaction ID up to which recovery will proceed
--recovery-target-inclusive whether we stop just after the recovery target
--recovery-target-timeline recovering into a particular timeline
--hard-copy copying archivelog not symbolic link
Catalog options:
-a, --show-all show deleted backup too
@ -54,7 +57,7 @@ Generic options:
Read the website for details. <http://code.google.com/p/pg-rman/>
Report bugs to <http://code.google.com/p/pg-rman/issues/list>.
pg_rman 1.2.5
pg_rman 1.2.6
ERROR: required parameter not specified: BACKUP_PATH (-B, --backup-path)
ERROR: required parameter not specified: BACKUP_MODE (-b, --backup-mode)
ERROR: required parameter not specified: ARCLOG_PATH (-A, --arclog-path)

View File

@ -2,7 +2,7 @@
*
* pg_rman.c: Backup/Recovery manager for PostgreSQL.
*
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2013, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -14,7 +14,7 @@
#include <time.h>
#include <sys/stat.h>
const char *PROGRAM_VERSION = "1.2.5";
const char *PROGRAM_VERSION = "1.2.6";
const char *PROGRAM_URL = "http://code.google.com/p/pg-rman/";
const char *PROGRAM_EMAIL = "http://code.google.com/p/pg-rman/issues/list";
@ -39,12 +39,15 @@ static int keep_srvlog_files = KEEP_INFINITE;
static int keep_srvlog_days = KEEP_INFINITE;
static int keep_data_generations = KEEP_INFINITE;
static int keep_data_days = KEEP_INFINITE;
static char *standby_host = NULL;
static char *standby_port = NULL;
/* restore configuration */
static char *target_time;
static char *target_xid;
static char *target_inclusive;
static TimeLineID target_tli;
static bool is_hard_copy = false;
/* delete configuration */
static bool force;
@ -70,6 +73,8 @@ static pgut_option options[] =
{ 'b', 's', "with-serverlog" , &current.with_serverlog , SOURCE_ENV },
{ 'b', 'Z', "compress-data" , &current.compress_data , SOURCE_ENV },
{ 'b', 'C', "smooth-checkpoint" , &smooth_checkpoint , SOURCE_ENV },
{ 's', 12, "standby-host" , &standby_host , SOURCE_ENV },
{ 's', 13, "standby-port" , &standby_port , SOURCE_ENV },
/* delete options */
{ 'b', 'f', "force" , &force , SOURCE_ENV },
/* options with only long name (keep-xxx) */
@ -84,6 +89,7 @@ static pgut_option options[] =
{ 's', 8, "recovery-target-xid" , &target_xid , SOURCE_ENV },
{ 's', 9, "recovery-target-inclusive" , &target_inclusive , SOURCE_ENV },
{ 'u', 10, "recovery-target-timeline" , &target_tli , SOURCE_ENV },
{ 'b', 11, "hard-copy" , &is_hard_copy , SOURCE_ENV },
/* catalog options */
{ 'b', 'a', "show-all" , &show_all },
{ 0 }
@ -183,19 +189,28 @@ main(int argc, char *argv[])
if (pg_strcasecmp(cmd, "init") == 0)
return do_init();
else if (pg_strcasecmp(cmd, "backup") == 0)
return do_backup(smooth_checkpoint,
keep_arclog_files, keep_arclog_days,
keep_srvlog_files, keep_srvlog_days,
keep_data_generations, keep_data_days);
{
pgBackupOption bkupopt;
bkupopt.smooth_checkpoint = smooth_checkpoint;
bkupopt.keep_arclog_files = keep_arclog_files;
bkupopt.keep_arclog_days = keep_arclog_days;
bkupopt.keep_srvlog_files = keep_srvlog_files;
bkupopt.keep_srvlog_days = keep_srvlog_days;
bkupopt.keep_data_generations = keep_data_generations;
bkupopt.keep_data_days = keep_data_days;
bkupopt.standby_host = standby_host;
bkupopt.standby_port = standby_port;
return do_backup(bkupopt);
}
else if (pg_strcasecmp(cmd, "restore") == 0){
return do_restore(target_time, target_xid, target_inclusive, target_tli);
return do_restore(target_time, target_xid,
target_inclusive, target_tli, is_hard_copy);
}
else if (pg_strcasecmp(cmd, "show") == 0)
return do_show(&range, show_timeline, show_all);
else if (pg_strcasecmp(cmd, "validate") == 0)
return do_validate(&range);
else if (pg_strcasecmp(cmd, "delete") == 0)
// return do_delete(&range);
return do_delete(&range, force);
else
elog(ERROR_ARGS, "invalid command \"%s\"", cmd);
@ -236,11 +251,14 @@ pgut_help(bool details)
printf(_(" --keep-arclog-days=DAY keep archived WAL modified in DAY days\n"));
printf(_(" --keep-srvlog-files=NUM keep NUM of serverlogs\n"));
printf(_(" --keep-srvlog-days=DAY keep serverlog modified in DAY days\n"));
printf(_(" --standby-host=HOSTNAME standby host when taking backup from standby\n"));
printf(_(" --standby-port=PORT standby port when taking backup from standby\n"));
printf(_("\nRestore options:\n"));
printf(_(" --recovery-target-time time stamp up to which recovery will proceed\n"));
printf(_(" --recovery-target-xid transaction ID up to which recovery will proceed\n"));
printf(_(" --recovery-target-inclusive whether we stop just after the recovery target\n"));
printf(_(" --recovery-target-timeline recovering into a particular timeline\n"));
printf(_(" --hard-copy copying archivelog not symbolic link\n"));
printf(_("\nCatalog options:\n"));
printf(_(" -a, --show-all show deleted backup too\n"));
}

View File

@ -2,7 +2,7 @@
*
* pg_rman.h: Backup/Recovery manager for PostgreSQL.
*
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2013, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -32,19 +32,21 @@
/* Directory/File names */
#define DATABASE_DIR "database"
#define ARCLOG_DIR "arclog"
#define SRVLOG_DIR "srvlog"
#define ARCLOG_DIR "arclog"
#define SRVLOG_DIR "srvlog"
#define RESTORE_WORK_DIR "backup"
#define PG_XLOG_DIR "pg_xlog"
#define PG_XLOG_DIR "pg_xlog"
#define PG_TBLSPC_DIR "pg_tblspc"
#define TIMELINE_HISTORY_DIR "timeline_history"
#define TIMELINE_HISTORY_DIR "timeline_history"
#define BACKUP_INI_FILE "backup.ini"
#define PG_RMAN_INI_FILE "pg_rman.ini"
#define MKDIRS_SH_FILE "mkdirs.sh"
#define DATABASE_FILE_LIST "file_database.txt"
#define ARCLOG_FILE_LIST "file_arclog.txt"
#define SRVLOG_FILE_LIST "file_srvlog.txt"
#define SNAPSHOT_SCRIPT_FILE "snapshot_script"
#define SNAPSHOT_SCRIPT_FILE "snapshot_script"
#define PG_BACKUP_LABEL_FILE "backup_label"
#define PG_BLACK_LIST "black_list"
/* Snapshot script command */
#define SNAPSHOT_FREEZE "freeze"
@ -160,8 +162,25 @@ typedef struct pgBackup
uint32 block_size;
uint32 wal_block_size;
/* if backup from standby or not */
bool is_from_standby;
} pgBackup;
typedef struct pgBackupOption
{
bool smooth_checkpoint;
int keep_arclog_files;
int keep_arclog_days;
int keep_srvlog_files;
int keep_srvlog_days;
int keep_data_generations;
int keep_data_days;
char *standby_host;
char *standby_port;
} pgBackupOption;
/* special values of pgBackup */
#define KEEP_INFINITE (INT_MAX)
#define BYTES_INVALID (-1)
@ -219,21 +238,17 @@ extern pgBackup current;
extern const char *pgdata_exclude[];
/* in backup.c */
extern int do_backup(bool smooth_checkpoint,
int keep_arclog_files,
int keep_arclog_days,
int keep_srvlog_files,
int keep_srvlog_days,
int keep_data_generations,
int keep_data_days);
extern int do_backup(pgBackupOption bkupopt);
extern BackupMode parse_backup_mode(const char *value, int elevel);
extern int get_server_version(void);
extern bool fileExists(const char *path);
/* in restore.c */
extern int do_restore(const char *target_time,
const char *target_xid,
const char *target_inclusive,
TimeLineID target_tli);
TimeLineID target_tli,
bool is_hard_copy);
/* in init.c */
extern int do_init(void);
@ -242,7 +257,6 @@ extern int do_init(void);
extern int do_show(pgBackupRange *range, bool show_timeline, bool show_all);
/* in delete.c */
//extern int do_delete(pgBackupRange *range);
extern int do_delete(pgBackupRange *range, bool force);
extern void pgBackupDelete(int keep_generations, int keep_days);
@ -273,6 +287,8 @@ extern int pgBackupCompareIdDesc(const void *f1, const void *f2);
/* in dir.c */
extern void dir_list_file(parray *files, const char *root, const char *exclude[], bool omit_symlink, bool add_root);
extern void dir_list_file_internal(parray *files, const char *root, const char *exclude[],
bool omit_symlink, bool add_root, parray *black_list);
extern void dir_print_mkdirs_sh(FILE *out, const parray *files, const char *root);
extern void dir_print_file_list(FILE *out, const parray *files, const char *root, const char *prefix);
extern parray *dir_read_file_list(const char *root, const char *file_txt);

View File

@ -2,7 +2,7 @@
*
* pgut.c
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2013, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -899,7 +899,6 @@ pgut_connect(int elevel)
elog(ERROR_INTERRUPTED, "interrupted");
#ifndef PGUT_NO_PROMPT
// if (prompt_password == DEFAULT) // katsumata
if (prompt_password == YES)
prompt_for_password(username);
#endif
@ -963,6 +962,31 @@ disconnect(void)
}
}
/* set/get host and port for connecting standby server */
const char *
pgut_get_host()
{
return host;
}
const char *
pgut_get_port()
{
return port;
}
void
pgut_set_host(const char *new_host)
{
host = new_host;
}
void
pgut_set_port(const char *new_port)
{
port = new_port;
}
PGresult *
pgut_execute(PGconn* conn, const char *query, int nParams, const char **params, int elevel)
{

View File

@ -2,7 +2,7 @@
*
* pgut.h
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2013, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -120,6 +120,13 @@ extern int pgut_wait(int num, PGconn *connections[], struct timeval *timeout);
extern PGconn *reconnect_elevel(int elevel);
extern void reconnect(void);
extern void disconnect(void);
extern const char *pgut_get_host(void);
extern const char *pgut_get_port(void);
extern void pgut_set_host(const char *new_host);
extern void pgut_set_port(const char *new_port);
extern PGresult *execute_elevel(const char *query, int nParams, const char **params, int elevel);
extern PGresult *execute(const char *query, int nParams, const char **params);
extern void command(const char *query, int nParams, const char **params);

View File

@ -2,7 +2,7 @@
*
* restore.c: restore DB cluster and archived WAL.
*
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2013, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -19,7 +19,7 @@
static void backup_online_files(bool re_recovery);
static void restore_online_files(void);
static void restore_database(pgBackup *backup);
static void restore_archive_logs(pgBackup *backup);
static void restore_archive_logs(pgBackup *backup, bool is_hard_copy);
static void create_recovery_conf(const char *target_time,
const char *target_xid,
const char *target_inclusive,
@ -39,7 +39,8 @@ int
do_restore(const char *target_time,
const char *target_xid,
const char *target_inclusive,
TimeLineID target_tli)
TimeLineID target_tli,
bool is_hard_copy)
{
int i;
int base_index; /* index of base (full) backup */
@ -201,6 +202,7 @@ base_backup_found:
continue;
/* is the backup is necessary for restore to target timeline ? */
//if (!satisfy_timeline(timelines, backup) && !satisfy_recovery_target(backup, rt))
if (!satisfy_timeline(timelines, backup) || !satisfy_recovery_target(backup, rt))
continue;
@ -242,7 +244,7 @@ base_backup_found:
if (!satisfy_timeline(timelines, backup))
continue;
restore_archive_logs(backup);
restore_archive_logs(backup, is_hard_copy);
if (check)
{
@ -474,7 +476,7 @@ restore_database(pgBackup *backup)
* archive directory.
*/
void
restore_archive_logs(pgBackup *backup)
restore_archive_logs(pgBackup *backup, bool is_hard_copy)
{
int i;
char timestamp[100];
@ -549,12 +551,27 @@ restore_archive_logs(pgBackup *backup)
elog(ERROR_SYSTEM, _("can't remove file \"%s\": %s"), path,
strerror(errno));
if ((symlink(file->path, path) == -1))
elog(ERROR_SYSTEM, _("can't create link to \"%s\": %s"),
file->path, strerror(errno));
if (!is_hard_copy)
{
/* create symlink */
if ((symlink(file->path, path) == -1))
elog(ERROR_SYSTEM, _("can't create link to \"%s\": %s"),
file->path, strerror(errno));
if (verbose)
printf(_("linked\n"));
}
else
{
/* create hard-copy */
if (!copy_file(base_path, arclog_path, file, NO_COMPRESSION))
elog(ERROR_SYSTEM, _("can't copy to \"%s\": %s"),
file->path, strerror(errno));
if (verbose)
printf(_("copied\n"));
}
if (verbose)
printf(_("linked\n"));
}
}

View File

@ -51,8 +51,6 @@ while [ $# -gt 0 ]; do
esac
done
export LANG=C
# delete old database cluster
pg_ctl stop -m immediate > /dev/null 2>&1
rm -rf $PGDATA
@ -140,7 +138,7 @@ pg_rman -w -p $TEST_PGPORT backup -b i --verbose -d postgres > $BASE_PATH/result
# validate all backup
pg_rman validate `date +%Y` --verbose > $BASE_PATH/results/log_validate1 2>&1
pg_rman -p $TEST_PGPORT show `date +%Y` -a --verbose -d postgres > $BASE_PATH/results/log_show0 2>&1
pg_dumpall -p $TEST_PGPORT > $BASE_PATH/results/dump_before_rtx.sql
pg_dumpall > $BASE_PATH/results/dump_before_rtx.sql
target_xid=`psql -p $TEST_PGPORT pgbench -tAq -c "INSERT INTO pgbench_history VALUES (1) RETURNING(xmin);"`
psql -p $TEST_PGPORT postgres -c "checkpoint"
#pg_rman -p $TEST_PGPORT backup -b i --verbose -d postgres > $BASE_PATH/results/log_incr2 2>&1
@ -158,7 +156,7 @@ sleep `expr $DURATION / 2`
pg_ctl stop -m immediate > /dev/null 2>&1
cp -rp $PGDATA $PGDATA.bak
pg_ctl start -w -t 3600 > /dev/null 2>&1
pg_dumpall -p $TEST_PGPORT > $BASE_PATH/results/dump_before.sql
pg_dumpall > $BASE_PATH/results/dump_before.sql
# revert to crushed cluster
pg_ctl stop > /dev/null 2>&1
@ -213,7 +211,7 @@ find $BACKUP_PATH/backup/srvlog -type f | wc -l
pg_ctl start -w -t 3600 > /dev/null 2>&1
# compare recovery results
pg_dumpall -p $TEST_PGPORT > $BASE_PATH/results/dump_after.sql
pg_dumpall > $BASE_PATH/results/dump_after.sql
diff $BASE_PATH/results/dump_before.sql $BASE_PATH/results/dump_after.sql
# take a backup and delete backed up online files
@ -256,7 +254,7 @@ grep -c "recovery_target_" $PGDATA/recovery.conf
# recovery database
pg_ctl start -w -t 3600 > /dev/null 2>&1
pg_dumpall -p $TEST_PGPORT > $BASE_PATH/results/dump_after_rtx.sql
pg_dumpall > $BASE_PATH/results/dump_after_rtx.sql
diff $BASE_PATH/results/dump_before_rtx.sql $BASE_PATH/results/dump_after_rtx.sql
# show timeline

5
xlog.c
View File

@ -2,7 +2,7 @@
*
* xlog.c: Parse WAL files.
*
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2013, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -29,6 +29,7 @@ typedef struct MemoryContextData *MemoryContext;
#define XLOG_PAGE_MAGIC_v90 0xD064 /* 9.0 */
#define XLOG_PAGE_MAGIC_v91 0xD066 /* 9.1 */
#define XLOG_PAGE_MAGIC_v92 0xD071 /* 9.2 */
#define XLOG_PAGE_MAGIC_v93 0xD075 /* 9.2 */
/*
* XLogLongPageHeaderData is modified in 8.3, but the layout is compatible
@ -81,6 +82,8 @@ xlog_is_complete_wal(const pgFile *file, int server_version)
xlog_page_magic = XLOG_PAGE_MAGIC_v91;
else if (server_version < 90300)
xlog_page_magic = XLOG_PAGE_MAGIC_v92;
else if (server_version < 90400)
xlog_page_magic = XLOG_PAGE_MAGIC_v93;
else
return false; /* not supported */