1
0
mirror of https://github.com/postgrespro/pg_probackup.git synced 2025-01-07 13:40:17 +02:00

revised for pg_rman1.2.2

git-svn-id: http://pg-rman.googlecode.com/svn/trunk@48 182aca00-e38e-11de-a668-6fd11605f5ce
This commit is contained in:
t.katsumata1122 2011-11-28 04:22:05 +00:00
parent ae6c0e0c55
commit 78eed96f63
42 changed files with 1940 additions and 1615 deletions

View File

@ -1,4 +1,4 @@
Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
Portions Copyright (c) 1994, The Regents of the University of California

View File

@ -24,7 +24,7 @@ OBJS = $(SRCS:.c=.o)
PG_CPPFLAGS = -I$(libpq_srcdir)
PG_LIBS = $(libpq_pgport)
REGRESS = option init show_validate backup_restore snapshot
REGRESS = option init show_validate backup_restore
ifdef USE_PGXS
PG_CONFIG = pg_config

View File

@ -9,7 +9,7 @@
## Set general information for pg_rman.
Summary: Backup and Recovery Tool for PostgreSQL
Name: pg_rman
Version: 1.2.1
Version: 1.2.0
Release: 1%{?dist}
License: BSD
Group: Applications/Databases
@ -58,7 +58,6 @@ rm -rf %{buildroot}
# History of pg_rman.
%changelog
* Mon Jun 20 2011 - Tomonari Katsumata <t.katsumata1122@gmail.com> 1.2.1-1
* 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

