Skip to content

Commit 9c662d5

Browse files
committed
[Issue #169] Major refactoring of backup, restore and merge internal algorihtms
1 parent e1b0f14 commit 9c662d5

File tree

11 files changed

+1549
-1544
lines changed

11 files changed

+1549
-1544
lines changed

src/backup.c

+135-134
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ static void backup_cleanup(bool fatal, void *userdata);
8080

8181
static void *backup_files(void *arg);
8282

83-
static void do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo);
83+
static void do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync);
8484

8585
static void pg_start_backup(const char *label, bool smooth, pgBackup *backup,
8686
PGNodeInfo *nodeInfo, PGconn *backup_conn, PGconn *master_conn);
@@ -129,7 +129,7 @@ backup_stopbackup_callback(bool fatal, void *userdata)
129129
* Move files from 'pgdata' to a subdirectory in 'backup_path'.
130130
*/
131131
static void
132-
do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo)
132+
do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync)
133133
{
134134
int i;
135135
char database_path[MAXPGPATH];
@@ -155,6 +155,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo)
155155

156156
/* for fancy reporting */
157157
time_t start_time, end_time;
158+
char pretty_time[20];
158159
char pretty_bytes[20];
159160

160161
elog(LOG, "Database backup start");
@@ -452,7 +453,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo)
452453
parray_qsort(backup_files_list, pgFileCompareSize);
453454
/* Sort the array for binary search */
454455
if (prev_backup_filelist)
455-
parray_qsort(prev_backup_filelist, pgFileComparePathWithExternal);
456+
parray_qsort(prev_backup_filelist, pgFileCompareRelPathWithExternal);
456457

457458
/* write initial backup_content.control file and update backup.control */
458459
write_backup_filelist(&current, backup_files_list,
@@ -485,6 +486,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo)
485486
/* Run threads */
486487
thread_interrupted = false;
487488
elog(INFO, "Start transferring data files");
489+
time(&start_time);
488490
for (i = 0; i < num_threads; i++)
489491
{
490492
backup_files_arg *arg = &(threads_args[i]);
@@ -500,10 +502,16 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo)
500502
if (threads_args[i].ret == 1)
501503
backup_isok = false;
502504
}
505+
506+
time(&end_time);
507+
pretty_time_interval(difftime(end_time, start_time),
508+
pretty_time, lengthof(pretty_time));
503509
if (backup_isok)
504-
elog(INFO, "Data files are transferred");
510+
elog(INFO, "Data files are transferred, time elapsed: %s",
511+
pretty_time);
505512
else
506-
elog(ERROR, "Data files transferring failed");
513+
elog(ERROR, "Data files transferring failed, time elapsed: %s",
514+
pretty_time);
507515

508516
/* Remove disappeared during backup files from backup_list */
509517
for (i = 0; i < parray_num(backup_files_list); i++)
@@ -589,7 +597,8 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo)
589597
{
590598
char *ptr = file->path;
591599

592-
file->path = pstrdup(GetRelativePath(ptr, database_path));
600+
file->path = pgut_strdup(GetRelativePath(ptr, database_path));
601+
file->rel_path = pgut_strdup(file->path);
593602
free(ptr);
594603
}
595604
}
@@ -613,6 +622,48 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo)
613622
/* update backup control file to update size info */
614623
write_backup(&current);
615624

