@@ -49,7 +49,6 @@ The parts not included are excluded by #ifndef UNIV_INNOCHECKSUM. */
4949#include " page0zip.h" /* page_zip_*() */
5050#include " trx0undo.h" /* TRX_* */
5151#include " fil0crypt.h" /* fil_space_verify_crypt_checksum */
52-
5352#include < string.h>
5453
5554#ifdef UNIV_NONINL
@@ -78,6 +77,8 @@ static ulint extent_size;
7877static ulint xdes_size;
7978ulong srv_page_size;
8079uint32_t srv_page_size_shift;
80+ static uint32_t dblwr_1;
81+ static uint32_t dblwr_2;
8182/* Current page number (0 based). */
8283uint32_t cur_page_num;
8384/* Current space. */
@@ -101,8 +102,10 @@ FILE* log_file = NULL;
101102/* Enabled for log write option. */
102103static bool is_log_enabled = false ;
103104static bool skip_freed_pages;
105+ static uint32_t tablespace_flags= 0 ;
104106static byte field_ref_zero_buf[UNIV_PAGE_SIZE_MAX];
105107const byte *field_ref_zero = field_ref_zero_buf;
108+ constexpr uint32_t USE_FSP_FLAGS{UINT32_MAX};
106109
107110#ifndef _WIN32
108111/* advisory lock for non-window system. */
@@ -257,12 +260,9 @@ void print_leaf_stats(
257260}
258261
259262/* * Init the page size for the tablespace.
260- @param[in] buf buffer used to read the page */
261- static void init_page_size (const byte* buf )
263+ @param[in] flags InnoDB tablespace flags */
264+ static void init_page_size_from_flags (const uint32_t flags )
262265{
263- const unsigned flags = mach_read_from_4 (buf + FIL_PAGE_DATA
264- + FSP_SPACE_FLAGS);
265-
266266 if (fil_space_t::full_crc32 (flags)) {
267267 const uint32_t ssize = FSP_FLAGS_FCRC32_GET_PAGE_SSIZE (flags);
268268 srv_page_size_shift = UNIV_ZIP_SIZE_SHIFT_MIN - 1 + ssize;
@@ -544,24 +544,15 @@ static bool is_page_corrupted(byte *buf, bool is_encrypted, uint32_t flags)
544544 return (is_corrupted);
545545}
546546
547- /* *******************************************/ /*
548- Check if page is doublewrite buffer or not.
549- @param [in] page buffer page
550-
551- @retval true if page is doublewrite buffer otherwise false.
552- */
553- static
554- bool
555- is_page_doublewritebuffer (
556- const byte* page)
547+ /* * Check if page is doublewrite buffer or not.
548+ @retval true if page is doublewrite buffer otherwise false. */
549+ static bool is_page_doublewritebuffer ()
557550{
558- if ((cur_page_num >= extent_size)
559- && (cur_page_num < extent_size * 3 )) {
560- /* page is doublewrite buffer. */
561- return (true );
562- }
563-
564- return (false );
551+ if (cur_space != 0 ) return false ;
552+ const uint32_t extent{static_cast <uint32_t >(
553+ cur_page_num & ~(extent_size - 1 ))};
554+ return cur_page_num > FSP_DICT_HDR_PAGE_NO &&
555+ extent && (extent == dblwr_1 || extent == dblwr_2);
565556}
566557
567558/* ******************************************************/ /*
@@ -768,7 +759,7 @@ Parse the page and collect/dump the information about page type
768759@param [in] file file for diagnosis.
769760@param [in] is_encrypted tablespace is encrypted
770761*/
771- void
762+ static void
772763parse_page (
773764 const byte* page,
774765 byte* xdes,
@@ -788,6 +779,12 @@ parse_page(
788779 str = skip_page ? " Double_write_buffer" : " -" ;
789780 page_no = mach_read_from_4 (page + FIL_PAGE_OFFSET);
790781 if (skip_freed_pages) {
782+
783+ /* * Skip doublewrite pages when -r is enabled */
784+ if (is_page_doublewritebuffer ()) {
785+ return ;
786+ }
787+
791788 const byte *des= xdes + XDES_ARR_OFFSET +
792789 xdes_size * ((page_no & (physical_page_size - 1 ))
793790 / extent_size);
@@ -982,6 +979,18 @@ parse_page(
982979 fprintf (file, " #::" UINT32PF " \t\t |\t\t Transaction system "
983980 " page\t\t |\t %s\n " , cur_page_num, str);
984981 }
982+
983+ if (cur_space == 0 &&
984+ (mach_read_from_4 (page + TRX_SYS_DOUBLEWRITE +
985+ TRX_SYS_DOUBLEWRITE_MAGIC) ==
986+ TRX_SYS_DOUBLEWRITE_MAGIC_N)) {
987+ dblwr_1 = mach_read_from_4 (
988+ page + TRX_SYS_DOUBLEWRITE +
989+ TRX_SYS_DOUBLEWRITE_BLOCK1);
990+ dblwr_2 = mach_read_from_4 (
991+ page + TRX_SYS_DOUBLEWRITE +
992+ TRX_SYS_DOUBLEWRITE_BLOCK2);
993+ }
985994 break ;
986995
987996 case FIL_PAGE_TYPE_FSP_HDR:
@@ -1224,6 +1233,9 @@ static struct my_option innochecksum_options[] = {
12241233 {" skip-freed-pages" , ' r' , " skip freed pages for the tablespace" ,
12251234 &skip_freed_pages, &skip_freed_pages, 0 , GET_BOOL, NO_ARG,
12261235 0 , 0 , 0 , 0 , 0 , 0 },
1236+ {" tablespace-flags" , 0 , " InnoDB tablespace flags (default: 4294967295 "
1237+ " = read from page 0)" , &tablespace_flags, &tablespace_flags, 0 ,
1238+ GET_UINT, REQUIRED_ARG, USE_FSP_FLAGS, 0 , USE_FSP_FLAGS, 0 , 0 , 0 },
12271239
12281240 {0 , 0 , 0 , 0 , 0 , 0 , GET_NO_ARG, NO_ARG, 0 , 0 , 0 , 0 , 0 , 0 }
12291241};
@@ -1298,6 +1310,14 @@ innochecksum_get_one_option(
12981310 my_end (0 );
12991311 exit (EXIT_SUCCESS);
13001312 break ;
1313+ default :
1314+ if (tablespace_flags != USE_FSP_FLAGS &&
1315+ !fil_space_t::is_valid_flags (tablespace_flags, false ) &&
1316+ !fil_space_t::is_valid_flags (tablespace_flags, true )) {
1317+ fprintf (stderr, " Error: Provided --tablespace-flags "
1318+ " is not valid." );
1319+ return true ;
1320+ }
13011321 }
13021322
13031323 return (false );
@@ -1428,6 +1448,87 @@ rewrite_checksum(
14281448 && !write_file (filename, fil_in, buf, flags, pos);
14291449}
14301450
1451+ /* * Read and validate page 0, then initialize tablespace flags
1452+ and page size.
1453+ @param fil_in File pointer
1454+ @param buf Buffer to read page into
1455+ @return whether the page was read successfully */
1456+ static bool read_and_validate_page0 (FILE *fil_in, byte *buf)
1457+ {
1458+ /* Read the minimum page size first */
1459+ size_t initial_page_size= UNIV_ZIP_SIZE_MIN;
1460+ if (tablespace_flags != USE_FSP_FLAGS)
1461+ {
1462+ init_page_size_from_flags (tablespace_flags);
1463+ initial_page_size= physical_page_size;
1464+ }
1465+
1466+ /* Read just enough to get the tablespace flags */
1467+ size_t bytes= fread (buf, 1 , initial_page_size, fil_in);
1468+
1469+ if (bytes != initial_page_size)
1470+ {
1471+ fprintf (stderr, " Error: Was not able to read the "
1472+ " minimum page size of %zu bytes. Bytes read "
1473+ " was %zu\n " , initial_page_size, bytes);
1474+ return false ;
1475+ }
1476+
1477+ /* Read space_id and page offset */
1478+ cur_space= mach_read_from_4 (buf + FIL_PAGE_SPACE_ID);
1479+ cur_page_num= mach_read_from_4 (buf + FIL_PAGE_OFFSET);
1480+
1481+ /* Get tablespace flags from the FSP header */
1482+ uint32_t flags= mach_read_from_4 (buf + FSP_HEADER_OFFSET +
1483+ FSP_SPACE_FLAGS);
1484+
1485+ if (tablespace_flags != USE_FSP_FLAGS)
1486+ {
1487+ if (cur_page_num == 0 && flags != tablespace_flags)
1488+ fprintf (stderr, " Error: Mismatch between provided tablespace "
1489+ " flags (0x%x) and file flags (0x%x)\n " ,
1490+ tablespace_flags, flags);
1491+ }
1492+ else
1493+ {
1494+ if (cur_page_num)
1495+ {
1496+ fprintf (stderr, " Error: First page of the tablespace file "
1497+ " should be 0, but encountered page number %" PRIu32 " . "
1498+ " If you are checking multi file system "
1499+ " tablespace files, please specify the correct "
1500+ " tablespace flags using --tablespace-flags option.\n " ,
1501+ cur_page_num);
1502+ return false ;
1503+ }
1504+ /* Initialize page size parameters based on flags */
1505+ init_page_size_from_flags (flags);
1506+ /* Read the rest of the page if it's larger than the minimum size */
1507+ if (physical_page_size > UNIV_ZIP_SIZE_MIN)
1508+ {
1509+ /* Read rest of the page 0 to determine crypt_data */
1510+ ulint bytes= read_file (buf, true , physical_page_size, fil_in);
1511+ if (bytes != physical_page_size)
1512+ {
1513+ fprintf (stderr, " Error: Was not able to read the rest of the "
1514+ " page of " ULINTPF " bytes. Bytes read was " ULINTPF " \n " ,
1515+ physical_page_size - UNIV_ZIP_SIZE_MIN, bytes);
1516+ return false ;
1517+ }
1518+ }
1519+ tablespace_flags= flags;
1520+ }
1521+
1522+ if (physical_page_size < UNIV_ZIP_SIZE_MIN ||
1523+ physical_page_size > UNIV_PAGE_SIZE_MAX)
1524+ {
1525+ fprintf (stderr, " Error: Invalid page size " ULINTPF
1526+ " encountered\n " , physical_page_size);
1527+ return false ;
1528+ }
1529+ return true ;
1530+ }
1531+
14311532int main (
14321533 int argc,
14331534 char **argv)
@@ -1563,51 +1664,13 @@ int main(
15631664 }
15641665 }
15651666
1566- /* Read the minimum page size. */
1567- bytes = fread (buf, 1 , UNIV_ZIP_SIZE_MIN, fil_in);
1568- partial_page_read = true ;
1569-
1570- if (bytes != UNIV_ZIP_SIZE_MIN) {
1571- fprintf (stderr, " Error: Was not able to read the "
1572- " minimum page size " );
1573- fprintf (stderr, " of %d bytes. Bytes read was " ULINTPF " \n " ,
1574- UNIV_ZIP_SIZE_MIN, bytes);
1575-
1667+ /* Read and validate page 0 */
1668+ if (!read_and_validate_page0 (fil_in, buf)) {
15761669 exit_status = 1 ;
15771670 goto my_exit;
15781671 }
15791672
1580- /* enable variable is_system_tablespace when space_id of given
1581- file is zero. Use to skip the checksum verification and rewrite
1582- for doublewrite pages. */
1583- cur_space = mach_read_from_4 (buf + FIL_PAGE_SPACE_ID);
1584- cur_page_num = mach_read_from_4 (buf + FIL_PAGE_OFFSET);
1585-
1586- /* Determine page size, zip_size and page compression
1587- from fsp_flags and encryption metadata from page 0 */
1588- init_page_size (buf);
1589-
1590- uint32_t flags = mach_read_from_4 (FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + buf);
1591-
1592- if (physical_page_size == UNIV_ZIP_SIZE_MIN) {
1593- partial_page_read = false ;
1594- } else {
1595- /* Read rest of the page 0 to determine crypt_data */
1596- bytes = read_file (buf, partial_page_read, physical_page_size, fil_in);
1597- if (bytes != physical_page_size) {
1598- fprintf (stderr, " Error: Was not able to read the "
1599- " rest of the page " );
1600- fprintf (stderr, " of " ULINTPF " bytes. Bytes read was " ULINTPF " \n " ,
1601- physical_page_size - UNIV_ZIP_SIZE_MIN, bytes);
1602-
1603- exit_status = 1 ;
1604- goto my_exit;
1605- }
1606- partial_page_read = false ;
1607- }
1608-
1609-
1610- /* Now that we have full page 0 in buffer, check encryption */
1673+ /* Check if tablespace is encrypted */
16111674 bool is_encrypted = check_encryption (filename, buf);
16121675
16131676 /* Verify page 0 contents. Note that we can't allow
@@ -1618,7 +1681,8 @@ int main(
16181681 allow_mismatches = 0 ;
16191682
16201683 exit_status = verify_checksum (buf, is_encrypted,
1621- &mismatch_count, flags);
1684+ &mismatch_count,
1685+ tablespace_flags);
16221686
16231687 if (exit_status) {
16241688 fprintf (stderr, " Error: Page 0 checksum mismatch, can't continue. \n " );
@@ -1629,7 +1693,8 @@ int main(
16291693
16301694 if ((exit_status = rewrite_checksum (
16311695 filename, fil_in, buf,
1632- &pos, is_encrypted, flags))) {
1696+ &pos, is_encrypted,
1697+ tablespace_flags))) {
16331698 goto my_exit;
16341699 }
16351700
@@ -1825,7 +1890,7 @@ int main(
18251890first_non_zero:
18261891 if (is_system_tablespace) {
18271892 /* enable when page is double write buffer.*/
1828- skip_page = is_page_doublewritebuffer (buf );
1893+ skip_page = is_page_doublewritebuffer ();
18291894 } else {
18301895 skip_page = false ;
18311896 }
@@ -1846,13 +1911,16 @@ int main(
18461911 && !is_page_free (xdes, physical_page_size, cur_page_num)
18471912 && (exit_status = verify_checksum (
18481913 buf, is_encrypted,
1849- &mismatch_count, flags))) {
1914+ &mismatch_count,
1915+ tablespace_flags))) {
18501916 goto my_exit;
18511917 }
18521918
1853- if ((exit_status = rewrite_checksum (
1854- filename, fil_in, buf,
1855- &pos, is_encrypted, flags))) {
1919+ if (!is_page_doublewritebuffer () &&
1920+ (exit_status = rewrite_checksum (
1921+ filename, fil_in, buf,
1922+ &pos, is_encrypted,
1923+ tablespace_flags))) {
18561924 goto my_exit;
18571925 }
18581926
0 commit comments