@ -2,7 +2,7 @@
*
* backup.c: backup DB cluster, archived WAL, serverlog.
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -41,6 +41,7 @@ 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 void delete_arclog_link(void);
static void delete_online_wal_backup(void);
@ -75,8 +76,26 @@ do_backup_database(parray *backup_list, bool smooth_checkpoint)
XLogRecPtr *lsn = NULL;
char prev_file_txt[MAXPGPATH]; /* path of the previous backup list file */
if (!HAVE_DATABASE(&current))
return NULL;
if (!HAVE_DATABASE(&current)) {
/* check if arclog backup. if arclog backup and no suitable full backup, */
/* take full backup instead. */
if (HAVE_ARCLOG(&current)) {
pgBackup *prev_backup;
/* find last completed database backup */
prev_backup = catalog_get_last_data_backup(backup_list);
if (prev_backup == NULL)
{
elog(ERROR_SYSTEM, _("There is indeed a full backup but it is not validated."
"So I can't take any arclog backup."
"Please validate it and retry."));
/// elog(INFO, _("no previous full backup, performing a full backup instead"));
/// current.backup_mode = BACKUP_MODE_FULL;
}
}
else
return NULL;
}
elog(INFO, _("database backup start"));
@ -89,6 +108,16 @@ do_backup_database(parray *backup_list, bool smooth_checkpoint)
strncat(label, " with pg_rman", lengthof(label));
pg_start_backup(label, smooth_checkpoint, &current);
/* If backup_label does not exist in $PGDATA, stop taking backup */
snprintf(path, lengthof(path), "%s/backup_label", pgdata);
make_native_path(path);
if (!fileExists(path)) {
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."));
}
/*
* list directories and symbolic links with the physical path to make
* mkdirs.sh
@ -127,10 +156,13 @@ do_backup_database(parray *backup_list, bool smooth_checkpoint)
/* find last completed database backup */
prev_backup = catalog_get_last_data_backup(backup_list);
if (prev_backup == NULL)
if (prev_backup == NULL || prev_backup->tli != current.tli)
{
elog(INFO, _("no previous full backup, do a full backup instead"));
current.backup_mode = BACKUP_MODE_FULL;
elog(ERROR_SYSTEM, _("There is indeed a full backup but it is not validated."
"So I can't take any incremental backup."
"Please validate it and retry."));
/// elog(INFO, _("no previous full backup, performing a full backup instead"));
/// current.backup_mode = BACKUP_MODE_FULL;
}
else
{
@ -440,7 +472,7 @@ do_backup_arclog(parray *backup_list)
*/
prev_backup = catalog_get_last_arclog_backup(backup_list);
if (verbose && prev_backup == NULL)
printf(_("no previous full backup, do a full backup instead\n"));
printf(_("no previous full backup, performing a full backup instead\n"));
if (prev_backup)
{
@ -564,7 +596,7 @@ do_backup_srvlog(parray *backup_list)
*/
prev_backup = catalog_get_last_srvlog_backup(backup_list);
if (verbose && prev_backup == NULL)
printf(_("no previous full backup, do a full backup instead\n"));
printf(_("no previous full backup, performing a full backup instead\n"));
if (prev_backup)
{
@ -695,6 +727,8 @@ 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;
/* create backup directory and backup.ini */
if (!check)
@ -708,6 +742,9 @@ do_backup(bool smooth_checkpoint,
/* get list of backups already taken */
backup_list = catalog_get_backup_list(NULL);
if(!backup_list){
elog(ERROR_SYSTEM, _("can't process any more."));
}
/* set the error processing function for the backup process */
pgut_atexit_push(backup_cleanup, NULL);
@ -893,6 +930,12 @@ wait_for_archive(pgBackup *backup, const char *sql)
elog(LOG, "%s() wait for %s", __FUNCTION__, ready_path);
PQclear(res);
res = execute(TXID_CURRENT_SQL, 0, NULL);
if(backup != NULL){
get_xid(res, &backup->recovery_xid);
backup->recovery_time = time(NULL);
}
disconnect();
/* wait until switched WAL is archived */
@ -960,6 +1003,26 @@ get_lsn(PGresult *res, TimeLineID *timeline, XLogRecPtr *lsn)
lsn->xrecoff += off_upper << 24;
}
/*
* Get XID from result of txid_current() after pg_stop_backup().
*/
static void
get_xid(PGresult *res, uint32 *xid)
{
if(res == NULL || PQntuples(res) != 1 || PQnfields(res) != 1)
elog(ERROR_PG_COMMAND,
_("result of txid_current() is invalid: %s"),
PQerrorMessage(connection));
if(sscanf(PQgetvalue(res, 0, 0), "%u", xid) != 1)
{
elog(ERROR_PG_COMMAND,
_("result of txid_current() is invalid: %s"),
PQerrorMessage(connection));
}
elog(LOG, "%s():%s", __FUNCTION__, PQgetvalue(res, 0, 0));
}
/*
* Return true if the path is a existing regular file.
*/
@ -1055,6 +1118,11 @@ backup_files(const char *from_root,
pgFile *file = (pgFile *) parray_get(files, i);
/* If current time is rewinded, abort this backup. */
if(tv.tv_sec < file->mtime){
elog(ERROR_SYSTEM, _("current time may be rewound. Please retry with full backup mode."));
}
/* check for interrupt */
if (interrupted)
elog(ERROR_INTERRUPTED, _("interrupted during backup"));
@ -1101,8 +1169,9 @@ backup_files(const char *from_root,
char dirpath[MAXPGPATH];
join_path_components(dirpath, to_root, JoinPathEnd(file->path, from_root));
if (!check)
if (!check){
dir_create_dir(dirpath, DIR_PERMISSION);
}
if (verbose)
printf(_("directory\n"));
}
@ -1143,7 +1212,7 @@ backup_files(const char *from_root,
prev_file = *p;
}
if (prev_file && prev_file->mtime >= file->mtime)
if (prev_file && prev_file->mtime == file->mtime)
{
/* record as skipped file in file_xxx.txt */
file->write_size = BYTES_INVALID;
@ -1158,7 +1227,8 @@ backup_files(const char *from_root,
* file should contain all modifications at the clock of mtime.
* timer resolution of ext3 file system is one second.
*/
if (tv.tv_sec <= file->mtime)
if (tv.tv_sec == file->mtime)
{
/* update time and recheck */
gettimeofday(&tv, NULL);

View File

@ -2,7 +2,7 @@
*
* catalog.c: backup catalog opration
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -364,6 +364,12 @@ pgBackupWriteResultSection(FILE *out, pgBackup *backup)
time2iso(timestamp, lengthof(timestamp), backup->end_time);
fprintf(out, "END_TIME='%s'\n", timestamp);
}
fprintf(out, "RECOVERY_XID=%u\n", backup->recovery_xid);
if (backup->recovery_time > 0)
{
time2iso(timestamp, lengthof(timestamp), backup->recovery_time);
fprintf(out, "RECOVERY_TIME='%s'\n", timestamp);
}
if (backup->total_data_bytes != BYTES_INVALID)
fprintf(out, "TOTAL_DATA_BYTES=" INT64_FORMAT "\n",
@ -434,6 +440,8 @@ catalog_read_ini(const char *path)
{ 's', 0, "stop-lsn" , NULL, SOURCE_ENV },
{ 't', 0, "start-time" , NULL, SOURCE_ENV },
{ 't', 0, "end-time" , NULL, SOURCE_ENV },
{ 'u', 0, "recovery-xid" , NULL, SOURCE_ENV },
{ 't', 0, "recovery-time" , NULL, SOURCE_ENV },
{ 'I', 0, "total-data-bytes" , NULL, SOURCE_ENV },
{ 'I', 0, "read-data-bytes" , NULL, SOURCE_ENV },
{ 'I', 0, "read-arclog-bytes" , NULL, SOURCE_ENV },
@ -445,6 +453,10 @@ catalog_read_ini(const char *path)
{ 0 }
};
if (access(path, F_OK) != 0){
return NULL;
}
backup = pgut_new(pgBackup);
catalog_init_config(backup);
@ -457,6 +469,8 @@ catalog_read_ini(const char *path)
options[i++].var = &stop_lsn;
options[i++].var = &backup->start_time;
options[i++].var = &backup->end_time;
options[i++].var = &backup->recovery_xid;
options[i++].var = &backup->recovery_time;
options[i++].var = &backup->total_data_bytes;
options[i++].var = &backup->read_data_bytes;
options[i++].var = &backup->read_arclog_bytes;
@ -601,6 +615,8 @@ catalog_init_config(pgBackup *backup)
backup->stop_lsn.xrecoff = 0;
backup->start_time = (time_t) 0;
backup->end_time = (time_t) 0;
backup->recovery_xid = 0;
backup->recovery_time = (time_t) 0;
backup->total_data_bytes = BYTES_INVALID;
backup->read_data_bytes = BYTES_INVALID;
backup->read_arclog_bytes = BYTES_INVALID;

View File

@ -2,7 +2,7 @@
*
* clean.c: cleanup backup files.
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/

18
data.c
View File

@ -2,7 +2,7 @@
*
* data.c: compress / uncompress data pages
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -756,6 +756,14 @@ 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);
@ -992,6 +1000,14 @@ 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

@ -7,7 +7,7 @@ TIMELINEID=1
START_LSN=0/0b40c800
STOP_LSN=0/0b4c8020
START_TIME='2009-06-03 17:05:53'
END_TIME='****-**-** **:**:**'
END_TIME='2009-06-03 17:05:53'
TOTAL_DATA_BYTES=-1
READ_DATA_BYTES=-1
READ_ARCLOG_BYTES=-1

2
db.c
View File

@ -2,7 +2,7 @@
*
* db.c: SQLite3 access module
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/

View File

@ -2,7 +2,7 @@
*
* delete.c: delete backup files.
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -10,14 +10,17 @@
#include "pg_rman.h"
static int pgBackupDeleteFiles(pgBackup *backup);
static bool checkIfDeletable(pgBackup *backup);
int
do_delete(pgBackupRange *range)
//do_delete(pgBackupRange *range)
do_delete(pgBackupRange *range, bool force)
{
int i;
int ret;
parray *backup_list;
bool do_delete;
bool force_delete;
/* DATE are always required */
if (!pgBackupRangeIsValid(range))
@ -29,20 +32,31 @@ do_delete(pgBackupRange *range)
elog(ERROR_SYSTEM, _("can't lock backup catalog."));
else if (ret == 1)
elog(ERROR_ALREADY_RUNNING,
_("another pg_rman is running, stop restore."));
_("another pg_rman is running, stop delete."));
/* get list of backups. */
backup_list = catalog_get_backup_list(NULL);
if(!backup_list){
elog(ERROR_SYSTEM, _("can't process any more."));
}
do_delete = false;
force_delete = false;
/* find delete target backup. */
for (i = 0; i < parray_num(backup_list); i++)
{
pgBackup *backup = (pgBackup *)parray_get(backup_list, i);
if(force)
force_delete = checkIfDeletable(backup);
/* delete backup and update status to DELETED */
if (do_delete)
if (do_delete || force_delete)
{
/* check for interrupt */
if (interrupted)
elog(ERROR_INTERRUPTED, _("interrupted during delete backup"));
pgBackupDeleteFiles(backup);
continue;
}
@ -76,6 +90,7 @@ pgBackupDelete(int keep_generations, int keep_days)
int backup_num;
time_t days_threshold = current.start_time - (keep_days * 60 * 60 * 24);
if (verbose)
{
char generations_str[100];
@ -123,7 +138,8 @@ pgBackupDelete(int keep_generations, int keep_days)
backup_num++;
/* do not include the latest full backup in a count. */
if (backup_num - 1 <= keep_generations)
// if (backup_num - 1 <= keep_generations)
if (backup_num <= keep_generations)
{
elog(LOG, "%s() backup are only %d", __FUNCTION__, backup_num);
continue;
@ -233,3 +249,15 @@ pgBackupDeleteFiles(pgBackup *backup)
return 0;
}
bool
checkIfDeletable(pgBackup *backup)
{
/* find latest full backup. */
if (backup->status != BACKUP_STATUS_OK &&
backup->status != BACKUP_STATUS_DELETED &&
backup->status != BACKUP_STATUS_DONE)
return true;
return false;
}

11
dir.c
View File

@ -2,7 +2,7 @@
*
* dir.c: directory operation utility.
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -363,11 +363,13 @@ dir_print_mkdirs_sh(FILE *out, const parray *files, const char *root)
pgFile *file = (pgFile *) parray_get(files, i);
if (S_ISDIR(file->mode))
{
if (strstr(file->path, root) == file->path)
if (strstr(file->path, root) == file->path) {
fprintf(out, "mkdir -m 700 -p %s\n", file->path + strlen(root)
+ 1);
else
}
else {
fprintf(out, "mkdir -m 700 -p %s\n", file->path);
}
}
}
@ -539,8 +541,9 @@ dir_copy_files(const char *from_root, const char *to_root)
if (verbose && !check)
printf(_("create directory \"%s\"\n"),
file->path + strlen(from_root) + 1);
if (!check)
if (!check) {
dir_create_dir(to_path, DIR_PERMISSION);
}
continue;
}
else if(S_ISREG(file->mode))

View File

@ -15,13 +15,13 @@ diff files in BACKUP_PATH/backup/pg_xlog
1
diff files in BACKUP_PATH/backup/pg_xlog
# of files in BACKUP_PATH/backup/srvlog
2
1
full database backup after recovery
CHECKPOINT
# of files in BACKUP_PATH/backup/pg_xlog
0
# of files in BACKUP_PATH/backup/srvlog
2
1
# of symbolic links in ARCLOG_PATH
0
# of files in BACKUP_PATH/timeline_history

View File

@ -1,6 +1,5 @@
\! rm -rf results/init_test
\! pg_rman init -B results/init_test --quiet;echo $?
WARNING: ARCLOG_PATH is not set because archive_command is empty
\! pg_rman init -B ${PWD}/results/init_test --quiet;echo $?
0
\! find results/init_test | xargs ls -Fd | sort
results/init_test/
@ -9,6 +8,6 @@ results/init_test/backup/pg_xlog/
results/init_test/backup/srvlog/
results/init_test/pg_rman.ini
results/init_test/timeline_history/
\! pg_rman init -B results/init_test --quiet;echo $?
ERROR: backup catalog already exist.
\! pg_rman init -B ${PWD}/results/init_test --quiet;echo $?
ERROR: backup catalog already exist. and it's not empty.
2

View File

@ -54,7 +54,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.1.2
pg_rman 1.2.2
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)
@ -62,11 +62,11 @@ ERROR: required parameter not specified: ARCLOG_PATH (-A, --arclog-path)
ERROR: required parameter not specified: ARCLOG_PATH (-A, --arclog-path)
ERROR: invalid backup-mode "bad"
ERROR: required delete range option not specified: delete DATE
INFO: validate: 2009-05-31 17:05:53
INFO: validate: 2009-06-01 17:05:53
INFO: validate: 2009-05-31 17:05:53 backup and archive log files by CRC
INFO: validate: 2009-06-01 17:05:53 backup and archive log files by CRC
WARNING: CRC of backup file "PG_VERSION" must be 0 but FEF71BC1
WARNING: backup 2009-06-01 17:05:53 is corrupted
WARNING: syntax error in " = INFINITE".
WARNING: syntax error in " = INFINITE"
ERROR: required parameter not specified: BACKUP_MODE (-b, --backup-mode)
ERROR: invalid backup-mode ""
ERROR: required parameter not specified: ARCLOG_PATH (-A, --arclog-path)

View File

@ -1,35 +1,35 @@
-- test show command
\! rm -rf results/sample_backup
\! cp -rp data/sample_backup results/sample_backup
\! pg_rman show -B results/sample_backup
\! rm -rf ${PWD}/results/sample_backup
\! cp -rp data/sample_backup ${PWD}/results/sample_backup
\! pg_rman show -B ${PWD}/results/sample_backup
============================================================================
Start Time Total Data WAL Log Backup Status
============================================================================
2009-06-03 17:05:53 ---- ---- ---- ---- ---- ---- RUNNING
2009-06-03 17:05:53 0m ---- ---- ---- ---- ---- RUNNING
2009-06-01 17:05:53 3m ---- 9223PB 16MB ---- 162MB DONE
2009-05-31 17:05:53 3m 1242MB ---- 9223PB ---- 242MB DONE
\! pg_rman validate -B results/sample_backup 2009-05-31 17:05:53 --debug
INFO: validate: 2009-05-31 17:05:53
\! pg_rman validate -B ${PWD}/results/sample_backup 2009-05-31 17:05:53 --debug
INFO: validate: 2009-05-31 17:05:53 backup and archive log files by CRC
LOG: database files...
LOG: (1/1) PG_VERSION
LOG: archive WAL files...
LOG: backup 2009-05-31 17:05:53 is valid
\! pg_rman validate -B results/sample_backup 2009-06-01 17:05:53 --debug
INFO: validate: 2009-06-01 17:05:53
\! pg_rman validate -B ${PWD}/results/sample_backup 2009-06-01 17:05:53 --debug
INFO: validate: 2009-06-01 17:05:53 backup and archive log files by CRC
LOG: database files...
LOG: (1/1) PG_VERSION
WARNING: CRC of backup file "PG_VERSION" must be 0 but FEF71BC1
LOG: archive WAL files...
WARNING: backup 2009-06-01 17:05:53 is corrupted
\! pg_rman show -a -B results/sample_backup
\! pg_rman show -a -B ${PWD}/results/sample_backup
============================================================================
Start Time Total Data WAL Log Backup Status
============================================================================
2009-06-03 17:05:53 ---- ---- ---- ---- ---- ---- RUNNING
2009-06-03 17:05:53 0m ---- ---- ---- ---- ---- RUNNING
2009-06-02 17:05:03 0m ---- ---- ---- 4335kB 162MB DELETED
2009-06-01 17:05:53 3m ---- 9223PB 16MB ---- 162MB CORRUPT
2009-05-31 17:05:53 3m 1242MB ---- 9223PB ---- 242MB OK
\! pg_rman show 2009-06-01 17:05:53 -B results/sample_backup
\! pg_rman show 2009-06-01 17:05:53 -B ${PWD}/results/sample_backup
# configuration
BACKUP_MODE=INCREMENTAL
WITH_SERVERLOG=false
@ -40,10 +40,10 @@ START_LSN=0/0b40c800
STOP_LSN=0/0b4c8020
START_TIME='2009-06-01 17:05:53'
END_TIME='2009-06-01 17:09:13'
RECOVERY_XID=0
TOTAL_DATA_BYTES=1242102558
READ_DATA_BYTES=9223372036854775807
READ_ARCLOG_BYTES=16777216
READ_SRVLOG_BYTES=-1
WRITE_BYTES=162372983
BLOCK_SIZE=8192
XLOG_BLOCK_SIZE=8192

2
file.c
View File

@ -2,7 +2,7 @@
*
* file.c:
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/

27
init.c
View File

@ -2,7 +2,7 @@
*
* init.c: manage backup catalog.
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -10,10 +10,19 @@
#include "pg_rman.h"
#include <unistd.h>
#include <dirent.h>
static void parse_postgresql_conf(const char *path, char **log_directory,
char **archive_command);
/*
* selects function for scandir.
*/
static int selects(const struct dirent *dir)
{
return dir->d_name[0] != '.';
}
/*
* Initialize backup catalog.
*/
@ -25,8 +34,14 @@ do_init(void)
char *archive_command = NULL;
FILE *fp;
if (access(backup_path, F_OK) == 0)
elog(ERROR, _("backup catalog already exist."));
struct dirent **dp;
int results;
if (access(backup_path, F_OK) == 0){
results = scandir(backup_path, &dp, selects, NULL);
if(results != 0){
elog(ERROR, _("backup catalog already exist. and it's not empty."));
}
}
/* create backup catalog root directory */
dir_create_dir(backup_path, DIR_PERMISSION);
@ -98,9 +113,11 @@ do_init(void)
elog(INFO, "ARCLOG_PATH is set to '%s'", arclog_path);
}
else if (archive_command && archive_command[0])
elog(WARNING, "ARCLOG_PATH is not set because failed to parse archive_command '%s'", archive_command);
elog(WARNING, "ARCLOG_PATH is not set because failed to parse archive_command '%s'."
"Please set ARCLOG_PATH in pg_rman.ini or environmental variable", archive_command);
else
elog(WARNING, "ARCLOG_PATH is not set because archive_command is empty");
elog(WARNING, "ARCLOG_PATH is not set because archive_command is empty."
"Please set ARCLOG_PATH in pg_rman.ini or environmental variable");
/* set SRVLOG_PATH refered with log_directory */
if (srvlog_path == NULL)

View File

@ -2,7 +2,7 @@
*
* parray.c: pointer array collection.
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/

View File

@ -2,7 +2,7 @@
*
* parray.h: pointer array collection.
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/

View File

@ -2,7 +2,7 @@
*
* pg_ctl.c: operations for control file
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/

View File

@ -2,7 +2,7 @@
*
* pg_rman.c: Backup/Recovery manager for PostgreSQL.
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -13,7 +13,7 @@
#include <stdlib.h>
#include <time.h>
const char *PROGRAM_VERSION = "1.2.1";
const char *PROGRAM_VERSION = "1.2.2";
const char *PROGRAM_URL = "http://code.google.com/p/pg-rman/";
const char *PROGRAM_EMAIL = "http://code.google.com/p/pg-rman/issues/list";
@ -45,6 +45,9 @@ static char *target_xid;
static char *target_inclusive;
static TimeLineID target_tli;
/* delete configuration */
static bool force;
/* show configuration */
static bool show_all = false;
@ -66,6 +69,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 },
/* delete options */
{ 'b', 'f', "force" , &force , SOURCE_ENV },
/* options with only long name (keep-xxx) */
{ 'i', 1, "keep-data-generations" , &keep_data_generations, SOURCE_ENV },
{ 'i', 2, "keep-data-days" , &keep_data_days , SOURCE_ENV },
@ -139,6 +144,13 @@ main(int argc, char *argv[])
if (backup_path)
{
char path[MAXPGPATH];
/* Check if backup_path is directory. */
struct stat stat_buf;
int rc = stat(backup_path, &stat_buf);
if(rc != -1 && !S_ISDIR(stat_buf.st_mode)){
/* If rc == -1, there is no file or directory. So it's OK. */
elog(ERROR_ARGS, "-B, --backup-path must be a path to directory");
}
join_path_components(path, backup_path, PG_RMAN_INI_FILE);
pgut_readopt(path, options, ERROR_ARGS);
@ -149,6 +161,8 @@ main(int argc, char *argv[])
elog(ERROR_ARGS, "required parameter not specified: BACKUP_PATH (-B, --backup-path)");
/* path must be absolute */
if (backup_path != NULL && !is_absolute_path(backup_path))
elog(ERROR_ARGS, "-B, --backup-path must be an absolute path");
if (pgdata != NULL && !is_absolute_path(pgdata))
elog(ERROR_ARGS, "-D, --pgdata must be an absolute path");
if (arclog_path != NULL && !is_absolute_path(arclog_path))
@ -172,14 +186,16 @@ main(int argc, char *argv[])
keep_arclog_files, keep_arclog_days,
keep_srvlog_files, keep_srvlog_days,
keep_data_generations, keep_data_days);
else if (pg_strcasecmp(cmd, "restore") == 0)
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_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);
return do_delete(&range, force);
else
elog(ERROR_ARGS, "invalid command \"%s\"", cmd);
@ -259,8 +275,12 @@ parse_range(pgBackupRange *range, const char *arg1, const char *arg2)
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
&tm.tm_hour, &tm.tm_min, &tm.tm_sec);
if (num < 1)
elog(ERROR_ARGS, _("supplied id(%s) is invalid."), tmp);
if (num < 1){
if (strcmp(tmp,"") != 0)
elog(ERROR_ARGS, _("supplied id(%s) is invalid."), tmp);
else
elog(ERROR_ARGS, _("argments are invalid. near \"%s\""), arg1);
}
free(tmp);
@ -269,6 +289,10 @@ parse_range(pgBackupRange *range, const char *arg1, const char *arg2)
if (num > 1)
tm.tm_mon -= 1;
tm.tm_isdst = -1;
if(!IsValidTime(tm)){
elog(ERROR_ARGS, _("supplied time(%s) is invalid."), arg1);
}
range->begin = mktime(&tm);
switch (num)

