@@ -861,13 +861,25 @@ backup_non_data_file(pgFile *file, pgFile *prev_file,
861861 * Apply changed blocks to destination file from every backup in parent chain.
862862 */
863863size_t
864- restore_data_file (parray * parent_chain , pgFile * dest_file , FILE * out , const char * to_fullpath )
864+ restore_data_file (parray * parent_chain , pgFile * dest_file , FILE * out ,
865+ const char * to_fullpath , bool use_bitmap )
865866{
866- int i ;
867867 size_t total_write_len = 0 ;
868868 char * in_buf = pgut_malloc (STDIO_BUFSIZE );
869+ int backup_seq = 0 ;
869870
870- for (i = parray_num (parent_chain ) - 1 ; i >= 0 ; i -- )
871+ // FULL -> INCR -> DEST
872+ // 2 1 0
873+ if (use_bitmap )
874+ /* start with dest backup */
875+ backup_seq = 0 ;
876+ else
877+ /* start with full backup */
878+ backup_seq = parray_num (parent_chain ) - 1 ;
879+
880+ // for (i = parray_num(parent_chain) - 1; i >= 0; i--)
881+ // for (i = 0; i < parray_num(parent_chain); i++)
882+ while (backup_seq >= 0 && backup_seq < parray_num (parent_chain ))
871883 {
872884 char from_root [MAXPGPATH ];
873885 char from_fullpath [MAXPGPATH ];
@@ -876,7 +888,12 @@ restore_data_file(parray *parent_chain, pgFile *dest_file, FILE *out, const char
876888 pgFile * * res_file = NULL ;
877889 pgFile * tmp_file = NULL ;
878890
879- pgBackup * backup = (pgBackup * ) parray_get (parent_chain , i );
891+ pgBackup * backup = (pgBackup * ) parray_get (parent_chain , backup_seq );
892+
893+ if (use_bitmap )
894+ backup_seq ++ ;
895+ else
896+ backup_seq -- ;
880897
881898 /* lookup file in intermediate backup */
882899 res_file = parray_bsearch (backup -> files , dest_file , pgFileCompareRelPathWithExternal );
@@ -923,20 +940,29 @@ restore_data_file(parray *parent_chain, pgFile *dest_file, FILE *out, const char
923940 */
924941 total_write_len += restore_data_file_internal (in , out , tmp_file ,
925942 parse_program_version (backup -> program_version ),
926- from_fullpath , to_fullpath , dest_file -> n_blocks );
943+ from_fullpath , to_fullpath , dest_file -> n_blocks ,
944+ use_bitmap ? & (dest_file )-> pagemap : NULL );
927945
928946 if (fclose (in ) != 0 )
929947 elog (ERROR , "Cannot close file \"%s\": %s" , from_fullpath ,
930948 strerror (errno ));
949+
950+ // datapagemap_print_debug(&(dest_file)->pagemap);
931951 }
932952 pg_free (in_buf );
933953
934954 return total_write_len ;
935955}
936956
957+ /* Restore block from "in" file to "out" file.
958+ * If "nblocks" is greater than zero, then skip restoring blocks,
959+ * whose position if greater than "nblocks".
960+ * If map is NULL, then page bitmap cannot be used for restore optimization
961+ */
937962size_t
938963restore_data_file_internal (FILE * in , FILE * out , pgFile * file , uint32 backup_version ,
939- const char * from_fullpath , const char * to_fullpath , int nblocks )
964+ const char * from_fullpath , const char * to_fullpath , int nblocks ,
965+ datapagemap_t * map )
940966{
941967 BackupPageHeader header ;
942968 BlockNumber blknum = 0 ;
@@ -994,9 +1020,9 @@ restore_data_file_internal(FILE *in, FILE *out, pgFile *file, uint32 backup_vers
9941020 }
9951021
9961022 /* sanity? */
997- if (header .block < blknum )
998- elog (ERROR , "Backup is broken at block %u of \"%s\"" ,
999- blknum , from_fullpath );
1023+ // if (header.block < blknum)
1024+ // elog(ERROR, "Backup is broken at block %u of \"%s\"",
1025+ // blknum, from_fullpath);
10001026
10011027 blknum = header .block ;
10021028
@@ -1044,6 +1070,16 @@ restore_data_file_internal(FILE *in, FILE *out, pgFile *file, uint32 backup_vers
10441070 if (compressed_size > BLCKSZ )
10451071 elog (ERROR , "Size of a blknum %i exceed BLCKSZ" , blknum );
10461072
1073+ /* if this page is marked as already restored, then skip it */
1074+ if (map && datapagemap_is_set (map , blknum ))
1075+ {
1076+ /* skip to the next page */
1077+ if (fseek (in , MAXALIGN (compressed_size ), SEEK_CUR ) != 0 )
1078+ elog (ERROR , "Cannot seek block %u of '%s': %s" ,
1079+ blknum , from_fullpath , strerror (errno ));
1080+ continue ;
1081+ }
1082+
10471083 /* read a page from file */
10481084 read_len = fread (page .data , 1 , MAXALIGN (compressed_size ), in );
10491085
@@ -1099,6 +1135,9 @@ restore_data_file_internal(FILE *in, FILE *out, pgFile *file, uint32 backup_vers
10991135
11001136 write_len += BLCKSZ ;
11011137 cur_pos = write_pos + BLCKSZ ; /* update current write position */
1138+
1139+ if (map )
1140+ datapagemap_add (map , blknum );
11021141 }
11031142
11041143 elog (VERBOSE , "Copied file \"%s\": %lu bytes" , from_fullpath , write_len );
@@ -1152,7 +1191,7 @@ size_t
11521191restore_non_data_file (parray * parent_chain , pgBackup * dest_backup ,
11531192 pgFile * dest_file , FILE * out , const char * to_fullpath )
11541193{
1155- int i ;
1194+ // int i;
11561195 char from_root [MAXPGPATH ];
11571196 char from_fullpath [MAXPGPATH ];
11581197 FILE * in = NULL ;
@@ -1175,12 +1214,11 @@ restore_non_data_file(parray *parent_chain, pgBackup *dest_backup,
11751214 * Full copy is latest possible destination file with size equal or
11761215 * greater than zero.
11771216 */
1178- for (i = 1 ; i < parray_num (parent_chain ); i ++ )
1217+ tmp_backup = dest_backup -> parent_backup_link ;
1218+ while (tmp_backup )
11791219 {
11801220 pgFile * * res_file = NULL ;
11811221
1182- tmp_backup = (pgBackup * ) parray_get (parent_chain , i );
1183-
11841222 /* lookup file in intermediate backup */
11851223 res_file = parray_bsearch (tmp_backup -> files , dest_file , pgFileCompareRelPathWithExternal );
11861224 tmp_file = (res_file ) ? * res_file : NULL ;
@@ -1203,6 +1241,8 @@ restore_non_data_file(parray *parent_chain, pgBackup *dest_backup,
12031241 /* Full copy is found */
12041242 if (tmp_file -> write_size > 0 )
12051243 break ;
1244+
1245+ tmp_backup = tmp_backup -> parent_backup_link ;
12061246 }
12071247 }
12081248
@@ -1214,6 +1254,11 @@ restore_non_data_file(parray *parent_chain, pgBackup *dest_backup,
12141254 if (!tmp_file )
12151255 elog (ERROR , "Failed to locate a full copy of non-data file \"%s\"" , to_fullpath );
12161256
1257+ if (tmp_file -> write_size <= 0 )
1258+ elog (ERROR , "Full copy of non-data file has invalid size. "
1259+ "Metadata corruption in backup %s in file: \"%s\"" ,
1260+ base36enc (tmp_backup -> start_time ), to_fullpath );
1261+
12171262 if (tmp_file -> external_dir_num == 0 )
12181263 join_path_components (from_root , tmp_backup -> root_dir , DATABASE_DIR );
12191264 else
0 commit comments