[Commits] 4fc7686bda7: MDEV-12610: MariaDB start is slow

jan jan.lindstrom at mariadb.com
Thu Jun 8 15:48:48 EEST 2017


revision-id: 4fc7686bda7be34c5be5022f3dc07e6562664b62 (mariadb-10.1.24-7-g4fc7686bda7)
parent(s): 112b21da37dad0fbb28bc65f9ab5a3ba6c0c2186
author: Jan Lindström
committer: Jan Lindström
timestamp: 2017-06-08 15:40:25 +0300
message:

MDEV-12610: MariaDB start is slow

Problem appears to be that the function fsp_flags_try_adjust()
is being unconditionally invoked on every .ibd file on startup.
Based on performance investigation also the top function
fsp_header_get_crypt_offset() needs to addressed.

Ported implementation of fsp_header_get_encryption_offset()
function from 10.2 to fsp_header_get_crypt_offset().

Introduced a new function fil_crypt_read_crypt_data()
to read page 0 if it is not yet read.

fil_crypt_find_space_to_rotate(): Now that page 0 for every .ibd
file is not read on startup we need to check has page 0 read
from space that we investigate for key rotation, if it is not read
we read it.

fil_space_crypt_get_status(): Now that page 0 for every .ibd
file is not read on startup here also we need to read page 0
if it is not yet read it. This is needed
as tests use IS query to wait until background encryption
or decryption has finished and this function is used to
produce results.

fil_crypt_thread(): Add is_stopping condition for tablespace
so that we do not rotate pages if usage of tablespace should
be stopped. This was needed for failure seen on regression
testing.

fil_space_create: Remove page_0_crypt_read and extra
unnecessary info output.

fil_open_single_table_tablespace(): We call fsp_flags_try_adjust
only when when no errors has happened and server was not started
on read only mode and tablespace validation was requested or
flags contain other table options except low order bits to
FSP_FLAGS_POS_PAGE_SSIZE position.

fil_space_t::page_0_crypt_read removed.

Added test case innodb-first-page-read to test startup when
encryption is on and when encryption is off to check that not
for all tables page 0 is read on startup.

---
 .../encryption/r/innodb-first-page-read.result     | 89 ++++++++++++++++++++
 .../suite/encryption/r/innodb_lotoftables.result   | 28 +++----
 .../suite/encryption/t/innodb-first-page-read.opt  |  5 ++
 .../suite/encryption/t/innodb-first-page-read.test | 97 ++++++++++++++++++++++
 storage/innobase/buf/buf0buf.cc                    |  1 +
 storage/innobase/fil/fil0crypt.cc                  | 61 +++++++++++++-
 storage/innobase/fil/fil0fil.cc                    | 41 ++++-----
 storage/innobase/fsp/fsp0fsp.cc                    | 16 +---
 storage/innobase/include/fil0fil.h                 |  3 -
 storage/xtradb/buf/buf0buf.cc                      |  1 +
 storage/xtradb/fil/fil0crypt.cc                    | 61 +++++++++++++-
 storage/xtradb/fil/fil0fil.cc                      | 41 ++++-----
 storage/xtradb/fsp/fsp0fsp.cc                      | 16 +---
 storage/xtradb/include/fil0fil.h                   |  3 -
 14 files changed, 359 insertions(+), 104 deletions(-)