View File

@ -2,7 +2,7 @@
*
* pg_rman.h: Backup/Recovery manager for PostgreSQL.
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -23,6 +23,13 @@
#define XLOG_BLCKSZ BLCKSZ
#endif
#if PG_VERSION_NUM < 80300
#define TXID_CURRENT_SQL "SELECT transactionid FROM pg_locks WHERE locktype = 'transactionid' AND pid = pg_backend_pid();"
#include <sys/stat.h>
#else
#define TXID_CURRENT_SQL "SELECT txid_current();"
#endif
/* Directory/File names */
#define DATABASE_DIR "database"
#define ARCLOG_DIR "arclog"
@ -88,6 +95,14 @@ typedef struct pgBackupRange
#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) */ \
(tm.tm_hour >= 0 && tm.tm_hour <= 23) && /* range check for tm_hour(0-23) */ \
(tm.tm_mday >= 1 && tm.tm_mday <= 31) && /* range check for tm_mday(1-31) */ \
(tm.tm_mon >= 0 && tm.tm_mon <= 11) && /* range check for tm_mon (0-23) */ \
(tm.tm_year + 1900 >= 1900)) /* range check for tm_year(70-) */
/* Backup status */
/* XXX re-order ? */
typedef enum BackupStatus
@ -131,6 +146,8 @@ typedef struct pgBackup
XLogRecPtr stop_lsn;
time_t start_time;
time_t end_time;
time_t recovery_time;
uint32 recovery_xid;
/* Size (-1 means not-backup'ed) */
int64 total_data_bytes;
@ -142,6 +159,7 @@ typedef struct pgBackup
/* data/wal block size for compatibility check */
uint32 block_size;
uint32 wal_block_size;
} pgBackup;
/* special values of pgBackup */
@ -161,6 +179,15 @@ typedef struct pgTimeLine
XLogRecPtr end;
} pgTimeLine;
typedef struct pgRecoveryTarget
{
bool time_specified;
time_t recovery_target_time;
bool xid_specified;
unsigned int recovery_target_xid;
bool recovery_target_inclusive;
} pgRecoveryTarget;
typedef enum CompressionMode
{
NO_COMPRESSION,
@ -215,12 +242,13 @@ 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);
extern int do_delete(pgBackupRange *range, bool force);
extern void pgBackupDelete(int keep_generations, int keep_days);
/* in validate.c */
extern int do_validate(pgBackupRange *range);
extern void pgBackupValidate(pgBackup *backup, bool size_only);
extern void pgBackupValidate(pgBackup *backup, bool size_only, bool for_get_timeline, bool with_database);
/* in catalog.c */
extern pgBackup *catalog_get_backup(time_t timestamp);

