Fix a critical bug that pg_rman cannot restore database from incremental backup. Backup itself worked correctly, but restore command broke database files.

git-svn-id: http://pg-rman.googlecode.com/svn/trunk@25 182aca00-e38e-11de-a668-6fd11605f5ce
This commit is contained in:
itagaki.takahiro
2009-12-22 07:36:31 +00:00
parent bc5717b1e0
commit 59d0911fa7
9 changed files with 193 additions and 194 deletions
+45 -40
View File
@@ -30,7 +30,7 @@ static void backup_cleanup(bool fatal, void *userdata);
static void delete_old_files(const char *root, parray *files, int keep_files, static void delete_old_files(const char *root, parray *files, int keep_files,
int keep_days, int server_version, bool is_arclog); int keep_days, int server_version, bool is_arclog);
static void backup_files(const char *from_root, const char *to_root, static void backup_files(const char *from_root, const char *to_root,
parray *files, parray *prev_files, XLogRecPtr *lsn, bool compress_data); parray *files, parray *prev_files, const XLogRecPtr *lsn, bool compress);
static parray *do_backup_database(parray *backup_list, bool smooth_checkpoint); static parray *do_backup_database(parray *backup_list, bool smooth_checkpoint);
static parray *do_backup_arclog(parray *backup_list); static parray *do_backup_arclog(parray *backup_list);
static parray *do_backup_srvlog(parray *backup_list); static parray *do_backup_srvlog(parray *backup_list);
@@ -137,7 +137,7 @@ do_backup_database(parray *backup_list, bool smooth_checkpoint)
files = parray_new(); files = parray_new();
dir_list_file(files, pgdata, pgdata_exclude, true, false); dir_list_file(files, pgdata, pgdata_exclude, true, false);
/* mark files as 'datafile' which are under base/global/pg_tblspc */ /* mark files that are possible datafile as 'datafile' */
for (i = 0; i < parray_num(files); i++) for (i = 0; i < parray_num(files); i++)
{ {
pgFile *file = (pgFile *) parray_get(files, i); pgFile *file = (pgFile *) parray_get(files, i);
@@ -148,7 +148,7 @@ do_backup_database(parray *backup_list, bool smooth_checkpoint)
if (!S_ISREG(file->mode)) if (!S_ISREG(file->mode))
continue; continue;
/* data files are under base/global/pg_tblspc */ /* data files are under "base", "global", or "pg_tblspc" */
relative = file->path + strlen(pgdata) + 1; relative = file->path + strlen(pgdata) + 1;
if (!path_is_prefix_of_path("base", relative) && if (!path_is_prefix_of_path("base", relative) &&
!path_is_prefix_of_path("global", relative) && !path_is_prefix_of_path("global", relative) &&
@@ -214,16 +214,16 @@ do_backup_database(parray *backup_list, bool smooth_checkpoint)
static parray * static parray *
do_backup_arclog(parray *backup_list) do_backup_arclog(parray *backup_list)
{ {
int i; int i;
parray *files; parray *files;
parray *prev_files = NULL; /* file list of previous database backup */ parray *prev_files = NULL; /* file list of previous database backup */
FILE *fp; FILE *fp;
char path[MAXPGPATH]; char path[MAXPGPATH];
char timeline_dir[MAXPGPATH]; char timeline_dir[MAXPGPATH];
char prev_file_txt[MAXPGPATH]; char prev_file_txt[MAXPGPATH];
pgBackup *prev_backup; pgBackup *prev_backup;
int64 arclog_write_bytes = 0; int64 arclog_write_bytes = 0;
char last_wal[MAXPGPATH]; char last_wal[MAXPGPATH];
if (!HAVE_ARCLOG(&current)) if (!HAVE_ARCLOG(&current))
return NULL; return NULL;
@@ -345,14 +345,14 @@ do_backup_arclog(parray *backup_list)
static parray * static parray *
do_backup_srvlog(parray *backup_list) do_backup_srvlog(parray *backup_list)
{ {
int i; int i;
parray *files; parray *files;
parray *prev_files = NULL; /* file list of previous database backup */ parray *prev_files = NULL; /* file list of previous database backup */
FILE *fp; FILE *fp;
char path[MAXPGPATH]; char path[MAXPGPATH];
char prev_file_txt[MAXPGPATH]; char prev_file_txt[MAXPGPATH];
pgBackup *prev_backup; pgBackup *prev_backup;
int64 srvlog_write_bytes = 0; int64 srvlog_write_bytes = 0;
if (!current.with_serverlog) if (!current.with_serverlog)
return NULL; return NULL;
@@ -818,10 +818,14 @@ backup_cleanup(bool fatal, void *userdata)
/* take incremental backup. */ /* take incremental backup. */
static void static void
backup_files(const char *from_root, const char *to_root, parray *files, backup_files(const char *from_root,
parray *prev_files, XLogRecPtr *lsn, bool compress_data) const char *to_root,
parray *files,
parray *prev_files,
const XLogRecPtr *lsn,
bool compress)
{ {
int i; int i;
struct timeval tv; struct timeval tv;
/* sort pathname ascending */ /* sort pathname ascending */
@@ -832,8 +836,9 @@ backup_files(const char *from_root, const char *to_root, parray *files,
/* backup a file or create a directory */ /* backup a file or create a directory */
for (i = 0; i < parray_num(files); i++) for (i = 0; i < parray_num(files); i++)
{ {
int ret; int ret;
struct stat buf; struct stat buf;
pgFile *file = (pgFile *) parray_get(files, i); pgFile *file = (pgFile *) parray_get(files, i);
/* check for interrupt */ /* check for interrupt */
@@ -869,6 +874,7 @@ backup_files(const char *from_root, const char *to_root, parray *files,
if (S_ISDIR(buf.st_mode)) if (S_ISDIR(buf.st_mode))
{ {
char dirpath[MAXPGPATH]; char dirpath[MAXPGPATH];
snprintf(dirpath, lengthof(dirpath), "%s/%s", to_root, snprintf(dirpath, lengthof(dirpath), "%s/%s", to_root,
file->path + strlen(from_root) + 1); file->path + strlen(from_root) + 1);
if (!check) if (!check)
@@ -918,7 +924,7 @@ backup_files(const char *from_root, const char *to_root, parray *files,
/* copy the file into backup */ /* copy the file into backup */
if (file->is_datafile) if (file->is_datafile)
{ {
backup_data_file(from_root, to_root, file, lsn, compress_data); backup_data_file(from_root, to_root, file, lsn, compress);
if (file->write_size == 0 && file->read_size > 0) if (file->write_size == 0 && file->read_size > 0)
{ {
/* record as skipped file in file_xxx.txt */ /* record as skipped file in file_xxx.txt */
@@ -930,7 +936,7 @@ backup_files(const char *from_root, const char *to_root, parray *files,
} }
else else
copy_file(from_root, to_root, file, copy_file(from_root, to_root, file,
compress_data ? COMPRESSION : NO_COMPRESSION); compress ? COMPRESSION : NO_COMPRESSION);
if (verbose) if (verbose)
{ {
@@ -965,11 +971,10 @@ delete_old_files(const char *root,
int server_version, int server_version,
bool is_arclog) bool is_arclog)
{ {
int i; int i;
int j; int j;
int file_num = 0; int file_num = 0;
time_t days_threashold = time_t days_threshold = current.start_time - (keep_days * 60 * 60 * 24);
current.start_time - (keep_days * 60 * 60 * 24);
if (verbose) if (verbose)
{ {
@@ -990,7 +995,7 @@ delete_old_files(const char *root,
root, files_str, days_str); root, files_str, days_str);
} }
/* delete files which satisfy both condition */ /* delete files which satisfy both conditions */
if (keep_files == KEEP_INFINITE || keep_days == KEEP_INFINITE) if (keep_files == KEEP_INFINITE || keep_days == KEEP_INFINITE)
{ {
elog(LOG, "%s() infinite", __FUNCTION__); elog(LOG, "%s() infinite", __FUNCTION__);
@@ -1003,7 +1008,7 @@ delete_old_files(const char *root,
pgFile *file = (pgFile *) parray_get(files, i); pgFile *file = (pgFile *) parray_get(files, i);
elog(LOG, "%s() %s", __FUNCTION__, file->path); elog(LOG, "%s() %s", __FUNCTION__, file->path);
/* Delete complete WAL only. */ /* Delete completed WALs only. */
if (is_arclog && !xlog_is_complete_wal(file, server_version)) if (is_arclog && !xlog_is_complete_wal(file, server_version))
{ {
elog(LOG, "%s() not complete WAL", __FUNCTION__); elog(LOG, "%s() not complete WAL", __FUNCTION__);
@@ -1013,17 +1018,17 @@ delete_old_files(const char *root,
file_num++; file_num++;
/* /*
* If the mtime of the file is older than the threashold and there are * If the mtime of the file is older than the threshold and there are
* enough number of files newer than the files, delete the file. * enough number of files newer than the files, delete the file.
*/ */
if (file->mtime >= days_threashold) if (file->mtime >= days_threshold)
{ {
elog(LOG, "%s() %lu is not older than %lu", __FUNCTION__, elog(LOG, "%s() %lu is not older than %lu", __FUNCTION__,
file->mtime, days_threashold); file->mtime, days_threshold);
continue; continue;
} }
elog(LOG, "%s() %lu is older than %lu", __FUNCTION__, elog(LOG, "%s() %lu is older than %lu", __FUNCTION__,
file->mtime, days_threashold); file->mtime, days_threshold);
if (file_num <= keep_files) if (file_num <= keep_files)
{ {
@@ -1035,7 +1040,7 @@ delete_old_files(const char *root,
if (verbose) if (verbose)
printf(_("delete \"%s\"\n"), file->path + strlen(root) + 1); printf(_("delete \"%s\"\n"), file->path + strlen(root) + 1);
/* delete corresponding backup history file if any */ /* delete corresponding backup history file if exists */
file = (pgFile *) parray_remove(files, i); file = (pgFile *) parray_remove(files, i);
for (j = parray_num(files) - 1; j >= 0; j--) for (j = parray_num(files) - 1; j >= 0; j--)
{ {
+4 -4
View File
@@ -247,8 +247,8 @@ err_proc:
pgBackup * pgBackup *
catalog_get_last_data_backup(parray *backup_list) catalog_get_last_data_backup(parray *backup_list)
{ {
int i; int i;
pgBackup *backup = NULL; pgBackup *backup = NULL;
/* backup_list is sorted in order of descending ID */ /* backup_list is sorted in order of descending ID */
for (i = 0; i < parray_num(backup_list); i++) for (i = 0; i < parray_num(backup_list); i++)
@@ -269,8 +269,8 @@ catalog_get_last_data_backup(parray *backup_list)
pgBackup * pgBackup *
catalog_get_last_arclog_backup(parray *backup_list) catalog_get_last_arclog_backup(parray *backup_list)
{ {
int i; int i;
pgBackup *backup = NULL; pgBackup *backup = NULL;
/* backup_list is sorted in order of descending ID */ /* backup_list is sorted in order of descending ID */
for (i = 0; i < parray_num(backup_list); i++) for (i = 0; i < parray_num(backup_list); i++)
+66 -56
View File
@@ -261,7 +261,8 @@ parse_page(const DataPage *page, int server_version,
return true; return true;
} }
} }
*offset = *length = 0;
return false; return false;
} }
@@ -273,7 +274,7 @@ parse_page(const DataPage *page, int server_version,
*/ */
void void
backup_data_file(const char *from_root, const char *to_root, backup_data_file(const char *from_root, const char *to_root,
pgFile *file, const XLogRecPtr *lsn, bool compress_data) pgFile *file, const XLogRecPtr *lsn, bool compress)
{ {
char to_path[MAXPGPATH]; char to_path[MAXPGPATH];
FILE *in; FILE *in;
@@ -324,7 +325,7 @@ backup_data_file(const char *from_root, const char *to_root,
file->write_size = 0; file->write_size = 0;
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
if (compress_data) if (compress)
{ {
z.zalloc = Z_NULL; z.zalloc = Z_NULL;
z.zfree = Z_NULL; z.zfree = Z_NULL;
@@ -366,7 +367,7 @@ backup_data_file(const char *from_root, const char *to_root,
fclose(out); fclose(out);
file->is_datafile = false; file->is_datafile = false;
copy_file(from_root, to_root, file, copy_file(from_root, to_root, file,
compress_data ? COMPRESSION : NO_COMPRESSION); compress ? COMPRESSION : NO_COMPRESSION);
return; return;
} }
@@ -380,7 +381,7 @@ backup_data_file(const char *from_root, const char *to_root,
upper_length = BLCKSZ - upper_offset; upper_length = BLCKSZ - upper_offset;
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
if (compress_data) if (compress)
{ {
doDeflate(&z, sizeof(header), sizeof(outbuf), &header, outbuf, in, doDeflate(&z, sizeof(header), sizeof(outbuf), &header, outbuf, in,
out, &crc, &file->write_size, Z_NO_FLUSH); out, &crc, &file->write_size, Z_NO_FLUSH);
@@ -444,7 +445,7 @@ backup_data_file(const char *from_root, const char *to_root,
header.hole_length = 0; header.hole_length = 0;
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
if (compress_data) if (compress)
{ {
doDeflate(&z, sizeof(header), sizeof(outbuf), &header, outbuf, doDeflate(&z, sizeof(header), sizeof(outbuf), &header, outbuf,
in, out, &crc, &file->write_size, Z_NO_FLUSH); in, out, &crc, &file->write_size, Z_NO_FLUSH);
@@ -469,7 +470,7 @@ backup_data_file(const char *from_root, const char *to_root,
/* write odd size page image */ /* write odd size page image */
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
if (compress_data) if (compress)
{ {
doDeflate(&z, read_len, sizeof(outbuf), page.data, outbuf, in, out, doDeflate(&z, read_len, sizeof(outbuf), page.data, outbuf, in, out,
&crc, &file->write_size, Z_NO_FLUSH); &crc, &file->write_size, Z_NO_FLUSH);
@@ -495,7 +496,7 @@ backup_data_file(const char *from_root, const char *to_root,
} }
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
if (compress_data) if (compress)
{ {
if (file->read_size > 0) if (file->read_size > 0)
{ {
@@ -512,9 +513,12 @@ backup_data_file(const char *from_root, const char *to_root,
elog(ERROR_SYSTEM, _("can't close compression stream: %s"), z.msg); elog(ERROR_SYSTEM, _("can't close compression stream: %s"), z.msg);
} }
} }
#endif #endif
/* update file permission */
/*
* update file permission
* FIXME: Should set permission on open?
*/
if (!check && chmod(to_path, FILE_PERMISSION) == -1) if (!check && chmod(to_path, FILE_PERMISSION) == -1)
{ {
int errno_tmp = errno; int errno_tmp = errno;
@@ -551,26 +555,29 @@ backup_data_file(const char *from_root, const char *to_root,
* same relative path. * same relative path.
*/ */
void void
restore_data_file(const char *from_root, const char *to_root, pgFile *file, bool compress_data) restore_data_file(const char *from_root,
const char *to_root,
pgFile *file,
bool compress)
{ {
char to_path[MAXPGPATH]; char to_path[MAXPGPATH];
FILE *in; FILE *in;
FILE *out; FILE *out;
BackupPageHeader header; BackupPageHeader header;
BlockNumber blknum; BlockNumber blknum;
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
z_stream z; z_stream z;
int status; int status;
char inbuf[zlibInSize]; char inbuf[zlibInSize];
pg_crc32 crc; pg_crc32 crc;
size_t read_size; size_t read_size;
#endif #endif
/* If the file is not a datafile, copy it. */ /* If the file is not a datafile, just copy it. */
if (!file->is_datafile) if (!file->is_datafile)
{ {
copy_file(from_root, to_root, file, copy_file(from_root, to_root, file,
compress_data ? DECOMPRESSION : NO_COMPRESSION); compress ? DECOMPRESSION : NO_COMPRESSION);
return; return;
} }
@@ -582,10 +589,16 @@ restore_data_file(const char *from_root, const char *to_root, pgFile *file, bool
strerror(errno)); strerror(errno));
} }
/* open backup file for write */ /*
* Open backup file for write. We use "r+" at first to overwrite only
* modified pages for incremental restore. If the file is not exists,
* re-open it with "w" to create an empty file.
*/
snprintf(to_path, lengthof(to_path), "%s/%s", to_root, snprintf(to_path, lengthof(to_path), "%s/%s", to_root,
file->path + strlen(from_root) + 1); file->path + strlen(from_root) + 1);
out = fopen(to_path, "w"); out = fopen(to_path, "r+");
if (out == NULL && errno == ENOENT)
out = fopen(to_path, "w");
if (out == NULL) if (out == NULL)
{ {
int errno_tmp = errno; int errno_tmp = errno;
@@ -595,7 +608,7 @@ restore_data_file(const char *from_root, const char *to_root, pgFile *file, bool
} }
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
if (compress_data) if (compress)
{ {
z.zalloc = Z_NULL; z.zalloc = Z_NULL;
z.zfree = Z_NULL; z.zfree = Z_NULL;
@@ -611,16 +624,16 @@ restore_data_file(const char *from_root, const char *to_root, pgFile *file, bool
} }
#endif #endif
for (blknum = 0; ;blknum++) for (blknum = 0; ; blknum++)
{ {
size_t read_len; size_t read_len;
DataPage page; /* used as read buffer */ DataPage page; /* used as read buffer */
int upper_offset; int upper_offset;
int upper_length; int upper_length;
/* read BackupPageHeader */ /* read BackupPageHeader */
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
if (compress_data) if (compress)
{ {
status = doInflate(&z, sizeof(inbuf), sizeof(header), inbuf, status = doInflate(&z, sizeof(inbuf), sizeof(header), inbuf,
&header, in, out, &crc, &read_size); &header, in, out, &crc, &read_size);
@@ -669,14 +682,15 @@ restore_data_file(const char *from_root, const char *to_root, pgFile *file, bool
/* read lower/upper into page.data and restore hole */ /* read lower/upper into page.data and restore hole */
memset(page.data + header.hole_offset, 0, header.hole_length); memset(page.data + header.hole_offset, 0, header.hole_length);
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
if (compress_data) if (compress)
{ {
elog(LOG, "\n%s() %s %d %d", __FUNCTION__, file->path, header.hole_offset, upper_length); elog(LOG, "\n%s() %s %d %d", __FUNCTION__, file->path, header.hole_offset, upper_length);
if (header.hole_offset > 0) if (header.hole_offset > 0)
{ {
doInflate(&z, sizeof(inbuf), header.hole_offset, inbuf, page.data, doInflate(&z, sizeof(inbuf), header.hole_offset, inbuf,
in, out, &crc, &read_size); page.data, in, out, &crc, &read_size);
if (z.avail_out != 0) if (z.avail_out != 0)
elog(ERROR_SYSTEM, _("can't read block %u of \"%s\""), elog(ERROR_SYSTEM, _("can't read block %u of \"%s\""),
blknum, file->path); blknum, file->path);
@@ -702,25 +716,21 @@ restore_data_file(const char *from_root, const char *to_root, pgFile *file, bool
} }
} }
/* by the incremental backup, we skip in a page without the update. */ /*
if (blknum != header.block) * Seek and write the restored page. Backup might have holes in
{ * incremental backups.
if (fseek(out, (header.block - blknum) * BLCKSZ, SEEK_CUR) < 0) */
elog(ERROR_SYSTEM, _("can't seek restore target file \"%s\": %s"), blknum = header.block;
to_path, strerror(errno)); if (fseek(out, blknum * BLCKSZ, SEEK_SET) < 0)
blknum = header.block; elog(ERROR_SYSTEM, _("can't seek block %u of \"%s\": %s"),
} blknum, to_path, strerror(errno));
if (fwrite(page.data, 1, sizeof(page), out) != sizeof(page)) if (fwrite(page.data, 1, sizeof(page), out) != sizeof(page))
{
elog(ERROR_SYSTEM, _("can't write block %u of \"%s\": %s"), elog(ERROR_SYSTEM, _("can't write block %u of \"%s\": %s"),
blknum, file->path, strerror(errno)); blknum, file->path, strerror(errno));
}
} }
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
if (compress_data && inflateEnd(&z) != Z_OK) if (compress && inflateEnd(&z) != Z_OK)
elog(ERROR_SYSTEM, _("can't close compression stream: %s"), z.msg); elog(ERROR_SYSTEM, _("can't close compression stream: %s"), z.msg);
#endif #endif
@@ -742,14 +752,14 @@ void
copy_file(const char *from_root, const char *to_root, pgFile *file, copy_file(const char *from_root, const char *to_root, pgFile *file,
CompressionMode mode) CompressionMode mode)
{ {
char to_path[MAXPGPATH]; char to_path[MAXPGPATH];
FILE *in; FILE *in;
FILE *out; FILE *out;
size_t read_len = 0; size_t read_len = 0;
int errno_tmp; int errno_tmp;
char buf[8192]; char buf[8192];
struct stat st; struct stat st;
pg_crc32 crc; pg_crc32 crc;
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
z_stream z; z_stream z;
int status; int status;
+5 -5
View File
@@ -74,7 +74,7 @@ pgBackupDelete(int keep_generations, int keep_days)
int i; int i;
parray *backup_list; parray *backup_list;
int backup_num; int backup_num;
time_t days_threashold = current.start_time - (keep_days * 60 * 60 * 24); time_t days_threshold = current.start_time - (keep_days * 60 * 60 * 24);
if (verbose) if (verbose)
{ {
@@ -130,18 +130,18 @@ pgBackupDelete(int keep_generations, int keep_days)
} }
/* /*
* If the start time of the backup is older than the threashold and * If the start time of the backup is older than the threshold and
* there are enough generations of full backups, delete the backup. * there are enough generations of full backups, delete the backup.
*/ */
if (backup->start_time >= days_threashold) if (backup->start_time >= days_threshold)
{ {
elog(LOG, "%s() %lu is not older than %lu", __FUNCTION__, elog(LOG, "%s() %lu is not older than %lu", __FUNCTION__,
backup->start_time, days_threashold); backup->start_time, days_threshold);
continue; continue;
} }
elog(LOG, "%s() %lu is older than %lu", __FUNCTION__, elog(LOG, "%s() %lu is older than %lu", __FUNCTION__,
backup->start_time, days_threashold); backup->start_time, days_threshold);
/* delete backup and update status to DELETED */ /* delete backup and update status to DELETED */
pgBackupDeleteFiles(backup); pgBackupDeleteFiles(backup);
+38 -35
View File
@@ -56,8 +56,8 @@ dir_create_dir(const char *dir, mode_t mode)
static pgFile * static pgFile *
pgFileNew(const char *path, bool omit_symlink) pgFileNew(const char *path, bool omit_symlink)
{ {
struct stat st; struct stat st;
pgFile *file; pgFile *file;
/* stat the file */ /* stat the file */
if ((omit_symlink ? stat(path, &st) : lstat(path, &st)) == -1) if ((omit_symlink ? stat(path, &st) : lstat(path, &st)) == -1)
@@ -84,28 +84,6 @@ pgFileNew(const char *path, bool omit_symlink)
return file; return file;
} }
void
pgFileDump(pgFile *file, FILE *out)
{
char mtime_str[100];
fprintf(out, "=================\n");
if (file)
{
time2iso(mtime_str, 100, file->mtime);
fprintf(out, "mtime=%lu(%s)\n", file->mtime, mtime_str);
fprintf(out, "size=" UINT64_FORMAT "\n", (uint64)file->size);
fprintf(out, "read_size=" UINT64_FORMAT "\n", (uint64)file->read_size);
fprintf(out, "write_size=" UINT64_FORMAT "\n", (uint64)file->write_size);
fprintf(out, "mode=0%o\n", file->mode);
fprintf(out, "crc=%u\n", file->crc);
fprintf(out, "is_datafile=%s\n", file->is_datafile ? "true" : "false");
fprintf(out, "linked=\"%s\"\n", file->linked ? file->linked : "nil");
fprintf(out, "path=\"%s\"\n", file->path);
}
fprintf(out, "=================\n");
}
/* /*
* Delete file pointed by the pgFile. * Delete file pointed by the pgFile.
* If the pgFile points directory, the directory must be empty. * If the pgFile points directory, the directory must be empty.
@@ -141,11 +119,11 @@ delete_file:
pg_crc32 pg_crc32
pgFileGetCRC(pgFile *file) pgFileGetCRC(pgFile *file)
{ {
FILE *fp; FILE *fp;
pg_crc32 crc = 0; pg_crc32 crc = 0;
char buf[1024]; char buf[1024];
size_t len; size_t len;
int errno_tmp; int errno_tmp;
/* open file in binary read mode */ /* open file in binary read mode */
fp = fopen(file->path, "r"); fp = fopen(file->path, "r");
@@ -211,7 +189,8 @@ pgFileCompareMtime(const void *f1, const void *f2)
return 1; return 1;
else if (f1p->mtime < f2p->mtime) else if (f1p->mtime < f2p->mtime)
return -1; return -1;
else return 0; else
return 0;
} }
/* Compare two pgFile with their modify timestamp in descending order. */ /* Compare two pgFile with their modify timestamp in descending order. */
@@ -287,11 +266,11 @@ dir_list_file(parray *files, const char *root, const char *exclude[], bool omit_
*/ */
while (S_ISDIR(file->mode)) while (S_ISDIR(file->mode))
{ {
int i; int i;
bool skip = false; bool skip = false;
DIR *dir; DIR *dir;
struct dirent *dent; struct dirent *dent;
char *dirname; char *dirname;
/* skip entry which matches exclude list */ /* skip entry which matches exclude list */
dirname = strrchr(file->path, '/'); dirname = strrchr(file->path, '/');
@@ -566,3 +545,27 @@ dir_copy_files(const char *from_root, const char *to_root)
parray_walk(files, pgFileFree); parray_walk(files, pgFileFree);
parray_free(files); parray_free(files);
} }
#ifdef NOT_USED
void
pgFileDump(pgFile *file, FILE *out)
{
char mtime_str[100];
fprintf(out, "=================\n");
if (file)
{
time2iso(mtime_str, 100, file->mtime);
fprintf(out, "mtime=%lu(%s)\n", file->mtime, mtime_str);
fprintf(out, "size=" UINT64_FORMAT "\n", (uint64)file->size);
fprintf(out, "read_size=" UINT64_FORMAT "\n", (uint64)file->read_size);
fprintf(out, "write_size=" UINT64_FORMAT "\n", (uint64)file->write_size);
fprintf(out, "mode=0%o\n", file->mode);
fprintf(out, "crc=%u\n", file->crc);
fprintf(out, "is_datafile=%s\n", file->is_datafile ? "true" : "false");
fprintf(out, "linked=\"%s\"\n", file->linked ? file->linked : "nil");
fprintf(out, "path=\"%s\"\n", file->path);
}
fprintf(out, "=================\n");
}
#endif
-1
View File
@@ -235,7 +235,6 @@ extern parray *dir_read_file_list(const char *root, const char *file_txt);
extern int dir_create_dir(const char *path, mode_t mode); extern int dir_create_dir(const char *path, mode_t mode);
extern void dir_copy_files(const char *from_root, const char *to_root); extern void dir_copy_files(const char *from_root, const char *to_root);
extern void pgFileDump(pgFile *file, FILE *out);
extern void pgFileDelete(pgFile *file); extern void pgFileDelete(pgFile *file);
extern void pgFileFree(void *file); extern void pgFileFree(void *file);
extern pg_crc32 pgFileGetCRC(pgFile *file); extern pg_crc32 pgFileGetCRC(pgFile *file);
+5 -7
View File
@@ -156,9 +156,7 @@ do_restore(const char *target_time,
} }
#endif #endif
if (satisfy_timeline(timelines, base_backup)) if (satisfy_timeline(timelines, base_backup))
{
goto base_backup_found; goto base_backup_found;
}
} }
/* no full backup found, can't restore */ /* no full backup found, can't restore */
elog(ERROR_NO_BACKUP, _("no full backup found, can't restore.")); elog(ERROR_NO_BACKUP, _("no full backup found, can't restore."));
@@ -291,12 +289,12 @@ base_backup_found:
void void
restore_database(pgBackup *backup) restore_database(pgBackup *backup)
{ {
char timestamp[100]; char timestamp[100];
char path[MAXPGPATH]; char path[MAXPGPATH];
char list_path[MAXPGPATH]; char list_path[MAXPGPATH];
int ret; int ret;
parray *files; parray *files;
int i; int i;
/* confirm block size compatibility */ /* confirm block size compatibility */
if (backup->block_size != BLCKSZ) if (backup->block_size != BLCKSZ)
+4 -2
View File
@@ -20,7 +20,7 @@ static bool pgBackupValidateFiles(parray *files, const char *root, bool size_onl
int int
do_validate(pgBackupRange *range) do_validate(pgBackupRange *range)
{ {
int i; int i;
parray *backup_list; parray *backup_list;
catalog_lock(); catalog_lock();
@@ -133,6 +133,7 @@ pgBackupValidateFiles(parray *files, const char *root, bool size_only)
for (i = 0; i < parray_num(files); i++) for (i = 0; i < parray_num(files); i++)
{ {
struct stat st; struct stat st;
pgFile *file = (pgFile *) parray_get(files, i); pgFile *file = (pgFile *) parray_get(files, i);
if (interrupted) if (interrupted)
@@ -168,7 +169,8 @@ pgBackupValidateFiles(parray *files, const char *root, bool size_only)
/* validate CRC too */ /* validate CRC too */
if (!size_only) if (!size_only)
{ {
pg_crc32 crc; pg_crc32 crc;
crc = pgFileGetCRC(file); crc = pgFileGetCRC(file);
if (crc != file->crc) if (crc != file->crc)
{ {
+26 -44
View File
@@ -26,29 +26,17 @@ typedef struct MemoryContextData *MemoryContext;
#define XLOG_PAGE_MAGIC_v82 0xD05E /* 8.2 */ #define XLOG_PAGE_MAGIC_v82 0xD05E /* 8.2 */
#define XLOG_PAGE_MAGIC_v83 0xD062 /* 8.3 */ #define XLOG_PAGE_MAGIC_v83 0xD062 /* 8.3 */
#define XLOG_PAGE_MAGIC_v84 0xD063 /* 8.4 */ #define XLOG_PAGE_MAGIC_v84 0xD063 /* 8.4 */
#define XLOG_PAGE_MAGIC_v85 0xD063 /* 8.5 */ #define XLOG_PAGE_MAGIC_v85 0xD166 /* 8.5 */
typedef struct XLogLongPageHeaderData_v81
{
XLogPageHeaderData std;
uint64 xlp_sysid;
uint32 xlp_seg_size;
} XLogLongPageHeaderData_v81, *XLogLongPageHeader_v81;
typedef struct XLogLongPageHeaderData_v82
{
XLogPageHeaderData std; /* standard header fields */
uint64 xlp_sysid; /* system identifier from pg_control */
uint32 xlp_seg_size; /* just as a cross-check */
uint32 xlp_xlog_blcksz; /* just as a cross-check */
} XLogLongPageHeaderData_v82, *XLogLongPageHeader_v82;
/*
* XLogLongPageHeaderData is modified in 8.3, but the layout is compatible
* except xlp_xlog_blcksz.
*/
typedef union XLogPage typedef union XLogPage
{ {
XLogPageHeaderData header; XLogPageHeaderData header;
XLogLongPageHeaderData_v81 long_v81; /* 8.1 - 8.2 */ XLogLongPageHeaderData lheader;
XLogLongPageHeaderData_v82 long_v82; /* 8.3 - */ char data[XLOG_BLCKSZ];
char data[XLOG_BLCKSZ];
} XLogPage; } XLogPage;
/* /*
@@ -73,7 +61,9 @@ xlog_is_complete_wal(const pgFile *file, int server_version)
fclose(fp); fclose(fp);
/* xlog_page_magic from server version */ /* xlog_page_magic from server version */
if (server_version < 80100) if (server_version < 80000)
return false; /* never happen */
else if (server_version < 80100)
xlog_page_magic = XLOG_PAGE_MAGIC_v80; xlog_page_magic = XLOG_PAGE_MAGIC_v80;
else if (server_version < 80200) else if (server_version < 80200)
xlog_page_magic = XLOG_PAGE_MAGIC_v81; xlog_page_magic = XLOG_PAGE_MAGIC_v81;
@@ -83,37 +73,29 @@ xlog_is_complete_wal(const pgFile *file, int server_version)
xlog_page_magic = XLOG_PAGE_MAGIC_v83; xlog_page_magic = XLOG_PAGE_MAGIC_v83;
else if (server_version < 80500) else if (server_version < 80500)
xlog_page_magic = XLOG_PAGE_MAGIC_v84; xlog_page_magic = XLOG_PAGE_MAGIC_v84;
else else if (server_version < 80600)
xlog_page_magic = XLOG_PAGE_MAGIC_v85; xlog_page_magic = XLOG_PAGE_MAGIC_v85;
else
return false; /* not supported */
/* check header */ /* check header */
if (page.header.xlp_magic != xlog_page_magic) if (page.header.xlp_magic != xlog_page_magic)
return false; return false;
if ((page.header.xlp_info & ~XLP_ALL_FLAGS) != 0) if ((page.header.xlp_info & ~XLP_ALL_FLAGS) != 0)
return false; return false;
if (page.header.xlp_info & XLP_LONG_HEADER) if ((page.header.xlp_info & XLP_LONG_HEADER) == 0)
{ return false;
if (page.long_v81.xlp_seg_size != XLogSegSize) if (page.lheader.xlp_seg_size != XLogSegSize)
return false; return false;
if (server_version >= 80300 && page.lheader.xlp_xlog_blcksz != XLOG_BLCKSZ)
return false;
/* compressed WAL (with lesslog) has 0 in lheader->xlp_xlog_blcksz. */ /*
if (server_version >= 80300) * check size (actual file size, not backup file size)
{ * TODO: Support pre-compressed xlog. They might have different file sizes.
if (page.long_v82.xlp_xlog_blcksz == XLOG_BLCKSZ) */
{ if (file->size != XLogSegSize)
/* check size (actual file size, not backup file size) */ return false;
if (file->size != XLogSegSize)
return false;
}
else
{
if (page.long_v82.xlp_xlog_blcksz != 0)
return false;
}
}
else if (file->size != XLogSegSize)
return false;
}
return true; return true;
} }