################################################################################ # InnoDB transparent tablespace data encryption for general shared tablespace. # This test case will test # - Crash during altering an encrypted tablespace # - encryption='y' to encryption='n' # - encryption='n' to encryption='y' # - Crash during altering an encrypted tablespace (Compressed) # - encryption='y' to encryption='n' # - encryption='n' to encryption='y' # - Crash # - just before encryption processing starts # - just after encryption processing finishes # - Crash during master key rotation # - Crash during creating an encrypted tablespace # - During alter tablespace encryption, DMLs are allowed and DDLs are blocked ################################################################################ --source include/big_test.inc --source include/have_debug.inc # --source include/no_valgrind_without_big.inc # Disable in valgrind because of timeout, cf. Bug#22760145 --source include/not_valgrind.inc # Waiting time when (re)starting the server --let $explicit_default_wait_counter=10000; --disable_query_log call mtr.add_suppression("ibd can't be decrypted, please confirm the keyfile is match and keyring plugin is loaded."); call mtr.add_suppression("\\[Error\\] \\[[^]]*\\] \\[[^]]*\\] Encryption can't find master key, please check the keyring plugin is loaded."); call mtr.add_suppression("\\[ERROR\\] \\[[^]]*\\] \\[[^]]*\\] Check keyring plugin fail, please check the keyring plugin is loaded."); --enable_query_log --echo ######################################################################### --echo # START : WITHOUT KEYRING PLUGIN --echo ######################################################################### --echo --echo ######### --echo # SETUP # --echo ######### # Create an Unencrypted tablespace CREATE TABLESPACE encrypt_ts ADD DATAFILE 'encrypt_ts.ibd' ENGINE=InnoDB ENCRYPTION="N"; # Create an unencrypted table in tablespace CREATE TABLE t1(c1 char(100)) ENGINE=InnoDB TABLESPACE encrypt_ts; # Insert few rows in table --disable_query_log INSERT INTO t1 VALUES ("SOME VALUES"); let $counter=12; while ($counter>0) { INSERT INTO test.t1 SELECT * FROM test.t1; dec $counter; } --enable_query_log # Make sure ts file is updated with new records in table set global innodb_buf_flush_list_now = 1; SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='encrypt_ts'; SELECT * FROM t1 LIMIT 10; # Try to alter tablespace to be encrypted. Should fail as keyring is not laoded. --error ER_CANNOT_FIND_KEY_IN_KEYRING ALTER TABLESPACE encrypt_ts ENCRYPTION='Y'; --echo ############################################################# --echo # TEST 1 : CRASH DURING ALTER ENCRYPT A TABLESPACE. --echo ############################################################# --echo --echo ######################################################################### --echo # RESTART 1 : WITH KEYRING PLUGIN --echo ######################################################################### let $restart_parameters = restart: --early-plugin-load=keyring_file=$KEYRING_PLUGIN --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring $KEYRING_PLUGIN_OPT; --source include/restart_mysqld_no_echo.inc --echo ############################################################ --echo # ALTER TABLESPACE 1 : Unencrypted => Encrypted # --echo # (crash at page 10) # --echo ############################################################ --echo # Set Encryption process to crash at page 10 SET SESSION debug= '+d,alter_encrypt_tablespace_page_10'; --echo # Encrypt the tablespace. It will cause crash. --source include/expect_crash.inc --error 0,CR_SERVER_LOST,ER_INTERNAL_ERROR ALTER TABLESPACE encrypt_ts ENCRYPTION='Y'; --echo # Restart after crash --source include/start_mysqld_no_echo.inc --echo # Wait for Encryption processing to finish in background thread let $wait_condition = SELECT ENCRYPTION = 'Y' FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='encrypt_ts'; --source include/wait_condition.inc # Make sure ts file is updated with new records in table set global innodb_buf_flush_list_now = 1; --echo # After restart/recovery, check that Encryption was roll-forward SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='encrypt_ts'; SELECT * FROM t1 LIMIT 10; --echo ######################################################################### --echo # RESTART 2 : WITHOUT KEYRING PLUGIN --echo ######################################################################### let $restart_parameters = restart:; --source include/restart_mysqld_no_echo.inc # We shouldn't be able to read t1 records as it is encrypted now and keyring # plugin is not loaded. --error ER_CANNOT_FIND_KEY_IN_KEYRING SELECT * FROM t1 LIMIT 10; --echo ######################################################################### --echo # RESTART 3 : WITH KEYRING PLUGIN --echo ######################################################################### let $restart_parameters = restart: --early-plugin-load=keyring_file=$KEYRING_PLUGIN --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring $KEYRING_PLUGIN_OPT; --source include/restart_mysqld_no_echo.inc SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='encrypt_ts'; SELECT * FROM t1 LIMIT 10; --echo ############################################################ --echo # ALTER TABLESPACE 2 : Encrypted => Unencrypted # --echo # (crash at page 10) # --echo ############################################################ --echo # Set Unencryption process to crash at page 10 SET SESSION debug= '+d,alter_encrypt_tablespace_page_10'; --echo # Unencrypt the tablespace. It will cause crash. --source include/expect_crash.inc --error 0,CR_SERVER_LOST,ER_INTERNAL_ERROR ALTER TABLESPACE encrypt_ts ENCRYPTION='N'; --echo # Restart after crash --source include/start_mysqld_no_echo.inc --echo # Wait for Unencryption processing to finish in background thread let $wait_condition = SELECT ENCRYPTION = 'N' FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='encrypt_ts'; --source include/wait_condition.inc # Make sure ts file is updated with new records in table set global innodb_buf_flush_list_now = 1; --echo # After restart/recovery, check that Unencryption was roll-forward SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='encrypt_ts'; SELECT * FROM t1 LIMIT 10; --echo ######################################################################### --echo # RESTART 4 : WITHOUT KEYRING PLUGIN --echo ######################################################################### let $restart_parameters = restart:; --source include/restart_mysqld_no_echo.inc SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='encrypt_ts'; # We should be able to read t1 records even without OKV keyring plugin as it should # be unencrypted now. SELECT * FROM t1 LIMIT 10; --echo #################################################################### --echo # TEST 2 : CRASH DURING ALTER ENCRYPT A TABLESPACE (Compressed). --echo #################################################################### --echo # Create an Unencrypted compressed tablespace CREATE TABLESPACE compress_ts ADD DATAFILE 'compress_ts.ibd' ENGINE=InnoDB ENCRYPTION="N" FILE_BLOCK_SIZE=8192; # Create an unencrypted table in tablespace CREATE TABLE t2(c1 char(100)) ENGINE=InnoDB TABLESPACE compress_ts ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; # Insert few rows in table --disable_query_log INSERT INTO t2 VALUES ("SOME VALUES"); let $counter=12; while ($counter>0) { INSERT INTO test.t2 SELECT * FROM test.t1; dec $counter; } --enable_query_log # Make sure ts file is updated with new records in table set global innodb_buf_flush_list_now = 1; SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='compress_ts'; SELECT * FROM t2 LIMIT 10; --echo ######################################################################### --echo # RESTART 5 : WITH KEYRING PLUGIN --echo ######################################################################### let $restart_parameters = restart: --early-plugin-load=keyring_file=$KEYRING_PLUGIN --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring $KEYRING_PLUGIN_OPT; --source include/restart_mysqld_no_echo.inc --echo ############################################################ --echo # ALTER TABLESPACE 1 : Unencrypted => Encrypted # --echo # (crash at page 10) # --echo ############################################################ --echo # Set Encryption process to crash at page 10 SET SESSION debug= '+d,alter_encrypt_tablespace_page_10'; --echo # Encrypt the tablespace. It will cause crash. --source include/expect_crash.inc --error 0,CR_SERVER_LOST,ER_INTERNAL_ERROR ALTER TABLESPACE compress_ts ENCRYPTION='Y'; --echo # Restart after crash --source include/start_mysqld_no_echo.inc --echo # Wait for Encryption processing to finish in background thread let $wait_condition = SELECT ENCRYPTION = 'Y' FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='compress_ts'; --source include/wait_condition.inc # Make sure ts file is updated with new records in table set global innodb_buf_flush_list_now = 1; --echo # After restart/recovery, check that Encryption was roll-forward SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='compress_ts'; SELECT * FROM t2 LIMIT 10; --echo ######################################################################### --echo # RESTART 6 : WITHOUT KEYRING PLUGIN --echo ######################################################################### let $restart_parameters = restart:; --source include/restart_mysqld_no_echo.inc # We shouldn't be able to read t2 records as it is encrypted now and keyring # plugin is not loaded. --error ER_CANNOT_FIND_KEY_IN_KEYRING SELECT * FROM t2 LIMIT 10; --echo ######################################################################### --echo # RESTART 7 WITH KEYRING PLUGIN --echo ######################################################################### let $restart_parameters = restart: --early-plugin-load=keyring_file=$KEYRING_PLUGIN --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring $KEYRING_PLUGIN_OPT; --source include/restart_mysqld_no_echo.inc SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='compress_ts'; SELECT * FROM t2 LIMIT 10; --echo ############################################################ --echo # ALTER TABLESPACE 2 : Encrypted => Unencrypted # --echo # (crash at page 10) # --echo ############################################################ --echo # Set Unencryption process to crash at page 10 SET SESSION debug= '+d,alter_encrypt_tablespace_page_10'; --echo # Unencrypt the tablespace. It will cause crash. --source include/expect_crash.inc --error 0,CR_SERVER_LOST,ER_INTERNAL_ERROR ALTER TABLESPACE compress_ts ENCRYPTION='N'; --echo # Restart after crash --source include/start_mysqld_no_echo.inc --echo # Wait for Unencryption processing to finish in background thread let $wait_condition = SELECT ENCRYPTION = 'N' FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='compress_ts'; --source include/wait_condition.inc # Make sure ts file is updated with new records in table set global innodb_buf_flush_list_now = 1; --echo # After restart/recovery, check that Unencryption was roll-forward SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='compress_ts'; SELECT * FROM t2 LIMIT 10; --echo ######################################################################### --echo # RESTART 8 : WITHOUT KEYRING PLUGIN --echo ######################################################################### let $restart_parameters = restart:; --source include/restart_mysqld_no_echo.inc SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='encrypt_ts'; # We should be able to read t1 records even without keyring plugin as it should # be unencrypted now. SELECT * FROM t2 LIMIT 10; DROP TABLE t2; DROP TABLESPACE compress_ts; --echo ############################################################# --echo # TEST 3 : CRASH BEFORE/AFTER ENCRYPTION PROCESSING. --echo ############################################################# --echo --echo ######################################################################### --echo # RESTART 9 : WITH KEYRING PLUGIN --echo ######################################################################### let $restart_parameters = restart: --early-plugin-load=keyring_file=$KEYRING_PLUGIN --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring $KEYRING_PLUGIN_OPT; --source include/restart_mysqld_no_echo.inc # Encrypt tablespace ALTER TABLESPACE encrypt_ts ENCRYPTION='Y'; # Read rows from table SELECT * FROM t1 LIMIT 10; --echo # Set server to crash just before encryption processing starts SET SESSION debug="+d,alter_encrypt_tablespace_crash_before_processing"; --echo # Unencrypt the tablespace. It will cause crash. --source include/expect_crash.inc --error 0,CR_SERVER_LOST,ER_INTERNAL_ERROR ALTER TABLESPACE encrypt_ts ENCRYPTION='N'; --echo # Restart after crash --source include/start_mysqld_no_echo.inc --echo # Wait for Unencryption processing to finish in background thread let $wait_condition = select count(*) = 0 from performance_schema.events_stages_current where EVENT_NAME='stage/innodb/alter tablespace (encryption)'; --source include/wait_condition.inc # Encrytion property of tablespace shouldn't have changed i.e. it should still # be encrypted. SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='encrypt_ts'; --echo # Set server to crash just after encryption processing finishes SET SESSION debug="-d,alter_encrypt_tablespace_crash_before_processing"; SET SESSION debug="+d,alter_encrypt_tablespace_crash_after_processing"; --echo # Unencrypt the tablespace. It will cause crash. --source include/expect_crash.inc --error 0,CR_SERVER_LOST,ER_INTERNAL_ERROR ALTER TABLESPACE encrypt_ts ENCRYPTION='N'; --echo # Restart after crash --source include/start_mysqld_no_echo.inc --echo # Wait for Unencryption processing to finish in background thread let $wait_condition = select count(*) = 0 from performance_schema.events_stages_current where EVENT_NAME='stage/innodb/alter tablespace (encryption)'; --source include/wait_condition.inc # Encrytion property of tablespace should have changed i.e. it should be # unencrypted now. SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='encrypt_ts'; --echo ############################################################# --echo # TEST 4 : CRASH DURING KEY ROTATION. --echo ############################################################# --echo --echo ######################################################################### --echo # RESTART 10 : WITH KEYRING PLUGIN --echo ######################################################################### let $restart_parameters = restart: --early-plugin-load=keyring_file=$KEYRING_PLUGIN --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring $KEYRING_PLUGIN_OPT; --source include/restart_mysqld_no_echo.inc # Encrypt tablespace ALTER TABLESPACE encrypt_ts ENCRYPTION='Y'; # Read rows from table SELECT * FROM t1 LIMIT 10; --echo # Set server to crash while rotating encryption SET SESSION debug="+d,ib_crash_during_rotation_for_encryption"; # Rotate the key. It will cause server to crash. --source include/expect_crash.inc --error 0,CR_SERVER_LOST,ER_INTERNAL_ERROR ALTER INSTANCE ROTATE INNODB MASTER KEY; --echo # Restart after crash --source include/start_mysqld_no_echo.inc # Read rows from table SELECT * FROM t1 LIMIT 10; # Rotate the key. SET SESSION debug="-d,ib_crash_during_rotation_for_encryption"; ALTER INSTANCE ROTATE INNODB MASTER KEY; # Read rows from table SELECT * FROM t1 LIMIT 10; --echo ############################################################### --echo # TEST 5 : CRASH DURING CREATING AN ENCRYPTED TABLESPACE --echo ############################################################### --echo --echo # Set server to crash while creating an encrypted tablespace SET SESSION debug="+d,ib_crash_during_create_tablespace_for_encryption"; --echo # Try to create an encrypted tablespace. It will cause server to crash. --source include/expect_crash.inc --error 0,CR_SERVER_LOST,ER_INTERNAL_ERROR CREATE TABLESPACE encrypt_ts_2 ADD DATAFILE 'encrypt_ts_2.ibd' ENGINE=InnoDB ENCRYPTION="Y"; --echo # Restart after crash --source include/start_mysqld_no_echo.inc SET SESSION debug="-d,ib_crash_during_create_tablespace_for_encryption"; SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME LIKE "%encrypt_ts%"; --echo ############################################################### --echo # TEST 6 : DMLs ALLOWED AND DDLs BLOCKED TEST --echo ############################################################### # Make sure metadata locks instrumentation is enabled SELECT ENABLED FROM performance_schema.setup_instruments WHERE NAME='wait/lock/metadata/sql/mdl'; let $con_default_thread_id= `select THREAD_ID from performance_schema.threads where PROCESSLIST_ID = connection_id()`; SET DEBUG_SYNC = 'innodb_alter_encrypt_tablespace SIGNAL s1 WAIT_FOR s2'; --send ALTER TABLESPACE encrypt_ts ENCRYPTION='N'; --echo # Session 2 connect(con2, localhost, root,,); --connection con2 let $con2_thread_id= `select THREAD_ID from performance_schema.threads where PROCESSLIST_ID = connection_id()`; SET DEBUG_SYNC = 'now WAIT_FOR s1'; # Make sure MDL on tablespace is GRANTED to 'default connection' thread. --disable_query_log eval SELECT OBJECT_TYPE, OBJECT_NAME, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS FROM performance_schema.metadata_locks WHERE OBJECT_NAME='encrypt_ts' AND OWNER_THREAD_ID = $con_default_thread_id; --enable_query_log # Try to run some DMLs. Should be allowed. DESCRIBE t1; SHOW CREATE TABLE t1; SELECT COUNT(*) FROM t1; INSERT INTO t1 VALUES ("SOME VALUES"); SELECT COUNT(*) from t1; # Try to run a DDL. Should be blocked. --send ALTER TABLE t1 ADD COLUMN (c2 int); --echo # Monitoring session connect(conmon, localhost, root,,); --connection conmon # Make sure 'connection default' thread has MDL request GRANTED. --disable_query_log eval SELECT OBJECT_TYPE, OBJECT_NAME, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS FROM performance_schema.metadata_locks WHERE OBJECT_NAME='encrypt_ts' AND OWNER_THREAD_ID = $con_default_thread_id; --echo # Wait for MDL request by con2 to appear in metadata_locks table. let $wait_condition = SELECT LOCK_STATUS = 'PENDING' FROM performance_schema.metadata_locks WHERE OBJECT_NAME='t1' AND OWNER_THREAD_ID = $con2_thread_id; --source include/wait_condition.inc # Make sure con2 thread has MDL request in PENDING state. eval SELECT OBJECT_TYPE, OBJECT_NAME, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS FROM performance_schema.metadata_locks WHERE OBJECT_NAME='t1' AND OWNER_THREAD_ID = $con2_thread_id; --enable_query_log # Allow 'default connection' thread to proceed SET DEBUG_SYNC = 'now SIGNAL s2'; --echo # Connection default --connection default --reap --echo # Connection con2 --connection con2 --reap --echo # Connection default --connection default # Make sure Tablespace 'unencryption' is done. SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME LIKE "%encrypt_ts%"; # Make sure table DDL is done. DESCRIBE t1; SHOW CREATE TABLE t1; --echo ########### --echo # Cleanup # --echo ########### --disconnect con2 --disconnect conmon DROP TABLE t1; DROP TABLESPACE encrypt_ts; remove_file $MYSQL_TMP_DIR/mysecret_keyring; --echo # Restarting server without keyring to restore server state let $restart_parameters = restart: ; --source include/restart_mysqld.inc