View File

@ -899,7 +899,8 @@ pgut_connect(int elevel)
elog(ERROR_INTERRUPTED, "interrupted");
#ifndef PGUT_NO_PROMPT
if (prompt_password == DEFAULT)
// if (prompt_password == DEFAULT) // katsumata
if (prompt_password == YES)
prompt_for_password(username);
#endif

View File

@ -2,7 +2,7 @@
*
* queue.c: Job queue with thread pooling.
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/

112
restore.c
View File

@ -2,7 +2,7 @@
*
* restore.c: restore DB cluster and archived WAL.
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -24,10 +24,14 @@ static void create_recovery_conf(const char *target_time,
const char *target_xid,
const char *target_inclusive,
TimeLineID target_tli);
static pgRecoveryTarget *checkIfCreateRecoveryConf(const char *target_time,
const char *target_xid,
const char *target_inclusive);
static parray * readTimeLineHistory(TimeLineID targetTLI);
static bool satisfy_timeline(const parray *timelines, const pgBackup *backup);
static bool satisfy_recovery_target(const pgBackup *backup, const pgRecoveryTarget *rt);
static TimeLineID get_current_timeline(void);
static TimeLineID get_fullbackup_timeline(parray *backups);
static TimeLineID get_fullbackup_timeline(parray *backups, const pgRecoveryTarget *rt);
static void print_backup_id(const pgBackup *backup);
static void search_next_wal(const char *path, uint32 *needId, uint32 *needSeg, parray *timelines);
@ -50,6 +54,7 @@ do_restore(const char *target_time,
char timeline_dir[MAXPGPATH];
uint32 needId = 0;
uint32 needSeg = 0;
pgRecoveryTarget *rt = NULL;
/* PGDATA and ARCLOG_PATH are always required */
if (pgdata == NULL)
@ -80,11 +85,19 @@ do_restore(const char *target_time,
if (is_pg_running())
elog(ERROR_PG_RUNNING, _("PostgreSQL server is running"));
rt = checkIfCreateRecoveryConf(target_time, target_xid, target_inclusive);
if(rt == NULL){
elog(ERROR_ARGS, _("can't create recovery.conf. specified args are invalid."));
}
/* get list of backups. (index == 0) is the last backup */
backups = catalog_get_backup_list(NULL);
if(!backups){
elog(ERROR_SYSTEM, _("can't process any more."));
}
cur_tli = get_current_timeline();
backup_tli = get_fullbackup_timeline(backups);
backup_tli = get_fullbackup_timeline(backups, rt);
/* determine target timeline */
if (target_tli == 0)
@ -154,7 +167,7 @@ do_restore(const char *target_time,
_("can't restore from compressed backup (compression not supported in this installation)"));
}
#endif
if (satisfy_timeline(timelines, base_backup))
if (satisfy_timeline(timelines, base_backup) && satisfy_recovery_target(base_backup, rt))
goto base_backup_found;
}
/* no full backup found, can't restore */
@ -168,6 +181,7 @@ base_backup_found:
/* restore base backup */
restore_database(base_backup);
last_restored_index = base_index;
/* restore following incremental backup */
@ -183,11 +197,11 @@ base_backup_found:
continue;
/* use database backup only */
if (backup->backup_mode < BACKUP_MODE_INCREMENTAL)
if (backup->backup_mode != BACKUP_MODE_INCREMENTAL)
continue;
/* is the backup is necessary for restore to target timeline ? */
if (!satisfy_timeline(timelines, backup))
if (!satisfy_timeline(timelines, backup) && !satisfy_recovery_target(backup, rt))
continue;
if (verbose)
@ -314,9 +328,9 @@ restore_database(pgBackup *backup)
/*
* Validate backup files with its size, because load of CRC calculation is
* not light.
* not right.
*/
pgBackupValidate(backup, true);
pgBackupValidate(backup, true, false, true);
/* make direcotries and symbolic links */
pgBackupGetPath(backup, path, lengthof(path), MKDIRS_SH_FILE);
@ -452,7 +466,7 @@ restore_database(pgBackup *backup)
parray_free(files);
if (verbose && !check)
printf(_("resotre backup completed\n"));
printf(_("restore backup completed\n"));
}
/*
@ -476,6 +490,12 @@ restore_archive_logs(pgBackup *backup)
printf(_("restoring WAL from backup %s.\n"), timestamp);
}
/*
* Validate backup files with its size, because load of CRC calculation is
* not light.
*/
pgBackupValidate(backup, true, false, false);
pgBackupGetPath(backup, list_path, lengthof(list_path), ARCLOG_FILE_LIST);
pgBackupGetPath(backup, base_path, lengthof(list_path), ARCLOG_DIR);
files = dir_read_file_list(base_path, list_path);
@ -806,6 +826,28 @@ readTimeLineHistory(TimeLineID targetTLI)
return result;
}
static bool
satisfy_recovery_target(const pgBackup *backup, const pgRecoveryTarget *rt)
{
if(rt->xid_specified){
// elog(INFO, "in satisfy_recovery_target:xid::%u:%u", backup->recovery_xid, rt->recovery_target_xid);
if(backup->recovery_xid <= rt->recovery_target_xid)
return true;
else
return false;
}
if(rt->time_specified){
// elog(INFO, "in satisfy_recovery_target:time_t::%ld:%ld", backup->recovery_time, rt->recovery_target_time);
if(backup->recovery_time <= rt->recovery_target_time)
return true;
else
return false;
}
else{
return true;
}
}
static bool
satisfy_timeline(const parray *timelines, const pgBackup *backup)
{
@ -878,7 +920,7 @@ get_current_timeline(void)
/* get TLI of the latest full backup */
static TimeLineID
get_fullbackup_timeline(parray *backups)
get_fullbackup_timeline(parray *backups, const pgRecoveryTarget *rt)
{
int i;
pgBackup *base_backup = NULL;
@ -892,10 +934,13 @@ get_fullbackup_timeline(parray *backups)
{
/*
* Validate backup files with its size, because load of CRC
* calculation is not light.
* calculation is not right.
*/
if (base_backup->status == BACKUP_STATUS_DONE)
pgBackupValidate(base_backup, true);
pgBackupValidate(base_backup, true, true, false);
if(!satisfy_recovery_target(base_backup, rt))
continue;
if (base_backup->status == BACKUP_STATUS_OK)
break;
@ -969,3 +1014,46 @@ search_next_wal(const char *path, uint32 *needId, uint32 *needSeg, parray *timel
NextLogSeg(*needId, *needSeg);
}
}
static pgRecoveryTarget *
checkIfCreateRecoveryConf(const char *target_time,
const char *target_xid,
const char *target_inclusive)
{
time_t dummy_time;
unsigned int dummy_xid;
bool dummy_bool;
pgRecoveryTarget *rt;
// init pgRecoveryTarget
rt = pgut_new(pgRecoveryTarget);
rt->time_specified = false;
rt->xid_specified = false;
rt->recovery_target_time = 0;
rt->recovery_target_xid = 0;
rt->recovery_target_inclusive = false;
if(target_time){
rt->time_specified = true;
if(parse_time(target_time, &dummy_time))
rt->recovery_target_time = dummy_time;
else
elog(ERROR_ARGS, _("can't create recovery.conf with %s"), target_time);
}
if(target_xid){
rt->xid_specified = true;
if(parse_uint32(target_xid, &dummy_xid))
rt->recovery_target_xid = dummy_xid;
else
elog(ERROR_ARGS, _("can't create recovery.conf with %s"), target_xid);
}
if(target_inclusive){
if(parse_bool(target_inclusive, &dummy_bool))
rt->recovery_target_inclusive = dummy_bool;
else
elog(ERROR_ARGS, _("can't create recovery.conf with %s"), target_inclusive);
}
return rt;
}

7
show.c
View File

@ -2,7 +2,7 @@
*
* show.c: show backup catalog.
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -45,8 +45,9 @@ do_show(pgBackupRange *range, bool show_timeline, bool show_all)
parray *backup_list;
backup_list = catalog_get_backup_list(range);
if (backup_list == NULL)
return 1;
if (backup_list == NULL){
elog(ERROR_SYSTEM, _("can't process any more."));
}
if (!show_timeline)
show_backup_list(stdout, backup_list, show_all);

View File

@ -75,6 +75,7 @@ initdb --no-locale > $BASE_PATH/results/initdb.log 2>&1
cat << EOF >> $PGDATA/postgresql.conf
port = $TEST_PGPORT
logging_collector = on
wal_level = archive
archive_mode = on
archive_command = 'cp "%p" "$ARCLOG_PATH/%f"'
EOF
@ -113,7 +114,8 @@ EOF
export KEEP_DATA_GENERATIONS=2
export KEEP_DATA_DAYS=0
for i in `seq 1 5`; do
pg_rman -p $TEST_PGPORT backup --verbose -d postgres > $BASE_PATH/results/log_full_0_$i 2>&1
# pg_rman -p $TEST_PGPORT backup --verbose -d postgres > $BASE_PATH/results/log_full_0_$i 2>&1
pg_rman -w -p $TEST_PGPORT backup --verbose -d postgres > $BASE_PATH/results/log_full_0_$i 2>&1
done
pg_rman -p $TEST_PGPORT show `date +%Y` -a --verbose -d postgres > $BASE_PATH/results/log_show_d_1 2>&1
echo "# of deleted backups"
@ -123,12 +125,14 @@ pgbench -p $TEST_PGPORT -i -s $SCALE pgbench > $BASE_PATH/results/pgbench.log 2>
echo "full database backup"
psql -p $TEST_PGPORT postgres -c "checkpoint"
pg_rman -p $TEST_PGPORT backup --verbose -d postgres > $BASE_PATH/results/log_full_1 2>&1
#pg_rman -p $TEST_PGPORT backup --verbose -d postgres > $BASE_PATH/results/log_full_1 2>&1
pg_rman -w -p $TEST_PGPORT backup --verbose -d postgres > $BASE_PATH/results/log_full_1 2>&1
pgbench -p $TEST_PGPORT -T $DURATION -c 10 pgbench >> $BASE_PATH/results/pgbench.log 2>&1
echo "incremental database backup"
psql -p $TEST_PGPORT postgres -c "checkpoint"
pg_rman -p $TEST_PGPORT backup -b i --verbose -d postgres > $BASE_PATH/results/log_incr1 2>&1
#pg_rman -p $TEST_PGPORT backup -b i --verbose -d postgres > $BASE_PATH/results/log_incr1 2>&1
pg_rman -w -p $TEST_PGPORT backup -b i --verbose -d postgres > $BASE_PATH/results/log_incr1 2>&1
# validate all backup
pg_rman validate `date +%Y` --verbose > $BASE_PATH/results/log_validate1 2>&1
@ -136,11 +140,13 @@ pg_rman -p $TEST_PGPORT show `date +%Y` -a --verbose -d postgres > $BASE_PATH/re
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
#pg_rman -p $TEST_PGPORT backup -b i --verbose -d postgres > $BASE_PATH/results/log_incr2 2>&1
pg_rman -w -p $TEST_PGPORT backup -b i --verbose -d postgres > $BASE_PATH/results/log_incr2 2>&1
pgbench -p $TEST_PGPORT -T $DURATION -c 10 pgbench >> $BASE_PATH/results/pgbench.log 2>&1
echo "archived WAL and serverlog backup"
pg_rman -p $TEST_PGPORT backup -b a --verbose -d postgres > $BASE_PATH/results/log_arclog 2>&1
#pg_rman -p $TEST_PGPORT backup -b a --verbose -d postgres > $BASE_PATH/results/log_arclog 2>&1
pg_rman -w -p $TEST_PGPORT backup -b a --verbose -d postgres > $BASE_PATH/results/log_arclog 2>&1
# stop PG during transaction and get commited info for verifing
echo "stop DB during running pgbench"
@ -211,7 +217,8 @@ diff $BASE_PATH/results/dump_before.sql $BASE_PATH/results/dump_after.sql
# incrementa backup can't find last full backup because new timeline started.
echo "full database backup after recovery"
psql -p $TEST_PGPORT postgres -c "checkpoint"
pg_rman -p $TEST_PGPORT backup -b f --verbose -d postgres > $BASE_PATH/results/log_full2 2>&1
#pg_rman -p $TEST_PGPORT backup -b f --verbose -d postgres > $BASE_PATH/results/log_full2 2>&1
pg_rman -w -p $TEST_PGPORT backup -b f --verbose -d postgres > $BASE_PATH/results/log_full2 2>&1
# Backup of online-WAL should been deleted, but serverlog remain.
echo "# of files in BACKUP_PATH/backup/pg_xlog"

View File

@ -1,4 +1,4 @@
\! rm -rf results/init_test
\! pg_rman init -B results/init_test --quiet;echo $?
\! pg_rman init -B ${PWD}/results/init_test --quiet;echo $?
\! find results/init_test | xargs ls -Fd | sort
\! pg_rman init -B results/init_test --quiet;echo $?
\! pg_rman init -B ${PWD}/results/init_test --quiet;echo $?

View File

@ -1,8 +1,8 @@
-- test show command
\! rm -rf results/sample_backup
\! cp -rp data/sample_backup results/sample_backup
\! pg_rman show -B results/sample_backup
\! pg_rman validate -B results/sample_backup 2009-05-31 17:05:53 --debug
\! pg_rman validate -B results/sample_backup 2009-06-01 17:05:53 --debug
\! pg_rman show -a -B results/sample_backup
\! pg_rman show 2009-06-01 17:05:53 -B results/sample_backup
\! rm -rf ${PWD}/results/sample_backup
\! cp -rp data/sample_backup ${PWD}/results/sample_backup
\! pg_rman show -B ${PWD}/results/sample_backup
\! pg_rman validate -B ${PWD}/results/sample_backup 2009-05-31 17:05:53 --debug
\! pg_rman validate -B ${PWD}/results/sample_backup 2009-06-01 17:05:53 --debug
\! pg_rman show -a -B ${PWD}/results/sample_backup
\! pg_rman show 2009-06-01 17:05:53 -B ${PWD}/results/sample_backup

2
util.c
View File

@ -2,7 +2,7 @@
*
* util.c: log messages to log file or stderr, and misc code.
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/

View File

@ -2,7 +2,7 @@
*
* utils.c:
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/

View File

@ -2,7 +2,7 @@
*
* validate.c: validate backup files.
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -22,22 +22,36 @@ do_validate(pgBackupRange *range)
{
int i;
parray *backup_list;
int ret;
bool another_pg_rman = false;
catalog_lock();
ret = catalog_lock();
if (ret == 1)
another_pg_rman = true;
/* get backup list matches given range */
backup_list = catalog_get_backup_list(range);
if(!backup_list){
elog(ERROR_SYSTEM, _("can't process any more."));
}
parray_qsort(backup_list, pgBackupCompareId);
for (i = 0; i < parray_num(backup_list); i++)
{
pgBackup *backup = (pgBackup *)parray_get(backup_list, i);
/* clean extra backups (switch STATUS to ERROR) */
if(!another_pg_rman &&
(backup->status == BACKUP_STATUS_RUNNING || backup->status == BACKUP_STATUS_DELETING)){
backup->status = BACKUP_STATUS_ERROR;
pgBackupWriteIni(backup);
}
/* Validate completed backups only. */
if (backup->status != BACKUP_STATUS_DONE)
continue;
/* validate with CRC value and update status to OK */
pgBackupValidate(backup, false);
pgBackupValidate(backup, false, false, (HAVE_DATABASE(backup)));
}
/* cleanup */
@ -53,7 +67,7 @@ do_validate(pgBackupRange *range)
* Validate each files in the backup with its size.
*/
void
pgBackupValidate(pgBackup *backup, bool size_only)
pgBackupValidate(pgBackup *backup, bool size_only, bool for_get_timeline, bool with_database)
{
char timestamp[100];
char base_path[MAXPGPATH];
@ -62,54 +76,65 @@ pgBackupValidate(pgBackup *backup, bool size_only)
bool corrupted = false;
time2iso(timestamp, lengthof(timestamp), backup->start_time);
elog(INFO, "validate: %s", timestamp);
if (HAVE_DATABASE(backup))
{
elog(LOG, "database files...");
pgBackupGetPath(backup, base_path, lengthof(base_path), DATABASE_DIR);
pgBackupGetPath(backup, path, lengthof(path),
DATABASE_FILE_LIST);
files = dir_read_file_list(base_path, path);
if (!pgBackupValidateFiles(files, base_path, size_only))
corrupted = true;
parray_walk(files, pgFileFree);
parray_free(files);
}
if (HAVE_ARCLOG(backup))
{
elog(LOG, "archive WAL files...");
pgBackupGetPath(backup, base_path, lengthof(base_path), ARCLOG_DIR);
pgBackupGetPath(backup, path, lengthof(path), ARCLOG_FILE_LIST);
files = dir_read_file_list(base_path, path);
if (!pgBackupValidateFiles(files, base_path, size_only))
corrupted = true;
parray_walk(files, pgFileFree);
parray_free(files);
}
if (backup->with_serverlog)
{
elog(LOG, "server log files...");
pgBackupGetPath(backup, base_path, lengthof(base_path), SRVLOG_DIR);
pgBackupGetPath(backup, path, lengthof(path), SRVLOG_FILE_LIST);
files = dir_read_file_list(base_path, path);
if (!pgBackupValidateFiles(files, base_path, size_only))
corrupted = true;
parray_walk(files, pgFileFree);
parray_free(files);
if(!for_get_timeline){
if (with_database)
elog(INFO, "validate: %s backup and archive log files by %s", timestamp, (size_only ? "SIZE" : "CRC"));
else{
if (backup->backup_mode == BACKUP_MODE_ARCHIVE)
elog(INFO, "validate: %s archive log files by %s", timestamp, (size_only ? "SIZE" : "CRC"));
else if (backup->with_serverlog)
elog(INFO, "validate: %s server log files by %s", timestamp, (size_only ? "SIZE" : "CRC"));
}
}
/* update status to OK */
if (corrupted)
backup->status = BACKUP_STATUS_CORRUPT;
else
backup->status = BACKUP_STATUS_OK;
pgBackupWriteIni(backup);
if(!check){
if (HAVE_DATABASE(backup))
{
elog(LOG, "database files...");
pgBackupGetPath(backup, base_path, lengthof(base_path), DATABASE_DIR);
pgBackupGetPath(backup, path, lengthof(path),
DATABASE_FILE_LIST);
files = dir_read_file_list(base_path, path);
if (!pgBackupValidateFiles(files, base_path, size_only))
corrupted = true;
parray_walk(files, pgFileFree);
parray_free(files);
}
if (HAVE_ARCLOG(backup))
{
elog(LOG, "archive WAL files...");
pgBackupGetPath(backup, base_path, lengthof(base_path), ARCLOG_DIR);
pgBackupGetPath(backup, path, lengthof(path), ARCLOG_FILE_LIST);
files = dir_read_file_list(base_path, path);
if (!pgBackupValidateFiles(files, base_path, size_only))
corrupted = true;
parray_walk(files, pgFileFree);
parray_free(files);
}
if (backup->with_serverlog)
{
elog(LOG, "server log files...");
pgBackupGetPath(backup, base_path, lengthof(base_path), SRVLOG_DIR);
pgBackupGetPath(backup, path, lengthof(path), SRVLOG_FILE_LIST);
files = dir_read_file_list(base_path, path);
if (!pgBackupValidateFiles(files, base_path, size_only))
corrupted = true;
parray_walk(files, pgFileFree);
parray_free(files);
}
if (corrupted)
elog(WARNING, "backup %s is corrupted", timestamp);
else
elog(LOG, "backup %s is valid", timestamp);
/* update status to OK */
if (corrupted)
backup->status = BACKUP_STATUS_CORRUPT;
else
backup->status = BACKUP_STATUS_OK;
pgBackupWriteIni(backup);
if (corrupted)
elog(WARNING, "backup %s is corrupted", timestamp);
else
elog(LOG, "backup %s is valid", timestamp);
}
}
static const char *

View File

@ -2,7 +2,7 @@
*
* verify.c: verify backup files.
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/

5
xlog.c
View File

@ -2,7 +2,7 @@
*
* xlog.c: Parse WAL files.
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
*-------------------------------------------------------------------------
*/
@ -27,6 +27,7 @@ typedef struct MemoryContextData *MemoryContext;
#define XLOG_PAGE_MAGIC_v83 0xD062 /* 8.3 */
#define XLOG_PAGE_MAGIC_v84 0xD063 /* 8.4 */
#define XLOG_PAGE_MAGIC_v90 0xD064 /* 9.0 */
#define XLOG_PAGE_MAGIC_v91 0xD066 /* 9.1 */
/*
* XLogLongPageHeaderData is modified in 8.3, but the layout is compatible
@ -75,6 +76,8 @@ xlog_is_complete_wal(const pgFile *file, int server_version)
xlog_page_magic = XLOG_PAGE_MAGIC_v84;
else if (server_version < 90100)
xlog_page_magic = XLOG_PAGE_MAGIC_v90;
else if (server_version < 90200)
xlog_page_magic = XLOG_PAGE_MAGIC_v91;
else
return false; /* not supported */