Skip to content

Commit 88354a8

Browse files
za-arthurArthur Zakirov
authored and
Arthur Zakirov
committed
PGPRO-1892: Continue failed merge command
1 parent 4995652 commit 88354a8

File tree

7 files changed

+75
-88
lines changed

7 files changed

+75
-88
lines changed

Diff for: src/backup.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,7 @@ do_backup_instance(void)
790790
}
791791

792792
/* Print the list of files to backup catalog */
793-
pgBackupWriteFileList(&current, backup_files_list, pgdata);
793+
write_backup_filelist(&current, backup_files_list, pgdata);
794794

795795
/* Compute summary of size of regular files in the backup */
796796
for (i = 0; i < parray_num(backup_files_list); i++)

Diff for: src/catalog.c

+9-5
Original file line numberDiff line numberDiff line change
@@ -509,18 +509,22 @@ write_backup(pgBackup *backup)
509509
fp = fopen(conf_path, "wt");
510510
if (fp == NULL)
511511
elog(ERROR, "Cannot open configuration file \"%s\": %s", conf_path,
512-
strerror(errno));
512+
strerror(errno));
513513

514514
pgBackupWriteControl(fp, backup);
515515

516-
fclose(fp);
516+
if (fflush(fp) != 0 ||
517+
fsync(fileno(fp)) != 0 ||
518+
fclose(fp))
519+
elog(ERROR, "Cannot write configuration file \"%s\": %s",
520+
conf_path, strerror(errno));
517521
}
518522

519523
/*
520524
* Output the list of files to backup catalog DATABASE_FILE_LIST
521525
*/
522526
void
523-
pgBackupWriteFileList(pgBackup *backup, parray *files, const char *root)
527+
write_backup_filelist(pgBackup *backup, parray *files, const char *root)
524528
{
525529
FILE *fp;
526530
char path[MAXPGPATH];
@@ -529,15 +533,15 @@ pgBackupWriteFileList(pgBackup *backup, parray *files, const char *root)
529533

530534
fp = fopen(path, "wt");
531535
if (fp == NULL)
532-
elog(ERROR, "cannot open file list \"%s\": %s", path,
536+
elog(ERROR, "Cannot open file list \"%s\": %s", path,
533537
strerror(errno));
534538

535539
print_file_list(fp, files, root);
536540

537541
if (fflush(fp) != 0 ||
538542
fsync(fileno(fp)) != 0 ||
539543
fclose(fp))
540-
elog(ERROR, "cannot write file list \"%s\": %s", path, strerror(errno));
544+
elog(ERROR, "Cannot write file list \"%s\": %s", path, strerror(errno));
541545
}
542546

543547
/*

Diff for: src/data.c

-16
Original file line numberDiff line numberDiff line change
@@ -1037,22 +1037,6 @@ copy_file(const char *from_root, const char *to_root, pgFile *file)
10371037
return true;
10381038
}
10391039

1040-
/*
1041-
* Move file from one backup to another.
1042-
* We do not apply compression to these files, because
1043-
* it is either small control file or already compressed cfs file.
1044-
*/
1045-
void
1046-
move_file(const char *from_root, const char *to_root, pgFile *file)
1047-
{
1048-
char to_path[MAXPGPATH];
1049-
1050-
join_path_components(to_path, to_root, file->path + strlen(from_root) + 1);
1051-
if (rename(file->path, to_path) == -1)
1052-
elog(ERROR, "Cannot move file \"%s\" to path \"%s\": %s",
1053-
file->path, to_path, strerror(errno));
1054-
}
1055-
10561040
#ifdef HAVE_LIBZ
10571041
/*
10581042
* Show error during work with compressed file

Diff for: src/delete.c

+15-12
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include <time.h>
1515
#include <unistd.h>
1616

17-
static int delete_backup_files(pgBackup *backup);
1817
static void delete_walfiles(XLogRecPtr oldest_lsn, TimeLineID oldest_tli,
1918
uint32 xlog_seg_size);
2019

@@ -245,7 +244,7 @@ do_retention_purge(void)
245244
* Delete backup files of the backup and update the status of the backup to
246245
* BACKUP_STATUS_DELETED.
247246
*/
248-
static int
247+
void
249248
delete_backup_files(pgBackup *backup)
250249
{
251250
size_t i;
@@ -257,11 +256,15 @@ delete_backup_files(pgBackup *backup)
257256
* If the backup was deleted already, there is nothing to do.
258257
*/
259258
if (backup->status == BACKUP_STATUS_DELETED)
260-
return 0;
259+
{
260+
elog(WARNING, "Backup %s already deleted",
261+
base36enc(backup->start_time));
262+
return;
263+
}
261264

262265
time2iso(timestamp, lengthof(timestamp), backup->recovery_time);
263266

264-
elog(INFO, "delete: %s %s",
267+
elog(INFO, "Delete: %s %s",
265268
base36enc(backup->start_time), timestamp);
266269

267270
/*
@@ -283,25 +286,25 @@ delete_backup_files(pgBackup *backup)
283286
pgFile *file = (pgFile *) parray_get(files, i);
284287

285288
/* print progress */
286-
elog(VERBOSE, "delete file(%zd/%lu) \"%s\"", i + 1,
289+
elog(VERBOSE, "Delete file(%zd/%lu) \"%s\"", i + 1,
287290
(unsigned long) parray_num(files), file->path);
288291

289292
if (remove(file->path))
290293
{
291-
elog(WARNING, "can't remove \"%s\": %s", file->path,
292-
strerror(errno));
293-
parray_walk(files, pgFileFree);
294-
parray_free(files);
295-
296-
return 1;
294+
if (errno == ENOENT)
295+
elog(VERBOSE, "File \"%s\" is absent", file->path);
296+
else
297+
elog(ERROR, "Cannot remove \"%s\": %s", file->path,
298+
strerror(errno));
299+
return;
297300
}
298301
}
299302

300303
parray_walk(files, pgFileFree);
301304
parray_free(files);
302305
backup->status = BACKUP_STATUS_DELETED;
303306

304-
return 0;
307+
return;
305308
}
306309

307310
/*

Diff for: src/merge.c

+38-50
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ do_merge(time_t backup_id)
7777
{
7878
if (backup->status != BACKUP_STATUS_OK &&
7979
/* It is possible that previous merging was interrupted */
80-
backup->status != BACKUP_STATUS_MERGING)
80+
backup->status != BACKUP_STATUS_MERGING &&
81+
backup->status != BACKUP_STATUS_DELETING)
8182
elog(ERROR, "Backup %s has status: %s",
8283
base36enc(backup->start_time), status2str(backup->status));
8384

