Skip to content

Commit 05e3211

Browse files
committed
Provide backward compatibility for decompression bug
1 parent 45940cb commit 05e3211

File tree

2 files changed

+61
-4
lines changed

2 files changed

+61
-4
lines changed

src/data.c

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,55 @@ do_decompress(void* dst, size_t dst_size, void const* src, size_t src_size,
9999
return -1;
100100
}
101101

102+
103+
#define ZLIB_MAGIC 0x78
104+
105+
/*
106+
* Before version 2.0.23 there was a bug in pro_backup that pages which compressed
107+
* size is exactly the same as original size are not treated as compressed.
108+
* This check tries to detect and decompress such pages.
109+
* There is no 100% criteria to determine whether page is compressed or not.
110+
* But at least we will do this check only for pages which will no pass validation step.
111+
*/
112+
static bool
113+
page_may_be_compressed(Page page, CompressAlg alg)
114+
{
115+
PageHeader phdr;
116+
117+
phdr = (PageHeader) page;
118+
119+
/* First check if page header is valid (it seems to be fast enough check) */
120+
if (!(PageGetPageSize(phdr) == BLCKSZ &&
121+
PageGetPageLayoutVersion(phdr) == PG_PAGE_LAYOUT_VERSION &&
122+
(phdr->pd_flags & ~PD_VALID_FLAG_BITS) == 0 &&
123+
phdr->pd_lower >= SizeOfPageHeaderData &&
124+
phdr->pd_lower <= phdr->pd_upper &&
125+
phdr->pd_upper <= phdr->pd_special &&
126+
phdr->pd_special <= BLCKSZ &&
127+
phdr->pd_special == MAXALIGN(phdr->pd_special)))
128+
{
129+
/* ... end only if it is invalid, then do more checks */
130+
int major, middle, minor;
131+
if ( parse_program_version(current.program_version) >= 20023)
132+
{
133+
/* Versions 2.0.23 and higher don't have such bug */
134+
return false;
135+
}
136+
#ifdef HAVE_LIBZ
137+
/* For zlib we can check page magic:
138+
* https://stackoverflow.com/questions/9050260/what-does-a-zlib-header-look-like
139+
*/
140+
if (alg == ZLIB_COMPRESS && *(char*)page != ZLIB_MAGIC)
141+
{
142+
return false;
143+
}
144+
#endif
145+
/* otherwize let's try to decompress the page */
146+
return true;
147+
}
148+
return false;
149+
}
150+
102151
/*
103152
* When copying datafiles to backup we validate and compress them block
104153
* by block. Thus special header is required for each data block.
@@ -717,7 +766,8 @@ restore_data_file(const char *to_path, pgFile *file, bool allow_truncate,
717766
elog(ERROR, "cannot read block %u of \"%s\" read %lu of %d",
718767
blknum, file->path, read_len, header.compressed_size);
719768

720-
if (header.compressed_size != BLCKSZ)
769+
if (header.compressed_size != BLCKSZ
770+
|| page_may_be_compressed(compressed_page.data, file->compress_alg))
721771
{
722772
int32 uncompressed_size = 0;
723773

@@ -1595,7 +1645,8 @@ check_file_pages(pgFile *file, XLogRecPtr stop_lsn, uint32 checksum_version)
15951645
elog(ERROR, "cannot read block %u of \"%s\" read %lu of %d",
15961646
blknum, file->path, read_len, header.compressed_size);
15971647

1598-
if (header.compressed_size != BLCKSZ)
1648+
if (header.compressed_size != BLCKSZ
1649+
|| page_may_be_compressed(compressed_page.data, file->compress_alg))
15991650
{
16001651
int32 uncompressed_size = 0;
16011652

@@ -1605,9 +1656,15 @@ check_file_pages(pgFile *file, XLogRecPtr stop_lsn, uint32 checksum_version)
16051656
file->compress_alg);
16061657

16071658
if (uncompressed_size != BLCKSZ)
1659+
{
1660+
if (header.compressed_size == BLCKSZ)
1661+
{
1662+
is_valid = false;
1663+
continue;
1664+
}
16081665
elog(ERROR, "page of file \"%s\" uncompressed to %d bytes. != BLCKSZ",
16091666
file->path, uncompressed_size);
1610-
1667+
}
16111668
if (validate_one_page(page.data, file, blknum,
16121669
stop_lsn, checksum_version) == PAGE_IS_FOUND_AND_NOT_VALID)
16131670
is_valid = false;

src/pg_probackup.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
#include "utils/thread.h"
1919

20-
const char *PROGRAM_VERSION = "2.0.22";
20+
const char *PROGRAM_VERSION = "2.0.23";
2121
const char *PROGRAM_URL = "https://github.com/postgrespro/pg_probackup";
2222
const char *PROGRAM_EMAIL = "https://github.com/postgrespro/pg_probackup/issues";
2323

0 commit comments

Comments
 (0)