Commit 509b8366 authored by Jan Lindström's avatar Jan Lindström

MDEV-8708: InnoDB temp file encryption

Added encryption support for online alter table where InnoDB temporary
files are used. Added similar support also for tables containing
full text-indexes.

Made sure that table remains encrypted during discard and import
tablespace.
parent 42574427
SET GLOBAL innodb_file_format = `Barracuda`;
SET GLOBAL innodb_file_per_table = ON;
CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY, a VARCHAR(255)) ENGINE=InnoDB encrypted=yes;
CREATE TABLE t2 (id INT NOT NULL PRIMARY KEY, a VARCHAR(255)) ENGINE=InnoDB;
CREATE TABLE t3 (id INT NOT NULL PRIMARY KEY, a VARCHAR(255)) ENGINE=InnoDB row_format=compressed encrypted=yes;
create procedure innodb_insert_proc (repeat_count int)
begin
declare current_num int;
set current_num = 0;
while current_num < repeat_count do
insert into t1 values (current_num,repeat('foobar',42));
insert into t2 values (current_num,repeat('temp', 42));
insert into t3 values (current_num,repeat('barfoo',42));
set current_num = current_num + 1;
end while;
end//
commit;
set autocommit=0;
call innodb_insert_proc(10000);
commit;
set autocommit=1;
# Wait max 10 min for key encryption threads to encrypt all spaces
# tablespaces should be now encrypted
# t1 yes on expecting NOT FOUND
NOT FOUND /foobar/ in t1.ibd
# t2 ... on expecting NOT FOUND
NOT FOUND /temp/ in t2.ibd
# t3 ... on expecting NOT FOUND
NOT FOUND /barfoo/ in t3.ibd
FLUSH TABLE t1, t2, t3 FOR EXPORT;
# List before copying files
t1.cfg
t1.frm
t1.ibd
t2.cfg
t2.frm
t2.ibd
t3.cfg
t3.frm
t3.ibd
UNLOCK TABLES;
# Restarting server
# Done restarting server
# List before t1 DISCARD
t1.frm
t1.ibd
t2.frm
t2.ibd
t3.frm
t3.ibd
SET GLOBAL innodb_file_format = `Barracuda`;
SET GLOBAL innodb_file_per_table = ON;
ALTER TABLE t1 DISCARD TABLESPACE;
ALTER TABLE t2 DISCARD TABLESPACE;
ALTER TABLE t3 DISCARD TABLESPACE;
# Discarded tablespaces should be encrypted
# t1 yes on expecting NOT FOUND
NOT FOUND /foobar/ in t1.ibd
# t2 ... on expecting NOT FOUND
NOT FOUND /temp/ in t2.ibd
# t3 ... on expecting NOT FOUND
NOT FOUND /barfoo/ in t3.ibd
# List after t1 DISCARD
t1.frm
t2.frm
t3.frm
# Tablespaces should be still encrypted
# t1 yes on expecting NOT FOUND
NOT FOUND /foobar/ in t1.ibd
# t2 ... on expecting NOT FOUND
NOT FOUND /temp/ in t2.ibd
# t3 ... on expecting NOT FOUND
NOT FOUND /barfoo/ in t3.ibd
ALTER TABLE t1 IMPORT TABLESPACE;
ALTER TABLE t2 IMPORT TABLESPACE;
ALTER TABLE t3 IMPORT TABLESPACE;
# tablespaces should remain encrypted after import
# t1 yes on expecting NOT FOUND
NOT FOUND /foobar/ in t1.ibd
# t2 ... on expecting NOT FOUND
NOT FOUND /temp/ in t2.ibd
# t3 ... on expecting NOT FOUND
NOT FOUND /barfoo/ in t3.ibd
ALTER TABLE t1 ENGINE InnoDB;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`id` int(11) NOT NULL,
`a` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 `encrypted`=yes
ALTER TABLE t2 ENGINE InnoDB;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`id` int(11) NOT NULL,
`a` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
ALTER TABLE t3 ENGINE InnoDB;
SHOW CREATE TABLE t3;
Table Create Table
t3 CREATE TABLE `t3` (
`id` int(11) NOT NULL,
`a` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED `encrypted`=yes
# Wait max 10 min for key encryption threads to encrypt all spaces
# Tablespaces should be encrypted after alter table
# t1 yes on expecting NOT FOUND
NOT FOUND /foobar/ in t1.ibd
# t2 ... on expecting NOT FOUND
NOT FOUND /temp/ in t2.ibd
# t3 ... on expecting NOT FOUND
NOT FOUND /barfoo/ in t3.ibd
# Restarting server
# Done restarting server
# Verify that tables are still usable
SELECT COUNT(1) FROM t1;
COUNT(1)
10000
SELECT COUNT(1) FROM t2;
COUNT(1)
10000
SELECT COUNT(1) FROM t3;
COUNT(1)
10000
# Tablespaces should be encrypted after restart
# t1 yes on expecting NOT FOUND
NOT FOUND /foobar/ in t1.ibd
# t2 ... on expecting NOT FOUND
NOT FOUND /temp/ in t2.ibd
# t3 ... on expecting NOT FOUND
NOT FOUND /barfoo/ in t3.ibd
DROP PROCEDURE innodb_insert_proc;
DROP TABLE t1, t2, t3;
SET GLOBAL innodb_file_format = `Barracuda`;
SET GLOBAL innodb_file_per_table = ON;
CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY, a VARCHAR(255)) ENGINE=InnoDB encrypted=yes;
CREATE TABLE t2 (id INT NOT NULL PRIMARY KEY, a VARCHAR(255)) ENGINE=InnoDB;
CREATE TABLE t3 (id INT, a VARCHAR(255)) ENGINE=InnoDB encrypted=yes;
CREATE TABLE t4 (id INT, a VARCHAR(255)) engine=InnoDB;
CREATE TABLE t5 (id INT NOT NULL PRIMARY KEY, a TEXT(500), b VARCHAR(255), FULLTEXT(b)) ENGINE=InnoDB encrypted=yes;
CREATE TABLE t6 (id INT, a TEXT(500), b VARCHAR(255), FULLTEXT(b)) ENGINE=InnoDB;
CREATE TABLE t7 (id INT NOT NULL PRIMARY KEY, a VARCHAR(255)) ENGINE=InnoDB row_format=compressed encrypted=yes;
create procedure innodb_insert_proc (repeat_count int)
begin
declare current_num int;
set current_num = 0;
while current_num < repeat_count do
insert into t1 values (current_num,repeat('foobar',42));
insert into t2 values (current_num,repeat('temp', 42));
insert into t3 values (current_num,repeat('barfoo',42));
insert into t4 values (current_num,repeat('repeat',42));
insert into t5 values (current_num,substring('A BC DEF GHIJ KLM NOPQRS TUV WXYZ 012 3456789', rand()*36+1, 100), repeat('author new',22));
insert into t6 values (current_num,substring('A BC DEF GHIJ KLM NOPQRS TUV WXYZ 012 3456789', rand()*36+1, 100), repeat('mangled old',22));
insert into t7 values (current_num,repeat('mysql',42));
set current_num = current_num + 1;
end while;
end//
commit;
set autocommit=0;
call innodb_insert_proc(15000);
commit;
set autocommit=1;
# Wait max 10 min for key encryption threads to encrypt all spaces
# t1 yes on expecting NOT FOUND
NOT FOUND /foobar/ in t1.ibd
# t2 ... on expecting NOT FOUND
NOT FOUND /temp/ in t2.ibd
# t3 ... on expecting NOT FOUND
NOT FOUND /barfoo/ in t3.ibd
# t4 ... on expecting NOT FOUND
NOT FOUND /repeat/ in t4.ibd
# t5 ... on expecting NOT FOUND
NOT FOUND /author/ in t5.ibd
# t6 ... on expecting NOT FOUND
NOT FOUND /mangled/ in t6.ibd
# t7 ... on expecting NOT FOUND
NOT FOUND /mysql/ in t7.ibd
ALTER TABLE t1 ADD COLUMN b int default 2;
ALTER TABLE t2 ADD COLUMN b int default 2;
ALTER TABLE t7 ADD COLUMN b int default 2;
ALTER TABLE t1 ADD KEY a(a), ADD KEY b(b);
ALTER TABLE t2 ADD KEY a(a), ADD KEY b(b);
ALTER TABLE t3 ADD COLUMN c int default 5;
ALTER TABLE t4 ADD COLUMN c int default 5;
ALTER TABLE t3 ADD KEY (a), ADD KEY c(c);
ALTER TABLE t4 ADD KEY (a), ADD KEY c(c);
ALTER TABLE t5 ADD FULLTEXT(a);
ALTER TABLE t6 ADD FULLTEXT(a);
ALTER TABLE t7 ADD KEY a(a), ADD key b(b);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`id` int(11) NOT NULL,
`a` varchar(255) DEFAULT NULL,
`b` int(11) DEFAULT '2',
PRIMARY KEY (`id`),
KEY `a` (`a`),
KEY `b` (`b`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 `encrypted`=yes
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`id` int(11) NOT NULL,
`a` varchar(255) DEFAULT NULL,
`b` int(11) DEFAULT '2',
PRIMARY KEY (`id`),
KEY `a` (`a`),
KEY `b` (`b`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
SHOW CREATE TABLE t3;
Table Create Table
t3 CREATE TABLE `t3` (
`id` int(11) DEFAULT NULL,
`a` varchar(255) DEFAULT NULL,
`c` int(11) DEFAULT '5',
KEY `a` (`a`),
KEY `c` (`c`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 `encrypted`=yes
SHOW CREATE TABLE t4;
Table Create Table
t4 CREATE TABLE `t4` (
`id` int(11) DEFAULT NULL,
`a` varchar(255) DEFAULT NULL,
`c` int(11) DEFAULT '5',
KEY `a` (`a`),
KEY `c` (`c`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
SHOW CREATE TABLE t5;
Table Create Table
t5 CREATE TABLE `t5` (
`id` int(11) NOT NULL,
`a` text,
`b` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
FULLTEXT KEY `b` (`b`),
FULLTEXT KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 `encrypted`=yes
SHOW CREATE TABLE t6;
Table Create Table
t6 CREATE TABLE `t6` (
`id` int(11) DEFAULT NULL,
`a` text,
`b` varchar(255) DEFAULT NULL,
FULLTEXT KEY `b` (`b`),
FULLTEXT KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
SHOW CREATE TABLE t7;
Table Create Table
t7 CREATE TABLE `t7` (
`id` int(11) NOT NULL,
`a` varchar(255) DEFAULT NULL,
`b` int(11) DEFAULT '2',
PRIMARY KEY (`id`),
KEY `a` (`a`),
KEY `b` (`b`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED `encrypted`=yes
# t1 yes on expecting NOT FOUND
NOT FOUND /foobar/ in t1.ibd
# t2 ... on expecting NOT FOUND
NOT FOUND /temp/ in t2.ibd
# t3 ... on expecting NOT FOUND
NOT FOUND /barfoo/ in t3.ibd
# t4 ... on expecting NOT FOUND
NOT FOUND /repeat/ in t4.ibd
# t5 ... on expecting NOT FOUND
NOT FOUND /author/ in t5.ibd
# t6 ... on expecting NOT FOUND
NOT FOUND /mangled/ in t6.ibd
# t7 ... on expecting NOT FOUND
NOT FOUND /mysql/ in t7.ibd
# Restarting server
# Done restarting server
select count(1) from t1;
count(1)
15000
select count(1) from t2;
count(1)
15000
select count(1) from t3;
count(1)
15000
select count(1) from t4;
count(1)
15000
select count(1) from t5;
count(1)
15000
select count(1) from t6;
count(1)
15000
select count(1) from t7;
count(1)
15000
# t1 yes on expecting NOT FOUND
NOT FOUND /foobar/ in t1.ibd
# t2 ... on expecting NOT FOUND
NOT FOUND /temp/ in t2.ibd
# t3 ... on expecting NOT FOUND
NOT FOUND /barfoo/ in t3.ibd
# t4 ... on expecting NOT FOUND
NOT FOUND /repeat/ in t4.ibd
# t5 ... on expecting NOT FOUND
NOT FOUND /author/ in t5.ibd
# t6 ... on expecting NOT FOUND
NOT FOUND /mangled/ in t6.ibd
# t7 ... on expecting NOT FOUND
NOT FOUND /mysql/ in t7.ibd
DROP PROCEDURE innodb_insert_proc;
DROP TABLE t1, t2, t3, t4, t5, t6, t7;
--innodb-encrypt-tables=ON
--innodb-encrypt-log=ON
--innodb-encryption-rotate-key-age=15
--innodb-encryption-threads=4
--innodb-tablespaces-encryption
--innodb-max-dirty-pages-pct=0.001
-- source include/have_innodb.inc
-- source include/have_example_key_management_plugin.inc
-- source include/not_valgrind.inc
-- source include/not_embedded.inc
-- source include/not_windows.inc
--let $MYSQLD_TMPDIR = `SELECT @@tmpdir`
--let $MYSQLD_DATADIR = `SELECT @@datadir`
--let SEARCH_RANGE = 10000000
--let t1_IBD = $MYSQLD_DATADIR/test/t1.ibd
--let t2_IBD = $MYSQLD_DATADIR/test/t2.ibd
--let t3_IBD = $MYSQLD_DATADIR/test/t3.ibd
--let t1_IBD_1 = $MYSQLD_TMPDIR/t1.ibd
--let t2_IBD_1 = $MYSQLD_TMPDIR/t2.ibd
--let t3_IBD_1 = $MYSQLD_TMPDIR/t3.ibd
--disable_query_log
let $innodb_file_format_orig = `SELECT @@innodb_file_format`;
let $innodb_file_per_table_orig = `SELECT @@innodb_file_per_table`;
--enable_query_log
SET GLOBAL innodb_file_format = `Barracuda`;
SET GLOBAL innodb_file_per_table = ON;
CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY, a VARCHAR(255)) ENGINE=InnoDB encrypted=yes;
CREATE TABLE t2 (id INT NOT NULL PRIMARY KEY, a VARCHAR(255)) ENGINE=InnoDB;
CREATE TABLE t3 (id INT NOT NULL PRIMARY KEY, a VARCHAR(255)) ENGINE=InnoDB row_format=compressed encrypted=yes;
delimiter //;
create procedure innodb_insert_proc (repeat_count int)
begin
declare current_num int;
set current_num = 0;
while current_num < repeat_count do
insert into t1 values (current_num,repeat('foobar',42));
insert into t2 values (current_num,repeat('temp', 42));
insert into t3 values (current_num,repeat('barfoo',42));
set current_num = current_num + 1;
end while;
end//
delimiter ;//
commit;
set autocommit=0;
call innodb_insert_proc(10000);
commit;
set autocommit=1;
--echo # Wait max 10 min for key encryption threads to encrypt all spaces
--let $wait_timeout= 600
--let $wait_condition=SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0
--source include/wait_condition.inc
--sleep 5
--echo # tablespaces should be now encrypted
--let SEARCH_PATTERN=foobar
--echo # t1 yes on expecting NOT FOUND
-- let SEARCH_FILE=$t1_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=temp
--echo # t2 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t2_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=barfoo
--echo # t3 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t3_IBD
-- source include/search_pattern_in_file.inc
FLUSH TABLE t1, t2, t3 FOR EXPORT;
--echo # List before copying files
--list_files $MYSQLD_DATADIR/test
--copy_file $MYSQLD_DATADIR/test/t1.cfg $MYSQLD_TMPDIR/t1.cfg
--copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_TMPDIR/t1.ibd
--copy_file $MYSQLD_DATADIR/test/t2.cfg $MYSQLD_TMPDIR/t2.cfg
--copy_file $MYSQLD_DATADIR/test/t2.ibd $MYSQLD_TMPDIR/t2.ibd
--copy_file $MYSQLD_DATADIR/test/t3.cfg $MYSQLD_TMPDIR/t3.cfg
--copy_file $MYSQLD_DATADIR/test/t3.ibd $MYSQLD_TMPDIR/t3.ibd
UNLOCK TABLES;
--echo # Restarting server
-- source include/restart_mysqld.inc
--echo # Done restarting server
--echo # List before t1 DISCARD
--list_files $MYSQLD_DATADIR/test
SET GLOBAL innodb_file_format = `Barracuda`;
SET GLOBAL innodb_file_per_table = ON;
ALTER TABLE t1 DISCARD TABLESPACE;
ALTER TABLE t2 DISCARD TABLESPACE;
ALTER TABLE t3 DISCARD TABLESPACE;
--sleep 5
--echo # Discarded tablespaces should be encrypted
--let SEARCH_PATTERN=foobar
--echo # t1 yes on expecting NOT FOUND
-- let SEARCH_FILE=$t1_IBD_1
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=temp
--echo # t2 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t2_IBD_1
-- source include/search_pattern_in_file.inc
--echo # t3 ... on expecting NOT FOUND
--let SEARCH_PATTERN=barfoo
-- let SEARCH_FILE=$t3_IBD_1
-- source include/search_pattern_in_file.inc
--echo # List after t1 DISCARD
--list_files $MYSQLD_DATADIR/test
--copy_file $MYSQLD_TMPDIR/t1.cfg $MYSQLD_DATADIR/test/t1.cfg
--copy_file $MYSQLD_TMPDIR/t1.ibd $MYSQLD_DATADIR/test/t1.ibd
--copy_file $MYSQLD_TMPDIR/t2.cfg $MYSQLD_DATADIR/test/t2.cfg
--copy_file $MYSQLD_TMPDIR/t2.ibd $MYSQLD_DATADIR/test/t2.ibd
--copy_file $MYSQLD_TMPDIR/t3.cfg $MYSQLD_DATADIR/test/t3.cfg
--copy_file $MYSQLD_TMPDIR/t3.ibd $MYSQLD_DATADIR/test/t3.ibd
--sleep 5
--echo # Tablespaces should be still encrypted
--let SEARCH_PATTERN=foobar
--echo # t1 yes on expecting NOT FOUND
-- let SEARCH_FILE=$t1_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=temp
--echo # t2 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t2_IBD
-- source include/search_pattern_in_file.inc
--echo # t3 ... on expecting NOT FOUND
--let SEARCH_PATTERN=barfoo
-- let SEARCH_FILE=$t3_IBD
-- source include/search_pattern_in_file.inc
ALTER TABLE t1 IMPORT TABLESPACE;
ALTER TABLE t2 IMPORT TABLESPACE;
ALTER TABLE t3 IMPORT TABLESPACE;
--sleep 5
--echo # tablespaces should remain encrypted after import
--let SEARCH_PATTERN=foobar
--echo # t1 yes on expecting NOT FOUND
-- let SEARCH_FILE=$t1_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=temp
--echo # t2 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t2_IBD
-- source include/search_pattern_in_file.inc
--echo # t3 ... on expecting NOT FOUND
--let SEARCH_PATTERN=barfoo
-- let SEARCH_FILE=$t3_IBD
-- source include/search_pattern_in_file.inc
ALTER TABLE t1 ENGINE InnoDB;
SHOW CREATE TABLE t1;
ALTER TABLE t2 ENGINE InnoDB;
SHOW CREATE TABLE t2;
ALTER TABLE t3 ENGINE InnoDB;
SHOW CREATE TABLE t3;
--echo # Wait max 10 min for key encryption threads to encrypt all spaces
--let $wait_timeout= 600
--let $wait_condition=SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0
--source include/wait_condition.inc
--sleep 5
--echo # Tablespaces should be encrypted after alter table
--let SEARCH_PATTERN=foobar
--echo # t1 yes on expecting NOT FOUND
-- let SEARCH_FILE=$t1_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=temp
--echo # t2 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t2_IBD
-- source include/search_pattern_in_file.inc
--echo # t3 ... on expecting NOT FOUND
--let SEARCH_PATTERN=barfoo
-- let SEARCH_FILE=$t3_IBD
-- source include/search_pattern_in_file.inc
--echo # Restarting server
-- source include/restart_mysqld.inc
--echo # Done restarting server
--echo # Verify that tables are still usable
SELECT COUNT(1) FROM t1;
SELECT COUNT(1) FROM t2;
SELECT COUNT(1) FROM t3;
--sleep 5
--echo # Tablespaces should be encrypted after restart
--let SEARCH_PATTERN=foobar
--echo # t1 yes on expecting NOT FOUND
-- let SEARCH_FILE=$t1_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=temp
--echo # t2 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t2_IBD
-- source include/search_pattern_in_file.inc
--echo # t3 ... on expecting NOT FOUND
--let SEARCH_PATTERN=barfoo
-- let SEARCH_FILE=$t3_IBD
-- source include/search_pattern_in_file.inc
DROP PROCEDURE innodb_insert_proc;
DROP TABLE t1, t2, t3;
# reset system
--disable_query_log
EVAL SET GLOBAL innodb_file_per_table = $innodb_file_per_table_orig;
EVAL SET GLOBAL innodb_file_format = $innodb_file_format_orig;
--enable_query_log
--innodb-encrypt-tables=ON
--innodb-encrypt-log=ON
--innodb-encryption-rotate-key-age=15
--innodb-encryption-threads=4
--innodb-tablespaces-encryption
--innodb-max-dirty-pages-pct=0.001
-- source include/have_innodb.inc
-- source include/have_example_key_management_plugin.inc
-- source include/not_valgrind.inc
-- source include/not_embedded.inc
-- source include/not_windows.inc
--disable_query_log
let $innodb_file_format_orig = `SELECT @@innodb_file_format`;
let $innodb_file_per_table_orig = `SELECT @@innodb_file_per_table`;
--enable_query_log
SET GLOBAL innodb_file_format = `Barracuda`;
SET GLOBAL innodb_file_per_table = ON;
--let $MYSQLD_DATADIR=`select @@datadir`
--let SEARCH_RANGE = 10000000
--let t1_IBD = $MYSQLD_DATADIR/test/t1.ibd
--let t2_IBD = $MYSQLD_DATADIR/test/t2.ibd
--let t3_IBD = $MYSQLD_DATADIR/test/t3.ibd
--let t4_IBD = $MYSQLD_DATADIR/test/t4.ibd
--let t5_IBD = $MYSQLD_DATADIR/test/t5.ibd
--let t6_IBD = $MYSQLD_DATADIR/test/t6.ibd
--let t7_IBD = $MYSQLD_DATADIR/test/t7.ibd
CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY, a VARCHAR(255)) ENGINE=InnoDB encrypted=yes;
CREATE TABLE t2 (id INT NOT NULL PRIMARY KEY, a VARCHAR(255)) ENGINE=InnoDB;
CREATE TABLE t3 (id INT, a VARCHAR(255)) ENGINE=InnoDB encrypted=yes;
CREATE TABLE t4 (id INT, a VARCHAR(255)) engine=InnoDB;
CREATE TABLE t5 (id INT NOT NULL PRIMARY KEY, a TEXT(500), b VARCHAR(255), FULLTEXT(b)) ENGINE=InnoDB encrypted=yes;
CREATE TABLE t6 (id INT, a TEXT(500), b VARCHAR(255), FULLTEXT(b)) ENGINE=InnoDB;
CREATE TABLE t7 (id INT NOT NULL PRIMARY KEY, a VARCHAR(255)) ENGINE=InnoDB row_format=compressed encrypted=yes;
delimiter //;
create procedure innodb_insert_proc (repeat_count int)
begin
declare current_num int;
set current_num = 0;
while current_num < repeat_count do
insert into t1 values (current_num,repeat('foobar',42));
insert into t2 values (current_num,repeat('temp', 42));
insert into t3 values (current_num,repeat('barfoo',42));
insert into t4 values (current_num,repeat('repeat',42));
insert into t5 values (current_num,substring('A BC DEF GHIJ KLM NOPQRS TUV WXYZ 012 3456789', rand()*36+1, 100), repeat('author new',22));
insert into t6 values (current_num,substring('A BC DEF GHIJ KLM NOPQRS TUV WXYZ 012 3456789', rand()*36+1, 100), repeat('mangled old',22));
insert into t7 values (current_num,repeat('mysql',42));
set current_num = current_num + 1;
end while;
end//
delimiter ;//
commit;
set autocommit=0;
call innodb_insert_proc(15000);
commit;
set autocommit=1;
--echo # Wait max 10 min for key encryption threads to encrypt all spaces
--let $wait_timeout= 600
--let $wait_condition=SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0
--source include/wait_condition.inc
--sleep 5
--let SEARCH_PATTERN=foobar
--echo # t1 yes on expecting NOT FOUND
-- let SEARCH_FILE=$t1_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=temp
--echo # t2 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t2_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=barfoo
--echo # t3 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t3_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=repeat
--echo # t4 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t4_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=author
--echo # t5 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t5_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=mangled
--echo # t6 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t6_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=mysql
--echo # t7 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t7_IBD
-- source include/search_pattern_in_file.inc
ALTER TABLE t1 ADD COLUMN b int default 2;
ALTER TABLE t2 ADD COLUMN b int default 2;
ALTER TABLE t7 ADD COLUMN b int default 2;
ALTER TABLE t1 ADD KEY a(a), ADD KEY b(b);
ALTER TABLE t2 ADD KEY a(a), ADD KEY b(b);
ALTER TABLE t3 ADD COLUMN c int default 5;
ALTER TABLE t4 ADD COLUMN c int default 5;
ALTER TABLE t3 ADD KEY (a), ADD KEY c(c);
ALTER TABLE t4 ADD KEY (a), ADD KEY c(c);
ALTER TABLE t5 ADD FULLTEXT(a);
ALTER TABLE t6 ADD FULLTEXT(a);
ALTER TABLE t7 ADD KEY a(a), ADD key b(b);
SHOW CREATE TABLE t1;
SHOW CREATE TABLE t2;
SHOW CREATE TABLE t3;
SHOW CREATE TABLE t4;
SHOW CREATE TABLE t5;
SHOW CREATE TABLE t6;
SHOW CREATE TABLE t7;
--sleep 5
--let SEARCH_PATTERN=foobar
--echo # t1 yes on expecting NOT FOUND
-- let SEARCH_FILE=$t1_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=temp
--echo # t2 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t2_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=barfoo
--echo # t3 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t3_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=repeat
--echo # t4 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t4_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=author
--echo # t5 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t5_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=mangled
--echo # t6 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t6_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=mysql
--echo # t7 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t7_IBD
-- source include/search_pattern_in_file.inc
--echo # Restarting server
-- source include/restart_mysqld.inc
--echo # Done restarting server
select count(1) from t1;
select count(1) from t2;
select count(1) from t3;
select count(1) from t4;
select count(1) from t5;
select count(1) from t6;
select count(1) from t7;
--let SEARCH_PATTERN=foobar
--echo # t1 yes on expecting NOT FOUND
-- let SEARCH_FILE=$t1_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=temp
--echo # t2 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t2_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=barfoo
--echo # t3 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t3_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=repeat
--echo # t4 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t4_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=author
--echo # t5 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t5_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=mangled
--echo # t6 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t6_IBD
-- source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=mysql
--echo # t7 ... on expecting NOT FOUND
-- let SEARCH_FILE=$t7_IBD
-- source include/search_pattern_in_file.inc
DROP PROCEDURE innodb_insert_proc;
DROP TABLE t1, t2, t3, t4, t5, t6, t7;
# reset system
--disable_query_log
EVAL SET GLOBAL innodb_file_per_table = $innodb_file_per_table_orig;
EVAL SET GLOBAL innodb_file_format = $innodb_file_format_orig;
--enable_query_log
...@@ -244,9 +244,6 @@ fil_space_merge_crypt_data( ...@@ -244,9 +244,6 @@ fil_space_merge_crypt_data(
ut_a(dst->type == CRYPT_SCHEME_UNENCRYPTED || ut_a(dst->type == CRYPT_SCHEME_UNENCRYPTED ||
dst->type == CRYPT_SCHEME_1); dst->type == CRYPT_SCHEME_1);
/* no support for changing iv (yet?) */
ut_a(memcmp(src->iv, dst->iv, sizeof(src->iv)) == 0);
dst->encryption = src->encryption; dst->encryption = src->encryption;
dst->type = src->type; dst->type = src->type;
dst->min_key_version = src->min_key_version; dst->min_key_version = src->min_key_version;
...@@ -287,7 +284,7 @@ fil_space_read_crypt_data( ...@@ -287,7 +284,7 @@ fil_space_read_crypt_data(
page[offset + 4], page[offset + 4],
page[offset + 5]); page[offset + 5]);
#endif #endif
/* Create data is not stored. */ /* Crypt data is not stored. */
return NULL; return NULL;
} }
...@@ -370,7 +367,7 @@ fil_space_destroy_crypt_data( ...@@ -370,7 +367,7 @@ fil_space_destroy_crypt_data(
mutex_enter(&(*crypt_data)->mutex); mutex_enter(&(*crypt_data)->mutex);
(*crypt_data)->inited = false; (*crypt_data)->inited = false;
mutex_exit(&(*crypt_data)->mutex); mutex_exit(&(*crypt_data)->mutex);
mutex_free(&(*crypt_data)->mutex); mutex_free(& (*crypt_data)->mutex);
memset(*crypt_data, 0, sizeof(fil_space_crypt_t)); memset(*crypt_data, 0, sizeof(fil_space_crypt_t));
free(*crypt_data); free(*crypt_data);
(*crypt_data) = NULL; (*crypt_data) = NULL;
...@@ -555,42 +552,22 @@ fil_space_clear_crypt_data( ...@@ -555,42 +552,22 @@ fil_space_clear_crypt_data(
} }
/****************************************************************** /******************************************************************
Encrypt a page */ Encrypt a buffer */
UNIV_INTERN UNIV_INTERN
byte* byte*
fil_space_encrypt( fil_encrypt_buf(
/*==============*/ /*============*/
fil_space_crypt_t* crypt_data, /*!< in: crypt data */
ulint space, /*!< in: Space id */ ulint space, /*!< in: Space id */
ulint offset, /*!< in: Page offset */ ulint offset, /*!< in: Page offset */
lsn_t lsn, /*!< in: lsn */ lsn_t lsn, /*!< in: lsn */
byte* src_frame, /*!< in: Source page to be encrypted */ byte* src_frame, /*!< in: Source page to be encrypted */
ulint zip_size, /*!< in: compressed size if ulint zip_size, /*!< in: compressed size if
row_format compressed */ row format compressed */
byte* dst_frame) /*!< in: outbut buffer */ byte* dst_frame) /*!< in: outbut buffer */
{ {
fil_space_crypt_t* crypt_data = NULL;
ulint page_size = (zip_size) ? zip_size : UNIV_PAGE_SIZE; ulint page_size = (zip_size) ? zip_size : UNIV_PAGE_SIZE;
uint key_version; uint key_version = fil_crypt_get_latest_key_version(crypt_data);
ulint orig_page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE);
if (orig_page_type==FIL_PAGE_TYPE_FSP_HDR
|| orig_page_type==FIL_PAGE_TYPE_XDES) {
/* File space header or extent descriptor do not need to be
encrypted. */
return src_frame;
}
/* Get crypt data from file space */
crypt_data = fil_space_get_crypt_data(space);
if (crypt_data == NULL) {
return src_frame;
}
ut_ad(crypt_data->encryption != FIL_SPACE_ENCRYPTION_OFF);
key_version = fil_crypt_get_latest_key_version(crypt_data);
if (key_version == ENCRYPTION_KEY_VERSION_INVALID) { if (key_version == ENCRYPTION_KEY_VERSION_INVALID) {
ib_logf(IB_LOG_LEVEL_FATAL, ib_logf(IB_LOG_LEVEL_FATAL,
...@@ -599,6 +576,7 @@ fil_space_encrypt( ...@@ -599,6 +576,7 @@ fil_space_encrypt(
ut_error; ut_error;
} }
ulint orig_page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE);
ibool page_compressed = (orig_page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED); ibool page_compressed = (orig_page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED);
ulint header_len = FIL_PAGE_DATA; ulint header_len = FIL_PAGE_DATA;
...@@ -661,6 +639,45 @@ fil_space_encrypt( ...@@ -661,6 +639,45 @@ fil_space_encrypt(
return dst_frame; return dst_frame;
} }
/******************************************************************
Encrypt a page */
UNIV_INTERN
byte*
fil_space_encrypt(
/*==============*/
ulint space, /*!< in: Space id */
ulint offset, /*!< in: Page offset */
lsn_t lsn, /*!< in: lsn */
byte* src_frame, /*!< in: Source page to be encrypted */
ulint zip_size, /*!< in: compressed size if
row_format compressed */
byte* dst_frame) /*!< in: outbut buffer */
{
fil_space_crypt_t* crypt_data = NULL;
ulint orig_page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE);
if (orig_page_type==FIL_PAGE_TYPE_FSP_HDR
|| orig_page_type==FIL_PAGE_TYPE_XDES) {
/* File space header or extent descriptor do not need to be
encrypted. */
return src_frame;
}
/* Get crypt data from file space */
crypt_data = fil_space_get_crypt_data(space);
if (crypt_data == NULL) {
return src_frame;
}
ut_ad(crypt_data->encryption != FIL_SPACE_ENCRYPTION_OFF);
byte* tmp = fil_encrypt_buf(crypt_data, space, offset, lsn, src_frame, zip_size, dst_frame);
return tmp;
}
/********************************************************************* /*********************************************************************
Check if extra buffer shall be allocated for decrypting after read Check if extra buffer shall be allocated for decrypting after read
@return true if fil space has encryption data. */ @return true if fil space has encryption data. */
...@@ -1075,7 +1092,7 @@ fil_crypt_start_encrypting_space( ...@@ -1075,7 +1092,7 @@ fil_crypt_start_encrypting_space(
do do
{ {
if (fil_crypt_is_closing(space) || if (fil_crypt_is_closing(space) ||
fil_space_found_by_id(space)) { fil_space_found_by_id(space) == NULL) {
break; break;
} }
...@@ -2326,11 +2343,11 @@ fil_crypt_threads_init() ...@@ -2326,11 +2343,11 @@ fil_crypt_threads_init()
fil_crypt_threads_event = os_event_create(); fil_crypt_threads_event = os_event_create();
mutex_create(fil_crypt_threads_mutex_key, mutex_create(fil_crypt_threads_mutex_key,
&fil_crypt_threads_mutex, SYNC_NO_ORDER_CHECK); &fil_crypt_threads_mutex, SYNC_NO_ORDER_CHECK);
fil_crypt_threads_inited = true;
uint cnt = srv_n_fil_crypt_threads; uint cnt = srv_n_fil_crypt_threads;
srv_n_fil_crypt_threads = 0; srv_n_fil_crypt_threads = 0;
fil_crypt_set_thread_cnt(cnt); fil_crypt_set_thread_cnt(cnt);
fil_crypt_threads_inited = true;
} }
/********************************************************************* /*********************************************************************
......
...@@ -6418,8 +6418,16 @@ fil_iterate( ...@@ -6418,8 +6418,16 @@ fil_iterate(
ut_ad(!(n_bytes % iter.page_size)); ut_ad(!(n_bytes % iter.page_size));
byte* readptr = io_buffer; byte* readptr = io_buffer;
if (iter.crypt_data != NULL) { byte* writeptr = io_buffer;
bool encrypted = false;
/* Use additional crypt io buffer if tablespace is encrypted */
if ((iter.crypt_data != NULL && iter.crypt_data->encryption == FIL_SPACE_ENCRYPTION_ON) ||
(srv_encrypt_tables &&
iter.crypt_data && iter.crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT)) {
encrypted = true;
readptr = iter.crypt_io_buffer; readptr = iter.crypt_io_buffer;
writeptr = iter.crypt_io_buffer;
} }
if (!os_file_read(iter.file, readptr, offset, (ulint) n_bytes)) { if (!os_file_read(iter.file, readptr, offset, (ulint) n_bytes)) {
...@@ -6432,12 +6440,15 @@ fil_iterate( ...@@ -6432,12 +6440,15 @@ fil_iterate(
bool updated = false; bool updated = false;
os_offset_t page_off = offset; os_offset_t page_off = offset;
ulint n_pages_read = (ulint) n_bytes / iter.page_size; ulint n_pages_read = (ulint) n_bytes / iter.page_size;
bool decrypted = false;
for (ulint i = 0; i < n_pages_read; ++i) { for (ulint i = 0; i < n_pages_read; ++i) {
ulint size = iter.page_size;
if (iter.crypt_data != NULL) { /* If tablespace is encrypted, we need to decrypt
ulint size = iter.page_size; the page. */
bool decrypted = fil_space_decrypt( if (encrypted) {
decrypted = fil_space_decrypt(
iter.crypt_data, iter.crypt_data,
io_buffer + i * size, //dst io_buffer + i * size, //dst
iter.page_size, iter.page_size,
...@@ -6468,6 +6479,32 @@ fil_iterate( ...@@ -6468,6 +6479,32 @@ fil_iterate(
buf_block_set_state(block, BUF_BLOCK_NOT_USED); buf_block_set_state(block, BUF_BLOCK_NOT_USED);
buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE); buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE);
/* If tablespace is encrypted, encrypt page before we
write it back. Note that we should not encrypt the
buffer that is in buffer pool. */
if (decrypted && encrypted) {
unsigned char *src = io_buffer + (i * size);
unsigned char *dst = writeptr + (i * size);
ulint space = mach_read_from_4(
src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
ulint offset = mach_read_from_4(src + FIL_PAGE_OFFSET);
ib_uint64_t lsn = mach_read_from_8(src + FIL_PAGE_LSN);
byte* tmp = fil_encrypt_buf(
iter.crypt_data,
space,
offset,
lsn,
src,
iter.page_size == UNIV_PAGE_SIZE ? 0 : iter.page_size,
dst);
if (tmp == src) {
/* TODO: remove unnecessary memcpy's */
memcpy(writeptr, src, size);
}
}
page_off += iter.page_size; page_off += iter.page_size;
block->frame += iter.page_size; block->frame += iter.page_size;
} }
...@@ -6475,7 +6512,7 @@ fil_iterate( ...@@ -6475,7 +6512,7 @@ fil_iterate(
/* A page was updated in the set, write back to disk. */ /* A page was updated in the set, write back to disk. */
if (updated if (updated
&& !os_file_write( && !os_file_write(
iter.filepath, iter.file, io_buffer, iter.filepath, iter.file, writeptr,
offset, (ulint) n_bytes)) { offset, (ulint) n_bytes)) {
ib_logf(IB_LOG_LEVEL_ERROR, "os_file_write() failed"); ib_logf(IB_LOG_LEVEL_ERROR, "os_file_write() failed");
...@@ -6637,28 +6674,6 @@ fil_tablespace_iterate( ...@@ -6637,28 +6674,6 @@ fil_tablespace_iterate(
mem_free(io_buffer); mem_free(io_buffer);
if (iter.crypt_data != NULL) { if (iter.crypt_data != NULL) {
/* clear crypt data from page 0 and write it back */
os_file_read(file, page, 0, UNIV_PAGE_SIZE);
fil_space_clear_crypt_data(page, crypt_data_offset);
lsn_t lsn = mach_read_from_8(page + FIL_PAGE_LSN);
if (callback.get_zip_size() == 0) {
buf_flush_init_for_writing(
page, 0, lsn);
} else {
buf_flush_update_zip_checksum(
page, callback.get_zip_size(), lsn);
}
if (!os_file_write(
iter.filepath, iter.file, page,
0, iter.page_size)) {
ib_logf(IB_LOG_LEVEL_ERROR,
"os_file_write() failed");
return(DB_IO_ERROR);
}
mem_free(crypt_io_buffer); mem_free(crypt_io_buffer);
iter.crypt_io_buffer = NULL; iter.crypt_io_buffer = NULL;
fil_space_destroy_crypt_data(&iter.crypt_data); fil_space_destroy_crypt_data(&iter.crypt_data);
......
...@@ -11976,6 +11976,8 @@ ha_innobase::discard_or_import_tablespace( ...@@ -11976,6 +11976,8 @@ ha_innobase::discard_or_import_tablespace(
| HA_STATUS_CONST | HA_STATUS_CONST
| HA_STATUS_VARIABLE | HA_STATUS_VARIABLE
| HA_STATUS_AUTO); | HA_STATUS_AUTO);
fil_crypt_set_encrypt_tables(srv_encrypt_tables);
} }
} }
......
...@@ -381,6 +381,20 @@ fil_crypt_set_encrypt_tables( ...@@ -381,6 +381,20 @@ fil_crypt_set_encrypt_tables(
/*=========================*/ /*=========================*/
uint val); /*!< in: New srv_encrypt_tables setting */ uint val); /*!< in: New srv_encrypt_tables setting */
/******************************************************************
Encrypt a buffer */
UNIV_INTERN
byte*
fil_encrypt_buf(
/*============*/
fil_space_crypt_t* crypt_data, /*!< in: crypt data */
ulint space, /*!< in: Space id */
ulint offset, /*!< in: Page offset */
lsn_t lsn, /*!< in: lsn */
byte* src_frame, /*!< in: Source page to be encrypted */
ulint zip_size, /*!< in: compressed size if
row_format compressed */
byte* dst_frame); /*!< in: outbut buffer */
/****************************************************************** /******************************************************************
Calculate post encryption checksum Calculate post encryption checksum
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 2010, 2012, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2010, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -71,6 +72,7 @@ struct fts_psort_common_t { ...@@ -71,6 +72,7 @@ struct fts_psort_common_t {
store Doc ID during sort, if store Doc ID during sort, if
Doc ID will not be big enough Doc ID will not be big enough
to use 8 bytes value */ to use 8 bytes value */
fil_space_crypt_t* crypt_data; /*!< crypt data or NULL */
}; };
struct fts_psort_t { struct fts_psort_t {
...@@ -83,6 +85,10 @@ struct fts_psort_t { ...@@ -83,6 +85,10 @@ struct fts_psort_t {
/*!< buffer to write to file */ /*!< buffer to write to file */
row_merge_block_t* block_alloc[FTS_NUM_AUX_INDEX]; row_merge_block_t* block_alloc[FTS_NUM_AUX_INDEX];
/*!< buffer to allocated */ /*!< buffer to allocated */
row_merge_block_t* crypt_block[FTS_NUM_AUX_INDEX];
/*!< buffer to crypt data */
row_merge_block_t* crypt_alloc[FTS_NUM_AUX_INDEX];
/*!< buffer to allocated */
ulint child_status; /*!< child thread status */ ulint child_status; /*!< child thread status */
ulint state; /*!< parent thread state */ ulint state; /*!< parent thread state */
fts_doc_list_t fts_doc_list; /*!< doc list to process */ fts_doc_list_t fts_doc_list; /*!< doc list to process */
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 2005, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2005, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -351,7 +352,11 @@ row_merge_write( ...@@ -351,7 +352,11 @@ row_merge_write(
int fd, /*!< in: file descriptor */ int fd, /*!< in: file descriptor */
ulint offset, /*!< in: offset where to write, ulint offset, /*!< in: offset where to write,
in number of row_merge_block_t elements */ in number of row_merge_block_t elements */
const void* buf); /*!< in: data */ const void* buf, /*!< in: data */
fil_space_crypt_t* crypt_data, /*!< in: table crypt data */
void* crypt_buf, /*!< in: crypt buf or NULL */
ulint space); /*!< in: space id */
/********************************************************************//** /********************************************************************//**
Empty a sort buffer. Empty a sort buffer.
@return sort buffer */ @return sort buffer */
...@@ -386,7 +391,10 @@ row_merge_sort( ...@@ -386,7 +391,10 @@ row_merge_sort(
int* tmpfd, /*!< in/out: temporary file handle */ int* tmpfd, /*!< in/out: temporary file handle */
const bool update_progress, /*!< in: update progress status variable or not */ const bool update_progress, /*!< in: update progress status variable or not */
const float pct_progress, /*!< in: total progress percent until now */ const float pct_progress, /*!< in: total progress percent until now */
const float pct_cost) /*!< in: current progress percent */ const float pct_cost, /*!< in: current progress percent */
fil_space_crypt_t* crypt_data,/*!< in: table crypt data */
row_merge_block_t* crypt_block, /*!< in: crypt buf or NULL */
ulint space) /*!< in: space id */
__attribute__((nonnull)); __attribute__((nonnull));
/*********************************************************************//** /*********************************************************************//**
Allocate a sort buffer. Allocate a sort buffer.
...@@ -424,7 +432,11 @@ row_merge_read( ...@@ -424,7 +432,11 @@ row_merge_read(
ulint offset, /*!< in: offset where to read ulint offset, /*!< in: offset where to read
in number of row_merge_block_t in number of row_merge_block_t
elements */ elements */
row_merge_block_t* buf); /*!< out: data */ row_merge_block_t* buf, /*!< out: data */
fil_space_crypt_t* crypt_data,/*!< in: table crypt data */
row_merge_block_t* crypt_buf, /*!< in: crypt buf or NULL */
ulint space); /*!< in: space id */
/********************************************************************//** /********************************************************************//**
Read a merge record. Read a merge record.
@return pointer to next record, or NULL on I/O error or end of list */ @return pointer to next record, or NULL on I/O error or end of list */
...@@ -441,6 +453,9 @@ row_merge_read_rec( ...@@ -441,6 +453,9 @@ row_merge_read_rec(
const mrec_t** mrec, /*!< out: pointer to merge record, const mrec_t** mrec, /*!< out: pointer to merge record,
or NULL on end of list or NULL on end of list
(non-NULL on I/O error) */ (non-NULL on I/O error) */
ulint* offsets)/*!< out: offsets of mrec */ ulint* offsets,/*!< out: offsets of mrec */
fil_space_crypt_t* crypt_data,/*!< in: table crypt data */
row_merge_block_t* crypt_block, /*!< in: crypt buf or NULL */
ulint space) /*!< in: space id */
__attribute__((nonnull, warn_unused_result)); __attribute__((nonnull, warn_unused_result));
#endif /* row0merge.h */ #endif /* row0merge.h */
/***************************************************************************** /*****************************************************************************
Copyright (c) 2010, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2010, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -37,7 +38,8 @@ Created 10/13/2010 Jimmy Yang ...@@ -37,7 +38,8 @@ Created 10/13/2010 Jimmy Yang
do { \ do { \
b[N] = row_merge_read_rec( \ b[N] = row_merge_read_rec( \
block[N], buf[N], b[N], index, \ block[N], buf[N], b[N], index, \
fd[N], &foffs[N], &mrec[N], offsets[N]); \ fd[N], &foffs[N], &mrec[N], offsets[N], \
crypt_data, crypt_block[N], space); \
if (UNIV_UNLIKELY(!b[N])) { \ if (UNIV_UNLIKELY(!b[N])) { \
if (mrec[N]) { \ if (mrec[N]) { \
goto exit; \ goto exit; \
...@@ -191,6 +193,8 @@ row_fts_psort_info_init( ...@@ -191,6 +193,8 @@ row_fts_psort_info_init(
fts_psort_t* merge_info = NULL; fts_psort_t* merge_info = NULL;
ulint block_size; ulint block_size;
ibool ret = TRUE; ibool ret = TRUE;
fil_space_crypt_t* crypt_data = NULL;
bool encrypted = false;
block_size = 3 * srv_sort_buf_size; block_size = 3 * srv_sort_buf_size;
...@@ -219,6 +223,19 @@ row_fts_psort_info_init( ...@@ -219,6 +223,19 @@ row_fts_psort_info_init(
common_info->sort_event = os_event_create(); common_info->sort_event = os_event_create();
common_info->merge_event = os_event_create(); common_info->merge_event = os_event_create();
common_info->opt_doc_id_size = opt_doc_id_size; common_info->opt_doc_id_size = opt_doc_id_size;
crypt_data = fil_space_get_crypt_data(new_table->space);
if ((crypt_data && crypt_data->encryption == FIL_SPACE_ENCRYPTION_ON) ||
(srv_encrypt_tables &&
crypt_data && crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT)) {
common_info->crypt_data = crypt_data;
encrypted = true;
} else {
/* Not needed */
common_info->crypt_data = NULL;
crypt_data = NULL;
}
/* There will be FTS_NUM_AUX_INDEX number of "sort buckets" for /* There will be FTS_NUM_AUX_INDEX number of "sort buckets" for
each parallel sort thread. Each "sort bucket" holds records for each parallel sort thread. Each "sort bucket" holds records for
...@@ -256,6 +273,29 @@ row_fts_psort_info_init( ...@@ -256,6 +273,29 @@ row_fts_psort_info_init(
ut_align( ut_align(
psort_info[j].block_alloc[i], 1024)); psort_info[j].block_alloc[i], 1024));
/* If tablespace is encrypted, allocate additional buffer for
encryption/decryption. */
if (encrypted) {
/* Need to align memory for O_DIRECT write */
psort_info[j].crypt_alloc[i] =
static_cast<row_merge_block_t*>(ut_malloc(
block_size + 1024));
psort_info[j].crypt_block[i] =
static_cast<row_merge_block_t*>(
ut_align(
psort_info[j].crypt_alloc[i], 1024));
if (!psort_info[j].crypt_block[i]) {
ret = FALSE;
goto func_exit;
}
} else {
psort_info[j].crypt_alloc[i] = NULL;
psort_info[j].crypt_block[i] = NULL;
}
if (!psort_info[j].merge_block[i]) { if (!psort_info[j].merge_block[i]) {
ret = FALSE; ret = FALSE;
goto func_exit; goto func_exit;
...@@ -313,6 +353,11 @@ row_fts_psort_info_destroy( ...@@ -313,6 +353,11 @@ row_fts_psort_info_destroy(
if (psort_info[j].block_alloc[i]) { if (psort_info[j].block_alloc[i]) {
ut_free(psort_info[j].block_alloc[i]); ut_free(psort_info[j].block_alloc[i]);
} }
if (psort_info[j].crypt_alloc[i]) {
ut_free(psort_info[j].crypt_alloc[i]);
}
mem_free(psort_info[j].merge_file[i]); mem_free(psort_info[j].merge_file[i]);
} }
...@@ -595,6 +640,7 @@ fts_parallel_tokenization( ...@@ -595,6 +640,7 @@ fts_parallel_tokenization(
ibool processed = FALSE; ibool processed = FALSE;
merge_file_t** merge_file; merge_file_t** merge_file;
row_merge_block_t** block; row_merge_block_t** block;
row_merge_block_t** crypt_block;
int tmpfd[FTS_NUM_AUX_INDEX]; int tmpfd[FTS_NUM_AUX_INDEX];
ulint mycount[FTS_NUM_AUX_INDEX]; ulint mycount[FTS_NUM_AUX_INDEX];
ib_uint64_t total_rec = 0; ib_uint64_t total_rec = 0;
...@@ -609,6 +655,7 @@ fts_parallel_tokenization( ...@@ -609,6 +655,7 @@ fts_parallel_tokenization(
fts_tokenize_ctx_t t_ctx; fts_tokenize_ctx_t t_ctx;
ulint retried = 0; ulint retried = 0;
dberr_t error = DB_SUCCESS; dberr_t error = DB_SUCCESS;
fil_space_crypt_t* crypt_data = NULL;
ut_ad(psort_info); ut_ad(psort_info);
...@@ -630,6 +677,8 @@ fts_parallel_tokenization( ...@@ -630,6 +677,8 @@ fts_parallel_tokenization(
? DATA_VARCHAR : DATA_VARMYSQL; ? DATA_VARCHAR : DATA_VARMYSQL;
block = psort_info->merge_block; block = psort_info->merge_block;
crypt_block = psort_info->crypt_block;
crypt_data = psort_info->psort_common->crypt_data;
zip_size = dict_table_zip_size(table); zip_size = dict_table_zip_size(table);
row_merge_fts_get_next_doc_item(psort_info, &doc_item); row_merge_fts_get_next_doc_item(psort_info, &doc_item);
...@@ -724,7 +773,10 @@ loop: ...@@ -724,7 +773,10 @@ loop:
if (!row_merge_write(merge_file[t_ctx.buf_used]->fd, if (!row_merge_write(merge_file[t_ctx.buf_used]->fd,
merge_file[t_ctx.buf_used]->offset++, merge_file[t_ctx.buf_used]->offset++,
block[t_ctx.buf_used])) { block[t_ctx.buf_used],
crypt_data,
crypt_block[t_ctx.buf_used],
table->space)) {
error = DB_TEMP_FILE_WRITE_FAILURE; error = DB_TEMP_FILE_WRITE_FAILURE;
goto func_exit; goto func_exit;
} }
...@@ -817,13 +869,21 @@ exit: ...@@ -817,13 +869,21 @@ exit:
if (merge_file[i]->offset != 0) { if (merge_file[i]->offset != 0) {
if (!row_merge_write(merge_file[i]->fd, if (!row_merge_write(merge_file[i]->fd,
merge_file[i]->offset++, merge_file[i]->offset++,
block[i])) { block[i],
crypt_data,
crypt_block[i],
table->space)) {
error = DB_TEMP_FILE_WRITE_FAILURE; error = DB_TEMP_FILE_WRITE_FAILURE;
goto func_exit; goto func_exit;
} }
UNIV_MEM_INVALID(block[i][0], UNIV_MEM_INVALID(block[i][0],
srv_sort_buf_size); srv_sort_buf_size);
if (crypt_block[i]) {
UNIV_MEM_INVALID(crypt_block[i][0],
srv_sort_buf_size);
}
} }
buf[i] = row_merge_buf_empty(buf[i]); buf[i] = row_merge_buf_empty(buf[i]);
...@@ -848,7 +908,10 @@ exit: ...@@ -848,7 +908,10 @@ exit:
error = row_merge_sort(psort_info->psort_common->trx, error = row_merge_sort(psort_info->psort_common->trx,
psort_info->psort_common->dup, psort_info->psort_common->dup,
merge_file[i], block[i], &tmpfd[i], false, 0.0/* pct_progress */, 0.0/* pct_cost */); merge_file[i], block[i], &tmpfd[i],
false, 0.0/* pct_progress */, 0.0/* pct_cost */,
crypt_data, crypt_block[i], table->space);
if (error != DB_SUCCESS) { if (error != DB_SUCCESS) {
close(tmpfd[i]); close(tmpfd[i]);
goto func_exit; goto func_exit;
...@@ -1352,6 +1415,7 @@ row_fts_merge_insert( ...@@ -1352,6 +1415,7 @@ row_fts_merge_insert(
mrec_buf_t** buf; mrec_buf_t** buf;
int* fd; int* fd;
byte** block; byte** block;
byte** crypt_block;
const mrec_t** mrec; const mrec_t** mrec;
ulint count = 0; ulint count = 0;
int* sel_tree; int* sel_tree;
...@@ -1359,6 +1423,8 @@ row_fts_merge_insert( ...@@ -1359,6 +1423,8 @@ row_fts_merge_insert(
ulint start; ulint start;
fts_psort_insert_t ins_ctx; fts_psort_insert_t ins_ctx;
ulint count_diag = 0; ulint count_diag = 0;
fil_space_crypt_t* crypt_data = NULL;
ulint space;
ut_ad(index); ut_ad(index);
ut_ad(table); ut_ad(table);
...@@ -1371,6 +1437,7 @@ row_fts_merge_insert( ...@@ -1371,6 +1437,7 @@ row_fts_merge_insert(
ins_ctx.trx->op_info = "inserting index entries"; ins_ctx.trx->op_info = "inserting index entries";
ins_ctx.opt_doc_id_size = psort_info[0].psort_common->opt_doc_id_size; ins_ctx.opt_doc_id_size = psort_info[0].psort_common->opt_doc_id_size;
crypt_data = psort_info[0].psort_common->crypt_data;
heap = mem_heap_create(500 + sizeof(mrec_buf_t)); heap = mem_heap_create(500 + sizeof(mrec_buf_t));
...@@ -1385,6 +1452,8 @@ row_fts_merge_insert( ...@@ -1385,6 +1452,8 @@ row_fts_merge_insert(
fd = (int*) mem_heap_alloc(heap, sizeof(*fd) * fts_sort_pll_degree); fd = (int*) mem_heap_alloc(heap, sizeof(*fd) * fts_sort_pll_degree);
block = (byte**) mem_heap_alloc( block = (byte**) mem_heap_alloc(
heap, sizeof(*block) * fts_sort_pll_degree); heap, sizeof(*block) * fts_sort_pll_degree);
crypt_block = (byte**) mem_heap_alloc(
heap, sizeof(*block) * fts_sort_pll_degree);
mrec = (const mrec_t**) mem_heap_alloc( mrec = (const mrec_t**) mem_heap_alloc(
heap, sizeof(*mrec) * fts_sort_pll_degree); heap, sizeof(*mrec) * fts_sort_pll_degree);
sel_tree = (int*) mem_heap_alloc( sel_tree = (int*) mem_heap_alloc(
...@@ -1405,6 +1474,7 @@ row_fts_merge_insert( ...@@ -1405,6 +1474,7 @@ row_fts_merge_insert(
offsets[i][0] = num; offsets[i][0] = num;
offsets[i][1] = dict_index_get_n_fields(index); offsets[i][1] = dict_index_get_n_fields(index);
block[i] = psort_info[i].merge_block[id]; block[i] = psort_info[i].merge_block[id];
crypt_block[i] = psort_info[i].crypt_block[id];
b[i] = psort_info[i].merge_block[id]; b[i] = psort_info[i].merge_block[id];
fd[i] = psort_info[i].merge_file[id]->fd; fd[i] = psort_info[i].merge_file[id]->fd;
foffs[i] = 0; foffs[i] = 0;
...@@ -1447,6 +1517,7 @@ row_fts_merge_insert( ...@@ -1447,6 +1517,7 @@ row_fts_merge_insert(
ins_ctx.fts_table.table_id = table->id; ins_ctx.fts_table.table_id = table->id;
ins_ctx.fts_table.parent = index->table->name; ins_ctx.fts_table.parent = index->table->name;
ins_ctx.fts_table.table = index->table; ins_ctx.fts_table.table = index->table;
space = table->space;
for (i = 0; i < fts_sort_pll_degree; i++) { for (i = 0; i < fts_sort_pll_degree; i++) {
if (psort_info[i].merge_file[id]->n_rec == 0) { if (psort_info[i].merge_file[id]->n_rec == 0) {
...@@ -1459,7 +1530,10 @@ row_fts_merge_insert( ...@@ -1459,7 +1530,10 @@ row_fts_merge_insert(
if (psort_info[i].merge_file[id]->offset > 0 if (psort_info[i].merge_file[id]->offset > 0
&& (!row_merge_read( && (!row_merge_read(
fd[i], foffs[i], fd[i], foffs[i],
(row_merge_block_t*) block[i]))) { (row_merge_block_t*) block[i],
crypt_data,
(row_merge_block_t*) crypt_block[i],
space))) {
error = DB_CORRUPTION; error = DB_CORRUPTION;
goto exit; goto exit;
} }
......
This diff is collapsed.
...@@ -244,9 +244,6 @@ fil_space_merge_crypt_data( ...@@ -244,9 +244,6 @@ fil_space_merge_crypt_data(
ut_a(dst->type == CRYPT_SCHEME_UNENCRYPTED || ut_a(dst->type == CRYPT_SCHEME_UNENCRYPTED ||
dst->type == CRYPT_SCHEME_1); dst->type == CRYPT_SCHEME_1);
/* no support for changing iv (yet?) */
ut_a(memcmp(src->iv, dst->iv, sizeof(src->iv)) == 0);
dst->encryption = src->encryption; dst->encryption = src->encryption;
dst->type = src->type; dst->type = src->type;
dst->min_key_version = src->min_key_version; dst->min_key_version = src->min_key_version;
...@@ -555,42 +552,22 @@ fil_space_clear_crypt_data( ...@@ -555,42 +552,22 @@ fil_space_clear_crypt_data(
} }
/****************************************************************** /******************************************************************
Encrypt a page */ Encrypt a buffer */
UNIV_INTERN UNIV_INTERN
byte* byte*
fil_space_encrypt( fil_encrypt_buf(
/*==============*/ /*============*/
fil_space_crypt_t* crypt_data, /*!< in: crypt data */
ulint space, /*!< in: Space id */ ulint space, /*!< in: Space id */
ulint offset, /*!< in: Page offset */ ulint offset, /*!< in: Page offset */
lsn_t lsn, /*!< in: lsn */ lsn_t lsn, /*!< in: lsn */
byte* src_frame, /*!< in: Source page to be encrypted */ byte* src_frame, /*!< in: Source page to be encrypted */
ulint zip_size, /*!< in: compressed size if ulint zip_size, /*!< in: compressed size if
row_format compressed */ row format compressed */
byte* dst_frame) /*!< in: outbut buffer */ byte* dst_frame) /*!< in: outbut buffer */
{ {
fil_space_crypt_t* crypt_data = NULL;
ulint page_size = (zip_size) ? zip_size : UNIV_PAGE_SIZE; ulint page_size = (zip_size) ? zip_size : UNIV_PAGE_SIZE;
uint key_version; uint key_version = fil_crypt_get_latest_key_version(crypt_data);
ulint orig_page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE);
if (orig_page_type==FIL_PAGE_TYPE_FSP_HDR
|| orig_page_type==FIL_PAGE_TYPE_XDES) {
/* File space header or extent descriptor do not need to be
encrypted. */
return src_frame;
}
/* Get crypt data from file space */
crypt_data = fil_space_get_crypt_data(space);
if (crypt_data == NULL) {
return src_frame;
}
ut_ad(crypt_data->encryption != FIL_SPACE_ENCRYPTION_OFF);
key_version = fil_crypt_get_latest_key_version(crypt_data);
if (key_version == ENCRYPTION_KEY_VERSION_INVALID) { if (key_version == ENCRYPTION_KEY_VERSION_INVALID) {
ib_logf(IB_LOG_LEVEL_FATAL, ib_logf(IB_LOG_LEVEL_FATAL,
...@@ -599,6 +576,7 @@ fil_space_encrypt( ...@@ -599,6 +576,7 @@ fil_space_encrypt(
ut_error; ut_error;
} }
ulint orig_page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE);
ibool page_compressed = (orig_page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED); ibool page_compressed = (orig_page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED);
ulint header_len = FIL_PAGE_DATA; ulint header_len = FIL_PAGE_DATA;
...@@ -661,6 +639,45 @@ fil_space_encrypt( ...@@ -661,6 +639,45 @@ fil_space_encrypt(
return dst_frame; return dst_frame;
} }
/******************************************************************
Encrypt a page */
UNIV_INTERN
byte*
fil_space_encrypt(
/*==============*/
ulint space, /*!< in: Space id */
ulint offset, /*!< in: Page offset */
lsn_t lsn, /*!< in: lsn */
byte* src_frame, /*!< in: Source page to be encrypted */
ulint zip_size, /*!< in: compressed size if
row_format compressed */
byte* dst_frame) /*!< in: outbut buffer */
{
fil_space_crypt_t* crypt_data = NULL;
ulint orig_page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE);
if (orig_page_type==FIL_PAGE_TYPE_FSP_HDR
|| orig_page_type==FIL_PAGE_TYPE_XDES) {
/* File space header or extent descriptor do not need to be
encrypted. */
return src_frame;
}
/* Get crypt data from file space */
crypt_data = fil_space_get_crypt_data(space);
if (crypt_data == NULL) {
return src_frame;
}
ut_ad(crypt_data->encryption != FIL_SPACE_ENCRYPTION_OFF);
byte* tmp = fil_encrypt_buf(crypt_data, space, offset, lsn, src_frame, zip_size, dst_frame);
return tmp;
}
/********************************************************************* /*********************************************************************
Check if extra buffer shall be allocated for decrypting after read Check if extra buffer shall be allocated for decrypting after read
@return true if fil space has encryption data. */ @return true if fil space has encryption data. */
...@@ -2330,6 +2347,7 @@ fil_crypt_threads_init() ...@@ -2330,6 +2347,7 @@ fil_crypt_threads_init()
uint cnt = srv_n_fil_crypt_threads; uint cnt = srv_n_fil_crypt_threads;
srv_n_fil_crypt_threads = 0; srv_n_fil_crypt_threads = 0;
fil_crypt_set_thread_cnt(cnt); fil_crypt_set_thread_cnt(cnt);
fil_crypt_threads_inited = true;
} }
/********************************************************************* /*********************************************************************
......
...@@ -6475,8 +6475,16 @@ fil_iterate( ...@@ -6475,8 +6475,16 @@ fil_iterate(
ut_ad(!(n_bytes % iter.page_size)); ut_ad(!(n_bytes % iter.page_size));
byte* readptr = io_buffer; byte* readptr = io_buffer;
if (iter.crypt_data != NULL) { byte* writeptr = io_buffer;
bool encrypted = false;
/* Use additional crypt io buffer if tablespace is encrypted */
if ((iter.crypt_data != NULL && iter.crypt_data->encryption == FIL_SPACE_ENCRYPTION_ON) ||
(srv_encrypt_tables &&
iter.crypt_data && iter.crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT)) {
encrypted = true;
readptr = iter.crypt_io_buffer; readptr = iter.crypt_io_buffer;
writeptr = iter.crypt_io_buffer;
} }
if (!os_file_read(iter.file, readptr, offset, (ulint) n_bytes)) { if (!os_file_read(iter.file, readptr, offset, (ulint) n_bytes)) {
...@@ -6489,12 +6497,15 @@ fil_iterate( ...@@ -6489,12 +6497,15 @@ fil_iterate(
bool updated = false; bool updated = false;
os_offset_t page_off = offset; os_offset_t page_off = offset;
ulint n_pages_read = (ulint) n_bytes / iter.page_size; ulint n_pages_read = (ulint) n_bytes / iter.page_size;
bool decrypted = false;
for (ulint i = 0; i < n_pages_read; ++i) { for (ulint i = 0; i < n_pages_read; ++i) {
ulint size = iter.page_size;
if (iter.crypt_data != NULL) { /* If tablespace is encrypted, we need to decrypt
ulint size = iter.page_size; the page. */
bool decrypted = fil_space_decrypt( if (encrypted) {
decrypted = fil_space_decrypt(
iter.crypt_data, iter.crypt_data,
io_buffer + i * size, //dst io_buffer + i * size, //dst
iter.page_size, iter.page_size,
...@@ -6525,6 +6536,32 @@ fil_iterate( ...@@ -6525,6 +6536,32 @@ fil_iterate(
buf_block_set_state(block, BUF_BLOCK_NOT_USED); buf_block_set_state(block, BUF_BLOCK_NOT_USED);
buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE); buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE);
/* If tablespace is encrypted, encrypt page before we
write it back. Note that we should not encrypt the
buffer that is in buffer pool. */
if (decrypted && encrypted) {
unsigned char *src = io_buffer + (i * size);
unsigned char *dst = writeptr + (i * size);
ulint space = mach_read_from_4(
src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
ulint offset = mach_read_from_4(src + FIL_PAGE_OFFSET);
ib_uint64_t lsn = mach_read_from_8(src + FIL_PAGE_LSN);
byte* tmp = fil_encrypt_buf(
iter.crypt_data,
space,
offset,
lsn,
src,
iter.page_size == UNIV_PAGE_SIZE ? 0 : iter.page_size,
dst);
if (tmp == src) {
/* TODO: remove unnecessary memcpy's */
memcpy(writeptr, src, size);
}
}
page_off += iter.page_size; page_off += iter.page_size;
block->frame += iter.page_size; block->frame += iter.page_size;
} }
...@@ -6532,7 +6569,7 @@ fil_iterate( ...@@ -6532,7 +6569,7 @@ fil_iterate(
/* A page was updated in the set, write back to disk. */ /* A page was updated in the set, write back to disk. */
if (updated if (updated
&& !os_file_write( && !os_file_write(
iter.filepath, iter.file, io_buffer, iter.filepath, iter.file, writeptr,
offset, (ulint) n_bytes)) { offset, (ulint) n_bytes)) {
ib_logf(IB_LOG_LEVEL_ERROR, "os_file_write() failed"); ib_logf(IB_LOG_LEVEL_ERROR, "os_file_write() failed");
...@@ -6694,28 +6731,6 @@ fil_tablespace_iterate( ...@@ -6694,28 +6731,6 @@ fil_tablespace_iterate(
mem_free(io_buffer); mem_free(io_buffer);
if (iter.crypt_data != NULL) { if (iter.crypt_data != NULL) {
/* clear crypt data from page 0 and write it back */
os_file_read(file, page, 0, UNIV_PAGE_SIZE);
fil_space_clear_crypt_data(page, crypt_data_offset);
lsn_t lsn = mach_read_from_8(page + FIL_PAGE_LSN);
if (callback.get_zip_size() == 0) {
buf_flush_init_for_writing(
page, 0, lsn);
} else {
buf_flush_update_zip_checksum(
page, callback.get_zip_size(), lsn);
}
if (!os_file_write(
iter.filepath, iter.file, page,
0, iter.page_size)) {
ib_logf(IB_LOG_LEVEL_ERROR,
"os_file_write() failed");
return(DB_IO_ERROR);
}
mem_free(crypt_io_buffer); mem_free(crypt_io_buffer);
iter.crypt_io_buffer = NULL; iter.crypt_io_buffer = NULL;
fil_space_destroy_crypt_data(&iter.crypt_data); fil_space_destroy_crypt_data(&iter.crypt_data);
......
...@@ -12465,6 +12465,8 @@ ha_innobase::discard_or_import_tablespace( ...@@ -12465,6 +12465,8 @@ ha_innobase::discard_or_import_tablespace(
| HA_STATUS_CONST | HA_STATUS_CONST
| HA_STATUS_VARIABLE | HA_STATUS_VARIABLE
| HA_STATUS_AUTO); | HA_STATUS_AUTO);
fil_crypt_set_encrypt_tables(srv_encrypt_tables);
} }
} }
......
...@@ -381,6 +381,21 @@ fil_crypt_set_encrypt_tables( ...@@ -381,6 +381,21 @@ fil_crypt_set_encrypt_tables(
/*=========================*/ /*=========================*/
uint val); /*!< in: New srv_encrypt_tables setting */ uint val); /*!< in: New srv_encrypt_tables setting */
/******************************************************************
Encrypt a buffer */
UNIV_INTERN
byte*
fil_encrypt_buf(
/*============*/
fil_space_crypt_t* crypt_data, /*!< in: crypt data */
ulint space, /*!< in: Space id */
ulint offset, /*!< in: Page offset */
lsn_t lsn, /*!< in: lsn */
byte* src_frame, /*!< in: Source page to be encrypted */
ulint zip_size, /*!< in: compressed size if
row_format compressed */
byte* dst_frame); /*!< in: outbut buffer */
/****************************************************************** /******************************************************************
Calculate post encryption checksum Calculate post encryption checksum
@return page checksum or BUF_NO_CHECKSUM_MAGIC @return page checksum or BUF_NO_CHECKSUM_MAGIC
...@@ -392,6 +407,7 @@ fil_crypt_calculate_checksum( ...@@ -392,6 +407,7 @@ fil_crypt_calculate_checksum(
ulint zip_size, /*!< in: zip_size or 0 */ ulint zip_size, /*!< in: zip_size or 0 */
byte* dst_frame); /*!< in: page where to calculate */ byte* dst_frame); /*!< in: page where to calculate */
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
#include "fil0crypt.ic" #include "fil0crypt.ic"
#endif #endif
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 2010, 2012, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2010, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -71,6 +72,7 @@ struct fts_psort_common_t { ...@@ -71,6 +72,7 @@ struct fts_psort_common_t {
store Doc ID during sort, if store Doc ID during sort, if
Doc ID will not be big enough Doc ID will not be big enough
to use 8 bytes value */ to use 8 bytes value */
fil_space_crypt_t* crypt_data; /*!< crypt data or NULL */
}; };
struct fts_psort_t { struct fts_psort_t {
...@@ -83,6 +85,10 @@ struct fts_psort_t { ...@@ -83,6 +85,10 @@ struct fts_psort_t {
/*!< buffer to write to file */ /*!< buffer to write to file */
row_merge_block_t* block_alloc[FTS_NUM_AUX_INDEX]; row_merge_block_t* block_alloc[FTS_NUM_AUX_INDEX];
/*!< buffer to allocated */ /*!< buffer to allocated */
row_merge_block_t* crypt_block[FTS_NUM_AUX_INDEX];
/*!< buffer to crypt data */
row_merge_block_t* crypt_alloc[FTS_NUM_AUX_INDEX];
/*!< buffer to allocated */
ulint child_status; /*!< child thread status */ ulint child_status; /*!< child thread status */
ulint state; /*!< parent thread state */ ulint state; /*!< parent thread state */
fts_doc_list_t fts_doc_list; /*!< doc list to process */ fts_doc_list_t fts_doc_list; /*!< doc list to process */
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 2005, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2005, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -351,7 +352,11 @@ row_merge_write( ...@@ -351,7 +352,11 @@ row_merge_write(
int fd, /*!< in: file descriptor */ int fd, /*!< in: file descriptor */
ulint offset, /*!< in: offset where to write, ulint offset, /*!< in: offset where to write,
in number of row_merge_block_t elements */ in number of row_merge_block_t elements */
const void* buf); /*!< in: data */ const void* buf, /*!< in: data */
fil_space_crypt_t* crypt_data, /*!< in: table crypt data */
void* crypt_buf, /*!< in: crypt buf or NULL */
ulint space); /*!< in: space id */
/********************************************************************//** /********************************************************************//**
Empty a sort buffer. Empty a sort buffer.
@return sort buffer */ @return sort buffer */
...@@ -386,7 +391,10 @@ row_merge_sort( ...@@ -386,7 +391,10 @@ row_merge_sort(
int* tmpfd, /*!< in/out: temporary file handle */ int* tmpfd, /*!< in/out: temporary file handle */
const bool update_progress, /*!< in: update progress status variable or not */ const bool update_progress, /*!< in: update progress status variable or not */
const float pct_progress, /*!< in: total progress percent until now */ const float pct_progress, /*!< in: total progress percent until now */
const float pct_cost) /*!< in: current progress percent */ const float pct_cost, /*!< in: current progress percent */
fil_space_crypt_t* crypt_data,/*!< in: table crypt data */
row_merge_block_t* crypt_block, /*!< in: crypt buf or NULL */
ulint space) /*!< in: space id */
__attribute__((nonnull)); __attribute__((nonnull));
/*********************************************************************//** /*********************************************************************//**
Allocate a sort buffer. Allocate a sort buffer.
...@@ -424,7 +432,11 @@ row_merge_read( ...@@ -424,7 +432,11 @@ row_merge_read(
ulint offset, /*!< in: offset where to read ulint offset, /*!< in: offset where to read
in number of row_merge_block_t in number of row_merge_block_t
elements */ elements */
row_merge_block_t* buf); /*!< out: data */ row_merge_block_t* buf, /*!< out: data */
fil_space_crypt_t* crypt_data,/*!< in: table crypt data */
row_merge_block_t* crypt_buf, /*!< in: crypt buf or NULL */
ulint space); /*!< in: space id */
/********************************************************************//** /********************************************************************//**
Read a merge record. Read a merge record.
@return pointer to next record, or NULL on I/O error or end of list */ @return pointer to next record, or NULL on I/O error or end of list */
...@@ -441,6 +453,9 @@ row_merge_read_rec( ...@@ -441,6 +453,9 @@ row_merge_read_rec(
const mrec_t** mrec, /*!< out: pointer to merge record, const mrec_t** mrec, /*!< out: pointer to merge record,
or NULL on end of list or NULL on end of list
(non-NULL on I/O error) */ (non-NULL on I/O error) */
ulint* offsets)/*!< out: offsets of mrec */ ulint* offsets,/*!< out: offsets of mrec */
fil_space_crypt_t* crypt_data,/*!< in: table crypt data */
row_merge_block_t* crypt_block, /*!< in: crypt buf or NULL */
ulint space) /*!< in: space id */
__attribute__((nonnull, warn_unused_result)); __attribute__((nonnull, warn_unused_result));
#endif /* row0merge.h */ #endif /* row0merge.h */
/***************************************************************************** /*****************************************************************************
Copyright (c) 2010, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2010, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -38,7 +39,8 @@ Created 10/13/2010 Jimmy Yang ...@@ -38,7 +39,8 @@ Created 10/13/2010 Jimmy Yang
do { \ do { \
b[N] = row_merge_read_rec( \ b[N] = row_merge_read_rec( \
block[N], buf[N], b[N], index, \ block[N], buf[N], b[N], index, \
fd[N], &foffs[N], &mrec[N], offsets[N]); \ fd[N], &foffs[N], &mrec[N], offsets[N], \
crypt_data, crypt_block[N], space); \
if (UNIV_UNLIKELY(!b[N])) { \ if (UNIV_UNLIKELY(!b[N])) { \
if (mrec[N]) { \ if (mrec[N]) { \
goto exit; \ goto exit; \
...@@ -194,6 +196,8 @@ row_fts_psort_info_init( ...@@ -194,6 +196,8 @@ row_fts_psort_info_init(
fts_psort_t* merge_info = NULL; fts_psort_t* merge_info = NULL;
ulint block_size; ulint block_size;
ibool ret = TRUE; ibool ret = TRUE;
fil_space_crypt_t* crypt_data = NULL;
bool encrypted = false;
block_size = 3 * srv_sort_buf_size; block_size = 3 * srv_sort_buf_size;
...@@ -222,6 +226,19 @@ row_fts_psort_info_init( ...@@ -222,6 +226,19 @@ row_fts_psort_info_init(
common_info->sort_event = os_event_create(); common_info->sort_event = os_event_create();
common_info->merge_event = os_event_create(); common_info->merge_event = os_event_create();
common_info->opt_doc_id_size = opt_doc_id_size; common_info->opt_doc_id_size = opt_doc_id_size;
crypt_data = fil_space_get_crypt_data(new_table->space);
if ((crypt_data && crypt_data->encryption == FIL_SPACE_ENCRYPTION_ON) ||
(srv_encrypt_tables &&
crypt_data && crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT)) {
common_info->crypt_data = crypt_data;
encrypted = true;
} else {
/* Not needed */
common_info->crypt_data = NULL;
crypt_data = NULL;
}
/* There will be FTS_NUM_AUX_INDEX number of "sort buckets" for /* There will be FTS_NUM_AUX_INDEX number of "sort buckets" for
each parallel sort thread. Each "sort bucket" holds records for each parallel sort thread. Each "sort bucket" holds records for
...@@ -259,6 +276,29 @@ row_fts_psort_info_init( ...@@ -259,6 +276,29 @@ row_fts_psort_info_init(
ut_align( ut_align(
psort_info[j].block_alloc[i], 1024)); psort_info[j].block_alloc[i], 1024));
/* If tablespace is encrypted, allocate additional buffer for
encryption/decryption. */
if (encrypted) {
/* Need to align memory for O_DIRECT write */
psort_info[j].crypt_alloc[i] =
static_cast<row_merge_block_t*>(ut_malloc(
block_size + 1024));
psort_info[j].crypt_block[i] =
static_cast<row_merge_block_t*>(
ut_align(
psort_info[j].crypt_alloc[i], 1024));
if (!psort_info[j].crypt_block[i]) {
ret = FALSE;
goto func_exit;
}
} else {
psort_info[j].crypt_alloc[i] = NULL;
psort_info[j].crypt_block[i] = NULL;
}
if (!psort_info[j].merge_block[i]) { if (!psort_info[j].merge_block[i]) {
ret = FALSE; ret = FALSE;
goto func_exit; goto func_exit;
...@@ -316,6 +356,11 @@ row_fts_psort_info_destroy( ...@@ -316,6 +356,11 @@ row_fts_psort_info_destroy(
if (psort_info[j].block_alloc[i]) { if (psort_info[j].block_alloc[i]) {
ut_free(psort_info[j].block_alloc[i]); ut_free(psort_info[j].block_alloc[i]);
} }
if (psort_info[j].crypt_alloc[i]) {
ut_free(psort_info[j].crypt_alloc[i]);
}
mem_free(psort_info[j].merge_file[i]); mem_free(psort_info[j].merge_file[i]);
} }
...@@ -598,6 +643,7 @@ fts_parallel_tokenization( ...@@ -598,6 +643,7 @@ fts_parallel_tokenization(
ibool processed = FALSE; ibool processed = FALSE;
merge_file_t** merge_file; merge_file_t** merge_file;
row_merge_block_t** block; row_merge_block_t** block;
row_merge_block_t** crypt_block;
int tmpfd[FTS_NUM_AUX_INDEX]; int tmpfd[FTS_NUM_AUX_INDEX];
ulint mycount[FTS_NUM_AUX_INDEX]; ulint mycount[FTS_NUM_AUX_INDEX];
ib_uint64_t total_rec = 0; ib_uint64_t total_rec = 0;
...@@ -612,6 +658,7 @@ fts_parallel_tokenization( ...@@ -612,6 +658,7 @@ fts_parallel_tokenization(
fts_tokenize_ctx_t t_ctx; fts_tokenize_ctx_t t_ctx;
ulint retried = 0; ulint retried = 0;
dberr_t error = DB_SUCCESS; dberr_t error = DB_SUCCESS;
fil_space_crypt_t* crypt_data = NULL;
ut_ad(psort_info); ut_ad(psort_info);
...@@ -633,6 +680,8 @@ fts_parallel_tokenization( ...@@ -633,6 +680,8 @@ fts_parallel_tokenization(
? DATA_VARCHAR : DATA_VARMYSQL; ? DATA_VARCHAR : DATA_VARMYSQL;
block = psort_info->merge_block; block = psort_info->merge_block;
crypt_block = psort_info->crypt_block;
crypt_data = psort_info->psort_common->crypt_data;
zip_size = dict_table_zip_size(table); zip_size = dict_table_zip_size(table);
row_merge_fts_get_next_doc_item(psort_info, &doc_item); row_merge_fts_get_next_doc_item(psort_info, &doc_item);
...@@ -727,7 +776,10 @@ loop: ...@@ -727,7 +776,10 @@ loop:
if (!row_merge_write(merge_file[t_ctx.buf_used]->fd, if (!row_merge_write(merge_file[t_ctx.buf_used]->fd,
merge_file[t_ctx.buf_used]->offset++, merge_file[t_ctx.buf_used]->offset++,
block[t_ctx.buf_used])) { block[t_ctx.buf_used],
crypt_data,
crypt_block[t_ctx.buf_used],
table->space)) {
error = DB_TEMP_FILE_WRITE_FAILURE; error = DB_TEMP_FILE_WRITE_FAILURE;
goto func_exit; goto func_exit;
} }
...@@ -820,13 +872,21 @@ exit: ...@@ -820,13 +872,21 @@ exit:
if (merge_file[i]->offset != 0) { if (merge_file[i]->offset != 0) {
if (!row_merge_write(merge_file[i]->fd, if (!row_merge_write(merge_file[i]->fd,
merge_file[i]->offset++, merge_file[i]->offset++,
block[i])) { block[i],
crypt_data,
crypt_block[i],
table->space)) {
error = DB_TEMP_FILE_WRITE_FAILURE; error = DB_TEMP_FILE_WRITE_FAILURE;
goto func_exit; goto func_exit;
} }
UNIV_MEM_INVALID(block[i][0], UNIV_MEM_INVALID(block[i][0],
srv_sort_buf_size); srv_sort_buf_size);
if (crypt_block[i]) {
UNIV_MEM_INVALID(crypt_block[i][0],
srv_sort_buf_size);
}
} }
buf[i] = row_merge_buf_empty(buf[i]); buf[i] = row_merge_buf_empty(buf[i]);
...@@ -851,7 +911,10 @@ exit: ...@@ -851,7 +911,10 @@ exit:
error = row_merge_sort(psort_info->psort_common->trx, error = row_merge_sort(psort_info->psort_common->trx,
psort_info->psort_common->dup, psort_info->psort_common->dup,
merge_file[i], block[i], &tmpfd[i], false, 0.0/* pct_progress */, 0.0/* pct_cost */); merge_file[i], block[i], &tmpfd[i],
false, 0.0/* pct_progress */, 0.0/* pct_cost */,
crypt_data, crypt_block[i], table->space);
if (error != DB_SUCCESS) { if (error != DB_SUCCESS) {
close(tmpfd[i]); close(tmpfd[i]);
goto func_exit; goto func_exit;
...@@ -1355,6 +1418,7 @@ row_fts_merge_insert( ...@@ -1355,6 +1418,7 @@ row_fts_merge_insert(
mrec_buf_t** buf; mrec_buf_t** buf;
int* fd; int* fd;
byte** block; byte** block;
byte** crypt_block;
const mrec_t** mrec; const mrec_t** mrec;
ulint count = 0; ulint count = 0;
int* sel_tree; int* sel_tree;
...@@ -1362,6 +1426,8 @@ row_fts_merge_insert( ...@@ -1362,6 +1426,8 @@ row_fts_merge_insert(
ulint start; ulint start;
fts_psort_insert_t ins_ctx; fts_psort_insert_t ins_ctx;
ulint count_diag = 0; ulint count_diag = 0;
fil_space_crypt_t* crypt_data = NULL;
ulint space;
ut_ad(index); ut_ad(index);
ut_ad(table); ut_ad(table);
...@@ -1374,6 +1440,7 @@ row_fts_merge_insert( ...@@ -1374,6 +1440,7 @@ row_fts_merge_insert(
ins_ctx.trx->op_info = "inserting index entries"; ins_ctx.trx->op_info = "inserting index entries";
ins_ctx.opt_doc_id_size = psort_info[0].psort_common->opt_doc_id_size; ins_ctx.opt_doc_id_size = psort_info[0].psort_common->opt_doc_id_size;
crypt_data = psort_info[0].psort_common->crypt_data;
heap = mem_heap_create(500 + sizeof(mrec_buf_t)); heap = mem_heap_create(500 + sizeof(mrec_buf_t));
...@@ -1388,6 +1455,8 @@ row_fts_merge_insert( ...@@ -1388,6 +1455,8 @@ row_fts_merge_insert(
fd = (int*) mem_heap_alloc(heap, sizeof(*fd) * fts_sort_pll_degree); fd = (int*) mem_heap_alloc(heap, sizeof(*fd) * fts_sort_pll_degree);
block = (byte**) mem_heap_alloc( block = (byte**) mem_heap_alloc(
heap, sizeof(*block) * fts_sort_pll_degree); heap, sizeof(*block) * fts_sort_pll_degree);
crypt_block = (byte**) mem_heap_alloc(
heap, sizeof(*block) * fts_sort_pll_degree);
mrec = (const mrec_t**) mem_heap_alloc( mrec = (const mrec_t**) mem_heap_alloc(
heap, sizeof(*mrec) * fts_sort_pll_degree); heap, sizeof(*mrec) * fts_sort_pll_degree);
sel_tree = (int*) mem_heap_alloc( sel_tree = (int*) mem_heap_alloc(
...@@ -1408,6 +1477,7 @@ row_fts_merge_insert( ...@@ -1408,6 +1477,7 @@ row_fts_merge_insert(
offsets[i][0] = num; offsets[i][0] = num;
offsets[i][1] = dict_index_get_n_fields(index); offsets[i][1] = dict_index_get_n_fields(index);
block[i] = psort_info[i].merge_block[id]; block[i] = psort_info[i].merge_block[id];
crypt_block[i] = psort_info[i].crypt_block[id];
b[i] = psort_info[i].merge_block[id]; b[i] = psort_info[i].merge_block[id];
fd[i] = psort_info[i].merge_file[id]->fd; fd[i] = psort_info[i].merge_file[id]->fd;
foffs[i] = 0; foffs[i] = 0;
...@@ -1450,6 +1520,7 @@ row_fts_merge_insert( ...@@ -1450,6 +1520,7 @@ row_fts_merge_insert(
ins_ctx.fts_table.table_id = table->id; ins_ctx.fts_table.table_id = table->id;
ins_ctx.fts_table.parent = index->table->name; ins_ctx.fts_table.parent = index->table->name;
ins_ctx.fts_table.table = index->table; ins_ctx.fts_table.table = index->table;
space = table->space;
for (i = 0; i < fts_sort_pll_degree; i++) { for (i = 0; i < fts_sort_pll_degree; i++) {
if (psort_info[i].merge_file[id]->n_rec == 0) { if (psort_info[i].merge_file[id]->n_rec == 0) {
...@@ -1462,7 +1533,10 @@ row_fts_merge_insert( ...@@ -1462,7 +1533,10 @@ row_fts_merge_insert(
if (psort_info[i].merge_file[id]->offset > 0 if (psort_info[i].merge_file[id]->offset > 0
&& (!row_merge_read( && (!row_merge_read(
fd[i], foffs[i], fd[i], foffs[i],
(row_merge_block_t*) block[i]))) { (row_merge_block_t*) block[i],
crypt_data,
(row_merge_block_t*) crypt_block[i],
space))) {
error = DB_CORRUPTION; error = DB_CORRUPTION;
goto exit; goto exit;
} }
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment