@@ -862,14 +862,19 @@ backup_non_data_file(pgFile *file, pgFile *prev_file,
862862 */
863863size_t
864864restore_data_file (parray * parent_chain , pgFile * dest_file , FILE * out ,
865- const char * to_fullpath , bool use_bitmap , uint16 * checksum_map )
865+ const char * to_fullpath , bool use_bitmap , PageState * checksum_map ,
866+ XLogRecPtr horizonLsn , datapagemap_t * lsn_map )
866867{
867868 size_t total_write_len = 0 ;
868869 char * in_buf = pgut_malloc (STDIO_BUFSIZE );
869870 int backup_seq = 0 ;
870871
871- // FULL -> INCR -> DEST
872- // 2 1 0
872+ /*
873+ * FULL -> INCR -> DEST
874+ * 2 1 0
875+ * Restore of backups of older versions cannot be optimized with bitmap
876+ * because of n_blocks
877+ */
873878 if (use_bitmap )
874879 /* start with dest backup */
875880 backup_seq = 0 ;
@@ -942,7 +947,8 @@ restore_data_file(parray *parent_chain, pgFile *dest_file, FILE *out,
942947 parse_program_version (backup -> program_version ),
943948 from_fullpath , to_fullpath , dest_file -> n_blocks ,
944949 use_bitmap ? & (dest_file )-> pagemap : NULL ,
945- checksum_map , backup -> checksum_version );
950+ checksum_map , backup -> checksum_version ,
951+ backup -> start_lsn <= horizonLsn ? lsn_map : NULL );
946952
947953 if (fclose (in ) != 0 )
948954 elog (ERROR , "Cannot close file \"%s\": %s" , from_fullpath ,
@@ -963,7 +969,8 @@ restore_data_file(parray *parent_chain, pgFile *dest_file, FILE *out,
963969size_t
964970restore_data_file_internal (FILE * in , FILE * out , pgFile * file , uint32 backup_version ,
965971 const char * from_fullpath , const char * to_fullpath , int nblocks ,
966- datapagemap_t * map , uint16 * checksum_map , int checksum_version )
972+ datapagemap_t * map , PageState * checksum_map , int checksum_version ,
973+ datapagemap_t * lsn_map )
967974{
968975 BackupPageHeader header ;
969976 BlockNumber blknum = 0 ;
@@ -1071,6 +1078,9 @@ restore_data_file_internal(FILE *in, FILE *out, pgFile *file, uint32 backup_vers
10711078 if (compressed_size > BLCKSZ )
10721079 elog (ERROR , "Size of a blknum %i exceed BLCKSZ" , blknum );
10731080
1081+ if (lsn_map && datapagemap_is_set (lsn_map , blknum ))
1082+ datapagemap_add (map , blknum );
1083+
10741084 /* if this page is marked as already restored, then skip it */
10751085 if (map && datapagemap_is_set (map , blknum ))
10761086 {
@@ -1101,10 +1111,14 @@ restore_data_file_internal(FILE *in, FILE *out, pgFile *file, uint32 backup_vers
11011111 is_compressed = true;
11021112 }
11031113
1104- /* Incremental restore */
1105- if (checksum_map && checksum_map [blknum ] != 0 )
1114+ /* Incremental restore
1115+ * TODO: move to another function
1116+ */
1117+ if (checksum_map && checksum_map [blknum ].checksum != 0 )
11061118 {
11071119 uint16 page_crc = 0 ;
1120+ XLogRecPtr page_lsn = InvalidXLogRecPtr ;
1121+ PageHeader phdr ;
11081122
11091123 if (is_compressed )
11101124 {
@@ -1117,8 +1131,7 @@ restore_data_file_internal(FILE *in, FILE *out, pgFile *file, uint32 backup_vers
11171131 else
11181132 page_crc = pg_checksum_page (uncompressed_buf , file -> segno * RELSEG_SIZE + blknum );
11191133
1120- // page_crc_1 = pg_checksum_page(uncompressed_buf, file->segno * RELSEG_SIZE + blknum);
1121- // Assert(page_crc == page_crc_1);
1134+ phdr = (PageHeader ) uncompressed_buf ;
11221135 }
11231136 else
11241137 {
@@ -1127,10 +1140,19 @@ restore_data_file_internal(FILE *in, FILE *out, pgFile *file, uint32 backup_vers
11271140 page_crc = ((PageHeader ) page .data )-> pd_checksum ;
11281141 else
11291142 page_crc = pg_checksum_page (page .data , file -> segno + blknum );
1143+
1144+ phdr = (PageHeader ) page .data ;
11301145 }
11311146
1132- /* the heart of incremental restore */
1133- if (page_crc == checksum_map [blknum ])
1147+ page_lsn = PageXLogRecPtrGet (phdr -> pd_lsn );
1148+
1149+ /*
1150+ * The heart of incremental restore
1151+ * If page in backup has the same checksum and lsn as
1152+ * page in backup, then page can be skipped.
1153+ */
1154+ if (page_crc == checksum_map [blknum ].checksum &&
1155+ page_lsn == checksum_map [blknum ].lsn )
11341156 {
11351157 if (map )
11361158 datapagemap_add (map , blknum );
@@ -1812,10 +1834,10 @@ check_file_pages(pgFile *file, const char *fullpath, XLogRecPtr stop_lsn,
18121834}
18131835
18141836/* read local data file and construct map with block checksums */
1815- uint16 * get_checksum_map (const char * fullpath , uint32 checksum_version ,
1837+ PageState * get_checksum_map (const char * fullpath , uint32 checksum_version ,
18161838 int n_blocks , XLogRecPtr dest_stop_lsn , BlockNumber segmentno )
18171839{
1818- uint16 * checksum_map = NULL ;
1840+ PageState * checksum_map = NULL ;
18191841 FILE * in = NULL ;
18201842 BlockNumber blknum = 0 ;
18211843 XLogRecPtr page_lsn = 0 ;
@@ -1834,8 +1856,8 @@ uint16 *get_checksum_map(const char *fullpath, uint32 checksum_version,
18341856 setvbuf (in , in_buf , _IOFBF , STDIO_BUFSIZE );
18351857
18361858 /* initialize array of checksums */
1837- checksum_map = pgut_malloc (n_blocks * sizeof (uint16 ));
1838- memset (checksum_map , 0 , n_blocks * sizeof (uint16 ));
1859+ checksum_map = pgut_malloc (n_blocks * sizeof (PageState ));
1860+ memset (checksum_map , 0 , n_blocks * sizeof (PageState ));
18391861
18401862 for (blknum = 0 ; blknum < n_blocks ; blknum ++ )
18411863 {
@@ -1855,9 +1877,11 @@ uint16 *get_checksum_map(const char *fullpath, uint32 checksum_version,
18551877 if (rc == PAGE_IS_VALID )
18561878 {
18571879 if (checksum_version )
1858- checksum_map [blknum ] = ((PageHeader ) read_buffer )-> pd_checksum ;
1880+ checksum_map [blknum ]. checksum = ((PageHeader ) read_buffer )-> pd_checksum ;
18591881 else
1860- checksum_map [blknum ] = pg_checksum_page (read_buffer , segmentno + blknum );
1882+ checksum_map [blknum ].checksum = pg_checksum_page (read_buffer , segmentno + blknum );
1883+
1884+ checksum_map [blknum ].lsn = page_lsn ;
18611885 }
18621886 }
18631887 else
@@ -1875,3 +1899,71 @@ uint16 *get_checksum_map(const char *fullpath, uint32 checksum_version,
18751899
18761900 return checksum_map ;
18771901}
1902+
1903+ /* return bitmap of valid blocks, bitmap is empty, then NULL is returned */
1904+ datapagemap_t *
1905+ get_lsn_map (const char * fullpath , uint32 checksum_version ,
1906+ int n_blocks , XLogRecPtr horizonLsn , BlockNumber segmentno )
1907+ {
1908+ FILE * in = NULL ;
1909+ BlockNumber blknum = 0 ;
1910+ XLogRecPtr page_lsn = 0 ;
1911+ char read_buffer [BLCKSZ ];
1912+ char in_buf [STDIO_BUFSIZE ];
1913+ datapagemap_t * lsn_map = NULL ;
1914+
1915+ /* truncate up to blocks */
1916+ if (truncate (fullpath , n_blocks * BLCKSZ ) != 0 )
1917+ elog (ERROR , "Cannot truncate file to blknum %u \"%s\": %s" ,
1918+ n_blocks , fullpath , strerror (errno ));
1919+
1920+ Assert (horizonLsn > 0 );
1921+
1922+ /* open file */
1923+ in = fopen (fullpath , PG_BINARY_R );
1924+ if (!in )
1925+ elog (ERROR , "Cannot open source file \"%s\": %s" , fullpath , strerror (errno ));
1926+ setvbuf (in , in_buf , _IOFBF , STDIO_BUFSIZE );
1927+
1928+ lsn_map = pgut_malloc (sizeof (datapagemap_t ));
1929+ memset (lsn_map , 0 , sizeof (datapagemap_t ));
1930+
1931+ for (blknum = 0 ; blknum < n_blocks ; blknum ++ )
1932+ {
1933+ size_t read_len = fread (read_buffer , 1 , BLCKSZ , in );
1934+ page_lsn = InvalidXLogRecPtr ;
1935+
1936+ /* report error */
1937+ if (ferror (in ))
1938+ elog (ERROR , "Cannot read block %u of \"%s\": %s" ,
1939+ blknum , fullpath , strerror (errno ));
1940+
1941+ if (read_len == BLCKSZ )
1942+ {
1943+ int rc = validate_one_page (read_buffer , segmentno + blknum ,
1944+ horizonLsn , & page_lsn , checksum_version );
1945+
1946+ if (rc == PAGE_IS_VALID )
1947+ datapagemap_add (lsn_map , blknum );
1948+ }
1949+ else
1950+ elog (ERROR , "Failed to read blknum %u from file \"%s\"" , blknum , fullpath );
1951+
1952+ if (feof (in ))
1953+ break ;
1954+
1955+ if (interrupted )
1956+ elog (ERROR , "Interrupted during page reading" );
1957+ }
1958+
1959+ if (in )
1960+ fclose (in );
1961+
1962+ if (lsn_map -> bitmapsize == 0 )
1963+ {
1964+ pg_free (lsn_map );
1965+ lsn_map = NULL ;
1966+ }
1967+
1968+ return lsn_map ;
1969+ }
0 commit comments