[Commits] ddf7e15dc00: MDEV-13591: InnoDB: Database page corruption on disk or a failed file read and assertion failure

jan jan.lindstrom at mariadb.com
Tue Aug 22 14:56:57 EEST 2017


revision-id: ddf7e15dc0052a5da414a05cb27319b42e8147a4 (mariadb-10.1.26-10-gddf7e15dc00)
parent(s): 9af7561eb44a7465a8a72789678546b37da96eb8
author: Jan Lindström
committer: Jan Lindström
timestamp: 2017-08-22 14:52:44 +0300
message:

MDEV-13591: InnoDB: Database page corruption on disk or a failed file read and assertion failure

Problem was that for undo-tablespaces page 0 was not read to check
is crypt_data and encryption set or not.

trx_rseg_create_instance: If space referenced on undo log entry
has no crypt_data read page 0 from that tablespace and try
to read crypt_data from there. This crypt_data will be then
later used when actual pages are read from undo tablespace.

Tested with test innodb_encryption using a new
innodb_encryption.combinations with both
innodb-undo-tablespaces=[0|3] settings.

---
 .../suite/encryption/r/innodb_encryption.result    |  2 ++
 .../encryption/t/innodb_encryption.combinations    |  5 ++++
 .../suite/encryption/t/innodb_encryption.test      |  3 ++
 storage/innobase/trx/trx0rseg.cc                   | 33 +++++++++++++++++++---
 storage/xtradb/trx/trx0rseg.cc                     | 33 +++++++++++++++++++---
 5 files changed, 68 insertions(+), 8 deletions(-)

diff --git a/mysql-test/suite/encryption/r/innodb_encryption.result b/mysql-test/suite/encryption/r/innodb_encryption.result
index 26c77499d25..ce494098d44 100644
--- a/mysql-test/suite/encryption/r/innodb_encryption.result
+++ b/mysql-test/suite/encryption/r/innodb_encryption.result
@@ -1,3 +1,5 @@
+call mtr.add_suppression("InnoDB: New log files created");
+call mtr.add_suppression("InnoDB: Creating foreign key constraint system tables.");
 SET @start_global_value = @@global.innodb_encryption_threads;
 SHOW VARIABLES LIKE 'innodb_encrypt%';
 Variable_name	Value
diff --git a/mysql-test/suite/encryption/t/innodb_encryption.combinations b/mysql-test/suite/encryption/t/innodb_encryption.combinations
new file mode 100644
index 00000000000..a876571113f
--- /dev/null
+++ b/mysql-test/suite/encryption/t/innodb_encryption.combinations
@@ -0,0 +1,5 @@
+[undo=3]
+innodb-undo-tablespaces=3
+
+[undo=0]
+innodb-undo-tablespaces=0
diff --git a/mysql-test/suite/encryption/t/innodb_encryption.test b/mysql-test/suite/encryption/t/innodb_encryption.test
index 50aca2a7260..8dba8d899b9 100644
--- a/mysql-test/suite/encryption/t/innodb_encryption.test
+++ b/mysql-test/suite/encryption/t/innodb_encryption.test
@@ -7,6 +7,9 @@
 # embedded does not support restart
 -- source include/not_embedded.inc
 
+call mtr.add_suppression("InnoDB: New log files created");
+call mtr.add_suppression("InnoDB: Creating foreign key constraint system tables.");
+
 SET @start_global_value = @@global.innodb_encryption_threads;
 
 SHOW VARIABLES LIKE 'innodb_encrypt%';
diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc
index 16fa334872b..72e9349459d 100644
--- a/storage/innobase/trx/trx0rseg.cc
+++ b/storage/innobase/trx/trx0rseg.cc
@@ -274,18 +274,43 @@ trx_rseg_create_instance(
 		page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr);
 
 		if (page_no != FIL_NULL) {
-			ulint		space;
+			ulint		space_id;
 			ulint		zip_size;
 			trx_rseg_t*	rseg = NULL;
 
 			ut_a(!trx_rseg_get_on_id(i));
 
-			space = trx_sysf_rseg_get_space(sys_header, i, mtr);
+			space_id = trx_sysf_rseg_get_space(sys_header, i, mtr);
 
-			zip_size = space ? fil_space_get_zip_size(space) : 0;
+			fil_space_t* space = fil_space_acquire_low(space_id, true);
+
+			zip_size = space ? fsp_flags_get_zip_size(space->flags) : 0;
+
+			/* In case of encryption, we need to read first page
+			from undo tablespace to find out if crypt_data is
+			there. TODO: How to avoid reading this page more
+			than once if crypt_data is not there ? */
+			if (page_no != 0 && space && !space->crypt_data) {
+				mtr_t new_mtr;
+				mtr_start(&new_mtr);
+				buf_block_t* block = buf_page_get(space_id,
+					zip_size, 0, RW_S_LATCH, &new_mtr);
+				if (block) {
+					const byte* page = buf_block_get_frame(block);
+					ulint offset = fsp_header_get_crypt_offset(zip_size);
+
+					space->crypt_data = fil_space_read_crypt_data(space_id,
+						page, offset);
+				}
+				mtr_commit(&new_mtr);
+			}
 
 			rseg = trx_rseg_mem_create(
-				i, space, zip_size, page_no, ib_bh, mtr);
+				i, space_id, zip_size, page_no, ib_bh, mtr);
+
+			if (space) {
+				fil_space_release(space);
+			}
 
 			ut_a(rseg->id == i);
 		} else {
diff --git a/storage/xtradb/trx/trx0rseg.cc b/storage/xtradb/trx/trx0rseg.cc
index 16fa334872b..72e9349459d 100644
--- a/storage/xtradb/trx/trx0rseg.cc
+++ b/storage/xtradb/trx/trx0rseg.cc
@@ -274,18 +274,43 @@ trx_rseg_create_instance(
 		page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr);
 
 		if (page_no != FIL_NULL) {
-			ulint		space;
+			ulint		space_id;
 			ulint		zip_size;
 			trx_rseg_t*	rseg = NULL;
 
 			ut_a(!trx_rseg_get_on_id(i));
 
-			space = trx_sysf_rseg_get_space(sys_header, i, mtr);
+			space_id = trx_sysf_rseg_get_space(sys_header, i, mtr);
 
-			zip_size = space ? fil_space_get_zip_size(space) : 0;
+			fil_space_t* space = fil_space_acquire_low(space_id, true);
+
+			zip_size = space ? fsp_flags_get_zip_size(space->flags) : 0;
+
+			/* In case of encryption, we need to read first page
+			from undo tablespace to find out if crypt_data is
+			there. TODO: How to avoid reading this page more
+			than once if crypt_data is not there ? */
+			if (page_no != 0 && space && !space->crypt_data) {
+				mtr_t new_mtr;
+				mtr_start(&new_mtr);
+				buf_block_t* block = buf_page_get(space_id,
+					zip_size, 0, RW_S_LATCH, &new_mtr);
+				if (block) {
+					const byte* page = buf_block_get_frame(block);
+					ulint offset = fsp_header_get_crypt_offset(zip_size);
+
+					space->crypt_data = fil_space_read_crypt_data(space_id,
+						page, offset);
+				}
+				mtr_commit(&new_mtr);
+			}
 
 			rseg = trx_rseg_mem_create(
-				i, space, zip_size, page_no, ib_bh, mtr);
+				i, space_id, zip_size, page_no, ib_bh, mtr);
+
+			if (space) {
+				fil_space_release(space);
+			}
 
 			ut_a(rseg->id == i);
 		} else {


More information about the commits mailing list