diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2019-11-07 10:34:33 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2019-11-07 10:34:33 +0200 |
commit | 77e8a311e1f919f15845c75d08de4340965c0bc4 (patch) | |
tree | 7afc1e49694bb16fcdc07495a294a8d89b62f5eb | |
parent | 3ad37ed0eb343cd173b103974aded5783958a88e (diff) | |
parent | c24ec3cece6d8bf70dac7519b6fd397c464f7a82 (diff) | |
download | mariadb-git-77e8a311e1f919f15845c75d08de4340965c0bc4.tar.gz |
Merge 10.4 into 10.5
A conflict between MDEV-19514 (b42294bc6409794bdbd2051b32fa079d81cea61d)
and MDEV-20934 (d7a2401750bb29dfdb45929a536539b9f17b347f)
was resolved. We will not invoke the function ibuf_delete_recs()
from ibuf_merge_or_delete_for_page(). Instead, we will add that
logic to the function ibuf_read_merge_pages().
27 files changed, 444 insertions, 143 deletions
diff --git a/extra/mariabackup/backup_copy.cc b/extra/mariabackup/backup_copy.cc index 21e574ae3b8..6ede0288e3a 100644 --- a/extra/mariabackup/backup_copy.cc +++ b/extra/mariabackup/backup_copy.cc @@ -478,7 +478,7 @@ struct datafile_cur_t { { memset(rel_path, 0, sizeof rel_path); if (filename) { - strncpy(abs_path, filename, sizeof abs_path); + strncpy(abs_path, filename, sizeof abs_path - 1); abs_path[(sizeof abs_path) - 1] = 0; } else { abs_path[0] = '\0'; diff --git a/extra/mariabackup/changed_page_bitmap.cc b/extra/mariabackup/changed_page_bitmap.cc index fcfb33c500a..5266bed800d 100644 --- a/extra/mariabackup/changed_page_bitmap.cc +++ b/extra/mariabackup/changed_page_bitmap.cc @@ -390,7 +390,7 @@ log_online_setup_bitmap_file_range( bitmap_files->files[array_pos].seq_num = file_seq_num; strncpy(bitmap_files->files[array_pos].name, - bitmap_dir_file_info.name, FN_REFLEN); + bitmap_dir_file_info.name, FN_REFLEN - 1); bitmap_files->files[array_pos].name[FN_REFLEN - 1] = '\0'; bitmap_files->files[array_pos].start_lsn diff --git a/include/heap.h b/include/heap.h index d0c907a48b4..ca6efa48f1b 100644 --- a/include/heap.h +++ b/include/heap.h @@ -246,7 +246,7 @@ int hp_panic(enum ha_panic_function flag); int heap_rkey(HP_INFO *info, uchar *record, int inx, const uchar *key, key_part_map keypart_map, enum ha_rkey_function find_flag); extern uchar * heap_find(HP_INFO *info,int inx,const uchar *key); -extern int heap_check_heap(HP_INFO *info, my_bool print_status); +extern int heap_check_heap(const HP_INFO *info, my_bool print_status); extern uchar *heap_position(HP_INFO *info); /* The following is for programs that uses the old HEAP interface where diff --git a/mysql-test/main/join_outer_innodb.result b/mysql-test/main/join_outer_innodb.result index ccd73ec955f..a0358094baa 100644 --- a/mysql-test/main/join_outer_innodb.result +++ b/mysql-test/main/join_outer_innodb.result @@ -434,46 +434,46 @@ where t1.a10 = 1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL a4,a6,a5,a7 NULL NULL NULL 3 Using where 1 SIMPLE t8 eq_ref PRIMARY PRIMARY 1 test.t1.a4 1 Using index +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 1 test.t1.a7 1 1 SIMPLE t11 eq_ref PRIMARY PRIMARY 4 test.t1.a5 1 1 SIMPLE t12 eq_ref PRIMARY PRIMARY 4 test.t11.k3 1 Using where 1 SIMPLE l2 eq_ref PRIMARY PRIMARY 4 test.t11.k4 1 Using where 1 SIMPLE t13 ref PRIMARY,m3 PRIMARY 4 test.t1.a1 1 Using where; Using index 1 SIMPLE t2 ref PRIMARY PRIMARY 4 test.t1.a1 1 Using index -1 SIMPLE t9 ref PRIMARY PRIMARY 1 test.t1.a4 1 1 SIMPLE l4 eq_ref PRIMARY PRIMARY 4 test.t13.m2 1 Using where; Using index 1 SIMPLE m2 ref PRIMARY,m3 PRIMARY 4 test.t1.a1 1 Using where; Using index 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.b2 1 Using where; Using index +1 SIMPLE t9 ref PRIMARY PRIMARY 1 test.t1.a4 1 +1 SIMPLE l3 eq_ref PRIMARY PRIMARY 4 test.m2.m2 1 Using where +1 SIMPLE t14 ALL PRIMARY NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t4 eq_ref PRIMARY PRIMARY 4 test.t1.a2 1 Using index -1 SIMPLE t5 ALL PRIMARY NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) -1 SIMPLE l3 ALL PRIMARY NULL NULL NULL 3 Using where; Using join buffer (incremental, BNL join) -1 SIMPLE t7 eq_ref PRIMARY PRIMARY 1 test.t1.a7 1 -1 SIMPLE t6 eq_ref PRIMARY PRIMARY 4 test.t1.a3 1 Using where; Using index -1 SIMPLE t14 eq_ref PRIMARY PRIMARY 2 test.t1.a8 1 Using where 1 SIMPLE t15 eq_ref PRIMARY PRIMARY 2 test.t1.a9 1 Using where; Using index 1 SIMPLE t16 ref PRIMARY PRIMARY 2 test.t15.o1 1 Using where 1 SIMPLE t10 ALL PRIMARY NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.d1 1 Using where +1 SIMPLE t6 eq_ref PRIMARY PRIMARY 4 test.t1.a3 1 Using where; Using index explain select * from v1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL a4,a6,a5,a7 NULL NULL NULL 3 Using where 1 SIMPLE t8 eq_ref PRIMARY PRIMARY 1 test.t1.a4 1 Using index +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 1 test.t1.a7 1 1 SIMPLE t11 eq_ref PRIMARY PRIMARY 4 test.t1.a5 1 1 SIMPLE t12 eq_ref PRIMARY PRIMARY 4 test.t11.k3 1 Using where 1 SIMPLE l2 eq_ref PRIMARY PRIMARY 4 test.t11.k4 1 Using where 1 SIMPLE t13 ref PRIMARY,m3 PRIMARY 4 test.t1.a1 1 Using where; Using index 1 SIMPLE t2 ref PRIMARY PRIMARY 4 test.t1.a1 1 Using index -1 SIMPLE t9 ref PRIMARY PRIMARY 1 test.t1.a4 1 1 SIMPLE l4 eq_ref PRIMARY PRIMARY 4 test.t13.m2 1 Using where; Using index 1 SIMPLE m2 ref PRIMARY,m3 PRIMARY 4 test.t1.a1 1 Using where; Using index 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.b2 1 Using where; Using index +1 SIMPLE t9 ref PRIMARY PRIMARY 1 test.t1.a4 1 +1 SIMPLE l3 eq_ref PRIMARY PRIMARY 4 test.m2.m2 1 Using where +1 SIMPLE t14 ALL PRIMARY NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t4 eq_ref PRIMARY PRIMARY 4 test.t1.a2 1 Using index -1 SIMPLE t5 ALL PRIMARY NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) -1 SIMPLE l3 ALL PRIMARY NULL NULL NULL 3 Using where; Using join buffer (incremental, BNL join) -1 SIMPLE t7 eq_ref PRIMARY PRIMARY 1 test.t1.a7 1 -1 SIMPLE t6 eq_ref PRIMARY PRIMARY 4 test.t1.a3 1 Using where; Using index -1 SIMPLE t14 eq_ref PRIMARY PRIMARY 2 test.t1.a8 1 Using where 1 SIMPLE t15 eq_ref PRIMARY PRIMARY 2 test.t1.a9 1 Using where; Using index 1 SIMPLE t16 ref PRIMARY PRIMARY 2 test.t15.o1 1 Using where 1 SIMPLE t10 ALL PRIMARY NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.d1 1 Using where +1 SIMPLE t6 eq_ref PRIMARY PRIMARY 4 test.t1.a3 1 Using where; Using index drop view v1; drop table t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16; # diff --git a/mysql-test/main/selectivity.result b/mysql-test/main/selectivity.result index f11fee4b985..c548748b242 100644 --- a/mysql-test/main/selectivity.result +++ b/mysql-test/main/selectivity.result @@ -1753,5 +1753,62 @@ a 1991 set optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity; DROP TABLE t1; +# +# MDEV-20424: New default value for optimizer_use_condition-selectivity +# leads to bad plan +# +create table t1(a int, b int, c int, d int, key(a,b)); +insert into t1 select 50,seq-1,seq-1,seq from seq_1_to_10; +insert into t1 select seq-1,seq-1,seq-1,seq from seq_1_to_100 limit 90; +create table t2(a int, b int, c int, primary key(a)); +insert into t2 select seq-1,seq-1,seq-1 from seq_1_to_100; +create table t3(a int, b int, c int, primary key(a)); +insert into t3 select seq-1,seq-1,seq-1 from seq_1_to_100 limit 30; +set optimizer_use_condition_selectivity=1; +explain extended select t1.b,t2.a,t3.a,t3.b from t1,t2,t3 +where t1.c = t2.a AND t1.d = t3.a and t1.a = 50 and t1.b <= 100; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 range a a 10 NULL 9 100.00 Using index condition; Using where +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.d 1 100.00 +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.c 1 100.00 Using index +Warnings: +Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t2`.`a` = `test`.`t1`.`c` and `test`.`t3`.`a` = `test`.`t1`.`d` and `test`.`t1`.`a` = 50 and `test`.`t1`.`b` <= 100 +select t1.b,t2.a,t3.a,t3.b from t1,t2,t3 +where t1.c = t2.a AND t1.d = t3.a and t1.a = 50 and t1.b <= 100; +b a a b +0 0 1 1 +1 1 2 2 +2 2 3 3 +3 3 4 4 +4 4 5 5 +5 5 6 6 +6 6 7 7 +7 7 8 8 +8 8 9 9 +9 9 10 10 +set optimizer_use_condition_selectivity=2; +explain extended select t1.b,t2.a,t3.a,t3.b from t1,t2,t3 +where t1.c = t2.a AND t1.d = t3.a and t1.a = 50 and t1.b <= 100; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 range a a 10 NULL 9 9.00 Using index condition; Using where +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.d 1 100.00 +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.c 1 100.00 Using index +Warnings: +Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t2`.`a` = `test`.`t1`.`c` and `test`.`t3`.`a` = `test`.`t1`.`d` and `test`.`t1`.`a` = 50 and `test`.`t1`.`b` <= 100 +select t1.b,t2.a,t3.a,t3.b from t1,t2,t3 +where t1.c = t2.a AND t1.d = t3.a and t1.a = 50 and t1.b <= 100; +b a a b +0 0 1 1 +1 1 2 2 +2 2 3 3 +3 3 4 4 +4 4 5 5 +5 5 6 6 +6 6 7 7 +7 7 8 8 +8 8 9 9 +9 9 10 10 +set optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity; +drop table t1,t2,t3; # End of 10.1 tests set @@global.histogram_size=@save_histogram_size; diff --git a/mysql-test/main/selectivity.test b/mysql-test/main/selectivity.test index a9588ea205d..3cf4f320994 100644 --- a/mysql-test/main/selectivity.test +++ b/mysql-test/main/selectivity.test @@ -1206,6 +1206,35 @@ set optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivit DROP TABLE t1; +--echo # +--echo # MDEV-20424: New default value for optimizer_use_condition-selectivity +--echo # leads to bad plan +--echo # + +create table t1(a int, b int, c int, d int, key(a,b)); +insert into t1 select 50,seq-1,seq-1,seq from seq_1_to_10; +insert into t1 select seq-1,seq-1,seq-1,seq from seq_1_to_100 limit 90; + +create table t2(a int, b int, c int, primary key(a)); +insert into t2 select seq-1,seq-1,seq-1 from seq_1_to_100; + +create table t3(a int, b int, c int, primary key(a)); +insert into t3 select seq-1,seq-1,seq-1 from seq_1_to_100 limit 30; + +let $query= select t1.b,t2.a,t3.a,t3.b from t1,t2,t3 +where t1.c = t2.a AND t1.d = t3.a and t1.a = 50 and t1.b <= 100; + +set optimizer_use_condition_selectivity=1; +eval explain extended $query; +eval $query; + +set optimizer_use_condition_selectivity=2; +eval explain extended $query; +eval $query; +set optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity; + +drop table t1,t2,t3; + --echo # End of 10.1 tests # diff --git a/mysql-test/main/selectivity_innodb.result b/mysql-test/main/selectivity_innodb.result index 80295473e9b..b293f6adb5f 100644 --- a/mysql-test/main/selectivity_innodb.result +++ b/mysql-test/main/selectivity_innodb.result @@ -1763,6 +1763,63 @@ a 1991 set optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity; DROP TABLE t1; +# +# MDEV-20424: New default value for optimizer_use_condition-selectivity +# leads to bad plan +# +create table t1(a int, b int, c int, d int, key(a,b)); +insert into t1 select 50,seq-1,seq-1,seq from seq_1_to_10; +insert into t1 select seq-1,seq-1,seq-1,seq from seq_1_to_100 limit 90; +create table t2(a int, b int, c int, primary key(a)); +insert into t2 select seq-1,seq-1,seq-1 from seq_1_to_100; +create table t3(a int, b int, c int, primary key(a)); +insert into t3 select seq-1,seq-1,seq-1 from seq_1_to_100 limit 30; +set optimizer_use_condition_selectivity=1; +explain extended select t1.b,t2.a,t3.a,t3.b from t1,t2,t3 +where t1.c = t2.a AND t1.d = t3.a and t1.a = 50 and t1.b <= 100; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 range a a 10 NULL 11 100.00 Using index condition; Using where +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.d 1 100.00 +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.c 1 100.00 Using index +Warnings: +Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t2`.`a` = `test`.`t1`.`c` and `test`.`t3`.`a` = `test`.`t1`.`d` and `test`.`t1`.`a` = 50 and `test`.`t1`.`b` <= 100 +select t1.b,t2.a,t3.a,t3.b from t1,t2,t3 +where t1.c = t2.a AND t1.d = t3.a and t1.a = 50 and t1.b <= 100; +b a a b +0 0 1 1 +1 1 2 2 +2 2 3 3 +3 3 4 4 +4 4 5 5 +5 5 6 6 +6 6 7 7 +7 7 8 8 +8 8 9 9 +9 9 10 10 +set optimizer_use_condition_selectivity=2; +explain extended select t1.b,t2.a,t3.a,t3.b from t1,t2,t3 +where t1.c = t2.a AND t1.d = t3.a and t1.a = 50 and t1.b <= 100; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 range a a 10 NULL 11 11.00 Using index condition; Using where +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.d 1 100.00 +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.c 1 100.00 Using index +Warnings: +Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t1` join `test`.`t2` join `test`.`t3` where `test`.`t2`.`a` = `test`.`t1`.`c` and `test`.`t3`.`a` = `test`.`t1`.`d` and `test`.`t1`.`a` = 50 and `test`.`t1`.`b` <= 100 +select t1.b,t2.a,t3.a,t3.b from t1,t2,t3 +where t1.c = t2.a AND t1.d = t3.a and t1.a = 50 and t1.b <= 100; +b a a b +0 0 1 1 +1 1 2 2 +2 2 3 3 +3 3 4 4 +4 4 5 5 +5 5 6 6 +6 6 7 7 +7 7 8 8 +8 8 9 9 +9 9 10 10 +set optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity; +drop table t1,t2,t3; # End of 10.1 tests set @@global.histogram_size=@save_histogram_size; set optimizer_switch=@save_optimizer_switch_for_selectivity_test; diff --git a/mysql-test/main/stat_tables.result b/mysql-test/main/stat_tables.result index 35a21377689..3ff10cc2448 100644 --- a/mysql-test/main/stat_tables.result +++ b/mysql-test/main/stat_tables.result @@ -218,8 +218,8 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE supplier eq_ref PRIMARY,i_s_nationkey PRIMARY 4 dbt3_s001.lineitem.l_suppkey 1 Using where 1 SIMPLE n2 eq_ref PRIMARY PRIMARY 4 dbt3_s001.supplier.s_nationkey 1 1 SIMPLE orders eq_ref PRIMARY,i_o_orderdate,i_o_custkey PRIMARY 4 dbt3_s001.lineitem.l_orderkey 1 Using where -1 SIMPLE customer eq_ref PRIMARY,i_c_nationkey PRIMARY 4 dbt3_s001.orders.o_custkey 1 -1 SIMPLE n1 ref PRIMARY,i_n_regionkey i_n_regionkey 5 dbt3_s001.region.r_regionkey 5 Using where +1 SIMPLE customer eq_ref PRIMARY,i_c_nationkey PRIMARY 4 dbt3_s001.orders.o_custkey 1 Using where +1 SIMPLE n1 eq_ref PRIMARY,i_n_regionkey PRIMARY 4 dbt3_s001.customer.c_nationkey 1 Using where select o_year, sum(case when nation = 'UNITED STATES' then volume else 0 end) / sum(volume) as mkt_share diff --git a/mysql-test/suite/innodb/r/ibuf_not_empty.result b/mysql-test/suite/innodb/r/ibuf_not_empty.result index 5147521b19f..dc852dfb8e5 100644 --- a/mysql-test/suite/innodb/r/ibuf_not_empty.result +++ b/mysql-test/suite/innodb/r/ibuf_not_empty.result @@ -21,6 +21,11 @@ INSERT INTO t1 SELECT 0,b,c FROM t1; # restart: --innodb-force-recovery=6 --innodb-change-buffer-dump check table t1; Table Op Msg_type Msg_text -test.t1 check status OK +test.t1 check Warning InnoDB: Index 'b' contains #### entries, should be 4096. +test.t1 check error Corrupt +# restart +SET GLOBAL innodb_purge_rseg_truncate_frequency=1; +InnoDB 0 transactions not purged +SET GLOBAL innodb_fast_shutdown=0; # restart DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/ibuf_not_empty.combinations b/mysql-test/suite/innodb/t/ibuf_not_empty.combinations new file mode 100644 index 00000000000..729380593f3 --- /dev/null +++ b/mysql-test/suite/innodb/t/ibuf_not_empty.combinations @@ -0,0 +1,5 @@ +[strict_crc32] +--innodb-checksum-algorithm=strict_crc32 + +[strict_full_crc32] +--innodb-checksum-algorithm=strict_full_crc32 diff --git a/mysql-test/suite/innodb/t/ibuf_not_empty.test b/mysql-test/suite/innodb/t/ibuf_not_empty.test index 470d375c661..14d8728cdf8 100644 --- a/mysql-test/suite/innodb/t/ibuf_not_empty.test +++ b/mysql-test/suite/innodb/t/ibuf_not_empty.test @@ -42,9 +42,44 @@ INSERT INTO t1 SELECT 0,b,c FROM t1; INSERT INTO t1 SELECT 0,b,c FROM t1; INSERT INTO t1 SELECT 0,b,c FROM t1; INSERT INTO t1 SELECT 0,b,c FROM t1; +let MYSQLD_DATADIR=`select @@datadir`; +let PAGE_SIZE=`select @@innodb_page_size`; + +--source include/shutdown_mysqld.inc + +# Corrupt the change buffer bitmap, to claim that pages are clean +perl; +do "$ENV{MTR_SUITE_DIR}/include/crc32.pl"; +my $file = "$ENV{MYSQLD_DATADIR}/test/t1.ibd"; +open(FILE, "+<$file") || die "Unable to open $file"; +binmode FILE; +my $ps= $ENV{PAGE_SIZE}; +my $page; +die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps; +my $full_crc32 = unpack("N",substr($page,54,4)) & 0x10; # FIL_SPACE_FLAGS +die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps; +# Clean the change buffer bitmap. +substr($page,38,$ps - 38 - 8) = chr(0) x ($ps - 38 - 8); +my $polynomial = 0x82f63b78; # CRC-32C +if ($full_crc32) +{ + my $ck = mycrc32(substr($page, 0, $ps-4), 0, $polynomial); + substr($page, $ps-4, 4) = pack("N", $ck); +} +else +{ + my $ck= pack("N",mycrc32(substr($page, 4, 22), 0, $polynomial) ^ + mycrc32(substr($page, 38, $ps - 38 - 8), 0, $polynomial)); + substr($page,0,4)=$ck; + substr($page,$ps-8,4)=$ck; +} +sysseek(FILE, $ps, 0) || die "Unable to rewind $file\n"; +syswrite(FILE, $page, $ps)==$ps || die "Unable to write $file\n"; +close(FILE) || die "Unable to close $file"; +EOF --let $restart_parameters= --innodb-force-recovery=6 --innodb-change-buffer-dump ---source include/restart_mysqld.inc +--source include/start_mysqld.inc --replace_regex /contains \d+ entries/contains #### entries/ check table t1; @@ -52,5 +87,13 @@ check table t1; --let $restart_parameters= --source include/restart_mysqld.inc +# Ensure that the slow shutdown will not time out due to running purge. +SET GLOBAL innodb_purge_rseg_truncate_frequency=1; +--source include/wait_all_purged.inc +# The change buffer merge for the injected corruption must complete +# without exceeding the 60-second shutdown_server timeout. +SET GLOBAL innodb_fast_shutdown=0; +--source include/restart_mysqld.inc + # Cleanup DROP TABLE t1; diff --git a/mysql-test/suite/innodb_fts/r/innodb_fts_misc.result b/mysql-test/suite/innodb_fts/r/innodb_fts_misc.result index 0bcea9165b1..91f875377e2 100644 --- a/mysql-test/suite/innodb_fts/r/innodb_fts_misc.result +++ b/mysql-test/suite/innodb_fts/r/innodb_fts_misc.result @@ -1,4 +1,3 @@ -drop table if exists t1; CREATE TABLE t1 ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, a VARCHAR(200), @@ -409,7 +408,6 @@ AGAINST ('"following database"@10' IN BOOLEAN MODE); id 105 DROP TABLE t1; -drop table if exists t50; set names utf8; "----------Test1---------" create table t50 (s1 varchar(60) character set utf8 collate utf8_bin) engine = innodb; @@ -648,9 +646,6 @@ s1 ŁŁŁŁ LLLL ŁŁŁŁ ŁŁŁŁ -DROP TABLE if EXISTS t2; -Warnings: -Note 1051 Unknown table 'test.t2' CREATE TABLE t2 (s1 VARCHAR(60) CHARACTER SET UTF8 COLLATE UTF8_POLISH_CI) ENGINE = InnoDB; CREATE FULLTEXT INDEX i ON t2 ( s1); INSERT INTO t2 VALUES @@ -702,9 +697,14 @@ DROP TABLE t1; CREATE TABLE t1 (id INT,char_column VARCHAR(60)); CREATE TABLE t2 (FTS_DOC_ID BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, a TEXT)ENGINE=InnoDB; ALTER TABLE t2 DROP a; -SET @@autocommit=0; CREATE FULLTEXT INDEX i ON t1 (char_column); INSERT INTO t1 values (1,'aaa'); +CREATE TABLE mdev20987_1(f1 INT NOT NULL, PRIMARY KEY(f1))ENGINE=InnoDB; +CREATE TABLE mdev20987_2(f1 INT NOT NULL, f2 CHAR(100), +FULLTEXT(f2), +FOREIGN KEY(f1) REFERENCES mdev20987_1(f1))ENGINE=InnoDB; +INSERT INTO mdev20987_1 VALUES(1); +INSERT INTO mdev20987_2 VALUES(1, 'mariadb'); # restart SHOW CREATE TABLE t2; Table Create Table @@ -713,12 +713,8 @@ t2 CREATE TABLE `t2` ( PRIMARY KEY (`FTS_DOC_ID`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 DELETE FROM t1 WHERE MATCH(char_column) AGAINST ('bbb'); -SET @@autocommit=1; -DROP TABLE t1, t2; +DROP TABLE t1, t2, mdev20987_2, mdev20987_1; "----------Test28---------" -drop table if exists `fts_test`; -Warnings: -Note 1051 Unknown table 'test.fts_test' create table `fts_test`(`a` text,fulltext key(`a`))engine=innodb; set session autocommit=0; insert into `fts_test` values (''); @@ -908,9 +904,6 @@ id title body 2 How To Use MySQL Well After you went through a ... 3 Optimizing MySQL In this tutorial we will show ... DROP TABLE articles; -drop table if exists t1; -Warnings: -Note 1051 Unknown table 'test.t1' create table t1 (FTS_DOC_ID bigint unsigned auto_increment not null primary key, title varchar(200),body text,fulltext(title,body)) engine=innodb; insert into t1 set body='test'; diff --git a/mysql-test/suite/innodb_fts/t/innodb_fts_misc.test b/mysql-test/suite/innodb_fts/t/innodb_fts_misc.test index 4563d6dde77..e1f4874a1d4 100644 --- a/mysql-test/suite/innodb_fts/t/innodb_fts_misc.test +++ b/mysql-test/suite/innodb_fts/t/innodb_fts_misc.test @@ -7,10 +7,6 @@ let collation=UTF8_UNICODE_CI; --source include/have_collation.inc ---disable_warnings -drop table if exists t1; ---enable_warnings - # Create FTS table CREATE TABLE t1 ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, @@ -403,10 +399,6 @@ DROP TABLE t1; #------------------------------------------------------------------------------ # More FTS test from peter's testing #------------------------------------------------------------------------------ ---disable_warnings -drop table if exists t50; ---enable_warnings - set names utf8; @@ -608,7 +600,6 @@ CREATE FULLTEXT INDEX i ON t1 (s1); INSERT INTO t1 VALUES ('a'),('b'),('c'),('d'),('ŁŁŁŁ'),('LLLL'),(NULL),('ŁŁŁŁ ŁŁŁŁ'),('LLLLLLLL'); SELECT * FROM t1 WHERE MATCH(s1) AGAINST ('LLLL' COLLATE UTF8_UNICODE_520_CI); -DROP TABLE if EXISTS t2; CREATE TABLE t2 (s1 VARCHAR(60) CHARACTER SET UTF8 COLLATE UTF8_POLISH_CI) ENGINE = InnoDB; CREATE FULLTEXT INDEX i ON t2 ( s1); INSERT INTO t2 VALUES @@ -672,17 +663,21 @@ DROP TABLE t1; CREATE TABLE t1 (id INT,char_column VARCHAR(60)); CREATE TABLE t2 (FTS_DOC_ID BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, a TEXT)ENGINE=InnoDB; ALTER TABLE t2 DROP a; -SET @@autocommit=0; CREATE FULLTEXT INDEX i ON t1 (char_column); INSERT INTO t1 values (1,'aaa'); + +CREATE TABLE mdev20987_1(f1 INT NOT NULL, PRIMARY KEY(f1))ENGINE=InnoDB; +CREATE TABLE mdev20987_2(f1 INT NOT NULL, f2 CHAR(100), + FULLTEXT(f2), + FOREIGN KEY(f1) REFERENCES mdev20987_1(f1))ENGINE=InnoDB; +INSERT INTO mdev20987_1 VALUES(1); +INSERT INTO mdev20987_2 VALUES(1, 'mariadb'); --source include/restart_mysqld.inc SHOW CREATE TABLE t2; DELETE FROM t1 WHERE MATCH(char_column) AGAINST ('bbb'); -SET @@autocommit=1; -DROP TABLE t1, t2; +DROP TABLE t1, t2, mdev20987_2, mdev20987_1; --echo "----------Test28---------" -drop table if exists `fts_test`; create table `fts_test`(`a` text,fulltext key(`a`))engine=innodb; set session autocommit=0; insert into `fts_test` values (''); @@ -871,8 +866,6 @@ DROP TABLE articles; # Test for Bug 13940669 - 64901: INNODB: ASSERTION FAILURE IN # THREAD 34387022112 IN FILE REM0CMP.CC LINE 5 -drop table if exists t1; - create table t1 (FTS_DOC_ID bigint unsigned auto_increment not null primary key, title varchar(200),body text,fulltext(title,body)) engine=innodb; diff --git a/mysql-test/suite/perfschema/r/misc.result b/mysql-test/suite/perfschema/r/misc.result index 4c8fdca8e68..2e4d21d625a 100644 --- a/mysql-test/suite/perfschema/r/misc.result +++ b/mysql-test/suite/perfschema/r/misc.result @@ -134,3 +134,19 @@ truncate performance_schema.events_statements_history 0 select * from t1 3 insert into t1 select RAND()*10000 from t1 6 drop table t1; +# +# MDEV-17896 Assertion `pfs->get_refcount() > 0' failed +# in release_table_share +# +SELECT COUNT(*)<@@performance_schema_max_table_instances FROM +performance_schema.objects_summary_global_by_type WHERE OBJECT_TYPE='TABLE'; +COUNT(*)<@@performance_schema_max_table_instances +1 +CREATE TABLE t0(a INT); +SELECT * FROM t0; +a +DROP TEMPORARY TABLE IF EXISTS t0; +Warnings: +Note 1051 Unknown table 'test.t0' +FLUSH TABLE t0; +DROP TABLE t0; diff --git a/mysql-test/suite/perfschema/t/misc.test b/mysql-test/suite/perfschema/t/misc.test index c9f7dc6bfc0..80ce64f0302 100644 --- a/mysql-test/suite/perfschema/t/misc.test +++ b/mysql-test/suite/perfschema/t/misc.test @@ -222,3 +222,51 @@ insert into t1 select RAND()*10000 from t1; select sql_text, rows_examined from performance_schema.events_statements_history; drop table t1; +--echo # +--echo # MDEV-17896 Assertion `pfs->get_refcount() > 0' failed +--echo # in release_table_share +--echo # + +# There must be at least one available slot in PFS table_share_array for +# this test to be meaningful. If there are no free slots we must +# restart mysqld, it is the only way to reset PFS table_share_array +let $query= SELECT COUNT(*)<@@performance_schema_max_table_instances FROM + performance_schema.objects_summary_global_by_type WHERE OBJECT_TYPE='TABLE'; + +let $free_slots_available= `$query`; + +if (!$free_slots_available) +{ + source include/restart_mysqld.inc; +} +eval $query; + +CREATE TABLE t0(a INT); + +# TABLE_SHARE must be cached in the table definition cache. +SELECT * FROM t0; + +# Dropping t0 using DROP TEMPORARY frees up a slot in table_share_array, +# but the persistent table is not correctly dropped, i.e. TABLE_SHARE::m_psi +# still points to that slot in table_share_array. +DROP TEMPORARY TABLE IF EXISTS t0; + +# Try re-using each and every slot in PFS table_share_array. If bug is +# there, we re-use t0 slot. +# The newly created table that re-uses the t0 slot ends up +# resetting the PFS_table_share refcount. +let $i= `SELECT @@performance_schema_max_table_instances`; +disable_query_log; +while ($i) +{ + # Memory engine is here to reduce disk IO + eval CREATE TABLE t$i(a INT) ENGINE=MEMORY; + eval DROP TABLE t$i; + dec $i; +} +enable_query_log; + +# FLUSH TABLE crashes the server when PFS_table_share is found with +# an unexpected refcount. +FLUSH TABLE t0; +DROP TABLE t0; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6b87f4a3c48..268fec84e3b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9831,7 +9831,10 @@ prev_record_reads(const POSITION *positions, uint idx, table_map found_ref) #max_nested_outer_joins=64-1) will not make it any more precise. */ if (pos->records_read) + { found= COST_MULT(found, pos->records_read); + found*= pos->cond_selectivity; + } } } return found; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 2917a320603..2734e5680f2 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2425,6 +2425,13 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, err, ER_THD(thd, err), tbl_name.c_ptr_safe()); + + /* + Our job is done here. This statement was added to avoid executing + unnecessary code farther below which in some strange corner cases + caused the server to crash (see MDEV-17896). + */ + goto log_query; } else { @@ -2540,6 +2547,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, mysql_audit_drop_table(thd, table); } +log_query: if (!dont_log_query && !drop_temporary) { non_tmp_table_deleted= (if_exists ? TRUE : non_tmp_table_deleted); diff --git a/storage/heap/_check.c b/storage/heap/_check.c index 883e67046e7..1a640fa13da 100644 --- a/storage/heap/_check.c +++ b/storage/heap/_check.c @@ -18,10 +18,8 @@ #include "heapdef.h" -static int check_one_key(HP_KEYDEF *keydef, uint keynr, ulong records, - ulong blength, my_bool print_status); -static int check_one_rb_key(HP_INFO *info, uint keynr, ulong records, - my_bool print_status); +static int check_one_key(HP_KEYDEF *, uint, ulong, ulong, my_bool); +static int check_one_rb_key(const HP_INFO *, uint, ulong, my_bool); /* @@ -40,13 +38,13 @@ static int check_one_rb_key(HP_INFO *info, uint keynr, ulong records, 1 error */ -int heap_check_heap(HP_INFO *info, my_bool print_status) +int heap_check_heap(const HP_INFO *info, my_bool print_status) { int error; uint key; ulong records=0, deleted=0, pos, next_block; HP_SHARE *share=info->s; - HP_INFO save_info= *info; /* Needed because scan_init */ + uchar *current_ptr= info->current_ptr; DBUG_ENTER("heap_check_heap"); for (error=key= 0 ; key < share->keys ; key++) @@ -65,7 +63,7 @@ int heap_check_heap(HP_INFO *info, my_bool print_status) { if (pos < next_block) { - info->current_ptr+= share->block.recbuffer; + current_ptr+= share->block.recbuffer; } else { @@ -77,9 +75,9 @@ int heap_check_heap(HP_INFO *info, my_bool print_status) break; /* End of file */ } } - hp_find_record(info,pos); + current_ptr= hp_find_block(&share->block, pos); - if (!info->current_ptr[share->visible]) + if (!current_ptr[share->visible]) deleted++; else records++; @@ -92,7 +90,6 @@ int heap_check_heap(HP_INFO *info, my_bool print_status) deleted, (ulong) share->deleted)); error= 1; } - *info= save_info; DBUG_RETURN(error); } @@ -165,7 +162,7 @@ static int check_one_key(HP_KEYDEF *keydef, uint keynr, ulong records, return error; } -static int check_one_rb_key(HP_INFO *info, uint keynr, ulong records, +static int check_one_rb_key(const HP_INFO *info, uint keynr, ulong records, my_bool print_status) { HP_KEYDEF *keydef= info->s->keydef + keynr; @@ -174,9 +171,11 @@ static int check_one_rb_key(HP_INFO *info, uint keynr, ulong records, uchar *key, *recpos; uint key_length; uint not_used[2]; + TREE_ELEMENT **last_pos; + TREE_ELEMENT *parents[MAX_TREE_HEIGHT+1]; - if ((key= tree_search_edge(&keydef->rb_tree, info->parents, - &info->last_pos, offsetof(TREE_ELEMENT, left)))) + if ((key= tree_search_edge(&keydef->rb_tree, parents, + &last_pos, offsetof(TREE_ELEMENT, left)))) { do { @@ -191,7 +190,7 @@ static int check_one_rb_key(HP_INFO *info, uint keynr, ulong records, } else found++; - key= tree_search_next(&keydef->rb_tree, &info->last_pos, + key= tree_search_next(&keydef->rb_tree, &last_pos, offsetof(TREE_ELEMENT, left), offsetof(TREE_ELEMENT, right)); } while (key); diff --git a/storage/innobase/dict/dict0boot.cc b/storage/innobase/dict/dict0boot.cc index 95bd9a48edd..618f6a2ad40 100644 --- a/storage/innobase/dict/dict0boot.cc +++ b/storage/innobase/dict/dict0boot.cc @@ -89,8 +89,7 @@ dict_hdr_get_new_id( } if (space_id) { - *space_id = mtr_read_ulint(dict_hdr + DICT_HDR_MAX_SPACE_ID, - MLOG_4BYTES, &mtr); + *space_id = mach_read_from_4(dict_hdr + DICT_HDR_MAX_SPACE_ID); if (fil_assign_new_space_id(space_id)) { mlog_write_ulint(dict_hdr + DICT_HDR_MAX_SPACE_ID, *space_id, MLOG_4BYTES, &mtr); @@ -323,9 +322,9 @@ dict_boot(void) dict_mem_index_add_field(index, "NAME", 0); index->id = DICT_TABLES_ID; - index = dict_index_add_to_cache( + dberr_t error = dict_index_add_to_cache( index, mach_read_from_4(dict_hdr + DICT_HDR_TABLES)); - ut_a(index); + ut_a(error == DB_SUCCESS); ut_ad(!table->is_instant()); table->indexes.start->n_core_null_bytes = UT_BITS_IN_BYTES( unsigned(table->indexes.start->n_nullable)); @@ -335,9 +334,9 @@ dict_boot(void) dict_mem_index_add_field(index, "ID", 0); index->id = DICT_TABLE_IDS_ID; - index = dict_index_add_to_cache( + error = dict_index_add_to_cache( index, mach_read_from_4(dict_hdr + DICT_HDR_TABLE_IDS)); - ut_a(index); + ut_a(error == DB_SUCCESS); /*-------------------------*/ table = dict_mem_table_create("SYS_COLUMNS", fil_system.sys_space, @@ -365,9 +364,9 @@ dict_boot(void) dict_mem_index_add_field(index, "POS", 0); index->id = DICT_COLUMNS_ID; - index = dict_index_add_to_cache( + error = dict_index_add_to_cache( index, mach_read_from_4(dict_hdr + DICT_HDR_COLUMNS)); - ut_a(index); + ut_a(error == DB_SUCCESS); ut_ad(!table->is_instant()); table->indexes.start->n_core_null_bytes = UT_BITS_IN_BYTES( unsigned(table->indexes.start->n_nullable)); @@ -408,9 +407,9 @@ dict_boot(void) dict_mem_index_add_field(index, "ID", 0); index->id = DICT_INDEXES_ID; - index = dict_index_add_to_cache( + error = dict_index_add_to_cache( index, mach_read_from_4(dict_hdr + DICT_HDR_INDEXES)); - ut_a(index); + ut_a(error == DB_SUCCESS); ut_ad(!table->is_instant()); table->indexes.start->n_core_null_bytes = UT_BITS_IN_BYTES( unsigned(table->indexes.start->n_nullable)); @@ -437,9 +436,9 @@ dict_boot(void) dict_mem_index_add_field(index, "POS", 0); index->id = DICT_FIELDS_ID; - index = dict_index_add_to_cache( + error = dict_index_add_to_cache( index, mach_read_from_4(dict_hdr + DICT_HDR_FIELDS)); - ut_a(index); + ut_a(error == DB_SUCCESS); ut_ad(!table->is_instant()); table->indexes.start->n_core_null_bytes = UT_BITS_IN_BYTES( unsigned(table->indexes.start->n_nullable)); diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index def439034dc..a480615f739 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -1242,9 +1242,9 @@ dict_create_index_step( if (node->state == INDEX_ADD_TO_CACHE) { ut_ad(node->index->table == node->table); - node->index = dict_index_add_to_cache( + err = dict_index_add_to_cache( node->index, FIL_NULL, trx_is_strict(trx), - &err, node->add_v); + node->add_v); ut_ad((node->index == NULL) == (err != DB_SUCCESS)); diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index f81096989d7..7cd4bb4a401 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -1462,8 +1462,7 @@ dict_table_rename_in_cache( /* The old table name in my_charset_filename is stored in old_name_cs_filename */ - strncpy(old_name_cs_filename, old_name, - MAX_FULL_NAME_LEN); + strcpy(old_name_cs_filename, old_name); old_name_cs_filename[MAX_FULL_NAME_LEN] = '\0'; if (strstr(old_name, TEMP_TABLE_PATH_PREFIX) == NULL) { @@ -1485,8 +1484,7 @@ dict_table_rename_in_cache( } else { /* Old name already in my_charset_filename */ - strncpy(old_name_cs_filename, old_name, - MAX_FULL_NAME_LEN); + strcpy(old_name_cs_filename, old_name); old_name_cs_filename[MAX_FULL_NAME_LEN] = '\0'; } @@ -1936,23 +1934,19 @@ add_field_size: /** Adds an index to the dictionary cache, with possible indexing newly added column. -@param[in] index index; NOTE! The index memory +@param[in,out] index index; NOTE! The index memory object is freed in this function! @param[in] page_no root page number of the index -@param[in] strict TRUE=refuse to create the index +@param[in] strict true=refuse to create the index if records could be too big to fit in an B-tree page -@param[out] err DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION -@param[in] add_v new virtual column that being added along with - an add index call -@return the added index -@retval NULL on error */ -dict_index_t* +@param[in] add_v virtual columns being added along with ADD INDEX +@return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */ +dberr_t dict_index_add_to_cache( - dict_index_t* index, + dict_index_t*& index, ulint page_no, bool strict, - dberr_t* err, const dict_add_v_col_t* add_v) { dict_index_t* new_index; @@ -1973,8 +1967,8 @@ dict_index_add_to_cache( if (!dict_index_find_cols(index, add_v)) { dict_mem_index_free(index); - if (err) *err = DB_CORRUPTION; - return NULL; + index = NULL; + return DB_CORRUPTION; } /* Build the cache internal representation of the index, @@ -2006,8 +2000,8 @@ dict_index_add_to_cache( if (strict) { dict_mem_index_free(new_index); dict_mem_index_free(index); - if (err) *err = DB_TOO_BIG_RECORD; - return NULL; + index = NULL; + return DB_TOO_BIG_RECORD; } else if (current_thd != NULL) { /* Avoid the warning to be printed during recovery. */ @@ -2085,8 +2079,8 @@ dict_index_add_to_cache( new_index->n_core_fields = new_index->n_fields; dict_mem_index_free(index); - if (err) *err = DB_SUCCESS; - return new_index; + index = new_index; + return DB_SUCCESS; } /**********************************************************************//** diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index df4786a7e20..2cf4410b936 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -2566,8 +2566,9 @@ corrupted: and simply did not load this index definition, the .frm file would disagree with the index definitions inside InnoDB. */ - if (!dict_index_add_to_cache( - index, index->page, false, &error)) { + if ((error = dict_index_add_to_cache(index, + index->page)) + != DB_SUCCESS) { goto func_exit; } } @@ -3080,7 +3081,7 @@ func_exit: fts_free(table); } else if (fts_optimize_wq) { fts_optimize_add_table(table); - } else { + } else if (table->can_be_evicted) { /* fts_optimize_thread is not started yet. So make the table as non-evictable from cache. */ dict_sys.prevent_eviction(table); diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 565171529af..476de28c423 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -6559,9 +6559,8 @@ new_clustered_failed: trx_is_strict(ctx->trx))) { for (uint a = 0; a < ctx->num_to_add_index; a++) { ctx->add_index[a]->table = ctx->new_table; - ctx->add_index[a] = dict_index_add_to_cache( - ctx->add_index[a], FIL_NULL, false, - &error, add_v); + error = dict_index_add_to_cache( + ctx->add_index[a], FIL_NULL, false, add_v); ut_a(error == DB_SUCCESS); } diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index 55bcd331f27..2f12b1e9aaf 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -2372,10 +2372,26 @@ ibuf_get_merge_pages( return(volume); } +/** +Delete a change buffer record. +@param[in] space tablespace identifier +@param[in] page_no page number +@param[in,out] pcur persistent cursor positioned on the record +@param[in] search_tuple search key for (space,page_no) +@param[in,out] mtr mini-transaction +@return whether mtr was committed (due to pessimistic operation) */ +static MY_ATTRIBUTE((warn_unused_result, nonnull)) +bool ibuf_delete_rec(ulint space, ulint page_no, btr_pcur_t* pcur, + const dtuple_t* search_tuple, mtr_t* mtr); + /** Merge the change buffer to some pages. */ static void ibuf_read_merge_pages(const ulint* space_ids, const ulint* page_nos, ulint n_stored) { + mem_heap_t* heap = mem_heap_create(512); + ulint dops[IBUF_OP_COUNT]; + memset(dops, 0, sizeof(dops)); + for (ulint i = 0; i < n_stored; i++) { const ulint space_id = space_ids[i]; fil_space_t* s = fil_space_acquire_for_io(space_id); @@ -2396,14 +2412,63 @@ tablespace_deleted: mtr_t mtr; mtr.start(); dberr_t err; - buf_page_get_gen(page_id_t(space_id, page_nos[i]), - zip_size, RW_X_LATCH, NULL, BUF_GET, + buf_page_get_gen(page_id_t(space_id, page_nos[i]), zip_size, + RW_X_LATCH, NULL, BUF_GET, __FILE__, __LINE__, &mtr, &err, true); mtr.commit(); if (err == DB_TABLESPACE_DELETED) { goto tablespace_deleted; } + /* Prevent an infinite loop, by removing entries from + the change buffer also in the case the bitmap bits were + wrongly clear even though buffered changes exist. */ + const dtuple_t* tuple = ibuf_search_tuple_build( + space_id, page_nos[i], heap); +loop: + btr_pcur_t pcur; + ibuf_mtr_start(&mtr); + btr_pcur_open(ibuf.index, tuple, PAGE_CUR_GE, BTR_MODIFY_LEAF, + &pcur, &mtr); + if (!btr_pcur_is_on_user_rec(&pcur)) { + ut_ad(btr_pcur_is_after_last_in_tree(&pcur)); + goto done; + } + + for (;;) { + ut_ad(btr_pcur_is_on_user_rec(&pcur)); + + const rec_t* ibuf_rec = btr_pcur_get_rec(&pcur); + if (ibuf_rec_get_space(&mtr, ibuf_rec) != space_id + || ibuf_rec_get_page_no(&mtr, ibuf_rec) + != page_nos[i]) { + break; + } + + dops[ibuf_rec_get_op_type(&mtr, ibuf_rec)]++; + /* Delete the record from ibuf */ + if (ibuf_delete_rec(space_id, page_nos[i], + &pcur, tuple, &mtr)) { + /* Deletion was pessimistic and mtr + was committed: we start from the + beginning again */ + ut_ad(mtr.has_committed()); + goto loop; + } + + if (btr_pcur_is_after_last_on_page(&pcur)) { + ibuf_mtr_commit(&mtr); + btr_pcur_close(&pcur); + goto loop; + } + } +done: + ibuf_mtr_commit(&mtr); + btr_pcur_close(&pcur); + mem_heap_empty(heap); } + + ibuf_add_ops(ibuf.n_discarded_ops, dops); + mem_heap_free(heap); } /*********************************************************************//** @@ -4125,23 +4190,17 @@ ibuf_restore_pos( return(FALSE); } -/*********************************************************************//** -Deletes from ibuf the record on which pcur is positioned. If we have to -resort to a pessimistic delete, this function commits mtr and closes -the cursor. -@return TRUE if mtr was committed and pcur closed in this operation */ -static MY_ATTRIBUTE((warn_unused_result)) -ibool -ibuf_delete_rec( -/*============*/ - ulint space, /*!< in: space id */ - ulint page_no,/*!< in: index page number that the record - should belong to */ - btr_pcur_t* pcur, /*!< in: pcur positioned on the record to - delete, having latch mode BTR_MODIFY_LEAF */ - const dtuple_t* search_tuple, - /*!< in: search tuple for entries of page_no */ - mtr_t* mtr) /*!< in: mtr */ +/** +Delete a change buffer record. +@param[in] space tablespace identifier +@param[in] page_no page number +@param[in,out] pcur persistent cursor positioned on the record +@param[in] search_tuple search key for (space,page_no) +@param[in,out] mtr mini-transaction +@return whether mtr was committed (due to pessimistic operation) */ +static MY_ATTRIBUTE((warn_unused_result, nonnull)) +bool ibuf_delete_rec(ulint space, ulint page_no, btr_pcur_t* pcur, + const dtuple_t* search_tuple, mtr_t* mtr) { ibool success; page_t* root; @@ -4278,9 +4337,7 @@ ibuf_merge_or_delete_for_page( ulint zip_size, bool update_ibuf_bitmap) { - mem_heap_t* heap; btr_pcur_t pcur; - dtuple_t* search_tuple; #ifdef UNIV_IBUF_DEBUG ulint volume = 0; #endif /* UNIV_IBUF_DEBUG */ @@ -4336,8 +4393,7 @@ ibuf_merge_or_delete_for_page( ibuf_mtr_commit(&mtr); if (!bitmap_bits) { - /* No inserts buffered for this page */ - + /* No changes are buffered for this page. */ space->release(); return; } @@ -4351,9 +4407,9 @@ ibuf_merge_or_delete_for_page( space = NULL; } - heap = mem_heap_create(512); + mem_heap_t* heap = mem_heap_create(512); - search_tuple = ibuf_search_tuple_build( + const dtuple_t* search_tuple = ibuf_search_tuple_build( page_id.space(), page_id.page_no(), heap); if (block != NULL) { diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index feb757a4666..74bdb365e26 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -973,26 +973,21 @@ dict_make_room_in_cache( /** Adds an index to the dictionary cache, with possible indexing newly added column. -@param[in] index index; NOTE! The index memory +@param[in,out] index index; NOTE! The index memory object is freed in this function! @param[in] page_no root page number of the index @param[in] strict true=refuse to create the index if records could be too big to fit in an B-tree page -@param[out] err DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION -@param[in] add_v new virtual column that being added along with - an add index call -@return the added index -@retval NULL on error */ -dict_index_t* +@param[in] add_v virtual columns being added along with ADD INDEX +@return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */ +dberr_t dict_index_add_to_cache( - dict_index_t* index, + dict_index_t*& index, ulint page_no, bool strict = false, - dberr_t* err = NULL, const dict_add_v_col_t* add_v = NULL) - MY_ATTRIBUTE((nonnull(1))); - + MY_ATTRIBUTE((warn_unused_result)); /********************************************************************//** Gets the number of fields in the internal representation of an index, including fields added by the dictionary system. diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 15daeec2e6c..8573ed137d9 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -2557,10 +2557,10 @@ row_create_index_for_mysql( } else { dict_build_index_def(table, index, trx); - /* add index to dictionary cache and also free index object. */ - index = dict_index_add_to_cache( - index, FIL_NULL, trx_is_strict(trx), &err); - if (index) { + err = dict_index_add_to_cache( + index, FIL_NULL, trx_is_strict(trx)); + ut_ad((index == NULL) == (err != DB_SUCCESS)); + if (UNIV_LIKELY(err == DB_SUCCESS)) { ut_ad(!index->is_instant()); index->n_core_null_bytes = UT_BITS_IN_BYTES( unsigned(index->n_nullable)); diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt index c3ff1383f86..863e72928d2 100644 --- a/support-files/CMakeLists.txt +++ b/support-files/CMakeLists.txt @@ -68,11 +68,12 @@ IF(UNIX) IF(CHECKMODULE AND SEMODULE_PACKAGE) FOREACH(pol mariadb) SET(src ${CMAKE_CURRENT_SOURCE_DIR}/policy/selinux/${pol}.te) - SET(tmp ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${pol}-pp.dir/${pol}.mod) + SET(tmp ${CMAKE_CURRENT_BINARY_DIR}/${pol}.mod) SET(out ${CMAKE_CURRENT_BINARY_DIR}/${pol}.pp) ADD_CUSTOM_COMMAND(OUTPUT ${out} COMMAND ${CHECKMODULE} -M -m ${src} -o ${tmp} COMMAND ${SEMODULE_PACKAGE} -m ${tmp} -o ${out} + COMMAND ${CMAKE_COMMAND} -E remove ${tmp} DEPENDS ${src}) ADD_CUSTOM_TARGET(${pol}-pp ALL DEPENDS ${out}) INSTALL(FILES ${out} DESTINATION ${inst_location}/policy/selinux COMPONENT SupportFiles) |