@@ -757,7 +757,7 @@ restore_data_file(const char *to_path, pgFile *file, bool allow_truncate,
757757 }
758758
759759 /*
760- * Open backup file for write. We use "r+" at first to overwrite only
760+ * Open backup file for write. We use "r+" at first to overwrite only
761761 * modified pages for differential restore. If the file does not exist,
762762 * re-open it with "w" to create an empty file.
763763 */
@@ -961,6 +961,193 @@ restore_data_file(const char *to_path, pgFile *file, bool allow_truncate,
961961 fclose (in );
962962}
963963
964+ /*
965+ * Restore files in the from_root directory to the to_root directory with
966+ * same relative path.
967+ *
968+ * If write_header is true then we add header to each restored block, currently
969+ * it is used for MERGE command.
970+ *
971+ * to_fullpath and from_fullpath are provided strictly for ERROR reporting
972+ */
973+ void
974+ restore_data_file_new (FILE * in , FILE * out , pgFile * file , uint32 backup_version ,
975+ const char * from_fullpath , const char * to_fullpath , int nblocks )
976+ {
977+ BackupPageHeader header ;
978+ BlockNumber blknum = 0 ;
979+ size_t write_len = 0 ;
980+
981+ while (true)
982+ {
983+ off_t write_pos ;
984+ size_t read_len ;
985+ DataPage compressed_page ; /* used as read buffer */
986+ DataPage page ;
987+ int32 uncompressed_size = 0 ;
988+
989+ /* read BackupPageHeader */
990+ read_len = fread (& header , 1 , sizeof (header ), in );
991+
992+ if (read_len != sizeof (header ))
993+ {
994+ int errno_tmp = errno ;
995+ if (read_len == 0 && feof (in ))
996+ break ; /* EOF found */
997+ else if (read_len != 0 && feof (in ))
998+ elog (ERROR , "Odd size page found at block %u of \"%s\"" ,
999+ blknum , from_fullpath );
1000+ else
1001+ elog (ERROR , "Cannot read header of block %u of \"%s\": %s" ,
1002+ blknum , from_fullpath , strerror (errno_tmp ));
1003+ }
1004+
1005+ /* Consider empty block */
1006+ if (header .block == 0 && header .compressed_size == 0 )
1007+ {
1008+ elog (VERBOSE , "Skip empty block of \"%s\"" , from_fullpath );
1009+ continue ;
1010+ }
1011+
1012+ /* sanity? */
1013+ if (header .block < blknum )
1014+ elog (ERROR , "Backup is broken at block %u of \"%s\"" ,
1015+ blknum , from_fullpath );
1016+
1017+ blknum = header .block ;
1018+
1019+ /* no point in writing redundant data */
1020+ if (nblocks > 0 && blknum >= nblocks )
1021+ return ;
1022+
1023+ if (header .compressed_size > BLCKSZ )
1024+ elog (ERROR , "Size of a blknum %i exceed BLCKSZ" , blknum );
1025+
1026+ /* read a page from file */
1027+ read_len = fread (compressed_page .data , 1 ,
1028+ MAXALIGN (header .compressed_size ), in );
1029+
1030+ if (read_len != MAXALIGN (header .compressed_size ))
1031+ elog (ERROR , "Cannot read block %u of \"%s\", read %zu of %d" ,
1032+ blknum , from_fullpath , read_len , header .compressed_size );
1033+
1034+ /*
1035+ * if page size is smaller than BLCKSZ, decompress the page.
1036+ * BUGFIX for versions < 2.0.23: if page size is equal to BLCKSZ.
1037+ * we have to check, whether it is compressed or not using
1038+ * page_may_be_compressed() function.
1039+ */
1040+ if (header .compressed_size != BLCKSZ
1041+ || page_may_be_compressed (compressed_page .data , file -> compress_alg ,
1042+ backup_version ))
1043+ {
1044+ const char * errormsg = NULL ;
1045+
1046+ uncompressed_size = do_decompress (page .data , BLCKSZ ,
1047+ compressed_page .data ,
1048+ header .compressed_size ,
1049+ file -> compress_alg , & errormsg );
1050+
1051+ if (uncompressed_size < 0 && errormsg != NULL )
1052+ elog (WARNING , "An error occured during decompressing block %u of file \"%s\": %s" ,
1053+ blknum , from_fullpath , errormsg );
1054+
1055+ if (uncompressed_size != BLCKSZ )
1056+ elog (ERROR , "Page of file \"%s\" uncompressed to %d bytes. != BLCKSZ" ,
1057+ from_fullpath , uncompressed_size );
1058+ }
1059+
1060+ write_pos = blknum * BLCKSZ ;
1061+
1062+ /*
1063+ * Seek and write the restored page.
1064+ * TODO: invent fio_pwrite().
1065+ */
1066+ if (fio_fseek (out , write_pos ) < 0 )
1067+ elog (ERROR , "Cannot seek block %u of \"%s\": %s" ,
1068+ blknum , to_fullpath , strerror (errno ));
1069+
1070+ /* if we uncompressed the page - write page.data,
1071+ * if page wasn't compressed -
1072+ * write what we've read - compressed_page.data
1073+ */
1074+ if (uncompressed_size == BLCKSZ )
1075+ {
1076+ if (fio_fwrite (out , page .data , BLCKSZ ) != BLCKSZ )
1077+ elog (ERROR , "Cannot write block %u of \"%s\": %s" ,
1078+ blknum , to_fullpath , strerror (errno ));
1079+ }
1080+ else
1081+ {
1082+ if (fio_fwrite (out , compressed_page .data , BLCKSZ ) != BLCKSZ )
1083+ elog (ERROR , "Cannot write block %u of \"%s\": %s" ,
1084+ blknum , to_fullpath , strerror (errno ));
1085+ }
1086+
1087+ write_len += BLCKSZ ;
1088+ }
1089+
1090+ elog (VERBOSE , "Copied file \"%s\": %lu bytes" , from_fullpath , write_len );
1091+ }
1092+
1093+ /*
1094+ * Copy file to backup.
1095+ * We do not apply compression to these files, because
1096+ * it is either small control file or already compressed cfs file.
1097+ */
1098+ void
1099+ restore_non_data_file (FILE * in , FILE * out , pgFile * file ,
1100+ const char * from_fullpath , const char * to_fullpath )
1101+ {
1102+ size_t read_len = 0 ;
1103+ int errno_tmp ;
1104+ char buf [BLCKSZ ];
1105+
1106+ /* copy content */
1107+ for (;;)
1108+ {
1109+ read_len = 0 ;
1110+
1111+ if ((read_len = fio_fread (in , buf , sizeof (buf ))) != sizeof (buf ))
1112+ break ;
1113+
1114+ if (fio_fwrite (out , buf , read_len ) != read_len )
1115+ {
1116+ errno_tmp = errno ;
1117+ /* oops */
1118+ fio_fclose (in );
1119+ fio_fclose (out );
1120+ elog (ERROR , "Cannot write to \"%s\": %s" , to_fullpath ,
1121+ strerror (errno_tmp ));
1122+ }
1123+ }
1124+
1125+ errno_tmp = errno ;
1126+ if (read_len < 0 )
1127+ {
1128+ fio_fclose (in );
1129+ fio_fclose (out );
1130+ elog (ERROR , "Cannot read backup mode file \"%s\": %s" ,
1131+ from_fullpath , strerror (errno_tmp ));
1132+ }
1133+
1134+ /* copy odd part. */
1135+ if (read_len > 0 )
1136+ {
1137+ if (fio_fwrite (out , buf , read_len ) != read_len )
1138+ {
1139+ errno_tmp = errno ;
1140+ /* oops */
1141+ fio_fclose (in );
1142+ fio_fclose (out );
1143+ elog (ERROR , "Cannot write to \"%s\": %s" , to_fullpath ,
1144+ strerror (errno_tmp ));
1145+ }
1146+ }
1147+
1148+ elog (VERBOSE , "Copied file \"%s\": %lu bytes" , from_fullpath , file -> write_size );
1149+ }
1150+
9641151/*
9651152 * Copy file to backup.
9661153 * We do not apply compression to these files, because
0 commit comments