@@ -160,6 +160,7 @@ do_merge(time_t backup_id)
160
160
161
161
/*
162
162
* Merge two backups data files using threads.
163
+ * - to_backup - FULL, from_backup - incremental.
163
164
* - move instance files from from_backup to to_backup
164
165
* - remove unnecessary directories and files from to_backup
165
166
* - update metadata of from_backup, it becames FULL backup
@@ -355,9 +356,12 @@ merge_backups(pgBackup *to_backup, pgBackup *from_backup)
355
356
pgFile * file = (pgFile * ) parray_get (files , i );
356
357
357
358
if (S_ISDIR (file -> mode ))
359
+ {
358
360
to_backup -> data_bytes += 4096 ;
361
+ continue ;
362
+ }
359
363
/* Count the amount of the data actually copied */
360
- else if (S_ISREG ( file -> mode ) )
364
+ if (file -> write_size > 0 )
361
365
to_backup -> data_bytes += file -> write_size ;
362
366
}
363
367
/* compute size of wal files of this backup stored in the archive */
@@ -381,7 +385,7 @@ merge_backups(pgBackup *to_backup, pgBackup *from_backup)
381
385
/*
382
386
* Delete files which are not in from_backup file list.
383
387
*/
384
- parray_qsort (files , pgFileComparePathDesc );
388
+ parray_qsort (files , pgFileComparePathWithExternalDesc );
385
389
for (i = 0 ; i < parray_num (to_files ); i ++ )
386
390
{
387
391
pgFile * file = (pgFile * ) parray_get (to_files , i );
@@ -394,7 +398,7 @@ merge_backups(pgBackup *to_backup, pgBackup *from_backup)
394
398
continue ;
395
399
}
396
400
397
- if (parray_bsearch (files , file , pgFileComparePathDesc ) == NULL )
401
+ if (parray_bsearch (files , file , pgFileComparePathWithExternalDesc ) == NULL )
398
402
{
399
403
char to_file_path [MAXPGPATH ];
400
404
char * prev_path ;
@@ -507,7 +511,7 @@ merge_files(void *arg)
507
511
(!file -> is_datafile || file -> is_cfs ))
508
512
{
509
513
elog (VERBOSE , "Skip merging file \"%s\", the file didn't change" ,
510
- file -> path );
514
+ file -> rel_path );
511
515
512
516
/*
513
517
* If the file wasn't changed, retreive its
@@ -529,6 +533,10 @@ merge_files(void *arg)
529
533
}
530
534
}
531
535
536
+ /* TODO optimization: file from incremental backup has size 0, then
537
+ * just truncate the file from FULL backup
538
+ */
539
+
532
540
/* We need to make full path, file object has relative path */
533
541
if (file -> external_dir_num )
534
542
{
@@ -560,46 +568,51 @@ merge_files(void *arg)
560
568
if (to_backup -> compress_alg == PGLZ_COMPRESS ||
561
569
to_backup -> compress_alg == ZLIB_COMPRESS )
562
570
{
571
+ char merge_to_file_path [MAXPGPATH ];
563
572
char tmp_file_path [MAXPGPATH ];
564
573
char * prev_path ;
565
574
575
+ snprintf (merge_to_file_path , MAXPGPATH , "%s_merge" , to_file_path );
566
576
snprintf (tmp_file_path , MAXPGPATH , "%s_tmp" , to_file_path );
567
577
568
578
/* Start the magic */
569
579
570
580
/*
571
581
* 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
574
583
* - 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
577
587
*/
578
588
579
589
/*
580
- * We need to decompress target file if it exists.
590
+ * We need to decompress target file in FULL backup if it exists.
581
591
*/
582
592
if (to_file )
583
593
{
584
594
elog (VERBOSE , "Merge target and source files into the temporary path \"%s\"" ,
585
- tmp_file_path );
595
+ merge_to_file_path );
586
596
587
597
/*
588
- * file->path points to the file in from_root directory. But we
589
- * need the file in directory to_root .
598
+ * file->path is relative, to_file_path - is absolute.
599
+ * Substitute them .
590
600
*/
591
601
prev_path = to_file -> path ;
592
602
to_file -> path = to_file_path ;
593
603
/* 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,
595
605
parse_program_version (to_backup -> program_version ));
596
606
to_file -> path = prev_path ;
597
607
}
598
608
else
599
609
elog (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
+
601
614
/* Merge source file with target file */
602
- restore_data_file (tmp_file_path , file ,
615
+ restore_data_file (merge_to_file_path , file ,
603
616
from_backup -> backup_mode == BACKUP_MODE_DIFF_DELTA ,
604
617
false,
605
618
parse_program_version (from_backup -> program_version ));
@@ -609,12 +622,12 @@ merge_files(void *arg)
609
622
610
623
/* Again we need to change path */
611
624
prev_path = file -> path ;
612
- file -> path = tmp_file_path ;
625
+ file -> path = merge_to_file_path ;
613
626
/* backup_data_file() requires file size to calculate nblocks */
614
627
file -> size = pgFileSize (file -> path );
615
628
/* Now we can compress the file */
616
629
backup_data_file (NULL , /* We shouldn't need 'arguments' here */
617
- to_file_path , file ,
630
+ tmp_file_path , file ,
618
631
to_backup -> start_lsn ,
619
632
to_backup -> backup_mode ,
620
633
to_backup -> compress_alg ,
@@ -623,10 +636,15 @@ merge_files(void *arg)
623
636
624
637
file -> path = prev_path ;
625
638
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 ))
628
646
elog (ERROR , "Could not remove temporary file \"%s\": %s" ,
629
- tmp_file_path , strerror (errno ));
647
+ merge_to_file_path , strerror (errno ));
630
648
}
631
649
/*
632
650
* Otherwise merging algorithm is simpler.
@@ -676,7 +694,8 @@ merge_files(void *arg)
676
694
elog (VERBOSE , "Merged file \"%s\": " INT64_FORMAT " bytes" ,
677
695
file -> path , file -> write_size );
678
696
else
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 );
680
699
681
700
/* Restore relative path */
682
701
file -> path = prev_file_path ;
0 commit comments