
[Commits] a6bcd05da44: MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
by Varun 28 Mar '19
by Varun 28 Mar '19
28 Mar '19
revision-id: a6bcd05da441169f87acc433dd2e08cc7505ea95 (mariadb-10.2.22-108-ga6bcd05da44)
parent(s): c676f58c270d75b6c1889b24b9833afc65b0d98b
author: Varun Gupta
committer: Varun Gupta
timestamp: 2019-03-28 12:18:30 +0530
message:
MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
To fix the crash there we need to make sure that the
server while storing the statistical values in statistical tables should do it
in a multi-byte safe way.
Also there is no need to throw warnings if there is truncation while storing
values from statistical fields.
---
mysql-test/r/stat_tables.result | 57 ++++++++++++++++++++++++++++++++++
mysql-test/r/stat_tables_innodb.result | 57 ++++++++++++++++++++++++++++++++++
mysql-test/t/stat_tables.test | 40 ++++++++++++++++++++++++
sql/field.cc | 7 +++--
sql/sql_statistics.cc | 10 ++++--
5 files changed, 166 insertions(+), 5 deletions(-)
diff --git a/mysql-test/r/stat_tables.result b/mysql-test/r/stat_tables.result
index 3ebc3b47833..be868e55e84 100644
--- a/mysql-test/r/stat_tables.result
+++ b/mysql-test/r/stat_tables.result
@@ -624,4 +624,61 @@ SELECT MAX(pk) FROM t1;
MAX(pk)
NULL
DROP TABLE t1;
+#
+# MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
+#
+set names utf8;
+set @save_optimizer_use_condition_selectivity=@@optimizer_use_condition_selectivity;
+set optimizer_use_condition_selectivity=4;
+set use_stat_tables=preferably;
+set @save_histogram_size= @@histogram_size;
+set histogram_size=255;
+create table t1 ( a varchar(255) character set utf8);
+insert into t1 values (REPEAT('ӥ',255)), (REPEAT('ç',255));
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats where db_name='test' and table_name='t1';
+HEX(RIGHT(min_value, 1)) length(min_value)
+A7 254
+select HEX(RIGHT(max_value, 1)), length(max_value) from mysql.column_stats where db_name='test' and table_name='t1';
+HEX(RIGHT(max_value, 1)) length(max_value)
+A5 254
+analyze select * from t1 where a >= 'ӥ';
+id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2.00 50.00 50.00 Using where
+set @save_sql_mode= @@sql_mode;
+set sql_mode='ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
+update mysql.column_stats set min_value= REPEAT('ӥ',255) where db_name='test' and table_name='t1';
+Warnings:
+Warning 1265 Data truncated for column 'min_value' at row 1
+select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats where db_name='test' and table_name='t1';
+HEX(RIGHT(min_value, 1)) length(min_value)
+D3 255
+analyze select * from t1 where a >= 'ӥ';
+id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2.00 50.00 50.00 Using where
+set names latin1;
+drop table t1;
+CREATE TABLE t1 (col1 date);
+INSERT INTO t1 VALUES('2004-01-01'),('2004-02-29');
+INSERT INTO t1 VALUES('0000-10-31');
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+update mysql.column_stats set min_value='2004-0-31123' where db_name='test' and table_name='t1';
+select min_value from mysql.column_stats where db_name='test' and table_name='t1';
+min_value
+2004-0-31123
+select * from t1;
+col1
+2004-01-01
+2004-02-29
+0000-10-31
+drop table t1;
+set @@sql_mode= @save_sql_mode;
set use_stat_tables=@save_use_stat_tables;
+set @@histogram_size= @save_histogram_size;
+set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
diff --git a/mysql-test/r/stat_tables_innodb.result b/mysql-test/r/stat_tables_innodb.result
index a6c5525a0d3..86088490871 100644
--- a/mysql-test/r/stat_tables_innodb.result
+++ b/mysql-test/r/stat_tables_innodb.result
@@ -651,6 +651,63 @@ SELECT MAX(pk) FROM t1;
MAX(pk)
NULL
DROP TABLE t1;
+#
+# MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
+#
+set names utf8;
+set @save_optimizer_use_condition_selectivity=@@optimizer_use_condition_selectivity;
+set optimizer_use_condition_selectivity=4;
+set use_stat_tables=preferably;
+set @save_histogram_size= @@histogram_size;
+set histogram_size=255;
+create table t1 ( a varchar(255) character set utf8);
+insert into t1 values (REPEAT('ӥ',255)), (REPEAT('ç',255));
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats where db_name='test' and table_name='t1';
+HEX(RIGHT(min_value, 1)) length(min_value)
+A7 254
+select HEX(RIGHT(max_value, 1)), length(max_value) from mysql.column_stats where db_name='test' and table_name='t1';
+HEX(RIGHT(max_value, 1)) length(max_value)
+A5 254
+analyze select * from t1 where a >= 'ӥ';
+id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2.00 50.00 50.00 Using where
+set @save_sql_mode= @@sql_mode;
+set sql_mode='ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
+update mysql.column_stats set min_value= REPEAT('ӥ',255) where db_name='test' and table_name='t1';
+Warnings:
+Warning 1265 Data truncated for column 'min_value' at row 1
+select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats where db_name='test' and table_name='t1';
+HEX(RIGHT(min_value, 1)) length(min_value)
+D3 255
+analyze select * from t1 where a >= 'ӥ';
+id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2.00 50.00 50.00 Using where
+set names latin1;
+drop table t1;
+CREATE TABLE t1 (col1 date);
+INSERT INTO t1 VALUES('2004-01-01'),('2004-02-29');
+INSERT INTO t1 VALUES('0000-10-31');
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+update mysql.column_stats set min_value='2004-0-31123' where db_name='test' and table_name='t1';
+select min_value from mysql.column_stats where db_name='test' and table_name='t1';
+min_value
+2004-0-31123
+select * from t1;
+col1
+2004-01-01
+2004-02-29
+0000-10-31
+drop table t1;
+set @@sql_mode= @save_sql_mode;
set use_stat_tables=@save_use_stat_tables;
+set @@histogram_size= @save_histogram_size;
+set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
set optimizer_switch=@save_optimizer_switch_for_stat_tables_test;
SET SESSION STORAGE_ENGINE=DEFAULT;
diff --git a/mysql-test/t/stat_tables.test b/mysql-test/t/stat_tables.test
index b89ab2bbd2d..89c11ed4acf 100644
--- a/mysql-test/t/stat_tables.test
+++ b/mysql-test/t/stat_tables.test
@@ -401,4 +401,44 @@ SELECT MAX(pk) FROM t1;
DROP TABLE t1;
+--echo #
+--echo # MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
+--echo #
+
+set names utf8;
+set @save_optimizer_use_condition_selectivity=@@optimizer_use_condition_selectivity;
+set optimizer_use_condition_selectivity=4;
+set use_stat_tables=preferably;
+set @save_histogram_size= @@histogram_size;
+set histogram_size=255;
+
+create table t1 ( a varchar(255) character set utf8);
+insert into t1 values (REPEAT('ӥ',255)), (REPEAT('ç',255));
+
+analyze table t1;
+select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats where db_name='test' and table_name='t1';
+select HEX(RIGHT(max_value, 1)), length(max_value) from mysql.column_stats where db_name='test' and table_name='t1';
+analyze select * from t1 where a >= 'ӥ';
+
+set @save_sql_mode= @@sql_mode;
+set sql_mode='ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
+update mysql.column_stats set min_value= REPEAT('ӥ',255) where db_name='test' and table_name='t1';
+select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats where db_name='test' and table_name='t1';
+analyze select * from t1 where a >= 'ӥ';
+
+set names latin1;
+drop table t1;
+
+CREATE TABLE t1 (col1 date);
+INSERT INTO t1 VALUES('2004-01-01'),('2004-02-29');
+INSERT INTO t1 VALUES('0000-10-31');
+analyze table t1;
+update mysql.column_stats set min_value='2004-0-31123' where db_name='test' and table_name='t1';
+select min_value from mysql.column_stats where db_name='test' and table_name='t1';
+select * from t1;
+drop table t1;
+
+set @@sql_mode= @save_sql_mode;
set use_stat_tables=@save_use_stat_tables;
+set @@histogram_size= @save_histogram_size;
+set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
diff --git a/sql/field.cc b/sql/field.cc
index 080cf34c76d..0621015c0e4 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -7027,8 +7027,11 @@ Field_longstr::check_string_copy_error(const String_copier *copier,
if (!(pos= copier->most_important_error_pos()))
return FALSE;
- convert_to_printable(tmp, sizeof(tmp), pos, (end - pos), cs, 6);
- set_warning_truncated_wrong_value("string", tmp);
+ if (!is_stat_field)
+ {
+ convert_to_printable(tmp, sizeof(tmp), pos, (end - pos), cs, 6);
+ set_warning_truncated_wrong_value("string", tmp);
+ }
return TRUE;
}
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index b5811c683e8..0a51346adb2 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -1060,7 +1060,9 @@ class Column_stat: public Stat_table
else
{
table_field->collected_stats->min_value->val_str(&val);
- stat_field->store(val.ptr(), val.length(), &my_charset_bin);
+ uint32 length= Well_formed_prefix(val.charset(), val.ptr(),
+ MY_MIN(val.length(), stat_field->field_length)).length();
+ stat_field->store(val.ptr(), length, &my_charset_bin);
}
break;
case COLUMN_STAT_MAX_VALUE:
@@ -1069,7 +1071,9 @@ class Column_stat: public Stat_table
else
{
table_field->collected_stats->max_value->val_str(&val);
- stat_field->store(val.ptr(), val.length(), &my_charset_bin);
+ uint32 length= Well_formed_prefix(val.charset(), val.ptr(),
+ MY_MIN(val.length(), stat_field->field_length)).length();
+ stat_field->store(val.ptr(), length, &my_charset_bin);
}
break;
case COLUMN_STAT_NULLS_RATIO:
@@ -3059,7 +3063,7 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
}
}
}
-
+
table->stats_is_read= TRUE;
DBUG_RETURN(0);
1
0

