From 76972163711f965402d51055f081ab51ae4a3bb7 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 21 Sep 2021 13:29:27 +0530 Subject: MDEV-26631 InnoDB fails to fetch page from doublewrite buffer Problem: ======== InnoDB fails to fetch the page0 from dblwr if page0 is corrupted.In that case, InnoDB defers the tablespace and doesn't find the INIT_PAGE redo log record for page0 and it leads to failure. Solution: ========= InnoDB should recover page0 from dblwr if space_id can be found for deferred tablespace. --- mysql-test/suite/innodb/r/doublewrite.result | 1 + mysql-test/suite/innodb/t/doublewrite.test | 2 ++ storage/innobase/fsp/fsp0file.cc | 32 +++++++++++++++++++++------- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/mysql-test/suite/innodb/r/doublewrite.result b/mysql-test/suite/innodb/r/doublewrite.result index 234d58012d3..ba1965ed4cd 100644 --- a/mysql-test/suite/innodb/r/doublewrite.result +++ b/mysql-test/suite/innodb/r/doublewrite.result @@ -65,6 +65,7 @@ where name = 'test/t1'; # Ensure that dirty pages of table t1 is flushed. flush tables t1 for export; unlock tables; +set global innodb_log_checkpoint_now=1; begin; insert into t1 values (6, repeat('%', 12)); # Make the first page dirty for table t1 diff --git a/mysql-test/suite/innodb/t/doublewrite.test b/mysql-test/suite/innodb/t/doublewrite.test index cedd2c9942b..d8dac955348 100644 --- a/mysql-test/suite/innodb/t/doublewrite.test +++ b/mysql-test/suite/innodb/t/doublewrite.test @@ -159,6 +159,8 @@ where name = 'test/t1'; flush tables t1 for export; unlock tables; +set global innodb_log_checkpoint_now=1; + begin; insert into t1 values (6, repeat('%', 12)); diff --git a/storage/innobase/fsp/fsp0file.cc b/storage/innobase/fsp/fsp0file.cc index aebe6c9ce23..9a552e6dc5c 100644 --- a/storage/innobase/fsp/fsp0file.cc +++ b/storage/innobase/fsp/fsp0file.cc @@ -400,10 +400,19 @@ Datafile::validate_for_recovery() err = validate_first_page(0); switch (err) { - case DB_SUCCESS: case DB_TABLESPACE_EXISTS: break; - + case DB_SUCCESS: + if (!m_defer || !m_space_id) { + break; + } + /* InnoDB should check whether the deferred + tablespace page0 can be recovered from + double write buffer. InnoDB should try + to recover only if m_space_id exists because + dblwr pages can be searched via {space_id, 0}. + m_space_id is set in read_first_page(). */ + /* fall through */ default: /* Re-open the file in read-write mode Attempt to restore page 0 from doublewrite and read the space ID from a survey @@ -414,23 +423,30 @@ Datafile::validate_for_recovery() return(err); } - err = find_space_id(); - if (err != DB_SUCCESS || m_space_id == 0) { - ib::error() << "Datafile '" << m_filepath << "' is" - " corrupted. Cannot determine the space ID from" - " the first 64 pages."; - return(err); + if (!m_defer) { + err = find_space_id(); + if (err != DB_SUCCESS || m_space_id == 0) { + ib::error() << "Datafile '" << m_filepath + << "' is corrupted. Cannot determine " + "the space ID from the first 64 pages."; + return(err); + } } + if (m_space_id == ULINT_UNDEFINED) { return DB_SUCCESS; /* empty file */ } if (restore_from_doublewrite()) { + if (m_defer) { + return err; + } return(DB_CORRUPTION); } /* Free the previously read first page and then re-validate. */ free_first_page(); + m_defer = false; err = validate_first_page(0); } -- cgit v1.2.1