@@ -164,7 +165,14 @@ merge_backups(pgBackup *to_backup, pgBackup *from_backup)
164165
int i;
165166
bool merge_isok = true;
166167

167-
elog(LOG, "Merging backup %s with backup %s", from_backup_id, to_backup_id);
168+
elog(INFO, "Merging backup %s with backup %s", from_backup_id, to_backup_id);
169+
170+
/*
171+
* Previous merging was interrupted during deleting source backup. It is
172+
* safe just to delete it again.
173+
*/
174+
if (from_backup->status == BACKUP_STATUS_DELETING)
175+
goto delete_source_backup;
168176

169177
to_backup->status = BACKUP_STATUS_MERGING;
170178
write_backup_status(to_backup);
@@ -244,37 +252,38 @@ merge_backups(pgBackup *to_backup, pgBackup *from_backup)
244252
elog(ERROR, "Data files merging failed");
245253

246254
/*
247-
* Files were copied into to_backup and deleted from from_backup. Remove
248-
* remaining directories from from_backup.
255+
* Update to_backup metadata.
249256
*/
250-
parray_qsort(files, pgFileComparePathDesc);
257+
to_backup->status = BACKUP_STATUS_OK;
258+
/* Compute summary of size of regular files in the backup */
259+
to_backup->data_bytes = 0;
251260
for (i = 0; i < parray_num(files); i++)
252261
{
253262
pgFile *file = (pgFile *) parray_get(files, i);
254263

255-
if (!S_ISDIR(file->mode))
256-
continue;
257-
258-
if (rmdir(file->path))
259-
elog(ERROR, "Could not remove directory \"%s\": %s",
260-
file->path, strerror(errno));
264+
if (S_ISDIR(file->mode))
265+
to_backup->data_bytes += 4096;
266+
/* Count the amount of the data actually copied */
267+
else if (S_ISREG(file->mode))
268+
to_backup->data_bytes += file->write_size;
261269
}
262-
if (rmdir(from_database_path))
263-
elog(ERROR, "Could not remove directory \"%s\": %s",
264-
from_database_path, strerror(errno));
265-
if (unlink(control_file))
266-
elog(ERROR, "Could not remove file \"%s\": %s",
267-
control_file, strerror(errno));
270+
/* compute size of wal files of this backup stored in the archive */
271+
if (!to_backup->stream)
272+
to_backup->wal_bytes = xlog_seg_size *
273+
(to_backup->stop_lsn / xlog_seg_size -
274+
to_backup->start_lsn / xlog_seg_size + 1);
275+
else
276+
to_backup->wal_bytes = BYTES_INVALID;
268277

269-
pgBackupGetPath(from_backup, control_file, lengthof(control_file),
270-
BACKUP_CONTROL_FILE);
271-
if (unlink(control_file))
272-
elog(ERROR, "Could not remove file \"%s\": %s",
273-
control_file, strerror(errno));
278+
write_backup_filelist(to_backup, files, from_database_path);
279+
write_backup(to_backup);
274280

275-
if (rmdir(from_backup_path))
276-
elog(ERROR, "Could not remove directory \"%s\": %s",
277-
from_backup_path, strerror(errno));
281+
delete_source_backup:
282+
/*
283+
* Files were copied into to_backup. It is time to remove source backup
284+
* entirely.
285+
*/
286+
delete_backup_files(from_backup);
278287

