@@ -160,6 +160,7 @@ do_merge(time_t backup_id)
160160
161161/*
162162 * Merge two backups data files using threads.
163+ * - to_backup - FULL, from_backup - incremental.
163164 * - move instance files from from_backup to to_backup
164165 * - remove unnecessary directories and files from to_backup
165166 * - update metadata of from_backup, it becames FULL backup
@@ -355,9 +356,12 @@ merge_backups(pgBackup *to_backup, pgBackup *from_backup)
355356pgFile * file = (pgFile * )parray_get (files ,i );
356357
357358if (S_ISDIR (file -> mode ))
359+ {
358360to_backup -> data_bytes += 4096 ;
361+ continue ;
362+ }
359363/* Count the amount of the data actually copied */
360- else if (S_ISREG ( file -> mode ) )
364+ if (file -> write_size > 0 )
361365to_backup -> data_bytes += file -> write_size ;
362366}
363367/* compute size of wal files of this backup stored in the archive */
@@ -381,7 +385,7 @@ merge_backups(pgBackup *to_backup, pgBackup *from_backup)
381385/*
382386 * Delete files which are not in from_backup file list.
383387 */
384- parray_qsort (files ,pgFileComparePathDesc );
388+ parray_qsort (files ,pgFileComparePathWithExternalDesc );
385389for (i = 0 ;i < parray_num (to_files );i ++ )
386390{
387391pgFile * file = (pgFile * )parray_get (to_files ,i );
@@ -394,7 +398,7 @@ merge_backups(pgBackup *to_backup, pgBackup *from_backup)
394398continue ;
395399}
396400
397- if (parray_bsearch (files ,file ,pgFileComparePathDesc )== NULL )
401+ if (parray_bsearch (files ,file ,pgFileComparePathWithExternalDesc )== NULL )
398402{
399403char to_file_path [MAXPGPATH ];
400404char * prev_path ;
@@ -507,7 +511,7 @@ merge_files(void *arg)
507511(!file -> is_datafile || file -> is_cfs ))
508512{
509513elog (VERBOSE ,"Skip merging file \"%s\", the file didn't change" ,
510- file -> path );
514+ file -> rel_path );
511515
512516/*
513517 * If the file wasn't changed, retreive its
@@ -529,6 +533,10 @@ merge_files(void *arg)
529533}
530534}
531535
536+ /* TODO optimization: file from incremental backup has size 0, then
537+ * just truncate the file from FULL backup
538+ */
539+
532540/* We need to make full path, file object has relative path */
533541if (file -> external_dir_num )
534542{
@@ -560,46 +568,51 @@ merge_files(void *arg)
560568if (to_backup -> compress_alg == PGLZ_COMPRESS ||
561569to_backup -> compress_alg == ZLIB_COMPRESS )
562570{
571+ char merge_to_file_path [MAXPGPATH ];
563572char tmp_file_path [MAXPGPATH ];
564573char * prev_path ;
565574
575+ snprintf (merge_to_file_path ,MAXPGPATH ,"%s_merge" ,to_file_path );
566576snprintf (tmp_file_path ,MAXPGPATH ,"%s_tmp" ,to_file_path );
567577
568578/* Start the magic */
569579
570580/*
571581 * Merge files:
572- * - if target file exists restore and decompress it to the temp
573- * path
582+ * - if to_file in FULL backup exists, restore and decompress it to to_file_merge
574583 * - decompress source file if necessary and merge it with the
575- * target decompressed file
576- * - compress result file
584+ * target decompressed file in to_file_merge.
585+ * - compress result file to to_file_tmp
586+ * - rename to_file_tmp to to_file
577587 */
578588
579589/*
580- * We need to decompress target file if it exists.
590+ * We need to decompress target filein FULL backup if it exists.
581591 */
582592if (to_file )
583593{
584594elog (VERBOSE ,"Merge target and source files into the temporary path \"%s\"" ,
585- tmp_file_path );
595+ merge_to_file_path );
586596
587597/*
588- * file->pathpoints to the file in from_root directory. But we
589- *need the file in directory to_root .
598+ * file->pathis relative, to_file_path - is absolute.
599+ *Substitute them .
590600 */
591601prev_path = to_file -> path ;
592602to_file -> path = to_file_path ;
593603/* Decompress target file into temporary one */
594- restore_data_file (tmp_file_path ,to_file , false, false,
604+ restore_data_file (merge_to_file_path ,to_file , false, false,
595605parse_program_version (to_backup -> program_version ));
596606to_file -> path = prev_path ;
597607}
598608else
599609elog (VERBOSE ,"Restore source file into the temporary path \"%s\"" ,
600- tmp_file_path );
610+ merge_to_file_path );
611+
612+ /* TODO: Optimize merge of new files */
613+
601614/* Merge source file with target file */
602- restore_data_file (tmp_file_path ,file ,
615+ restore_data_file (merge_to_file_path ,file ,
603616from_backup -> backup_mode == BACKUP_MODE_DIFF_DELTA ,
604617 false,
605618parse_program_version (from_backup -> program_version ));
@@ -609,12 +622,12 @@ merge_files(void *arg)
609622
610623/* Again we need to change path */
611624prev_path = file -> path ;
612- file -> path = tmp_file_path ;
625+ file -> path = merge_to_file_path ;
613626/* backup_data_file() requires file size to calculate nblocks */
614627file -> size = pgFileSize (file -> path );
615628/* Now we can compress the file */
616629backup_data_file (NULL ,/* We shouldn't need 'arguments' here */
617- to_file_path ,file ,
630+ tmp_file_path ,file ,
618631to_backup -> start_lsn ,
619632to_backup -> backup_mode ,
620633to_backup -> compress_alg ,
@@ -623,10 +636,15 @@ merge_files(void *arg)
623636
624637file -> path = prev_path ;
625638
626- /* We can remove temporary file now */
627- if (unlink (tmp_file_path ))
639+ /* rename temp file */
640+ if (rename (tmp_file_path ,to_file_path )== -1 )
641+ elog (ERROR ,"Could not rename file \"%s\" to \"%s\": %s" ,
642+ file -> path ,tmp_file_path ,strerror (errno ));
643+
644+ /* We can remove temporary file */
645+ if (unlink (merge_to_file_path ))
628646elog (ERROR ,"Could not remove temporary file \"%s\": %s" ,
629- tmp_file_path ,strerror (errno ));
647+ merge_to_file_path ,strerror (errno ));
630648}
631649/*
632650 * Otherwise merging algorithm is simpler.
@@ -676,7 +694,8 @@ merge_files(void *arg)
676694elog (VERBOSE ,"Merged file \"%s\": " INT64_FORMAT " bytes" ,
677695file -> path ,file -> write_size );
678696else
679- elog (ERROR ,"Merge of file \"%s\" failed. Invalid size: %i" ,BYTES_INVALID );
697+ elog (ERROR ,"Merge of file \"%s\" failed. Invalid size: %i" ,
698+ file -> path ,BYTES_INVALID );
680699
681700/* Restore relative path */
682701file -> path = prev_file_path ;