You've already forked pg_probackup
mirror of
https://github.com/postgrespro/pg_probackup.git
synced 2026-06-21 01:34:15 +02:00
Add muti-thread validation.
This commit is contained in:
@@ -178,6 +178,9 @@ main(int argc, char *argv[])
|
|||||||
if (target_time != NULL && target_xid != NULL)
|
if (target_time != NULL && target_xid != NULL)
|
||||||
elog(ERROR, "You can't specify recovery-target-time and recovery-target-xid at the same time");
|
elog(ERROR, "You can't specify recovery-target-time and recovery-target-xid at the same time");
|
||||||
|
|
||||||
|
if (num_threads < 1)
|
||||||
|
num_threads = 1;
|
||||||
|
|
||||||
/* do actual operation */
|
/* do actual operation */
|
||||||
if (pg_strcasecmp(cmd, "init") == 0)
|
if (pg_strcasecmp(cmd, "init") == 0)
|
||||||
return do_init();
|
return do_init();
|
||||||
|
|||||||
@@ -335,9 +335,6 @@ restore_database(pgBackup *backup)
|
|||||||
pgFileFree(parray_remove(files, i));
|
pgFileFree(parray_remove(files, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_threads < 1)
|
|
||||||
num_threads = 1;
|
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
+63
-18
@@ -10,8 +10,17 @@
|
|||||||
#include "pg_probackup.h"
|
#include "pg_probackup.h"
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
static bool pgBackupValidateFiles(parray *files, const char *root, bool size_only);
|
static void pgBackupValidateFiles(void *arg);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
parray *files;
|
||||||
|
const char *root;
|
||||||
|
bool size_only;
|
||||||
|
bool corrupted;
|
||||||
|
} validate_files_args;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Validate files in the backup and update its status to OK.
|
* Validate files in the backup and update its status to OK.
|
||||||
@@ -85,6 +94,8 @@ pgBackupValidate(pgBackup *backup,
|
|||||||
char path[MAXPGPATH];
|
char path[MAXPGPATH];
|
||||||
parray *files;
|
parray *files;
|
||||||
bool corrupted = false;
|
bool corrupted = false;
|
||||||
|
pthread_t validate_threads[num_threads];
|
||||||
|
validate_files_args *validate_threads_args[num_threads];
|
||||||
|
|
||||||
time2iso(timestamp, lengthof(timestamp), backup->recovery_time);
|
time2iso(timestamp, lengthof(timestamp), backup->recovery_time);
|
||||||
if (!for_get_timeline)
|
if (!for_get_timeline)
|
||||||
@@ -102,13 +113,41 @@ pgBackupValidate(pgBackup *backup,
|
|||||||
backup->backup_mode == BACKUP_MODE_DIFF_PAGE ||
|
backup->backup_mode == BACKUP_MODE_DIFF_PAGE ||
|
||||||
backup->backup_mode == BACKUP_MODE_DIFF_PTRACK)
|
backup->backup_mode == BACKUP_MODE_DIFF_PTRACK)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
elog(LOG, "database files...");
|
elog(LOG, "database files...");
|
||||||
pgBackupGetPath(backup, base_path, lengthof(base_path), DATABASE_DIR);
|
pgBackupGetPath(backup, base_path, lengthof(base_path), DATABASE_DIR);
|
||||||
pgBackupGetPath(backup, path, lengthof(path),
|
pgBackupGetPath(backup, path, lengthof(path),
|
||||||
DATABASE_FILE_LIST);
|
DATABASE_FILE_LIST);
|
||||||
files = dir_read_file_list(base_path, path);
|
files = dir_read_file_list(base_path, path);
|
||||||
if (!pgBackupValidateFiles(files, base_path, size_only))
|
|
||||||
corrupted = true;
|
/* setup threads */
|
||||||
|
for (i = 0; i < parray_num(files); i++)
|
||||||
|
{
|
||||||
|
pgFile *file = (pgFile *) parray_get(files, i);
|
||||||
|
__sync_lock_release(&file->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* restore files into $PGDATA */
|
||||||
|
for (i = 0; i < num_threads; i++)
|
||||||
|
{
|
||||||
|
validate_files_args *arg = pg_malloc(sizeof(validate_files_args));
|
||||||
|
arg->files = files;
|
||||||
|
arg->root = base_path;
|
||||||
|
arg->size_only = size_only;
|
||||||
|
arg->corrupted = false;
|
||||||
|
|
||||||
|
validate_threads_args[i] = arg;
|
||||||
|
pthread_create(&validate_threads[i], NULL, (void *(*)(void *)) pgBackupValidateFiles, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait theads */
|
||||||
|
for (i = 0; i < num_threads; i++)
|
||||||
|
{
|
||||||
|
pthread_join(validate_threads[i], NULL);
|
||||||
|
if (validate_threads_args[i]->corrupted)
|
||||||
|
corrupted = true;
|
||||||
|
pg_free(validate_threads_args[i]);
|
||||||
|
}
|
||||||
parray_walk(files, pgFileFree);
|
parray_walk(files, pgFileFree);
|
||||||
parray_free(files);
|
parray_free(files);
|
||||||
}
|
}
|
||||||
@@ -140,16 +179,21 @@ get_relative_path(const char *path, const char *root)
|
|||||||
/*
|
/*
|
||||||
* Validate files in the backup with size or CRC.
|
* Validate files in the backup with size or CRC.
|
||||||
*/
|
*/
|
||||||
static bool
|
static void
|
||||||
pgBackupValidateFiles(parray *files, const char *root, bool size_only)
|
pgBackupValidateFiles(void *arg)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < parray_num(files); i++)
|
validate_files_args *arguments = (validate_files_args *)arg;
|
||||||
|
|
||||||
|
|
||||||
|
for (i = 0; i < parray_num(arguments->files); i++)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
pgFile *file = (pgFile *) parray_get(files, i);
|
pgFile *file = (pgFile *) parray_get(arguments->files, i);
|
||||||
|
if (__sync_lock_test_and_set(&file->lock, 1) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (interrupted)
|
if (interrupted)
|
||||||
elog(ERROR, "interrupted during validate");
|
elog(ERROR, "interrupted during validate");
|
||||||
@@ -159,8 +203,8 @@ pgBackupValidateFiles(parray *files, const char *root, bool size_only)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* print progress */
|
/* print progress */
|
||||||
elog(LOG, "(%d/%lu) %s", i + 1, (unsigned long) parray_num(files),
|
elog(LOG, "(%d/%lu) %s", i + 1, (unsigned long) parray_num(arguments->files),
|
||||||
get_relative_path(file->path, root));
|
get_relative_path(file->path, arguments->root));
|
||||||
|
|
||||||
/* always validate file size */
|
/* always validate file size */
|
||||||
if (stat(file->path, &st) == -1)
|
if (stat(file->path, &st) == -1)
|
||||||
@@ -169,20 +213,22 @@ pgBackupValidateFiles(parray *files, const char *root, bool size_only)
|
|||||||
elog(WARNING, "backup file \"%s\" vanished", file->path);
|
elog(WARNING, "backup file \"%s\" vanished", file->path);
|
||||||
else
|
else
|
||||||
elog(ERROR, "cannot stat backup file \"%s\": %s",
|
elog(ERROR, "cannot stat backup file \"%s\": %s",
|
||||||
get_relative_path(file->path, root), strerror(errno));
|
get_relative_path(file->path, arguments->root), strerror(errno));
|
||||||
return false;
|
arguments->corrupted = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (file->write_size != st.st_size)
|
if (file->write_size != st.st_size)
|
||||||
{
|
{
|
||||||
elog(WARNING, "size of backup file \"%s\" must be %lu but %lu",
|
elog(WARNING, "size of backup file \"%s\" must be %lu but %lu",
|
||||||
get_relative_path(file->path, root),
|
get_relative_path(file->path, arguments->root),
|
||||||
(unsigned long) file->write_size,
|
(unsigned long) file->write_size,
|
||||||
(unsigned long) st.st_size);
|
(unsigned long) st.st_size);
|
||||||
return false;
|
arguments->corrupted = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* validate CRC too */
|
/* validate CRC too */
|
||||||
if (!size_only)
|
if (!arguments->size_only)
|
||||||
{
|
{
|
||||||
pg_crc32 crc;
|
pg_crc32 crc;
|
||||||
|
|
||||||
@@ -190,11 +236,10 @@ pgBackupValidateFiles(parray *files, const char *root, bool size_only)
|
|||||||
if (crc != file->crc)
|
if (crc != file->crc)
|
||||||
{
|
{
|
||||||
elog(WARNING, "CRC of backup file \"%s\" must be %X but %X",
|
elog(WARNING, "CRC of backup file \"%s\" must be %X but %X",
|
||||||
get_relative_path(file->path, root), file->crc, crc);
|
get_relative_path(file->path, arguments->root), file->crc, crc);
|
||||||
return false;
|
arguments->corrupted = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user