Skip to content

Commit d280fef

Browse files
committed
Merge branch 'pgpro_1539'
2 parents 3dec5b3 + c8971f5 commit d280fef

File tree

3 files changed

+226
-1
lines changed

3 files changed

+226
-1
lines changed

src/data.c

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,3 +1405,215 @@ calc_file_checksum(pgFile *file)
14051405

14061406
return true;
14071407
}
1408+
1409+
/* Validate given page
1410+
* return value:
1411+
* 0 - if the page is not found
1412+
* 1 - if the page is found and valid
1413+
* -1 - if the page is found but invalid
1414+
*/
1415+
#define PAGE_IS_NOT_FOUND 0
1416+
#define PAGE_IS_FOUND_AND_VALID 1
1417+
#define PAGE_IS_FOUND_AND__NOT_VALID -1
1418+
static int
1419+
validate_one_page(Page page, pgFile *file,
1420+
BlockNumber blknum, XLogRecPtr stop_lsn,
1421+
uint32 checksum_version)
1422+
{
1423+
PageHeader phdr;
1424+
XLogRecPtr lsn;
1425+
bool page_header_is_sane = false;
1426+
bool checksum_is_ok = false;
1427+
1428+
/* new level of paranoia */
1429+
if (page == NULL)
1430+
{
1431+
elog(LOG, "File %s, block %u, page is NULL",
1432+
file->path, blknum);
1433+
return PAGE_IS_NOT_FOUND;
1434+
}
1435+
1436+
if (PageIsNew(page))
1437+
{
1438+
int i;
1439+
/* Check if the page is zeroed. */
1440+
for(i = 0; i < BLCKSZ && page[i] == 0; i++);
1441+
1442+
if (i == BLCKSZ)
1443+
{
1444+
elog(LOG, "File: %s blknum %u, page is New. empty zeroed page",
1445+
file->path, blknum);
1446+
return PAGE_IS_FOUND_AND_VALID;
1447+
}
1448+
else
1449+
{
1450+
elog(WARNING, "File: %s, block %u, page is New, but not zeroed",
1451+
file->path, blknum);
1452+
}
1453+
1454+
/* Page is zeroed. No sense to check header and checksum. */
1455+
page_header_is_sane = false;
1456+
}
1457+
else
1458+
{
1459+
phdr = (PageHeader) page;
1460+
1461+
if (PageGetPageSize(phdr) == BLCKSZ &&
1462+
PageGetPageLayoutVersion(phdr) == PG_PAGE_LAYOUT_VERSION &&
1463+
(phdr->pd_flags & ~PD_VALID_FLAG_BITS) == 0 &&
1464+
phdr->pd_lower >= SizeOfPageHeaderData &&
1465+
phdr->pd_lower <= phdr->pd_upper &&
1466+
phdr->pd_upper <= phdr->pd_special &&
1467+
phdr->pd_special <= BLCKSZ &&
1468+
phdr->pd_special == MAXALIGN(phdr->pd_special))
1469+
page_header_is_sane = true;
1470+
}
1471+
1472+
if (page_header_is_sane)
1473+
{
1474+
/* Verify checksum */
1475+
if(checksum_version)
1476+
{
1477+
/*
1478+
* If checksum is wrong, sleep a bit and then try again
1479+
* several times. If it didn't help, throw error
1480+
*/
1481+
if (pg_checksum_page(page, file->segno * RELSEG_SIZE + blknum)
1482+
== ((PageHeader) page)->pd_checksum)
1483+
{
1484+
checksum_is_ok = true;
1485+
}
1486+
else
1487+
{
1488+
elog(WARNING, "File: %s blknum %u have wrong checksum",
1489+
file->path, blknum);
1490+
}
1491+
}
1492+
1493+
if (!checksum_version)
1494+
{
1495+
/* Get lsn from page header. Ensure that page is from our time */
1496+
lsn = PageXLogRecPtrGet(phdr->pd_lsn);
1497+
1498+
if (lsn > stop_lsn)
1499+
elog(WARNING, "File: %s, block %u, checksum is not enabled."
1500+
"page is from future: pageLSN %X/%X stopLSN %X/%X",
1501+
file->path, blknum, (uint32) (lsn >> 32), (uint32) lsn,
1502+
(uint32) (stop_lsn >> 32), (uint32) stop_lsn);
1503+
else
1504+
return PAGE_IS_FOUND_AND_VALID;
1505+
}
1506+
1507+
if (checksum_is_ok)
1508+
{
1509+
/* Get lsn from page header. Ensure that page is from our time */
1510+
lsn = PageXLogRecPtrGet(phdr->pd_lsn);
1511+
1512+
if (lsn > stop_lsn)
1513+
elog(WARNING, "File: %s, block %u, checksum is correct."
1514+
"page is from future: pageLSN %X/%X stopLSN %X/%X",
1515+
file->path, blknum, (uint32) (lsn >> 32), (uint32) lsn,
1516+
(uint32) (stop_lsn >> 32), (uint32) stop_lsn);
1517+
else
1518+
return PAGE_IS_FOUND_AND_VALID;
1519+
}
1520+
}
1521+
1522+
return PAGE_IS_FOUND_AND__NOT_VALID;
1523+
}
1524+
1525+
/* Valiate pages of datafile in backup one by one */
1526+
bool
1527+
check_file_pages(pgFile *file, XLogRecPtr stop_lsn, uint32 checksum_version)
1528+
{
1529+
size_t read_len = 0;
1530+
bool is_valid = true;
1531+
FILE *in;
1532+
1533+
elog(VERBOSE, "validate relation blocks for file %s", file->name);
1534+
1535+
in = fopen(file->path, PG_BINARY_R);
1536+
if (in == NULL)
1537+
{
1538+
if (errno == ENOENT)
1539+
{
1540+
elog(WARNING, "File \"%s\" is not found", file->path);
1541+
return false;
1542+
}
1543+
1544+
elog(ERROR, "cannot open file \"%s\": %s",
1545+
file->path, strerror(errno));
1546+
}
1547+
1548+
/* read and validate pages one by one */
1549+
while (true)
1550+
{
1551+
Page compressed_page = NULL; /* used as read buffer */
1552+
Page page = NULL;
1553+
BackupPageHeader header;
1554+
BlockNumber blknum;
1555+
1556+
/* read BackupPageHeader */
1557+
read_len = fread(&header, 1, sizeof(header), in);
1558+
if (read_len != sizeof(header))
1559+
{
1560+
int errno_tmp = errno;
1561+
if (read_len == 0 && feof(in))
1562+
break; /* EOF found */
1563+
else if (read_len != 0 && feof(in))
1564+
elog(ERROR,
1565+
"odd size page found at block %u of \"%s\"",
1566+
blknum, file->path);
1567+
else
1568+
elog(ERROR, "cannot read header of block %u of \"%s\": %s",
1569+
blknum, file->path, strerror(errno_tmp));
1570+
}
1571+
1572+
if (header.block < blknum)
1573+
elog(ERROR, "backup is broken at file->path %s block %u",
1574+
file->path, blknum);
1575+
1576+
blknum = header.block;
1577+
1578+
if (header.compressed_size == PageIsTruncated)
1579+
{
1580+
elog(LOG, "File %s, block %u is truncated",
1581+
file->path, blknum);
1582+
continue;
1583+
}
1584+
1585+
Assert(header.compressed_size <= BLCKSZ);
1586+
1587+
read_len = fread(compressed_page, 1,
1588+
MAXALIGN(header.compressed_size), in);
1589+
if (read_len != MAXALIGN(header.compressed_size))
1590+
elog(ERROR, "cannot read block %u of \"%s\" read %lu of %d",
1591+
blknum, file->path, read_len, header.compressed_size);
1592+
1593+
if (header.compressed_size != BLCKSZ)
1594+
{
1595+
int32 uncompressed_size = 0;
1596+
1597+
uncompressed_size = do_decompress(page, BLCKSZ,
1598+
compressed_page,
1599+
MAXALIGN(header.compressed_size),
1600+
file->compress_alg);
1601+
1602+
if (uncompressed_size != BLCKSZ)
1603+
elog(ERROR, "page of file \"%s\" uncompressed to %d bytes. != BLCKSZ",
1604+
file->path, uncompressed_size);
1605+
1606+
if (validate_one_page(page, file, blknum,
1607+
stop_lsn, checksum_version) == PAGE_IS_FOUND_AND__NOT_VALID)
1608+
is_valid = false;
1609+
}
1610+
else
1611+
{
1612+
if (validate_one_page(compressed_page, file, blknum,
1613+
stop_lsn, checksum_version) == PAGE_IS_FOUND_AND__NOT_VALID)
1614+
is_valid = false;
1615+
}
1616+
}
1617+
1618+
return is_valid;
1619+
}

