Skip to content

Commit 3b91712

Browse files
committed
Merge remote-tracking branch 'origin/master' into pgpro-1918
2 parents 3474784 + 0aa1403 commit 3b91712

18 files changed

+926
-48
lines changed

src/backup.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,9 @@ do_backup_instance(void)
574574
strlen(" with pg_probackup"));
575575
pg_start_backup(label, smooth_checkpoint, &current);
576576

577+
/* Update running backup meta with START LSN */
578+
write_backup(&current);
579+
577580
pgBackupGetPath(&current, database_path, lengthof(database_path),
578581
DATABASE_DIR);
579582

@@ -760,6 +763,19 @@ do_backup_instance(void)
760763
else
761764
elog(ERROR, "Data files transferring failed");
762765

766+
/* Remove disappeared during backup files from backup_list */
767+
for (i = 0; i < parray_num(backup_files_list); i++)
768+
{
769+
pgFile *tmp_file = (pgFile *) parray_get(backup_files_list, i);
770+
771+
if (tmp_file->write_size == FILE_NOT_FOUND)
772+
{
773+
pg_atomic_clear_flag(&tmp_file->lock);
774+
pgFileFree(tmp_file);
775+
parray_remove(backup_files_list, i);
776+
}
777+
}
778+
763779
/* clean previous backup file list */
764780
if (prev_backup_filelist)
765781
{
@@ -2235,7 +2251,7 @@ backup_files(void *arg)
22352251
* If file is not found, this is not en error.
22362252
* It could have been deleted by concurrent postgres transaction.
22372253
*/
2238-
file->write_size = BYTES_INVALID;
2254+
file->write_size = FILE_NOT_FOUND;
22392255
elog(LOG, "File \"%s\" is not found", file->path);
22402256
continue;
22412257
}
@@ -2285,7 +2301,9 @@ backup_files(void *arg)
22852301
instance_config.compress_alg,
22862302
instance_config.compress_level))
22872303
{
2288-
file->write_size = BYTES_INVALID;
2304+
/* disappeared file not to be confused with 'not changed' */
2305+
if (file->write_size != FILE_NOT_FOUND)
2306+
file->write_size = BYTES_INVALID;
22892307
elog(VERBOSE, "File \"%s\" was not copied to backup", file->path);
22902308
continue;
22912309
}
@@ -2309,7 +2327,9 @@ backup_files(void *arg)
23092327
if (skip ||
23102328
!copy_file(arguments->from_root, arguments->to_root, file))
23112329
{
2312-
file->write_size = BYTES_INVALID;
2330+
/* disappeared file not to be confused with 'not changed' */
2331+
if (file->write_size != FILE_NOT_FOUND)
2332+
file->write_size = BYTES_INVALID;
23132333
elog(VERBOSE, "File \"%s\" was not copied to backup",
23142334
file->path);
23152335
continue;

src/catalog.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,9 @@ is_parent(time_t parent_backup_time, pgBackup *child_backup, bool inclusive)
10211021
if (!child_backup)
10221022
elog(ERROR, "Target backup cannot be NULL");
10231023

1024+
if (inclusive && child_backup->start_time == parent_backup_time)
1025+
return true;
1026+
10241027
while (child_backup->parent_backup_link &&
10251028
child_backup->parent_backup != parent_backup_time)
10261029
{
@@ -1030,8 +1033,8 @@ is_parent(time_t parent_backup_time, pgBackup *child_backup, bool inclusive)
10301033
if (child_backup->parent_backup == parent_backup_time)
10311034
return true;
10321035

1033-
if (inclusive && child_backup->start_time == parent_backup_time)
1034-
return true;
1036+
//if (inclusive && child_backup->start_time == parent_backup_time)
1037+
// return true;
10351038

10361039
return false;
10371040
}

src/data.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,7 @@ backup_data_file(backup_files_arg* arguments,
564564
if (errno == ENOENT)
565565
{
566566
elog(LOG, "File \"%s\" is not found", file->path);
567+
file->write_size = FILE_NOT_FOUND;
567568
return false;
568569
}
569570

@@ -946,7 +947,11 @@ copy_file(const char *from_root, const char *to_root, pgFile *file)
946947

947948
/* maybe deleted, it's not error */
948949
if (errno == ENOENT)
950+
{
951+
elog(LOG, "File \"%s\" is not found", file->path);
952+
file->write_size = FILE_NOT_FOUND;
949953
return false;
954+
}
950955

951956
elog(ERROR, "cannot open source file \"%s\": %s", file->path,
952957
strerror(errno));

src/dir.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,14 @@ dir_check_file(const char *root, pgFile *file)
630630
}
631631
else
632632
{
633+
/*
634+
* snapfs files:
635+
* RELFILENODE.BLOCKNO.snapmap.SNAPID
636+
* RELFILENODE.BLOCKNO.snap.SNAPID
637+
*/
638+
if (strstr(file->name, "snap") != NULL)
639+
return true;
640+
633641
len = strlen(file->name);
634642
/* reloid.cfm */
635643
if (len > 3 && strcmp(file->name + len - 3, "cfm") == 0)
@@ -1047,11 +1055,11 @@ create_data_directories(const char *data_dir, const char *backup_dir,
10471055
}
10481056

10491057
if (link_sep)
1050-
elog(LOG, "create directory \"%s\" and symbolic link \"%.*s\"",
1058+
elog(VERBOSE, "create directory \"%s\" and symbolic link \"%.*s\"",
10511059
linked_path,
10521060
(int) (link_sep - relative_ptr), relative_ptr);
10531061
else
1054-
elog(LOG, "create directory \"%s\" and symbolic link \"%s\"",
1062+
elog(VERBOSE, "create directory \"%s\" and symbolic link \"%s\"",
10551063
linked_path, relative_ptr);
10561064

10571065
/* Firstly, create linked directory */
@@ -1082,7 +1090,7 @@ create_data_directories(const char *data_dir, const char *backup_dir,
10821090
}
10831091

10841092
create_directory:
1085-
elog(LOG, "create directory \"%s\"", relative_ptr);
1093+
elog(VERBOSE, "create directory \"%s\"", relative_ptr);
10861094

10871095
/* This is not symlink, create directory */
10881096
join_path_components(to_path, data_dir, relative_ptr);

src/parsexlog.c

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ typedef struct XLogPageReadPrivate
9393
TimeLineID tli;
9494
uint32 xlog_seg_size;
9595

96+
char page_buf[XLOG_BLCKSZ];
97+
uint32 prev_page_off;
98+
9699
bool manual_switch;
97100
bool need_switch;
98101

@@ -1037,6 +1040,17 @@ SimpleXLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
10371040
*/
10381041
Assert(private_data->xlogexists);
10391042

1043+
/*
1044+
* Do not read same page read earlier from the file, read it from the buffer
1045+
*/
1046+
if (private_data->prev_page_off != 0 &&
1047+
private_data->prev_page_off == targetPageOff)
1048+
{
1049+
memcpy(readBuf, private_data->page_buf, XLOG_BLCKSZ);
1050+
*pageTLI = private_data->tli;
1051+
return XLOG_BLCKSZ;
1052+
}
1053+
10401054
/* Read the requested page */
10411055
if (private_data->xlogfile != -1)
10421056
{
@@ -1060,23 +1074,25 @@ SimpleXLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
10601074
if (gzseek(private_data->gz_xlogfile, (z_off_t) targetPageOff, SEEK_SET) == -1)
10611075
{
10621076
elog(WARNING, "Thread [%d]: Could not seek in compressed WAL segment \"%s\": %s",
1063-
private_data->thread_num,
1064-
private_data->gz_xlogpath,
1065-
get_gz_error(private_data->gz_xlogfile));
1077+
private_data->thread_num,
1078+
private_data->gz_xlogpath,
1079+
get_gz_error(private_data->gz_xlogfile));
10661080
return -1;
10671081
}
10681082

10691083
if (gzread(private_data->gz_xlogfile, readBuf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
10701084
{
10711085
elog(WARNING, "Thread [%d]: Could not read from compressed WAL segment \"%s\": %s",
1072-
private_data->thread_num,
1073-
private_data->gz_xlogpath,
1074-
get_gz_error(private_data->gz_xlogfile));
1086+
private_data->thread_num,
1087+
private_data->gz_xlogpath,
1088+
get_gz_error(private_data->gz_xlogfile));
10751089
return -1;
10761090
}
10771091
}
10781092
#endif
10791093

1094+
memcpy(private_data->page_buf, readBuf, XLOG_BLCKSZ);
1095+
private_data->prev_page_off = targetPageOff;
10801096
*pageTLI = private_data->tli;
10811097
return XLOG_BLCKSZ;
10821098
}
@@ -1133,6 +1149,7 @@ CleanupXLogPageRead(XLogReaderState *xlogreader)
11331149
private_data->gz_xlogfile = NULL;
11341150
}
11351151
#endif
1152+
private_data->prev_page_off = 0;
11361153
private_data->xlogexists = false;
11371154
}
11381155

src/pg_probackup.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ typedef enum ShowFormat
165165

166166
/* special values of pgBackup fields */
167167
#define INVALID_BACKUP_ID 0 /* backup ID is not provided by user */
168-
#define BYTES_INVALID (-1)
168+
#define BYTES_INVALID (-1) /* file didn`t changed since previous backup, DELTA backup do not rely on it */
169+
#define FILE_NOT_FOUND (-2) /* file disappeared during backup */
169170
#define BLOCKNUM_INVALID (-1)
170171

171172
/*

src/restore.c

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
5757
int base_full_backup_index = 0;
5858
int corrupted_backup_index = 0;
5959
char *action = is_restore ? "Restore":"Validate";
60+
parray *parent_chain = NULL;
6061

6162
if (is_restore)
6263
{
@@ -283,34 +284,54 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
283284
if (is_restore)
284285
check_tablespace_mapping(dest_backup);
285286

287+
/* At this point we are sure that parent chain is whole
288+
* so we can build separate array, containing all needed backups,
289+
* to simplify validation and restore
290+
*/
291+
parent_chain = parray_new();
292+
293+
/* Take every backup that is a child of base_backup AND parent of dest_backup
294+
* including base_backup and dest_backup
295+
*/
296+
for (i = base_full_backup_index; i >= dest_backup_index; i--)
297+
{
298+
tmp_backup = (pgBackup *) parray_get(backups, i);
299+
300+
if (is_parent(base_full_backup->start_time, tmp_backup, true) &&
301+
is_parent(tmp_backup->start_time, dest_backup, true))
302+
{
303+
parray_append(parent_chain, tmp_backup);
304+
}
305+
}
306+
307+
/* for validation or restore with enabled validation */
286308
if (!is_restore || !rt->restore_no_validate)
287309
{
288310
if (dest_backup->backup_mode != BACKUP_MODE_FULL)
289311
elog(INFO, "Validating parents for backup %s", base36enc(dest_backup->start_time));
290312

291313
/*
292314
* Validate backups from base_full_backup to dest_backup.
293-
* At this point we are sure that parent chain is intact.
294315
*/
295-
for (i = base_full_backup_index; i >= dest_backup_index; i--)
316+
for (i = 0; i < parray_num(parent_chain); i++)
296317
{
297-
tmp_backup = (pgBackup *) parray_get(backups, i);
318+
tmp_backup = (pgBackup *) parray_get(parent_chain, i);
298319

299-
if (is_parent(base_full_backup->start_time, tmp_backup, true))
320+
lock_backup(tmp_backup);
321+
pgBackupValidate(tmp_backup);
322+
/* Maybe we should be more paranoid and check for !BACKUP_STATUS_OK? */
323+
if (tmp_backup->status == BACKUP_STATUS_CORRUPT)
300324
{
301-
lock_backup(tmp_backup);
302-
pgBackupValidate(tmp_backup);
303-
/* Maybe we should be more paranoid and check for !BACKUP_STATUS_OK? */
304-
if (tmp_backup->status == BACKUP_STATUS_CORRUPT)
305-
{
306-
corrupted_backup = tmp_backup;
307-
corrupted_backup_index = i;
308-
break;
309-
}
310-
/* We do not validate WAL files of intermediate backups
311-
* It`s done to speed up restore
325+
corrupted_backup = tmp_backup;
326+
/* we need corrupted backup index from 'backups' not parent_chain
327+
* so we can properly orphanize all its descendants
312328
*/
329+
corrupted_backup_index = get_backup_index_number(backups, corrupted_backup);
330+
break;
313331
}
332+
/* We do not validate WAL files of intermediate backups
333+
* It`s done to speed up restore
334+
*/
314335
}
315336

316337
/* There is no point in wal validation of corrupted backups */
@@ -353,7 +374,6 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
353374
}
354375
}
355376

