27
27
28
28
#ifdef HAVE_LIBZ
29
29
/* Implementation of zlib compression method */
30
- static size_t zlib_compress (void * dst , size_t dst_size , void const * src , size_t src_size )
30
+ static int32 zlib_compress (void * dst , size_t dst_size , void const * src , size_t src_size )
31
31
{
32
32
uLongf compressed_size = dst_size ;
33
33
int rc = compress2 (dst , & compressed_size , src , src_size , compress_level );
34
34
return rc == Z_OK ? compressed_size : rc ;
35
35
}
36
36
37
37
/* Implementation of zlib compression method */
38
- static size_t zlib_decompress (void * dst , size_t dst_size , void const * src , size_t src_size )
38
+ static int32 zlib_decompress (void * dst , size_t dst_size , void const * src , size_t src_size )
39
39
{
40
40
uLongf dest_len = dst_size ;
41
41
int rc = uncompress (dst , & dest_len , src , src_size );
@@ -47,7 +47,7 @@ static size_t zlib_decompress(void* dst, size_t dst_size, void const* src, size_
47
47
* Compresses source into dest using algorithm. Returns the number of bytes
48
48
* written in the destination buffer, or -1 if compression fails.
49
49
*/
50
- static size_t
50
+ static int32
51
51
do_compress (void * dst , size_t dst_size , void const * src , size_t src_size , CompressAlg alg )
52
52
{
53
53
switch (alg )
@@ -70,7 +70,7 @@ do_compress(void* dst, size_t dst_size, void const* src, size_t src_size, Compre
70
70
* Decompresses source into dest using algorithm. Returns the number of bytes
71
71
* decompressed in the destination buffer, or -1 if decompression fails.
72
72
*/
73
- static size_t
73
+ static int32
74
74
do_decompress (void * dst , size_t dst_size , void const * src , size_t src_size , CompressAlg alg )
75
75
{
76
76
switch (alg )
@@ -101,6 +101,7 @@ typedef struct BackupPageHeader
101
101
102
102
/* Special value for compressed_size field */
103
103
#define PageIsTruncated -2
104
+ #define SkipCurrentPage -3
104
105
105
106
/* Verify page's header */
106
107
static bool
@@ -134,8 +135,8 @@ static int
134
135
read_page_from_file (pgFile * file , BlockNumber blknum ,
135
136
FILE * in , Page page , XLogRecPtr * page_lsn )
136
137
{
137
- off_t offset = blknum * BLCKSZ ;
138
- size_t read_len = 0 ;
138
+ off_t offset = blknum * BLCKSZ ;
139
+ size_t read_len = 0 ;
139
140
140
141
/* read the block */
141
142
if (fseek (in , offset , SEEK_SET ) != 0 )
@@ -216,32 +217,29 @@ read_page_from_file(pgFile *file, BlockNumber blknum,
216
217
}
217
218
218
219
/*
219
- * Backup the specified block from a file of a relation.
220
- * Verify page header and checksum of the page and write it
221
- * to the backup file.
220
+ * Retrieves a page taking the backup mode into account
221
+ * and writes it into argument "page". Argument "page"
222
+ * should be a pointer to allocated BLCKSZ of bytes.
223
+ *
224
+ * Prints appropriate warnings/errors/etc into log.
225
+ * Returns 0 if page was successfully retrieved
226
+ * SkipCurrentPage(-3) if we need to skip this page
227
+ * PageIsTruncated(-2) if the page was truncated
222
228
*/
223
- static void
224
- backup_data_page (backup_files_args * arguments ,
229
+ static int32
230
+ prepare_page (backup_files_args * arguments ,
225
231
pgFile * file , XLogRecPtr prev_backup_start_lsn ,
226
232
BlockNumber blknum , BlockNumber nblocks ,
227
- FILE * in , FILE * out ,
228
- pg_crc32 * crc , int * n_skipped ,
229
- BackupMode backup_mode )
233
+ FILE * in , int * n_skipped ,
234
+ BackupMode backup_mode ,
235
+ Page page )
230
236
{
231
- BackupPageHeader header ;
232
- Page page = malloc (BLCKSZ );
233
- Page compressed_page = NULL ;
234
- XLogRecPtr page_lsn = 0 ;
235
- size_t write_buffer_size ;
236
- char write_buffer [BLCKSZ + sizeof (header )];
237
-
238
- int try_again = 100 ;
239
- bool page_is_valid = false;
237
+ XLogRecPtr page_lsn = 0 ;
238
+ int try_again = 100 ;
239
+ bool page_is_valid = false;
240
+ bool page_is_truncated = false;
240
241
BlockNumber absolute_blknum = file -> segno * RELSEG_SIZE + blknum ;
241
242
242
- header .block = blknum ;
243
- header .compressed_size = 0 ;
244
-
245
243
/* check for interrupt */
246
244
if (interrupted )
247
245
elog (ERROR , "Interrupted during backup" );
@@ -262,7 +260,7 @@ backup_data_page(backup_files_args *arguments,
262
260
if (result == 0 )
263
261
{
264
262
/* This block was truncated.*/
265
- header . compressed_size = PageIsTruncated ;
263
+ page_is_truncated = true ;
266
264
/* Page is not actually valid, but it is absent
267
265
* and we're not going to reread it or validate */
268
266
page_is_valid = true;
@@ -295,35 +293,38 @@ backup_data_page(backup_files_args *arguments,
295
293
if (backup_mode == BACKUP_MODE_DIFF_PTRACK || (!page_is_valid && is_ptrack_support ))
296
294
{
297
295
size_t page_size = 0 ;
298
-
299
- free (page );
300
- page = NULL ;
301
- page = (Page ) pg_ptrack_get_block (arguments , file -> dbOid , file -> tblspcOid ,
296
+ Page ptrack_page = NULL ;
297
+ ptrack_page = (Page ) pg_ptrack_get_block (arguments , file -> dbOid , file -> tblspcOid ,
302
298
file -> relOid , absolute_blknum , & page_size );
303
299
304
- if (page == NULL )
300
+ if (ptrack_page == NULL )
305
301
{
306
302
/* This block was truncated.*/
307
- header . compressed_size = PageIsTruncated ;
303
+ page_is_truncated = true ;
308
304
}
309
305
else if (page_size != BLCKSZ )
310
306
{
307
+ free (ptrack_page );
311
308
elog (ERROR , "File: %s, block %u, expected block size %d, but read %lu" ,
312
309
file -> path , absolute_blknum , BLCKSZ , page_size );
313
310
}
314
311
else
315
312
{
316
313
/*
314
+ * We need to copy the page that was successfully
315
+ * retreieved from ptrack into our output "page" parameter.
317
316
* We must set checksum here, because it is outdated
318
317
* in the block recieved from shared buffers.
319
318
*/
319
+ memcpy (page , ptrack_page , BLCKSZ );
320
+ free (ptrack_page );
320
321
if (is_checksum_enabled )
321
322
((PageHeader ) page )-> pd_checksum = pg_checksum_page (page , absolute_blknum );
322
323
}
323
324
/* get lsn from page, provided by pg_ptrack_get_block() */
324
325
if (backup_mode == BACKUP_MODE_DIFF_DELTA &&
325
326
file -> exists_in_prev &&
326
- header . compressed_size != PageIsTruncated &&
327
+ ! page_is_truncated &&
327
328
!parse_page (page , & page_lsn ))
328
329
elog (ERROR , "Cannot parse page after pg_ptrack_get_block. "
329
330
"Possible risk of a memory corruption" );
@@ -332,52 +333,70 @@ backup_data_page(backup_files_args *arguments,
332
333
333
334
if (backup_mode == BACKUP_MODE_DIFF_DELTA &&
334
335
file -> exists_in_prev &&
335
- header . compressed_size != PageIsTruncated &&
336
+ ! page_is_truncated &&
336
337
page_lsn < prev_backup_start_lsn )
337
338
{
338
339
elog (VERBOSE , "Skipping blknum: %u in file: %s" , blknum , file -> path );
339
340
(* n_skipped )++ ;
340
- free (page );
341
- return ;
341
+ return SkipCurrentPage ;
342
342
}
343
343
344
- if (header .compressed_size != PageIsTruncated )
345
- {
346
- file -> read_size += BLCKSZ ;
344
+ if (page_is_truncated )
345
+ return PageIsTruncated ;
347
346
348
- compressed_page = malloc (BLCKSZ );
349
- header .compressed_size = do_compress (compressed_page , BLCKSZ ,
350
- page , BLCKSZ , compress_alg );
347
+ return 0 ;
348
+ }
351
349
352
- file -> compress_alg = compress_alg ;
350
+ static void
351
+ compress_and_backup_page (pgFile * file , BlockNumber blknum ,
352
+ FILE * in , FILE * out , pg_crc32 * crc ,
353
+ int page_state , Page page )
354
+ {
355
+ BackupPageHeader header ;
356
+ size_t write_buffer_size = sizeof (header );
357
+ char write_buffer [BLCKSZ + sizeof (header )];
358
+ char compressed_page [BLCKSZ ];
353
359
354
- Assert ( header . compressed_size <= BLCKSZ );
355
- }
360
+ if ( page_state == SkipCurrentPage )
361
+ return ;
356
362
357
- write_buffer_size = sizeof (header );
363
+ header .block = blknum ;
364
+ header .compressed_size = page_state ;
358
365
359
- /*
360
- * The page was truncated. Write only header
361
- * to know that we must truncate restored file
362
- */
363
- if (header .compressed_size == PageIsTruncated )
364
- {
365
- memcpy (write_buffer , & header , sizeof (header ));
366
- }
367
- /* The page compression failed. Write it as is. */
368
- else if (header .compressed_size == -1 )
366
+ if (page_state == PageIsTruncated )
369
367
{
370
- header .compressed_size = BLCKSZ ;
368
+ /*
369
+ * The page was truncated. Write only header
370
+ * to know that we must truncate restored file
371
+ */
371
372
memcpy (write_buffer , & header , sizeof (header ));
372
- memcpy (write_buffer + sizeof (header ), page , BLCKSZ );
373
- write_buffer_size += header .compressed_size ;
374
373
}
375
- /* The page was successfully compressed */
376
- else if (header .compressed_size > 0 )
374
+ else
377
375
{
378
- memcpy (write_buffer , & header , sizeof (header ));
379
- memcpy (write_buffer + sizeof (header ), compressed_page , header .compressed_size );
380
- write_buffer_size += MAXALIGN (header .compressed_size );
376
+ /* The page was not truncated, so we need to compress it */
377
+ header .compressed_size = do_compress (compressed_page , BLCKSZ ,
378
+ page , BLCKSZ , compress_alg );
379
+
380
+ file -> compress_alg = compress_alg ;
381
+ file -> read_size += BLCKSZ ;
382
+ Assert (header .compressed_size <= BLCKSZ );
383
+
384
+ /* The page was successfully compressed. */
385
+ if (header .compressed_size > 0 )
386
+ {
387
+ memcpy (write_buffer , & header , sizeof (header ));
388
+ memcpy (write_buffer + sizeof (header ),
389
+ compressed_page , header .compressed_size );
390
+ write_buffer_size += MAXALIGN (header .compressed_size );
391
+ }
392
+ /* Nonpositive value means that compression failed. Write it as is. */
393
+ else
394
+ {
395
+ header .compressed_size = BLCKSZ ;
396
+ memcpy (write_buffer , & header , sizeof (header ));
397
+ memcpy (write_buffer + sizeof (header ), page , BLCKSZ );
398
+ write_buffer_size += header .compressed_size ;
399
+ }
381
400
}
382
401
383
402
/* elog(VERBOSE, "backup blkno %u, compressed_size %d write_buffer_size %ld",
@@ -389,19 +408,14 @@ backup_data_page(backup_files_args *arguments,
389
408
/* write data page */
390
409
if (fwrite (write_buffer , 1 , write_buffer_size , out ) != write_buffer_size )
391
410
{
392
- int errno_tmp = errno ;
411
+ int errno_tmp = errno ;
393
412
fclose (in );
394
413
fclose (out );
395
414
elog (ERROR , "File: %s, cannot write backup at block %u : %s" ,
396
415
file -> path , blknum , strerror (errno_tmp ));
397
416
}
398
417
399
418
file -> write_size += write_buffer_size ;
400
-
401
- if (page != NULL )
402
- free (page );
403
- if (compressed_page != NULL )
404
- free (compressed_page );
405
419
}
406
420
407
421
/*
@@ -418,13 +432,15 @@ backup_data_file(backup_files_args* arguments,
418
432
pgFile * file , XLogRecPtr prev_backup_start_lsn ,
419
433
BackupMode backup_mode )
420
434
{
421
- char to_path [MAXPGPATH ];
422
- FILE * in ;
423
- FILE * out ;
424
- BlockNumber blknum = 0 ;
425
- BlockNumber nblocks = 0 ;
426
- int n_blocks_skipped = 0 ;
427
- int n_blocks_read = 0 ;
435
+ char to_path [MAXPGPATH ];
436
+ FILE * in ;
437
+ FILE * out ;
438
+ BlockNumber blknum = 0 ;
439
+ BlockNumber nblocks = 0 ;
440
+ int n_blocks_skipped = 0 ;
441
+ int n_blocks_read = 0 ;
442
+ int page_state ;
443
+ char curr_page [BLCKSZ ];
428
444
429
445
/*
430
446
* Skip unchanged file only if it exists in previous backup.
@@ -503,9 +519,11 @@ backup_data_file(backup_files_args* arguments,
503
519
{
504
520
for (blknum = 0 ; blknum < nblocks ; blknum ++ )
505
521
{
506
- backup_data_page (arguments , file , prev_backup_start_lsn , blknum ,
507
- nblocks , in , out , & (file -> crc ),
508
- & n_blocks_skipped , backup_mode );
522
+ page_state = prepare_page (arguments , file , prev_backup_start_lsn ,
523
+ blknum , nblocks , in , & n_blocks_skipped ,
524
+ backup_mode , curr_page );
525
+ compress_and_backup_page (file , blknum , in , out , & (file -> crc ),
526
+ page_state , curr_page );
509
527
n_blocks_read ++ ;
510
528
}
511
529
if (backup_mode == BACKUP_MODE_DIFF_DELTA )
@@ -518,9 +536,11 @@ backup_data_file(backup_files_args* arguments,
518
536
iter = datapagemap_iterate (& file -> pagemap );
519
537
while (datapagemap_next (iter , & blknum ))
520
538
{
521
- backup_data_page (arguments , file , prev_backup_start_lsn , blknum ,
522
- nblocks , in , out , & (file -> crc ),
523
- & n_blocks_skipped , backup_mode );
539
+ page_state = prepare_page (arguments , file , prev_backup_start_lsn ,
540
+ blknum , nblocks , in , & n_blocks_skipped ,
541
+ backup_mode , curr_page );
542
+ compress_and_backup_page (file , blknum , in , out , & (file -> crc ),
543
+ page_state , curr_page );
524
544
n_blocks_read ++ ;
525
545
}
526
546
@@ -635,7 +655,8 @@ restore_data_file(const char *from_root,
635
655
}
636
656
637
657
if (header .block < blknum )
638
- elog (ERROR , "backup is broken at file->path %s block %u" ,file -> path , blknum );
658
+ elog (ERROR , "backup is broken at file->path %s block %u" ,
659
+ file -> path , blknum );
639
660
640
661
if (header .compressed_size == PageIsTruncated )
641
662
{
@@ -646,7 +667,8 @@ restore_data_file(const char *from_root,
646
667
if (ftruncate (fileno (out ), header .block * BLCKSZ ) != 0 )
647
668
elog (ERROR , "cannot truncate \"%s\": %s" ,
648
669
file -> path , strerror (errno ));
649
- elog (VERBOSE , "truncate file %s to block %u" , file -> path , header .block );
670
+ elog (VERBOSE , "truncate file %s to block %u" ,
671
+ file -> path , header .block );
650
672
break ;
651
673
}
652
674
@@ -664,10 +686,12 @@ restore_data_file(const char *from_root,
664
686
665
687
uncompressed_size = do_decompress (page .data , BLCKSZ ,
666
688
compressed_page .data ,
667
- header .compressed_size , file -> compress_alg );
689
+ header .compressed_size ,
690
+ file -> compress_alg );
668
691
669
692
if (uncompressed_size != BLCKSZ )
670
- elog (ERROR , "page uncompressed to %ld bytes. != BLCKSZ" , uncompressed_size );
693
+ elog (ERROR , "page uncompressed to %ld bytes. != BLCKSZ" ,
694
+ uncompressed_size );
671
695
}
672
696
673
697
/*
@@ -714,7 +738,8 @@ restore_data_file(const char *from_root,
714
738
if (ftruncate (fileno (out ), file -> n_blocks * BLCKSZ ) != 0 )
715
739
elog (ERROR , "cannot truncate \"%s\": %s" ,
716
740
file -> path , strerror (errno ));
717
- elog (INFO , "Delta truncate file %s to block %u" , file -> path , file -> n_blocks );
741
+ elog (INFO , "Delta truncate file %s to block %u" ,
742
+ file -> path , file -> n_blocks );
718
743
}
719
744
}
720
745
0 commit comments