279288
/*
280289
* Delete files which are not in from_backup file list.
@@ -286,7 +295,7 @@ merge_backups(pgBackup *to_backup, pgBackup *from_backup)
286295
if (parray_bsearch(files, file, pgFileComparePathDesc) == NULL)
287296
{
288297
pgFileDelete(file);
289-
elog(LOG, "Deleted \"%s\"", file->path);
298+
elog(VERBOSE, "Deleted \"%s\"", file->path);
290299
}
291300
}
292301

@@ -298,34 +307,14 @@ merge_backups(pgBackup *to_backup, pgBackup *from_backup)
298307
to_backup_path, from_backup_path, strerror(errno));
299308

300309
/*
301-
* Update to_backup metadata.
310+
* Merging finished, now we can safely update ID of the destination backup.
302311
*/
303312
pgBackupCopy(to_backup, from_backup);
313+
elog(INFO, "to_backup: %s", base36enc(to_backup->start_time));
304314
/* Correct metadata */
305315
to_backup->backup_mode = BACKUP_MODE_FULL;
306316
to_backup->status = BACKUP_STATUS_OK;
307317
to_backup->parent_backup = INVALID_BACKUP_ID;
308-
/* Compute summary of size of regular files in the backup */
309-
to_backup->data_bytes = 0;
310-
for (i = 0; i < parray_num(files); i++)
311-
{
312-
pgFile *file = (pgFile *) parray_get(files, i);
313-
314-
if (S_ISDIR(file->mode))
315-
to_backup->data_bytes += 4096;
316-
/* Count the amount of the data actually copied */
317-
else if (S_ISREG(file->mode))
318-
to_backup->data_bytes += file->write_size;
319-
}
320-
/* compute size of wal files of this backup stored in the archive */
321-
if (!to_backup->stream)
322-
to_backup->wal_bytes = xlog_seg_size *
323-
(to_backup->stop_lsn / xlog_seg_size -
324-
to_backup->start_lsn / xlog_seg_size + 1);
325-
else
326-
to_backup->wal_bytes = BYTES_INVALID;
327-
328-
pgBackupWriteFileList(to_backup, files, from_database_path);
329318
write_backup(to_backup);
330319

331320
/* Cleanup */
@@ -508,10 +497,9 @@ merge_files(void *arg)
508497
file->write_size = pgFileSize(to_path_tmp);
509498
file->crc = pgFileGetCRC(to_path_tmp, false);
510499
}
511-
pgFileDelete(file);
512500
}
513501
else
514-
move_file(argument->from_root, argument->to_root, file);
502+
copy_file(argument->from_root, argument->to_root, file);
515503

516504
if (file->write_size != BYTES_INVALID)
517505
elog(LOG, "Moved file \"%s\": " INT64_FORMAT " bytes",

Diff for: src/pg_probackup.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ extern int do_show(time_t requested_backup_id);
448448

449449
/* in delete.c */
450450
extern void do_delete(time_t backup_id);
451+
extern void delete_backup_files(pgBackup *backup);
451452
extern int do_retention_purge(void);
452453
extern int do_delete_instance(void);
453454

@@ -478,10 +479,11 @@ extern pgBackup *catalog_get_last_data_backup(parray *backup_list,
478479
TimeLineID tli);
479480
extern void catalog_lock(void);
480481
extern void pgBackupWriteControl(FILE *out, pgBackup *backup);
481-
extern void pgBackupWriteFileList(pgBackup *backup, parray *files,
482+
extern void write_backup_filelist(pgBackup *backup, parray *files,
482483
const char *root);
483484

484-
extern void pgBackupGetPath(const pgBackup *backup, char *path, size_t len, const char *subdir);
485+
extern void pgBackupGetPath(const pgBackup *backup, char *path, size_t len,
486+
const char *subdir);
485487
extern void pgBackupGetPath2(const pgBackup *backup, char *path, size_t len,
486488
const char *subdir1, const char *subdir2);
487489
extern int pgBackupCreateDir(pgBackup *backup);
@@ -543,7 +545,6 @@ extern void restore_data_file(const char *to_path,
543545
bool write_header,
544546
uint32 backup_version);
545547
extern bool copy_file(const char *from_root, const char *to_root, pgFile *file);
546-
extern void move_file(const char *from_root, const char *to_root, pgFile *file);
547548
extern void push_wal_file(const char *from_path, const char *to_path,
548549
bool is_compress, bool overwrite);
549550
extern void get_wal_file(const char *from_path, const char *to_path);

Diff for: tests/merge.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ def test_continue_failed_merge(self):
602602

603603
gdb = self.merge_backup(backup_dir, "node", backup_id, gdb=True)
604604

605-
gdb.set_breakpoint('move_file')
605+
gdb.set_breakpoint('copy_file')
606606
gdb.run_until_break()
607607

608608
if gdb.continue_execution_until_break(20) != 'breakpoint-hit':
@@ -615,3 +615,10 @@ def test_continue_failed_merge(self):
615615

616616
# Try to continue failed MERGE
617617
self.merge_backup(backup_dir, "node", backup_id)
618+
619+
# Drop node and restore it
620+
node.cleanup()
621+
self.restore_node(backup_dir, 'node', node)
622+
623+
# Clean after yourself
624+
self.del_test_dir(module_name, fname)

0 commit comments

Comments
 (0)