@@ -48,9 +48,8 @@ The parts not included are excluded by #ifndef UNIV_INNOCHECKSUM. */
4848#include " buf0buf.h" /* buf_page_is_corrupted */
4949#include " page0zip.h" /* page_zip_*() */
5050#include " trx0undo.h" /* TRX_* */
51- #include " ut0crc32.h" /* ut_crc32_init() */
51+ #include " ut0crc32.h" /* ut_crc32_init() */
5252#include " fil0crypt.h" /* fil_space_verify_crypt_checksum */
53-
5453#include < string.h>
5554
5655#ifdef UNIV_NONINL
@@ -79,6 +78,8 @@ static ulint extent_size;
7978static ulint xdes_size;
8079ulong srv_page_size;
8180ulong srv_page_size_shift;
81+ static uint32_t dblwr_1;
82+ static uint32_t dblwr_2;
8283/* Current page number (0 based). */
8384uint32_t cur_page_num;
8485/* Current space. */
@@ -102,8 +103,10 @@ FILE* log_file = NULL;
102103/* Enabled for log write option. */
103104static bool is_log_enabled = false ;
104105static bool skip_freed_pages;
106+ static uint32_t tablespace_flags= 0 ;
105107static byte field_ref_zero_buf[UNIV_PAGE_SIZE_MAX];
106108const byte *field_ref_zero = field_ref_zero_buf;
109+ constexpr uint32_t USE_FSP_FLAGS{UINT32_MAX};
107110
108111#ifndef _WIN32
109112/* advisory lock for non-window system. */
@@ -258,12 +261,9 @@ void print_leaf_stats(
258261}
259262
260263/* * Init the page size for the tablespace.
261- @param[in] buf buffer used to read the page */
262- static void init_page_size (const byte* buf )
264+ @param[in] flags InnoDB tablespace flags */
265+ static void init_page_size_from_flags (const uint32_t flags )
263266{
264- const unsigned flags = mach_read_from_4 (buf + FIL_PAGE_DATA
265- + FSP_SPACE_FLAGS);
266-
267267 if (fil_space_t::full_crc32 (flags)) {
268268 const ulong ssize = FSP_FLAGS_FCRC32_GET_PAGE_SSIZE (flags);
269269 srv_page_size_shift = UNIV_ZIP_SIZE_SHIFT_MIN - 1 + ssize;
@@ -550,24 +550,15 @@ is_page_corrupted(
550550 return (is_corrupted);
551551}
552552
553- /* *******************************************/ /*
554- Check if page is doublewrite buffer or not.
555- @param [in] page buffer page
556-
557- @retval true if page is doublewrite buffer otherwise false.
558- */
559- static
560- bool
561- is_page_doublewritebuffer (
562- const byte* page)
553+ /* * Check if page is doublewrite buffer or not.
554+ @retval true if page is doublewrite buffer otherwise false. */
555+ static bool is_page_doublewritebuffer ()
563556{
564- if ((cur_page_num >= extent_size)
565- && (cur_page_num < extent_size * 3 )) {
566- /* page is doublewrite buffer. */
567- return (true );
568- }
569-
570- return (false );
557+ if (cur_space != 0 ) return false ;
558+ const uint32_t extent{static_cast <uint32_t >(
559+ cur_page_num & ~(extent_size - 1 ))};
560+ return cur_page_num > FSP_DICT_HDR_PAGE_NO &&
561+ extent && (extent == dblwr_1 || extent == dblwr_2);
571562}
572563
573564/* ******************************************************/ /*
@@ -774,7 +765,7 @@ Parse the page and collect/dump the information about page type
774765@param [in] file file for diagnosis.
775766@param [in] is_encrypted tablespace is encrypted
776767*/
777- void
768+ static void
778769parse_page (
779770 const byte* page,
780771 byte* xdes,
@@ -794,6 +785,12 @@ parse_page(
794785 str = skip_page ? " Double_write_buffer" : " -" ;
795786 page_no = mach_read_from_4 (page + FIL_PAGE_OFFSET);
796787 if (skip_freed_pages) {
788+
789+ /* * Skip doublewrite pages when -r is enabled */
790+ if (is_page_doublewritebuffer ()) {
791+ return ;
792+ }
793+
797794 const byte *des= xdes + XDES_ARR_OFFSET +
798795 xdes_size * ((page_no & (physical_page_size - 1 ))
799796 / extent_size);
@@ -988,6 +985,18 @@ parse_page(
988985 fprintf (file, " #::" UINT32PF " \t\t |\t\t Transaction system "
989986 " page\t\t |\t %s\n " , cur_page_num, str);
990987 }
988+
989+ if (cur_space == 0 &&
990+ (mach_read_from_4 (page + TRX_SYS_DOUBLEWRITE +
991+ TRX_SYS_DOUBLEWRITE_MAGIC) ==
992+ TRX_SYS_DOUBLEWRITE_MAGIC_N)) {
993+ dblwr_1 = mach_read_from_4 (
994+ page + TRX_SYS_DOUBLEWRITE +
995+ TRX_SYS_DOUBLEWRITE_BLOCK1);
996+ dblwr_2 = mach_read_from_4 (
997+ page + TRX_SYS_DOUBLEWRITE +
998+ TRX_SYS_DOUBLEWRITE_BLOCK2);
999+ }
9911000 break ;
9921001
9931002 case FIL_PAGE_TYPE_FSP_HDR:
@@ -1230,6 +1239,9 @@ static struct my_option innochecksum_options[] = {
12301239 {" skip-freed-pages" , ' r' , " skip freed pages for the tablespace" ,
12311240 &skip_freed_pages, &skip_freed_pages, 0 , GET_BOOL, NO_ARG,
12321241 0 , 0 , 0 , 0 , 0 , 0 },
1242+ {" tablespace-flags" , 0 , " InnoDB tablespace flags (default: 4294967295 "
1243+ " = read from page 0)" , &tablespace_flags, &tablespace_flags, 0 ,
1244+ GET_UINT, REQUIRED_ARG, USE_FSP_FLAGS, 0 , USE_FSP_FLAGS, 0 , 0 , 0 },
12331245
12341246 {0 , 0 , 0 , 0 , 0 , 0 , GET_NO_ARG, NO_ARG, 0 , 0 , 0 , 0 , 0 , 0 }
12351247};
@@ -1304,6 +1316,14 @@ innochecksum_get_one_option(
13041316 my_end (0 );
13051317 exit (EXIT_SUCCESS);
13061318 break ;
1319+ default :
1320+ if (tablespace_flags != USE_FSP_FLAGS &&
1321+ !fil_space_t::is_valid_flags (tablespace_flags, false ) &&
1322+ !fil_space_t::is_valid_flags (tablespace_flags, true )) {
1323+ fprintf (stderr, " Error: Provided --tablespace-flags "
1324+ " is not valid." );
1325+ return true ;
1326+ }
13071327 }
13081328
13091329 return (false );
@@ -1434,6 +1454,87 @@ rewrite_checksum(
14341454 && !write_file (filename, fil_in, buf, flags, pos);
14351455}
14361456
1457+ /* * Read and validate page 0, then initialize tablespace flags
1458+ and page size.
1459+ @param fil_in File pointer
1460+ @param buf Buffer to read page into
1461+ @return whether the page was read successfully */
1462+ static bool read_and_validate_page0 (FILE *fil_in, byte *buf)
1463+ {
1464+ /* Read the minimum page size first */
1465+ size_t initial_page_size= UNIV_ZIP_SIZE_MIN;
1466+ if (tablespace_flags != USE_FSP_FLAGS)
1467+ {
1468+ init_page_size_from_flags (tablespace_flags);
1469+ initial_page_size= physical_page_size;
1470+ }
1471+
1472+ /* Read just enough to get the tablespace flags */
1473+ size_t bytes= fread (buf, 1 , initial_page_size, fil_in);
1474+
1475+ if (bytes != initial_page_size)
1476+ {
1477+ fprintf (stderr, " Error: Was not able to read the "
1478+ " minimum page size of %zu bytes. Bytes read "
1479+ " was %zu\n " , initial_page_size, bytes);
1480+ return false ;
1481+ }
1482+
1483+ /* Read space_id and page offset */
1484+ cur_space= mach_read_from_4 (buf + FIL_PAGE_SPACE_ID);
1485+ cur_page_num= mach_read_from_4 (buf + FIL_PAGE_OFFSET);
1486+
1487+ /* Get tablespace flags from the FSP header */
1488+ uint32_t flags= mach_read_from_4 (buf + FSP_HEADER_OFFSET +
1489+ FSP_SPACE_FLAGS);
1490+
1491+ if (tablespace_flags != USE_FSP_FLAGS)
1492+ {
1493+ if (cur_page_num == 0 && flags != tablespace_flags)
1494+ fprintf (stderr, " Error: Mismatch between provided tablespace "
1495+ " flags (0x%x) and file flags (0x%x)\n " ,
1496+ tablespace_flags, flags);
1497+ }
1498+ else
1499+ {
1500+ if (cur_page_num)
1501+ {
1502+ fprintf (stderr, " Error: First page of the tablespace file "
1503+ " should be 0, but encountered page number %" PRIu32 " . "
1504+ " If you are checking multi file system "
1505+ " tablespace files, please specify the correct "
1506+ " tablespace flags using --tablespace-flags option.\n " ,
1507+ cur_page_num);
1508+ return false ;
1509+ }
1510+ /* Initialize page size parameters based on flags */
1511+ init_page_size_from_flags (flags);
1512+ /* Read the rest of the page if it's larger than the minimum size */
1513+ if (physical_page_size > UNIV_ZIP_SIZE_MIN)
1514+ {
1515+ /* Read rest of the page 0 to determine crypt_data */
1516+ ulint bytes= read_file (buf, true , physical_page_size, fil_in);
1517+ if (bytes != physical_page_size)
1518+ {
1519+ fprintf (stderr, " Error: Was not able to read the rest of the "
1520+ " page of " ULINTPF " bytes. Bytes read was " ULINTPF " \n " ,
1521+ physical_page_size - UNIV_ZIP_SIZE_MIN, bytes);
1522+ return false ;
1523+ }
1524+ }
1525+ tablespace_flags= flags;
1526+ }
1527+
1528+ if (physical_page_size < UNIV_ZIP_SIZE_MIN ||
1529+ physical_page_size > UNIV_PAGE_SIZE_MAX)
1530+ {
1531+ fprintf (stderr, " Error: Invalid page size " ULINTPF
1532+ " encountered\n " , physical_page_size);
1533+ return false ;
1534+ }
1535+ return true ;
1536+ }
1537+
14371538int main (
14381539 int argc,
14391540 char **argv)
@@ -1569,51 +1670,13 @@ int main(
15691670 }
15701671 }
15711672
1572- /* Read the minimum page size. */
1573- bytes = fread (buf, 1 , UNIV_ZIP_SIZE_MIN, fil_in);
1574- partial_page_read = true ;
1575-
1576- if (bytes != UNIV_ZIP_SIZE_MIN) {
1577- fprintf (stderr, " Error: Was not able to read the "
1578- " minimum page size " );
1579- fprintf (stderr, " of %d bytes. Bytes read was " ULINTPF " \n " ,
1580- UNIV_ZIP_SIZE_MIN, bytes);
1581-
1673+ /* Read and validate page 0 */
1674+ if (!read_and_validate_page0 (fil_in, buf)) {
15821675 exit_status = 1 ;
15831676 goto my_exit;
15841677 }
15851678
1586- /* enable variable is_system_tablespace when space_id of given
1587- file is zero. Use to skip the checksum verification and rewrite
1588- for doublewrite pages. */
1589- cur_space = mach_read_from_4 (buf + FIL_PAGE_SPACE_ID);
1590- cur_page_num = mach_read_from_4 (buf + FIL_PAGE_OFFSET);
1591-
1592- /* Determine page size, zip_size and page compression
1593- from fsp_flags and encryption metadata from page 0 */
1594- init_page_size (buf);
1595-
1596- ulint flags = mach_read_from_4 (FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + buf);
1597-
1598- if (physical_page_size == UNIV_ZIP_SIZE_MIN) {
1599- partial_page_read = false ;
1600- } else {
1601- /* Read rest of the page 0 to determine crypt_data */
1602- bytes = read_file (buf, partial_page_read, physical_page_size, fil_in);
1603- if (bytes != physical_page_size) {
1604- fprintf (stderr, " Error: Was not able to read the "
1605- " rest of the page " );
1606- fprintf (stderr, " of " ULINTPF " bytes. Bytes read was " ULINTPF " \n " ,
1607- physical_page_size - UNIV_ZIP_SIZE_MIN, bytes);
1608-
1609- exit_status = 1 ;
1610- goto my_exit;
1611- }
1612- partial_page_read = false ;
1613- }
1614-
1615-
1616- /* Now that we have full page 0 in buffer, check encryption */
1679+ /* Check if tablespace is encrypted */
16171680 bool is_encrypted = check_encryption (filename, buf);
16181681
16191682 /* Verify page 0 contents. Note that we can't allow
@@ -1624,7 +1687,8 @@ int main(
16241687 allow_mismatches = 0 ;
16251688
16261689 exit_status = verify_checksum (buf, is_encrypted,
1627- &mismatch_count, flags);
1690+ &mismatch_count,
1691+ tablespace_flags);
16281692
16291693 if (exit_status) {
16301694 fprintf (stderr, " Error: Page 0 checksum mismatch, can't continue. \n " );
@@ -1635,7 +1699,8 @@ int main(
16351699
16361700 if ((exit_status = rewrite_checksum (
16371701 filename, fil_in, buf,
1638- &pos, is_encrypted, flags))) {
1702+ &pos, is_encrypted,
1703+ tablespace_flags))) {
16391704 goto my_exit;
16401705 }
16411706
@@ -1831,7 +1896,7 @@ int main(
18311896first_non_zero:
18321897 if (is_system_tablespace) {
18331898 /* enable when page is double write buffer.*/
1834- skip_page = is_page_doublewritebuffer (buf );
1899+ skip_page = is_page_doublewritebuffer ();
18351900 } else {
18361901 skip_page = false ;
18371902 }
@@ -1852,13 +1917,16 @@ int main(
18521917 && !is_page_free (xdes, physical_page_size, cur_page_num)
18531918 && (exit_status = verify_checksum (
18541919 buf, is_encrypted,
1855- &mismatch_count, flags))) {
1920+ &mismatch_count,
1921+ tablespace_flags))) {
18561922 goto my_exit;
18571923 }
18581924
1859- if ((exit_status = rewrite_checksum (
1860- filename, fil_in, buf,
1861- &pos, is_encrypted, flags))) {
1925+ if (!is_page_doublewritebuffer () &&
1926+ (exit_status = rewrite_checksum (
1927+ filename, fil_in, buf,
1928+ &pos, is_encrypted,
1929+ tablespace_flags))) {
18621930 goto my_exit;
18631931 }
18641932
0 commit comments