@@ -59,7 +59,7 @@ do_merge(time_t backup_id)
5959 if (instance_name == NULL )
6060 elog (ERROR , "required parameter is not specified: --instance" );
6161
62- elog (LOG , "Merge started" );
62+ elog (INFO , "Merge started" );
6363
6464 catalog_lock ();
6565
@@ -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
@@ -128,17 +129,21 @@ do_merge(time_t backup_id)
128129 */
129130 for (i = full_backup_idx ; i > dest_backup_idx ; i -- )
130131 {
131- pgBackup * to_backup = (pgBackup * ) parray_get (backups , i );
132132 pgBackup * from_backup = (pgBackup * ) parray_get (backups , i - 1 );
133133
134- merge_backups (to_backup , from_backup );
134+ full_backup = (pgBackup * ) parray_get (backups , i );
135+ merge_backups (full_backup , from_backup );
135136 }
136137
138+ pgBackupValidate (full_backup );
139+ if (full_backup -> status == BACKUP_STATUS_CORRUPT )
140+ elog (ERROR , "Merging of backup %s failed" , base36enc (backup_id ));
141+
137142 /* cleanup */
138143 parray_walk (backups , pgBackupFree );
139144 parray_free (backups );
140145
141- elog (LOG , "Merge completed" );
146+ elog (INFO , "Merge of backup %s completed" , base36enc ( backup_id ) );
142147}
143148
144149/*
@@ -164,7 +169,36 @@ merge_backups(pgBackup *to_backup, pgBackup *from_backup)
164169 int i ;
165170 bool merge_isok = true;
166171
167- elog (LOG , "Merging backup %s with backup %s" , from_backup_id , to_backup_id );
172+ elog (INFO , "Merging backup %s with backup %s" , from_backup_id , to_backup_id );
173+
174+ /*
175+ * Validate to_backup only if it is BACKUP_STATUS_OK. If it has
176+ * BACKUP_STATUS_MERGING status then it isn't valid backup until merging
177+ * finished.
178+ */
179+ if (to_backup -> status == BACKUP_STATUS_OK )
180+ {
181+ pgBackupValidate (to_backup );
182+ if (to_backup -> status == BACKUP_STATUS_CORRUPT )
183+ elog (ERROR , "Interrupt merging" );
184+ }
185+
186+ /*
187+ * It is OK to validate from_backup if it has BACKUP_STATUS_OK or
188+ * BACKUP_STATUS_MERGING status.
189+ */
190+ Assert (from_backup -> status == BACKUP_STATUS_OK ||
191+ from_backup -> status == BACKUP_STATUS_MERGING );
192+ pgBackupValidate (from_backup );
193+ if (from_backup -> status == BACKUP_STATUS_CORRUPT )
194+ elog (ERROR , "Interrupt merging" );
195+
196+ /*
197+ * Previous merging was interrupted during deleting source backup. It is
198+ * safe just to delete it again.
199+ */
200+ if (from_backup -> status == BACKUP_STATUS_DELETING )
201+ goto delete_source_backup ;
168202
169203 to_backup -> status = BACKUP_STATUS_MERGING ;
170204 write_backup_status (to_backup );
@@ -244,37 +278,38 @@ merge_backups(pgBackup *to_backup, pgBackup *from_backup)
244278 elog (ERROR , "Data files merging failed" );
245279
246280 /*
247- * Files were copied into to_backup and deleted from from_backup. Remove
248- * remaining directories from from_backup.
281+ * Update to_backup metadata.
249282 */
250- parray_qsort (files , pgFileComparePathDesc );
283+ to_backup -> status = BACKUP_STATUS_OK ;
284+ /* Compute summary of size of regular files in the backup */
285+ to_backup -> data_bytes = 0 ;
251286 for (i = 0 ; i < parray_num (files ); i ++ )
252287 {
253288 pgFile * file = (pgFile * ) parray_get (files , i );
254289
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 ));
290+ if (S_ISDIR (file -> mode ))
291+ to_backup -> data_bytes += 4096 ;
292+ /* Count the amount of the data actually copied */
293+ else if (S_ISREG (file -> mode ))
294+ to_backup -> data_bytes += file -> write_size ;
261295 }
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 ));
296+ /* compute size of wal files of this backup stored in the archive */
297+ if (!to_backup -> stream )
298+ to_backup -> wal_bytes = xlog_seg_size *
299+ (to_backup -> stop_lsn / xlog_seg_size -
300+ to_backup -> start_lsn / xlog_seg_size + 1 );
301+ else
302+ to_backup -> wal_bytes = BYTES_INVALID ;
268303
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 ));
304+ write_backup_filelist (to_backup , files , from_database_path );
305+ write_backup (to_backup );
274306
275- if (rmdir (from_backup_path ))
276- elog (ERROR , "Could not remove directory \"%s\": %s" ,
277- from_backup_path , strerror (errno ));
307+ delete_source_backup :
308+ /*
309+ * Files were copied into to_backup. It is time to remove source backup
310+ * entirely.
311+ */
312+ delete_backup_files (from_backup );
278313
279314 /*
280315 * Delete files which are not in from_backup file list.
@@ -286,46 +321,26 @@ merge_backups(pgBackup *to_backup, pgBackup *from_backup)
286321 if (parray_bsearch (files , file , pgFileComparePathDesc ) == NULL )
287322 {
288323 pgFileDelete (file );
289- elog (LOG , "Deleted \"%s\"" , file -> path );
324+ elog (VERBOSE , "Deleted \"%s\"" , file -> path );
290325 }
291326 }
292327
293328 /*
294329 * Rename FULL backup directory.
295330 */
331+ elog (INFO , "Rename %s to %s" , to_backup_id , from_backup_id );
296332 if (rename (to_backup_path , from_backup_path ) == -1 )
297333 elog (ERROR , "Could not rename directory \"%s\" to \"%s\": %s" ,
298334 to_backup_path , from_backup_path , strerror (errno ));
299335
300336 /*
301- * Update to_backup metadata .
337+ * Merging finished, now we can safely update ID of the destination backup .
302338 */
303339 pgBackupCopy (to_backup , from_backup );
304340 /* Correct metadata */
305341 to_backup -> backup_mode = BACKUP_MODE_FULL ;
306342 to_backup -> status = BACKUP_STATUS_OK ;
307343 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 );
329344 write_backup (to_backup );
330345
331346 /* Cleanup */
@@ -508,10 +523,9 @@ merge_files(void *arg)
508523 file -> write_size = pgFileSize (to_path_tmp );
509524 file -> crc = pgFileGetCRC (to_path_tmp , false);
510525 }
511- pgFileDelete (file );
512526 }
513527 else
514- move_file (argument -> from_root , argument -> to_root , file );
528+ copy_file (argument -> from_root , argument -> to_root , file );
515529
516530 if (file -> write_size != BYTES_INVALID )
517531 elog (LOG , "Moved file \"%s\": " INT64_FORMAT " bytes" ,
0 commit comments