625+
/* Sync all copied files unless '--no-sync' flag is used */
626+
if (no_sync)
627+
elog(WARNING, "Backup files are not synced to disk");
628+
else
629+
{
630+
elog(INFO, "Syncing backup files to disk");
631+
time(&start_time);
632+
633+
for (i = 0; i < parray_num(backup_files_list); i++)
634+
{
635+
char to_fullpath[MAXPGPATH];
636+
pgFile *file = (pgFile *) parray_get(backup_files_list, i);
637+
638+
/* TODO: sync directory ? */
639+
if (S_ISDIR(file->mode))
640+
continue;
641+
642+
if (file->write_size <= 0)
643+
continue;
644+
645+
/* construct fullpath */
646+
if (file->external_dir_num == 0)
647+
join_path_components(to_fullpath, database_path, file->rel_path);
648+
else
649+
{
650+
char external_dst[MAXPGPATH];
651+
652+
makeExternalDirPathByNum(external_dst, external_prefix,
653+
file->external_dir_num);
654+
join_path_components(to_fullpath, external_dst, file->rel_path);
655+
}
656+
657+
if (fio_sync(to_fullpath, FIO_BACKUP_HOST) != 0)
658+
elog(ERROR, "Failed to sync file \"%s\": %s", to_fullpath, strerror(errno));
659+
}
660+
661+
time(&end_time);
662+
pretty_time_interval(difftime(end_time, start_time),
663+
pretty_time, lengthof(pretty_time));
664+
elog(INFO, "Backup files are synced, time elapsed: %s", pretty_time);
665+
}
666+
616667
/* clean external directories list */
617668
if (external_dirs)
618669
free_dir_list(external_dirs);
@@ -696,7 +747,7 @@ pgdata_basic_setup(ConnectionOptions conn_opt, PGNodeInfo *nodeInfo)
696747
*/
697748
int
698749
do_backup(time_t start_time, bool no_validate,
699-
pgSetBackupParams *set_backup_params)
750+
pgSetBackupParams *set_backup_params, bool no_sync)
700751
{
701752
PGconn *backup_conn = NULL;
702753
PGNodeInfo nodeInfo;
@@ -795,7 +846,7 @@ do_backup(time_t start_time, bool no_validate,
795846
elog(ERROR, "Options for connection to master must be provided to perform backup from replica");
796847

797848
/* backup data */
798-
do_backup_instance(backup_conn, &nodeInfo);
849+
do_backup_instance(backup_conn, &nodeInfo, no_sync);
799850
pgut_atexit_pop(backup_cleanup, NULL);
800851

801852
/* compute size of wal files of this backup stored in the archive */
@@ -1928,18 +1979,24 @@ static void *
19281979
backup_files(void *arg)
19291980
{
19301981
int i;
1931-
backup_files_arg *arguments = (backup_files_arg *) arg;
1932-
int n_backup_files_list = parray_num(arguments->files_list);
1982+
char from_fullpath[MAXPGPATH];
1983+
char to_fullpath[MAXPGPATH];
19331984
static time_t prev_time;
19341985

1986+
backup_files_arg *arguments = (backup_files_arg *) arg;
1987+
int n_backup_files_list = parray_num(arguments->files_list);
1988+
19351989
prev_time = current.start_time;
19361990

19371991
/* backup a file */
19381992
for (i = 0; i < n_backup_files_list; i++)
19391993
{
1940-
int ret;
1941-
struct stat buf;
1942-
pgFile *file = (pgFile *) parray_get(arguments->files_list, i);
1994+
pgFile *file = (pgFile *) parray_get(arguments->files_list, i);
1995+
pgFile *prev_file = NULL;
1996+
1997+
/* We have already copied all directories */
1998+
if (S_ISDIR(file->mode))
1999+
continue;
19432000

19442001
if (arguments->thread_num == 1)
19452002
{
@@ -1957,147 +2014,91 @@ backup_files(void *arg)
19572014

19582015
if (!pg_atomic_test_set_flag(&file->lock))
19592016
continue;
1960-
elog(VERBOSE, "Copying file: \"%s\"", file->path);
19612017

19622018
/* check for interrupt */
19632019
if (interrupted || thread_interrupted)
19642020
elog(ERROR, "interrupted during backup");
19652021

19662022
if (progress)
19672023
elog(INFO, "Progress: (%d/%d). Process file \"%s\"",
1968-
i + 1, n_backup_files_list, file->path);
2024+
i + 1, n_backup_files_list, file->rel_path);
19692025

1970-
/* stat file to check its current state */
1971-
ret = fio_stat(file->path, &buf, true, FIO_DB_HOST);
1972-
if (ret == -1)
2026+
/* Handle zero sized files */
2027+
if (file->size == 0)
19732028
{
1974-
if (errno == ENOENT)
1975-
{
1976-
/*
1977-
* If file is not found, this is not en error.
1978-
* It could have been deleted by concurrent postgres transaction.
1979-
*/
1980-
file->write_size = FILE_NOT_FOUND;
1981-
elog(LOG, "File \"%s\" is not found", file->path);
1982-
continue;
1983-
}
1984-
else
1985-
{
1986-
elog(ERROR,
1987-
"can't stat file to backup \"%s\": %s",
1988-
file->path, strerror(errno));
1989-
}
1990-
}
1991-
1992-
/* We have already copied all directories */
1993-
if (S_ISDIR(buf.st_mode))
2029+
file->write_size = 0;
19942030
continue;
2031+
}
19952032

1996-
if (S_ISREG(buf.st_mode))
2033+
/* construct destination filepath */
2034+
if (file->external_dir_num == 0)
2035+
{
2036+
join_path_components(from_fullpath, arguments->from_root, file->rel_path);
2037+
join_path_components(to_fullpath, arguments->to_root, file->rel_path);
2038+
}
2039+
else
19972040
{
1998-
pgFile **prev_file = NULL;
1999-
char *external_path = NULL;
2041+
char external_dst[MAXPGPATH];
2042+
char *external_path = parray_get(arguments->external_dirs,
2043+
file->external_dir_num - 1);
20002044

2001-
if (file->external_dir_num)
2002-
external_path = parray_get(arguments->external_dirs,
2003-
file->external_dir_num - 1);
2045+
makeExternalDirPathByNum(external_dst,
2046+
arguments->external_prefix,
2047+
file->external_dir_num);
20042048

2005-
/* Check that file exist in previous backup */
2006-
if (current.backup_mode != BACKUP_MODE_FULL)
2007-
{
2008-
char *relative;
2009-
pgFile key;
2010-
2011-
relative = GetRelativePath(file->path, file->external_dir_num ?
2012-
external_path : arguments->from_root);
2013-
key.path = relative;
2014-
key.external_dir_num = file->external_dir_num;
2015-
2016-
prev_file = (pgFile **) parray_bsearch(arguments->prev_filelist,
2017-
&key, pgFileComparePathWithExternal);
2018-
if (prev_file)
2019-
/* File exists in previous backup */
2020-
file->exists_in_prev = true;
2021-
}
2049+
join_path_components(to_fullpath, external_dst, file->rel_path);
2050+
join_path_components(from_fullpath, external_path, file->rel_path);
2051+
}
20222052

2023-
/* copy the file into backup */
2024-
if (file->is_datafile && !file->is_cfs)
2025-
{
2026-
char to_path[MAXPGPATH];
2027-
2028-
join_path_components(to_path, arguments->to_root,
2029-
file->path + strlen(arguments->from_root) + 1);
2030-
2031-
if (current.backup_mode != BACKUP_MODE_FULL)
2032-
file->n_blocks = file->size/BLCKSZ;
2033-
2034-
/* backup block by block if datafile AND not compressed by cfs*/
2035-
if (!backup_data_file(arguments, to_path, file,
2036-
arguments->prev_start_lsn,
2037-
current.backup_mode,
2038-
instance_config.compress_alg,
2039-
instance_config.compress_level,
2040-
arguments->nodeInfo->checksum_version,
2041-
arguments->nodeInfo->ptrack_version_num,
2042-
arguments->nodeInfo->ptrack_schema,
2043-
true))
2044-
{
2045-
/* disappeared file not to be confused with 'not changed' */
2046-
if (file->write_size != FILE_NOT_FOUND)
2047-
file->write_size = BYTES_INVALID;
2048-
elog(VERBOSE, "File \"%s\" was not copied to backup", file->path);
2049-
continue;
2050-
}
2051-
}
2052-
else if (!file->external_dir_num &&
2053-
strcmp(file->name, "pg_control") == 0)
2054-
copy_pgcontrol_file(arguments->from_root, FIO_DB_HOST,
2055-
arguments->to_root, FIO_BACKUP_HOST,
2056-
file);
2057-
else
2058-
{
2059-
const char *dst;
2060-
bool skip = false;
2061-
char external_dst[MAXPGPATH];
2053+
/* Encountered some strange beast */
2054+
if (!S_ISREG(file->mode))
2055+
elog(WARNING, "Unexpected type %d of file \"%s\", skipping",
2056+
file->mode, from_fullpath);
20622057

2063-
/* If non-data file has not changed since last backup... */
2064-
if (prev_file && file->exists_in_prev &&
2065-
buf.st_mtime < current.parent_backup)
2066-
{
2067-
file->crc = pgFileGetCRC(file->path, true, false,
2068-
&file->read_size, FIO_DB_HOST);
2069-
file->write_size = file->read_size;
2070-
/* ...and checksum is the same... */
2071-
if (EQ_TRADITIONAL_CRC32(file->crc, (*prev_file)->crc))
2072-
skip = true; /* ...skip copying file. */
2073-
}
2074-
/* Set file paths */
2075-
if (file->external_dir_num)
2076-
{
2077-
makeExternalDirPathByNum(external_dst,
2078-
arguments->external_prefix,
2079-
file->external_dir_num);
2080-
dst = external_dst;
2081-
}
2082-
else
2083-
dst = arguments->to_root;
2084-
if (skip ||
2085-
!copy_file(FIO_DB_HOST, dst, FIO_BACKUP_HOST, file, true))
2086-
{
2087-
/* disappeared file not to be confused with 'not changed' */
2088-
if (file->write_size != FILE_NOT_FOUND)
2089-
file->write_size = BYTES_INVALID;
2090-
elog(VERBOSE, "File \"%s\" was not copied to backup",
2091-
file->path);
2092-
continue;
2093-
}
2058+
/* Check that file exist in previous backup */
2059+
if (current.backup_mode != BACKUP_MODE_FULL)
2060+
{
2061+
pgFile **prev_file_tmp = NULL;
2062+
prev_file_tmp = (pgFile **) parray_bsearch(arguments->prev_filelist,
2063+
file, pgFileCompareRelPathWithExternal);
2064+
if (prev_file_tmp)
2065+
{
2066+
/* File exists in previous backup */
2067+
file->exists_in_prev = true;
2068+
prev_file = *prev_file_tmp;
20942069
}
2070+
}
20952071

2096-
elog(VERBOSE, "File \"%s\". Copied "INT64_FORMAT " bytes",
2097-
file->path, file->write_size);
2072+
/* backup file */
2073+
if (file->is_datafile && !file->is_cfs)
2074+
{
2075+
backup_data_file(&(arguments->conn_arg), file, from_fullpath, to_fullpath,
2076+
arguments->prev_start_lsn,
2077+
current.backup_mode,
2078+
instance_config.compress_alg,
2079+
instance_config.compress_level,
2080+
arguments->nodeInfo->checksum_version,
2081+
arguments->nodeInfo->ptrack_version_num,
2082+
arguments->nodeInfo->ptrack_schema,
2083+
true);
20982084
}
20992085
else
2100-
elog(WARNING, "unexpected file type %d", buf.st_mode);
2086+
{
2087+
backup_non_data_file(file, prev_file, from_fullpath, to_fullpath,
2088+
current.backup_mode, current.parent_backup, true);
2089+
}
2090+
2091+
if (file->write_size == FILE_NOT_FOUND)
2092+
continue;
2093+
2094+
if (file->write_size == BYTES_INVALID)
2095+
{
2096+
elog(VERBOSE, "Skipping the unchanged file: \"%s\"", from_fullpath);
2097+
continue;
2098+
}
2099+
2100+
elog(VERBOSE, "File \"%s\". Copied "INT64_FORMAT " bytes",
2101+
from_fullpath, file->write_size);
21012102
}
21022103

21032104
/* ssh connection to longer needed */

0 commit comments

Comments
 (0)