Skip to content

Commit 2bedc39

Browse files
author
Jan Lindström
committed
MDEV-9931: InnoDB reads first page of every .ibd file at startup
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.
1 parent e387bfa commit 2bedc39

40 files changed

+1173
-132
lines changed

mysql-test/suite/encryption/r/innodb-bad-key-change.result

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,13 @@ SELECT * FROM t1;
3636
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
3737
SHOW WARNINGS;
3838
Level Code Message
39-
Warning 1812 Tablespace is missing for table 'test/t1'
40-
Warning 192 Table test/t1 is encrypted but encryption service or used key_id 2 is not available. Can't continue reading table.
39+
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.
40+
Warning 192 Table test/t1 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
4141
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
4242
DROP TABLE t1;
43+
Warnings:
44+
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.
45+
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.
4346
# Start server with keys.txt
4447
CREATE TABLE t2 (c VARCHAR(8), id int not null primary key, b int, key(b)) ENGINE=InnoDB ENCRYPTED=YES;
4548
INSERT INTO t2 VALUES ('foobar',1,2);
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
SET GLOBAL innodb_file_format = `Barracuda`;
2+
SET GLOBAL innodb_file_per_table = ON;
3+
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;
4+
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;
5+
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;
6+
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;
7+
insert into innodb_compressed1 values (1, 20, 'private', 'evenmoreprivate');
8+
insert into innodb_compressed1 values (2, 20, 'private', 'evenmoreprivate');
9+
insert into innodb_compressed1 values (3, 30, 'private', 'evenmoreprivate');
10+
insert into innodb_compressed1 values (4, 30, 'private', 'evenmoreprivate');
11+
insert into innodb_compressed1 values (5, 30, 'private', 'evenmoreprivate');
12+
insert into innodb_compressed1 values (6, 30, 'private', 'evenmoreprivate');
13+
insert into innodb_compressed1 values (7, 30, 'private', 'evenmoreprivate');
14+
insert into innodb_compressed1 values (8, 20, 'private', 'evenmoreprivate');
15+
insert into innodb_compressed1 values (9, 20, 'private', 'evenmoreprivate');
16+
insert into innodb_compressed1 values (10, 20, 'private', 'evenmoreprivate');
17+
insert into innodb_compressed2 select * from innodb_compressed1;
18+
insert into innodb_compressed3 select * from innodb_compressed1;
19+
insert into innodb_compressed4 select * from innodb_compressed1;
20+
# t1 yes on expecting NOT FOUND
21+
NOT FOUND /private/ in innodb_compressed1.ibd
22+
# t2 yes on expecting NOT FOUND
23+
NOT FOUND /private/ in innodb_compressed2.ibd
24+
# t3 yes on expecting NOT FOUND
25+
NOT FOUND /private/ in innodb_compressed3.ibd
26+
# t4 yes on expecting NOT FOUND
27+
NOT FOUND /private/ in innodb_compressed4.ibd
28+
SET GLOBAL innodb_file_format = `Barracuda`;
29+
SET GLOBAL innodb_file_per_table = ON;
30+
select * from innodb_compressed1 where d = 20;
31+
c1 d a b
32+
1 20 private evenmoreprivate
33+
2 20 private evenmoreprivate
34+
8 20 private evenmoreprivate
35+
9 20 private evenmoreprivate
36+
10 20 private evenmoreprivate
37+
select * from innodb_compressed1 where d = 30;
38+
c1 d a b
39+
3 30 private evenmoreprivate
40+
4 30 private evenmoreprivate
41+
5 30 private evenmoreprivate
42+
6 30 private evenmoreprivate
43+
7 30 private evenmoreprivate
44+
select * from innodb_compressed2 where d = 20;
45+
c1 d a b
46+
1 20 private evenmoreprivate
47+
2 20 private evenmoreprivate
48+
8 20 private evenmoreprivate
49+
9 20 private evenmoreprivate
50+
10 20 private evenmoreprivate
51+
select * from innodb_compressed2 where d = 30;
52+
c1 d a b
53+
3 30 private evenmoreprivate
54+
4 30 private evenmoreprivate
55+
5 30 private evenmoreprivate
56+
6 30 private evenmoreprivate
57+
7 30 private evenmoreprivate
58+
select * from innodb_compressed3 where d = 20;
59+
c1 d a b
60+
1 20 private evenmoreprivate
61+
2 20 private evenmoreprivate
62+
8 20 private evenmoreprivate
63+
9 20 private evenmoreprivate
64+
10 20 private evenmoreprivate
65+
select * from innodb_compressed3 where d = 30;
66+
c1 d a b
67+
3 30 private evenmoreprivate
68+
4 30 private evenmoreprivate
69+
5 30 private evenmoreprivate
70+
6 30 private evenmoreprivate
71+
7 30 private evenmoreprivate
72+
select * from innodb_compressed4 where d = 20;
73+
c1 d a b
74+
1 20 private evenmoreprivate
75+
2 20 private evenmoreprivate
76+
8 20 private evenmoreprivate
77+
9 20 private evenmoreprivate
78+
10 20 private evenmoreprivate
79+
select * from innodb_compressed4 where d = 30;
80+
c1 d a b
81+
3 30 private evenmoreprivate
82+
4 30 private evenmoreprivate
83+
5 30 private evenmoreprivate
84+
6 30 private evenmoreprivate
85+
7 30 private evenmoreprivate
86+
update innodb_compressed1 set d = d + 10 where d = 30;
87+
update innodb_compressed2 set d = d + 10 where d = 30;
88+
update innodb_compressed3 set d = d + 10 where d = 30;
89+
update innodb_compressed4 set d = d + 10 where d = 30;
90+
insert into innodb_compressed1 values (20, 60, 'newprivate', 'newevenmoreprivate');
91+
insert into innodb_compressed2 values (20, 60, 'newprivate', 'newevenmoreprivate');
92+
insert into innodb_compressed3 values (20, 60, 'newprivate', 'newevenmoreprivate');
93+
insert into innodb_compressed4 values (20, 60, 'newprivate', 'newevenmoreprivate');
94+
# t1 yes on expecting NOT FOUND
95+
NOT FOUND /private/ in innodb_compressed1.ibd
96+
# t2 yes on expecting NOT FOUND
97+
NOT FOUND /private/ in innodb_compressed2.ibd
98+
# t3 yes on expecting NOT FOUND
99+
NOT FOUND /private/ in innodb_compressed3.ibd
100+
# t4 yes on expecting NOT FOUND
101+
NOT FOUND /private/ in innodb_compressed4.ibd
102+
select * from innodb_compressed1 where d = 40;
103+
c1 d a b
104+
3 40 private evenmoreprivate
105+
4 40 private evenmoreprivate
106+
5 40 private evenmoreprivate
107+
6 40 private evenmoreprivate
108+
7 40 private evenmoreprivate
109+
select * from innodb_compressed1 where d = 60;
110+
c1 d a b
111+
20 60 newprivate newevenmoreprivate
112+
select * from innodb_compressed2 where d = 40;
113+
c1 d a b
114+
3 40 private evenmoreprivate
115+
4 40 private evenmoreprivate
116+
5 40 private evenmoreprivate
117+
6 40 private evenmoreprivate
118+
7 40 private evenmoreprivate
119+
select * from innodb_compressed2 where d = 60;
120+
c1 d a b
121+
20 60 newprivate newevenmoreprivate
122+
select * from innodb_compressed3 where d = 40;
123+
c1 d a b
124+
3 40 private evenmoreprivate
125+
4 40 private evenmoreprivate
126+
5 40 private evenmoreprivate
127+
6 40 private evenmoreprivate
128+
7 40 private evenmoreprivate
129+
select * from innodb_compressed3 where d = 60;
130+
c1 d a b
131+
20 60 newprivate newevenmoreprivate
132+
select * from innodb_compressed4 where d = 40;
133+
c1 d a b
134+
3 40 private evenmoreprivate
135+
4 40 private evenmoreprivate
136+
5 40 private evenmoreprivate
137+
6 40 private evenmoreprivate
138+
7 40 private evenmoreprivate
139+
select * from innodb_compressed4 where d = 60;
140+
c1 d a b
141+
20 60 newprivate newevenmoreprivate
142+
# t1 yes on expecting NOT FOUND
143+
NOT FOUND /private/ in innodb_compressed1.ibd
144+
# t2 yes on expecting NOT FOUND
145+
NOT FOUND /private/ in innodb_compressed2.ibd
146+
# t3 yes on expecting NOT FOUND
147+
NOT FOUND /private/ in innodb_compressed3.ibd
148+
# t4 yes on expecting NOT FOUND
149+
NOT FOUND /private/ in innodb_compressed4.ibd
150+
drop table innodb_compressed1;
151+
drop table innodb_compressed2;
152+
drop table innodb_compressed3;
153+
drop table innodb_compressed4;
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
SET GLOBAL innodb_file_format = `Barracuda`;
2+
SET GLOBAL innodb_file_per_table = ON;
3+
SHOW VARIABLES LIKE 'innodb_encrypt%';
4+
Variable_name Value
5+
innodb_encrypt_log OFF
6+
innodb_encrypt_tables OFF
7+
innodb_encryption_rotate_key_age 1
8+
innodb_encryption_rotation_iops 100
9+
innodb_encryption_threads 0
10+
create database innodb_encrypted_1;
11+
use innodb_encrypted_1;
12+
show status like 'innodb_pages0_read%';
13+
Variable_name Value
14+
Innodb_pages0_read 1
15+
set autocommit=0;
16+
set autocommit=1;
17+
commit work;
18+
show status like 'innodb_pages0_read%';
19+
Variable_name Value
20+
Innodb_pages0_read 1
21+
# should be 100
22+
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE NAME LIKE 'innodb_encrypted%';
23+
COUNT(*)
24+
100
25+
create database innodb_encrypted_2;
26+
use innodb_encrypted_2;
27+
show status like 'innodb_pages0_read%';
28+
Variable_name Value
29+
Innodb_pages0_read 3
30+
set autocommit=0;
31+
commit work;
32+
set autocommit=1;
33+
show status like 'innodb_pages0_read%';
34+
Variable_name Value
35+
Innodb_pages0_read 3
36+
# should be 100
37+
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND NAME LIKE 'innodb_encrypted%';
38+
COUNT(*)
39+
100
40+
# should be 100
41+
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND NAME LIKE 'innodb_encrypted%';
42+
COUNT(*)
43+
100
44+
create database innodb_encrypted_3;
45+
use innodb_encrypted_3;
46+
show status like 'innodb_pages0_read%';
47+
Variable_name Value
48+
Innodb_pages0_read 3
49+
set autocommit=0;
50+
commit work;
51+
set autocommit=1;
52+
show status like 'innodb_pages0_read%';
53+
Variable_name Value
54+
Innodb_pages0_read 3
55+
# should be 100
56+
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND NAME LIKE 'innodb_encrypted%';
57+
COUNT(*)
58+
100
59+
# should be 200
60+
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND NAME LIKE 'innodb_encrypted%';
61+
COUNT(*)
62+
200
63+
use test;
64+
show status like 'innodb_pages0_read%';
65+
Variable_name Value
66+
Innodb_pages0_read 3
67+
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND NAME LIKE 'innodb_encrypted%';
68+
COUNT(*)
69+
100
70+
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND NAME LIKE 'innodb_encrypted%';
71+
COUNT(*)
72+
200
73+
SET GLOBAL innodb_encrypt_tables = on;
74+
SET GLOBAL innodb_encryption_threads=4;
75+
# Wait until all encrypted tables have been encrypted
76+
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND NAME LIKE 'innodb_encrypted%';
77+
COUNT(*)
78+
200
79+
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND NAME LIKE 'innodb_encrypted%';
80+
COUNT(*)
81+
100
82+
show status like 'innodb_pages0_read%';
83+
Variable_name Value
84+
Innodb_pages0_read 3
85+
# Success!
86+
# Restart mysqld --innodb_encrypt_tables=0 --innodb_encryption_threads=0
87+
# Restart Success!
88+
show status like 'innodb_pages0_read%';
89+
Variable_name Value
90+
Innodb_pages0_read 3
91+
show status like 'innodb_pages0_read%';
92+
Variable_name Value
93+
Innodb_pages0_read 3
94+
use test;
95+
show status like 'innodb_pages0_read%';
96+
Variable_name Value
97+
Innodb_pages0_read 3
98+
use innodb_encrypted_1;
99+
show status like 'innodb_pages0_read%';
100+
Variable_name Value
101+
Innodb_pages0_read 3
102+
use innodb_encrypted_2;
103+
show status like 'innodb_pages0_read%';
104+
Variable_name Value
105+
Innodb_pages0_read 3
106+
use innodb_encrypted_3;
107+
show status like 'innodb_pages0_read%';
108+
Variable_name Value
109+
Innodb_pages0_read 3
110+
use innodb_encrypted_1;
111+
show status like 'innodb_pages0_read%';
112+
Variable_name Value
113+
Innodb_pages0_read 3
114+
show status like 'innodb_pages0_read%';
115+
Variable_name Value
116+
Innodb_pages0_read 103
117+
use innodb_encrypted_2;
118+
show status like 'innodb_pages0_read%';
119+
Variable_name Value
120+
Innodb_pages0_read 103
121+
show status like 'innodb_pages0_read%';
122+
Variable_name Value
123+
Innodb_pages0_read 203
124+
use innodb_encrypted_3;
125+
show status like 'innodb_pages0_read%';
126+
Variable_name Value
127+
Innodb_pages0_read 203
128+
show status like 'innodb_pages0_read%';
129+
Variable_name Value
130+
Innodb_pages0_read 203
131+
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND NAME LIKE 'innodb_encrypted%';
132+
COUNT(*)
133+
100
134+
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND NAME LIKE 'innodb_encrypted%';
135+
COUNT(*)
136+
200
137+
SET GLOBAL innodb_encrypt_tables = off;
138+
SET GLOBAL innodb_encryption_threads=4;
139+
# Wait until all default encrypted tables have been decrypted
140+
# should be 100
141+
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND NAME LIKE 'innodb_encrypted%';
142+
COUNT(*)
143+
100
144+
# should be 200
145+
SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND NAME LIKE 'innodb_encrypted%';
146+
COUNT(*)
147+
200
148+
show status like 'innodb_pages0_read%';
149+
Variable_name Value
150+
Innodb_pages0_read 303
151+
use test;
152+
drop database innodb_encrypted_1;
153+
drop database innodb_encrypted_2;
154+
drop database innodb_encrypted_3;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
--innodb-encrypt-tables=ON
2+
--innodb-encryption-rotate-key-age=15
3+
--innodb-encryption-threads=4
4+
--innodb-tablespaces-encryption

0 commit comments

Comments
 (0)