@@ -51,7 +51,6 @@ The parts not included are excluded by #ifndef UNIV_INNOCHECKSUM. */
5151#include " page0zip.h" /* page_zip_*() */
5252#include " trx0undo.h" /* TRX_* */
5353#include " fil0crypt.h" /* fil_space_verify_crypt_checksum */
54-
5554#include < string.h>
5655
5756#ifndef PRIuMAX
@@ -74,6 +73,8 @@ static ulint extent_size;
7473static ulint xdes_size;
7574ulong srv_page_size;
7675uint32_t srv_page_size_shift;
76+ static uint32_t dblwr_1;
77+ static uint32_t dblwr_2;
7778/* Current page number (0 based). */
7879uint32_t cur_page_num;
7980/* Current space. */
@@ -97,8 +98,10 @@ FILE* log_file = NULL;
9798/* Enabled for log write option. */
9899static bool is_log_enabled = false ;
99100static bool skip_freed_pages;
101+ static uint32_t tablespace_flags= 0 ;
100102static byte field_ref_zero_buf[UNIV_PAGE_SIZE_MAX];
101103const byte *field_ref_zero = field_ref_zero_buf;
104+ constexpr uint32_t USE_FSP_FLAGS{UINT32_MAX};
102105
103106#ifndef _WIN32
104107/* advisory lock for non-window system. */
@@ -253,12 +256,9 @@ void print_leaf_stats(
253256}
254257
255258/* * Init the page size for the tablespace.
256- @param[in] buf buffer used to read the page */
257- static void init_page_size (const byte* buf )
259+ @param[in] flags InnoDB tablespace flags */
260+ static void init_page_size_from_flags (const uint32_t flags )
258261{
259- const unsigned flags = mach_read_from_4 (buf + FIL_PAGE_DATA
260- + FSP_SPACE_FLAGS);
261-
262262 if (fil_space_t::full_crc32 (flags)) {
263263 const uint32_t ssize = FSP_FLAGS_FCRC32_GET_PAGE_SSIZE (flags);
264264 srv_page_size_shift = UNIV_ZIP_SIZE_SHIFT_MIN - 1 + ssize;
@@ -540,24 +540,15 @@ static bool is_page_corrupted(byte *buf, bool is_encrypted, uint32_t flags)
540540 return (is_corrupted);
541541}
542542
543- /* *******************************************/ /*
544- Check if page is doublewrite buffer or not.
545- @param [in] page buffer page
546-
547- @retval true if page is doublewrite buffer otherwise false.
548- */
549- static
550- bool
551- is_page_doublewritebuffer (
552- const byte* page)
543+ /* * Check if page is doublewrite buffer or not.
544+ @retval true if page is doublewrite buffer otherwise false. */
545+ static bool is_page_doublewritebuffer ()
553546{
554- if ((cur_page_num >= extent_size)
555- && (cur_page_num < extent_size * 3 )) {
556- /* page is doublewrite buffer. */
557- return (true );
558- }
559-
560- return (false );
547+ if (cur_space != 0 ) return false ;
548+ const uint32_t extent{static_cast <uint32_t >(
549+ cur_page_num & ~(extent_size - 1 ))};
550+ return cur_page_num > FSP_DICT_HDR_PAGE_NO &&
551+ extent && (extent == dblwr_1 || extent == dblwr_2);
561552}
562553
563554/* ******************************************************/ /*
@@ -764,7 +755,7 @@ Parse the page and collect/dump the information about page type
764755@param [in] file file for diagnosis.
765756@param [in] is_encrypted tablespace is encrypted
766757*/
767- void
758+ static void
768759parse_page (
769760 const byte* page,
770761 byte* xdes,
@@ -784,6 +775,12 @@ parse_page(
784775 str = skip_page ? " Double_write_buffer" : " -" ;
785776 page_no = mach_read_from_4 (page + FIL_PAGE_OFFSET);
786777 if (skip_freed_pages) {
778+
779+ /* * Skip doublewrite pages when -r is enabled */
780+ if (is_page_doublewritebuffer ()) {
781+ return ;
782+ }
783+
787784 const byte *des= xdes + XDES_ARR_OFFSET +
788785 xdes_size * ((page_no & (physical_page_size - 1 ))
789786 / extent_size);
@@ -978,6 +975,18 @@ parse_page(
978975 fprintf (file, " #::" UINT32PF " \t\t |\t\t Transaction system "
979976 " page\t\t |\t %s\n " , cur_page_num, str);
980977 }
978+
979+ if (cur_space == 0 &&
980+ (mach_read_from_4 (page + TRX_SYS_DOUBLEWRITE +
981+ TRX_SYS_DOUBLEWRITE_MAGIC) ==
982+ TRX_SYS_DOUBLEWRITE_MAGIC_N)) {
983+ dblwr_1 = mach_read_from_4 (
984+ page + TRX_SYS_DOUBLEWRITE +
985+ TRX_SYS_DOUBLEWRITE_BLOCK1);
986+ dblwr_2 = mach_read_from_4 (
987+ page + TRX_SYS_DOUBLEWRITE +
988+ TRX_SYS_DOUBLEWRITE_BLOCK2);
989+ }
981990 break ;
982991
983992 case FIL_PAGE_TYPE_FSP_HDR:
@@ -1220,6 +1229,9 @@ static struct my_option innochecksum_options[] = {
12201229 {" skip-freed-pages" , ' r' , " skip freed pages for the tablespace" ,
12211230 &skip_freed_pages, &skip_freed_pages, 0 , GET_BOOL, NO_ARG,
12221231 0 , 0 , 0 , 0 , 0 , 0 },
1232+ {" tablespace-flags" , 0 , " InnoDB tablespace flags (default: 4294967295 "
1233+ " = read from page 0)" , &tablespace_flags, &tablespace_flags, 0 ,
1234+ GET_UINT, REQUIRED_ARG, USE_FSP_FLAGS, 0 , USE_FSP_FLAGS, 0 , 0 , 0 },
12231235
12241236 {0 , 0 , 0 , 0 , 0 , 0 , GET_NO_ARG, NO_ARG, 0 , 0 , 0 , 0 , 0 , 0 }
12251237};
@@ -1280,6 +1292,14 @@ innochecksum_get_one_option(
12801292 my_end (0 );
12811293 exit (EXIT_SUCCESS);
12821294 break ;
1295+ default :
1296+ if (tablespace_flags != USE_FSP_FLAGS &&
1297+ !fil_space_t::is_valid_flags (tablespace_flags, false ) &&
1298+ !fil_space_t::is_valid_flags (tablespace_flags, true )) {
1299+ fprintf (stderr, " Error: Provided --tablespace-flags "
1300+ " is not valid." );
1301+ return true ;
1302+ }
12831303 }
12841304
12851305 return (false );
@@ -1410,6 +1430,87 @@ rewrite_checksum(
14101430 && !write_file (filename, fil_in, buf, flags, pos);
14111431}
14121432
1433+ /* * Read and validate page 0, then initialize tablespace flags
1434+ and page size.
1435+ @param fil_in File pointer
1436+ @param buf Buffer to read page into
1437+ @return whether the page was read successfully */
1438+ static bool read_and_validate_page0 (FILE *fil_in, byte *buf)
1439+ {
1440+ /* Read the minimum page size first */
1441+ size_t initial_page_size= UNIV_ZIP_SIZE_MIN;
1442+ if (tablespace_flags != USE_FSP_FLAGS)
1443+ {
1444+ init_page_size_from_flags (tablespace_flags);
1445+ initial_page_size= physical_page_size;
1446+ }
1447+
1448+ /* Read just enough to get the tablespace flags */
1449+ size_t bytes= fread (buf, 1 , initial_page_size, fil_in);
1450+
1451+ if (bytes != initial_page_size)
1452+ {
1453+ fprintf (stderr, " Error: Was not able to read the "
1454+ " minimum page size of %zu bytes. Bytes read "
1455+ " was %zu\n " , initial_page_size, bytes);
1456+ return false ;
1457+ }
1458+
1459+ /* Read space_id and page offset */
1460+ cur_space= mach_read_from_4 (buf + FIL_PAGE_SPACE_ID);
1461+ cur_page_num= mach_read_from_4 (buf + FIL_PAGE_OFFSET);
1462+
1463+ /* Get tablespace flags from the FSP header */
1464+ uint32_t flags= mach_read_from_4 (buf + FSP_HEADER_OFFSET +
1465+ FSP_SPACE_FLAGS);
1466+
1467+ if (tablespace_flags != USE_FSP_FLAGS)
1468+ {
1469+ if (cur_page_num == 0 && flags != tablespace_flags)
1470+ fprintf (stderr, " Error: Mismatch between provided tablespace "
1471+ " flags (0x%x) and file flags (0x%x)\n " ,
1472+ tablespace_flags, flags);
1473+ }
1474+ else
1475+ {
1476+ if (cur_page_num)
1477+ {
1478+ fprintf (stderr, " Error: First page of the tablespace file "
1479+ " should be 0, but encountered page number %" PRIu32 " . "
1480+ " If you are checking multi file system "
1481+ " tablespace files, please specify the correct "
1482+ " tablespace flags using --tablespace-flags option.\n " ,
1483+ cur_page_num);
1484+ return false ;
1485+ }
1486+ /* Initialize page size parameters based on flags */
1487+ init_page_size_from_flags (flags);
1488+ /* Read the rest of the page if it's larger than the minimum size */
1489+ if (physical_page_size > UNIV_ZIP_SIZE_MIN)
1490+ {
1491+ /* Read rest of the page 0 to determine crypt_data */
1492+ ulint bytes= read_file (buf, true , physical_page_size, fil_in);
1493+ if (bytes != physical_page_size)
1494+ {
1495+ fprintf (stderr, " Error: Was not able to read the rest of the "
1496+ " page of " ULINTPF " bytes. Bytes read was " ULINTPF " \n " ,
1497+ physical_page_size - UNIV_ZIP_SIZE_MIN, bytes);
1498+ return false ;
1499+ }
1500+ }
1501+ tablespace_flags= flags;
1502+ }
1503+
1504+ if (physical_page_size < UNIV_ZIP_SIZE_MIN ||
1505+ physical_page_size > UNIV_PAGE_SIZE_MAX)
1506+ {
1507+ fprintf (stderr, " Error: Invalid page size " ULINTPF
1508+ " encountered\n " , physical_page_size);
1509+ return false ;
1510+ }
1511+ return true ;
1512+ }
1513+
14131514int main (
14141515 int argc,
14151516 char **argv)
@@ -1545,51 +1646,13 @@ int main(
15451646 }
15461647 }
15471648
1548- /* Read the minimum page size. */
1549- bytes = fread (buf, 1 , UNIV_ZIP_SIZE_MIN, fil_in);
1550- partial_page_read = true ;
1551-
1552- if (bytes != UNIV_ZIP_SIZE_MIN) {
1553- fprintf (stderr, " Error: Was not able to read the "
1554- " minimum page size " );
1555- fprintf (stderr, " of %d bytes. Bytes read was " ULINTPF " \n " ,
1556- UNIV_ZIP_SIZE_MIN, bytes);
1557-
1649+ /* Read and validate page 0 */
1650+ if (!read_and_validate_page0 (fil_in, buf)) {
15581651 exit_status = 1 ;
15591652 goto my_exit;
15601653 }
15611654
1562- /* enable variable is_system_tablespace when space_id of given
1563- file is zero. Use to skip the checksum verification and rewrite
1564- for doublewrite pages. */
1565- cur_space = mach_read_from_4 (buf + FIL_PAGE_SPACE_ID);
1566- cur_page_num = mach_read_from_4 (buf + FIL_PAGE_OFFSET);
1567-
1568- /* Determine page size, zip_size and page compression
1569- from fsp_flags and encryption metadata from page 0 */
1570- init_page_size (buf);
1571-
1572- uint32_t flags = mach_read_from_4 (FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + buf);
1573-
1574- if (physical_page_size == UNIV_ZIP_SIZE_MIN) {
1575- partial_page_read = false ;
1576- } else {
1577- /* Read rest of the page 0 to determine crypt_data */
1578- bytes = read_file (buf, partial_page_read, physical_page_size, fil_in);
1579- if (bytes != physical_page_size) {
1580- fprintf (stderr, " Error: Was not able to read the "
1581- " rest of the page " );
1582- fprintf (stderr, " of " ULINTPF " bytes. Bytes read was " ULINTPF " \n " ,
1583- physical_page_size - UNIV_ZIP_SIZE_MIN, bytes);
1584-
1585- exit_status = 1 ;
1586- goto my_exit;
1587- }
1588- partial_page_read = false ;
1589- }
1590-
1591-
1592- /* Now that we have full page 0 in buffer, check encryption */
1655+ /* Check if tablespace is encrypted */
15931656 bool is_encrypted = check_encryption (filename, buf);
15941657
15951658 /* Verify page 0 contents. Note that we can't allow
@@ -1600,7 +1663,8 @@ int main(
16001663 allow_mismatches = 0 ;
16011664
16021665 exit_status = verify_checksum (buf, is_encrypted,
1603- &mismatch_count, flags);
1666+ &mismatch_count,
1667+ tablespace_flags);
16041668
16051669 if (exit_status) {
16061670 fprintf (stderr, " Error: Page 0 checksum mismatch, can't continue. \n " );
@@ -1611,7 +1675,8 @@ int main(
16111675
16121676 if ((exit_status = rewrite_checksum (
16131677 filename, fil_in, buf,
1614- &pos, is_encrypted, flags))) {
1678+ &pos, is_encrypted,
1679+ tablespace_flags))) {
16151680 goto my_exit;
16161681 }
16171682
@@ -1807,7 +1872,7 @@ int main(
18071872first_non_zero:
18081873 if (is_system_tablespace) {
18091874 /* enable when page is double write buffer.*/
1810- skip_page = is_page_doublewritebuffer (buf );
1875+ skip_page = is_page_doublewritebuffer ();
18111876 } else {
18121877 skip_page = false ;
18131878 }
@@ -1828,13 +1893,16 @@ int main(
18281893 && !is_page_free (xdes, physical_page_size, cur_page_num)
18291894 && (exit_status = verify_checksum (
18301895 buf, is_encrypted,
1831- &mismatch_count, flags))) {
1896+ &mismatch_count,
1897+ tablespace_flags))) {
18321898 goto my_exit;
18331899 }
18341900
1835- if ((exit_status = rewrite_checksum (
1836- filename, fil_in, buf,
1837- &pos, is_encrypted, flags))) {
1901+ if (!is_page_doublewritebuffer () &&
1902+ (exit_status = rewrite_checksum (
1903+ filename, fil_in, buf,
1904+ &pos, is_encrypted,
1905+ tablespace_flags))) {
18381906 goto my_exit;
18391907 }
18401908
0 commit comments