diff --git a/mysql-test/suite/encryption/r/innodb-encryption-alter.result b/mysql-test/suite/encryption/r/innodb-encryption-alter.result index a610b404228d0..f6d95711a6b0e 100644 --- a/mysql-test/suite/encryption/r/innodb-encryption-alter.result +++ b/mysql-test/suite/encryption/r/innodb-encryption-alter.result @@ -1,6 +1,6 @@ SET GLOBAL innodb_encrypt_tables = ON; SET GLOBAL innodb_encryption_threads = 4; -CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256)) ENGINE=INNODB ENCRYPTED=NO ENCRYPTION_KEY_ID=4; +CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256)) ENGINE=INNODB ENCRYPTED='False' ENCRYPTION_KEY_ID=4; Warnings: Warning 140 InnoDB: ENCRYPTED=NO implies ENCRYPTION_KEY_ID=1 DROP TABLE t1; @@ -27,14 +27,14 @@ Warning 140 InnoDB: ENCRYPTION_KEY_ID 99 not available Error 1005 Can't create table `test`.`t1` (errno: 140 "Wrong create options") Warning 1030 Got error 140 "Wrong create options" from storage engine InnoDB set innodb_default_encryption_key_id = 4; -CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256)) ENGINE=INNODB ENCRYPTED=YES; +CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256)) ENGINE=INNODB ENCRYPTED='on'; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `pk` int(11) NOT NULL AUTO_INCREMENT, `c` varchar(256) DEFAULT NULL, PRIMARY KEY (`pk`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci `ENCRYPTED`=YES `ENCRYPTION_KEY_ID`=4 +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci `ENCRYPTED`='on' `ENCRYPTION_KEY_ID`=4 DROP TABLE t1; CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256)) ENGINE=INNODB; SHOW CREATE TABLE t1; diff --git a/mysql-test/suite/encryption/t/innodb-encryption-alter.test b/mysql-test/suite/encryption/t/innodb-encryption-alter.test index 6e5d449b10a23..b7909846015d4 100644 --- a/mysql-test/suite/encryption/t/innodb-encryption-alter.test +++ b/mysql-test/suite/encryption/t/innodb-encryption-alter.test @@ -10,7 +10,7 @@ SET GLOBAL innodb_encrypt_tables = ON; SET GLOBAL innodb_encryption_threads = 4; -CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256)) ENGINE=INNODB ENCRYPTED=NO ENCRYPTION_KEY_ID=4; +CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256)) ENGINE=INNODB ENCRYPTED='False' ENCRYPTION_KEY_ID=4; DROP TABLE t1; set @save_global = @@GLOBAL.innodb_default_encryption_key_id; set innodb_default_encryption_key_id = 99; @@ -23,7 +23,7 @@ SHOW WARNINGS; CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256)) ENGINE=INNODB ENCRYPTED=YES; SHOW WARNINGS; set innodb_default_encryption_key_id = 4; -CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256)) ENGINE=INNODB ENCRYPTED=YES; +CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256)) ENGINE=INNODB ENCRYPTED='on'; SHOW CREATE TABLE t1; DROP TABLE t1; CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256)) ENGINE=INNODB; diff --git a/mysql-test/suite/innodb/r/index_ahi_option,ahi.rdiff b/mysql-test/suite/innodb/r/index_ahi_option,ahi.rdiff new file mode 100644 index 0000000000000..a287e871c065f --- /dev/null +++ b/mysql-test/suite/innodb/r/index_ahi_option,ahi.rdiff @@ -0,0 +1,37 @@ +--- index_ahi_option.result ++++ index_ahi_option,ahi.result +@@ -2,7 +2,7 @@ + # Test InnoDB index-level adaptive_hash_index options + # + SET @start_global_value = @@global.innodb_adaptive_hash_index; +-SET GLOBAL innodb_adaptive_hash_index=OFF; ++SET GLOBAL innodb_adaptive_hash_index=ON; + # + # Scenario 1: complete_fields parameter with point lookups + # +@@ -30,20 +30,20 @@ + SET GLOBAL innodb_monitor_enable = module_adaptive_hash; + # Warming up AHI + # Warmed up AHI +-# No AHI used in SELECT (idx_1) +-# No AHI used in SELECT (idx_2) ++# Used AHI in SELECT (idx_1) ++# Used AHI in SELECT (idx_2) + # No AHI used in SELECT (idx_3) + ALTER TABLE t1 adaptive_hash_index=OFF; + # Warming up AHI + # Warmed up AHI + # No AHI used in SELECT (idx_1) +-# No AHI used in SELECT (idx_2) ++# Used AHI in SELECT (idx_2) + # No AHI used in SELECT (idx_3) + ALTER TABLE t1 adaptive_hash_index='ON'; + # Warming up AHI + # Warmed up AHI +-# No AHI used in SELECT (idx_1) +-# No AHI used in SELECT (idx_2) ++# Used AHI in SELECT (idx_1) ++# Used AHI in SELECT (idx_2) + # No AHI used in SELECT (idx_3) + DROP TABLE t1; + SET @@global.innodb_adaptive_hash_index = @start_global_value; diff --git a/mysql-test/suite/innodb/r/index_ahi_option,if_specified.rdiff b/mysql-test/suite/innodb/r/index_ahi_option,if_specified.rdiff new file mode 100644 index 0000000000000..9e1a5ec3f3a55 --- /dev/null +++ b/mysql-test/suite/innodb/r/index_ahi_option,if_specified.rdiff @@ -0,0 +1,35 @@ +--- index_ahi_option.result ++++ index_ahi_option,if_specified.result +@@ -2,7 +2,7 @@ + # Test InnoDB index-level adaptive_hash_index options + # + SET @start_global_value = @@global.innodb_adaptive_hash_index; +-SET GLOBAL innodb_adaptive_hash_index=OFF; ++SET GLOBAL innodb_adaptive_hash_index=if_specified; + # + # Scenario 1: complete_fields parameter with point lookups + # +@@ -31,19 +31,19 @@ + # Warming up AHI + # Warmed up AHI + # No AHI used in SELECT (idx_1) +-# No AHI used in SELECT (idx_2) ++# Used AHI in SELECT (idx_2) + # No AHI used in SELECT (idx_3) + ALTER TABLE t1 adaptive_hash_index=OFF; + # Warming up AHI + # Warmed up AHI + # No AHI used in SELECT (idx_1) +-# No AHI used in SELECT (idx_2) ++# Used AHI in SELECT (idx_2) + # No AHI used in SELECT (idx_3) + ALTER TABLE t1 adaptive_hash_index='ON'; + # Warming up AHI + # Warmed up AHI +-# No AHI used in SELECT (idx_1) +-# No AHI used in SELECT (idx_2) ++# Used AHI in SELECT (idx_1) ++# Used AHI in SELECT (idx_2) + # No AHI used in SELECT (idx_3) + DROP TABLE t1; + SET @@global.innodb_adaptive_hash_index = @start_global_value; diff --git a/mysql-test/suite/innodb/r/index_ahi_option.result b/mysql-test/suite/innodb/r/index_ahi_option.result new file mode 100644 index 0000000000000..3730298191b9f --- /dev/null +++ b/mysql-test/suite/innodb/r/index_ahi_option.result @@ -0,0 +1,52 @@ +# +# Test InnoDB index-level adaptive_hash_index options +# +SET @start_global_value = @@global.innodb_adaptive_hash_index; +SET GLOBAL innodb_adaptive_hash_index=OFF; +# +# Scenario 1: complete_fields parameter with point lookups +# +CREATE TABLE t1 ( +id INT PRIMARY KEY, +col1 INT, col2 INT, col3 INT, +INDEX idx_1 (col1) adaptive_hash_index=DEFAULT, +INDEX idx_2 (col1, col2) adaptive_hash_index=YES, +INDEX idx_3 (col1, col2, col3) adaptive_hash_index=NO +) ENGINE=InnoDB STATS_PERSISTENT=0 adaptive_hash_index=DEFAULT; +INSERT INTO t1 SELECT seq, seq % 100, seq % 10, seq % 5 FROM seq_1_to_50000; +INSERT INTO t1 VALUES (50001, 50, 1, 1), (50002, 50, 2, 2), +(50003, 50, 3, 3), (50004, 50, 4, 4), (50005, 50, 5, 0), +(50006, 50, 6, 1), (50007, 50, 7, 2), (50008, 50, 8, 3), +(50009, 50, 9, 4); +# +# AHI usage in searches is verified by measuring an increase in +# the "count" of "adaptive_hash_searches" InnoDB metric. +# An alternative strategy would use "ANALYZE FORMAT=JSON" and +# check the "pages_accessed" entry: lower values w.r.t. the +# base case would imply that AHI was used for the search. +# Unfortunately, that is not really stable. +# Hopefully using "innodb_metrics" is more stable. +# +SET GLOBAL innodb_monitor_enable = module_adaptive_hash; +# Warming up AHI +# Warmed up AHI +# No AHI used in SELECT (idx_1) +# No AHI used in SELECT (idx_2) +# No AHI used in SELECT (idx_3) +ALTER TABLE t1 adaptive_hash_index=OFF; +# Warming up AHI +# Warmed up AHI +# No AHI used in SELECT (idx_1) +# No AHI used in SELECT (idx_2) +# No AHI used in SELECT (idx_3) +ALTER TABLE t1 adaptive_hash_index='ON'; +# Warming up AHI +# Warmed up AHI +# No AHI used in SELECT (idx_1) +# No AHI used in SELECT (idx_2) +# No AHI used in SELECT (idx_3) +DROP TABLE t1; +SET @@global.innodb_adaptive_hash_index = @start_global_value; +SET GLOBAL innodb_monitor_disable = module_adaptive_hash; +SET GLOBAL innodb_monitor_disable = default; +SET GLOBAL innodb_monitor_enable = default; diff --git a/mysql-test/suite/innodb/r/innodb_buffer_pool_resize.result b/mysql-test/suite/innodb/r/innodb_buffer_pool_resize.result index 7b254daf4925d..46f5549c3e09b 100644 --- a/mysql-test/suite/innodb/r/innodb_buffer_pool_resize.result +++ b/mysql-test/suite/innodb/r/innodb_buffer_pool_resize.result @@ -20,12 +20,12 @@ SET STATEMENT foreign_key_checks=0, unique_checks=0 FOR INSERT INTO t2 SELECT seq*4,seq*4 FROM seq_1_to_16384; SELECT @@GLOBAL.innodb_adaptive_hash_index; @@GLOBAL.innodb_adaptive_hash_index -1 +ON SET STATEMENT max_statement_time=1e-9 FOR SET GLOBAL innodb_buffer_pool_size = 7340032; SELECT @@GLOBAL.innodb_adaptive_hash_index; @@GLOBAL.innodb_adaptive_hash_index -1 +ON FOUND 1 /innodb_buffer_pool_size=7m.*resized from|innodb_buffer_pool_size change aborted/ in mysqld.1.err set global innodb_buffer_pool_size = 7340032; select count(val) from t1; diff --git a/mysql-test/suite/innodb/r/innodb_buffer_pool_resize_temporary.result b/mysql-test/suite/innodb/r/innodb_buffer_pool_resize_temporary.result index 12fb02a40c757..7af3268b970c7 100644 --- a/mysql-test/suite/innodb/r/innodb_buffer_pool_resize_temporary.result +++ b/mysql-test/suite/innodb/r/innodb_buffer_pool_resize_temporary.result @@ -10,7 +10,7 @@ SET GLOBAL innodb_buffer_pool_size=8388608; ERROR HY000: innodb_buffer_pool_size change aborted SELECT @@GLOBAL.innodb_adaptive_hash_index,@@GLOBAL.innodb_buffer_pool_size; @@GLOBAL.innodb_adaptive_hash_index @@GLOBAL.innodb_buffer_pool_size -1 16777216 +ON 16777216 SET GLOBAL innodb_adaptive_hash_index = @old_innodb_adaptive_hash_index; CREATE TEMPORARY TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t1 SELECT seq FROM seq_1_to_200; diff --git a/mysql-test/suite/innodb/t/index_ahi_option.combinations b/mysql-test/suite/innodb/t/index_ahi_option.combinations new file mode 100644 index 0000000000000..f9099f637b0fa --- /dev/null +++ b/mysql-test/suite/innodb/t/index_ahi_option.combinations @@ -0,0 +1,3 @@ +[ahi] +[no_ahi] +[if_specified] diff --git a/mysql-test/suite/innodb/t/index_ahi_option.test b/mysql-test/suite/innodb/t/index_ahi_option.test new file mode 100644 index 0000000000000..5b86c2a250d9c --- /dev/null +++ b/mysql-test/suite/innodb/t/index_ahi_option.test @@ -0,0 +1,272 @@ +--source include/have_innodb.inc +--source include/have_sequence.inc + +--echo # +--echo # Test InnoDB index-level adaptive_hash_index options +--echo # + +SET @start_global_value = @@global.innodb_adaptive_hash_index; +if ($MTR_COMBINATION_AHI) { +SET GLOBAL innodb_adaptive_hash_index=ON; +} +if ($MTR_COMBINATION_NO_AHI) { +SET GLOBAL innodb_adaptive_hash_index=OFF; +} +if ($MTR_COMBINATION_IF_SPECIFIED) { +SET GLOBAL innodb_adaptive_hash_index=if_specified; +} + +--echo # +--echo # Scenario 1: complete_fields parameter with point lookups +--echo # + +CREATE TABLE t1 ( + id INT PRIMARY KEY, + col1 INT, col2 INT, col3 INT, + INDEX idx_1 (col1) adaptive_hash_index=DEFAULT, + INDEX idx_2 (col1, col2) adaptive_hash_index=YES, + INDEX idx_3 (col1, col2, col3) adaptive_hash_index=NO +) ENGINE=InnoDB STATS_PERSISTENT=0 adaptive_hash_index=DEFAULT; + +INSERT INTO t1 SELECT seq, seq % 100, seq % 10, seq % 5 FROM seq_1_to_50000; + +INSERT INTO t1 VALUES (50001, 50, 1, 1), (50002, 50, 2, 2), +(50003, 50, 3, 3), (50004, 50, 4, 4), (50005, 50, 5, 0), +(50006, 50, 6, 1), (50007, 50, 7, 2), (50008, 50, 8, 3), +(50009, 50, 9, 4); + +--echo # +--echo # AHI usage in searches is verified by measuring an increase in +--echo # the "count" of "adaptive_hash_searches" InnoDB metric. +--echo # An alternative strategy would use "ANALYZE FORMAT=JSON" and +--echo # check the "pages_accessed" entry: lower values w.r.t. the +--echo # base case would imply that AHI was used for the search. +--echo # Unfortunately, that is not really stable. +--echo # Hopefully using "innodb_metrics" is more stable. +--echo # + +SET GLOBAL innodb_monitor_enable = module_adaptive_hash; +let $warm_up_rounds= 200; +let $query_rounds= 10; + +--echo # Warming up AHI +let $i = $warm_up_rounds; +while ($i) +{ + --disable_query_log + --disable_result_log + SELECT COUNT(*) FROM t1 FORCE INDEX(idx_1) WHERE col1 = 50; + SELECT COUNT(*) FROM t1 FORCE INDEX(idx_2) WHERE col1 = 50 AND col2 >= 0; + SELECT count(*) FROM t1 FORCE INDEX(idx_3) WHERE col1 = 50 and col2 >= 0 and col3 = 0; + --enable_result_log + --enable_query_log + dec $i; +} +--echo # Warmed up AHI + +let $val0 = query_get_value(SELECT count FROM information_schema.innodb_metrics WHERE name = 'adaptive_hash_searches', count, 1); +let $k = $query_rounds; +--disable_query_log +--disable_result_log +while ($k) { + SELECT COUNT(*) FROM t1 FORCE INDEX(idx_1) WHERE col1 = 50; + dec $k; +} +--enable_result_log +--enable_query_log +let $val1 = query_get_value(SELECT count FROM information_schema.innodb_metrics WHERE name = 'adaptive_hash_searches', count, 1); +if ($val1 > $val0) { + --echo # Used AHI in SELECT (idx_1) +} +if ($val1 <= $val0) { + --echo # No AHI used in SELECT (idx_1) +} +let $val0 = $val1; + +let $k = $query_rounds; +--disable_query_log +--disable_result_log +while ($k) { + SELECT COUNT(*) FROM t1 FORCE INDEX(idx_2) WHERE col1 = 50 AND col2 BETWEEN 0 AND 9; + dec $k; +} +--enable_result_log +--enable_query_log +let $val1 = query_get_value(SELECT count FROM information_schema.innodb_metrics WHERE name = 'adaptive_hash_searches', count, 1); +if ($val1 > $val0) { + --echo # Used AHI in SELECT (idx_2) +} +if ($val1 <= $val0) { + --echo # No AHI used in SELECT (idx_2) +} +let $val0 = $val1; + +let $k = $query_rounds; +--disable_query_log +--disable_result_log +while ($k) { + SELECT COUNT(*) FROM t1 FORCE INDEX(idx_3) WHERE col1 = 50 AND col2 BETWEEN 0 AND 9 AND col3 BETWEEN 0 AND 9; + dec $k; +} +--enable_result_log +--enable_query_log +let $val1 = query_get_value(SELECT count FROM information_schema.innodb_metrics WHERE name = 'adaptive_hash_searches', count, 1); +if ($val1 > $val0) { + --echo # Used AHI in SELECT (idx_3) +} +if ($val1 <= $val0) { + --echo # No AHI used in SELECT (idx_3) +} +let $val0 = $val1; + +ALTER TABLE t1 adaptive_hash_index=OFF; + +--echo # Warming up AHI +let $i = $warm_up_rounds; +while ($i) +{ + --disable_query_log + --disable_result_log + SELECT COUNT(*) FROM t1 FORCE INDEX(idx_1) WHERE col1 = 50; + SELECT COUNT(*) FROM t1 FORCE INDEX(idx_2) WHERE col1 = 50 AND col2 >= 0; + SELECT count(*) FROM t1 FORCE INDEX(idx_3) WHERE col1 = 50 and col2 >= 0 and col3 = 0; + --enable_result_log + --enable_query_log + dec $i; +} +--echo # Warmed up AHI + +let $val0 = query_get_value(SELECT count FROM information_schema.innodb_metrics WHERE name = 'adaptive_hash_searches', count, 1); +let $k = $query_rounds; +--disable_query_log +--disable_result_log +while ($k) { + SELECT COUNT(*) FROM t1 FORCE INDEX(idx_1) WHERE col1 = 50; + dec $k; +} +--enable_result_log +--enable_query_log +let $val1 = query_get_value(SELECT count FROM information_schema.innodb_metrics WHERE name = 'adaptive_hash_searches', count, 1); +if ($val1 > $val0) { + --echo # Used AHI in SELECT (idx_1) +} +if ($val1 <= $val0) { + --echo # No AHI used in SELECT (idx_1) +} +let $val0 = $val1; + +let $k = $query_rounds; +--disable_query_log +--disable_result_log +while ($k) { + SELECT COUNT(*) FROM t1 FORCE INDEX(idx_2) WHERE col1 = 50 AND col2 BETWEEN 0 AND 9; + dec $k; +} +--enable_result_log +--enable_query_log +let $val1 = query_get_value(SELECT count FROM information_schema.innodb_metrics WHERE name = 'adaptive_hash_searches', count, 1); +if ($val1 > $val0) { + --echo # Used AHI in SELECT (idx_2) +} +if ($val1 <= $val0) { + --echo # No AHI used in SELECT (idx_2) +} +let $val0 = $val1; + +let $k = $query_rounds; +--disable_query_log +--disable_result_log +while ($k) { + SELECT COUNT(*) FROM t1 FORCE INDEX(idx_3) WHERE col1 = 50 AND col2 BETWEEN 0 AND 9 AND col3 BETWEEN 0 AND 9; + dec $k; +} +--enable_result_log +--enable_query_log +let $val1 = query_get_value(SELECT count FROM information_schema.innodb_metrics WHERE name = 'adaptive_hash_searches', count, 1); +if ($val1 > $val0) { + --echo # Used AHI in SELECT (idx_3) +} +if ($val1 <= $val0) { + --echo # No AHI used in SELECT (idx_3) +} +let $val0 = $val1; + +ALTER TABLE t1 adaptive_hash_index='ON'; + +--echo # Warming up AHI +let $i = 200; +while ($i) +{ + --disable_query_log + --disable_result_log + SELECT COUNT(*) FROM t1 FORCE INDEX(idx_1) WHERE col1 = 50; + SELECT COUNT(*) FROM t1 FORCE INDEX(idx_2) WHERE col1 = 50 AND col2 >= 0; + SELECT count(*) FROM t1 FORCE INDEX(idx_3) WHERE col1 = 50 and col2 >= 0 and col3 = 0; + --enable_result_log + --enable_query_log + dec $i; +} +--echo # Warmed up AHI + +let $val0 = query_get_value(SELECT count FROM information_schema.innodb_metrics WHERE name = 'adaptive_hash_searches', count, 1); +let $k = $query_rounds; +--disable_query_log +--disable_result_log +while ($k) { + SELECT COUNT(*) FROM t1 FORCE INDEX(idx_1) WHERE col1 = 50; + dec $k; +} +--enable_result_log +--enable_query_log +let $val1 = query_get_value(SELECT count FROM information_schema.innodb_metrics WHERE name = 'adaptive_hash_searches', count, 1); +if ($val1 > $val0) { + --echo # Used AHI in SELECT (idx_1) +} +if ($val1 <= $val0) { + --echo # No AHI used in SELECT (idx_1) +} +let $val0 = $val1; + +let $k = $query_rounds; +--disable_query_log +--disable_result_log +while ($k) { + SELECT COUNT(*) FROM t1 FORCE INDEX(idx_2) WHERE col1 = 50 AND col2 BETWEEN 0 AND 9; + dec $k; +} +--enable_result_log +--enable_query_log +let $val1 = query_get_value(SELECT count FROM information_schema.innodb_metrics WHERE name = 'adaptive_hash_searches', count, 1); +if ($val1 > $val0) { + --echo # Used AHI in SELECT (idx_2) +} +if ($val1 <= $val0) { + --echo # No AHI used in SELECT (idx_2) +} +let $val0 = $val1; + +let $k = $query_rounds; +--disable_query_log +--disable_result_log +while ($k) { + SELECT COUNT(*) FROM t1 FORCE INDEX(idx_3) WHERE col1 = 50 AND col2 BETWEEN 0 AND 9 AND col3 BETWEEN 0 AND 9; + dec $k; +} +--enable_result_log +--enable_query_log +let $val1 = query_get_value(SELECT count FROM information_schema.innodb_metrics WHERE name = 'adaptive_hash_searches', count, 1); +if ($val1 > $val0) { + --echo # Used AHI in SELECT (idx_3) +} +if ($val1 <= $val0) { + --echo # No AHI used in SELECT (idx_3) +} +let $val0 = $val1; + +DROP TABLE t1; +SET @@global.innodb_adaptive_hash_index = @start_global_value; +SET GLOBAL innodb_monitor_disable = module_adaptive_hash; +--disable_warnings +SET GLOBAL innodb_monitor_disable = default; +SET GLOBAL innodb_monitor_enable = default; +--enable_warnings diff --git a/mysql-test/suite/sys_vars/r/innodb_adaptive_hash_index_basic.result b/mysql-test/suite/sys_vars/r/innodb_adaptive_hash_index_basic.result index 1471ae3624493..77701e9c8f44b 100644 --- a/mysql-test/suite/sys_vars/r/innodb_adaptive_hash_index_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_adaptive_hash_index_basic.result @@ -1,7 +1,7 @@ SET @start_global_value = @@global.innodb_adaptive_hash_index; -Valid values are 'ON' and 'OFF' -select @@global.innodb_adaptive_hash_index in (0, 1); -@@global.innodb_adaptive_hash_index in (0, 1) +Valid values are 'ON', 'OFF' and 'IF_SPECIFIED' +select @@global.innodb_adaptive_hash_index in ("ON", "OFF", "IF_SPECIFIED"); +@@global.innodb_adaptive_hash_index in ("ON", "OFF", "IF_SPECIFIED") 1 select @@session.innodb_adaptive_hash_index; ERROR HY000: Variable 'innodb_adaptive_hash_index' is a GLOBAL variable @@ -20,7 +20,7 @@ INNODB_ADAPTIVE_HASH_INDEX set global innodb_adaptive_hash_index='OFF'; select @@global.innodb_adaptive_hash_index; @@global.innodb_adaptive_hash_index -0 +OFF select * from information_schema.global_variables where variable_name='innodb_adaptive_hash_index'; VARIABLE_NAME VARIABLE_VALUE INNODB_ADAPTIVE_HASH_INDEX OFF @@ -30,7 +30,7 @@ INNODB_ADAPTIVE_HASH_INDEX OFF set @@global.innodb_adaptive_hash_index=1; select @@global.innodb_adaptive_hash_index; @@global.innodb_adaptive_hash_index -1 +ON select * from information_schema.global_variables where variable_name='innodb_adaptive_hash_index'; VARIABLE_NAME VARIABLE_VALUE INNODB_ADAPTIVE_HASH_INDEX ON @@ -40,17 +40,27 @@ INNODB_ADAPTIVE_HASH_INDEX ON set global innodb_adaptive_hash_index=0; select @@global.innodb_adaptive_hash_index; @@global.innodb_adaptive_hash_index -0 +OFF select * from information_schema.global_variables where variable_name='innodb_adaptive_hash_index'; VARIABLE_NAME VARIABLE_VALUE INNODB_ADAPTIVE_HASH_INDEX OFF select * from information_schema.session_variables where variable_name='innodb_adaptive_hash_index'; VARIABLE_NAME VARIABLE_VALUE INNODB_ADAPTIVE_HASH_INDEX OFF +set @@global.innodb_adaptive_hash_index='IF_SPECIFIED'; +select @@global.innodb_adaptive_hash_index; +@@global.innodb_adaptive_hash_index +IF_SPECIFIED +select * from information_schema.global_variables where variable_name='innodb_adaptive_hash_index'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_ADAPTIVE_HASH_INDEX IF_SPECIFIED +select * from information_schema.session_variables where variable_name='innodb_adaptive_hash_index'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_ADAPTIVE_HASH_INDEX IF_SPECIFIED set @@global.innodb_adaptive_hash_index='ON'; select @@global.innodb_adaptive_hash_index; @@global.innodb_adaptive_hash_index -1 +ON select * from information_schema.global_variables where variable_name='innodb_adaptive_hash_index'; VARIABLE_NAME VARIABLE_VALUE INNODB_ADAPTIVE_HASH_INDEX ON @@ -65,13 +75,11 @@ set global innodb_adaptive_hash_index=1.1; ERROR 42000: Incorrect argument type to variable 'innodb_adaptive_hash_index' set global innodb_adaptive_hash_index=1e1; ERROR 42000: Incorrect argument type to variable 'innodb_adaptive_hash_index' -set global innodb_adaptive_hash_index=2; -ERROR 42000: Variable 'innodb_adaptive_hash_index' can't be set to the value of '2' set global innodb_adaptive_hash_index=-3; ERROR 42000: Variable 'innodb_adaptive_hash_index' can't be set to the value of '-3' select @@global.innodb_adaptive_hash_index; @@global.innodb_adaptive_hash_index -1 +ON select * from information_schema.global_variables where variable_name='innodb_adaptive_hash_index'; VARIABLE_NAME VARIABLE_VALUE INNODB_ADAPTIVE_HASH_INDEX ON @@ -80,4 +88,169 @@ VARIABLE_NAME VARIABLE_VALUE INNODB_ADAPTIVE_HASH_INDEX ON set global innodb_adaptive_hash_index='AUTO'; ERROR 42000: Variable 'innodb_adaptive_hash_index' can't be set to the value of 'AUTO' +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b)) engine=innodb adaptive_hash_index=yes; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(100) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `b` (`b`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci `adaptive_hash_index`=yes +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b)) engine=innodb adaptive_hash_index=no; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(100) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `b` (`b`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci `adaptive_hash_index`=no +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b)) engine=innodb adaptive_hash_index='off'; +ALTER TABLE t1 adaptive_hash_index=default; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(100) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `b` (`b`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b)) engine=innodb adaptive_hash_index=default; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(100) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `b` (`b`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index=yes) engine=innodb; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(100) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `b` (`b`) `adaptive_hash_index`=yes +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index=no) engine=innodb, adaptive_hash_index=yes; +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index='off') engine=innodb, adaptive_hash_index='on'; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(100) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `b` (`b`) `adaptive_hash_index`='off' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci `adaptive_hash_index`='on' +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index=0) engine=innodb, adaptive_hash_index=1; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(100) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `b` (`b`) `adaptive_hash_index`=0 +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci `adaptive_hash_index`=1 +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index=yes) engine=innodb, adaptive_hash_index=no; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(100) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `b` (`b`) `adaptive_hash_index`=yes +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci `adaptive_hash_index`=no +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index=yes) engine=innodb, adaptive_hash_index=yes; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(100) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `b` (`b`) `adaptive_hash_index`=yes +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci `adaptive_hash_index`=yes +alter table t1 add column c int, add index (c); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(100) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `b` (`b`) `adaptive_hash_index`=yes, + KEY `c` (`c`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci `adaptive_hash_index`=yes +alter table t1 drop index b, add index b (b); +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index=default) engine=innodb, adaptive_hash_index=default; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(100) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `b` (`b`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index='on') engine=innodb, adaptive_hash_index='off'; +drop table t1; +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), c int, index (c,b) adaptive_hash_index=yes complete_fields=1 bytes_from_incomplete_fields=1 for_equal_hash_point_to_last_record=no) engine=innodb; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(100) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `c` (`c`,`b`) `adaptive_hash_index`=yes `complete_fields`=1 `bytes_from_incomplete_fields`=1 `for_equal_hash_point_to_last_record`=no +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci +alter table t1 drop index c, add index (c,b) complete_fields=2 bytes_from_incomplete_fields=default for_equal_hash_point_to_last_record=default; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(100) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `c` (`c`,`b`) `complete_fields`=2 +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci +alter table t1 drop index c, add index (c,b) complete_fields=0 bytes_from_incomplete_fields=0 for_equal_hash_point_to_last_record=yes; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(100) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `c` (`c`,`b`) `complete_fields`=0 `bytes_from_incomplete_fields`=0 `for_equal_hash_point_to_last_record`=yes +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci +drop table t1; +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index(b)) engine=innodb, adaptive_hash_index='on' ENGINE=innodb PARTITION BY KEY (a) PARTITIONS 2; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(100) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `b` (`b`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci `adaptive_hash_index`='on' + PARTITION BY KEY (`a`) +PARTITIONS 2 +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index(b) adaptive_hash_index=yes) engine=innodb adaptive_hash_index='off' ENGINE=innodb PARTITION BY KEY (a) PARTITIONS 2; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(100) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `b` (`b`) `adaptive_hash_index`=yes +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci `adaptive_hash_index`='off' + PARTITION BY KEY (`a`) +PARTITIONS 2 +drop table t1; +# +# Error handling +# +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index=on) engine=innodb, adaptive_hash_index=off; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'on) engine=innodb, adaptive_hash_index=off' at line 1 SET @@global.innodb_adaptive_hash_index = @start_global_value; diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result index b9f1e8b68f60c..06ac058eb57a5 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result @@ -36,12 +36,12 @@ VARIABLE_NAME INNODB_ADAPTIVE_HASH_INDEX SESSION_VALUE NULL DEFAULT_VALUE OFF VARIABLE_SCOPE GLOBAL -VARIABLE_TYPE BOOLEAN -VARIABLE_COMMENT Enable InnoDB adaptive hash index (disabled by default) +VARIABLE_TYPE ENUM +VARIABLE_COMMENT Enable InnoDB adaptive hash index. Values OFF (default), ON or IF_SPECIFIED (enabled only tables or indexes that have adaptive_hash_index=on) NUMERIC_MIN_VALUE NULL NUMERIC_MAX_VALUE NULL NUMERIC_BLOCK_SIZE NULL -ENUM_VALUE_LIST OFF,ON +ENUM_VALUE_LIST OFF,ON,IF_SPECIFIED READ_ONLY NO COMMAND_LINE_ARGUMENT OPTIONAL VARIABLE_NAME INNODB_ADAPTIVE_HASH_INDEX_CELLS diff --git a/mysql-test/suite/sys_vars/t/innodb_adaptive_hash_index_basic.test b/mysql-test/suite/sys_vars/t/innodb_adaptive_hash_index_basic.test index 88e239574d2c0..2ac6c88a299b2 100644 --- a/mysql-test/suite/sys_vars/t/innodb_adaptive_hash_index_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_adaptive_hash_index_basic.test @@ -1,17 +1,13 @@ - - -# 2010-01-25 - Added -# - --source include/have_innodb.inc +--source include/have_partition.inc SET @start_global_value = @@global.innodb_adaptive_hash_index; # # exists as global only # ---echo Valid values are 'ON' and 'OFF' -select @@global.innodb_adaptive_hash_index in (0, 1); +--echo Valid values are 'ON', 'OFF' and 'IF_SPECIFIED' +select @@global.innodb_adaptive_hash_index in ("ON", "OFF", "IF_SPECIFIED"); --error ER_INCORRECT_GLOBAL_LOCAL_VAR select @@session.innodb_adaptive_hash_index; --replace_column 2 # @@ -36,6 +32,10 @@ set global innodb_adaptive_hash_index=0; select @@global.innodb_adaptive_hash_index; select * from information_schema.global_variables where variable_name='innodb_adaptive_hash_index'; select * from information_schema.session_variables where variable_name='innodb_adaptive_hash_index'; +set @@global.innodb_adaptive_hash_index='IF_SPECIFIED'; +select @@global.innodb_adaptive_hash_index; +select * from information_schema.global_variables where variable_name='innodb_adaptive_hash_index'; +select * from information_schema.session_variables where variable_name='innodb_adaptive_hash_index'; set @@global.innodb_adaptive_hash_index='ON'; select @@global.innodb_adaptive_hash_index; select * from information_schema.global_variables where variable_name='innodb_adaptive_hash_index'; @@ -53,8 +53,6 @@ set global innodb_adaptive_hash_index=1.1; --error ER_WRONG_TYPE_FOR_VAR set global innodb_adaptive_hash_index=1e1; --error ER_WRONG_VALUE_FOR_VAR -set global innodb_adaptive_hash_index=2; ---error ER_WRONG_VALUE_FOR_VAR set global innodb_adaptive_hash_index=-3; select @@global.innodb_adaptive_hash_index; select * from information_schema.global_variables where variable_name='innodb_adaptive_hash_index'; @@ -62,6 +60,73 @@ select * from information_schema.session_variables where variable_name='innodb_a --error ER_WRONG_VALUE_FOR_VAR set global innodb_adaptive_hash_index='AUTO'; +# +# Test table level adaptive_hash_index options +# + +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b)) engine=innodb adaptive_hash_index=yes; +show create table t1; +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b)) engine=innodb adaptive_hash_index=no; +show create table t1; +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b)) engine=innodb adaptive_hash_index='off'; +ALTER TABLE t1 adaptive_hash_index=default; +show create table t1; +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b)) engine=innodb adaptive_hash_index=default; +show create table t1; + +# +# Test index level adaptive_hash_index options +# + +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index=yes) engine=innodb; +show create table t1; +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index=no) engine=innodb, adaptive_hash_index=yes; +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index='off') engine=innodb, adaptive_hash_index='on'; +show create table t1; +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index=0) engine=innodb, adaptive_hash_index=1; +show create table t1; +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index=yes) engine=innodb, adaptive_hash_index=no; +show create table t1; +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index=yes) engine=innodb, adaptive_hash_index=yes; +show create table t1; +alter table t1 add column c int, add index (c); +show create table t1; +alter table t1 drop index b, add index b (b); +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index=default) engine=innodb, adaptive_hash_index=default; +show create table t1; +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index='on') engine=innodb, adaptive_hash_index='off'; + +drop table t1; + +# +# Test extra index options +# + +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), c int, index (c,b) adaptive_hash_index=yes complete_fields=1 bytes_from_incomplete_fields=1 for_equal_hash_point_to_last_record=no) engine=innodb; +show create table t1; +alter table t1 drop index c, add index (c,b) complete_fields=2 bytes_from_incomplete_fields=default for_equal_hash_point_to_last_record=default; +show create table t1; +alter table t1 drop index c, add index (c,b) complete_fields=0 bytes_from_incomplete_fields=0 for_equal_hash_point_to_last_record=yes; +show create table t1; +drop table t1; + +# +# Test partitioned tables +# + +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index(b)) engine=innodb, adaptive_hash_index='on' ENGINE=innodb PARTITION BY KEY (a) PARTITIONS 2; +show create table t1; +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index(b) adaptive_hash_index=yes) engine=innodb adaptive_hash_index='off' ENGINE=innodb PARTITION BY KEY (a) PARTITIONS 2; +show create table t1; +drop table t1; + +--echo # +--echo # Error handling +--echo # + +--error 1064 +CREATE OR REPLACE TABLE t1 (a int primary key, b varchar(100), index (b) adaptive_hash_index=on) engine=innodb, adaptive_hash_index=off; + # # Cleanup # diff --git a/sql/create_options.cc b/sql/create_options.cc index 91211fbdda348..2cea91171ce56 100644 --- a/sql/create_options.cc +++ b/sql/create_options.cc @@ -27,7 +27,7 @@ #define FRM_QUOTED_VALUE 0x8000U -static const char *bools="NO,OFF,0,YES,ON,1"; +static const char *bools="NO,OFF,FALSE,0,YES,ON,TRUE,1"; /** Links this item to the given list end @@ -182,6 +182,34 @@ static bool set_one_value(ha_create_table_option *opt, THD *thd, DBUG_RETURN(0); } + /* check boolean aliases. */ + uint bool_val= value->find_in_list(bools); + if (bool_val != UINT_MAX) + { + bool_val= bool_val > 3; + + static const LEX_CSTRING vals[2]= { + { STRING_WITH_LEN("NO") }, + { STRING_WITH_LEN("YES") }, + }; + const LEX_CSTRING &str_val= vals[bool_val]; + const char *str= opt->values; + size_t len= 0; + for (int num= 0; str[len]; num++) + { + for (len= 0; str[len] && str[len] != ','; len++) /* no-op */; + if (str_val.length == len && !strncasecmp(str_val.str, str, len)) + { + *val= num; + DBUG_RETURN(0); + } + str+= len; + if (*str == ',') + ++str; + len= 0; + } + } + DBUG_RETURN(report_wrong_value(thd, opt->name, value->str, suppress_warning)); } @@ -196,7 +224,7 @@ static bool set_one_value(ha_create_table_option *opt, THD *thd, uint num= value->find_in_list(bools); if (num != UINT_MAX) { - *val= num > 2; + *val= num > 3; DBUG_RETURN(0); } @@ -492,8 +520,8 @@ bool parse_engine_table_options(THD *thd, handlerton *ht, TABLE_SHARE *share) */ bool parse_engine_part_options(THD *thd, TABLE *table) { - MEM_ROOT *root= &table->mem_root; TABLE_SHARE *share= table->s; + MEM_ROOT *root= &share->mem_root; partition_info *part_info= table->part_info; engine_option_value *tmp_option_list; handlerton *ht; diff --git a/sql/create_options.h b/sql/create_options.h index 732225c243e0c..21b661abe2c38 100644 --- a/sql/create_options.h +++ b/sql/create_options.h @@ -54,7 +54,9 @@ class engine_option_value: public Sql_alloc for (end=str; *end && *end != ','; end++) /* no-op */; if (streq(Lex_cstring(str, end))) return num; - str= end + 1; + str= end; + if (*str == ',') + ++str; } return UINT_MAX; } diff --git a/sql/handler.cc b/sql/handler.cc index 8da1c18feb421..7aa815ab9d489 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -68,6 +68,9 @@ #include "wsrep_var.h" /* wsrep_hton_check() */ #endif /* WITH_WSREP */ +/* DEFAULT (0), YES (1), NO (2) */ +const char *table_hint_options= "DEFAULT,YES,NO"; + /** @def MYSQL_TABLE_LOCK_WAIT Instrumentation helper for table io_waits. diff --git a/sql/handler.h b/sql/handler.h index 9d16645092244..279ef8305a28d 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -5867,4 +5867,20 @@ int get_select_field_pos(Alter_info *alter_info, bool versioned); #ifndef DBUG_OFF String dbug_format_row(TABLE *table, const uchar *rec, bool print_names= true); #endif /* DBUG_OFF */ + +/* + This is used when creating table options that affects optimizations and + features, like QUERY_CACHE=OFF. + The user can use YES and NO as synonyms for ON/OFF (needed as some options + are already using ON/OFF and others using YES/NO and we don't want to confuse + the user. + DEFAULT is automatically handled by sys_vars. +*/ + +enum table_hint_options +{ + TABLE_HINT_DEFAULT, TABLE_HINT_YES, TABLE_HINT_NO +}; + +extern const char *table_hint_options; #endif /* HANDLER_INCLUDED */ diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 09d8ed284b05f..d170705ad5d4a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3397,10 +3397,10 @@ mysql_prepare_create_table_finalize(THD *thd, HA_CREATE_INFO *create_info, auto_increment++; extend_option_list(thd, create_info->db_type, !sql_field->field, &sql_field->option_list, - create_info->db_type->field_options); + file->partition_ht()->field_options); if (parse_option_list(thd, &sql_field->option_struct, &sql_field->option_list, - create_info->db_type->field_options, FALSE, + file->partition_ht()->field_options, FALSE, thd->mem_root)) DBUG_RETURN(TRUE); /* @@ -3621,7 +3621,7 @@ mysql_prepare_create_table_finalize(THD *thd, HA_CREATE_INFO *create_info, Create_field *auto_increment_key= 0; Key_part_spec *column; st_plugin_int *index_plugin= hton2plugin[create_info->db_type->slot]; - ha_create_table_option *index_options= create_info->db_type->index_options; + ha_create_table_option *index_options= file->partition_ht()->index_options; if (key->type == Key::IGNORE_KEY) { diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index b57f5ec5d2e69..83ccbd1bc2fd3 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -1137,7 +1137,7 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode, ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_G); /* We do a dirty read of btr_search.enabled below, and btr_search_guess_on_hash() will have to check it again. */ - else if (!btr_search.enabled); + else if (!btr_search.is_enabled(index())) ; else if (btr_search_guess_on_hash(index(), tuple, mode != PAGE_CUR_LE, latch_mode, this, mtr)) { @@ -1661,7 +1661,7 @@ dberr_t btr_cur_t::pessimistic_search_leaf(const dtuple_t *tuple, /* We do a dirty read of btr_search.enabled here. We will recheck in btr_search_build_page_hash_index() before building a page hash index, while holding search latch. */ - if (!btr_search.enabled); + if (!btr_search.is_enabled(index())) ; else if (tuple->info_bits & REC_INFO_MIN_REC_FLAG) /* This may be a search tuple for btr_pcur_t::restore_position(). */ ut_ad(tuple->is_metadata() || diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc index 05e3d67ae2c7f..c0c58037f370d 100644 --- a/storage/innobase/btr/btr0sea.cc +++ b/storage/innobase/btr/btr0sea.cc @@ -343,7 +343,7 @@ ATTRIBUTE_COLD ATTRIBUTE_NOINLINE void btr_sea::partition::rollback_insert() noexcept { ut_ad(latch.have_any()); - ut_ad(!btr_search.enabled); + ut_ad(!btr_search.get_enabled()); if (buf_block_t *block= spare.exchange(nullptr)) { MEM_MAKE_ADDRESSABLE(block->page.frame, srv_page_size); @@ -386,18 +386,18 @@ ATTRIBUTE_COLD void btr_search_lazy_free(dict_index_t *index) noexcept } } -ATTRIBUTE_COLD bool btr_sea::disable_and_lock() noexcept +ATTRIBUTE_COLD ulong btr_sea::disable_and_lock() noexcept { dict_sys.freeze(SRW_LOCK_CALL); for (ulong i= 0; i < n_parts; i++) parts[i].latch.wr_lock(SRW_LOCK_CALL); - const bool was_enabled{enabled}; + const ulong was_enabled{enabled}; if (was_enabled) { - enabled= false; + enabled= 0; btr_search_disable(dict_sys.table_LRU); btr_search_disable(dict_sys.table_non_LRU); dict_sys.unfreeze(); @@ -418,16 +418,18 @@ ATTRIBUTE_COLD void btr_sea::unlock() noexcept parts[i].latch.wr_unlock(); } -ATTRIBUTE_COLD bool btr_sea::disable() noexcept +ATTRIBUTE_COLD ulong btr_sea::disable() noexcept { - const bool was_enabled{disable_and_lock()}; + const ulong was_enabled{disable_and_lock()}; unlock(); return was_enabled; } /** Enable the adaptive hash search system. -@param resize whether buf_pool_t::resize() is the caller */ -ATTRIBUTE_COLD void btr_sea::enable(bool resize) noexcept +@param resize whether buf_pool_t::resize() is the caller +@param resize Type of adaptive_hash_index. + 1 (enable for all tables) or 2 (if_specified */ +ATTRIBUTE_COLD void btr_sea::enable(bool resize, ulong enable_opt) noexcept { if (!resize) { @@ -442,16 +444,21 @@ ATTRIBUTE_COLD void btr_sea::enable(bool resize) noexcept parts[i].latch.wr_lock(SRW_LOCK_CALL); if (!parts[0].table.array) - enabled= alloc(n_cells); + { + if (alloc(n_cells)) + enabled= enable_opt; + } else + { + enabled= enable_opt; ut_ad(enabled); - + } unlock(); } ATTRIBUTE_COLD void btr_sea::resize(uint n_cells) noexcept { - const bool was_enabled{disable_and_lock()}; + const ulong was_enabled{disable_and_lock()}; clear(); ut_ad(!parts[0].table.array); @@ -480,7 +487,7 @@ void btr_sea::partition::insert(uint32_t fold, const rec_t *rec) noexcept #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG ut_a(block->page.frame == page_align(rec)); #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - ut_ad(btr_search.enabled); + ut_ad(btr_search.get_enabled()); hash_chain &cell{table.cell_get(fold)}; page_hash_latch &hash_lock{table.lock_get(cell)}; @@ -593,7 +600,8 @@ static void btr_search_update_hash_ref(const btr_cur_t &cursor, if (ut_d(const dict_index_t *block_index=) block->index) { ut_ad(block_index == index); - ut_ad(btr_search.enabled); + ut_ad(btr_search.get_enabled()); + ut_ad(index->search_info.ahi_enabled); uint32_t bytes_fields{block->ahi_left_bytes_fields}; if (bytes_fields != left_bytes_fields) goto skip; @@ -632,7 +640,7 @@ static void btr_search_update_hash_ref(const btr_cur_t &cursor, # if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG ut_a(!block->n_pointers); # endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - if (!btr_search.enabled) + if (!btr_search.get_enabled()) { ut_ad(!index->any_ahi_pages()); part.rollback_insert(); @@ -678,9 +686,15 @@ static uint32_t btr_search_info_update_hash(const btr_cur_t &cursor) noexcept uint8_t n_hash_potential= info.n_hash_potential; uint32_t ret; + const uint32_t mask= info.ahi_fixed_left_bytes_fields_mask.load(); + const uint32_t fixed= info.ahi_fixed_left_bytes_fields.load(); + if (!n_hash_potential) { - info.left_bytes_fields= left_bytes_fields= buf_block_t::LEFT_SIDE | 1; + left_bytes_fields= buf_block_t::LEFT_SIDE | 1; + /* Override with fixed values */ + left_bytes_fields= (left_bytes_fields & ~mask) | (fixed & mask); + info.left_bytes_fields= left_bytes_fields; info.hash_analysis_reset(); increment_potential: if (n_hash_potential < BTR_SEARCH_BUILD_LIMIT) @@ -740,6 +754,8 @@ static uint32_t btr_search_info_update_hash(const btr_cur_t &cursor) noexcept left_bytes_fields|= uint32_t(cursor.up_bytes + 1) << 16; } } + /* Override with fixed values */ + left_bytes_fields= (left_bytes_fields & ~mask) | (fixed & mask); /* We have to set a new recommendation; skip the hash analysis for a while to avoid unnecessary CPU time usage when there is no chance for success */ @@ -841,7 +857,7 @@ buf_block_t * btr_sea::partition::cleanup_after_erase(ahi_node *erase) noexcept { ut_ad(latch.have_wr()); - ut_ad(btr_search.enabled); + ut_ad(btr_search.get_enabled()); const ahi_node *const top= cleanup_after_erase_start(); @@ -864,7 +880,7 @@ btr_sea::partition::cleanup_after_erase(ahi_node *erase, page_hash_latch *l) { ut_ad(latch.have_rd()); ut_ad(l->is_write_locked()); - ut_ad(btr_search.enabled); + ut_ad(btr_search.get_enabled()); const ahi_node *const top= cleanup_after_erase_start(); @@ -922,7 +938,7 @@ btr_sea::partition::erase_status btr_sea::partition::erase(hash_chain &cell, const rec_t *rec) noexcept { ut_ad(ex ? latch.have_wr() : latch.have_rd()); - ut_ad(btr_search.enabled); + ut_ad(btr_search.get_enabled()); page_hash_latch *const hash_lock{ex ? nullptr : &table.lock_get(cell)}; buf_block_t *block= nullptr; @@ -1000,7 +1016,7 @@ static bool ha_search_and_update_if_found(btr_sea::hash_table *table, #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG ut_a(new_block->page.frame == page_align(new_data)); #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - ut_ad(btr_search.enabled); + ut_ad(btr_search.get_enabled()); btr_sea::hash_chain &cell{table->cell_get(fold)}; page_hash_latch &hash_lock{table->lock_get(cell)}; @@ -1115,7 +1131,7 @@ btr_search_guess_on_hash( !index->search_info.n_hash_potential) { ahi_unusable: - if (!index->table->is_temporary() && btr_search.enabled) + if (!index->table->is_temporary() && btr_search.get_enabled()) cursor->flag= BTR_CUR_HASH_ABORT; return false; } @@ -1142,7 +1158,7 @@ btr_search_guess_on_hash( page_hash_latch *hash_lock= nullptr; part.latch.rd_lock(SRW_LOCK_CALL); - if (!btr_search.enabled) + if (!btr_search.get_enabled()) { ut_ad(!index->any_ahi_pages()); ahi_release_and_fail: @@ -1312,7 +1328,7 @@ static void btr_search_drop_page_hash_index(buf_block_t *block, return; } - ut_ad(btr_search.enabled); + ut_ad(btr_search.get_enabled()); bool holding_x= index->freed(); @@ -1526,7 +1542,7 @@ static void btr_search_build_page_hash_index(dict_index_t *index, { ut_ad(!index->table->is_temporary()); - if (!btr_search.enabled) + if (!btr_search.is_enabled(index)) return; ut_ad(block->page.id().space() == index->table->space_id); @@ -1541,7 +1557,7 @@ static void btr_search_build_page_hash_index(dict_index_t *index, const bool rebuild= block_index && (block_index != index || block->ahi_left_bytes_fields != left_bytes_fields); - const bool enabled= btr_search.enabled; + const ulong enabled= btr_search.get_enabled(); ut_ad(enabled || !index->any_ahi_pages()); part.latch.rd_unlock(); @@ -1638,7 +1654,7 @@ static void btr_search_build_page_hash_index(dict_index_t *index, { ut_ad(!block->n_pointers); - if (!btr_search.enabled) + if (!btr_search.get_enabled()) { ut_ad(!index->any_ahi_pages()); part.rollback_insert(); @@ -1663,7 +1679,7 @@ static void btr_search_build_page_hash_index(dict_index_t *index, else { ut_ad(!block->n_pointers); - if (!btr_search.enabled) + if (!btr_search.get_enabled()) { ut_ad(!index->any_ahi_pages()); part.rollback_insert(); @@ -1730,10 +1746,12 @@ void btr_search_move_or_delete_hash_entries(buf_block_t *new_block, ut_ad(block->page.lock.have_x()); ut_ad(new_block->page.lock.have_x()); - if (!btr_search.enabled) + dict_index_t *index= block->index; + + if (!btr_search.may_be_enabled(index)) return; - dict_index_t *index= block->index, *new_block_index= new_block->index; + dict_index_t *new_block_index= new_block->index; assert_block_ahi_valid(block); assert_block_ahi_valid(new_block); @@ -1742,7 +1760,8 @@ void btr_search_move_or_delete_hash_entries(buf_block_t *new_block, { ut_ad(!index || index == new_block_index); drop_exit: - btr_search_drop_page_hash_index(block, nullptr); + if (btr_search.is_enabled(new_block_index)) + btr_search_drop_page_hash_index(block, nullptr); return; } @@ -1775,7 +1794,7 @@ void btr_search_move_or_delete_hash_entries(buf_block_t *new_block, void btr_search_update_hash_on_delete(btr_cur_t *cursor) noexcept { ut_ad(page_is_leaf(btr_cur_get_page(cursor))); - if (!btr_search.enabled) + if (!btr_search.get_enabled()) return; buf_block_t *block= btr_cur_get_block(cursor); @@ -1783,7 +1802,7 @@ void btr_search_update_hash_on_delete(btr_cur_t *cursor) noexcept assert_block_ahi_valid(block); dict_index_t *index= block->index; - if (!index) + if (!index || !btr_search.is_enabled(index)) return; ut_ad(!cursor->index()->table->is_temporary()); @@ -1807,7 +1826,7 @@ void btr_search_update_hash_on_delete(btr_cur_t *cursor) noexcept if (ut_d(dict_index_t *block_index=) block->index) { - ut_ad(btr_search.enabled); + ut_ad(btr_search.get_enabled()); ut_ad(block_index == index); btr_sea::partition::erase_status s= @@ -1840,7 +1859,7 @@ void btr_search_update_hash_on_delete(btr_cur_t *cursor) noexcept } else { - ut_ad(btr_search.enabled || !index->any_ahi_pages()); + ut_ad(btr_search.get_enabled() || !index->any_ahi_pages()); part.latch.rd_unlock(); } } @@ -1887,7 +1906,7 @@ void btr_search_update_hash_on_insert(btr_cur_t *cursor, bool reorg) noexcept part.latch.rd_lock(SRW_LOCK_CALL); if (!block->index) goto unlock_exit; - ut_ad(btr_search.enabled); + ut_ad(btr_search.get_enabled()); locked= true; if (page_is_comp(page)) { @@ -1956,7 +1975,7 @@ void btr_search_update_hash_on_insert(btr_cur_t *cursor, bool reorg) noexcept if (!block->index) { rollback: - if (!btr_search.enabled) + if (!btr_search.get_enabled()) { ut_ad(!index->any_ahi_pages()); part.rollback_insert(); @@ -2080,7 +2099,7 @@ static bool btr_search_hash_table_validate(THD *thd, ulint hash_table_id) ulint cell_count; btr_search_x_lock_all(); - if (!btr_search.enabled || (thd && thd_kill_level(thd))) { + if (!btr_search.get_enabled() || (thd && thd_kill_level(thd))) { func_exit: btr_search_x_unlock_all(); return ok; @@ -2112,7 +2131,7 @@ static bool btr_search_hash_table_validate(THD *thd, ulint hash_table_id) btr_search_x_lock_all(); - if (!btr_search.enabled + if (!btr_search.get_enabled() || (thd && thd_kill_level(thd))) { goto func_exit; } @@ -2202,7 +2221,7 @@ static bool btr_search_hash_table_validate(THD *thd, ulint hash_table_id) btr_search_x_lock_all(); - if (!btr_search.enabled + if (!btr_search.get_enabled() || (thd && thd_kill_level(thd))) { goto func_exit; } diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 3c46f6e8ce3df..5b506ad802c27 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -1071,7 +1071,7 @@ inline void buf_pool_t::garbage_collect() noexcept my_cond_wait(&done_flush_list, &flush_list_mutex.m_mutex); mysql_mutex_unlock(&flush_list_mutex); # ifdef BTR_CUR_HASH_ADAPT - bool ahi_disabled= btr_search.disable(); + ulong ahi_disabled= btr_search.disable(); # endif /* BTR_CUR_HASH_ADAPT */ time_t start= time(nullptr); mysql_mutex_lock(&mutex); @@ -1092,7 +1092,7 @@ inline void buf_pool_t::garbage_collect() noexcept shrunk(size, reduce_size); # ifdef BTR_CUR_HASH_ADAPT if (ahi_disabled) - btr_search.enable(true); + btr_search.enable(true, ahi_disabled); # endif mysql_mutex_unlock(&mutex); sql_print_information("InnoDB: Memory pressure event shrunk" @@ -1502,8 +1502,8 @@ bool buf_pool_t::create() noexcept buf_LRU_old_ratio_update(100 * 3 / 8, false); #ifdef BTR_CUR_HASH_ADAPT - if (btr_search.enabled) - btr_search.enable(); + if (btr_search.get_enabled()) + btr_search.enable(false, btr_search.get_enabled()); #endif #ifdef __linux__ @@ -1959,7 +1959,7 @@ ATTRIBUTE_COLD void buf_pool_t::resize(size_t size, THD *thd) noexcept } #ifdef BTR_CUR_HASH_ADAPT - bool ahi_disabled= false; + ulong ahi_disabled= 0; #endif const bool significant_change= @@ -2075,7 +2075,7 @@ ATTRIBUTE_COLD void buf_pool_t::resize(size_t size, THD *thd) noexcept #ifdef BTR_CUR_HASH_ADAPT if (ahi_disabled) - btr_search.enable(true); + btr_search.enable(true, ahi_disabled); #endif if (n_blocks_removed) sql_print_information("InnoDB: innodb_buffer_pool_size=%zum (%zu pages)" @@ -2161,7 +2161,7 @@ ATTRIBUTE_COLD void buf_pool_t::resize(size_t size, THD *thd) noexcept MYF(ME_ERROR_LOG)); #ifdef BTR_CUR_HASH_ADAPT if (ahi_disabled) - btr_search.enable(true); + btr_search.enable(true, ahi_disabled); #endif mysql_mutex_lock(&LOCK_global_system_variables); } @@ -3696,7 +3696,7 @@ ATTRIBUTE_COLD void buf_pool_t::clear_hash_index() noexcept std::set garbage; mysql_mutex_lock(&mutex); - ut_ad(!btr_search.enabled); + ut_ad(!btr_search.get_enabled()); for (char *extent= memory, *end= memory + block_descriptors_in_bytes(n_blocks); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index eacde4912b89e..759615cb1c55a 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -666,10 +666,26 @@ ha_create_table_option innodb_table_option_list[]= HA_TOPTION_ENUM("ENCRYPTED", encryption, "DEFAULT,YES,NO", 0), /* With this option the user defines the key identifier using for the encryption */ HA_TOPTION_SYSVAR("ENCRYPTION_KEY_ID", encryption_key_id, default_encryption_key_id), - + HA_TOPTION_ENUM("ADAPTIVE_HASH_INDEX", adaptive_hash_index, + table_hint_options, TABLE_HINT_DEFAULT), HA_TOPTION_END }; + +ha_create_table_option innodb_index_option_list[]= +{ + HA_IOPTION_ENUM("ADAPTIVE_HASH_INDEX", adaptive_hash_index, + table_hint_options, TABLE_HINT_DEFAULT), + HA_IOPTION_NUMBER("COMPLETE_FIELDS", complete_fields, ULONGLONG_MAX, 0, 32, + 1), + HA_IOPTION_NUMBER("BYTES_FROM_INCOMPLETE_FIELDS", + bytes_from_incomplete_fields, ULONGLONG_MAX, 0, 8192, 1), + HA_IOPTION_ENUM("FOR_EQUAL_HASH_POINT_TO_LAST_RECORD", + for_equal_hash_point_to_last_record, table_hint_options, + TABLE_HINT_DEFAULT), + HA_IOPTION_END +}; + /*************************************************************//** Check whether valid argument given to innodb_ft_*_stopword_table. This function is registered as a callback with MySQL. @@ -2935,6 +2951,75 @@ static bool innodb_copy_stat_flags(dict_table_t *table, return true; } +#ifdef BTR_CUR_HASH_ADAPT +/** Enable the adaptive hash index for indexes where needed. +@param innodb_table InnoDB table definition +@param option_struct MariaDB table options +@param table MariaDB table handle */ +static void innodb_ahi_enable(dict_table_t *innodb_table, + const ha_table_option_struct *option_struct, + const TABLE *table) +{ + /* + ahi_enabled maps: + TABLE_HINT_NO (2) -> 0 (force disabled) + TABLE_HINT_DEFAULT (0) -> 1 (default, use global setting) + TABLE_HINT_YES (1) -> 2 (prefer enabled, if not globally disabled) + + Index preference, if set, will override table preference. + */ + const uint8_t table_ahi= option_struct + ? uint8_t((option_struct->adaptive_hash_index + 1) % 3) + : uint8_t{1}; + + /* In case there is no PRIMARY KEY or UNIQUE INDEX on NOT NULL + columns, there will be GEN_CLUST_INDEX(DB_ROW_ID). Default to the + table option for it. If a PRIMARY KEY is defined, this default + value may be updated in the loop below. */ + UT_LIST_GET_FIRST(innodb_table->indexes)->search_info.ahi_enabled= + table_ahi; + for (auto i= table->s->keys; i--; ) + { + const KEY &key= table->key_info[i]; + dict_index_t *index= + dict_table_get_index_on_name(innodb_table, key.name.str); + if (!index) + continue; + const uint8_t index_ahi= + uint8_t((key.option_struct->adaptive_hash_index + 1) % 3); + /* Use index preference if set, otherwise use table preference */ + const uint8_t ahi= index_ahi != 1 ? index_ahi: table_ahi; + index->search_info.ahi_enabled= ahi; + if (ahi == 0) + { + index->search_info.ahi_fixed_left_bytes_fields_mask= 0; + index->search_info.ahi_fixed_left_bytes_fields= 0; + continue; + } + const uint64_t fields= key.option_struct->complete_fields; + const uint64_t bytes= key.option_struct->bytes_from_incomplete_fields; + const uint32_t left= + key.option_struct->for_equal_hash_point_to_last_record; + ut_ad(fields == ULONGLONG_MAX || fields < 0xFFFF); + ut_ad(bytes == ULONGLONG_MAX || bytes < 0x8000); + ut_ad(left >= TABLE_HINT_DEFAULT && left <= TABLE_HINT_NO); + const bool is_fields_set= fields != ULONGLONG_MAX; + const bool is_bytes_set= bytes != ULONGLONG_MAX; + const bool is_left_set= left != TABLE_HINT_DEFAULT; + const uint32_t mask= + (is_fields_set ? 0x0000FFFF : 0) | + (is_bytes_set ? 0x7FFF0000 : 0) | + (is_left_set ? 0x80000000 : 0); + const uint32_t fixed= + (is_fields_set ? static_cast(fields) : 0) | + (is_bytes_set ? (static_cast(bytes) << 16) : 0) | + (left == TABLE_HINT_YES ? 0x80000000 : 0); + index->search_info.ahi_fixed_left_bytes_fields_mask= mask; + index->search_info.ahi_fixed_left_bytes_fields= fixed; + } +} +#endif + /*********************************************************************//** Copy table flags from MySQL's HA_CREATE_INFO into an InnoDB table object. Those flags are stored in .frm file and end up in the MySQL table object, @@ -2945,28 +3030,39 @@ void innobase_copy_frm_flags_from_create_info( /*=====================================*/ dict_table_t* innodb_table, /*!< in/out: InnoDB table */ - const HA_CREATE_INFO* create_info) /*!< in: create info */ + const HA_CREATE_INFO* create_info, /*!< in: create info */ + const TABLE* table) /*!< in: MariaDB table */ { if (innodb_copy_stat_flags(innodb_table, create_info->table_options, create_info->stats_auto_recalc, false)) + { innodb_table->stats_sample_pages= create_info->stats_sample_pages; +#ifdef BTR_CUR_HASH_ADAPT + innodb_ahi_enable(innodb_table, create_info->option_struct, table); +#endif + } } -/*********************************************************************//** -Copy table flags from MySQL's TABLE_SHARE into an InnoDB table object. +/** +Copy table flags from MariaDB TABLE into an InnoDB table object. Those flags are stored in .frm file and end up in the MySQL table object, but are frequently used inside InnoDB so we keep their copies into the -InnoDB table object. */ -void -innobase_copy_frm_flags_from_table_share( -/*=====================================*/ - dict_table_t* innodb_table, /*!< in/out: InnoDB table */ - const TABLE_SHARE* table_share) /*!< in: table share */ +InnoDB table object. +@param innodb_table InnoDB table +@param table MariaDB table handle */ +void innobase_copy_frm_flags_from_table(dict_table_t *innodb_table, + const TABLE *table) noexcept { + const TABLE_SHARE *const table_share{table->s}; if (innodb_copy_stat_flags(innodb_table, table_share->db_create_options, table_share->stats_auto_recalc, innodb_table->stat_initialized())) + { innodb_table->stats_sample_pages= table_share->stats_sample_pages; +#ifdef BTR_CUR_HASH_ADAPT + innodb_ahi_enable(innodb_table, table_share->option_struct, table); +#endif + } } /*********************************************************************//** @@ -3668,10 +3764,13 @@ static MYSQL_SYSVAR_UINT(log_write_ahead_size, log_sys.write_size, static void innodb_adaptive_hash_index_update(THD*, st_mysql_sys_var*, void*, const void *save) noexcept { + ulong option; /* Prevent a possible deadlock with innobase_fts_load_stopword() */ mysql_mutex_unlock(&LOCK_global_system_variables); - if (*static_cast(save)) - btr_search.enable(); + + option= *static_cast(save); + if (option) + btr_search.enable(false, option); else btr_search.disable(); mysql_mutex_lock(&LOCK_global_system_variables); @@ -4152,6 +4251,7 @@ static int innodb_init(void* p) innobase_hton->tablefile_extensions = ha_innobase_exts; innobase_hton->table_options = innodb_table_option_list; + innobase_hton->index_options = innodb_index_option_list; /* System Versioning */ innobase_hton->prepare_commit_versioned @@ -5851,7 +5951,7 @@ ha_innobase::open(const char* name, int, uint) DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); } - innobase_copy_frm_flags_from_table_share(ib_table, table->s); + innobase_copy_frm_flags_from_table(ib_table, table); MONITOR_INC(MONITOR_TABLE_OPEN); @@ -6029,7 +6129,7 @@ ha_innobase::open(const char* name, int, uint) /* Set plugin parser for fulltext index */ for (uint i = 0; i < table->s->keys; i++) { if (table->key_info[i].flags & HA_USES_PARSER) { - dict_index_t* index = innobase_get_index(i); + dict_index_t *index = innobase_get_index(i); plugin_ref parser = table->key_info[i].parser; ut_ad(index->type & DICT_FTS); @@ -11396,7 +11496,6 @@ create_table_info_t::check_table_options() return "PAGE_COMPRESSION_LEVEL"; } } - return NULL; } @@ -13172,7 +13271,7 @@ void create_table_info_t::create_table_update_dict(dict_table_t *table, DBUG_ASSERT(!table->fts == !table->fts_doc_id_index); - innobase_copy_frm_flags_from_create_info(table, &info); + innobase_copy_frm_flags_from_create_info(table, &info, &t); /* Load server stopword into FTS cache */ if (table->flags2 & DICT_TF2_FTS && @@ -17421,7 +17520,7 @@ ha_innobase::check_if_incompatible_data( m_prebuilt->table->stats_mutex_lock(); if (!m_prebuilt->table->stat_initialized()) { innobase_copy_frm_flags_from_create_info( - m_prebuilt->table, info); + m_prebuilt->table, info, table); } m_prebuilt->table->stats_mutex_unlock(); @@ -19315,10 +19414,26 @@ static MYSQL_SYSVAR_BOOL(stats_traditional, srv_stats_sample_traditional, NULL, NULL, TRUE); #ifdef BTR_CUR_HASH_ADAPT -static MYSQL_SYSVAR_BOOL(adaptive_hash_index, *(my_bool*) &btr_search.enabled, +/** Possible values for the variable adaptive_hash_index */ +const char* innodb_ahi_names[] = { + "OFF", + "ON", + "IF_SPECIFIED", + NullS +}; + +/** Used to define an enumerate type of the system variable +innodb_checksum_algorithm. */ +TYPELIB innodb_ahi_typelib = + CREATE_TYPELIB_FOR(innodb_ahi_names); + +static MYSQL_SYSVAR_ENUM(adaptive_hash_index, *(ulong*) &btr_search.enabled, PLUGIN_VAR_OPCMDARG, - "Enable InnoDB adaptive hash index (disabled by default)", - NULL, innodb_adaptive_hash_index_update, false); + "Enable InnoDB adaptive hash index. Values OFF (default), ON or " + "IF_SPECIFIED (enabled only tables or indexes that " + "have adaptive_hash_index=on)", + NULL, innodb_adaptive_hash_index_update, false, + &innodb_ahi_typelib); static MYSQL_SYSVAR_ULONG(adaptive_hash_index_parts, btr_search.n_parts, PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY, diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index b6fb571078bea..81229ee4247c8 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -44,10 +44,21 @@ struct ha_table_option_struct innodb_use_atomic_writes. Atomic writes are not used if value OFF.*/ - uint encryption; /*!< DEFAULT, ON, OFF */ + uint adaptive_hash_index; /*!< DEFAULT, ON, OFF */ + uint encryption; /*!< DEFAULT, ON, OFF */ ulonglong encryption_key_id; /*!< encryption key id */ }; +struct ha_index_option_struct +{ + uint adaptive_hash_index; /*!< DEFAULT, ON, OFF */ + ulonglong complete_fields; + ulonglong bytes_from_incomplete_fields; + /** DEFAULT (0), YES (1), NO (2) + DEFAULT means no fixed recommendation for this AHI parameter. */ + uint for_equal_hash_point_to_last_record; +}; + /** The class defining a handle to an Innodb table */ class ha_innobase final : public handler { @@ -797,14 +808,14 @@ innobase_fts_check_doc_id_index_in_def( MY_ATTRIBUTE((warn_unused_result)); /** -Copy table flags from MySQL's TABLE_SHARE into an InnoDB table object. +Copy table flags from MariaDB TABLE into an InnoDB table object. Those flags are stored in .frm file and end up in the MySQL table object, but are frequently used inside InnoDB so we keep their copies into the -InnoDB table object. */ -void -innobase_copy_frm_flags_from_table_share( - dict_table_t* innodb_table, /*!< in/out: InnoDB table */ - const TABLE_SHARE* table_share); /*!< in: table share */ +InnoDB table object. +@param innodb_table InnoDB table +@param table MariaDB table handle */ +void innobase_copy_frm_flags_from_table(dict_table_t *innodb_table, + const TABLE *table) noexcept; /** Set up base columns for virtual column @param[in] table the InnoDB table diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 7d3ede43c1a89..f443c4cbab9a2 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -11707,8 +11707,8 @@ ha_innobase::commit_inplace_alter_table( DBUG_ASSERT(ctx->need_rebuild() == new_clustered); - innobase_copy_frm_flags_from_table_share( - ctx->new_table, altered_table->s); + innobase_copy_frm_flags_from_table( + ctx->new_table, altered_table); if (new_clustered) { DBUG_PRINT("to_be_dropped", @@ -11783,8 +11783,8 @@ ha_innobase::commit_inplace_alter_table( ctx->prebuilt->table = innobase_reload_table( m_user_thd, ctx->prebuilt->table, table->s->table_name, *ctx); - innobase_copy_frm_flags_from_table_share( - ctx->prebuilt->table, altered_table->s); + innobase_copy_frm_flags_from_table( + ctx->prebuilt->table, altered_table); } unlock_and_close_files(deleted, trx); diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index f2c4f9bc0cd76..19f5c692b0bd5 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -900,7 +900,7 @@ ATTRIBUTE_COLD dberr_t ibuf_upgrade() sql_print_information("InnoDB: Upgrading the change buffer"); #ifdef BTR_CUR_HASH_ADAPT - const bool ahi= btr_search.enabled; + const ulong ahi= btr_search.get_enabled(); if (ahi) btr_search.disable(); #endif @@ -1007,7 +1007,7 @@ ATTRIBUTE_COLD dberr_t ibuf_upgrade() #ifdef BTR_CUR_HASH_ADAPT if (ahi) - btr_search.enable(); + btr_search.enable(false, ahi); #endif ibuf_index->lock.free(); diff --git a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h index 685d9a4feb2b1..0c33cbda240ab 100644 --- a/storage/innobase/include/btr0sea.h +++ b/storage/innobase/include/btr0sea.h @@ -108,24 +108,56 @@ struct btr_sea { /** the actual value of innodb_adaptive_hash_index, protected by all partition::latch. Note that if buf_block_t::index is not nullptr - while a thread is holding a partition::latch, then also this must hold. */ - Atomic_relaxed enabled; + while a thread is holding a partition::latch, then also this must hold. + Values 0 (disabled), 1 (enabled) or 2 (enabled if table or index option + enabled ahi */ + Atomic_relaxed enabled; private: /** Disable the adaptive hash search system and empty the index. @return whether the adaptive hash index was enabled */ - ATTRIBUTE_COLD bool disable_and_lock() noexcept; + ATTRIBUTE_COLD ulong disable_and_lock() noexcept; /** Unlock the adaptive hash search system. */ ATTRIBUTE_COLD void unlock() noexcept; + public: + + /** Check if ahi is enable for an index + @return true if enabled */ + inline bool is_enabled(const dict_index_t *index) const noexcept + { + /* + Index is enabled if global ahi is enabled and index can be enabled. + If enabled is set to 2 (IF_SPECIFIED), only enable indexes declared + with ahi enabled on (ahi_enabled == 2). + We don't have to check if index->search_info.ahi_enabled != 0 + as the test enabled <= ahi_enabled will not be true in this case. + */ + const ulong enabled{get_enabled()}; + return (unlikely(enabled != 0) && + enabled <= index->search_info.ahi_enabled); + } + /* + Same as above, but if index == 0 return 1. This to handle the case + where we do not yet know if ahi for the index is enabled or not + */ + inline bool may_be_enabled(const dict_index_t *index) const noexcept + { + const ulong enabled{get_enabled()}; + return (unlikely(enabled != 0) && + (!index || enabled <= index->search_info.ahi_enabled)); + } + + inline ulong get_enabled() const noexcept { return enabled; } + /** Disable the adaptive hash search system and empty the index. @return whether the adaptive hash index was enabled */ - ATTRIBUTE_COLD bool disable() noexcept; + ATTRIBUTE_COLD ulong disable() noexcept; /** Enable the adaptive hash search system. @param resize whether buf_pool_t::resize() is the caller */ - ATTRIBUTE_COLD void enable(bool resize= false) noexcept; + ATTRIBUTE_COLD void enable(bool resize, ulong enable_type) noexcept; /** Hash cell chain in hash_table */ struct hash_chain diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 0fa14f747c9f7..83cdcae1d6c53 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -1089,11 +1089,26 @@ struct dict_index_t { search, and the calculation itself is not always accurate! */ Atomic_relaxed last_hash_succ{false}; + /** If adaptive hash indexes are enabled for this index: + - 0: force disabled + - 1: no preference (set by default, use global setting) + - 2: prefer enabled (if not globally disabled) + */ + Atomic_relaxed ahi_enabled{0}; + /** recommended parameters; @see buf_block_t::left_bytes_fields */ Atomic_relaxed left_bytes_fields{buf_block_t::LEFT_SIDE | 1}; /** number of buf_block_t::index pointers to this index */ Atomic_counter ref_count{0}; + /** mask which indicates which bits are valid in + ahi_fixed_left_bytes_fields */ + Atomic_relaxed ahi_fixed_left_bytes_fields_mask{0}; + /** fixed parameters in recommendations, validity depends on + ahi_fixed_left_bytes_fields_mask; + @see buf_block_t::left_bytes_fields */ + Atomic_relaxed ahi_fixed_left_bytes_fields{0}; + # ifdef UNIV_SEARCH_PERF_STAT /** number of successful hash searches */ size_t n_hash_succ{0}; diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index c3c17dd1d305e..38a64ce2324ca 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -4541,7 +4541,7 @@ row_search_mvcc( if (UNIV_UNLIKELY(direction == 0) && unique_search - && btr_search.enabled + && btr_search.get_enabled() && dict_index_is_clust(index) && !index->table->is_temporary() && !prebuilt->templ_contains_blob diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index f9fffde59bb2e..6bd5d774e7d92 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -739,7 +739,7 @@ srv_printf_innodb_monitor( os_aio_print(file); #ifdef BTR_CUR_HASH_ADAPT - if (btr_search.enabled) { + if (btr_search.get_enabled()) { fputs("-------------------\n" "ADAPTIVE HASH INDEX\n" "-------------------\n", file);