[Commits] 5469d88e7b4: MDEV-19049 Server crashes in check_duplicate_long_entry_key, ASAN stack-buffer-overflow in Field_blob::get_key_image
by sachin.setiya@mariadb.com 28 Mar '19
by sachin.setiya@mariadb.com 28 Mar '19
28 Mar '19
revision-id: 5469d88e7b4e723e545cd7d511801a16a3642dc4 (mariadb-10.4.3-104-g5469d88e7b4)
parent(s): 0bc42602266815b81fe86b08c2228912c1a95340
author: Sachin
committer: Sachin
timestamp: 2019-03-28 11:29:25 +0530
message:
MDEV-19049 Server crashes in check_duplicate_long_entry_key, ASAN stack-buffer-overflow in Field_blob::get_key_image
Long Unique keys should always be last unique key.
---
mysql-test/main/long_unique.result | 64 +++++++++++++++----------------
mysql-test/main/long_unique_bugs.result | 46 ++++++++++++++++++++++
mysql-test/main/long_unique_bugs.test | 22 ++++++++++-
mysql-test/main/long_unique_innodb.result | 4 +-
mysql-test/main/long_unique_update.result | 8 ++--
sql/sql_table.cc | 9 +++++
6 files changed, 114 insertions(+), 39 deletions(-)
diff --git a/mysql-test/main/long_unique.result b/mysql-test/main/long_unique.result
index 3843ff4aff0..8ea6d36c321 100644
--- a/mysql-test/main/long_unique.result
+++ b/mysql-test/main/long_unique.result
@@ -184,8 +184,8 @@ t1 CREATE TABLE `t1` (
`a` blob DEFAULT NULL,
`c` int(11) DEFAULT NULL,
`db_row_hash_1` int(11) DEFAULT NULL,
- UNIQUE KEY `a` (`a`) USING HASH,
- UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`)
+ UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`),
+ UNIQUE KEY `a` (`a`) USING HASH
) ENGINE=MyISAM DEFAULT CHARSET=latin1
insert into t1 values(45,1,55),(46,1,55);
ERROR 23000: Duplicate entry '55' for key 'db_row_hash_1'
@@ -507,13 +507,13 @@ t1 CREATE TABLE `t1` (
`db_row_hash_1` int(11) DEFAULT NULL,
`db_row_hash_2` int(11) DEFAULT NULL,
`db_row_hash_3` int(11) DEFAULT NULL,
+ UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`),
+ UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`),
+ UNIQUE KEY `db_row_hash_3` (`db_row_hash_3`),
UNIQUE KEY `a` (`a`) USING HASH,
UNIQUE KEY `c` (`c`) USING HASH,
UNIQUE KEY `d` (`d`) USING HASH,
- UNIQUE KEY `e` (`e`) USING HASH,
- UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`),
- UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`),
- UNIQUE KEY `db_row_hash_3` (`db_row_hash_3`)
+ UNIQUE KEY `e` (`e`) USING HASH
) ENGINE=MyISAM DEFAULT CHARSET=latin1
alter table t1 add column db_row_hash_7 int, add column db_row_hash_5 int , add column db_row_hash_4 int ;
alter table t1 drop column db_row_hash_7,drop column db_row_hash_3, drop column db_row_hash_4;
@@ -543,17 +543,17 @@ t1 CREATE TABLE `t1` (
`db_row_hash_1` int(11) DEFAULT NULL,
`db_row_hash_2` int(11) DEFAULT NULL,
`db_row_hash_5` int(11) DEFAULT NULL,
- UNIQUE KEY `d` (`d`) USING HASH,
- UNIQUE KEY `e` (`e`) USING HASH,
UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`),
- UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`)
+ UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`),
+ UNIQUE KEY `d` (`d`) USING HASH,
+ UNIQUE KEY `e` (`e`) USING HASH
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show keys from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
-t1 0 d 1 d A NULL NULL NULL YES HASH
-t1 0 e 1 e A NULL NULL NULL YES HASH
t1 0 db_row_hash_1 1 db_row_hash_1 A NULL NULL NULL YES BTREE
t1 0 db_row_hash_2 1 db_row_hash_2 A NULL NULL NULL YES BTREE
+t1 0 d 1 d A NULL NULL NULL YES HASH
+t1 0 e 1 e A NULL NULL NULL YES HASH
#add column with unique index on blob;
alter table t1 add column a blob unique;
show create table t1;
@@ -567,18 +567,18 @@ t1 CREATE TABLE `t1` (
`db_row_hash_2` int(11) DEFAULT NULL,
`db_row_hash_5` int(11) DEFAULT NULL,
`a` blob DEFAULT NULL,
- UNIQUE KEY `d` (`d`) USING HASH,
- UNIQUE KEY `e` (`e`) USING HASH,
UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`),
UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`),
+ UNIQUE KEY `d` (`d`) USING HASH,
+ UNIQUE KEY `e` (`e`) USING HASH,
UNIQUE KEY `a` (`a`) USING HASH
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show keys from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
-t1 0 d 1 d A NULL NULL NULL YES HASH
-t1 0 e 1 e A NULL NULL NULL YES HASH
t1 0 db_row_hash_1 1 db_row_hash_1 A NULL NULL NULL YES BTREE
t1 0 db_row_hash_2 1 db_row_hash_2 A NULL NULL NULL YES BTREE
+t1 0 d 1 d A NULL NULL NULL YES HASH
+t1 0 e 1 e A NULL NULL NULL YES HASH
t1 0 a 1 a A NULL NULL NULL YES HASH
#try to change the blob unique column name;
#this will change index to b tree;
@@ -594,19 +594,19 @@ t1 CREATE TABLE `t1` (
`db_row_hash_2` int(11) DEFAULT NULL,
`db_row_hash_5` int(11) DEFAULT NULL,
`a` int(11) DEFAULT NULL,
- UNIQUE KEY `d` (`d`) USING HASH,
- UNIQUE KEY `e` (`e`),
UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`),
UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`),
- UNIQUE KEY `a` (`a`)
+ UNIQUE KEY `e` (`e`),
+ UNIQUE KEY `a` (`a`),
+ UNIQUE KEY `d` (`d`) USING HASH
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show keys from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
-t1 0 d 1 d A NULL NULL NULL YES HASH
-t1 0 e 1 e A NULL NULL NULL YES BTREE
t1 0 db_row_hash_1 1 db_row_hash_1 A NULL NULL NULL YES BTREE
t1 0 db_row_hash_2 1 db_row_hash_2 A NULL NULL NULL YES BTREE
+t1 0 e 1 e A NULL NULL NULL YES BTREE
t1 0 a 1 a A NULL NULL NULL YES BTREE
+t1 0 d 1 d A NULL NULL NULL YES HASH
alter table t1 add column clm1 blob unique,add column clm2 blob unique;
#try changing the name;
alter table t1 change column clm1 clm_changed1 blob, change column clm2 clm_changed2 blob;
@@ -623,21 +623,21 @@ t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL,
`clm_changed1` blob DEFAULT NULL,
`clm_changed2` blob DEFAULT NULL,
- UNIQUE KEY `d` (`d`) USING HASH,
- UNIQUE KEY `e` (`e`),
UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`),
UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`),
+ UNIQUE KEY `e` (`e`),
UNIQUE KEY `a` (`a`),
+ UNIQUE KEY `d` (`d`) USING HASH,
UNIQUE KEY `clm1` (`clm_changed1`) USING HASH,
UNIQUE KEY `clm2` (`clm_changed2`) USING HASH
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show keys from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
-t1 0 d 1 d A NULL NULL NULL YES HASH
-t1 0 e 1 e A NULL NULL NULL YES BTREE
t1 0 db_row_hash_1 1 db_row_hash_1 A NULL NULL NULL YES BTREE
t1 0 db_row_hash_2 1 db_row_hash_2 A NULL NULL NULL YES BTREE
+t1 0 e 1 e A NULL NULL NULL YES BTREE
t1 0 a 1 a A NULL NULL NULL YES BTREE
+t1 0 d 1 d A NULL NULL NULL YES HASH
t1 0 clm1 1 clm_changed1 A NULL NULL NULL YES HASH
t1 0 clm2 1 clm_changed2 A NULL NULL NULL YES HASH
#now drop the unique key;
@@ -655,19 +655,19 @@ t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL,
`clm_changed1` blob DEFAULT NULL,
`clm_changed2` blob DEFAULT NULL,
- UNIQUE KEY `d` (`d`) USING HASH,
- UNIQUE KEY `e` (`e`),
UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`),
UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`),
- UNIQUE KEY `a` (`a`)
+ UNIQUE KEY `e` (`e`),
+ UNIQUE KEY `a` (`a`),
+ UNIQUE KEY `d` (`d`) USING HASH
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show keys from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
-t1 0 d 1 d A NULL NULL NULL YES HASH
-t1 0 e 1 e A NULL NULL NULL YES BTREE
t1 0 db_row_hash_1 1 db_row_hash_1 A NULL NULL NULL YES BTREE
t1 0 db_row_hash_2 1 db_row_hash_2 A NULL NULL NULL YES BTREE
+t1 0 e 1 e A NULL NULL NULL YES BTREE
t1 0 a 1 a A NULL NULL NULL YES BTREE
+t1 0 d 1 d A NULL NULL NULL YES HASH
drop table t1;
#now the table with key on multiple columns; the ultimate test;
create table t1(a blob, b int , c varchar(2000) , d text , e varchar(3000) , f longblob , g int , h text ,
@@ -1130,17 +1130,17 @@ t1 CREATE TABLE `t1` (
`c` blob DEFAULT NULL,
`d` blob DEFAULT NULL,
`e` int(11) DEFAULT NULL,
+ UNIQUE KEY `e` (`e`),
UNIQUE KEY `a` (`a`,`c`) USING HASH,
- UNIQUE KEY `b` (`b`,`d`) USING HASH,
- UNIQUE KEY `e` (`e`)
+ UNIQUE KEY `b` (`b`,`d`) USING HASH
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show keys from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+t1 0 e 1 e A NULL NULL NULL YES BTREE
t1 0 a 1 a A NULL NULL NULL YES HASH
t1 0 a 2 c A NULL NULL NULL YES HASH
t1 0 b 1 b A NULL NULL NULL YES HASH
t1 0 b 2 d A NULL NULL NULL YES HASH
-t1 0 e 1 e A 0 NULL NULL YES BTREE
drop table t1;
#visibility of db_row_hash
create table t1 (a blob unique , b blob unique);
diff --git a/mysql-test/main/long_unique_bugs.result b/mysql-test/main/long_unique_bugs.result
index 87a57fb4614..48e74bdd564 100644
--- a/mysql-test/main/long_unique_bugs.result
+++ b/mysql-test/main/long_unique_bugs.result
@@ -239,3 +239,49 @@ CREATE TABLE t1 (a INT, UNIQUE USING HASH (a)) PARTITION BY HASH (a) PARTITIONS
INSERT INTO t1 VALUES (2);
REPLACE INTO t1 VALUES (2);
DROP TABLE t1;
+CREATE TABLE t1 (pk INT, a CHAR(4), b BLOB NOT NULL, PRIMARY KEY(pk));
+INSERT INTO t1 VALUES (1,'foo','bar');
+ALTER TABLE t1 ADD KEY (b(64));
+ALTER TABLE t1 ADD UNIQUE (b(165));
+ALTER TABLE t1 ADD KEY (b(1000));
+ALTER TABLE t1 ADD KEY (b(500));
+ALTER TABLE t1 ADD UNIQUE (a,b);
+ALTER TABLE t1 ADD UNIQUE (b(95));
+ALTER TABLE t1 ADD KEY (b(30));
+ALTER TABLE t1 ADD UNIQUE (b(20));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `pk` int(11) NOT NULL,
+ `a` char(4) DEFAULT NULL,
+ `b` blob NOT NULL,
+ PRIMARY KEY (`pk`),
+ UNIQUE KEY `b_2` (`b`(165)),
+ UNIQUE KEY `b_5` (`b`(95)),
+ UNIQUE KEY `b_7` (`b`(20)),
+ UNIQUE KEY `a` (`a`,`b`) USING HASH,
+ KEY `b` (`b`(64)),
+ KEY `b_3` (`b`(1000)),
+ KEY `b_4` (`b`(500)),
+ KEY `b_6` (`b`(30))
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+ALTER TABLE t1 ADD UNIQUE (b);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `pk` int(11) NOT NULL,
+ `a` char(4) DEFAULT NULL,
+ `b` blob NOT NULL,
+ PRIMARY KEY (`pk`),
+ UNIQUE KEY `b_2` (`b`(165)),
+ UNIQUE KEY `b_5` (`b`(95)),
+ UNIQUE KEY `b_7` (`b`(20)),
+ UNIQUE KEY `a` (`a`,`b`) USING HASH,
+ UNIQUE KEY `b_8` (`b`) USING HASH,
+ KEY `b` (`b`(64)),
+ KEY `b_3` (`b`(1000)),
+ KEY `b_4` (`b`(500)),
+ KEY `b_6` (`b`(30))
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+ALTER TABLE t1 FORCE;
+DROP TABLE t1;
diff --git a/mysql-test/main/long_unique_bugs.test b/mysql-test/main/long_unique_bugs.test
index ed0daee426f..11b1c4f09b6 100644
--- a/mysql-test/main/long_unique_bugs.test
+++ b/mysql-test/main/long_unique_bugs.test
@@ -1,4 +1,5 @@
--source include/have_innodb.inc
+--source include/have_partition.inc
#
# MDEV-18707 Server crash in my_hash_sort_bin, ASAN heap-use-after-free in Field::is_null, server hang, corrupted double-linked list
@@ -269,8 +270,27 @@ drop table t1;
#
# MDEV-18904 Assertion `m_part_spec.start_part >= m_part_spec.end_part' failed in ha_partition::index_read_idx_map
#
---source include/have_partition.inc
CREATE TABLE t1 (a INT, UNIQUE USING HASH (a)) PARTITION BY HASH (a) PARTITIONS 2;
INSERT INTO t1 VALUES (2);
REPLACE INTO t1 VALUES (2);
DROP TABLE t1;
+
+#
+# MDEV-19049 Server crashes in check_duplicate_long_entry_key, ASAN stack-buffer-overflow in Field_blob::get_key_image
+#
+CREATE TABLE t1 (pk INT, a CHAR(4), b BLOB NOT NULL, PRIMARY KEY(pk));
+INSERT INTO t1 VALUES (1,'foo','bar');
+
+ALTER TABLE t1 ADD KEY (b(64));
+ALTER TABLE t1 ADD UNIQUE (b(165));
+ALTER TABLE t1 ADD KEY (b(1000));
+ALTER TABLE t1 ADD KEY (b(500));
+ALTER TABLE t1 ADD UNIQUE (a,b);
+ALTER TABLE t1 ADD UNIQUE (b(95));
+ALTER TABLE t1 ADD KEY (b(30));
+ALTER TABLE t1 ADD UNIQUE (b(20));
+show create table t1;
+ALTER TABLE t1 ADD UNIQUE (b);
+show create table t1;
+ALTER TABLE t1 FORCE;
+DROP TABLE t1;
diff --git a/mysql-test/main/long_unique_innodb.result b/mysql-test/main/long_unique_innodb.result
index cb8c3ea4858..135bb0808cc 100644
--- a/mysql-test/main/long_unique_innodb.result
+++ b/mysql-test/main/long_unique_innodb.result
@@ -9,8 +9,8 @@ Table Create Table
t1 CREATE TABLE `t1` (
`a` blob DEFAULT NULL,
`c` int(11) DEFAULT NULL,
- UNIQUE KEY `a` (`a`) USING HASH,
- UNIQUE KEY `c` (`c`)
+ UNIQUE KEY `c` (`c`),
+ UNIQUE KEY `a` (`a`) USING HASH
) ENGINE=InnoDB DEFAULT CHARSET=latin1
drop table t1;
#test for concurrent insert of long unique in innodb
diff --git a/mysql-test/main/long_unique_update.result b/mysql-test/main/long_unique_update.result
index 60a4fb46558..b508583f47c 100644
--- a/mysql-test/main/long_unique_update.result
+++ b/mysql-test/main/long_unique_update.result
@@ -71,8 +71,8 @@ create table t1 (a int primary key, b blob unique , c int unique );
show keys from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
t1 0 PRIMARY 1 a A 0 NULL NULL BTREE
-t1 0 b 1 b A NULL NULL NULL YES HASH
t1 0 c 1 c A NULL NULL NULL YES BTREE
+t1 0 b 1 b A NULL NULL NULL YES HASH
insert into t1 values(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),(6,6,6),(7,7,7);
select * from t1 limit 3;
a b c
@@ -220,18 +220,18 @@ t1 CREATE TABLE `t1` (
`f` int(11) DEFAULT NULL,
`g` text DEFAULT NULL,
PRIMARY KEY (`a`),
- UNIQUE KEY `b` (`b`,`c`) USING HASH,
UNIQUE KEY `b_2` (`b`,`f`),
+ UNIQUE KEY `b` (`b`,`c`) USING HASH,
UNIQUE KEY `e` (`e`,`g`) USING HASH,
UNIQUE KEY `a` (`a`,`b`,`c`,`d`,`e`,`f`,`g`) USING HASH
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show keys from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
t1 0 PRIMARY 1 a A 0 NULL NULL BTREE
-t1 0 b 1 b A NULL NULL NULL YES HASH
-t1 0 b 2 c A NULL NULL NULL YES HASH
t1 0 b_2 1 b A NULL NULL NULL YES BTREE
t1 0 b_2 2 f A NULL NULL NULL YES BTREE
+t1 0 b 1 b A NULL NULL NULL YES HASH
+t1 0 b 2 c A NULL NULL NULL YES HASH
t1 0 e 1 e A NULL NULL NULL YES HASH
t1 0 e 2 g A NULL NULL NULL YES HASH
t1 0 a 1 a A NULL NULL NULL HASH
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index ad62ecc1103..c755a74e174 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -2773,6 +2773,7 @@ bool quick_rm_table(THD *thd, handlerton *base, const LEX_CSTRING *db,
- UNIQUE keys where all column are NOT NULL
- UNIQUE keys that don't contain partial segments
- Other UNIQUE keys
+ - LONG UNIQUE keys
- Normal keys
- Fulltext keys
@@ -2796,6 +2797,14 @@ static int sort_keys(KEY *a, KEY *b)
{
if (!(b_flags & HA_NOSAME))
return -1;
+ /*
+ Long Unique keys should always be last unique key.
+ Before this patch they used to change order wrt to partial keys (MDEV-19049)
+ */
+ if (a->algorithm == HA_KEY_ALG_LONG_HASH)
+ return 1;
+ if (b->algorithm == HA_KEY_ALG_LONG_HASH)
+ return -1;
if ((a_flags ^ b_flags) & HA_NULL_PART_KEY)
{
/* Sort NOT NULL keys before other keys */
1
0

[Commits] ade7a65e183: MDEV-18820 Assertion `lock_table_has(trx, index->table, LOCK_IX)' failed in lock_rec_insert_check_and_lock upon INSERT into table with blob key
by sachin.setiya@mariadb.com 28 Mar '19
by sachin.setiya@mariadb.com 28 Mar '19
28 Mar '19
revision-id: ade7a65e183296b0afc67dae49e7f9eced9a8fcd (mariadb-10.4.3-105-gade7a65e183)
parent(s): 5469d88e7b4e723e545cd7d511801a16a3642dc4
author: Sachin
committer: Sachin
timestamp: 2019-03-28 11:33:14 +0530
message:
MDEV-18820 Assertion `lock_table_has(trx, index->table, LOCK_IX)' failed in lock_rec_insert_check_and_lock upon INSERT into table with blob key
Don't Ignore HA_ERR_LOCK_DEADLOCK error
---
mysql-test/main/long_unique_bugs.result | 26 ++++++++++++++++++++
mysql-test/main/long_unique_bugs.test | 43 +++++++++++++++++++++++++++++++++
sql/handler.cc | 5 ++--
3 files changed, 72 insertions(+), 2 deletions(-)
diff --git a/mysql-test/main/long_unique_bugs.result b/mysql-test/main/long_unique_bugs.result
index 48e74bdd564..9b0df9e32fe 100644
--- a/mysql-test/main/long_unique_bugs.result
+++ b/mysql-test/main/long_unique_bugs.result
@@ -285,3 +285,29 @@ t1 CREATE TABLE `t1` (
) ENGINE=MyISAM DEFAULT CHARSET=latin1
ALTER TABLE t1 FORCE;
DROP TABLE t1;
+set innodb_lock_wait_timeout= 10;
+CREATE TABLE t1 (
+id int primary key,
+f INT unique
+) ENGINE=InnoDB;
+CREATE TABLE t2 (
+id int primary key,
+a blob unique
+) ENGINE=InnoDB;
+START TRANSACTION;
+connect con1,localhost,root,,test;
+connection con1;
+set innodb_lock_wait_timeout= 10;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1,1)/*1*/;
+connection default;
+INSERT INTO t2 VALUES (2, 1)/*2*/ ;
+connection con1;
+INSERT INTO t2 VALUES (3, 1)/*3*/;
+connection default;
+INSERT IGNORE INTO t1 VALUES (4, 1)/*4*/;
+connection con1;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+disconnect con1;
+connection default;
+DROP TABLE t1, t2;
diff --git a/mysql-test/main/long_unique_bugs.test b/mysql-test/main/long_unique_bugs.test
index 11b1c4f09b6..8e4b950b250 100644
--- a/mysql-test/main/long_unique_bugs.test
+++ b/mysql-test/main/long_unique_bugs.test
@@ -294,3 +294,46 @@ ALTER TABLE t1 ADD UNIQUE (b);
show create table t1;
ALTER TABLE t1 FORCE;
DROP TABLE t1;
+
+#
+# MDEV-18820 Assertion `lock_table_has(trx, index->table, LOCK_IX)' failed in lock_rec_insert_check_and_lock upon INSERT into table with blob key'
+#
+
+--source include/have_innodb.inc
+set innodb_lock_wait_timeout= 10;
+
+CREATE TABLE t1 (
+ id int primary key,
+ f INT unique
+) ENGINE=InnoDB;
+
+CREATE TABLE t2 (
+ id int primary key,
+ a blob unique
+) ENGINE=InnoDB;
+
+START TRANSACTION;
+
+--connect (con1,localhost,root,,test)
+
+--connection con1
+set innodb_lock_wait_timeout= 10;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1,1)/*1*/;
+
+--connection default
+INSERT INTO t2 VALUES (2, 1)/*2*/ ;
+
+--connection con1
+--send
+ INSERT INTO t2 VALUES (3, 1)/*3*/;
+
+--connection default
+INSERT IGNORE INTO t1 VALUES (4, 1)/*4*/;
+
+--connection con1
+--error ER_LOCK_DEADLOCK
+--reap
+--disconnect con1
+--connection default
+DROP TABLE t1, t2;
diff --git a/sql/handler.cc b/sql/handler.cc
index da7850c5c4e..5fb67f92fc7 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -6590,8 +6590,9 @@ static int check_duplicate_long_entry_key(TABLE *table, handler *h,
error= HA_ERR_FOUND_DUPP_KEY;
goto exit;
}
- if (result == HA_ERR_LOCK_WAIT_TIMEOUT)
- error= HA_ERR_LOCK_WAIT_TIMEOUT;
+ if (result == HA_ERR_LOCK_WAIT_TIMEOUT ||
+ result == HA_ERR_LOCK_DEADLOCK)
+ error= result;
exit:
if (error)
{
1
0

[Commits] e0fa1993692: MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
by Varun 27 Mar '19
by Varun 27 Mar '19
27 Mar '19
revision-id: e0fa1993692a3552feddae56cbee3078d4da2121 (mariadb-10.2.22-91-ge0fa1993692)
parent(s): 50a8fc52988d13a5164a1a542b9d7a85e3ecc1c1
author: Varun Gupta
committer: Varun Gupta
timestamp: 2019-03-27 13:48:44 +0530
message:
MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
To fix the crash there we need to make sure that the
server while storing the statistical values in statistical tables should do it
in a multi-byte safe way.
Also there is no need to throw warnings if there is truncation while storing
values from statistical fields.
---
mysql-test/r/stat_tables.result | 57 ++++++++++++++++++++++++++++++++++
mysql-test/r/stat_tables_innodb.result | 57 ++++++++++++++++++++++++++++++++++
mysql-test/t/stat_tables.test | 40 ++++++++++++++++++++++++
sql/field.cc | 9 ++++--
sql/sql_statistics.cc | 13 +++++---
5 files changed, 169 insertions(+), 7 deletions(-)
diff --git a/mysql-test/r/stat_tables.result b/mysql-test/r/stat_tables.result
index 3ebc3b47833..c3a9fc17d55 100644
--- a/mysql-test/r/stat_tables.result
+++ b/mysql-test/r/stat_tables.result
@@ -624,4 +624,61 @@ SELECT MAX(pk) FROM t1;
MAX(pk)
NULL
DROP TABLE t1;
+#
+# MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
+#
+set names utf8;
+set @save_optimizer_use_condition_selectivity=@@optimizer_use_condition_selectivity;
+set optimizer_use_condition_selectivity=4;
+set use_stat_tables=preferably;
+set @save_histogram_size= @@histogram_size;
+set histogram_size=255;
+create table t1 ( a varchar(255) character set utf8);
+insert into t1 values (REPEAT('ӥ',255)), (REPEAT('ç',255));
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats;
+HEX(RIGHT(min_value, 1)) length(min_value)
+A7 254
+select HEX(RIGHT(max_value, 1)), length(max_value) from mysql.column_stats;
+HEX(RIGHT(max_value, 1)) length(max_value)
+A5 254
+analyze select * from t1 where a >= 'ӥ';
+id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2.00 50.00 50.00 Using where
+set @save_sql_mode= @@sql_mode;
+set sql_mode='ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
+update mysql.column_stats set min_value= REPEAT('ӥ',255);
+Warnings:
+Warning 1265 Data truncated for column 'min_value' at row 1
+select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats;
+HEX(RIGHT(min_value, 1)) length(min_value)
+D3 255
+analyze select * from t1 where a >= 'ӥ';
+id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2.00 50.00 50.00 Using where
+set names latin1;
+drop table t1;
+CREATE TABLE t1 (col1 date);
+INSERT INTO t1 VALUES('2004-01-01'),('2004-02-29');
+INSERT INTO t1 VALUES('0000-10-31');
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+update mysql.column_stats set min_value='2004-0-31123';
+select min_value from mysql.column_stats;
+min_value
+2004-0-31123
+select * from t1;
+col1
+2004-01-01
+2004-02-29
+0000-10-31
+drop table t1;
+set @@sql_mode= @save_sql_mode;
set use_stat_tables=@save_use_stat_tables;
+set @@histogram_size= @save_histogram_size;
+set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
diff --git a/mysql-test/r/stat_tables_innodb.result b/mysql-test/r/stat_tables_innodb.result
index a6c5525a0d3..0ec31ed095b 100644
--- a/mysql-test/r/stat_tables_innodb.result
+++ b/mysql-test/r/stat_tables_innodb.result
@@ -651,6 +651,63 @@ SELECT MAX(pk) FROM t1;
MAX(pk)
NULL
DROP TABLE t1;
+#
+# MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
+#
+set names utf8;
+set @save_optimizer_use_condition_selectivity=@@optimizer_use_condition_selectivity;
+set optimizer_use_condition_selectivity=4;
+set use_stat_tables=preferably;
+set @save_histogram_size= @@histogram_size;
+set histogram_size=255;
+create table t1 ( a varchar(255) character set utf8);
+insert into t1 values (REPEAT('ӥ',255)), (REPEAT('ç',255));
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats;
+HEX(RIGHT(min_value, 1)) length(min_value)
+A7 254
+select HEX(RIGHT(max_value, 1)), length(max_value) from mysql.column_stats;
+HEX(RIGHT(max_value, 1)) length(max_value)
+A5 254
+analyze select * from t1 where a >= 'ӥ';
+id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2.00 50.00 50.00 Using where
+set @save_sql_mode= @@sql_mode;
+set sql_mode='ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
+update mysql.column_stats set min_value= REPEAT('ӥ',255);
+Warnings:
+Warning 1265 Data truncated for column 'min_value' at row 1
+select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats;
+HEX(RIGHT(min_value, 1)) length(min_value)
+D3 255
+analyze select * from t1 where a >= 'ӥ';
+id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2.00 50.00 50.00 Using where
+set names latin1;
+drop table t1;
+CREATE TABLE t1 (col1 date);
+INSERT INTO t1 VALUES('2004-01-01'),('2004-02-29');
+INSERT INTO t1 VALUES('0000-10-31');
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+update mysql.column_stats set min_value='2004-0-31123';
+select min_value from mysql.column_stats;
+min_value
+2004-0-31123
+select * from t1;
+col1
+2004-01-01
+2004-02-29
+0000-10-31
+drop table t1;
+set @@sql_mode= @save_sql_mode;
set use_stat_tables=@save_use_stat_tables;
+set @@histogram_size= @save_histogram_size;
+set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
set optimizer_switch=@save_optimizer_switch_for_stat_tables_test;
SET SESSION STORAGE_ENGINE=DEFAULT;
diff --git a/mysql-test/t/stat_tables.test b/mysql-test/t/stat_tables.test
index b89ab2bbd2d..114c5c97a7e 100644
--- a/mysql-test/t/stat_tables.test
+++ b/mysql-test/t/stat_tables.test
@@ -401,4 +401,44 @@ SELECT MAX(pk) FROM t1;
DROP TABLE t1;
+--echo #
+--echo # MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
+--echo #
+
+set names utf8;
+set @save_optimizer_use_condition_selectivity=@@optimizer_use_condition_selectivity;
+set optimizer_use_condition_selectivity=4;
+set use_stat_tables=preferably;
+set @save_histogram_size= @@histogram_size;
+set histogram_size=255;
+
+create table t1 ( a varchar(255) character set utf8);
+insert into t1 values (REPEAT('ӥ',255)), (REPEAT('ç',255));
+
+analyze table t1;
+select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats;
+select HEX(RIGHT(max_value, 1)), length(max_value) from mysql.column_stats;
+analyze select * from t1 where a >= 'ӥ';
+
+set @save_sql_mode= @@sql_mode;
+set sql_mode='ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
+update mysql.column_stats set min_value= REPEAT('ӥ',255);
+select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats;
+analyze select * from t1 where a >= 'ӥ';
+
+set names latin1;
+drop table t1;
+
+CREATE TABLE t1 (col1 date);
+INSERT INTO t1 VALUES('2004-01-01'),('2004-02-29');
+INSERT INTO t1 VALUES('0000-10-31');
+analyze table t1;
+update mysql.column_stats set min_value='2004-0-31123';
+select min_value from mysql.column_stats;
+select * from t1;
+drop table t1;
+
+set @@sql_mode= @save_sql_mode;
set use_stat_tables=@save_use_stat_tables;
+set @@histogram_size= @save_histogram_size;
+set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
diff --git a/sql/field.cc b/sql/field.cc
index 080cf34c76d..c26195a3650 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -2219,7 +2219,6 @@ bool Field_str::can_be_substituted_to_equal_item(const Context &ctx,
return false;
}
-
void Field_num::make_field(Send_field *field)
{
Field::make_field(field);
@@ -7023,12 +7022,16 @@ Field_longstr::check_string_copy_error(const String_copier *copier,
{
const char *pos;
char tmp[32];
+ THD *thd= get_thd();
if (!(pos= copier->most_important_error_pos()))
return FALSE;
- convert_to_printable(tmp, sizeof(tmp), pos, (end - pos), cs, 6);
- set_warning_truncated_wrong_value("string", tmp);
+ if (thd->count_cuted_fields)
+ {
+ convert_to_printable(tmp, sizeof(tmp), pos, (end - pos), cs, 6);
+ set_warning_truncated_wrong_value("string", tmp);
+ }
return TRUE;
}
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index b5811c683e8..0960a9a1ec5 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -1044,6 +1044,7 @@ class Column_stat: public Stat_table
{
char buff[MAX_FIELD_WIDTH];
String val(buff, sizeof(buff), &my_charset_bin);
+ uint32 length= 0;
for (uint i= COLUMN_STAT_MIN_VALUE; i <= COLUMN_STAT_HISTOGRAM; i++)
{
@@ -1060,7 +1061,9 @@ class Column_stat: public Stat_table
else
{
table_field->collected_stats->min_value->val_str(&val);
- stat_field->store(val.ptr(), val.length(), &my_charset_bin);
+ length= Well_formed_prefix(val.charset(), val.ptr(),
+ MY_MIN(val.length(), stat_field->field_length)).length();
+ stat_field->store(val.ptr(), length, &my_charset_bin);
}
break;
case COLUMN_STAT_MAX_VALUE:
@@ -1069,7 +1072,9 @@ class Column_stat: public Stat_table
else
{
table_field->collected_stats->max_value->val_str(&val);
- stat_field->store(val.ptr(), val.length(), &my_charset_bin);
+ length= Well_formed_prefix(val.charset(), val.ptr(),
+ MY_MIN(val.length(), stat_field->field_length)).length();
+ stat_field->store(val.ptr(), length, &my_charset_bin);
}
break;
case COLUMN_STAT_NULLS_RATIO:
@@ -2934,7 +2939,6 @@ int update_statistics_for_table(THD *thd, TABLE *table)
DBUG_RETURN(rc);
}
-
/**
@brief
Read statistics for a table from the persistent statistical tables
@@ -2980,6 +2984,7 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
Table_statistics *read_stats= table_share->stats_cb.table_stats;
DBUG_ENTER("read_statistics_for_table");
+ DBUG_ASSERT(thd->count_cuted_fields == CHECK_FIELD_IGNORE);
/* Read statistics from the statistical table table_stats */
stat_table= stat_tables[TABLE_STAT].table;
@@ -3059,7 +3064,7 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
}
}
}
-
+
table->stats_is_read= TRUE;
DBUG_RETURN(0);
2
1

[Commits] 90346ebbfe8: MDEV-19049 Server crashes in check_duplicate_long_entry_key, ASAN stack-buffer-overflow in Field_blob::get_key_image
by sachin.setiya@mariadb.com 27 Mar '19
by sachin.setiya@mariadb.com 27 Mar '19
27 Mar '19
revision-id: 90346ebbfe860221fb85330ce6c9056bf4a065ad (mariadb-10.4.3-104-g90346ebbfe8)
parent(s): 0bc42602266815b81fe86b08c2228912c1a95340
author: Sachin
committer: Sachin
timestamp: 2019-03-27 14:44:00 +0530
message:
MDEV-19049 Server crashes in check_duplicate_long_entry_key, ASAN stack-buffer-overflow in Field_blob::get_key_image
Long Unique keys should always be last unique key.
---
mysql-test/main/long_unique_bugs.result | 46 +++++++++++++++++++++++++++++++++
mysql-test/main/long_unique_bugs.test | 22 +++++++++++++++-
sql/sql_table.cc | 9 +++++++
3 files changed, 76 insertions(+), 1 deletion(-)
diff --git a/mysql-test/main/long_unique_bugs.result b/mysql-test/main/long_unique_bugs.result
index 87a57fb4614..48e74bdd564 100644
--- a/mysql-test/main/long_unique_bugs.result
+++ b/mysql-test/main/long_unique_bugs.result
@@ -239,3 +239,49 @@ CREATE TABLE t1 (a INT, UNIQUE USING HASH (a)) PARTITION BY HASH (a) PARTITIONS
INSERT INTO t1 VALUES (2);
REPLACE INTO t1 VALUES (2);
DROP TABLE t1;
+CREATE TABLE t1 (pk INT, a CHAR(4), b BLOB NOT NULL, PRIMARY KEY(pk));
+INSERT INTO t1 VALUES (1,'foo','bar');
+ALTER TABLE t1 ADD KEY (b(64));
+ALTER TABLE t1 ADD UNIQUE (b(165));
+ALTER TABLE t1 ADD KEY (b(1000));
+ALTER TABLE t1 ADD KEY (b(500));
+ALTER TABLE t1 ADD UNIQUE (a,b);
+ALTER TABLE t1 ADD UNIQUE (b(95));
+ALTER TABLE t1 ADD KEY (b(30));
+ALTER TABLE t1 ADD UNIQUE (b(20));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `pk` int(11) NOT NULL,
+ `a` char(4) DEFAULT NULL,
+ `b` blob NOT NULL,
+ PRIMARY KEY (`pk`),
+ UNIQUE KEY `b_2` (`b`(165)),
+ UNIQUE KEY `b_5` (`b`(95)),
+ UNIQUE KEY `b_7` (`b`(20)),
+ UNIQUE KEY `a` (`a`,`b`) USING HASH,
+ KEY `b` (`b`(64)),
+ KEY `b_3` (`b`(1000)),
+ KEY `b_4` (`b`(500)),
+ KEY `b_6` (`b`(30))
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+ALTER TABLE t1 ADD UNIQUE (b);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `pk` int(11) NOT NULL,
+ `a` char(4) DEFAULT NULL,
+ `b` blob NOT NULL,
+ PRIMARY KEY (`pk`),
+ UNIQUE KEY `b_2` (`b`(165)),
+ UNIQUE KEY `b_5` (`b`(95)),
+ UNIQUE KEY `b_7` (`b`(20)),
+ UNIQUE KEY `a` (`a`,`b`) USING HASH,
+ UNIQUE KEY `b_8` (`b`) USING HASH,
+ KEY `b` (`b`(64)),
+ KEY `b_3` (`b`(1000)),
+ KEY `b_4` (`b`(500)),
+ KEY `b_6` (`b`(30))
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+ALTER TABLE t1 FORCE;
+DROP TABLE t1;
diff --git a/mysql-test/main/long_unique_bugs.test b/mysql-test/main/long_unique_bugs.test
index ed0daee426f..11b1c4f09b6 100644
--- a/mysql-test/main/long_unique_bugs.test
+++ b/mysql-test/main/long_unique_bugs.test
@@ -1,4 +1,5 @@
--source include/have_innodb.inc
+--source include/have_partition.inc
#
# MDEV-18707 Server crash in my_hash_sort_bin, ASAN heap-use-after-free in Field::is_null, server hang, corrupted double-linked list
@@ -269,8 +270,27 @@ drop table t1;
#
# MDEV-18904 Assertion `m_part_spec.start_part >= m_part_spec.end_part' failed in ha_partition::index_read_idx_map
#
---source include/have_partition.inc
CREATE TABLE t1 (a INT, UNIQUE USING HASH (a)) PARTITION BY HASH (a) PARTITIONS 2;
INSERT INTO t1 VALUES (2);
REPLACE INTO t1 VALUES (2);
DROP TABLE t1;
+
+#
+# MDEV-19049 Server crashes in check_duplicate_long_entry_key, ASAN stack-buffer-overflow in Field_blob::get_key_image
+#
+CREATE TABLE t1 (pk INT, a CHAR(4), b BLOB NOT NULL, PRIMARY KEY(pk));
+INSERT INTO t1 VALUES (1,'foo','bar');
+
+ALTER TABLE t1 ADD KEY (b(64));
+ALTER TABLE t1 ADD UNIQUE (b(165));
+ALTER TABLE t1 ADD KEY (b(1000));
+ALTER TABLE t1 ADD KEY (b(500));
+ALTER TABLE t1 ADD UNIQUE (a,b);
+ALTER TABLE t1 ADD UNIQUE (b(95));
+ALTER TABLE t1 ADD KEY (b(30));
+ALTER TABLE t1 ADD UNIQUE (b(20));
+show create table t1;
+ALTER TABLE t1 ADD UNIQUE (b);
+show create table t1;
+ALTER TABLE t1 FORCE;
+DROP TABLE t1;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index ad62ecc1103..c755a74e174 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -2773,6 +2773,7 @@ bool quick_rm_table(THD *thd, handlerton *base, const LEX_CSTRING *db,
- UNIQUE keys where all column are NOT NULL
- UNIQUE keys that don't contain partial segments
- Other UNIQUE keys
+ - LONG UNIQUE keys
- Normal keys
- Fulltext keys
@@ -2796,6 +2797,14 @@ static int sort_keys(KEY *a, KEY *b)
{
if (!(b_flags & HA_NOSAME))
return -1;
+ /*
+ Long Unique keys should always be last unique key.
+ Before this patch they used to change order wrt to partial keys (MDEV-19049)
+ */
+ if (a->algorithm == HA_KEY_ALG_LONG_HASH)
+ return 1;
+ if (b->algorithm == HA_KEY_ALG_LONG_HASH)
+ return -1;
if ((a_flags ^ b_flags) & HA_NULL_PART_KEY)
{
/* Sort NOT NULL keys before other keys */
1
0

27 Mar '19
revision-id: 5af1899d19fa872c4a7c9e2c6a572701009c0437 (mariadb-10.1.38-78-g5af1899d19f)
parent(s): 762419a5732fceb5c7ed5728cd7d22b4d82ff74c
author: Jan Lindström
committer: Jan Lindström
timestamp: 2019-03-27 09:28:49 +0200
message:
MDEV-18464: Port kill_one_trx fixes from 10.4 to 10.1
Pushed the decision for innodb transaction and system
locking down to lock0lock.cc level. With this,
we can avoid releasing these mutexes for executions
where these mutexes were acquired upfront.
This patch will also fix BF aborting of native threads, e.g.
threads which have declared wsrep_on=OFF. Earlier, we have
used, for innodb trx locks, was_chosen_as_deadlock_victim
flag, for marking inodb transactions, which are victims for
wsrep BF abort. With native threads (wsrep_on==OFF), re-using
was_chosen_as_deadlock_victim flag may lead to inteference
with real deadlock, and to deal with this, the patch has added new
flag for marking wsrep BF aborts only: victim=true
Similar way if replication decides to abort one of the threads
we mark victim by: victim=true
innobase_kill_query
Remove lock sys and trx mutex handling.
wsrep_innobase_kill_one_trx
Mark victim trx with victim=true
trx0trx.h
Remove trx_abort_t type and abort type variable from
trx struct. Add victim variable to trx.
wsrep_kill_victim
Remove abort_type
lock_report_waiters_to_mysql
Take also trx mutex and mark trx as a victim for
replication abort.
lock_trx_handle_wait_low
New low level function to check whether the transaction
has already been rolled back because it was selected as
a deadlock victim, or if it has to wait then cancel
the wait lock.
lock_trx_handle_wait
If transaction is not marked as victim take lock sys
and trx mutex before calling lock_trx_handle_wait_low
and release them after that.
row_search_for_mysql
Remove lock sys and trx mutex taking and releasing.
trx_rollback_to_savepoint_for_mysql_low
trx_commit_in_memory
Clean up victim variable.
---
storage/innobase/handler/ha_innodb.cc | 38 +++++---------------------
storage/innobase/include/trx0trx.h | 19 +++++--------
storage/innobase/lock/lock0lock.cc | 50 ++++++++++++++++++++++-------------
storage/innobase/row/row0sel.cc | 4 ---
storage/innobase/trx/trx0roll.cc | 3 ++-
storage/innobase/trx/trx0trx.cc | 8 ++----
storage/xtradb/handler/ha_innodb.cc | 36 +++++--------------------
storage/xtradb/include/trx0trx.h | 19 +++++--------
storage/xtradb/lock/lock0lock.cc | 50 ++++++++++++++++++++++-------------
storage/xtradb/row/row0sel.cc | 4 ---
storage/xtradb/trx/trx0roll.cc | 21 ++-------------
storage/xtradb/trx/trx0trx.cc | 17 ++----------
12 files changed, 99 insertions(+), 170 deletions(-)
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index c670839b5cd..21f9e9c91ef 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -4929,8 +4929,6 @@ static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels)
/* if victim has been signaled by BF thread and/or aborting
is already progressing, following query aborting is not necessary
any more.
- Also, BF thread should own trx mutex for the victim, which would
- conflict with trx_mutex_enter() below
*/
DBUG_VOID_RETURN;
}
@@ -4939,34 +4937,8 @@ static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels)
if (trx_t* trx = thd_to_trx(thd)) {
ut_ad(trx->mysql_thd == thd);
- switch (trx->abort_type) {
-#ifdef WITH_WSREP
- case TRX_WSREP_ABORT:
- break;
-#endif
- case TRX_SERVER_ABORT:
- if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
- lock_mutex_enter();
- }
- /* fall through */
- case TRX_REPLICATION_ABORT:
- trx_mutex_enter(trx);
- }
/* Cancel a pending lock request if there are any */
lock_trx_handle_wait(trx);
- switch (trx->abort_type) {
-#ifdef WITH_WSREP
- case TRX_WSREP_ABORT:
- break;
-#endif
- case TRX_SERVER_ABORT:
- if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
- lock_mutex_exit();
- }
- /* fall through */
- case TRX_REPLICATION_ABORT:
- trx_mutex_exit(trx);
- }
}
DBUG_VOID_RETURN;
@@ -18683,6 +18655,12 @@ wsrep_innobase_kill_one_trx(
wsrep_thd_ws_handle(thd)->trx_id);
wsrep_thd_LOCK(thd);
+
+ /* We mark this as victim transaction, which is already marked
+ as BF victim. Both trx mutex and lock_sys mutex is held until
+ this victim has aborted. */
+ victim_trx->victim = true;
+
DBUG_EXECUTE_IF("sync.wsrep_after_BF_victim_lock",
{
const char act[]=
@@ -18866,7 +18844,7 @@ wsrep_abort_transaction(
my_bool signal)
{
DBUG_ENTER("wsrep_innobase_abort_thd");
-
+
trx_t* victim_trx = thd_to_trx(victim_thd);
trx_t* bf_trx = (bf_thd) ? thd_to_trx(bf_thd) : NULL;
@@ -18878,12 +18856,10 @@ wsrep_abort_transaction(
if (victim_trx) {
lock_mutex_enter();
trx_mutex_enter(victim_trx);
- victim_trx->abort_type = TRX_WSREP_ABORT;
int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx,
victim_trx, signal);
trx_mutex_exit(victim_trx);
lock_mutex_exit();
- victim_trx->abort_type = TRX_SERVER_ABORT;
wsrep_srv_conc_cancel_wait(victim_trx);
DBUG_RETURN(rcode);
} else {
diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
index fe16b8272b8..b40c6ae4667 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2018, MariaDB Corporation.
+Copyright (c) 2015, 2019, MariaDB Corporation.
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
@@ -623,7 +623,6 @@ struct trx_lock_t {
lock_sys->mutex. Otherwise, this may
only be modified by the thread that is
serving the running transaction. */
-
mem_heap_t* lock_heap; /*!< memory heap for trx_locks;
protected by lock_sys->mutex */
@@ -695,14 +694,6 @@ lock_rec_convert_impl_to_expl()) will access transactions associated
to other connections. The locks of transactions are protected by
lock_sys->mutex and sometimes by trx->mutex. */
-enum trx_abort_t {
- TRX_SERVER_ABORT = 0,
-#ifdef WITH_WSREP
- TRX_WSREP_ABORT,
-#endif
- TRX_REPLICATION_ABORT
-};
-
struct trx_t{
ulint magic_n;
@@ -880,8 +871,12 @@ struct trx_t{
/*------------------------------*/
THD* mysql_thd; /*!< MySQL thread handle corresponding
to this trx, or NULL */
- trx_abort_t abort_type; /*!< Transaction abort type*/
-
+ bool victim; /*!< This transaction is
+ selected as victim for abort
+ either by replication or
+ high priority wsrep thread. This
+ field is protected by trx and
+ lock sys mutex. */
const char* mysql_log_file_name;
/*!< if MySQL binlog is used, this field
contains a pointer to the latest file
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index 3970a559a4c..ecaf6afd980 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2014, 2018, MariaDB Corporation.
+Copyright (c) 2014, 2019, MariaDB Corporation.
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
@@ -1793,10 +1793,8 @@ wsrep_kill_victim(
}
}
- lock->trx->abort_type = TRX_WSREP_ABORT;
wsrep_innobase_kill_one_trx(trx->mysql_thd,
(const trx_t*) trx, lock->trx, TRUE);
- lock->trx->abort_type = TRX_SERVER_ABORT;
}
}
}
@@ -4782,12 +4780,11 @@ lock_report_waiters_to_mysql(
if (w_trx->id != victim_trx_id) {
/* If thd_report_wait_for() decides to kill the
transaction, then we will get a call back into
- innobase_kill_query. We mark this by setting
- current_lock_mutex_owner, so we can avoid trying
- to recursively take lock_sys->mutex. */
- w_trx->abort_type = TRX_REPLICATION_ABORT;
+ innobase_kill_query.*/
+ trx_mutex_enter(w_trx);
+ w_trx->victim = true;
thd_report_wait_for(mysql_thd, w_trx->mysql_thd);
- w_trx->abort_type = TRX_SERVER_ABORT;
+ trx_mutex_exit(w_trx);
}
++i;
}
@@ -7967,16 +7964,7 @@ lock_trx_release_locks(
lock_mutex_exit();
}
-/*********************************************************************//**
-Check whether the transaction has already been rolled back because it
-was selected as a deadlock victim, or if it has to wait then cancel
-the wait lock.
-@return DB_DEADLOCK, DB_LOCK_WAIT or DB_SUCCESS */
-UNIV_INTERN
-dberr_t
-lock_trx_handle_wait(
-/*=================*/
- trx_t* trx) /*!< in/out: trx lock state */
+inline dberr_t lock_trx_handle_wait_low(trx_t* trx)
{
ut_ad(lock_mutex_own());
ut_ad(trx_mutex_own(trx));
@@ -7993,6 +7981,32 @@ lock_trx_handle_wait(
return DB_LOCK_WAIT;
}
+/*********************************************************************//**
+Check whether the transaction has already been rolled back because it
+was selected as a deadlock victim, or if it has to wait then cancel
+the wait lock.
+@return DB_DEADLOCK, DB_LOCK_WAIT or DB_SUCCESS */
+UNIV_INTERN
+dberr_t
+lock_trx_handle_wait(
+/*=================*/
+ trx_t* trx) /*!< in/out: trx lock state */
+{
+ if (!trx->victim) {
+ lock_mutex_enter();
+ trx_mutex_enter(trx);
+ }
+
+ dberr_t err = lock_trx_handle_wait_low(trx);
+
+ if (!trx->victim) {
+ lock_mutex_exit();
+ trx_mutex_exit(trx);
+ }
+
+ return err;
+}
+
/*********************************************************************//**
Get the number of locks on a table.
@return number of locks */
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index 06bf4cc30c0..855266686e6 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -4746,11 +4746,7 @@ row_search_for_mysql(
a deadlock and the transaction had to wait then
release the lock it is waiting on. */
- lock_mutex_enter();
- trx_mutex_enter(trx);
err = lock_trx_handle_wait(trx);
- lock_mutex_exit();
- trx_mutex_exit(trx);
switch (err) {
case DB_SUCCESS:
diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc
index 3fd71aff23a..127e834335d 100644
--- a/storage/innobase/trx/trx0roll.cc
+++ b/storage/innobase/trx/trx0roll.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2016, 2018, MariaDB Corporation.
+Copyright (c) 2016, 2019, MariaDB Corporation.
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
@@ -370,6 +370,7 @@ trx_rollback_to_savepoint_for_mysql_low(
trx_mark_sql_stat_end(trx);
trx->op_info = "";
+ trx->victim = false;
return(err);
}
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index f36aabba8b4..98ac08a00e7 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2018, MariaDB Corporation.
+Copyright (c) 2015, 2019, MariaDB Corporation.
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
@@ -1339,11 +1339,7 @@ trx_commit_in_memory(
ut_ad(!trx->in_ro_trx_list);
ut_ad(!trx->in_rw_trx_list);
-#ifdef WITH_WSREP
- if (trx->mysql_thd && wsrep_on(trx->mysql_thd)) {
- trx->lock.was_chosen_as_deadlock_victim = FALSE;
- }
-#endif
+ trx->victim = false;
trx->dict_operation = TRX_DICT_OP_NONE;
trx->error_state = DB_SUCCESS;
diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index d943a87ab78..853894c3977 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -5534,8 +5534,6 @@ static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels)
/* if victim has been signaled by BF thread and/or aborting
is already progressing, following query aborting is not necessary
any more.
- Also, BF thread should own trx mutex for the victim, which would
- conflict with trx_mutex_enter() below
*/
DBUG_VOID_RETURN;
}
@@ -5543,34 +5541,8 @@ static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels)
if (trx_t* trx = thd_to_trx(thd)) {
ut_ad(trx->mysql_thd == thd);
- switch (trx->abort_type) {
-#ifdef WITH_WSREP
- case TRX_WSREP_ABORT:
- break;
-#endif
- case TRX_SERVER_ABORT:
- if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
- lock_mutex_enter();
- }
- /* fall through */
- case TRX_REPLICATION_ABORT:
- trx_mutex_enter(trx);
- }
/* Cancel a pending lock request if there are any */
lock_trx_handle_wait(trx);
- switch (trx->abort_type) {
-#ifdef WITH_WSREP
- case TRX_WSREP_ABORT:
- break;
-#endif
- case TRX_SERVER_ABORT:
- if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
- lock_mutex_exit();
- }
- /* fall through */
- case TRX_REPLICATION_ABORT:
- trx_mutex_exit(trx);
- }
}
DBUG_VOID_RETURN;
@@ -19723,6 +19695,12 @@ wsrep_innobase_kill_one_trx(
(thd && wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void");
wsrep_thd_LOCK(thd);
+
+ /* We mark this as victim transaction, which is already marked
+ as BF victim. Both trx mutex and lock_sys mutex is held until
+ this victim has aborted. */
+ victim_trx->victim = true;
+
DBUG_EXECUTE_IF("sync.wsrep_after_BF_victim_lock",
{
const char act[]=
@@ -19911,12 +19889,10 @@ wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd,
if (victim_trx) {
lock_mutex_enter();
trx_mutex_enter(victim_trx);
- victim_trx->abort_type = TRX_WSREP_ABORT;
int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx,
victim_trx, signal);
trx_mutex_exit(victim_trx);
lock_mutex_exit();
- victim_trx->abort_type = TRX_SERVER_ABORT;
wsrep_srv_conc_cancel_wait(victim_trx);
DBUG_RETURN(rcode);
} else {
diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h
index 77afde4c35c..df01284af05 100644
--- a/storage/xtradb/include/trx0trx.h
+++ b/storage/xtradb/include/trx0trx.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2018, MariaDB Corporation.
+Copyright (c) 2015, 2019, MariaDB Corporation.
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
@@ -672,7 +672,6 @@ struct trx_lock_t {
lock_sys->mutex. Otherwise, this may
only be modified by the thread that is
serving the running transaction. */
-
mem_heap_t* lock_heap; /*!< memory heap for trx_locks;
protected by lock_sys->mutex */
@@ -744,14 +743,6 @@ lock_rec_convert_impl_to_expl()) will access transactions associated
to other connections. The locks of transactions are protected by
lock_sys->mutex and sometimes by trx->mutex. */
-enum trx_abort_t {
- TRX_SERVER_ABORT = 0,
-#ifdef WITH_WSREP
- TRX_WSREP_ABORT,
-#endif
- TRX_REPLICATION_ABORT
-};
-
struct trx_t{
ulint magic_n;
@@ -930,8 +921,12 @@ struct trx_t{
/*------------------------------*/
THD* mysql_thd; /*!< MySQL thread handle corresponding
to this trx, or NULL */
- trx_abort_t abort_type; /*!< Transaction abort type */
-
+ bool victim; /*!< This transaction is
+ selected as victim for abort
+ either by replication or
+ high priority wsrep thread. This
+ field is protected by trx and
+ lock sys mutex. */
const char* mysql_log_file_name;
/*!< if MySQL binlog is used, this field
contains a pointer to the latest file
diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc
index 2183d281b78..60db0283e4e 100644
--- a/storage/xtradb/lock/lock0lock.cc
+++ b/storage/xtradb/lock/lock0lock.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2014, 2018, MariaDB Corporation.
+Copyright (c) 2014, 2019, MariaDB Corporation.
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
@@ -1804,10 +1804,8 @@ wsrep_kill_victim(
}
}
- lock->trx->abort_type = TRX_WSREP_ABORT;
wsrep_innobase_kill_one_trx(trx->mysql_thd,
(const trx_t*) trx, lock->trx, TRUE);
- lock->trx->abort_type = TRX_SERVER_ABORT;
}
}
}
@@ -4821,12 +4819,11 @@ lock_report_waiters_to_mysql(
if (w_trx->id != victim_trx_id) {
/* If thd_report_wait_for() decides to kill the
transaction, then we will get a call back into
- innobase_kill_query. We mark this by setting
- current_lock_mutex_owner, so we can avoid trying
- to recursively take lock_sys->mutex. */
- w_trx->abort_type = TRX_REPLICATION_ABORT;
+ innobase_kill_query.*/
+ trx_mutex_enter(w_trx);
+ w_trx->victim = true;
thd_report_wait_for(mysql_thd, w_trx->mysql_thd);
- w_trx->abort_type = TRX_SERVER_ABORT;
+ trx_mutex_exit(w_trx);
}
++i;
}
@@ -8077,16 +8074,7 @@ lock_trx_release_locks(
lock_mutex_exit();
}
-/*********************************************************************//**
-Check whether the transaction has already been rolled back because it
-was selected as a deadlock victim, or if it has to wait then cancel
-the wait lock.
-@return DB_DEADLOCK, DB_LOCK_WAIT or DB_SUCCESS */
-UNIV_INTERN
-dberr_t
-lock_trx_handle_wait(
-/*=================*/
- trx_t* trx) /*!< in/out: trx lock state */
+inline dberr_t lock_trx_handle_wait_low(trx_t* trx)
{
ut_ad(lock_mutex_own());
ut_ad(trx_mutex_own(trx));
@@ -8103,6 +8091,32 @@ lock_trx_handle_wait(
return DB_LOCK_WAIT;
}
+/*********************************************************************//**
+Check whether the transaction has already been rolled back because it
+was selected as a deadlock victim, or if it has to wait then cancel
+the wait lock.
+@return DB_DEADLOCK, DB_LOCK_WAIT or DB_SUCCESS */
+UNIV_INTERN
+dberr_t
+lock_trx_handle_wait(
+/*=================*/
+ trx_t* trx) /*!< in/out: trx lock state */
+{
+ if (!trx->victim) {
+ lock_mutex_enter();
+ trx_mutex_enter(trx);
+ }
+
+ dberr_t err = lock_trx_handle_wait_low(trx);
+
+ if (!trx->victim) {
+ lock_mutex_exit();
+ trx_mutex_exit(trx);
+ }
+
+ return err;
+}
+
/*********************************************************************//**
Get the number of locks on a table.
@return number of locks */
diff --git a/storage/xtradb/row/row0sel.cc b/storage/xtradb/row/row0sel.cc
index b6b5d107885..87bc2aa2875 100644
--- a/storage/xtradb/row/row0sel.cc
+++ b/storage/xtradb/row/row0sel.cc
@@ -4755,11 +4755,7 @@ row_search_for_mysql(
a deadlock and the transaction had to wait then
release the lock it is waiting on. */
- lock_mutex_enter();
- trx_mutex_enter(trx);
err = lock_trx_handle_wait(trx);
- lock_mutex_exit();
- trx_mutex_exit(trx);
switch (err) {
case DB_SUCCESS:
diff --git a/storage/xtradb/trx/trx0roll.cc b/storage/xtradb/trx/trx0roll.cc
index 56b7120fa34..127e834335d 100644
--- a/storage/xtradb/trx/trx0roll.cc
+++ b/storage/xtradb/trx/trx0roll.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2016, 2018, MariaDB Corporation.
+Copyright (c) 2016, 2019, MariaDB Corporation.
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
@@ -33,8 +33,6 @@ Created 3/26/1996 Heikki Tuuri
#include "trx0roll.ic"
#endif
-#include <mysql/service_wsrep.h>
-
#include "fsp0fsp.h"
#include "mach0data.h"
#include "trx0rseg.h"
@@ -51,9 +49,6 @@ Created 3/26/1996 Heikki Tuuri
#include "pars0pars.h"
#include "srv0mon.h"
#include "trx0sys.h"
-#ifdef WITH_WSREP
-#include "ha_prototypes.h"
-#endif /* WITH_WSREP */
/** This many pages must be undone before a truncate is tried within
rollback */
@@ -375,13 +370,7 @@ trx_rollback_to_savepoint_for_mysql_low(
trx_mark_sql_stat_end(trx);
trx->op_info = "";
-
-#ifdef WITH_WSREP
- if (wsrep_on(trx->mysql_thd) &&
- trx->lock.was_chosen_as_deadlock_victim) {
- trx->lock.was_chosen_as_deadlock_victim = FALSE;
- }
-#endif
+ trx->victim = false;
return(err);
}
@@ -1079,12 +1068,6 @@ trx_roll_try_truncate(
if (trx->update_undo) {
trx_undo_truncate_end(trx, trx->update_undo, limit);
}
-
-#ifdef WITH_WSREP_OUT
- if (wsrep_on(trx->mysql_thd)) {
- trx->lock.was_chosen_as_deadlock_victim = FALSE;
- }
-#endif /* WITH_WSREP */
}
/***********************************************************************//**
diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc
index 17cba81daf3..8ca247fadc8 100644
--- a/storage/xtradb/trx/trx0trx.cc
+++ b/storage/xtradb/trx/trx0trx.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2018, MariaDB Corporation.
+Copyright (c) 2015, 2019, MariaDB Corporation.
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
@@ -1563,11 +1563,7 @@ trx_commit_in_memory(
ut_ad(!trx->in_ro_trx_list);
ut_ad(!trx->in_rw_trx_list);
-#ifdef WITH_WSREP
- if (trx->mysql_thd && wsrep_on(trx->mysql_thd)) {
- trx->lock.was_chosen_as_deadlock_victim = FALSE;
- }
-#endif
+ trx->victim = false;
trx->dict_operation = TRX_DICT_OP_NONE;
trx->error_state = DB_SUCCESS;
@@ -2668,10 +2664,6 @@ trx_start_if_not_started_low(
{
switch (trx->state) {
case TRX_STATE_NOT_STARTED:
-#ifdef WITH_WSREP
- ut_d(trx->start_file = __FILE__);
- ut_d(trx->start_line = __LINE__);
-#endif /* WITH_WSREP */
trx_start_low(trx);
/* fall through */
case TRX_STATE_ACTIVE:
@@ -2705,11 +2697,6 @@ trx_start_for_ddl_low(
trx->will_lock = 1;
trx->ddl = true;
-
-#ifdef WITH_WSREP
- ut_d(trx->start_file = __FILE__);
- ut_d(trx->start_line = __LINE__);
-#endif /* WITH_WSREP */
trx_start_low(trx);
return;
1
0

[Commits] b73e7b0bc1e: MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
by Varun 26 Mar '19
by Varun 26 Mar '19
26 Mar '19
revision-id: b73e7b0bc1e6c7a9c62e1c22a026244fd58e1833 (mariadb-10.2.22-91-gb73e7b0bc1e)
parent(s): 50a8fc52988d13a5164a1a542b9d7a85e3ecc1c1
author: Varun Gupta
committer: Varun Gupta
timestamp: 2019-03-26 14:36:58 +0530
message:
MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
To fix the crash there were 2 steps:
1) Set table_field->table to a non-null pointer for min and max fields which
are created in function create_min_max_statistical_fields_for_table_share()
2) Fix writing code to write only full multi-byte sequences
---
mysql-test/r/stat_tables.result | 39 ++++++++++++++++++++++++++++++++++
mysql-test/r/stat_tables_innodb.result | 39 ++++++++++++++++++++++++++++++++++
mysql-test/t/stat_tables.test | 31 +++++++++++++++++++++++++++
sql/field.cc | 7 +++---
sql/sql_statistics.cc | 34 +++++++++++++++++++++++++++--
sql/sql_statistics.h | 2 ++
6 files changed, 146 insertions(+), 6 deletions(-)
diff --git a/mysql-test/r/stat_tables.result b/mysql-test/r/stat_tables.result
index 3ebc3b47833..4ab69c4c3c9 100644
--- a/mysql-test/r/stat_tables.result
+++ b/mysql-test/r/stat_tables.result
@@ -624,4 +624,43 @@ SELECT MAX(pk) FROM t1;
MAX(pk)
NULL
DROP TABLE t1;
+#
+# MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
+#
+set names utf8;
+set @save_optimizer_use_condition_selectivity=@@optimizer_use_condition_selectivity;
+set optimizer_use_condition_selectivity=4;
+set use_stat_tables=preferably;
+set @save_histogram_size= @@histogram_size;
+set histogram_size=255;
+create table t1 ( a varchar(255) character set utf8);
+insert into t1 values ('ӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥ'), ('ççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççç');
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats;
+HEX(RIGHT(min_value, 1)) length(min_value)
+A7 254
+select HEX(RIGHT(max_value, 1)), length(max_value) from mysql.column_stats;
+HEX(RIGHT(max_value, 1)) length(max_value)
+A5 254
+analyze
+select * from t1 where a >= 'ӥ';
+id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2.00 50.00 50.00 Using where
+set @save_sql_mode= @@sql_mode;
+set sql_mode='ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
+update mysql.column_stats set min_value= 'ӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥ';
+Warnings:
+Warning 1265 Data truncated for column 'min_value' at row 1
+analyze
+select * from t1 where a >= 'ӥ';
+id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2.00 50.00 50.00 Using where
+set names latin1;
+set @@sql_mode= @save_sql_mode;
set use_stat_tables=@save_use_stat_tables;
+set @@histogram_size= @save_histogram_size;
+set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
+drop table t1;
diff --git a/mysql-test/r/stat_tables_innodb.result b/mysql-test/r/stat_tables_innodb.result
index a6c5525a0d3..f4801019508 100644
--- a/mysql-test/r/stat_tables_innodb.result
+++ b/mysql-test/r/stat_tables_innodb.result
@@ -651,6 +651,45 @@ SELECT MAX(pk) FROM t1;
MAX(pk)
NULL
DROP TABLE t1;
+#
+# MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
+#
+set names utf8;
+set @save_optimizer_use_condition_selectivity=@@optimizer_use_condition_selectivity;
+set optimizer_use_condition_selectivity=4;
+set use_stat_tables=preferably;
+set @save_histogram_size= @@histogram_size;
+set histogram_size=255;
+create table t1 ( a varchar(255) character set utf8);
+insert into t1 values ('ӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥ'), ('ççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççç');
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats;
+HEX(RIGHT(min_value, 1)) length(min_value)
+A7 254
+select HEX(RIGHT(max_value, 1)), length(max_value) from mysql.column_stats;
+HEX(RIGHT(max_value, 1)) length(max_value)
+A5 254
+analyze
+select * from t1 where a >= 'ӥ';
+id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2.00 50.00 50.00 Using where
+set @save_sql_mode= @@sql_mode;
+set sql_mode='ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
+update mysql.column_stats set min_value= 'ӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥ';
+Warnings:
+Warning 1265 Data truncated for column 'min_value' at row 1
+analyze
+select * from t1 where a >= 'ӥ';
+id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2.00 50.00 50.00 Using where
+set names latin1;
+set @@sql_mode= @save_sql_mode;
set use_stat_tables=@save_use_stat_tables;
+set @@histogram_size= @save_histogram_size;
+set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
+drop table t1;
set optimizer_switch=@save_optimizer_switch_for_stat_tables_test;
SET SESSION STORAGE_ENGINE=DEFAULT;
diff --git a/mysql-test/t/stat_tables.test b/mysql-test/t/stat_tables.test
index b89ab2bbd2d..dee4e911623 100644
--- a/mysql-test/t/stat_tables.test
+++ b/mysql-test/t/stat_tables.test
@@ -401,4 +401,35 @@ SELECT MAX(pk) FROM t1;
DROP TABLE t1;
+--echo #
+--echo # MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
+--echo #
+
+set names utf8;
+set @save_optimizer_use_condition_selectivity=@@optimizer_use_condition_selectivity;
+set optimizer_use_condition_selectivity=4;
+set use_stat_tables=preferably;
+set @save_histogram_size= @@histogram_size;
+set histogram_size=255;
+
+create table t1 ( a varchar(255) character set utf8);
+insert into t1 values ('ӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥ'), ('ççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççç');
+analyze table t1;
+select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats;
+select HEX(RIGHT(max_value, 1)), length(max_value) from mysql.column_stats;
+analyze
+select * from t1 where a >= 'ӥ';
+
+set @save_sql_mode= @@sql_mode;
+set sql_mode='ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
+update mysql.column_stats set min_value= 'ӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥӥ';
+
+analyze
+select * from t1 where a >= 'ӥ';
+
+set names latin1;
+set @@sql_mode= @save_sql_mode;
set use_stat_tables=@save_use_stat_tables;
+set @@histogram_size= @save_histogram_size;
+set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
+drop table t1;
diff --git a/sql/field.cc b/sql/field.cc
index 080cf34c76d..118710410df 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -2219,7 +2219,6 @@ bool Field_str::can_be_substituted_to_equal_item(const Context &ctx,
return false;
}
-
void Field_num::make_field(Send_field *field)
{
Field::make_field(field);
@@ -4332,7 +4331,7 @@ longlong Field_long::val_int(void)
ASSERT_COLUMN_MARKED_FOR_READ;
int32 j;
/* See the comment in Field_long::store(long long) */
- DBUG_ASSERT(!table || table->in_use == current_thd);
+ DBUG_ASSERT(table->in_use == current_thd);
j=sint4korr(ptr);
return unsigned_flag ? (longlong) (uint32) j : (longlong) j;
}
@@ -7087,7 +7086,7 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
String_copier copier;
/* See the comment for Field_long::store(long long) */
- DBUG_ASSERT(!table || table->in_use == current_thd);
+ DBUG_ASSERT(table->in_use == current_thd);
copy_length= copier.well_formed_copy(field_charset,
(char*) ptr, field_length,
@@ -7273,7 +7272,7 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)),
{
ASSERT_COLUMN_MARKED_FOR_READ;
/* See the comment for Field_long::store(long long) */
- DBUG_ASSERT(!table || table->in_use == current_thd);
+ DBUG_ASSERT(table->in_use == current_thd);
uint length;
if (get_thd()->variables.sql_mode &
MODE_PAD_CHAR_TO_FULL_LENGTH)
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index b5811c683e8..dd9070e5bc0 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -1044,6 +1044,7 @@ class Column_stat: public Stat_table
{
char buff[MAX_FIELD_WIDTH];
String val(buff, sizeof(buff), &my_charset_bin);
+ uint32 length= 0;
for (uint i= COLUMN_STAT_MIN_VALUE; i <= COLUMN_STAT_HISTOGRAM; i++)
{
@@ -1060,7 +1061,9 @@ class Column_stat: public Stat_table
else
{
table_field->collected_stats->min_value->val_str(&val);
- stat_field->store(val.ptr(), val.length(), &my_charset_bin);
+ length= Well_formed_prefix(val.charset(), val.ptr(),
+ MY_MIN(val.length(), stat_field->field_length)).length();
+ stat_field->store(val.ptr(), length, &my_charset_bin);
}
break;
case COLUMN_STAT_MAX_VALUE:
@@ -1069,7 +1072,9 @@ class Column_stat: public Stat_table
else
{
table_field->collected_stats->max_value->val_str(&val);
- stat_field->store(val.ptr(), val.length(), &my_charset_bin);
+ length= Well_formed_prefix(val.charset(), val.ptr(),
+ MY_MIN(val.length(), stat_field->field_length)).length();
+ stat_field->store(val.ptr(), length, &my_charset_bin);
}
break;
case COLUMN_STAT_NULLS_RATIO:
@@ -2935,6 +2940,25 @@ int update_statistics_for_table(THD *thd, TABLE *table)
}
+void set_min_max_fields_table(Field* field, TABLE *table)
+{
+ if (field->read_stats->min_value)
+ field->read_stats->min_value->table= table;
+ if (field->read_stats->max_value)
+ field->read_stats->max_value->table= table;
+}
+
+void check_stat_tables_owner(THD *thd, TABLE_LIST *table_list)
+{
+ for ( ; table_list ; table_list= table_list->next_global)
+ {
+ DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE,
+ table_list->db,
+ table_list->table_name,
+ MDL_SHARED_READ));
+ }
+}
+
/**
@brief
Read statistics for a table from the persistent statistical tables
@@ -2978,8 +3002,10 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
KEY *key_info, *key_info_end;
TABLE_SHARE *table_share= table->s;
Table_statistics *read_stats= table_share->stats_cb.table_stats;
+ TABLE_LIST *table_list= stat_tables;
DBUG_ENTER("read_statistics_for_table");
+ check_stat_tables_owner(thd, stat_tables);
/* Read statistics from the statistical table table_stats */
stat_table= stat_tables[TABLE_STAT].table;
@@ -2994,6 +3020,7 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
for (field_ptr= table_share->field; *field_ptr; field_ptr++)
{
table_field= *field_ptr;
+ set_min_max_fields_table(table_field, table);
column_stat.set_key_fields(table_field);
column_stat.get_stat_values();
total_hist_size+= table_field->read_stats->histogram.get_size();
@@ -3059,6 +3086,9 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
}
}
}
+
+ for (field_ptr= table_share->field; *field_ptr; field_ptr++)
+ set_min_max_fields_table(table_field, NULL);
table->stats_is_read= TRUE;
diff --git a/sql/sql_statistics.h b/sql/sql_statistics.h
index 8600db8890d..0912d89b004 100644
--- a/sql/sql_statistics.h
+++ b/sql/sql_statistics.h
@@ -113,6 +113,8 @@ double get_column_range_cardinality(Field *field,
uint range_flag);
bool is_stat_table(const char *db, const char *table);
bool is_eits_usable(Field* field);
+void set_min_max_fields_table(Field* field);
+void check_stat_tables_owner(THD *thd, TABLE_LIST *table_list);
class Histogram
{
1
0

26 Mar '19
revision-id: 842ef80b029c975b7f7f7ec25fe55817ec626f02 (mariadb-10.1.38-68-g842ef80b029)
parent(s): 8be02be08bf6a7227e2ab6a5443b63f3a155e2a9
author: Jan Lindström
committer: Jan Lindström
timestamp: 2019-03-22 13:52:35 +0200
message:
MDEV-18464: Port kill_one_trx fixes from 10.4 to 10.1
Pushed the decision for innodb transaction and system
locking down to lock_trx_handle_wait() level. With this,
we can avoid releasing these mutexes for executions
where these mutexes were acquired upfront.
This patch will also fix BF aborting of native threads, e.g.
threads which have declared wsrep_on=OFF. Earlier, we have
used, for innodb trx locks, was_chosen_as_deadlock_victim
flag, for marking inodb transactions, which are victims for
wsrep BF abort. With native threads (wsrep_on==OFF), re-using
was_chosen_as_deadlock_victim flag may lead to inteference
with real deadlock, and to deal with this, the patch has added new
flag for marking wsrep BF aborts only: was_chosen_as_wsrep_victim
Similar way if replication decides to abort one of the threads
we mark victim by: was_chosen_as_replication_victim
innobase_kill_query()
Removed lock mutex and trx mutex code.
wsrep_innobase_kill_one_trx()
Here new was_chosen_as_wsrep_victim flag is set
wsrep_kill_victim
Remove unnecessary abort type
lock_report_waiters_to_mysql
Mark trx as a victim of replication abort
lock_trx_handle_wait_low()
New low lever function to handle lock waits.
lock_trx_handle_wait()
Taking lock mutex and trx mutex is pushed down to this
function.
row_search_for_mysql
Remove lock mutex and trx mutex enter/exit
trx_commit_in_memory
trx_rollback_to_savepoint_for_mysql_low
Initialize was_chosen_as_wsrep_victim
---
storage/innobase/handler/ha_innodb.cc | 40 +++++++---------------------
storage/innobase/include/trx0trx.h | 21 +++++++--------
storage/innobase/lock/lock0lock.cc | 49 ++++++++++++++++++++++++-----------
storage/innobase/row/row0sel.cc | 4 ---
storage/innobase/trx/trx0roll.cc | 3 +++
storage/innobase/trx/trx0trx.cc | 6 ++---
storage/xtradb/handler/ha_innodb.cc | 38 ++++++---------------------
storage/xtradb/include/trx0trx.h | 21 +++++++--------
storage/xtradb/lock/lock0lock.cc | 49 ++++++++++++++++++++++++-----------
storage/xtradb/row/row0sel.cc | 4 ---
storage/xtradb/trx/trx0roll.cc | 6 +----
storage/xtradb/trx/trx0trx.cc | 6 ++---
12 files changed, 113 insertions(+), 134 deletions(-)
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index c670839b5cd..6ccb1d6a05e 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -4929,8 +4929,6 @@ static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels)
/* if victim has been signaled by BF thread and/or aborting
is already progressing, following query aborting is not necessary
any more.
- Also, BF thread should own trx mutex for the victim, which would
- conflict with trx_mutex_enter() below
*/
DBUG_VOID_RETURN;
}
@@ -4939,34 +4937,8 @@ static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels)
if (trx_t* trx = thd_to_trx(thd)) {
ut_ad(trx->mysql_thd == thd);
- switch (trx->abort_type) {
-#ifdef WITH_WSREP
- case TRX_WSREP_ABORT:
- break;
-#endif
- case TRX_SERVER_ABORT:
- if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
- lock_mutex_enter();
- }
- /* fall through */
- case TRX_REPLICATION_ABORT:
- trx_mutex_enter(trx);
- }
/* Cancel a pending lock request if there are any */
lock_trx_handle_wait(trx);
- switch (trx->abort_type) {
-#ifdef WITH_WSREP
- case TRX_WSREP_ABORT:
- break;
-#endif
- case TRX_SERVER_ABORT:
- if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
- lock_mutex_exit();
- }
- /* fall through */
- case TRX_REPLICATION_ABORT:
- trx_mutex_exit(trx);
- }
}
DBUG_VOID_RETURN;
@@ -18683,6 +18655,14 @@ wsrep_innobase_kill_one_trx(
wsrep_thd_ws_handle(thd)->trx_id);
wsrep_thd_LOCK(thd);
+
+ /*
+ * we mark with was_chosen_as_deadlock_victim transaction,
+ * which is already marked as BF victim
+ * lock_sys is held until this victim has aborted
+ */
+ victim_trx->lock.was_chosen_as_wsrep_victim = true;
+
DBUG_EXECUTE_IF("sync.wsrep_after_BF_victim_lock",
{
const char act[]=
@@ -18866,7 +18846,7 @@ wsrep_abort_transaction(
my_bool signal)
{
DBUG_ENTER("wsrep_innobase_abort_thd");
-
+
trx_t* victim_trx = thd_to_trx(victim_thd);
trx_t* bf_trx = (bf_thd) ? thd_to_trx(bf_thd) : NULL;
@@ -18878,12 +18858,10 @@ wsrep_abort_transaction(
if (victim_trx) {
lock_mutex_enter();
trx_mutex_enter(victim_trx);
- victim_trx->abort_type = TRX_WSREP_ABORT;
int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx,
victim_trx, signal);
trx_mutex_exit(victim_trx);
lock_mutex_exit();
- victim_trx->abort_type = TRX_SERVER_ABORT;
wsrep_srv_conc_cancel_wait(victim_trx);
DBUG_RETURN(rcode);
} else {
diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
index fe16b8272b8..b83734b154a 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2018, MariaDB Corporation.
+Copyright (c) 2015, 2019, MariaDB Corporation.
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
@@ -613,6 +613,9 @@ struct trx_lock_t {
transaction as a victim in deadlock
resolution, it sets this to TRUE.
Protected by trx->mutex. */
+ bool was_chosen_as_replication_victim;
+ /* replication has marked this
+ trx to abort */
time_t wait_started; /*!< lock wait started at this time,
protected only by lock_sys->mutex */
@@ -624,6 +627,12 @@ struct trx_lock_t {
only be modified by the thread that is
serving the running transaction. */
+#ifdef WITH_WSREP
+ bool was_chosen_as_wsrep_victim;
+ /*!< high priority wsrep thread has
+ marked this trx to abort */
+#endif /* WITH_WSREP */
+
mem_heap_t* lock_heap; /*!< memory heap for trx_locks;
protected by lock_sys->mutex */
@@ -695,14 +704,6 @@ lock_rec_convert_impl_to_expl()) will access transactions associated
to other connections. The locks of transactions are protected by
lock_sys->mutex and sometimes by trx->mutex. */
-enum trx_abort_t {
- TRX_SERVER_ABORT = 0,
-#ifdef WITH_WSREP
- TRX_WSREP_ABORT,
-#endif
- TRX_REPLICATION_ABORT
-};
-
struct trx_t{
ulint magic_n;
@@ -880,8 +881,6 @@ struct trx_t{
/*------------------------------*/
THD* mysql_thd; /*!< MySQL thread handle corresponding
to this trx, or NULL */
- trx_abort_t abort_type; /*!< Transaction abort type*/
-
const char* mysql_log_file_name;
/*!< if MySQL binlog is used, this field
contains a pointer to the latest file
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index 3970a559a4c..984ac6cacbc 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2014, 2018, MariaDB Corporation.
+Copyright (c) 2014, 2019, MariaDB Corporation.
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
@@ -1793,10 +1793,8 @@ wsrep_kill_victim(
}
}
- lock->trx->abort_type = TRX_WSREP_ABORT;
wsrep_innobase_kill_one_trx(trx->mysql_thd,
(const trx_t*) trx, lock->trx, TRUE);
- lock->trx->abort_type = TRX_SERVER_ABORT;
}
}
}
@@ -4785,9 +4783,8 @@ lock_report_waiters_to_mysql(
innobase_kill_query. We mark this by setting
current_lock_mutex_owner, so we can avoid trying
to recursively take lock_sys->mutex. */
- w_trx->abort_type = TRX_REPLICATION_ABORT;
+ w_trx->lock.was_chosen_as_replication_victim = true;
thd_report_wait_for(mysql_thd, w_trx->mysql_thd);
- w_trx->abort_type = TRX_SERVER_ABORT;
}
++i;
}
@@ -7967,16 +7964,7 @@ lock_trx_release_locks(
lock_mutex_exit();
}
-/*********************************************************************//**
-Check whether the transaction has already been rolled back because it
-was selected as a deadlock victim, or if it has to wait then cancel
-the wait lock.
-@return DB_DEADLOCK, DB_LOCK_WAIT or DB_SUCCESS */
-UNIV_INTERN
-dberr_t
-lock_trx_handle_wait(
-/*=================*/
- trx_t* trx) /*!< in/out: trx lock state */
+static inline dberr_t lock_trx_handle_wait_low(trx_t* trx)
{
ut_ad(lock_mutex_own());
ut_ad(trx_mutex_own(trx));
@@ -7993,6 +7981,37 @@ lock_trx_handle_wait(
return DB_LOCK_WAIT;
}
+/*********************************************************************//**
+Check whether the transaction has already been rolled back because it
+was selected as a deadlock victim, or if it has to wait then cancel
+the wait lock.
+@return DB_DEADLOCK, DB_LOCK_WAIT or DB_SUCCESS */
+UNIV_INTERN
+dberr_t
+lock_trx_handle_wait(
+/*=================*/
+ trx_t* trx) /*!< in/out: trx lock state */
+{
+ bool lock_mutex_taken = false;
+#ifdef WITH_WSREP
+ /* We already own mutexes */
+ if (trx->lock.was_chosen_as_wsrep_victim) {
+ return lock_trx_handle_wait_low(trx);
+ }
+#endif /* WITH_WSREP */
+ if (!trx->lock.was_chosen_as_replication_victim) {
+ lock_mutex_enter();
+ lock_mutex_taken = true;
+ }
+ trx_mutex_enter(trx);
+ dberr_t err = lock_trx_handle_wait_low(trx);
+ if (lock_mutex_taken) {
+ lock_mutex_exit();
+ }
+ trx_mutex_exit(trx);
+ return err;
+}
+
/*********************************************************************//**
Get the number of locks on a table.
@return number of locks */
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index 06bf4cc30c0..855266686e6 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -4746,11 +4746,7 @@ row_search_for_mysql(
a deadlock and the transaction had to wait then
release the lock it is waiting on. */
- lock_mutex_enter();
- trx_mutex_enter(trx);
err = lock_trx_handle_wait(trx);
- lock_mutex_exit();
- trx_mutex_exit(trx);
switch (err) {
case DB_SUCCESS:
diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc
index 3fd71aff23a..925fcf4f790 100644
--- a/storage/innobase/trx/trx0roll.cc
+++ b/storage/innobase/trx/trx0roll.cc
@@ -370,6 +370,9 @@ trx_rollback_to_savepoint_for_mysql_low(
trx_mark_sql_stat_end(trx);
trx->op_info = "";
+#ifdef WITH_WSREP
+ trx->lock.was_chosen_as_wsrep_victim = false;
+#endif
return(err);
}
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index f36aabba8b4..396703250db 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2018, MariaDB Corporation.
+Copyright (c) 2015, 2019, MariaDB Corporation.
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
@@ -1340,9 +1340,7 @@ trx_commit_in_memory(
ut_ad(!trx->in_rw_trx_list);
#ifdef WITH_WSREP
- if (trx->mysql_thd && wsrep_on(trx->mysql_thd)) {
- trx->lock.was_chosen_as_deadlock_victim = FALSE;
- }
+ trx->lock.was_chosen_as_wsrep_victim = false;
#endif
trx->dict_operation = TRX_DICT_OP_NONE;
diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index d943a87ab78..6fd2ff62663 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -5534,8 +5534,6 @@ static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels)
/* if victim has been signaled by BF thread and/or aborting
is already progressing, following query aborting is not necessary
any more.
- Also, BF thread should own trx mutex for the victim, which would
- conflict with trx_mutex_enter() below
*/
DBUG_VOID_RETURN;
}
@@ -5543,34 +5541,8 @@ static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels)
if (trx_t* trx = thd_to_trx(thd)) {
ut_ad(trx->mysql_thd == thd);
- switch (trx->abort_type) {
-#ifdef WITH_WSREP
- case TRX_WSREP_ABORT:
- break;
-#endif
- case TRX_SERVER_ABORT:
- if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
- lock_mutex_enter();
- }
- /* fall through */
- case TRX_REPLICATION_ABORT:
- trx_mutex_enter(trx);
- }
/* Cancel a pending lock request if there are any */
lock_trx_handle_wait(trx);
- switch (trx->abort_type) {
-#ifdef WITH_WSREP
- case TRX_WSREP_ABORT:
- break;
-#endif
- case TRX_SERVER_ABORT:
- if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
- lock_mutex_exit();
- }
- /* fall through */
- case TRX_REPLICATION_ABORT:
- trx_mutex_exit(trx);
- }
}
DBUG_VOID_RETURN;
@@ -19723,6 +19695,14 @@ wsrep_innobase_kill_one_trx(
(thd && wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void");
wsrep_thd_LOCK(thd);
+
+ /*
+ * we mark with was_chosen_as_deadlock_victim transaction,
+ * which is already marked as BF victim
+ * lock_sys is held until this victim has aborted
+ */
+ victim_trx->lock.was_chosen_as_wsrep_victim = true;
+
DBUG_EXECUTE_IF("sync.wsrep_after_BF_victim_lock",
{
const char act[]=
@@ -19911,12 +19891,10 @@ wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd,
if (victim_trx) {
lock_mutex_enter();
trx_mutex_enter(victim_trx);
- victim_trx->abort_type = TRX_WSREP_ABORT;
int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx,
victim_trx, signal);
trx_mutex_exit(victim_trx);
lock_mutex_exit();
- victim_trx->abort_type = TRX_SERVER_ABORT;
wsrep_srv_conc_cancel_wait(victim_trx);
DBUG_RETURN(rcode);
} else {
diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h
index 77afde4c35c..9f6a3e756fd 100644
--- a/storage/xtradb/include/trx0trx.h
+++ b/storage/xtradb/include/trx0trx.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2018, MariaDB Corporation.
+Copyright (c) 2015, 2019, MariaDB Corporation.
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
@@ -662,6 +662,9 @@ struct trx_lock_t {
transaction as a victim in deadlock
resolution, it sets this to TRUE.
Protected by trx->mutex. */
+ bool was_chosen_as_replication_victim;
+ /* replication has marked this
+ trx to abort */
time_t wait_started; /*!< lock wait started at this time,
protected only by lock_sys->mutex */
@@ -673,6 +676,12 @@ struct trx_lock_t {
only be modified by the thread that is
serving the running transaction. */
+#ifdef WITH_WSREP
+ bool was_chosen_as_wsrep_victim;
+ /*!< high priority wsrep thread has
+ marked this trx to abort */
+#endif /* WITH_WSREP */
+
mem_heap_t* lock_heap; /*!< memory heap for trx_locks;
protected by lock_sys->mutex */
@@ -744,14 +753,6 @@ lock_rec_convert_impl_to_expl()) will access transactions associated
to other connections. The locks of transactions are protected by
lock_sys->mutex and sometimes by trx->mutex. */
-enum trx_abort_t {
- TRX_SERVER_ABORT = 0,
-#ifdef WITH_WSREP
- TRX_WSREP_ABORT,
-#endif
- TRX_REPLICATION_ABORT
-};
-
struct trx_t{
ulint magic_n;
@@ -930,8 +931,6 @@ struct trx_t{
/*------------------------------*/
THD* mysql_thd; /*!< MySQL thread handle corresponding
to this trx, or NULL */
- trx_abort_t abort_type; /*!< Transaction abort type */
-
const char* mysql_log_file_name;
/*!< if MySQL binlog is used, this field
contains a pointer to the latest file
diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc
index 2183d281b78..8f92b9c9295 100644
--- a/storage/xtradb/lock/lock0lock.cc
+++ b/storage/xtradb/lock/lock0lock.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2014, 2018, MariaDB Corporation.
+Copyright (c) 2014, 2019, MariaDB Corporation.
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
@@ -1804,10 +1804,8 @@ wsrep_kill_victim(
}
}
- lock->trx->abort_type = TRX_WSREP_ABORT;
wsrep_innobase_kill_one_trx(trx->mysql_thd,
(const trx_t*) trx, lock->trx, TRUE);
- lock->trx->abort_type = TRX_SERVER_ABORT;
}
}
}
@@ -4824,9 +4822,8 @@ lock_report_waiters_to_mysql(
innobase_kill_query. We mark this by setting
current_lock_mutex_owner, so we can avoid trying
to recursively take lock_sys->mutex. */
- w_trx->abort_type = TRX_REPLICATION_ABORT;
+ w_trx->lock.was_chosen_as_replication_victim = true;
thd_report_wait_for(mysql_thd, w_trx->mysql_thd);
- w_trx->abort_type = TRX_SERVER_ABORT;
}
++i;
}
@@ -8077,16 +8074,7 @@ lock_trx_release_locks(
lock_mutex_exit();
}
-/*********************************************************************//**
-Check whether the transaction has already been rolled back because it
-was selected as a deadlock victim, or if it has to wait then cancel
-the wait lock.
-@return DB_DEADLOCK, DB_LOCK_WAIT or DB_SUCCESS */
-UNIV_INTERN
-dberr_t
-lock_trx_handle_wait(
-/*=================*/
- trx_t* trx) /*!< in/out: trx lock state */
+static inline dberr_t lock_trx_handle_wait_low(trx_t* trx)
{
ut_ad(lock_mutex_own());
ut_ad(trx_mutex_own(trx));
@@ -8103,6 +8091,37 @@ lock_trx_handle_wait(
return DB_LOCK_WAIT;
}
+/*********************************************************************//**
+Check whether the transaction has already been rolled back because it
+was selected as a deadlock victim, or if it has to wait then cancel
+the wait lock.
+@return DB_DEADLOCK, DB_LOCK_WAIT or DB_SUCCESS */
+UNIV_INTERN
+dberr_t
+lock_trx_handle_wait(
+/*=================*/
+ trx_t* trx) /*!< in/out: trx lock state */
+{
+ bool lock_mutex_taken = false;
+#ifdef WITH_WSREP
+ /* We already own mutexes */
+ if (trx->lock.was_chosen_as_wsrep_victim) {
+ return lock_trx_handle_wait_low(trx);
+ }
+#endif /* WITH_WSREP */
+ if (!trx->lock.was_chosen_as_replication_victim) {
+ lock_mutex_enter();
+ lock_mutex_taken = true;
+ }
+ trx_mutex_enter(trx);
+ dberr_t err = lock_trx_handle_wait_low(trx);
+ if (lock_mutex_taken) {
+ lock_mutex_exit();
+ }
+ trx_mutex_exit(trx);
+ return err;
+}
+
/*********************************************************************//**
Get the number of locks on a table.
@return number of locks */
diff --git a/storage/xtradb/row/row0sel.cc b/storage/xtradb/row/row0sel.cc
index b6b5d107885..87bc2aa2875 100644
--- a/storage/xtradb/row/row0sel.cc
+++ b/storage/xtradb/row/row0sel.cc
@@ -4755,11 +4755,7 @@ row_search_for_mysql(
a deadlock and the transaction had to wait then
release the lock it is waiting on. */
- lock_mutex_enter();
- trx_mutex_enter(trx);
err = lock_trx_handle_wait(trx);
- lock_mutex_exit();
- trx_mutex_exit(trx);
switch (err) {
case DB_SUCCESS:
diff --git a/storage/xtradb/trx/trx0roll.cc b/storage/xtradb/trx/trx0roll.cc
index 56b7120fa34..85ab3de6308 100644
--- a/storage/xtradb/trx/trx0roll.cc
+++ b/storage/xtradb/trx/trx0roll.cc
@@ -375,12 +375,8 @@ trx_rollback_to_savepoint_for_mysql_low(
trx_mark_sql_stat_end(trx);
trx->op_info = "";
-
#ifdef WITH_WSREP
- if (wsrep_on(trx->mysql_thd) &&
- trx->lock.was_chosen_as_deadlock_victim) {
- trx->lock.was_chosen_as_deadlock_victim = FALSE;
- }
+ trx->lock.was_chosen_as_wsrep_victim = false;
#endif
return(err);
diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc
index 17cba81daf3..ad5467e126c 100644
--- a/storage/xtradb/trx/trx0trx.cc
+++ b/storage/xtradb/trx/trx0trx.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2018, MariaDB Corporation.
+Copyright (c) 2015, 2019, MariaDB Corporation.
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
@@ -1564,9 +1564,7 @@ trx_commit_in_memory(
ut_ad(!trx->in_rw_trx_list);
#ifdef WITH_WSREP
- if (trx->mysql_thd && wsrep_on(trx->mysql_thd)) {
- trx->lock.was_chosen_as_deadlock_victim = FALSE;
- }
+ trx->lock.was_chosen_as_wsrep_victim = false;
#endif
trx->dict_operation = TRX_DICT_OP_NONE;
2
1
revision-id: 132a95a1c7945edd2327383c260751fdf42d3e26 (mariadb-10.4.3-83-g132a95a1c79)
parent(s): 4eff940dde0fee130cf3a7512b1fe25fc71bbe81
author: Oleksandr Byelkin
committer: Oleksandr Byelkin
timestamp: 2019-03-23 22:00:33 +0100
message:
ccc
---
sql/sql_class.h | 2 ++
storage/maria/ma_pagecache.c | 5 +++--
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/sql/sql_class.h b/sql/sql_class.h
index bbe9433eeb2..77773437807 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -5611,6 +5611,8 @@ class select_create: public select_insert {
#else
#undef USE_ARIA_FOR_TMP_TABLES
#endif
+/* TODO: remove after big block tests */
+#undef USE_ARIA_FOR_TMP_TABLES
#ifdef USE_ARIA_FOR_TMP_TABLES
#define TMP_ENGINE_COLUMNDEF MARIA_COLUMNDEF
diff --git a/storage/maria/ma_pagecache.c b/storage/maria/ma_pagecache.c
index aa8ffc31d0a..cdf4dd21874 100644
--- a/storage/maria/ma_pagecache.c
+++ b/storage/maria/ma_pagecache.c
@@ -2108,8 +2108,8 @@ static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache,
if (! pagecache->used_last)
{
- DBUG_PRINT("XXX", ("there is NOT UNUSED blocks"));
struct st_my_thread_var *thread;
+ DBUG_PRINT("XXX", ("there is NOT UNUSED blocks"));
/*
Wait until a new block is added to the LRU chain;
several threads might wait here for the same page,
@@ -4257,7 +4257,8 @@ my_bool pagecache_write_part(PAGECACHE *pagecache,
if (file->big_block_read)
{
- DBUG_ASSERT(0);
+ //DBUG_ASSERT(0);
+ my_errno= HA_ERR_READ_ONLY_TRANSACTION;
DBUG_RETURN(1);
}
1
0
revision-id: 4eff940dde0fee130cf3a7512b1fe25fc71bbe81 (mariadb-10.4.3-82-g4eff940dde0)
parent(s): 9c7299365f04faf1b3963a2d891c8cb6dda89e4a
author: Oleksandr Byelkin
committer: Oleksandr Byelkin
timestamp: 2019-03-23 18:15:41 +0100
message:
cc
---
storage/maria/ma_pagecache.c | 345 ++++++++++++++++++++++++++++++++++++++++---
storage/maria/ma_pagecache.h | 20 ++-
2 files changed, 347 insertions(+), 18 deletions(-)
diff --git a/storage/maria/ma_pagecache.c b/storage/maria/ma_pagecache.c
index d10595fffd9..aa8ffc31d0a 100644
--- a/storage/maria/ma_pagecache.c
+++ b/storage/maria/ma_pagecache.c
@@ -85,6 +85,9 @@
#define PAGECACHE_DEBUG
#define PAGECACHE_DEBUG_LOG "my_pagecache_debug.log"
*/
+#define PAGECACHE_DEBUG
+#define PAGECACHE_DEBUG_LOG "my_pagecache_debug.log"
+#define _VARARGS(X) X
/*
In key cache we have external raw locking here we use
@@ -127,7 +130,8 @@ my_bool my_disable_flush_pagecache_blocks= 0;
#define COND_FOR_REQUESTED 0 /* queue of thread waiting for read operation */
#define COND_FOR_SAVED 1 /* queue of thread waiting for flush */
#define COND_FOR_WRLOCK 2 /* queue of write lock */
-#define COND_SIZE 3 /* number of COND_* queues */
+#define COND_FOR_BIG_BLOCK 3 /* queue of waiting fo big block read */
+#define COND_SIZE 4 /* number of COND_* queues */
typedef mysql_cond_t KEYCACHE_CONDVAR;
@@ -146,7 +150,7 @@ struct st_pagecache_hash_link
struct st_pagecache_block_link
*block; /* reference to the block for the page: */
PAGECACHE_FILE file; /* from such a file */
- pgcache_page_no_t pageno; /* this page */
+ pgcache_page_no_t pageno; /* this page */
uint requests; /* number of requests for the page */
};
@@ -174,6 +178,7 @@ struct st_pagecache_hash_link
#define PCBLOCK_CHANGED 32 /* block buffer contains a dirty page */
#define PCBLOCK_DIRECT_W 64 /* possible direct write to the block */
#define PCBLOCK_DEL_WRITE 128 /* should be written on delete */
+#define PCBLOCK_BIG_READ 256 /* the first block of the big read in progress */
/* page status, returned by find_block */
#define PAGE_READ 0
@@ -534,10 +539,22 @@ static void pagecache_debug_print _VARARGS((const char *fmt, ...));
#if defined(PAGECACHE_DEBUG_LOG) && defined(PAGECACHE_DEBUG)
#define KEYCACHE_PRINT(l, m) KEYCACHE_DBUG_PRINT(l,m)
+
+#ifdef PAGECACHE_DEBUG_DLOG
#define KEYCACHE_DBUG_PRINT(l, m) \
{ if (pagecache_debug_log) \
+ { \
fprintf(pagecache_debug_log, "%s: ", l); \
+ DBUG_PRINT("PCDEBUG", ("%s: ", l)); \
+ } \
pagecache_debug_print m; }
+#else
+#define KEYCACHE_DBUG_PRINT(l, m) \
+ { if (pagecache_debug_log) \
+ fprintf(pagecache_debug_log, "%s: ", l); \
+ pagecache_debug_print m; }
+#endif
+
#define KEYCACHE_DBUG_ASSERT(a) \
{ if (! (a) && pagecache_debug_log) \
@@ -748,7 +765,8 @@ static inline uint next_power(uint value)
size_t init_pagecache(PAGECACHE *pagecache, size_t use_mem,
uint division_limit, uint age_threshold,
- uint block_size, uint changed_blocks_hash_size,
+ uint block_size,
+ uint changed_blocks_hash_size,
myf my_readwrite_flags)
{
size_t blocks, hash_links, length;
@@ -1350,6 +1368,8 @@ static void link_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block,
}
}
while (thread != last_thread);
+ DBUG_PRINT("XXX", ("hash_link (link block): %p, hash_link: %p -> %p",
+ hash_link, hash_link->block, block));
hash_link->block= block;
/* Ensure that no other thread tries to use this block */
block->status|= PCBLOCK_REASSIGNED;
@@ -1646,6 +1666,9 @@ static void unlink_hash(PAGECACHE *pagecache, PAGECACHE_HASH_LINK *hash_link)
if ((*hash_link->prev= hash_link->next))
hash_link->next->prev= hash_link->prev;
+
+ DBUG_PRINT("XXX", ("hash_link (unlink): %p, hash_link: %p -> NULL",
+ hash_link, hash_link->block));
hash_link->block= NULL;
if (pagecache->waiting_for_hash_link.last_thread)
{
@@ -1893,6 +1916,7 @@ static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache,
my_bool wrmode,
my_bool block_is_copied,
my_bool reg_req,
+ my_bool fast,
int *page_st)
{
PAGECACHE_HASH_LINK *hash_link;
@@ -1909,6 +1933,7 @@ static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache,
DBUG_EXECUTE("check_pagecache",
test_key_cache(pagecache, "start of find_block", 0););
#endif
+ DBUG_ASSERT(!fast || !wrmode);
restart:
/* Find the hash link for the requested page (file, pageno) */
@@ -2018,9 +2043,11 @@ static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache,
/* This is a request for a new page or for a page not to be removed */
if (! block)
{
+ DBUG_PRINT("XXX", ("request for a new page"));
/* No block is assigned for the page yet */
if (pagecache->blocks_unused)
{
+ DBUG_PRINT("XXX", ("there is never used blocks"));
if (pagecache->free_block_list)
{
/* There is a block in the free list. */
@@ -2054,7 +2081,11 @@ static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache,
block->last_hit_time= 0;
block->rec_lsn= LSN_MAX;
link_to_file_list(pagecache, block, file, 0);
+ DBUG_PRINT("XXX", ("block (no block assigned): %p, hash_link: %p -> %p",
+ block, block->hash_link, hash_link));
block->hash_link= hash_link;
+ DBUG_PRINT("XXX", ("hash_link (no block assignment): %p, hash_link: %p -> %p",
+ hash_link, hash_link->block, block));
hash_link->block= block;
page_status= PAGE_TO_BE_READ;
DBUG_PRINT("info", ("page to be read set for page %p (%u)",
@@ -2065,6 +2096,7 @@ static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache,
}
else
{
+ DBUG_PRINT("XXX", ("there is NOT never used blocks"));
/* There are no never used blocks, use a block from the LRU chain */
/*
@@ -2076,6 +2108,8 @@ static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache,
if (! pagecache->used_last)
{
+ DBUG_PRINT("XXX", ("there is NOT UNUSED blocks"));
+ struct st_my_thread_var *thread;
/*
Wait until a new block is added to the LRU chain;
several threads might wait here for the same page,
@@ -2084,8 +2118,18 @@ static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache,
The block is given to us by the next thread executing
link_block().
*/
+ if (fast)
+ {
+ DBUG_ASSERT(hash_link->requests == 0);
+ unlink_hash(pagecache, hash_link);
+ DBUG_PRINT("info", ("fast and no blocks in LRU"));
- struct st_my_thread_var *thread= my_thread_var;
+ KEYCACHE_DBUG_PRINT("find_block",
+ ("fast and no blocks in LRU"));
+ DBUG_RETURN(0);
+ }
+
+ thread= my_thread_var;
thread->keycache_link= (void *) hash_link;
wqueue_link_into_queue(&pagecache->waiting_for_block, thread);
do
@@ -2104,13 +2148,30 @@ static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache,
}
else
{
+ DBUG_PRINT("XXX", ("take a block from LRU"));
/*
Take the first block from the LRU chain
unlinking it from the chain
*/
block= pagecache->used_last->next_used;
+ if (fast &&
+ ((block->status & (PCBLOCK_IN_FLUSH | PCBLOCK_CHANGED)) ||
+ (block->hash_link && block->hash_link != hash_link &&
+ block->hash_link->requests)))
+ {
+ DBUG_ASSERT(hash_link->requests == 0);
+ unlink_hash(pagecache, hash_link);
+ DBUG_PRINT("info", ("fast and LRU block is in switch or has "
+ "readers"));
+ KEYCACHE_DBUG_PRINT("find_block",
+ ("fast and LRU block is in switch or has "
+ "readers"));
+ DBUG_RETURN (0);
+ }
if (reg_req)
reg_requests(pagecache, block, 1);
+ DBUG_PRINT("XXX", ("hash_link (LRU): %p, hash_link: %p -> %p",
+ hash_link, hash_link->block, block));
hash_link->block= block;
DBUG_ASSERT(block->requests == 1);
}
@@ -2181,6 +2242,8 @@ static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache,
link_to_file_list(pagecache, block, file,
(my_bool)(block->hash_link ? 1 : 0));
+ DBUG_PRINT("XXX", ("block (LRU): %p, hash_link: %p -> %p",
+ block, block->hash_link, hash_link));
block->hash_link= hash_link;
PCBLOCK_INFO(block);
block->hits_left= init_hits_left;
@@ -2669,6 +2732,170 @@ static my_bool make_lock_and_pin(PAGECACHE *pagecache,
}
+static my_bool read_big_block(PAGECACHE *pagecache,
+ PAGECACHE_BLOCK_LINK *block)
+{
+ int page_st;
+ size_t big_block_size_in_pages;
+ size_t offset;
+ pgcache_page_no_t page, our_page;
+ pgcache_page_no_t page_to_read;
+ PAGECACHE_BLOCK_LINK *block_to_read= NULL;
+ PAGECACHE_IO_HOOK_ARGS args;
+ LEX_STRING data= {0,0};
+ DBUG_ENTER("read_big_block");
+ DBUG_PRINT("enter", ("read BIG block: %p", block));
+
+ DBUG_ASSERT(block->hash_link->file.big_block_size %
+ pagecache->block_size == 0);
+ big_block_size_in_pages=
+ block->hash_link->file.big_block_size / pagecache->block_size;
+ /* find first page of the big block (page_to_read) */
+ page_to_read=
+ (block->hash_link->pageno - block->hash_link->file.first_page) /
+ big_block_size_in_pages * big_block_size_in_pages +
+ block->hash_link->file.first_page;
+ if (page_to_read != block->hash_link->pageno)
+ {
+ block_to_read= find_block(pagecache, &block->hash_link->file,
+ page_to_read, 1,
+ FALSE, TRUE /* copy under protection (?)*/,
+ TRUE /*register*/, FALSE, &page_st);
+ DBUG_ASSERT(block_to_read == block_to_read->hash_link->block);
+
+ if (block_to_read->status & PCBLOCK_ERROR)
+ {
+ /* We get first block with an error so all operation failed */
+ block->status|= PCBLOCK_ERROR;
+ block->error= block_to_read->error;
+ DBUG_RETURN(FALSE); // no retry
+ }
+ // only primary request here, PAGE_WAIT_TO_BE_READ is impossible
+ DBUG_ASSERT(page_st != PAGE_WAIT_TO_BE_READ);
+ if (block_to_read->status & PCBLOCK_BIG_READ)
+ {
+ struct st_my_thread_var *thread;
+ DBUG_ASSERT(page_st != PAGE_TO_BE_READ);
+ /*
+ Other thread perform the operation =>
+ unlock and repeat
+ */
+ // Big block read failed because somebody else read the first block
+ unreg_request(pagecache, block, 1);
+ thread= my_thread_var;
+ /* Put the request into a queue and wait until it can be processed */
+ wqueue_add_to_queue(&block->wqueue[COND_FOR_BIG_BLOCK], thread);
+ do
+ {
+ DBUG_PRINT("wait",
+ ("suspend thread %s %ld", thread->name,
+ (ulong) thread->id));
+ pagecache_pthread_cond_wait(&thread->suspend,
+ &pagecache->cache_lock);
+ }
+ while (thread->next);
+ DBUG_RETURN(TRUE);
+ }
+ }
+ else
+ block_to_read= block;
+
+
+ DBUG_ASSERT(!(block_to_read->status & PCBLOCK_BIG_READ));
+ // Mark the first page of a big block
+ block_to_read->status|= PCBLOCK_BIG_READ;
+
+ // perform read
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+
+ args.page= NULL;
+ args.pageno= block->hash_link->pageno;
+ args.data= block->hash_link->file.callback_data;
+
+ if (block->hash_link->file.big_block_read(pagecache,
+ &args, &block->hash_link->file,
+ &data))
+ {
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+ block_to_read->status|= PCBLOCK_ERROR;
+ block->status|= PCBLOCK_ERROR;
+ block_to_read->error= block->error= (int16) my_errno;
+ if (block_to_read != block)
+ {
+ remove_reader(block_to_read);
+ unreg_request(pagecache, block_to_read, 1);
+ }
+ /* TODO: is it correct? */
+ if (data.str)
+ my_free(data.str);
+ DBUG_RETURN(FALSE); // no retry
+ }
+
+ // fill pages
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+
+ our_page= block->hash_link->pageno;
+
+ for(offset= 0, page= page_to_read;
+ offset < data.length;
+ offset+= pagecache->block_size, page++)
+ {
+ DBUG_ASSERT(offset + pagecache->block_size <= data.length);
+ if (page == page_to_read)
+ {
+ if (page_st != PAGE_READ)
+ {
+ DBUG_ASSERT(page_st != PAGE_WAIT_TO_BE_READ);
+ DBUG_ASSERT(offset == 0);
+ memcpy(block_to_read->buffer, data.str, pagecache->block_size);
+ block_to_read->status|= PCBLOCK_READ;
+ }
+ else
+ DBUG_ASSERT(block->status & PCBLOCK_READ);
+ } else if (page == our_page)
+ {
+ DBUG_ASSERT(!(block->status & PCBLOCK_READ));
+ memcpy(block->buffer, data.str + offset, pagecache->block_size);
+ block->status|= PCBLOCK_READ;
+ }
+ else
+ {
+ PAGECACHE_BLOCK_LINK *bl;
+ bl= find_block(pagecache, &block->hash_link->file, page, 1,
+ FALSE, TRUE /* copy under protection (?)*/,
+ TRUE /*register*/, TRUE /*fast*/, &page_st);
+ if (!bl)
+ {
+ // we run out of easy awaliable pages in the cache
+ break;
+ }
+ DBUG_ASSERT(bl == bl->hash_link->block);
+ if ((bl->status & PCBLOCK_ERROR) == 0 &&
+ page_st == PAGE_TO_BE_READ)
+ {
+ memcpy(bl->buffer, data.str + offset, pagecache->block_size);
+ bl->status|= PCBLOCK_READ;
+ }
+ remove_reader(bl);
+ unreg_request(pagecache, bl, 1);
+ }
+ }
+ /* TODO: is it correct? */
+ my_free(data.str);
+
+ block_to_read->status&= ~PCBLOCK_BIG_READ;
+ if (block_to_read != block)
+ {
+ remove_reader(block_to_read);
+ unreg_request(pagecache, block_to_read, 1);
+ }
+ if (block->wqueue[COND_FOR_BIG_BLOCK].last_thread)
+ wqueue_release_queue(&block->wqueue[COND_FOR_BIG_BLOCK]);
+
+ DBUG_RETURN(FALSE);
+}
+
+
/*
Read into a key cache block buffer from disk.
@@ -2861,7 +3088,7 @@ void pagecache_unlock(PAGECACHE *pagecache,
inc_counter_for_resize_op(pagecache);
/* See NOTE for pagecache_unlock about registering requests */
block= find_block(pagecache, file, pageno, 0, 0, 0,
- pin == PAGECACHE_PIN_LEFT_UNPINNED, &page_st);
+ pin == PAGECACHE_PIN_LEFT_UNPINNED, FALSE, &page_st);
PCBLOCK_INFO(block);
DBUG_ASSERT(block != 0 && page_st == PAGE_READ);
if (first_REDO_LSN_for_page)
@@ -2948,7 +3175,7 @@ void pagecache_unpin(PAGECACHE *pagecache,
inc_counter_for_resize_op(pagecache);
/* See NOTE for pagecache_unlock about registering requests */
- block= find_block(pagecache, file, pageno, 0, 0, 0, 0, &page_st);
+ block= find_block(pagecache, file, pageno, 0, 0, 0, 0, FALSE, &page_st);
DBUG_ASSERT(block != 0);
DBUG_ASSERT(page_st == PAGE_READ);
/* we can't unpin such page without unlock */
@@ -3349,7 +3576,7 @@ uchar *pagecache_read(PAGECACHE *pagecache,
char llbuf[22];
DBUG_ENTER("pagecache_read");
DBUG_PRINT("enter", ("fd: %u page: %s buffer: %p level: %u "
- "t:%s (%d)%s->%s %s->%s",
+ "t:%s (%d)%s->%s %s->%s big block: %d",
(uint) file->file, ullstr(pageno, llbuf),
buff, level,
page_cache_page_type_str[type],
@@ -3357,7 +3584,8 @@ uchar *pagecache_read(PAGECACHE *pagecache,
page_cache_page_lock_str[lock_to_read[lock].new_lock],
page_cache_page_lock_str[lock_to_read[lock].unlock_lock],
page_cache_page_pin_str[new_pin],
- page_cache_page_pin_str[unlock_pin]));
+ page_cache_page_pin_str[unlock_pin],
+ MY_TEST(file->big_block_read)));
DBUG_ASSERT(buff != 0 || (buff == 0 && (unlock_pin == PAGECACHE_PIN ||
unlock_pin == PAGECACHE_PIN_LEFT_PINNED)));
DBUG_ASSERT(pageno < ((1ULL) << 40));
@@ -3369,6 +3597,19 @@ uchar *pagecache_read(PAGECACHE *pagecache,
restart:
+ /*
+ If we use big block than the big block is multiple of blocks and we
+ have enouch blocks in cache
+ */
+ DBUG_ASSERT(!file->big_block_read ||
+ (file->big_block_size != 0 &&
+ file->big_block_size % pagecache->block_size == 0));
+ /*
+ &&
+ pagecache->blocks /
+ (file->big_block_size/pagecache->block_size) > 8));
+ */
+
if (pagecache->can_be_used)
{
/* Key cache is used */
@@ -3387,19 +3628,41 @@ uchar *pagecache_read(PAGECACHE *pagecache,
pagecache->global_cache_r_requests++;
/* See NOTE for pagecache_unlock about registering requests. */
reg_request= ((new_pin == PAGECACHE_PIN_LEFT_UNPINNED) ||
- (new_pin == PAGECACHE_PIN));
+ (new_pin == PAGECACHE_PIN) ||
+ file->big_block_read);
block= find_block(pagecache, file, pageno, level,
lock == PAGECACHE_LOCK_WRITE, buff != 0,
- reg_request, &page_st);
+ reg_request, FALSE, &page_st);
DBUG_PRINT("info", ("Block type: %s current type %s",
page_cache_page_type_str[block->type],
page_cache_page_type_str[type]));
if (((block->status & PCBLOCK_ERROR) == 0) && (page_st != PAGE_READ))
{
- /* The requested page is to be read into the block buffer */
- read_block(pagecache, block,
- (my_bool)(page_st == PAGE_TO_BE_READ));
- DBUG_PRINT("info", ("read is done"));
+ my_bool primary= (my_bool)(page_st == PAGE_TO_BE_READ);
+ if (!file->big_block_read || !primary ||
+ pageno < file->first_page) // TODO: remove after testing
+ {
+ /* The requested page is to be read into the block buffer */
+ read_block(pagecache, block, primary);
+ DBUG_PRINT("info", ("read is done"));
+ }
+ else
+ {
+ // It is big read and this thread should read
+ if (read_big_block(pagecache, block))
+ {
+ // block is unregistered in read_big_block
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ DBUG_PRINT("info", ("big block fail, restarting..."));
+ goto restart;
+ }
+ if (!((new_pin == PAGECACHE_PIN_LEFT_UNPINNED) ||
+ (new_pin == PAGECACHE_PIN)))
+ {
+ // we registered reqest only for big_block_read
+ unreg_request(pagecache, block, 1);
+ }
+ }
}
/*
Assert after block is read. Imagine two concurrent SELECTs on same
@@ -3992,6 +4255,12 @@ my_bool pagecache_write_part(PAGECACHE *pagecache,
DBUG_ASSERT(pageno < ((1ULL) << 40));
#endif
+ if (file->big_block_read)
+ {
+ DBUG_ASSERT(0);
+ DBUG_RETURN(1);
+ }
+
if (!page_link)
page_link= &fake_link;
*page_link= 0;
@@ -4026,7 +4295,7 @@ my_bool pagecache_write_part(PAGECACHE *pagecache,
(pin == PAGECACHE_PIN));
block= find_block(pagecache, file, pageno, level,
TRUE, FALSE,
- reg_request, &page_st);
+ reg_request, FALSE, &page_st);
if (!block)
{
DBUG_ASSERT(write_mode != PAGECACHE_WRITE_DONE);
@@ -4278,6 +4547,8 @@ static my_bool free_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block,
block->type= PAGECACHE_EMPTY_PAGE;
#endif
block->rec_lsn= LSN_MAX;
+ DBUG_PRINT("XXX", ("block (Free): %p, hash_link: %p -> NULL",
+ block, block->hash_link));
block->hash_link= NULL;
if (block->temperature == PCBLOCK_WARM)
pagecache->warm_blocks--;
@@ -5265,8 +5536,11 @@ static void pagecache_debug_print(const char * fmt, ...)
va_start(args,fmt);
if (pagecache_debug_log)
{
- VOID(vfprintf(pagecache_debug_log, fmt, args));
- VOID(fputc('\n',pagecache_debug_log));
+ vfprintf(pagecache_debug_log, fmt, args);
+ fputc('\n',pagecache_debug_log);
+#ifdef PAGECACHE_DEBUG_DLOG
+ _db_doprnt_(fmt, args);
+#endif
}
va_end(args);
}
@@ -5307,6 +5581,35 @@ static void null_post_write_hook(int res __attribute__((unused)),
return;
}
+#ifndef DBUG_OFF
+static my_bool
+ _pagecache_big_block_read_emu(struct st_pagecache *pagecache,
+ PAGECACHE_IO_HOOK_ARGS *args,
+ struct st_pagecache_file *file,
+ LEX_STRING *data)
+{
+ DBUG_ASSERT(file->big_block_size > 0);
+
+ if (!(data->str= my_malloc(file->big_block_size, MYF(MY_WME))))
+ return TRUE;
+
+ data->length= mysql_file_pread(file->file,
+ (unsigned char *)data->str,
+ file->big_block_size,
+ ((my_off_t) args->pageno << pagecache->shift),
+ MYF(0));
+ if (data->length == 0 || data->length == MY_FILE_ERROR)
+ {
+ data->length = 0;
+ if (!my_errno)
+ my_errno= HA_ERR_UNSUPPORTED; // just something
+ return TRUE;
+ }
+
+ return FALSE;
+}
+#endif /* DBUG_OFF */
+
void
pagecache_file_set_null_hooks(PAGECACHE_FILE *file)
{
@@ -5316,4 +5619,12 @@ pagecache_file_set_null_hooks(PAGECACHE_FILE *file)
file->post_write_hook= null_post_write_hook;
file->flush_log_callback= null_pre_hook;
file->callback_data= NULL;
+ file->first_page= file->big_block_size= 0;
+ file->big_block_read= NULL;
+ DBUG_EXECUTE_IF("maria_emulate_big_block",
+ {
+ file->first_page= 1;
+ file->big_block_size= 4*1024*1024;
+ file->big_block_read= _pagecache_big_block_read_emu;
+ });
}
diff --git a/storage/maria/ma_pagecache.h b/storage/maria/ma_pagecache.h
index 1183f9d57e0..e3b68ce4f5f 100644
--- a/storage/maria/ma_pagecache.h
+++ b/storage/maria/ma_pagecache.h
@@ -86,9 +86,16 @@ typedef struct st_pagecache_io_hook_args
uchar *crypt_buf; /* when using encryption */
} PAGECACHE_IO_HOOK_ARGS;
+struct st_pagecache;
+
/* file descriptor for Maria */
typedef struct st_pagecache_file
{
+ /* size n pages of first "page" (which is not a big block) */
+ size_t first_page;
+ /* size of a big block for S3 or 0 */
+ size_t big_block_size;
+ /* File number */
File file;
/** Cannot be NULL */
@@ -99,9 +106,19 @@ typedef struct st_pagecache_file
my_bool (*pre_write_hook)(PAGECACHE_IO_HOOK_ARGS *args);
void (*post_write_hook)(int error, PAGECACHE_IO_HOOK_ARGS *args);
- /** Cannot be NULL */
my_bool (*flush_log_callback)(PAGECACHE_IO_HOOK_ARGS *args);
+ /**
+ Function for reading file in big hunks from S3
+ Data will be filled with pointer and length to data read
+ start_page will be contain first page read.
+ */
+ my_bool (*big_block_read)(struct st_pagecache *pagecache,
+ PAGECACHE_IO_HOOK_ARGS *args,
+ struct st_pagecache_file *file, LEX_STRING *data);
+
+
+ /** Cannot be NULL */
uchar *callback_data;
} PAGECACHE_FILE;
@@ -123,6 +140,7 @@ typedef struct st_pagecache_hash_link PAGECACHE_HASH_LINK;
#define PAGECACHE_PRIORITY_DEFAULT 3
#define PAGECACHE_PRIORITY_HIGH 6
+
/*
The page cache structure
It also contains read-only statistics parameters.
1
0