356-
// TODO: rewrite restore to use parent_chain
357377
/*
358378
* If dest backup is corrupted or was orphaned in previous check
359379
* produce corresponding error message
@@ -374,13 +394,12 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
374394
base36enc(dest_backup->start_time), status2str(dest_backup->status));
375395

376396
/* We ensured that all backups are valid, now restore if required
377-
* TODO: use parent_link
378397
*/
379398
if (is_restore)
380399
{
381-
for (i = base_full_backup_index; i >= dest_backup_index; i--)
400+
for (i = 0; i < parray_num(parent_chain); i++)
382401
{
383-
pgBackup *backup = (pgBackup *) parray_get(backups, i);
402+
pgBackup *backup = (pgBackup *) parray_get(parent_chain, i);
384403

385404
if (rt->lsn_specified && parse_server_version(backup->server_version) < 100000)
386405
elog(ERROR, "Backup %s was created for version %s which doesn't support recovery_target_lsn",
@@ -410,6 +429,7 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
410429
/* cleanup */
411430
parray_walk(backups, pgBackupFree);
412431
parray_free(backups);
432+
parray_free(parent_chain);
413433

414434
elog(INFO, "%s of backup %s completed.",
415435
action, base36enc(dest_backup->start_time));
@@ -485,6 +505,7 @@ restore_backup(pgBackup *backup)
485505
/* By default there are some error */
486506
threads_args[i].ret = 1;
487507

508+
/* Useless message TODO: rewrite */
488509
elog(LOG, "Start thread for num:%zu", parray_num(files));
489510

490511
pthread_create(&threads[i], NULL, restore_files, arg);

src/show.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ show_instance_plain(parray *backup_list, bool show_name)
325325
uint32 widths[SHOW_FIELDS_COUNT];
326326
uint32 widths_sum = 0;
327327
ShowBackendRow *rows;
328+
time_t current_time = time(NULL);
328329

329330
for (i = 0; i < SHOW_FIELDS_COUNT; i++)
330331
widths[i] = strlen(names[i]);
@@ -384,7 +385,11 @@ show_instance_plain(parray *backup_list, bool show_name)
384385
cur++;
385386

386387
/* Time */
387-
if (backup->end_time != (time_t) 0)
388+
if (backup->status == BACKUP_STATUS_RUNNING)
389+
snprintf(row->duration, lengthof(row->duration), "%.*lfs", 0,
390+
difftime(current_time, backup->start_time));
391+
392+
else if (backup->end_time != (time_t) 0)
388393
snprintf(row->duration, lengthof(row->duration), "%.*lfs", 0,
389394
difftime(backup->end_time, backup->start_time));
390395
else

tests/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
ptrack_vacuum_full, ptrack_vacuum_truncate, pgpro560, pgpro589, \
99
false_positive, replica, compression, page, ptrack, archive, \
1010
exclude, cfs_backup, cfs_restore, cfs_validate_backup, auth_test, \
11-
time_stamp, snapfs, logging, locking
11+
time_stamp, snapfs, logging, locking, remote
1212

1313

1414
def load_tests(loader, tests, pattern):
@@ -44,6 +44,7 @@ def load_tests(loader, tests, pattern):
4444
suite.addTests(loader.loadTestsFromModule(ptrack_vacuum_bits_visibility))
4545
suite.addTests(loader.loadTestsFromModule(ptrack_vacuum_full))
4646
suite.addTests(loader.loadTestsFromModule(ptrack_vacuum_truncate))
47+
suite.addTests(loader.loadTestsFromModule(remote))
4748
suite.addTests(loader.loadTestsFromModule(replica))
4849
suite.addTests(loader.loadTestsFromModule(restore_test))
4950
suite.addTests(loader.loadTestsFromModule(retention_test))

0 commit comments

Comments
 (0)