@@ -132,11 +132,10 @@ parse_page(Page page, XLogRecPtr *lsn)
132132 */
133133static int
134134read_page_from_file (pgFile * file , BlockNumber blknum ,
135- FILE * in , Page page )
135+ FILE * in , Page page , XLogRecPtr * page_lsn )
136136{
137137 off_t offset = blknum * BLCKSZ ;
138138 size_t read_len = 0 ;
139- XLogRecPtr page_lsn ;
140139
141140 /* read the block */
142141 if (fseek (in , offset , SEEK_SET ) != 0 )
@@ -167,7 +166,7 @@ read_page_from_file(pgFile *file, BlockNumber blknum,
167166 * If after several attempts page header is still invalid, throw an error.
168167 * The same idea is applied to checksum verification.
169168 */
170- if (!parse_page (page , & page_lsn ))
169+ if (!parse_page (page , page_lsn ))
171170 {
172171 int i ;
173172 /* Check if the page is zeroed. */
@@ -232,6 +231,7 @@ backup_data_page(backup_files_args *arguments,
232231 BackupPageHeader header ;
233232 Page page = malloc (BLCKSZ );
234233 Page compressed_page = NULL ;
234+ XLogRecPtr page_lsn = 0 ;
235235 size_t write_buffer_size ;
236236 char write_buffer [BLCKSZ + sizeof (header )];
237237
@@ -252,7 +252,7 @@ backup_data_page(backup_files_args *arguments,
252252 while (!page_is_valid && try_again )
253253 {
254254 int result = read_page_from_file (file , blknum ,
255- in , page );
255+ in , page , & page_lsn );
256256
257257 try_again -- ;
258258 if (result == 0 )
@@ -316,6 +316,20 @@ backup_data_page(backup_files_args *arguments,
316316 if (is_checksum_enabled )
317317 ((PageHeader ) page )-> pd_checksum = pg_checksum_page (page , absolute_blknum );
318318 }
319+ /* get lsn from page */
320+ if (!parse_page (page , & page_lsn ))
321+ elog (ERROR , "Cannot parse page after pg_ptrack_get_block. "
322+ "Possible risk of a memory corruption" );
323+
324+ }
325+
326+ if (backup_mode == BACKUP_MODE_DIFF_DELTA &&
327+ header .compressed_size != PageIsTruncated &&
328+ page_lsn < prev_backup_start_lsn )
329+ {
330+ elog (VERBOSE , "Skipping blknum: %u in file: %s" , blknum , file -> path );
331+ free (page );
332+ return ;
319333 }
320334
321335 if (header .compressed_size != PageIsTruncated )
@@ -478,6 +492,8 @@ backup_data_file(backup_files_args* arguments,
478492 & n_blocks_skipped , backup_mode );
479493 n_blocks_read ++ ;
480494 }
495+ if (backup_mode == BACKUP_MODE_DIFF_DELTA )
496+ file -> n_blocks = n_blocks_read ;
481497 }
482498 /* If page map is not empty we scan only changed blocks, */
483499 else
@@ -545,6 +561,7 @@ restore_data_file(const char *from_root,
545561 FILE * out ;
546562 BackupPageHeader header ;
547563 BlockNumber blknum ;
564+ size_t file_size ;
548565
549566 /* open backup mode file for read */
550567 in = fopen (file -> path , "r" );
@@ -652,6 +669,31 @@ restore_data_file(const char *from_root,
652669 }
653670 }
654671
672+ /*
673+ * DELTA backup has no knowledge about truncated blocks as PAGE or PTRACK do
674+ * but knows file size at the time of backup.
675+ * So when restoring file from delta backup we, knowning it`s size at
676+ * a time of a backup, can truncate file to this size.
677+ */
678+
679+ if (backup -> backup_mode == BACKUP_MODE_DIFF_DELTA )
680+ {
681+ /* get file current size */
682+ fseek (out , 0 , SEEK_END );
683+ file_size = ftell (out );
684+
685+ if (file_size > file -> n_blocks * BLCKSZ )
686+ {
687+ /*
688+ * Truncate file to this length.
689+ */
690+ if (ftruncate (fileno (out ), file -> n_blocks * BLCKSZ ) != 0 )
691+ elog (ERROR , "cannot truncate \"%s\": %s" ,
692+ file -> path , strerror (errno ));
693+ elog (INFO , "Delta truncate file %s to block %u" , file -> path , file -> n_blocks );
694+ }
695+ }
696+
655697 /* update file permission */
656698 if (chmod (to_path , file -> mode ) == -1 )
657699 {
0 commit comments