@@ -59,7 +59,7 @@ do_merge(time_t backup_id)
59
59
if (instance_name == NULL )
60
60
elog (ERROR , "required parameter is not specified: --instance" );
61
61
62
- elog (LOG , "Merge started" );
62
+ elog (INFO , "Merge started" );
63
63
64
64
catalog_lock ();
65
65
@@ -77,7 +77,8 @@ do_merge(time_t backup_id)
77
77
{
78
78
if (backup -> status != BACKUP_STATUS_OK &&
79
79
/* 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 )
81
82
elog (ERROR , "Backup %s has status: %s" ,
82
83
base36enc (backup -> start_time ), status2str (backup -> status ));
83
84
@@ -128,17 +129,21 @@ do_merge(time_t backup_id)
128
129
*/
129
130
for (i = full_backup_idx ; i > dest_backup_idx ; i -- )
130
131
{
131
- pgBackup * to_backup = (pgBackup * ) parray_get (backups , i );
132
132
pgBackup * from_backup = (pgBackup * ) parray_get (backups , i - 1 );
133
133
134
- merge_backups (to_backup , from_backup );
134
+ full_backup = (pgBackup * ) parray_get (backups , i );
135
+ merge_backups (full_backup , from_backup );
135
136
}
136
137
138
+ pgBackupValidate (full_backup );
139
+ if (full_backup -> status == BACKUP_STATUS_CORRUPT )
140
+ elog (ERROR , "Merging of backup %s failed" , base36enc (backup_id ));
141
+
137
142
/* cleanup */
138
143
parray_walk (backups , pgBackupFree );
139
144
parray_free (backups );
140
145
141
- elog (LOG , "Merge completed" );
146
+ elog (INFO , "Merge of backup %s completed" , base36enc ( backup_id ) );
142
147
}
143
148
144
149
/*
@@ -164,7 +169,36 @@ merge_backups(pgBackup *to_backup, pgBackup *from_backup)
164
169
int i ;
165
170
bool merge_isok = true;
166
171
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 ;
168
202
169
203
to_backup -> status = BACKUP_STATUS_MERGING ;
170
204
write_backup_status (to_backup );
@@ -244,37 +278,38 @@ merge_backups(pgBackup *to_backup, pgBackup *from_backup)
244
278
elog (ERROR , "Data files merging failed" );
245
279
246
280
/*
247
- * Files were copied into to_backup and deleted from from_backup. Remove
248
- * remaining directories from from_backup.
281
+ * Update to_backup metadata.
249
282
*/
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 ;
251
286
for (i = 0 ; i < parray_num (files ); i ++ )
252
287
{
253
288
pgFile * file = (pgFile * ) parray_get (files , i );
254
289
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 ;
261
295
}
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 ;
268
303
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 );
274
306
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 );
278
313
279
314
/*
280
315
* Delete files which are not in from_backup file list.
@@ -286,46 +321,26 @@ merge_backups(pgBackup *to_backup, pgBackup *from_backup)
286
321
if (parray_bsearch (files , file , pgFileComparePathDesc ) == NULL )
287
322
{
288
323
pgFileDelete (file );
289
- elog (LOG , "Deleted \"%s\"" , file -> path );
324
+ elog (VERBOSE , "Deleted \"%s\"" , file -> path );
290
325
}
291
326
}
292
327
293
328
/*
294
329
* Rename FULL backup directory.
295
330
*/
331
+ elog (INFO , "Rename %s to %s" , to_backup_id , from_backup_id );
296
332
if (rename (to_backup_path , from_backup_path ) == -1 )
297
333
elog (ERROR , "Could not rename directory \"%s\" to \"%s\": %s" ,
298
334
to_backup_path , from_backup_path , strerror (errno ));
299
335
300
336
/*
301
- * Update to_backup metadata .
337
+ * Merging finished, now we can safely update ID of the destination backup .
302
338
*/
303
339
pgBackupCopy (to_backup , from_backup );
304
340
/* Correct metadata */
305
341
to_backup -> backup_mode = BACKUP_MODE_FULL ;
306
342
to_backup -> status = BACKUP_STATUS_OK ;
307
343
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 );
329
344
write_backup (to_backup );
330
345
331
346
/* Cleanup */
@@ -508,10 +523,9 @@ merge_files(void *arg)
508
523
file -> write_size = pgFileSize (to_path_tmp );
509
524
file -> crc = pgFileGetCRC (to_path_tmp , false);
510
525
}
511
- pgFileDelete (file );
512
526
}
513
527
else
514
- move_file (argument -> from_root , argument -> to_root , file );
528
+ copy_file (argument -> from_root , argument -> to_root , file );
515
529
516
530
if (file -> write_size != BYTES_INVALID )
517
531
elog (LOG , "Moved file \"%s\": " INT64_FORMAT " bytes" ,
0 commit comments