Skip to content

Commit 9cdded9

Browse files
committed
PGPRO-1457: fix DELTA backup not copiying files created by CREATE DATABASE
1 parent 70d7e46 commit 9cdded9

File tree

6 files changed

+912
-60
lines changed

6 files changed

+912
-60
lines changed

src/backup.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,8 @@ do_backup_instance(void)
496496

497497
pgBackupGetPath(prev_backup, prev_backup_filelist_path, lengthof(prev_backup_filelist_path),
498498
DATABASE_FILE_LIST);
499-
prev_backup_filelist = dir_read_file_list(pgdata, prev_backup_filelist_path);
499+
/* Files of previous backup needed by DELTA backup */
500+
prev_backup_filelist = dir_read_file_list(NULL, prev_backup_filelist_path);
500501

501502
/* If lsn is not NULL, only pages with higher lsn will be copied. */
502503
prev_backup_start_lsn = prev_backup->start_lsn;
@@ -1946,6 +1947,25 @@ backup_files(void *arg)
19461947

19471948
if (S_ISREG(buf.st_mode))
19481949
{
1950+
/* Check that file exist in previous backup */
1951+
if (current.backup_mode == BACKUP_MODE_DIFF_DELTA)
1952+
{
1953+
int p;
1954+
char *relative;
1955+
int n_prev_backup_files_list = parray_num(arguments->prev_backup_filelist);
1956+
relative = GetRelativePath(file->path, arguments->from_root);
1957+
for (p = 0; p < n_prev_backup_files_list; p++)
1958+
{
1959+
pgFile *prev_file = (pgFile *) parray_get(arguments->prev_backup_filelist, p);
1960+
if (strcmp(relative, prev_file->path) == 0)
1961+
{
1962+
/* File exists in previous backup */
1963+
file->exists_in_prev = true;
1964+
elog(INFO, "File exists at the time of previous backup %s", relative);
1965+
break;
1966+
}
1967+
}
1968+
}
19491969
/* copy the file into backup */
19501970
if (file->is_datafile && !file->is_cfs)
19511971
{

src/data.c

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -317,17 +317,22 @@ backup_data_page(backup_files_args *arguments,
317317
((PageHeader) page)->pd_checksum = pg_checksum_page(page, absolute_blknum);
318318
}
319319
/* get lsn from page */
320-
if (!parse_page(page, &page_lsn))
320+
if (backup_mode == BACKUP_MODE_DIFF_DELTA &&
321+
file->exists_in_prev &&
322+
header.compressed_size != PageIsTruncated &&
323+
!parse_page(page, &page_lsn))
321324
elog(ERROR, "Cannot parse page after pg_ptrack_get_block. "
322325
"Possible risk of a memory corruption");
323326

324327
}
325328

326329
if (backup_mode == BACKUP_MODE_DIFF_DELTA &&
330+
file->exists_in_prev &&
327331
header.compressed_size != PageIsTruncated &&
328-
page_lsn < prev_backup_start_lsn)
332+
page_lsn < prev_backup_start_lsn)
329333
{
330334
elog(VERBOSE, "Skipping blknum: %u in file: %s", blknum, file->path);
335+
(*n_skipped)++;
331336
free(page);
332337
return;
333338
}
@@ -557,18 +562,22 @@ restore_data_file(const char *from_root,
557562
pgBackup *backup)
558563
{
559564
char to_path[MAXPGPATH];
560-
FILE *in;
561-
FILE *out;
565+
FILE *in = NULL;
566+
FILE *out = NULL;
562567
BackupPageHeader header;
563568
BlockNumber blknum;
564569
size_t file_size;
565570

566-
/* open backup mode file for read */
567-
in = fopen(file->path, "r");
568-
if (in == NULL)
571+
/* BYTES_INVALID allowed only in case of restoring file from DELTA backup */
572+
if (file->write_size != BYTES_INVALID)
569573
{
570-
elog(ERROR, "cannot open backup file \"%s\": %s", file->path,
571-
strerror(errno));
574+
/* open backup mode file for read */
575+
in = fopen(file->path, "r");
576+
if (in == NULL)
577+
{
578+
elog(ERROR, "cannot open backup file \"%s\": %s", file->path,
579+
strerror(errno));
580+
}
572581
}
573582

574583
/*
@@ -594,6 +603,10 @@ restore_data_file(const char *from_root,
594603
DataPage compressed_page; /* used as read buffer */
595604
DataPage page;
596605

606+
/* File didn`t changed. Nothig to copy */
607+
if (file->write_size == BYTES_INVALID)
608+
break;
609+
597610
/* read BackupPageHeader */
598611
read_len = fread(&header, 1, sizeof(header), in);
599612
if (read_len != sizeof(header))
@@ -670,9 +683,10 @@ restore_data_file(const char *from_root,
670683
}
671684

672685
/*
673-
* DELTA backup has no knowledge about truncated blocks as PAGE or PTRACK do
674-
* but knows file size at the time of backup.
675-
* So when restoring file from delta backup we, knowning it`s size at
686+
* DELTA backup have no knowledge about truncated blocks as PAGE or PTRACK do
687+
* But during DELTA backup we read every file in PGDATA and thus DELTA backup
688+
* knows exact size of every file at the time of backup.
689+
* So when restoring file from DELTA backup we, knowning it`s size at
676690
* a time of a backup, can truncate file to this size.
677691
*/
678692

@@ -681,7 +695,6 @@ restore_data_file(const char *from_root,
681695
/* get file current size */
682696
fseek(out, 0, SEEK_END);
683697
file_size = ftell(out);
684-
685698
if (file_size > file->n_blocks * BLCKSZ)
686699
{
687700
/*
@@ -699,7 +712,8 @@ restore_data_file(const char *from_root,
699712
{
700713
int errno_tmp = errno;
701714

702-
fclose(in);
715+
if (in)
716+
fclose(in);
703717
fclose(out);
704718
elog(ERROR, "cannot change mode of \"%s\": %s", to_path,
705719
strerror(errno_tmp));
@@ -709,7 +723,8 @@ restore_data_file(const char *from_root,
709723
fsync(fileno(out)) != 0 ||
710724
fclose(out))
711725
elog(ERROR, "cannot write \"%s\": %s", to_path, strerror(errno));
712-
fclose(in);
726+
if (in)
727+
fclose(in);
713728
}
714729

715730
/*

src/dir.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ pgFileInit(const char *path)
166166
file->path = pgut_malloc(strlen(path) + 1);
167167
strcpy(file->path, path); /* enough buffer size guaranteed */
168168
file->is_cfs = false;
169-
file->n_blocks = -1; /* can change only in DELTA backups */
169+
file->exists_in_prev = false; /* can change only in Incremental backup. */
170+
file->n_blocks = -1; /* can change only in DELTA backup. Number of blocks readed during backup */
170171
file->compress_alg = NOT_DEFINED_COMPRESS;
171172
return file;
172173
}

src/pg_probackup.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ typedef struct pgFile
8383
char *name; /* file or directory name */
8484
mode_t mode; /* protection (file type and permission) */
8585
size_t size; /* size of the file */
86-
int n_blocks; /* size of the file in blocks, readed during DELTA backup */
8786
size_t read_size; /* size of the portion read (if only some pages are
8887
backed up, it's different from size) */
8988
size_t write_size; /* size of the backed-up file. BYTES_INVALID means
@@ -98,8 +97,10 @@ typedef struct pgFile
9897
Oid relOid; /* relOid extracted from path, if applicable */
9998
char *forkName; /* forkName extracted from path, if applicable */
10099
int segno; /* Segment number for ptrack */
100+
int n_blocks; /* size of the file in blocks, readed during DELTA backup */
101101
bool is_cfs; /* Flag to distinguish files compressed by CFS*/
102102
bool is_database;
103+
bool exists_in_prev; /* Mark files, both data and regular, that exists in previous backup */
103104
CompressAlg compress_alg; /* compression algorithm applied to the file */
104105
volatile uint32 lock; /* lock for synchronization of parallel threads */
105106
datapagemap_t pagemap; /* bitmap of pages updated since previous backup */

src/restore.c

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -378,16 +378,25 @@ restore_backup(pgBackup *backup)
378378
pgBackupGetPath(backup, database_path, lengthof(database_path), DATABASE_DIR);
379379
pgBackupGetPath(backup, list_path, lengthof(list_path), DATABASE_FILE_LIST);
380380
files = dir_read_file_list(database_path, list_path);
381-
for (i = parray_num(files) - 1; i >= 0; i--)
382-
{
383-
pgFile *file = (pgFile *) parray_get(files, i);
384381

385-
/*
386-
* Remove files which haven't changed since previous backup
387-
* and was not backed up
388-
*/
389-
if (file->write_size == BYTES_INVALID)
390-
pgFileFree(parray_remove(files, i));
382+
/*
383+
* For PAGE and PTRACK backups remove files which haven't changed
384+
* since previous backup and thus were not backed up.
385+
* We can`t do the same when restoring DELTA backup because we need information
386+
* about every file to correctly truncate them.
387+
*/
388+
if (backup->backup_mode == BACKUP_MODE_DIFF_PAGE ||
389+
backup->backup_mode == BACKUP_MODE_DIFF_PTRACK)
390+
{
391+
for (i = parray_num(files) - 1; i >= 0; i--)
392+
{
393+
pgFile *file = (pgFile *) parray_get(files, i);
394+
if (file->write_size == BYTES_INVALID)
395+
{
396+
elog(VERBOSE, "The file didn`t changed. Skip restore: %s", file->path);
397+
pgFileFree(parray_remove(files, i));
398+
}
399+
}
391400
}
392401

393402
/* setup threads */
@@ -719,21 +728,14 @@ restore_files(void *arg)
719728
/* Directories was created before */
720729
if (S_ISDIR(file->mode))
721730
{
722-
elog(LOG, "directory, skip");
723-
continue;
724-
}
725-
726-
/* not backed up */
727-
if (file->write_size == BYTES_INVALID)
728-
{
729-
elog(LOG, "not backed up, skip");
731+
elog(VERBOSE, "directory, skip");
730732
continue;
731733
}
732734

733735
/* Do not restore tablespace_map file */
734736
if (path_is_prefix_of_path(PG_TABLESPACE_MAP_FILE, rel_path))
735737
{
736-
elog(LOG, "skip tablespace_map");
738+
elog(VERBOSE, "skip tablespace_map");
737739
continue;
738740
}
739741

@@ -750,8 +752,9 @@ restore_files(void *arg)
750752
copy_file(from_root, pgdata, file);
751753

752754
/* print size of restored file */
753-
elog(LOG, "Restored file %s : %lu bytes",
754-
file->path, (unsigned long) file->write_size);
755+
if (file->write_size != BYTES_INVALID)
756+
elog(LOG, "Restored file %s : %lu bytes",
757+
file->path, (unsigned long) file->write_size);
755758
}
756759
}
757760

0 commit comments

Comments
 (0)