src/pg_probackup.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,9 @@ extern void get_wal_file(const char *from_path, const char *to_path);
564564

565565
extern bool calc_file_checksum(pgFile *file);
566566

567+
extern bool check_file_pages(pgFile* file,
568+
XLogRecPtr stop_lsn, uint32 checksum_version);
569+
567570
/* parsexlog.c */
568571
extern void extractPageMap(const char *archivedir,
569572
TimeLineID tli, uint32 seg_size,

src/validate.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ typedef struct
2424
{
2525
parray *files;
2626
bool corrupted;
27+
XLogRecPtr stop_lsn;
28+
uint32 checksum_version;
2729

2830
/*
2931
* Return value from the thread.
@@ -100,6 +102,8 @@ pgBackupValidate(pgBackup *backup)
100102

101103
arg->files = files;
102104
arg->corrupted = false;
105+
arg->stop_lsn = backup->stop_lsn;
106+
arg->checksum_version = backup->checksum_version;
103107
/* By default there are some error */
104108
threads_args[i].ret = 1;
105109

@@ -207,7 +211,13 @@ pgBackupValidateFiles(void *arg)
207211
elog(WARNING, "Invalid CRC of backup file \"%s\" : %X. Expected %X",
208212
file->path, file->crc, crc);
209213
arguments->corrupted = true;
210-
break;
214+
215+
/* validate relation blocks */
216+
if (file->is_datafile)
217+
{
218+
if (!check_file_pages(file, arguments->stop_lsn, arguments->checksum_version))
219+
arguments->corrupted = true;
220+
}
211221
}
212222
}
213223

0 commit comments

Comments
 (0)