diff --git a/mysql-test/suite/encryption/r/innodb-first-page-read.result b/mysql-test/suite/encryption/r/innodb-first-page-read.result
new file mode 100644
index 00000000000..6c9eea80fa9
--- /dev/null
+++ b/mysql-test/suite/encryption/r/innodb-first-page-read.result
@@ -0,0 +1,89 @@
+SET GLOBAL innodb_file_format = `Barracuda`;
+SET GLOBAL innodb_file_per_table = ON;
+create database innodb_test;
+use innodb_test;
+create table innodb_normal(c1 bigint not null, b char(200)) engine=innodb;
+create table innodb_compact(c1 bigint not null, b char(200)) engine=innodb row_format=compact;
+create table innodb_dynamic(c1 bigint not null, b char(200)) engine=innodb row_format=dynamic;
+create table innodb_compressed(c1 bigint not null, b char(200)) engine=innodb row_format=compressed;
+create table innodb_compressed1(c1 bigint not null, b char(200)) engine=innodb row_format=compressed key_block_size=1;
+create table innodb_compressed2(c1 bigint not null, b char(200)) engine=innodb row_format=compressed key_block_size=2;
+create table innodb_compressed4(c1 bigint not null, b char(200)) engine=innodb row_format=compressed key_block_size=4;
+create table innodb_compressed8(c1 bigint not null, b char(200)) engine=innodb row_format=compressed key_block_size=8;
+create table innodb_compressed16(c1 bigint not null, b char(200)) engine=innodb row_format=compressed key_block_size=16;
+create table innodb_redundant(c1 bigint not null, b char(200)) engine=innodb row_format=redundant;
+create table innodb_pagecomp(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes;
+create table innodb_pagecomp1(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=1;
+create table innodb_pagecomp2(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=2;
+create table innodb_pagecomp3(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=3;
+create table innodb_pagecomp4(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=4;
+create table innodb_pagecomp5(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=5;
+create table innodb_pagecomp6(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=6;
+create table innodb_pagecomp7(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=7;
+create table innodb_pagecomp8(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=8;
+create table innodb_pagecomp9(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=9;
+create table innodb_datadir1(c1 bigint not null, b char(200)) engine=innodb DATA DIRECTORY='MYSQL_TMP_DIR';
+create table innodb_datadir2(c1 bigint not null, b char(200)) engine=innodb row_format=compressed DATA DIRECTORY='MYSQL_TMP_DIR';
+create table innodb_datadir3(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes DATA DIRECTORY='MYSQL_TMP_DIR';
+begin;
+insert into innodb_normal values (1,'secret');
+insert into innodb_compact select * from innodb_normal;
+insert into innodb_dynamic select * from innodb_normal;
+insert into innodb_compressed select * from innodb_normal;
+insert into innodb_compressed1 select * from innodb_normal;
+insert into innodb_compressed2 select * from innodb_normal;
+insert into innodb_compressed4 select * from innodb_normal;
+insert into innodb_compressed8 select * from innodb_normal;
+insert into innodb_compressed16 select * from innodb_normal;
+insert into innodb_redundant select * from innodb_normal;
+insert into innodb_pagecomp select * from innodb_normal;
+insert into innodb_pagecomp1 select * from innodb_normal;
+insert into innodb_pagecomp2 select * from innodb_normal;
+insert into innodb_pagecomp3 select * from innodb_normal;
+insert into innodb_pagecomp4 select * from innodb_normal;
+insert into innodb_pagecomp5 select * from innodb_normal;
+insert into innodb_pagecomp6 select * from innodb_normal;
+insert into innodb_pagecomp7 select * from innodb_normal;
+insert into innodb_pagecomp8 select * from innodb_normal;
+insert into innodb_pagecomp9 select * from innodb_normal;
+insert into innodb_datadir1 select * from innodb_normal;
+insert into innodb_datadir2 select * from innodb_normal;
+insert into innodb_datadir3 select * from innodb_normal;
+commit;
+# Restart server and see how many page 0's are read
+# result should be less than actual number of tables
+# i.e. < 23 + 3 = 26
+show status like 'innodb_pages0_read%';
+Variable_name	Value
+Innodb_pages0_read	17
+use innodb_test;
+show status like 'innodb_pages0_read%';
+Variable_name	Value
+Innodb_pages0_read	17
+use test;
+show status like 'innodb_pages0_read%';
+Variable_name	Value
+Innodb_pages0_read	17
+set global innodb_encrypt_tables=OFF;
+# wait until tables are decrypted
+show status like 'innodb_pages0_read%';
+Variable_name	Value
+Innodb_pages0_read	29
+use innodb_test;
+show status like 'innodb_pages0_read%';
+Variable_name	Value
+Innodb_pages0_read	29
+use test;
+# restart and see number read page 0
+show status like 'innodb_pages0_read%';
+Variable_name	Value
+Innodb_pages0_read	17
+use innodb_test;
+show status like 'innodb_pages0_read%';
+Variable_name	Value
+Innodb_pages0_read	17
+use test;
+drop database innodb_test;
+show status like 'innodb_pages0_read%';
+Variable_name	Value
+Innodb_pages0_read	29
diff --git a/mysql-test/suite/encryption/r/innodb_lotoftables.result b/mysql-test/suite/encryption/r/innodb_lotoftables.result
index 418ab175a01..b7cfdd2db9d 100644
--- a/mysql-test/suite/encryption/r/innodb_lotoftables.result
+++ b/mysql-test/suite/encryption/r/innodb_lotoftables.result
@@ -12,13 +12,13 @@ create database innodb_encrypted_1;
 use innodb_encrypted_1;
 show status like 'innodb_pages0_read%';
 Variable_name	Value
-Innodb_pages0_read	3
+Innodb_pages0_read	1
 set autocommit=0;
 set autocommit=1;
 commit work;
 show status like 'innodb_pages0_read%';
 Variable_name	Value
-Innodb_pages0_read	3
+Innodb_pages0_read	1
 # should be 100
 SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE NAME LIKE 'innodb_encrypted%';
 COUNT(*)
@@ -88,47 +88,47 @@ Innodb_pages0_read	3
 # Restart Success!
 show status like 'innodb_pages0_read%';
 Variable_name	Value
-Innodb_pages0_read	303
+Innodb_pages0_read	1
 show status like 'innodb_pages0_read%';
 Variable_name	Value
-Innodb_pages0_read	303
+Innodb_pages0_read	1
 use test;
 show status like 'innodb_pages0_read%';
 Variable_name	Value
-Innodb_pages0_read	303
+Innodb_pages0_read	1
 use innodb_encrypted_1;
 show status like 'innodb_pages0_read%';
 Variable_name	Value
-Innodb_pages0_read	303
+Innodb_pages0_read	1
 use innodb_encrypted_2;
 show status like 'innodb_pages0_read%';
 Variable_name	Value
-Innodb_pages0_read	303
+Innodb_pages0_read	1
 use innodb_encrypted_3;
 show status like 'innodb_pages0_read%';
 Variable_name	Value
-Innodb_pages0_read	303
+Innodb_pages0_read	1
 use innodb_encrypted_1;
 show status like 'innodb_pages0_read%';
 Variable_name	Value
-Innodb_pages0_read	303
+Innodb_pages0_read	1
 show status like 'innodb_pages0_read%';
 Variable_name	Value
-Innodb_pages0_read	303
+Innodb_pages0_read	101
 use innodb_encrypted_2;
 show status like 'innodb_pages0_read%';
 Variable_name	Value
-Innodb_pages0_read	303
+Innodb_pages0_read	101
 show status like 'innodb_pages0_read%';
 Variable_name	Value
-Innodb_pages0_read	303
+Innodb_pages0_read	201
 use innodb_encrypted_3;
 show status like 'innodb_pages0_read%';
 Variable_name	Value
-Innodb_pages0_read	303
+Innodb_pages0_read	201
 show status like 'innodb_pages0_read%';
 Variable_name	Value
-Innodb_pages0_read	303
+Innodb_pages0_read	301
 SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND NAME LIKE 'innodb_encrypted%';
 COUNT(*)
 100
diff --git a/mysql-test/suite/encryption/t/innodb-first-page-read.opt b/mysql-test/suite/encryption/t/innodb-first-page-read.opt
new file mode 100644
index 00000000000..38d69691ed6
--- /dev/null
+++ b/mysql-test/suite/encryption/t/innodb-first-page-read.opt
@@ -0,0 +1,5 @@
+--innodb-encrypt-tables=ON
+--innodb-encrypt-log=ON
+--innodb-encryption-rotate-key-age=15
+--innodb-encryption-threads=4
+--innodb-tablespaces-encryption
diff --git a/mysql-test/suite/encryption/t/innodb-first-page-read.test b/mysql-test/suite/encryption/t/innodb-first-page-read.test
new file mode 100644
index 00000000000..1fc07159e05
--- /dev/null
+++ b/mysql-test/suite/encryption/t/innodb-first-page-read.test
@@ -0,0 +1,97 @@
+-- source include/have_innodb.inc
+-- source include/have_file_key_management_plugin.inc
+-- source include/not_embedded.inc
+
+--disable_warnings
+SET GLOBAL innodb_file_format = `Barracuda`;
+SET GLOBAL innodb_file_per_table = ON;
+--enable_warnings
+
+create database innodb_test;
+use innodb_test;
+create table innodb_normal(c1 bigint not null, b char(200)) engine=innodb;
+create table innodb_compact(c1 bigint not null, b char(200)) engine=innodb row_format=compact;
+create table innodb_dynamic(c1 bigint not null, b char(200)) engine=innodb row_format=dynamic;
+create table innodb_compressed(c1 bigint not null, b char(200)) engine=innodb row_format=compressed;
+create table innodb_compressed1(c1 bigint not null, b char(200)) engine=innodb row_format=compressed key_block_size=1;
+create table innodb_compressed2(c1 bigint not null, b char(200)) engine=innodb row_format=compressed key_block_size=2;
+create table innodb_compressed4(c1 bigint not null, b char(200)) engine=innodb row_format=compressed key_block_size=4;
+create table innodb_compressed8(c1 bigint not null, b char(200)) engine=innodb row_format=compressed key_block_size=8;
+create table innodb_compressed16(c1 bigint not null, b char(200)) engine=innodb row_format=compressed key_block_size=16;
+create table innodb_redundant(c1 bigint not null, b char(200)) engine=innodb row_format=redundant;
+create table innodb_pagecomp(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes;
+create table innodb_pagecomp1(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=1;
+create table innodb_pagecomp2(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=2;
+create table innodb_pagecomp3(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=3;
+create table innodb_pagecomp4(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=4;
+create table innodb_pagecomp5(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=5;
+create table innodb_pagecomp6(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=6;
+create table innodb_pagecomp7(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=7;
+create table innodb_pagecomp8(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=8;
+create table innodb_pagecomp9(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes page_compression_level=9;
+
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval create table innodb_datadir1(c1 bigint not null, b char(200)) engine=innodb DATA DIRECTORY='$MYSQL_TMP_DIR';
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval create table innodb_datadir2(c1 bigint not null, b char(200)) engine=innodb row_format=compressed DATA DIRECTORY='$MYSQL_TMP_DIR';
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval create table innodb_datadir3(c1 bigint not null, b char(200)) engine=innodb page_compressed=yes DATA DIRECTORY='$MYSQL_TMP_DIR';
+
+begin;
+insert into innodb_normal values (1,'secret');
+insert into innodb_compact select * from innodb_normal;
+insert into innodb_dynamic select * from innodb_normal;
+insert into innodb_compressed select * from innodb_normal;
+insert into innodb_compressed1 select * from innodb_normal;
+insert into innodb_compressed2 select * from innodb_normal;
+insert into innodb_compressed4 select * from innodb_normal;
+insert into innodb_compressed8 select * from innodb_normal;
+insert into innodb_compressed16 select * from innodb_normal;
+insert into innodb_redundant select * from innodb_normal;
+insert into innodb_pagecomp select * from innodb_normal;
+insert into innodb_pagecomp1 select * from innodb_normal;
+insert into innodb_pagecomp2 select * from innodb_normal;
+insert into innodb_pagecomp3 select * from innodb_normal;
+insert into innodb_pagecomp4 select * from innodb_normal;
+insert into innodb_pagecomp5 select * from innodb_normal;
+insert into innodb_pagecomp6 select * from innodb_normal;
+insert into innodb_pagecomp7 select * from innodb_normal;
+insert into innodb_pagecomp8 select * from innodb_normal;
+insert into innodb_pagecomp9 select * from innodb_normal;
+insert into innodb_datadir1 select * from innodb_normal;
+insert into innodb_datadir2 select * from innodb_normal;
+insert into innodb_datadir3 select * from innodb_normal;
+commit;
+
+--echo # Restart server and see how many page 0's are read
+--source include/restart_mysqld.inc
+
+--echo # result should be less than actual number of tables
+--echo # i.e. < 23 + 3 = 26
+show status like 'innodb_pages0_read%';
+use innodb_test;
+show status like 'innodb_pages0_read%';
+use test;
+show status like 'innodb_pages0_read%';
+
+set global innodb_encrypt_tables=OFF;
+
+--echo # wait until tables are decrypted
+--let $wait_condition=SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0
+--source include/wait_condition.inc
+
+show status like 'innodb_pages0_read%';
+use innodb_test;
+show status like 'innodb_pages0_read%';
+use test;
+
+--echo # restart and see number read page 0
+-- source include/restart_mysqld.inc
+
+show status like 'innodb_pages0_read%';
+use innodb_test;
+show status like 'innodb_pages0_read%';
+use test;
+
+drop database innodb_test;
+show status like 'innodb_pages0_read%';
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index 9b9d0b37f13..97cc162422f 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -4555,6 +4555,7 @@ buf_page_check_corrupt(buf_page_t* bpage, fil_space_t* space)
 		!bpage->encrypted &&
 		fil_space_verify_crypt_checksum(dst_frame, zip_size,
 			space, bpage->offset));
+
 	if (!still_encrypted) {
 		/* If traditional checksums match, we assume that page is
 		not anymore encrypted. */
diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc
index 2131a936656..70d8558ede2 100644
--- a/storage/innobase/fil/fil0crypt.cc
+++ b/storage/innobase/fil/fil0crypt.cc
@@ -1115,6 +1115,43 @@ fil_crypt_needs_rotation(
 	return false;
 }
 
+/** Read page 0 and possible crypt data from there.
+ at param[in]	space		Tablespace */
+static inline
+void
+fil_crypt_read_crypt_data(fil_space_t* space)
+{
+	mutex_enter(&fil_system->mutex);
+
+	/* If space does not contain crypt data and space size is 0
+	we have not yet read first page of tablespace. We need to
+	read it to find out tablespace current encryption status. */
+	if (!space->crypt_data && space->size == 0) {
+		mtr_t	mtr;
+		mtr_start(&mtr);
+		ulint zip_size = fsp_flags_get_zip_size(space->flags);
+		ulint offset = fsp_header_get_crypt_offset(zip_size);
+		mutex_exit(&fil_system->mutex);
+		if (buf_block_t* block = buf_page_get(space->id, zip_size, 0,
+				RW_X_LATCH, &mtr)) {
+			byte* frame = buf_block_get_frame(block);
+
+			mutex_enter(&fil_system->mutex);
+
+			if (!space->crypt_data) {
+				space->crypt_data = fil_space_read_crypt_data(space->id,
+					frame, offset);
+			}
+
+			mutex_exit(&fil_system->mutex);
+		}
+
+		mtr_commit(&mtr);
+	} else {
+		mutex_exit(&fil_system->mutex);
+	}
+}
+
 /***********************************************************************
 Start encrypting a space
 @param[in,out]		space		Tablespace
@@ -1125,6 +1162,7 @@ fil_crypt_start_encrypting_space(
 	fil_space_t*	space)
 {
 	bool recheck = false;
+
 	mutex_enter(&fil_crypt_threads_mutex);
 
 	fil_space_crypt_t *crypt_data = space->crypt_data;
@@ -1191,8 +1229,6 @@ fil_crypt_start_encrypting_space(
 		byte* frame = buf_block_get_frame(block);
 		crypt_data->type = CRYPT_SCHEME_1;
 		crypt_data->write_page0(frame, &mtr);
-
-
 		mtr_commit(&mtr);
 
 		/* record lsn of update */
@@ -1620,6 +1656,13 @@ fil_crypt_find_space_to_rotate(
 	}
 
 	while (!state->should_shutdown() && state->space) {
+		/* If there is no crypt data and we have not yet read
+		page 0 for this tablespace, we need to read it before
+		we can continue. */
+		if (!state->space->crypt_data) {
+			fil_crypt_read_crypt_data(state->space);
+		}
+
 		if (fil_crypt_space_needs_rotation(state, key_state, recheck)) {
 			ut_ad(key_state->key_id);
 			/* init state->min_key_version_found before
@@ -2314,8 +2357,10 @@ DECLARE_THREAD(fil_crypt_thread)(
 			while (!thr.should_shutdown() &&
 			       fil_crypt_find_page_to_rotate(&new_state, &thr)) {
 
-				/* rotate a (set) of pages */
-				fil_crypt_rotate_pages(&new_state, &thr);
+				if (!thr.space->is_stopping()) {
+					/* rotate a (set) of pages */
+					fil_crypt_rotate_pages(&new_state, &thr);
+				}
 
 				/* If space is marked as stopping, release
 				space and stop rotation. */
@@ -2544,6 +2589,14 @@ fil_space_crypt_get_status(
 	memset(status, 0, sizeof(*status));
 
 	ut_ad(space->n_pending_ops > 0);
+
+	/* If there is no crypt data and we have not yet read
+	page 0 for this tablespace, we need to read it before
+	we can continue. */
+	if (!space->crypt_data) {
+		fil_crypt_read_crypt_data(const_cast<fil_space_t*>(space));
+	}
+
 	fil_space_crypt_t* crypt_data = space->crypt_data;
 	status->space = space->id;
 
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index e19ef110b4f..f72d87dfc33 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -653,12 +653,10 @@ fil_node_open_file(
 
 		/* Try to read crypt_data from page 0 if it is not yet
 		read. */
-		if (!node->space->page_0_crypt_read) {
-			ulint offset = fsp_header_get_crypt_offset(
-				fsp_flags_get_zip_size(flags));
-			ut_ad(node->space->crypt_data == NULL);
+		if (!node->space->crypt_data) {
+			const ulint offset = fsp_header_get_crypt_offset(
+					fsp_flags_get_zip_size(flags));
 			node->space->crypt_data = fil_space_read_crypt_data(space_id, page, offset);
-			node->space->page_0_crypt_read = true;
 		}
 
 		ut_free(buf2);
@@ -1557,22 +1555,6 @@ fil_space_create(
 	space->magic_n = FIL_SPACE_MAGIC_N;
 	space->crypt_data = crypt_data;
 
-	/* In create table we write page 0 so we have already
-	"read" it and for system tablespaces we have read
-	crypt data at startup. */
-	if (create_table || crypt_data != NULL) {
-		space->page_0_crypt_read = true;
-	}
-
-#ifdef UNIV_DEBUG
-	ib_logf(IB_LOG_LEVEL_INFO,
-		"Created tablespace for space %lu name %s key_id %u encryption %d.",
-		space->id,
-		space->name,
-		space->crypt_data ? space->crypt_data->key_id : 0,
-		space->crypt_data ? space->crypt_data->encryption : 0);
-#endif
-
 	rw_lock_create(fil_space_latch_key, &space->latch, SYNC_FSP);
 
 	HASH_INSERT(fil_space_t, hash, fil_system->spaces, id, space);
@@ -2401,8 +2383,8 @@ fil_read_first_page(
 		/* Possible encryption crypt data is also stored only to first page
 		of the first datafile. */
 
-		ulint offset = fsp_header_get_crypt_offset(
-			fsp_flags_get_zip_size(*flags));
+		const ulint offset = fsp_header_get_crypt_offset(
+					fsp_flags_get_zip_size(*flags));
 
 		cdata = fil_space_read_crypt_data(*space_id, page, offset);
 
@@ -4018,6 +4000,7 @@ fsp_flags_try_adjust(ulint space_id, ulint flags)
 					 flags, MLOG_4BYTES, &mtr);
 		}
 	}
+
 	mtr_commit(&mtr);
 }
 
@@ -4437,7 +4420,17 @@ fil_open_single_table_tablespace(
 
 	mem_free(def.filepath);
 
-	if (err == DB_SUCCESS && !srv_read_only_mode) {
+	/* We need to check fsp flags when no errors has happened and
+	server was not started on read only mode and tablespace validation
+	was requested or flags contain other table options except
+	low order bits to FSP_FLAGS_POS_PAGE_SSIZE position.
+	Note that flag comparison is pessimistic. Adjust is required
+	only when flags contain buggy MariaDB 10.1.0 -
+	MariaDB 10.1.20 flags.  */
+	if (err == DB_SUCCESS
+	    && !srv_read_only_mode
+	    && (validate
+		|| flags >= (1U << FSP_FLAGS_POS_PAGE_SSIZE))) {
 		fsp_flags_try_adjust(id, flags & ~FSP_FLAGS_MEM_MASK);
 	}
 
diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc
index 98cd11f3369..1c636b0d1f5 100644
--- a/storage/innobase/fsp/fsp0fsp.cc
+++ b/storage/innobase/fsp/fsp0fsp.cc
@@ -4151,20 +4151,8 @@ ulint
 fsp_header_get_crypt_offset(
 	const ulint   zip_size)
 {
-	ulint pageno = 0;
-	/* compute first page_no that will have xdes stored on page != 0*/
-	for (ulint i = 0;
-	     (pageno = xdes_calc_descriptor_page(zip_size, i)) == 0; )
-		i++;
-
-	/* use pageno prior to this...i.e last page on page 0 */
-	ut_ad(pageno > 0);
-	pageno--;
-
-	ulint iv_offset = XDES_ARR_OFFSET +
-		XDES_SIZE * (1 + xdes_calc_descriptor_index(zip_size, pageno));
-
-	return FSP_HEADER_OFFSET + iv_offset;
+	return (FSP_HEADER_OFFSET + (XDES_ARR_OFFSET + XDES_SIZE *
+			(zip_size ? zip_size : UNIV_PAGE_SIZE) / FSP_EXTENT_SIZE));
 }
 
 /**********************************************************************//**
diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h
index ba440cb2a1c..e16c7cb102e 100644
--- a/storage/innobase/include/fil0fil.h
+++ b/storage/innobase/include/fil0fil.h
@@ -351,9 +351,6 @@ struct fil_space_t {
 				compression failure */
 	fil_space_crypt_t* crypt_data;
 				/*!< tablespace crypt data or NULL */
-	bool		page_0_crypt_read;
-				/*!< tablespace crypt data has been
-				read */
 	ulint		file_block_size;
 				/*!< file system block size */
 
diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc
index da4ab059d07..03dc1346517 100644
--- a/storage/xtradb/buf/buf0buf.cc
+++ b/storage/xtradb/buf/buf0buf.cc
@@ -4642,6 +4642,7 @@ buf_page_check_corrupt(buf_page_t* bpage, fil_space_t* space)
 		!bpage->encrypted &&
 		fil_space_verify_crypt_checksum(dst_frame, zip_size,
 			space, bpage->offset));
+
 	if (!still_encrypted) {
 		/* If traditional checksums match, we assume that page is
 		not anymore encrypted. */
diff --git a/storage/xtradb/fil/fil0crypt.cc b/storage/xtradb/fil/fil0crypt.cc
index 21c1e3b730e..e24278dd102 100644
--- a/storage/xtradb/fil/fil0crypt.cc
+++ b/storage/xtradb/fil/fil0crypt.cc
@@ -1115,6 +1115,43 @@ fil_crypt_needs_rotation(
 	return false;
 }
 
+/** Read page 0 and possible crypt data from there.
+ at param[in]	space		Tablespace */
+static inline
+void
+fil_crypt_read_crypt_data(fil_space_t* space)
+{
+	mutex_enter(&fil_system->mutex);
+
+	/* If space does not contain crypt data and space size is 0
+	we have not yet read first page of tablespace. We need to
+	read it to find out tablespace current encryption status. */
+	if (!space->crypt_data && space->size == 0) {
+		mtr_t	mtr;
+		mtr_start(&mtr);
+		ulint zip_size = fsp_flags_get_zip_size(space->flags);
+		ulint offset = fsp_header_get_crypt_offset(zip_size);
+		mutex_exit(&fil_system->mutex);
+		if (buf_block_t* block = buf_page_get(space->id, zip_size, 0,
+				RW_X_LATCH, &mtr)) {
+			byte* frame = buf_block_get_frame(block);
+
+			mutex_enter(&fil_system->mutex);
+
+			if (!space->crypt_data) {
+				space->crypt_data = fil_space_read_crypt_data(space->id,
+					frame, offset);
+			}
+
+			mutex_exit(&fil_system->mutex);
+		}
+
+		mtr_commit(&mtr);
+	} else {
+		mutex_exit(&fil_system->mutex);
+	}
+}
+
 /***********************************************************************
 Start encrypting a space
 @param[in,out]		space		Tablespace
@@ -1125,6 +1162,7 @@ fil_crypt_start_encrypting_space(
 	fil_space_t*	space)
 {
 	bool recheck = false;
+
 	mutex_enter(&fil_crypt_threads_mutex);
 
 	fil_space_crypt_t *crypt_data = space->crypt_data;
@@ -1191,8 +1229,6 @@ fil_crypt_start_encrypting_space(
 		byte* frame = buf_block_get_frame(block);
 		crypt_data->type = CRYPT_SCHEME_1;
 		crypt_data->write_page0(frame, &mtr);
-
-
 		mtr_commit(&mtr);
 
 		/* record lsn of update */
@@ -1620,6 +1656,13 @@ fil_crypt_find_space_to_rotate(
 	}
 
 	while (!state->should_shutdown() && state->space) {
+		/* If there is no crypt data and we have not yet read
+		page 0 for this tablespace, we need to read it before
+		we can continue. */
+		if (!state->space->crypt_data) {
+			fil_crypt_read_crypt_data(state->space);
+		}
+
 		if (fil_crypt_space_needs_rotation(state, key_state, recheck)) {
 			ut_ad(key_state->key_id);
 			/* init state->min_key_version_found before
@@ -2314,8 +2357,10 @@ DECLARE_THREAD(fil_crypt_thread)(
 			while (!thr.should_shutdown() &&
 			       fil_crypt_find_page_to_rotate(&new_state, &thr)) {
 
-				/* rotate a (set) of pages */
-				fil_crypt_rotate_pages(&new_state, &thr);
+				if (!thr.space->is_stopping()) {
+					/* rotate a (set) of pages */
+					fil_crypt_rotate_pages(&new_state, &thr);
+				}
 
 				/* If space is marked as stopping, release
 				space and stop rotation. */
@@ -2545,6 +2590,14 @@ fil_space_crypt_get_status(
 	memset(status, 0, sizeof(*status));
 
 	ut_ad(space->n_pending_ops > 0);
+
+	/* If there is no crypt data and we have not yet read
+	page 0 for this tablespace, we need to read it before
+	we can continue. */
+	if (!space->crypt_data) {
+		fil_crypt_read_crypt_data(const_cast<fil_space_t*>(space));
+	}
+
 	fil_space_crypt_t* crypt_data = space->crypt_data;
 	status->space = space->id;
 
diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc
index b669d35ff15..fda632cdddc 100644
--- a/storage/xtradb/fil/fil0fil.cc
+++ b/storage/xtradb/fil/fil0fil.cc
@@ -661,12 +661,10 @@ fil_node_open_file(
 
 		/* Try to read crypt_data from page 0 if it is not yet
 		read. */
-		if (!node->space->page_0_crypt_read) {
-			ulint offset = fsp_header_get_crypt_offset(
-				fsp_flags_get_zip_size(flags));
-			ut_ad(node->space->crypt_data == NULL);
+		if (!node->space->crypt_data) {
+			const ulint offset = fsp_header_get_crypt_offset(
+					fsp_flags_get_zip_size(flags));
 			node->space->crypt_data = fil_space_read_crypt_data(space_id, page, offset);
-			node->space->page_0_crypt_read = true;
 		}
 
 		ut_free(buf2);
@@ -1600,22 +1598,6 @@ fil_space_create(
 	space->magic_n = FIL_SPACE_MAGIC_N;
 	space->crypt_data = crypt_data;
 
-	/* In create table we write page 0 so we have already
-	"read" it and for system tablespaces we have read
-	crypt data at startup. */
-	if (create_table || crypt_data != NULL) {
-		space->page_0_crypt_read = true;
-	}
-
-#ifdef UNIV_DEBUG
-	ib_logf(IB_LOG_LEVEL_INFO,
-		"Created tablespace for space %lu name %s key_id %u encryption %d.",
-		space->id,
-		space->name,
-		space->crypt_data ? space->crypt_data->key_id : 0,
-		space->crypt_data ? space->crypt_data->encryption : 0);
-#endif
-
 	rw_lock_create(fil_space_latch_key, &space->latch, SYNC_FSP);
 
 	HASH_INSERT(fil_space_t, hash, fil_system->spaces, id, space);
@@ -2463,8 +2445,8 @@ fil_read_first_page(
 		/* Possible encryption crypt data is also stored only to first page
 		of the first datafile. */
 
-		ulint offset = fsp_header_get_crypt_offset(
-			fsp_flags_get_zip_size(*flags));
+		const ulint offset = fsp_header_get_crypt_offset(
+					fsp_flags_get_zip_size(*flags));
 
 		cdata = fil_space_read_crypt_data(*space_id, page, offset);
 
@@ -4211,6 +4193,7 @@ fsp_flags_try_adjust(ulint space_id, ulint flags)
 					 flags, MLOG_4BYTES, &mtr);
 		}
 	}
+
 	mtr_commit(&mtr);
 }
 
@@ -4631,7 +4614,17 @@ fil_open_single_table_tablespace(
 
 	mem_free(def.filepath);
 
-	if (err == DB_SUCCESS && !srv_read_only_mode) {
+	/* We need to check fsp flags when no errors has happened and
+	server was not started on read only mode and tablespace validation
+	was requested or flags contain other table options except
+	low order bits to FSP_FLAGS_POS_PAGE_SSIZE position.
+	Note that flag comparison is pessimistic. Adjust is required
+	only when flags contain buggy MariaDB 10.1.0 -
+	MariaDB 10.1.20 flags.  */
+	if (err == DB_SUCCESS
+	    && !srv_read_only_mode
+	    && (validate
+		|| flags >= (1U << FSP_FLAGS_POS_PAGE_SSIZE))) {
 		fsp_flags_try_adjust(id, flags & ~FSP_FLAGS_MEM_MASK);
 	}
 
diff --git a/storage/xtradb/fsp/fsp0fsp.cc b/storage/xtradb/fsp/fsp0fsp.cc
index 7929372ae6c..fa0c96717c8 100644
--- a/storage/xtradb/fsp/fsp0fsp.cc
+++ b/storage/xtradb/fsp/fsp0fsp.cc
@@ -4177,20 +4177,8 @@ ulint
 fsp_header_get_crypt_offset(
 	const ulint   zip_size)
 {
-	ulint pageno = 0;
-	/* compute first page_no that will have xdes stored on page != 0*/
-	for (ulint i = 0;
-	     (pageno = xdes_calc_descriptor_page(zip_size, i)) == 0; )
-		i++;
-
-	/* use pageno prior to this...i.e last page on page 0 */
-	ut_ad(pageno > 0);
-	pageno--;
-
-	ulint iv_offset = XDES_ARR_OFFSET +
-		XDES_SIZE * (1 + xdes_calc_descriptor_index(zip_size, pageno));
-
-	return FSP_HEADER_OFFSET + iv_offset;
+	return (FSP_HEADER_OFFSET + (XDES_ARR_OFFSET + XDES_SIZE *
+			(zip_size ? zip_size : UNIV_PAGE_SIZE) / FSP_EXTENT_SIZE));
 }
 
 /**********************************************************************//**
diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h
index b861225f562..a09833c3a73 100644
--- a/storage/xtradb/include/fil0fil.h
+++ b/storage/xtradb/include/fil0fil.h
@@ -350,9 +350,6 @@ struct fil_space_t {
 				compression failure */
 	fil_space_crypt_t* crypt_data;
 				/*!< tablespace crypt data or NULL */
-	bool		page_0_crypt_read;
-				/*!< tablespace crypt data has been
-				read */
 	ulint		file_block_size;
 				/*!< file system block size */
 


More information about the commits mailing list