From 54324e542f322ffa8d0f70af7ec5c4323a4687c3 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Wed, 10 May 2023 08:11:15 -0400 Subject: [PATCH 01/17] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 2abc1c05da3..91b253ca00c 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=4 -MYSQL_VERSION_PATCH=29 +MYSQL_VERSION_PATCH=30 SERVER_MATURITY=stable From aa713f5ae20513b0c4d9a74ea3ba3ea3bbdcd719 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 9 May 2023 21:20:10 -0700 Subject: [PATCH 02/17] MDEV-31224 Crash with EXPLAIN EXTENDED for multi-table update of system table EXPLAIN EXTENDED should always print the field item used in the left part of an equality expression from the SET clause of an update statement as a reference to table column. Approved by Oleksandr Byelkin --- mysql-test/main/explain_non_select.result | 19 ++++++++++++++++++ mysql-test/main/explain_non_select.test | 20 +++++++++++++++++++ .../main/myisam_explain_non_select_all.result | 4 ++-- sql/sql_select.cc | 2 +- 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/mysql-test/main/explain_non_select.result b/mysql-test/main/explain_non_select.result index d60f10f85c8..1200a3f9400 100644 --- a/mysql-test/main/explain_non_select.result +++ b/mysql-test/main/explain_non_select.result @@ -277,3 +277,22 @@ EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 2 drop table t1,t2; +# +# MDEV-31224: EXPLAIN EXTENDED for multi-table update of system table +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (b INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (3); +EXPLAIN EXTENDED UPDATE t1, t2 SET b = 4 WHERE a IN (6,2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 system NULL NULL NULL NULL 1 100.00 +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 update `test`.`t1` set `test`.`t2`.`b` = 4 where `test`.`t1`.`a` in (6,2) +UPDATE t1, t2 SET b = 4 WHERE a IN (6,2); +SELECT * from t2; +b +4 +DROP TABLE t1, t2; +# End of 10.4 tests diff --git a/mysql-test/main/explain_non_select.test b/mysql-test/main/explain_non_select.test index d9ff0fb7245..f87a5d9ec8d 100644 --- a/mysql-test/main/explain_non_select.test +++ b/mysql-test/main/explain_non_select.test @@ -250,3 +250,23 @@ PREPARE stmt FROM 'EXPLAIN INSERT INTO t1 SELECT * FROM t2'; EXECUTE stmt; drop table t1,t2; +--echo # +--echo # MDEV-31224: EXPLAIN EXTENDED for multi-table update of system table +--echo # + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); + +CREATE TABLE t2 (b INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (3); + +let $q= +UPDATE t1, t2 SET b = 4 WHERE a IN (6,2); + +eval EXPLAIN EXTENDED $q; +eval $q; +SELECT * from t2; + +DROP TABLE t1, t2; + +--echo # End of 10.4 tests diff --git a/mysql-test/main/myisam_explain_non_select_all.result b/mysql-test/main/myisam_explain_non_select_all.result index 3ca9629d027..b515cb4fd83 100644 --- a/mysql-test/main/myisam_explain_non_select_all.result +++ b/mysql-test/main/myisam_explain_non_select_all.result @@ -2689,7 +2689,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 system NULL NULL NULL NULL 0 0.00 Const row not found 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Warnings: -Note 1003 update `test`.`t1` set NULL = 10 +Note 1003 update `test`.`t1` set `test`.`t2`.`c2` = 10 # Status of EXPLAIN EXTENDED query Variable_name Value Handler_read_key 7 @@ -2734,7 +2734,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 system NULL NULL NULL NULL 0 0.00 Const row not found 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 update `test`.`t1` set NULL = 10 where `test`.`t1`.`c3` = 10 +Note 1003 update `test`.`t1` set `test`.`t2`.`c2` = 10 where `test`.`t1`.`c3` = 10 # Status of EXPLAIN EXTENDED query Variable_name Value Handler_read_key 7 diff --git a/sql/sql_select.cc b/sql/sql_select.cc index bfe17bb43e1..cb60b3442d8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -28138,7 +28138,7 @@ void st_select_lex::print_set_clause(THD *thd, String *str, else str->append(','); - item->print(str, query_type); + item->print(str, (enum_query_type) (query_type | QT_NO_DATA_EXPANSION)); str->append(STRING_WITH_LEN(" = ")); val->print(str, query_type); } From 8f3bf593d24de9cd4744e71c86de80cd502786c7 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 11 May 2023 23:34:41 -0700 Subject: [PATCH 03/17] MDEV-31240 Crash with condition pushable into derived and containing outer reference This bug could affect queries containing a subquery over splittable derived tables and having an outer references in its WHERE clause. If such subquery contained an equality condition whose left part was a reference to a column of the derived table and the right part referred only to outer columns then the server crashed in the function st_join_table::choose_best_splitting() The crashing code was added in the commit ce7ffe61d836fe9f0cfc1087f058bc40d66e5cfb that made the code of the function sensitive to presence of the flag OUTER_REF_TABLE_BIT in the KEYUSE_EXT::needed_in_prefix fields. The field needed_in_prefix of the KEYUSE_EXT structure should not contain table maps with OUTER_REF_TABLE_BIT or RAND_TABLE_BIT. Note that this fix is quite conservative: for affected queries it just returns the query plans that were used before the above mentioned commit. In fact the equalities causing crashes should be pushed into derived tables without any usage of split optimization. Approved by Sergei Petrunia --- mysql-test/main/derived_cond_pushdown.result | 94 ++++++++++++++++++++ mysql-test/main/derived_cond_pushdown.test | 41 +++++++++ sql/opt_split.cc | 3 +- 3 files changed, 137 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/derived_cond_pushdown.result b/mysql-test/main/derived_cond_pushdown.result index 4b202ea7a12..a4fc7a7447d 100644 --- a/mysql-test/main/derived_cond_pushdown.result +++ b/mysql-test/main/derived_cond_pushdown.result @@ -18358,4 +18358,98 @@ a deallocate prepare stmt; drop view v1; drop table t1; +# +# MDEV-31240: condition pushed into splittable derived has reference to +# outer column and does not refer to any column of embedding +# select +# +create table t1 (a int); +insert into t1 select seq from seq_1_to_1000; +create table t2 (a int, b int, key (a)); +insert into t2 select mod(seq,100), rand(13) * mod(seq,500) from seq_1_to_1000; +create table t3 (a int); +insert into t3 values (3), (1); +analyze table t1, t2, t3 persistent for all; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status Table is already up to date +test.t3 analyze status Engine-independent statistics collected +test.t3 analyze status OK +explain select +a, +( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +from t1 limit 5; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 1000 +2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY ref key0 key0 5 test.t1.a 2 +3 LATERAL DERIVED t2 ref a a 5 test.t1.a 10 +select +a, +( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +from t1 limit 5; +a ( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +1 1=804 +2 1=1056 +3 1=846 +4 1=947 +5 1=973 +truncate table t2; +insert into t2 select mod(seq,10), rand(15) * mod(seq,500) from seq_1_to_1000; +analyze table t2 persistent for all; +Table Op Msg_type Msg_text +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status Table is already up to date +explain select +a, +( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +from t1 limit 5; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 1000 +2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY ref key0 key0 5 test.t1.a 100 +3 DERIVED t2 ALL a NULL NULL NULL 1000 Using temporary; Using filesort +select +a, +( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +from t1 limit 5; +a ( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +1 1=11858 +2 1=11380 +3 1=11588 +4 1=11373 +5 1=11612 +drop table t1,t2,t3; # End of 10.4 tests diff --git a/mysql-test/main/derived_cond_pushdown.test b/mysql-test/main/derived_cond_pushdown.test index b4e131dbe79..7a4d9b4ad7d 100644 --- a/mysql-test/main/derived_cond_pushdown.test +++ b/mysql-test/main/derived_cond_pushdown.test @@ -3972,4 +3972,45 @@ deallocate prepare stmt; drop view v1; drop table t1; +--echo # +--echo # MDEV-31240: condition pushed into splittable derived has reference to +--echo # outer column and does not refer to any column of embedding +--echo # select +--echo # + +create table t1 (a int); +insert into t1 select seq from seq_1_to_1000; + +create table t2 (a int, b int, key (a)); +insert into t2 select mod(seq,100), rand(13) * mod(seq,500) from seq_1_to_1000; + +create table t3 (a int); +insert into t3 values (3), (1); + +analyze table t1, t2, t3 persistent for all; + +let $q= +select + a, + ( select concat(t3.a,'=',dt.s) + from + (select a, sum(b) as s from t2 group by a) as dt, + t3 + where dt.a=t1.a and t3.a < 3 + ) +from t1 limit 5; + +eval explain $q; +eval $q; + +truncate table t2; +insert into t2 select mod(seq,10), rand(15) * mod(seq,500) from seq_1_to_1000; + +analyze table t2 persistent for all; + +eval explain $q; +eval $q; + +drop table t1,t2,t3; + --echo # End of 10.4 tests diff --git a/sql/opt_split.cc b/sql/opt_split.cc index bb3aec9ee8d..6d816552baf 100644 --- a/sql/opt_split.cc +++ b/sql/opt_split.cc @@ -664,7 +664,8 @@ add_ext_keyuse_for_splitting(Dynamic_array *ext_keyuses, keyuse_ext.cond_guard= added_key_field->cond_guard; keyuse_ext.sj_pred_no= added_key_field->sj_pred_no; keyuse_ext.validity_ref= 0; - keyuse_ext.needed_in_prefix= added_key_field->val->used_tables(); + keyuse_ext.needed_in_prefix= added_key_field->val->used_tables() & + ~(OUTER_REF_TABLE_BIT | RAND_TABLE_BIT); keyuse_ext.validity_var= false; return ext_keyuses->push(keyuse_ext); } From 0fd54c98922a49a0a5ea5df6a4ca5320aaa82103 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 3 Jun 2023 10:15:18 +0200 Subject: [PATCH 04/17] Revert "MDEV-30473 : Do not allow GET_LOCK() / RELEASE_LOCK() in cluster" This reverts commit 844ddb1109410e0ab1d4444549932f1dddb7b845. This fixes MDEV-30967, MDEV-31325, MDEV-31388 --- .../suite/galera/r/galera_locks_funcs.result | 19 ------------------- .../suite/galera/t/galera_locks_funcs.test | 14 -------------- sql/item_create.cc | 14 -------------- 3 files changed, 47 deletions(-) delete mode 100644 mysql-test/suite/galera/r/galera_locks_funcs.result delete mode 100644 mysql-test/suite/galera/t/galera_locks_funcs.test diff --git a/mysql-test/suite/galera/r/galera_locks_funcs.result b/mysql-test/suite/galera/r/galera_locks_funcs.result deleted file mode 100644 index 378067aa461..00000000000 --- a/mysql-test/suite/galera/r/galera_locks_funcs.result +++ /dev/null @@ -1,19 +0,0 @@ -connection node_2; -connection node_1; -CREATE TABLE t (c DOUBLE,c2 INT,PRIMARY KEY(c)) ENGINE=InnoDB; -INSERT INTO t values (1,1); -SELECT GET_LOCK('a',1); -ERROR 42000: This version of MariaDB doesn't yet support 'GET_LOCK in cluster (WSREP_ON=ON)' -SHOW WARNINGS; -Level Code Message -Error 1235 This version of MariaDB doesn't yet support 'GET_LOCK in cluster (WSREP_ON=ON)' -SELECT * FROM t; -c c2 -1 1 -SELECT RELEASE_LOCK('a'); -ERROR 42000: This version of MariaDB doesn't yet support 'RELEASE_LOCK in cluster (WSREP_ON=ON)' -SHOW WARNINGS; -Level Code Message -Error 1235 This version of MariaDB doesn't yet support 'RELEASE_LOCK in cluster (WSREP_ON=ON)' -COMMIT; -DROP TABLE t; diff --git a/mysql-test/suite/galera/t/galera_locks_funcs.test b/mysql-test/suite/galera/t/galera_locks_funcs.test deleted file mode 100644 index 68737f2daab..00000000000 --- a/mysql-test/suite/galera/t/galera_locks_funcs.test +++ /dev/null @@ -1,14 +0,0 @@ ---source include/galera_cluster.inc - -CREATE TABLE t (c DOUBLE,c2 INT,PRIMARY KEY(c)) ENGINE=InnoDB; -INSERT INTO t values (1,1); ---error ER_NOT_SUPPORTED_YET -SELECT GET_LOCK('a',1); -SHOW WARNINGS; -SELECT * FROM t; ---error ER_NOT_SUPPORTED_YET -SELECT RELEASE_LOCK('a'); -SHOW WARNINGS; -COMMIT; -DROP TABLE t; - diff --git a/sql/item_create.cc b/sql/item_create.cc index 616ba3a641a..29d9563d1d1 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -4933,13 +4933,6 @@ Create_func_get_lock Create_func_get_lock::s_singleton; Item* Create_func_get_lock::create_2_arg(THD *thd, Item *arg1, Item *arg2) { -#ifdef WITH_WSREP - if (WSREP_ON && WSREP(thd)) - { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), "GET_LOCK in cluster (WSREP_ON=ON)"); - return NULL; - } -#endif /* WITH_WSREP */ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_get_lock(thd, arg1, arg2); @@ -6542,13 +6535,6 @@ Create_func_release_lock Create_func_release_lock::s_singleton; Item* Create_func_release_lock::create_1_arg(THD *thd, Item *arg1) { -#ifdef WITH_WSREP - if (WSREP_ON && WSREP(thd)) - { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), "RELEASE_LOCK in cluster (WSREP_ON=ON)"); - return NULL; - } -#endif /* WITH_WSREP */ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_release_lock(thd, arg1); From eb472f77e3f6696bbdbe48d15e71a2c444edc5e1 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 3 Jun 2023 10:35:59 +0200 Subject: [PATCH 05/17] Revert "MDEV-30473 : Do not allow GET_LOCK() / RELEASE_LOCK() in cluster" This reverts commit b05218e08f45a17f46d1b73cbb9dcb2969dc04cd. --- mysql-test/suite/galera/r/MDEV-24143.result | 23 ++++++++++++ .../galera/r/galera_bf_abort_get_lock.result | 18 ++++++++++ mysql-test/suite/galera/t/MDEV-24143.test | 20 +++++++++++ .../galera/t/galera_bf_abort_get_lock.test | 36 +++++++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 mysql-test/suite/galera/r/MDEV-24143.result create mode 100644 mysql-test/suite/galera/r/galera_bf_abort_get_lock.result create mode 100644 mysql-test/suite/galera/t/MDEV-24143.test create mode 100644 mysql-test/suite/galera/t/galera_bf_abort_get_lock.test diff --git a/mysql-test/suite/galera/r/MDEV-24143.result b/mysql-test/suite/galera/r/MDEV-24143.result new file mode 100644 index 00000000000..860d8a35834 --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-24143.result @@ -0,0 +1,23 @@ +connection node_2; +connection node_1; +CREATE TABLE t1 (c1 BIGINT NOT NULL PRIMARY KEY, c2 BINARY (10), c3 DATETIME); +SELECT get_lock ('test2', 0); +get_lock ('test2', 0) +1 +DROP TABLE t1; +CREATE TABLE t1 (c1 SMALLINT NOT NULL AUTO_INCREMENT PRIMARY KEY); +INSERT INTO t1 VALUES (1); +SET SESSION wsrep_trx_fragment_size=10; +SET SESSION autocommit=0; +SELECT * FROM t1 WHERE c1 <=0 ORDER BY c1 DESC; +c1 +INSERT INTO t1 VALUES (4),(3),(1),(2); +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +CREATE TABLE t1 (pk INT PRIMARY KEY, b INT) ENGINE=SEQUENCE; +ERROR 42S01: Table 't1' already exists +ALTER TABLE t1 DROP COLUMN c2; +ERROR 42000: Can't DROP COLUMN `c2`; check that it exists +SELECT get_lock ('test', 1.5); +get_lock ('test', 1.5) +1 +DROP TABLE t1; diff --git a/mysql-test/suite/galera/r/galera_bf_abort_get_lock.result b/mysql-test/suite/galera/r/galera_bf_abort_get_lock.result new file mode 100644 index 00000000000..0ef2a1a72c6 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_bf_abort_get_lock.result @@ -0,0 +1,18 @@ +connection node_2; +connection node_1; +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; +connection node_2a; +SELECT GET_LOCK("foo", 1000); +GET_LOCK("foo", 1000) +1 +connection node_2; +SET AUTOCOMMIT=OFF; +INSERT INTO t1 VALUES (1); +SELECT GET_LOCK("foo", 1000);; +connection node_1; +INSERT INTO t1 VALUES (1); +connection node_2; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +wsrep_local_aborts_increment +1 +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/MDEV-24143.test b/mysql-test/suite/galera/t/MDEV-24143.test new file mode 100644 index 00000000000..e58f147cb7c --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-24143.test @@ -0,0 +1,20 @@ +--source include/galera_cluster.inc +--source include/have_sequence.inc + +CREATE TABLE t1 (c1 BIGINT NOT NULL PRIMARY KEY, c2 BINARY (10), c3 DATETIME); +SELECT get_lock ('test2', 0); +DROP TABLE t1; +CREATE TABLE t1 (c1 SMALLINT NOT NULL AUTO_INCREMENT PRIMARY KEY); +INSERT INTO t1 VALUES (1); +SET SESSION wsrep_trx_fragment_size=10; +SET SESSION autocommit=0; +SELECT * FROM t1 WHERE c1 <=0 ORDER BY c1 DESC; +--error ER_LOCK_DEADLOCK +INSERT INTO t1 VALUES (4),(3),(1),(2); +--error ER_TABLE_EXISTS_ERROR +CREATE TABLE t1 (pk INT PRIMARY KEY, b INT) ENGINE=SEQUENCE; +--error ER_CANT_DROP_FIELD_OR_KEY +ALTER TABLE t1 DROP COLUMN c2; +SELECT get_lock ('test', 1.5); +DROP TABLE t1; + diff --git a/mysql-test/suite/galera/t/galera_bf_abort_get_lock.test b/mysql-test/suite/galera/t/galera_bf_abort_get_lock.test new file mode 100644 index 00000000000..72fc1c5b583 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_bf_abort_get_lock.test @@ -0,0 +1,36 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +# +# Test a local transaction being aborted by a slave one while it is running a GET_LOCK() +# + +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; + +--let $galera_connection_name = node_2a +--let $galera_server_number = 2 +--source include/galera_connect.inc +--connection node_2a +SELECT GET_LOCK("foo", 1000); + +--connection node_2 +SET AUTOCOMMIT=OFF; +--let $wsrep_local_bf_aborts_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'` +INSERT INTO t1 VALUES (1); +--send SELECT GET_LOCK("foo", 1000); + +--connection node_1 +INSERT INTO t1 VALUES (1); + +--connection node_2 +--error ER_LOCK_DEADLOCK +--reap + +--let $wsrep_local_bf_aborts_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'` + +# Check that wsrep_local_bf_aborts has been incremented by exactly 1 +--disable_query_log +--eval SELECT $wsrep_local_bf_aborts_after - $wsrep_local_bf_aborts_before = 1 AS wsrep_local_aborts_increment; +--enable_query_log + +DROP TABLE t1; From 318012a80a5b4365b4942edf2723742503a9fd1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 19 May 2023 12:19:26 +0300 Subject: [PATCH 06/17] MDEV-31234 InnoDB does not free UNDO after the fix of MDEV-30671 trx_purge_truncate_history(): Only call trx_purge_truncate_rseg_history() if the rollback segment is safe to process. This will avoid leaking undo log pages that are not yet ready to be processed. This fixes a regression that was introduced in commit 0de3be8cfdfc26f5c236eaefe12d03c7b4af22c8 (MDEV-30671). trx_sys_t::any_active_transactions(): Separately count XA PREPARE transactions. srv_purge_should_exit(): Terminate slow shutdown if the history size does not change and XA PREPARE transactions exist in the system. This will avoid a hang of the test innodb.recovery_shutdown. Tested by: Matthias Leich --- storage/innobase/include/trx0sys.h | 2 +- storage/innobase/srv/srv0srv.cc | 41 ++++++++++++++++++------------ storage/innobase/trx/trx0purge.cc | 10 +++----- storage/innobase/trx/trx0sys.cc | 24 +++++++++++++---- 4 files changed, 48 insertions(+), 29 deletions(-) diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index e033a3e1fe4..016ac0b1363 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -1055,7 +1055,7 @@ public: void close(); /** @return total number of active (non-prepared) transactions */ - ulint any_active_transactions(); + size_t any_active_transactions(size_t *prepared= nullptr); /** diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 57aa4bef9fe..50569f810ea 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -1697,7 +1697,7 @@ void srv_master_callback(void*) } /** @return whether purge should exit due to shutdown */ -static bool srv_purge_should_exit() +static bool srv_purge_should_exit(size_t old_history_size) { ut_ad(srv_shutdown_state <= SRV_SHUTDOWN_CLEANUP); @@ -1708,7 +1708,12 @@ static bool srv_purge_should_exit() return true; /* Slow shutdown was requested. */ - if (const size_t history_size= trx_sys.rseg_history_len) + size_t prepared, active= trx_sys.any_active_transactions(&prepared); + const size_t history_size= trx_sys.rseg_history_len; + + if (!history_size); + else if (!active && history_size == old_history_size && prepared); + else { static time_t progress_time; time_t now= time(NULL); @@ -1725,7 +1730,7 @@ static bool srv_purge_should_exit() return false; } - return !trx_sys.any_active_transactions(); + return !active; } /*********************************************************************//** @@ -1845,7 +1850,7 @@ static size_t srv_do_purge(ulint* n_total_purged) *n_total_purged += n_pages_purged; } while (n_pages_purged > 0 && !purge_sys.paused() - && !srv_purge_should_exit()); + && !srv_purge_should_exit(rseg_history_len)); return(rseg_history_len); } @@ -1960,7 +1965,7 @@ static void purge_coordinator_callback_low() } } while ((purge_sys.enabled() && !purge_sys.paused()) || - !srv_purge_should_exit()); + !srv_purge_should_exit(trx_sys.rseg_history_len)); } static void purge_coordinator_callback(void*) @@ -2031,15 +2036,19 @@ ulint srv_get_task_queue_length() /** Shut down the purge threads. */ void srv_purge_shutdown() { - if (purge_sys.enabled()) { - if (!srv_fast_shutdown && !opt_bootstrap) - srv_update_purge_thread_count(innodb_purge_threads_MAX); - while(!srv_purge_should_exit()) { - ut_a(!purge_sys.paused()); - srv_wake_purge_thread_if_not_active(); - purge_coordinator_task.wait(); - } - purge_sys.coordinator_shutdown(); - srv_shutdown_purge_tasks(); - } + if (purge_sys.enabled()) + { + if (!srv_fast_shutdown && !opt_bootstrap) + srv_update_purge_thread_count(innodb_purge_threads_MAX); + size_t history_size= trx_sys.rseg_history_len; + while (!srv_purge_should_exit(history_size)) + { + history_size= trx_sys.rseg_history_len; + ut_a(!purge_sys.paused()); + srv_wake_purge_thread_if_not_active(); + purge_coordinator_task.wait(); + } + purge_sys.coordinator_shutdown(); + srv_shutdown_purge_tasks(); + } } diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index b22a85f4646..97979a3fefe 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -448,12 +448,7 @@ func_exit: prev_hdr_addr.boffset = static_cast(prev_hdr_addr.boffset - TRX_UNDO_HISTORY_NODE); - if (!rseg.trx_ref_count - && rseg.needs_purge <= (purge_sys.head.trx_no - ? purge_sys.head.trx_no - : purge_sys.tail.trx_no) - && mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE - + block->frame) + if (mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + block->frame) == TRX_UNDO_TO_PURGE && !mach_read_from_2(block->frame + hdr_addr.boffset + TRX_UNDO_NEXT_LOG)) { @@ -544,7 +539,8 @@ static void trx_purge_truncate_history() ut_ad(rseg->id == i); ut_ad(rseg->is_persistent()); mutex_enter(&rseg->mutex); - trx_purge_truncate_rseg_history(*rseg, head); + if (!rseg->trx_ref_count && rseg->needs_purge <= head.trx_no) + trx_purge_truncate_rseg_history(*rseg, head); mutex_exit(&rseg->mutex); } } diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index bcde969eb41..ab3de55db64 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -325,15 +325,29 @@ trx_sys_t::close() } /** @return total number of active (non-prepared) transactions */ -ulint trx_sys_t::any_active_transactions() +size_t trx_sys_t::any_active_transactions(size_t *prepared) { - uint32_t total_trx= 0; + size_t total_trx= 0, prepared_trx= 0; - trx_sys.trx_list.for_each([&total_trx](const trx_t &trx) { - if (trx.state == TRX_STATE_COMMITTED_IN_MEMORY || - (trx.state == TRX_STATE_ACTIVE && trx.id)) + trx_sys.trx_list.for_each([&](const trx_t &trx) { + switch (trx.state) { + case TRX_STATE_NOT_STARTED: + break; + case TRX_STATE_ACTIVE: + if (!trx.id) + break; + /* fall through */ + case TRX_STATE_COMMITTED_IN_MEMORY: total_trx++; + break; + case TRX_STATE_PREPARED: + case TRX_STATE_PREPARED_RECOVERED: + prepared_trx++; + } }); + if (prepared) + *prepared= prepared_trx; + return total_trx; } From 48d6a5f61bde7065cc04a9d225514535780b34a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 24 May 2023 08:25:26 +0300 Subject: [PATCH 07/17] MDEV-31234 fixup: Free some UNDO pages earlier trx_purge_truncate_rseg_history(): Add a parameter to specify if the entire rollback segment is safe to be freed. If not, we may still be able to invoke trx_undo_truncate_start() and free some pages. --- storage/innobase/trx/trx0purge.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 97979a3fefe..c5ec42ecfce 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -399,12 +399,14 @@ void trx_purge_free_segment(mtr_t &mtr, trx_rseg_t* rseg, fil_addr_t hdr_addr) /** Remove unnecessary history data from a rollback segment. @param[in,out] rseg rollback segment -@param[in] limit truncate anything before this */ +@param[in] limit truncate anything before this +@param[in] all whether everything can be truncated */ static void trx_purge_truncate_rseg_history( trx_rseg_t& rseg, - const purge_sys_t::iterator& limit) + const purge_sys_t::iterator& limit, + bool all) { fil_addr_t hdr_addr; fil_addr_t prev_hdr_addr; @@ -443,6 +445,10 @@ func_exit: goto func_exit; } + if (!all) { + goto func_exit; + } + prev_hdr_addr = flst_get_prev_addr(block->frame + hdr_addr.boffset + TRX_UNDO_HISTORY_NODE); prev_hdr_addr.boffset = static_cast(prev_hdr_addr.boffset @@ -539,8 +545,9 @@ static void trx_purge_truncate_history() ut_ad(rseg->id == i); ut_ad(rseg->is_persistent()); mutex_enter(&rseg->mutex); - if (!rseg->trx_ref_count && rseg->needs_purge <= head.trx_no) - trx_purge_truncate_rseg_history(*rseg, head); + trx_purge_truncate_rseg_history(*rseg, head, + !rseg->trx_ref_count && + rseg->needs_purge <= head.trx_no); mutex_exit(&rseg->mutex); } } From 3b4b512d8e42bb3d33cf78789754cd10ff310646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 23 May 2023 12:20:27 +0300 Subject: [PATCH 08/17] MDEV-31234 fixup: Allow innodb_undo_log_truncate=ON after upgrade trx_purge_truncate_history(): Relax a condition that would prevent undo log truncation if the undo log tablespaces were "contaminated" by the bug that commit e0084b9d315f10e3ceb578b65e144d751b208bf1 fixed. That is, trx_purge_truncate_rseg_history() would have invoked flst_remove() on TRX_RSEG_HISTORY but not reduced TRX_RSEG_HISTORY_SIZE. To avoid any regression with normal operation, we implement this fixup during slow shutdown only. The condition on the history list being empty is necessary: without it, in the test innodb.undo_truncate_recover there may be much fewer than the expected 90,000 calls to row_purge() before the truncation. That is, we would truncate the undo tablespace before actually having processed all undo log records in it. To truncate such "contaminated" or "bloated" undo log tablespaces (when using innodb_undo_tablespaces=2 or more) you can execute the following SQL: BEGIN;INSERT mysql.innodb_table_stats VALUES('','',DEFAULT,0,0,0);ROLLBACK; SET GLOBAL innodb_undo_log_truncate=ON, innodb_fast_shutdown=0; SHUTDOWN; The first line creates a dummy InnoDB transaction, to ensure that there will be some history to be purged during shutdown and that the undo tablespaces will be truncated. --- storage/innobase/trx/trx0purge.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index c5ec42ecfce..2f21a4de1e6 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -626,7 +626,8 @@ static void trx_purge_truncate_history() ut_ad(rseg->curr_size > cached); - if (rseg->curr_size > cached + 1) + if (rseg->curr_size > cached + 1 && + (srv_fast_shutdown || srv_undo_sources || trx_sys.rseg_history_len)) goto not_free; mutex_exit(&rseg->mutex); From e89bd39c9b9c85454c3db21458b361a116100eb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 26 May 2023 16:16:10 +0300 Subject: [PATCH 09/17] MDEV-31343 Another server hang with innodb_undo_log_truncate=ON trx_purge_truncate_history(): While waiting for a write-fixed block to become available, simply wait for an exclusive latch on it. Also, simplify the iteration: first check for oldest_modification>2 (to ignore clean pages or pages belonging to the temporary tablespace) and then compare the tablespace identifier. Before releasing buf_pool.flush_list_mutex we will buffer-fix the block of interest. In that way, buf_page_t::can_relocate() will not hold on the block and it must remain in the buffer pool until we have acquired an exclusive latch on it. If the block is still dirty, we will register it with the tablespace truncation mini-transaction; else, we will simply release the latch and buffer-fix and move to the next block. This also reverts commit c4d79399895827c592d12b7be4b7ef21443d3a0f because that fix should no longer be necessary; the wait for an exclusive block latch should allow buf_pool_t::release_freed_page() on the same block to proceed. Tested by: Axel Schwenke, Matthias Leich --- storage/innobase/trx/trx0purge.cc | 42 ++++++++++++++++--------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index b04e71ba871..4b4afab5ef6 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -706,6 +706,7 @@ not_free: mtr_t mtr; mtr.start(); mtr.x_lock_space(&space); + const auto space_id= space.id; /* Lock all modified pages of the tablespace. @@ -715,8 +716,8 @@ not_free: mini-transaction commit and the server was killed, then discarding the to-be-trimmed pages without flushing would break crash recovery. */ + rescan: mysql_mutex_lock(&buf_pool.flush_list_mutex); - for (buf_page_t *bpage= UT_LIST_GET_LAST(buf_pool.flush_list); bpage; ) { ut_ad(bpage->oldest_modification()); @@ -724,46 +725,47 @@ not_free: buf_page_t *prev= UT_LIST_GET_PREV(list, bpage); - if (bpage->id().space() == space.id && - bpage->oldest_modification() != 1) + if (bpage->oldest_modification() > 2 && bpage->id().space() == space_id) { ut_ad(bpage->frame); - auto block= reinterpret_cast(bpage); - if (!bpage->lock.x_lock_try()) + bpage->fix(); { - rescan: - /* Let buf_pool_t::release_freed_page() proceed. */ + /* Try to acquire an exclusive latch while the cache line is + fresh after fix(). */ + const bool got_lock{bpage->lock.x_lock_try()}; + buf_pool.flush_hp.set(prev); mysql_mutex_unlock(&buf_pool.flush_list_mutex); - mysql_mutex_lock(&buf_pool.mutex); - mysql_mutex_lock(&buf_pool.flush_list_mutex); - mysql_mutex_unlock(&buf_pool.mutex); - bpage= UT_LIST_GET_LAST(buf_pool.flush_list); - continue; + if (!got_lock) + bpage->lock.x_lock(); } - buf_pool.flush_hp.set(prev); - mysql_mutex_unlock(&buf_pool.flush_list_mutex); #ifdef BTR_CUR_HASH_ADAPT - ut_ad(!block->index); /* There is no AHI on undo tablespaces. */ + /* There is no AHI on undo tablespaces. */ + ut_ad(!reinterpret_cast(bpage)->index); #endif - bpage->fix(); ut_ad(!bpage->is_io_fixed()); - mysql_mutex_lock(&buf_pool.flush_list_mutex); + ut_ad(bpage->id().space() == space_id); - if (bpage->oldest_modification() > 1) + if (bpage->oldest_modification() > 2) { + mtr.memo_push(reinterpret_cast(bpage), + MTR_MEMO_PAGE_X_FIX); + mysql_mutex_lock(&buf_pool.flush_list_mutex); + ut_ad(bpage->oldest_modification() > 2); bpage->reset_oldest_modification(); - mtr.memo_push(block, MTR_MEMO_PAGE_X_FIX); } else { bpage->unfix(); bpage->lock.x_unlock(); + mysql_mutex_lock(&buf_pool.flush_list_mutex); } if (prev != buf_pool.flush_hp.get()) - /* Rescan, because we may have lost the position. */ + { + mysql_mutex_unlock(&buf_pool.flush_list_mutex); goto rescan; + } } bpage= prev; From 459eb9a68646a73033336f46fd7ce7f510e1767b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 22 May 2023 17:10:25 +0300 Subject: [PATCH 10/17] MDEV-29593 fixup: Avoid a leak if rseg.undo_cached is corrupted trx_purge_truncate_rseg_history(): Avoid a leak similar to the one that was fixed in MDEV-31324, in case a supposedly cached undo log page is not found in the rseg.undo_cached list. --- storage/innobase/trx/trx0purge.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 4b4afab5ef6..17666ddbd64 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -510,9 +510,9 @@ loop: if (undo->hdr_page_no == hdr_addr.page) goto found_cached; ut_ad("inconsistent undo logs" == 0); - break; - found_cached: - UT_LIST_REMOVE(rseg.undo_cached, undo); + if (false) + found_cached: + UT_LIST_REMOVE(rseg.undo_cached, undo); static_assert(FIL_NULL == 0xffffffff, ""); if (UNIV_UNLIKELY(mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT + rseg_hdr->page.frame))) From 883333a74eb4b8d88b765dd5a111c24400996e6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 11 May 2023 08:43:00 +0300 Subject: [PATCH 11/17] MDEV-31158: Potential hang with ROW_FORMAT=COMPRESSED tables btr_cur_need_opposite_intention(): Check also page_zip_available() so that we will escalate to exclusive index latch when a non-leaf page may have to be split further due to ROW_FORMAT=COMPRESSED page overflow. Tested by: Matthias Leich --- .../suite/innodb_zip/r/page_size.result | 21 +++++++++++++++ mysql-test/suite/innodb_zip/t/page_size.test | 24 +++++++++++++++++ storage/innobase/btr/btr0cur.cc | 27 ++++++++++++------- 3 files changed, 63 insertions(+), 9 deletions(-) diff --git a/mysql-test/suite/innodb_zip/r/page_size.result b/mysql-test/suite/innodb_zip/r/page_size.result index 47effe06884..48b954c945b 100644 --- a/mysql-test/suite/innodb_zip/r/page_size.result +++ b/mysql-test/suite/innodb_zip/r/page_size.result @@ -608,4 +608,25 @@ SET GLOBAL innodb_compression_level=0; INSERT INTO t1 VALUES (''); SET GLOBAL innodb_compression_level= @save_innodb_compression_level; DROP TABLE t1; +# +# MDEV-31158 Assertion ...MTR_MEMO_X_LOCKED in btr_attach_half_pages() +# +SET @save_compression_level=@@GLOBAL.innodb_compression_level; +SET GLOBAL innodb_compression_level=0; +CREATE TEMPORARY TABLE t(a SERIAL, prefix VARBINARY(4), pad INT); +INSERT INTO t(prefix, pad) VALUES +(_binary 0xff,160),('',19),(_binary 0x0001,253),(_binary 0x0b11,169), +(_binary 0x0b010001,23),(_binary 0x0b100001,251),(_binary 0x0d,163), +(_binary 0xb3,254),(_binary 0x96,254),(_binary 0xeb,61), +(_binary 0xf231,253),(_binary 0x1db0,253),(_binary 0x0005,101), +(_binary 0x6370,253),(_binary 0x0b12,112),(_binary 0x0b010002,23), +(_binary 0x0b100002,80),(_binary 0x181984,163),(_binary 0x181926,168), +(_binary 0xe1,176),(_binary 0xe2,187),(_binary 0xe6,254),(_binary 0xbb,51), +(_binary 0x1c,248),(_binary 0x8a,94),(_binary 0x14,254); +CREATE TABLE u(a SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, +b VARBINARY(255), KEY(b)) ENGINE=InnoDB +KEY_BLOCK_SIZE=1 ROW_FORMAT=COMPRESSED; +INSERT INTO u SELECT a,CONCAT(prefix,REPEAT(chr(0),pad)) FROM t; +DROP TABLE u, t; +SET GLOBAL innodb_compression_level=@save_compression_level; # End of 10.6 tests diff --git a/mysql-test/suite/innodb_zip/t/page_size.test b/mysql-test/suite/innodb_zip/t/page_size.test index 16d65a139cf..3455ef8ed94 100644 --- a/mysql-test/suite/innodb_zip/t/page_size.test +++ b/mysql-test/suite/innodb_zip/t/page_size.test @@ -888,4 +888,28 @@ INSERT INTO t1 VALUES (''); SET GLOBAL innodb_compression_level= @save_innodb_compression_level; DROP TABLE t1; +--echo # +--echo # MDEV-31158 Assertion ...MTR_MEMO_X_LOCKED in btr_attach_half_pages() +--echo # +--source include/have_innodb.inc + +SET @save_compression_level=@@GLOBAL.innodb_compression_level; +SET GLOBAL innodb_compression_level=0; +CREATE TEMPORARY TABLE t(a SERIAL, prefix VARBINARY(4), pad INT); +INSERT INTO t(prefix, pad) VALUES +(_binary 0xff,160),('',19),(_binary 0x0001,253),(_binary 0x0b11,169), +(_binary 0x0b010001,23),(_binary 0x0b100001,251),(_binary 0x0d,163), +(_binary 0xb3,254),(_binary 0x96,254),(_binary 0xeb,61), +(_binary 0xf231,253),(_binary 0x1db0,253),(_binary 0x0005,101), +(_binary 0x6370,253),(_binary 0x0b12,112),(_binary 0x0b010002,23), +(_binary 0x0b100002,80),(_binary 0x181984,163),(_binary 0x181926,168), +(_binary 0xe1,176),(_binary 0xe2,187),(_binary 0xe6,254),(_binary 0xbb,51), +(_binary 0x1c,248),(_binary 0x8a,94),(_binary 0x14,254); +CREATE TABLE u(a SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, + b VARBINARY(255), KEY(b)) ENGINE=InnoDB + KEY_BLOCK_SIZE=1 ROW_FORMAT=COMPRESSED; +INSERT INTO u SELECT a,CONCAT(prefix,REPEAT(chr(0),pad)) FROM t; +DROP TABLE u, t; +SET GLOBAL innodb_compression_level=@save_compression_level; + --echo # End of 10.6 tests diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 70b0ae4c32c..784e32a11c1 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -748,18 +748,24 @@ btr_cur_will_modify_tree( /** Detects whether the modifying record might need a opposite modification to the intention. -@param page page -@param lock_intention lock intention for the tree operation +@param bpage buffer pool page +@param is_clust whether this is a clustered index +@param lock_intention lock intention for the tree operation @param node_ptr_max_size the maximum size of a node pointer @param compress_limit BTR_CUR_PAGE_COMPRESS_LIMIT(index) -@param rec record (current node_ptr) -@return true if tree modification is needed */ -static bool btr_cur_need_opposite_intention(const page_t *page, +@param rec record (current node_ptr) +@return true if tree modification is needed */ +static bool btr_cur_need_opposite_intention(const buf_page_t &bpage, + bool is_clust, btr_intention_t lock_intention, ulint node_ptr_max_size, ulint compress_limit, const rec_t *rec) { + if (UNIV_LIKELY_NULL(bpage.zip.data) && + !page_zip_available(&bpage.zip, is_clust, node_ptr_max_size, 1)) + return true; + const page_t *const page= bpage.frame; if (lock_intention != BTR_INTENTION_INSERT) { /* We compensate also for btr_cur_compress_recommendation() */ @@ -1342,7 +1348,8 @@ release_tree: !btr_block_get(*index(), btr_page_get_next(block->page.frame), RW_X_LATCH, false, mtr, &err)) goto func_exit; - if (btr_cur_need_opposite_intention(block->page.frame, lock_intention, + if (btr_cur_need_opposite_intention(block->page, index()->is_clust(), + lock_intention, node_ptr_max_size, compress_limit, page_cur.rec)) goto need_opposite_intention; @@ -1398,7 +1405,8 @@ release_tree: default: break; case BTR_MODIFY_TREE: - if (btr_cur_need_opposite_intention(block->page.frame, lock_intention, + if (btr_cur_need_opposite_intention(block->page, index()->is_clust(), + lock_intention, node_ptr_max_size, compress_limit, page_cur.rec)) /* If the rec is the first or last in the page for pessimistic @@ -1948,7 +1956,7 @@ index_locked: break; if (!index->lock.have_x() && - btr_cur_need_opposite_intention(block->page.frame, + btr_cur_need_opposite_intention(block->page, index->is_clust(), lock_intention, node_ptr_max_size, compress_limit, page_cur.rec)) @@ -1995,7 +2003,8 @@ index_locked: ut_ad(latch_mode != BTR_MODIFY_TREE || upper_rw_latch == RW_X_LATCH); if (latch_mode != BTR_MODIFY_TREE); - else if (btr_cur_need_opposite_intention(block->page.frame, lock_intention, + else if (btr_cur_need_opposite_intention(block->page, index->is_clust(), + lock_intention, node_ptr_max_size, compress_limit, page_cur.rec)) { From 89eb6fa8a7f0d76c9b24e28646e1fe3401b5f4c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 19 May 2023 15:29:26 +0300 Subject: [PATCH 12/17] MDEV-31308 InnoDB monitor trx_rseg_history_len was accidentally disabled by default innodb_counter_info[]: Revert a change that was accidentally made in commit 204e7225dce32130ac2c96f469611d2cb421241e --- mysql-test/suite/innodb/r/monitor.result | 138 ++++++++++++----------- mysql-test/suite/innodb/t/monitor.test | 4 +- storage/innobase/srv/srv0mon.cc | 2 +- 3 files changed, 74 insertions(+), 70 deletions(-) diff --git a/mysql-test/suite/innodb/r/monitor.result b/mysql-test/suite/innodb/r/monitor.result index c874a84d26b..22e6fbea1e3 100644 --- a/mysql-test/suite/innodb/r/monitor.result +++ b/mysql-test/suite/innodb/r/monitor.result @@ -1,10 +1,9 @@ -set global innodb_monitor_disable = All; select name, if(enabled,'enabled','disabled') status from information_schema.innodb_metrics; name status metadata_table_handles_opened disabled -lock_deadlocks disabled -lock_timeouts disabled +lock_deadlocks enabled +lock_timeouts enabled lock_rec_lock_waits disabled lock_table_lock_waits disabled lock_rec_lock_requests disabled @@ -14,32 +13,32 @@ lock_rec_locks disabled lock_table_lock_created disabled lock_table_lock_removed disabled lock_table_locks disabled -lock_row_lock_current_waits disabled -lock_row_lock_time disabled -lock_row_lock_time_max disabled -lock_row_lock_waits disabled -lock_row_lock_time_avg disabled -buffer_pool_size disabled -buffer_pool_reads disabled -buffer_pool_read_requests disabled -buffer_pool_write_requests disabled -buffer_pool_wait_free disabled -buffer_pool_read_ahead disabled -buffer_pool_read_ahead_evicted disabled -buffer_pool_pages_total disabled -buffer_pool_pages_misc disabled -buffer_pool_pages_data disabled -buffer_pool_bytes_data disabled -buffer_pool_pages_dirty disabled -buffer_pool_bytes_dirty disabled -buffer_pool_pages_free disabled -buffer_pages_created disabled -buffer_pages_written disabled -buffer_pages_read disabled -buffer_index_sec_rec_cluster_reads disabled -buffer_index_sec_rec_cluster_reads_avoided disabled -buffer_data_reads disabled -buffer_data_written disabled +lock_row_lock_current_waits enabled +lock_row_lock_time enabled +lock_row_lock_time_max enabled +lock_row_lock_waits enabled +lock_row_lock_time_avg enabled +buffer_pool_size enabled +buffer_pool_reads enabled +buffer_pool_read_requests enabled +buffer_pool_write_requests enabled +buffer_pool_wait_free enabled +buffer_pool_read_ahead enabled +buffer_pool_read_ahead_evicted enabled +buffer_pool_pages_total enabled +buffer_pool_pages_misc enabled +buffer_pool_pages_data enabled +buffer_pool_bytes_data enabled +buffer_pool_pages_dirty enabled +buffer_pool_bytes_dirty enabled +buffer_pool_pages_free enabled +buffer_pages_created enabled +buffer_pages_written enabled +buffer_pages_read enabled +buffer_index_sec_rec_cluster_reads enabled +buffer_index_sec_rec_cluster_reads_avoided enabled +buffer_data_reads enabled +buffer_data_written enabled buffer_flush_batch_scanned disabled buffer_flush_batch_num_scan disabled buffer_flush_batch_scanned_per_call disabled @@ -72,8 +71,8 @@ buffer_flush_background_pages disabled buffer_LRU_batch_scanned disabled buffer_LRU_batch_num_scan disabled buffer_LRU_batch_scanned_per_call disabled -buffer_LRU_batch_flush_total_pages disabled -buffer_LRU_batch_evict_total_pages disabled +buffer_LRU_batch_flush_total_pages enabled +buffer_LRU_batch_evict_total_pages enabled buffer_LRU_single_flush_failure_count disabled buffer_LRU_get_free_search disabled buffer_LRU_search_scanned disabled @@ -114,24 +113,24 @@ buffer_page_written_blob disabled buffer_page_written_zblob disabled buffer_page_written_zblob2 disabled buffer_page_written_other disabled -os_data_reads disabled -os_data_writes disabled -os_data_fsyncs disabled -os_pending_reads disabled -os_pending_writes disabled -os_log_bytes_written disabled -os_log_fsyncs disabled -os_log_pending_fsyncs disabled -os_log_pending_writes disabled +os_data_reads enabled +os_data_writes enabled +os_data_fsyncs enabled +os_pending_reads enabled +os_pending_writes enabled +os_log_bytes_written enabled +os_log_fsyncs enabled +os_log_pending_fsyncs enabled +os_log_pending_writes enabled trx_rw_commits disabled trx_ro_commits disabled trx_nl_ro_commits disabled trx_commits_insert_update disabled trx_rollbacks disabled trx_rollbacks_savepoint disabled -trx_rseg_history_len disabled +trx_rseg_history_len enabled trx_undo_slots_used disabled -trx_undo_slots_cached disabled +trx_undo_slots_cached enabled trx_rseg_current_size disabled purge_del_mark_records disabled purge_upd_exist_or_extern_records disabled @@ -150,10 +149,10 @@ log_max_modified_age_async disabled log_pending_log_flushes disabled log_pending_checkpoint_writes disabled log_num_log_io disabled -log_waits disabled -log_write_requests disabled -log_writes disabled -log_padded disabled +log_waits enabled +log_write_requests enabled +log_writes enabled +log_padded enabled compress_pages_compressed disabled compress_pages_decompressed disabled compression_pad_increments disabled @@ -171,42 +170,42 @@ index_page_merge_successful disabled index_page_reorg_attempts disabled index_page_reorg_successful disabled index_page_discards disabled -adaptive_hash_searches disabled -adaptive_hash_searches_btree disabled +adaptive_hash_searches enabled +adaptive_hash_searches_btree enabled adaptive_hash_pages_added disabled adaptive_hash_pages_removed disabled adaptive_hash_rows_added disabled adaptive_hash_rows_removed disabled adaptive_hash_rows_deleted_no_hash_entry disabled adaptive_hash_rows_updated disabled -file_num_open_files disabled -ibuf_merges_insert disabled -ibuf_merges_delete_mark disabled -ibuf_merges_delete disabled -ibuf_merges_discard_insert disabled -ibuf_merges_discard_delete_mark disabled -ibuf_merges_discard_delete disabled -ibuf_merges disabled -ibuf_size disabled +file_num_open_files enabled +ibuf_merges_insert enabled +ibuf_merges_delete_mark enabled +ibuf_merges_delete enabled +ibuf_merges_discard_insert enabled +ibuf_merges_discard_delete_mark enabled +ibuf_merges_discard_delete enabled +ibuf_merges enabled +ibuf_size enabled innodb_master_thread_sleeps disabled -innodb_activity_count disabled +innodb_activity_count enabled innodb_master_active_loops disabled innodb_master_idle_loops disabled innodb_log_flush_usec disabled innodb_dict_lru_usec disabled innodb_dict_lru_count_active disabled innodb_dict_lru_count_idle disabled -innodb_dblwr_writes disabled -innodb_dblwr_pages_written disabled -innodb_page_size disabled +innodb_dblwr_writes enabled +innodb_dblwr_pages_written enabled +innodb_page_size enabled dml_reads disabled -dml_inserts disabled -dml_deletes disabled -dml_updates disabled -dml_system_reads disabled -dml_system_inserts disabled -dml_system_deletes disabled -dml_system_updates disabled +dml_inserts enabled +dml_deletes enabled +dml_updates enabled +dml_system_reads enabled +dml_system_inserts enabled +dml_system_deletes enabled +dml_system_updates enabled ddl_background_drop_indexes disabled ddl_online_create_index disabled ddl_pending_alter_table disabled @@ -216,6 +215,9 @@ icp_attempts disabled icp_no_match disabled icp_out_of_range disabled icp_match disabled +set global innodb_monitor_disable = All; +select name from information_schema.innodb_metrics where enabled; +name set global innodb_monitor_enable = all; select name from information_schema.innodb_metrics where not enabled; name diff --git a/mysql-test/suite/innodb/t/monitor.test b/mysql-test/suite/innodb/t/monitor.test index d6fa3f2fbc9..65a93e5a97a 100644 --- a/mysql-test/suite/innodb/t/monitor.test +++ b/mysql-test/suite/innodb/t/monitor.test @@ -5,12 +5,14 @@ # sys_vars.innodb_monitor_enable_basic --source include/have_innodb.inc -set global innodb_monitor_disable = All; # Test turn on/off the monitor counter with "all" option # By default, they will be off. select name, if(enabled,'enabled','disabled') status from information_schema.innodb_metrics; +set global innodb_monitor_disable = All; +select name from information_schema.innodb_metrics where enabled; + # Turn on all monitor counters set global innodb_monitor_enable = all; diff --git a/storage/innobase/srv/srv0mon.cc b/storage/innobase/srv/srv0mon.cc index 971f4f330c8..3065ab19462 100644 --- a/storage/innobase/srv/srv0mon.cc +++ b/storage/innobase/srv/srv0mon.cc @@ -704,7 +704,7 @@ static monitor_info_t innodb_counter_info[] = {"trx_rseg_history_len", "transaction", "Length of the TRX_RSEG_HISTORY list", static_cast( - MONITOR_EXISTING | MONITOR_DISPLAY_CURRENT), + MONITOR_EXISTING | MONITOR_DISPLAY_CURRENT | MONITOR_DEFAULT_ON), MONITOR_DEFAULT_START, MONITOR_RSEG_HISTORY_LEN}, {"trx_undo_slots_used", "transaction", "Number of undo slots used", From dd298873daf1681aaa3269e0e88a9344bcb2bfdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 19 May 2023 15:38:48 +0300 Subject: [PATCH 13/17] MDEV-31309 Innodb_buffer_pool_read_requests is not updated correctly srv_export_innodb_status(): Update export_vars.innodb_buffer_pool_read_requests as it was done before commit a55b951e6082a4ce9a1f2ed5ee176ea7dbbaf1f2 (MDEV-26827). If innodb_status_variables[] pointed to a sharded variable, it would only access the first shard. --- storage/innobase/handler/ha_innodb.cc | 3 ++- storage/innobase/include/srv0srv.h | 2 ++ storage/innobase/srv/srv0srv.cc | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 0b117c02e29..2937ca40752 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -946,7 +946,8 @@ static SHOW_VAR innodb_status_variables[]= { {"buffer_pool_read_ahead", &buf_pool.stat.n_ra_pages_read, SHOW_SIZE_T}, {"buffer_pool_read_ahead_evicted", &buf_pool.stat.n_ra_pages_evicted, SHOW_SIZE_T}, - {"buffer_pool_read_requests", &buf_pool.stat.n_page_gets, SHOW_SIZE_T}, + {"buffer_pool_read_requests", + &export_vars.innodb_buffer_pool_read_requests, SHOW_SIZE_T}, {"buffer_pool_reads", &buf_pool.stat.n_pages_read, SHOW_SIZE_T}, {"buffer_pool_wait_free", &buf_pool.stat.LRU_waits, SHOW_SIZE_T}, {"buffer_pool_write_requests", diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 96cfe886c02..c4c854f6b9c 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -674,6 +674,8 @@ struct export_var_t{ #ifdef UNIV_DEBUG ulint innodb_buffer_pool_pages_latched; /*!< Latched pages */ #endif /* UNIV_DEBUG */ + /** buf_pool.stat.n_page_gets (a sharded counter) */ + ulint innodb_buffer_pool_read_requests; ulint innodb_buffer_pool_write_requests;/*!< srv_stats.buf_pool_write_requests */ ulint innodb_checkpoint_age; ulint innodb_checkpoint_max_age; diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index f87c748bb67..0ce75fe84da 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -1011,6 +1011,9 @@ srv_export_innodb_status(void) export_vars.innodb_data_written = srv_stats.data_written + (dblwr << srv_page_size_shift); + export_vars.innodb_buffer_pool_read_requests + = buf_pool.stat.n_page_gets; + export_vars.innodb_buffer_pool_write_requests = srv_stats.buf_pool_write_requests; From cf37e44eecca75bdabe139056587a81c2e5af6e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 26 May 2023 16:40:07 +0300 Subject: [PATCH 14/17] MDEV-31350: Hang in innodb.recovery_memory buf_flush_page_cleaner(): Whenever buf_pool.ran_out(), invoke buf_pool.get_oldest_modification(0) so that all clean blocks will be removed from buf_pool.flush_list and buf_flush_LRU_list_batch() will be able to evict some pages. This fixes a regression that was likely caused by commit a55b951e6082a4ce9a1f2ed5ee176ea7dbbaf1f2 (MDEV-26827). --- storage/innobase/buf/buf0flu.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index 73fc2957ebb..fedade950ab 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -2322,6 +2322,7 @@ static void buf_flush_page_cleaner() else if (buf_pool.ran_out()) { buf_pool.page_cleaner_set_idle(false); + buf_pool.get_oldest_modification(0); mysql_mutex_unlock(&buf_pool.flush_list_mutex); n= srv_max_io_capacity; mysql_mutex_lock(&buf_pool.mutex); From fcfd6361cb752fc53ade2811f9f5f82fd515d586 Mon Sep 17 00:00:00 2001 From: Otto Kekalainen Date: Sat, 27 May 2023 22:42:59 -0700 Subject: [PATCH 15/17] Deb: Fix blocksize check to use $mysql_datadir/$datadir correctly In commit f99a8918 this line was changed to not use awk, and new version copied both to init file and preinst file but overlooking that they use different variable names. Also fix minor syntax issues to make Shellcheck happy. All new code of the whole pull request, including one or several files that are either new files or modified ones, are contributed under the BSD-new license. I am contributing on behalf of my employer Amazon Web Services, Inc. --- debian/mariadb-server-10.6.mariadb.init | 2 +- debian/mariadb-server-10.6.preinst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/mariadb-server-10.6.mariadb.init b/debian/mariadb-server-10.6.mariadb.init index b2b7142084f..f68fbc99bc2 100644 --- a/debian/mariadb-server-10.6.mariadb.init +++ b/debian/mariadb-server-10.6.mariadb.init @@ -86,7 +86,7 @@ sanity_checks() { datadir=`mariadbd_get_param datadir` # As preset blocksize of GNU df is 1024 then available bytes is $df_available_blocks * 1024 # 4096 blocks is then lower than 4 MB - df_available_blocks=`LC_ALL=C BLOCKSIZE= df --output=avail "$datadir" | tail -n 1` + df_available_blocks="$(LC_ALL=C BLOCKSIZE='' df --output=avail "$datadir" | tail -n 1)" if [ "$df_available_blocks" -lt "4096" ]; then log_failure_msg "$0: ERROR: The partition with $datadir is too full!" echo "ERROR: The partition with $datadir is too full!" | $ERR_LOGGER diff --git a/debian/mariadb-server-10.6.preinst b/debian/mariadb-server-10.6.preinst index c865173e29e..92b8505e421 100644 --- a/debian/mariadb-server-10.6.preinst +++ b/debian/mariadb-server-10.6.preinst @@ -211,7 +211,7 @@ fi # As preset blocksize of GNU df is 1024 then available bytes is $df_available_blocks * 1024 # 4096 blocks is then lower than 4 MB -df_available_blocks=`LC_ALL=C BLOCKSIZE= df --output=avail "$datadir" | tail -n 1` +df_available_blocks="$(LC_ALL=C BLOCKSIZE='' df --output=avail "$mysql_datadir" | tail -n 1)" if [ "$df_available_blocks" -lt "4096" ]; then echo "ERROR: There's not enough space in $mysql_datadir/" 1>&2 db_stop From 928012a27ae2d1549f1b3e6975b9d22652bbea3a Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Mon, 5 Jun 2023 16:40:08 +0300 Subject: [PATCH 16/17] MDEV-31403: Server crashes in st_join_table::choose_best_splitting The code in choose_best_splitting() assumed that the join prefix is in join->positions[]. This is not necessarily the case. This function might be called when the join prefix is in join->best_positions[], too. Follow the approach from best_access_path(), which calls this function: pass the current join prefix as an argument, "const POSITION *join_positions" and use that. --- mysql-test/main/derived_split_innodb.result | 15 +++++++++++++++ mysql-test/main/derived_split_innodb.test | 21 +++++++++++++++++++++ sql/opt_split.cc | 3 ++- sql/sql_select.cc | 1 + sql/sql_select.h | 1 + 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/derived_split_innodb.result b/mysql-test/main/derived_split_innodb.result index 736e6a2c020..bea2271eaf3 100644 --- a/mysql-test/main/derived_split_innodb.result +++ b/mysql-test/main/derived_split_innodb.result @@ -810,4 +810,19 @@ SELECT t1.* FROM t1 JOIN (SELECT id, COUNT(*) FROM t2 GROUP BY id) sq ON sq.id= a set optimizer_switch= @tmp1, join_cache_level= @tmp2; DROP TABLE t1, t2; +# +# MDEV-31403: Server crashes in st_join_table::choose_best_splitting (still) +# +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES +(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15); +CREATE TABLE t2 (b INT) ENGINE=InnoDB; +INSERT INTO t2 VALUES (100),(200); +CREATE TABLE t3 (c INT, d INT, KEY(c)) ENGINE=InnoDB; +INSERT INTO t3 VALUES (1,1),(2,2); +CREATE VIEW v AS SELECT c, d FROM t3 GROUP BY c, d; +SELECT * FROM t1 JOIN t2 WHERE (t1.a, t2.b) IN (SELECT * FROM v); +a b +DROP VIEW v; +DROP TABLE t1, t2, t3; # End of 10.4 tests diff --git a/mysql-test/main/derived_split_innodb.test b/mysql-test/main/derived_split_innodb.test index b8dd5ad20e1..3c51f54fe02 100644 --- a/mysql-test/main/derived_split_innodb.test +++ b/mysql-test/main/derived_split_innodb.test @@ -462,4 +462,25 @@ set optimizer_switch= @tmp1, join_cache_level= @tmp2; # Cleanup DROP TABLE t1, t2; +--echo # +--echo # MDEV-31403: Server crashes in st_join_table::choose_best_splitting (still) +--echo # +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES + (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15); + +CREATE TABLE t2 (b INT) ENGINE=InnoDB; +INSERT INTO t2 VALUES (100),(200); + +CREATE TABLE t3 (c INT, d INT, KEY(c)) ENGINE=InnoDB; +INSERT INTO t3 VALUES (1,1),(2,2); + +CREATE VIEW v AS SELECT c, d FROM t3 GROUP BY c, d; + +SELECT * FROM t1 JOIN t2 WHERE (t1.a, t2.b) IN (SELECT * FROM v); + +# Cleanup +DROP VIEW v; +DROP TABLE t1, t2, t3; + --echo # End of 10.4 tests diff --git a/sql/opt_split.cc b/sql/opt_split.cc index 6d816552baf..89ffe35aba1 100644 --- a/sql/opt_split.cc +++ b/sql/opt_split.cc @@ -948,6 +948,7 @@ void reset_validity_vars_for_keyuses(KEYUSE_EXT *key_keyuse_ext_start, SplM_plan_info * JOIN_TAB::choose_best_splitting(uint idx, table_map remaining_tables, + const POSITION *join_positions, table_map *spl_pd_boundary) { SplM_opt_info *spl_opt_info= table->spl_opt_info; @@ -1045,7 +1046,7 @@ SplM_plan_info * JOIN_TAB::choose_best_splitting(uint idx, else { table_map last_found= this->table->map; - for (POSITION *pos= &this->join->positions[idx - 1]; ; pos--) + for (const POSITION *pos= &join_positions[idx - 1]; ; pos--) { if (pos->table->table->map & excluded_tables) continue; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index cb60b3442d8..2834c771ca3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7452,6 +7452,7 @@ best_access_path(JOIN *join, if (s->table->is_splittable()) spl_plan= s->choose_best_splitting(idx, remaining_tables, + join_positions, &spl_pd_boundary); Json_writer_array trace_paths(thd, "considered_access_paths"); diff --git a/sql/sql_select.h b/sql/sql_select.h index f4b266292c9..37c784fc9b9 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -694,6 +694,7 @@ typedef struct st_join_table { void add_keyuses_for_splitting(); SplM_plan_info *choose_best_splitting(uint idx, table_map remaining_tables, + const POSITION *join_positions, table_map *spl_pd_boundary); bool fix_splitting(SplM_plan_info *spl_plan, table_map excluded_tables, bool is_const_table); From c93754d45e5d9379e3e23d7ada1d5f21d2711f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 19 May 2023 12:25:30 +0300 Subject: [PATCH 17/17] MDEV-31234 related cleanup trx_purge_free_segment(), trx_purge_truncate_rseg_history(): Replace some unreachable code with debug assertions. A buffer-fix does prevent pages from being evicted from the buffer pool; see buf_page_t::can_relocate(). Tested by: Matthias Leich --- storage/innobase/trx/trx0purge.cc | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index f1d0807b7fb..3cb5e9574fb 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -378,7 +378,7 @@ static void trx_purge_free_segment(buf_block_t *block, mtr_t &mtr) block->page.frame, &mtr)) { block->fix(); - const page_id_t id{block->page.id()}; + ut_d(const page_id_t id{block->page.id()}); mtr.commit(); /* NOTE: If the server is killed after the log that was produced up to this point was written, and before the log from the mtr.commit() @@ -390,16 +390,8 @@ static void trx_purge_free_segment(buf_block_t *block, mtr_t &mtr) log_free_check(); mtr.start(); block->page.lock.x_lock(); - if (UNIV_UNLIKELY(block->page.id() != id)) - { - block->unfix(); - block->page.lock.x_unlock(); - block= buf_page_get_gen(id, 0, RW_X_LATCH, nullptr, BUF_GET, &mtr); - if (!block) - return; - } - else - mtr.memo_push(block, MTR_MEMO_PAGE_X_MODIFY); + ut_ad(block->page.id() == id); + mtr.memo_push(block, MTR_MEMO_PAGE_X_MODIFY); } while (!fseg_free_step(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER + @@ -422,7 +414,6 @@ trx_purge_truncate_rseg_history(trx_rseg_t &rseg, mtr.start(); dberr_t err; -reget: buf_block_t *rseg_hdr= rseg.get(&mtr, &err); if (!rseg_hdr) { @@ -524,12 +515,7 @@ loop: log_free_check(); mtr.start(); rseg_hdr->page.lock.x_lock(); - if (UNIV_UNLIKELY(rseg_hdr->page.id() != rseg.page_id())) - { - rseg_hdr->unfix(); - rseg_hdr->page.lock.x_unlock(); - goto reget; - } + ut_ad(rseg_hdr->page.id() == rseg.page_id()); mtr.memo_push(rseg_hdr, MTR_MEMO_PAGE_X_MODIFY); goto loop;