Skip to content

Commit

Permalink
MDEV-9931: InnoDB reads first page of every .ibd file at startup
Browse files Browse the repository at this point in the history
Analysis: By design InnoDB was reading first page of every .ibd file
at startup to find out is tablespace encrypted or not. This is
because tablespace could have been encrypted always, not
encrypted newer or encrypted based on configuration and this
information can be find realible only from first page of .ibd file.

Fix: Do not read first page of every .ibd file at startup. Instead
whenever tablespace is first time accedded we will read the first
page to find necessary information about tablespace encryption
status.

TODO: Add support for SYS_TABLEOPTIONS where all table options
encryption information included will be stored.
  • Loading branch information
Jan Lindström committed Sep 22, 2016
1 parent e387bfa commit 2bedc39
Show file tree
Hide file tree
Showing 40 changed files with 1,173 additions and 132 deletions.
7 changes: 5 additions & 2 deletions mysql-test/suite/encryption/r/innodb-bad-key-change.result
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,13 @@ SELECT * FROM t1;
ERROR HY000: Got error 192 'Table encrypted but decryption failed. This could be because correct encryption management plugin is not loaded, used encryption key is not available or encryption method does not match.' from InnoDB
SHOW WARNINGS;
Level Code Message
Warning 1812 Tablespace is missing for table 'test/t1'
Warning 192 Table test/t1 is encrypted but encryption service or used key_id 2 is not available. Can't continue reading table.
Warning 192 Table test/t1 in tablespace 6 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
Warning 192 Table test/t1 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
Error 1296 Got error 192 'Table encrypted but decryption failed. This could be because correct encryption management plugin is not loaded, used encryption key is not available or encryption method does not match.' from InnoDB
DROP TABLE t1;
Warnings:
Warning 192 Table in tablespace 6 encrypted.However key management plugin or used key_id 1 is not found or used encryption algorithm or method does not match. Can't continue opening the table.
Warning 192 Table in tablespace 6 encrypted.However key management plugin or used key_id 1 is not found or used encryption algorithm or method does not match. Can't continue opening the table.
# Start server with keys.txt
CREATE TABLE t2 (c VARCHAR(8), id int not null primary key, b int, key(b)) ENGINE=InnoDB ENCRYPTED=YES;
INSERT INTO t2 VALUES ('foobar',1,2);
Expand Down
153 changes: 153 additions & 0 deletions mysql-test/suite/encryption/r/innodb_encryption_row_compressed.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
SET GLOBAL innodb_file_format = `Barracuda`;
SET GLOBAL innodb_file_per_table = ON;
create table innodb_compressed1(c1 bigint not null primary key, d int, a varchar(20), b char(200)) engine=innodb row_format=compressed encrypted=yes;
create table innodb_compressed2(c1 bigint not null primary key, d int, a varchar(20), b char(200)) engine=innodb row_format=compressed key_block_size=1 encrypted=yes;
create table innodb_compressed3(c1 bigint not null primary key, d int, a varchar(20), b char(200)) engine=innodb row_format=compressed key_block_size=2 encrypted=yes;
create table innodb_compressed4(c1 bigint not null primary key, d int, a varchar(20), b char(200)) engine=innodb row_format=compressed key_block_size=4 encrypted=yes;
insert into innodb_compressed1 values (1, 20, 'private', 'evenmoreprivate');
insert into innodb_compressed1 values (2, 20, 'private', 'evenmoreprivate');
insert into innodb_compressed1 values (3, 30, 'private', 'evenmoreprivate');
insert into innodb_compressed1 values (4, 30, 'private', 'evenmoreprivate');
insert into innodb_compressed1 values (5, 30, 'private', 'evenmoreprivate');
insert into innodb_compressed1 values (6, 30, 'private', 'evenmoreprivate');
insert into innodb_compressed1 values (7, 30, 'private', 'evenmoreprivate');
insert into innodb_compressed1 values (8, 20, 'private', 'evenmoreprivate');
insert into innodb_compressed1 values (9, 20, 'private', 'evenmoreprivate');
insert into innodb_compressed1 values (10, 20, 'private', 'evenmoreprivate');
insert into innodb_compressed2 select * from innodb_compressed1;
insert into innodb_compressed3 select * from innodb_compressed1;
insert into innodb_compressed4 select * from innodb_compressed1;
# t1 yes on expecting NOT FOUND
NOT FOUND /private/ in innodb_compressed1.ibd
# t2 yes on expecting NOT FOUND
NOT FOUND /private/ in innodb_compressed2.ibd
# t3 yes on expecting NOT FOUND
NOT FOUND /private/ in innodb_compressed3.ibd
# t4 yes on expecting NOT FOUND
NOT FOUND /private/ in innodb_compressed4.ibd
SET GLOBAL innodb_file_format = `Barracuda`;
SET GLOBAL innodb_file_per_table = ON;
select * from innodb_compressed1 where d = 20;
c1 d a b
1 20 private evenmoreprivate
2 20 private evenmoreprivate
8 20 private evenmoreprivate
9 20 private evenmoreprivate
10 20 private evenmoreprivate
select * from innodb_compressed1 where d = 30;
c1 d a b
3 30 private evenmoreprivate
4 30 private evenmoreprivate
5 30 private evenmoreprivate
6 30 private evenmoreprivate
7 30 private evenmoreprivate
select * from innodb_compressed2 where d = 20;
c1 d a b
1 20 private evenmoreprivate
2 20 private evenmoreprivate
8 20 private evenmoreprivate
9 20 private evenmoreprivate
10 20 private evenmoreprivate
select * from innodb_compressed2 where d = 30;
c1 d a b
3 30 private evenmoreprivate
4 30 private evenmoreprivate
5 30 private evenmoreprivate
6 30 private evenmoreprivate
7 30 private evenmoreprivate
select * from innodb_compressed3 where d = 20;
c1 d a b
1 20 private evenmoreprivate
2 20 private evenmoreprivate
8 20 private evenmoreprivate
9 20 private evenmoreprivate
10 20 private evenmoreprivate
select * from innodb_compressed3 where d = 30;
c1 d a b
3 30 private evenmoreprivate
4 30 private evenmoreprivate
5 30 private evenmoreprivate
6 30 private evenmoreprivate
7 30 private evenmoreprivate
select * from innodb_compressed4 where d = 20;
c1 d a b
1 20 private evenmoreprivate
2 20 private evenmoreprivate
8 20 private evenmoreprivate
9 20 private evenmoreprivate
10 20 private evenmoreprivate
select * from innodb_compressed4 where d = 30;
c1 d a b
3 30 private evenmoreprivate
4 30 private evenmoreprivate
5 30 private evenmoreprivate
6 30 private evenmoreprivate
7 30 private evenmoreprivate
update innodb_compressed1 set d = d + 10 where d = 30;
update innodb_compressed2 set d = d + 10 where d = 30;
update innodb_compressed3 set d = d + 10 where d = 30;
update innodb_compressed4 set d = d + 10 where d = 30;
insert into innodb_compressed1 values (20, 60, 'newprivate', 'newevenmoreprivate');
insert into innodb_compressed2 values (20, 60, 'newprivate', 'newevenmoreprivate');
insert into innodb_compressed3 values (20, 60, 'newprivate', 'newevenmoreprivate');
insert into innodb_compressed4 values (20, 60, 'newprivate', 'newevenmoreprivate');
# t1 yes on expecting NOT FOUND
NOT FOUND /private/ in innodb_compressed1.ibd
# t2 yes on expecting NOT FOUND
NOT FOUND /private/ in innodb_compressed2.ibd
# t3 yes on expecting NOT FOUND
NOT FOUND /private/ in innodb_compressed3.ibd
# t4 yes on expecting NOT FOUND
NOT FOUND /private/ in innodb_compressed4.ibd
select * from innodb_compressed1 where d = 40;
c1 d a b
3 40 private evenmoreprivate
4 40 private evenmoreprivate
5 40 private evenmoreprivate
6 40 private evenmoreprivate
7 40 private evenmoreprivate
select * from innodb_compressed1 where d = 60;
c1 d a b
20 60 newprivate newevenmoreprivate
select * from innodb_compressed2 where d = 40;
c1 d a b
3 40 private evenmoreprivate
4 40 private evenmoreprivate
5 40 private evenmoreprivate
6 40 private evenmoreprivate
7 40 private evenmoreprivate
select * from innodb_compressed2 where d = 60;
c1 d a b
20 60 newprivate newevenmoreprivate
select * from innodb_compressed3 where d = 40;
c1 d a b
3 40 private evenmoreprivate
4 40 private evenmoreprivate
5 40 private evenmoreprivate
6 40 private evenmoreprivate
7 40 private evenmoreprivate
select * from innodb_compressed3 where d = 60;
c1 d a b
20 60 newprivate newevenmoreprivate
select * from innodb_compressed4 where d = 40;
c1 d a b
3 40 private evenmoreprivate
4 40 private evenmoreprivate
5 40 private evenmoreprivate
6 40 private evenmoreprivate
7 40 private evenmoreprivate
select * from innodb_compressed4 where d = 60;
c1 d a b
20 60 newprivate newevenmoreprivate
# t1 yes on expecting NOT FOUND
NOT FOUND /private/ in innodb_compressed1.ibd
# t2 yes on expecting NOT FOUND
NOT FOUND /private/ in innodb_compressed2.ibd
# t3 yes on expecting NOT FOUND
NOT FOUND /private/ in innodb_compressed3.ibd
# t4 yes on expecting NOT FOUND
NOT FOUND /private/ in innodb_compressed4.ibd
drop table innodb_compressed1;
drop table innodb_compressed2;
drop table innodb_compressed3;
drop table innodb_compressed4;
154 changes: 154 additions & 0 deletions mysql-test/suite/encryption/r/innodb_lotoftables.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
SET GLOBAL innodb_file_format = `Barracuda`;
SET GLOBAL innodb_file_per_table = ON;
SHOW VARIABLES LIKE 'innodb_encrypt%';
Variable_name Value
innodb_encrypt_log OFF
innodb_encrypt_tables OFF
innodb_encryption_rotate_key_age 1
innodb_encryption_rotation_iops 100
innodb_encryption_threads 0
create database innodb_encrypted_1;
use innodb_encrypted_1;
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 1
set autocommit=0;
set autocommit=1;
commit work;
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 1
# should be 100
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE NAME LIKE 'innodb_encrypted%';
COUNT(*)
100
create database innodb_encrypted_2;
use innodb_encrypted_2;
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 3
set autocommit=0;
commit work;
set autocommit=1;
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 3
# should be 100
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND NAME LIKE 'innodb_encrypted%';
COUNT(*)
100
# should be 100
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND NAME LIKE 'innodb_encrypted%';
COUNT(*)
100
create database innodb_encrypted_3;
use innodb_encrypted_3;
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 3
set autocommit=0;
commit work;
set autocommit=1;
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 3
# should be 100
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND NAME LIKE 'innodb_encrypted%';
COUNT(*)
100
# should be 200
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND NAME LIKE 'innodb_encrypted%';
COUNT(*)
200
use test;
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 3
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND NAME LIKE 'innodb_encrypted%';
COUNT(*)
100
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND NAME LIKE 'innodb_encrypted%';
COUNT(*)
200
SET GLOBAL innodb_encrypt_tables = on;
SET GLOBAL innodb_encryption_threads=4;
# Wait until all encrypted tables have been encrypted
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND NAME LIKE 'innodb_encrypted%';
COUNT(*)
200
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND NAME LIKE 'innodb_encrypted%';
COUNT(*)
100
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 3
# Success!
# Restart mysqld --innodb_encrypt_tables=0 --innodb_encryption_threads=0
# Restart Success!
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 3
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 3
use test;
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 3
use innodb_encrypted_1;
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 3
use innodb_encrypted_2;
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 3
use innodb_encrypted_3;
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 3
use innodb_encrypted_1;
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 3
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 103
use innodb_encrypted_2;
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 103
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 203
use innodb_encrypted_3;
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 203
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 203
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND NAME LIKE 'innodb_encrypted%';
COUNT(*)
100
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND NAME LIKE 'innodb_encrypted%';
COUNT(*)
200
SET GLOBAL innodb_encrypt_tables = off;
SET GLOBAL innodb_encryption_threads=4;
# Wait until all default encrypted tables have been decrypted
# should be 100
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND NAME LIKE 'innodb_encrypted%';
COUNT(*)
100
# should be 200
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND NAME LIKE 'innodb_encrypted%';
COUNT(*)
200
show status like 'innodb_pages0_read%';
Variable_name Value
Innodb_pages0_read 303
use test;
drop database innodb_encrypted_1;
drop database innodb_encrypted_2;
drop database innodb_encrypted_3;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
--innodb-encrypt-tables=ON
--innodb-encryption-rotate-key-age=15
--innodb-encryption-threads=4
--innodb-tablespaces-encryption
Loading

0 comments on commit 2bedc39

Please sign in to comment.