From 02d67cecb6e443895e7a93759918224b226efc75 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 31 Aug 2023 13:14:03 +1000 Subject: [PATCH 01/34] MDEV-32043 mariadb-upgrade should remove bundled plugins from mysql.plugin Also in the startup, lets not "Error" on attempting to install a mysql.plugin that is already there. We use the 'if_not_exists' parameter to true to downgrade this to a "Note". Also corrects: MDEV-32041 "plugin already loaded" should be a Warning, not an Error --- mysql-test/main/mysql_upgrade.result | 8 ++++++++ mysql-test/main/mysql_upgrade.test | 11 +++++++++++ scripts/mysql_system_tables_fix.sql | 5 +++++ sql/sql_plugin.cc | 2 +- 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/mysql_upgrade.result b/mysql-test/main/mysql_upgrade.result index 64d6cd12753d0..a640d7e3ee629 100644 --- a/mysql-test/main/mysql_upgrade.result +++ b/mysql-test/main/mysql_upgrade.result @@ -1058,4 +1058,12 @@ test Phase 7/7: Running 'FLUSH PRIVILEGES' OK set global sql_safe_updates=@orig_sql_safe_updates; +# +# MDEV-32043 Remove plugins previously external that are now built in (unix_socket) +# +INSERT INTO mysql.plugin SELECT 'unix_socket', 'auth_socket.so' + FROM dual WHERE convert(@@version_compile_os using latin1) not in ('Win32', 'Win64', 'Windows'); +# mariadb-upgrade --force --silent 2>&1 +SELECT * FROM mysql.plugin WHERE name='unix_socket'; +name dl # End of 10.4 tests diff --git a/mysql-test/main/mysql_upgrade.test b/mysql-test/main/mysql_upgrade.test index f7a1bdf7be08c..df7f802905d2d 100644 --- a/mysql-test/main/mysql_upgrade.test +++ b/mysql-test/main/mysql_upgrade.test @@ -495,4 +495,15 @@ set global sql_safe_updates=ON; --remove_file $MYSQLD_DATADIR/mysql_upgrade_info set global sql_safe_updates=@orig_sql_safe_updates; +--echo # +--echo # MDEV-32043 Remove plugins previously external that are now built in (unix_socket) +--echo # + +INSERT INTO mysql.plugin SELECT 'unix_socket', 'auth_socket.so' + FROM dual WHERE convert(@@version_compile_os using latin1) not in ('Win32', 'Win64', 'Windows'); +--echo # mariadb-upgrade --force --silent 2>&1 +--exec $MYSQL_UPGRADE --force --silent 2>&1 +SELECT * FROM mysql.plugin WHERE name='unix_socket'; +--remove_file $MYSQLD_DATADIR/mysql_upgrade_info + --echo # End of 10.4 tests diff --git a/scripts/mysql_system_tables_fix.sql b/scripts/mysql_system_tables_fix.sql index fe3470352efe3..7d2cc7d9103ce 100644 --- a/scripts/mysql_system_tables_fix.sql +++ b/scripts/mysql_system_tables_fix.sql @@ -180,6 +180,11 @@ UPDATE user SET plugin='unix_socket' WHERE plugin='auth_socket'; DELETE FROM plugin WHERE name='auth_socket'; +# Delete plugins that are now inbuilt but might not have been before (MDEV-32043) +DELETE plugin + FROM information_schema.PLUGINS is_p + JOIN plugin ON plugin.name = is_p.PLUGIN_NAME + WHERE is_p.PLUGIN_LIBRARY IS NULL; ALTER TABLE user MODIFY Password char(41) character set latin1 collate latin1_bin NOT NULL default '', diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 19c5f86c7650d..9f144ca5a73b8 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1929,7 +1929,7 @@ static void plugin_load(MEM_ROOT *tmp_root) the mutex here to satisfy the assert */ mysql_mutex_lock(&LOCK_plugin); - plugin_add(tmp_root, false, &name, &dl, MYF(ME_ERROR_LOG)); + plugin_add(tmp_root, true, &name, &dl, MYF(ME_ERROR_LOG)); free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE)); mysql_mutex_unlock(&LOCK_plugin); } From 5775df012701144a76eb96501336d53c61fb28a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sun, 10 Dec 2023 13:19:21 +0200 Subject: [PATCH 02/34] MDEV-20142 encryption.innodb_encrypt_temporary_tables fails The data type of the column INFORMATION_SCHEMA.GLOBAL_STATUS.VARIABLE_VALUE is a character string. Therefore, if we want to compare some values as integers, we must explicitly cast them to integer type, to avoid an awkward comparison where '10'<'9' because the first digit is smaller. --- .../r/innodb_encrypt_temporary_tables.result | 16 ++++++++++------ .../t/innodb_encrypt_temporary_tables.test | 12 ++++++++---- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/mysql-test/suite/encryption/r/innodb_encrypt_temporary_tables.result b/mysql-test/suite/encryption/r/innodb_encrypt_temporary_tables.result index 541680ae862a3..d86ca6f9c0032 100644 --- a/mysql-test/suite/encryption/r/innodb_encrypt_temporary_tables.result +++ b/mysql-test/suite/encryption/r/innodb_encrypt_temporary_tables.result @@ -1,6 +1,8 @@ -SELECT variable_value into @old_encrypted FROM information_schema.global_status +SELECT CAST(variable_value AS INT) INTO @old_encrypted +FROM information_schema.global_status WHERE variable_name = 'innodb_encryption_n_temp_blocks_encrypted'; -SELECT variable_value into @old_decrypted FROM information_schema.global_status +SELECT CAST(variable_value AS INT) INTO @old_decrypted +FROM information_schema.global_status WHERE variable_name = 'innodb_encryption_n_temp_blocks_decrypted'; CREATE TEMPORARY TABLE t1(f1 CHAR(200), f2 CHAR(200)) ENGINE=InnoDB; INSERT INTO t1 (f1,f2) SELECT '', '' FROM seq_1_to_8192; @@ -12,11 +14,13 @@ COUNT(*) SELECT COUNT(*) FROM t2; COUNT(*) 8192 -SELECT variable_value > @old_encrypted FROM information_schema.global_status +SELECT CAST(variable_value AS INT) > @old_encrypted +FROM information_schema.global_status WHERE variable_name = 'innodb_encryption_n_temp_blocks_encrypted'; -variable_value > @old_encrypted +CAST(variable_value AS INT) > @old_encrypted 1 -SELECT variable_value > @old_decrypted FROM information_schema.global_status +SELECT CAST(variable_value AS INT) > @old_decrypted +FROM information_schema.global_status WHERE variable_name = 'innodb_encryption_n_temp_blocks_decrypted'; -variable_value > @old_decrypted +CAST(variable_value AS INT) > @old_decrypted 1 diff --git a/mysql-test/suite/encryption/t/innodb_encrypt_temporary_tables.test b/mysql-test/suite/encryption/t/innodb_encrypt_temporary_tables.test index d99a55b9b44ef..83abb783c9e33 100644 --- a/mysql-test/suite/encryption/t/innodb_encrypt_temporary_tables.test +++ b/mysql-test/suite/encryption/t/innodb_encrypt_temporary_tables.test @@ -2,10 +2,12 @@ --source include/have_innodb.inc --source include/have_file_key_management_plugin.inc -SELECT variable_value into @old_encrypted FROM information_schema.global_status +SELECT CAST(variable_value AS INT) INTO @old_encrypted +FROM information_schema.global_status WHERE variable_name = 'innodb_encryption_n_temp_blocks_encrypted'; -SELECT variable_value into @old_decrypted FROM information_schema.global_status +SELECT CAST(variable_value AS INT) INTO @old_decrypted +FROM information_schema.global_status WHERE variable_name = 'innodb_encryption_n_temp_blocks_decrypted'; CREATE TEMPORARY TABLE t1(f1 CHAR(200), f2 CHAR(200)) ENGINE=InnoDB; @@ -17,8 +19,10 @@ INSERT INTO t2 (f1,f2,f3) SELECT '', '', '' FROM seq_1_to_8192; SELECT COUNT(*) FROM t1; SELECT COUNT(*) FROM t2; -SELECT variable_value > @old_encrypted FROM information_schema.global_status +SELECT CAST(variable_value AS INT) > @old_encrypted +FROM information_schema.global_status WHERE variable_name = 'innodb_encryption_n_temp_blocks_encrypted'; -SELECT variable_value > @old_decrypted FROM information_schema.global_status +SELECT CAST(variable_value AS INT) > @old_decrypted +FROM information_schema.global_status WHERE variable_name = 'innodb_encryption_n_temp_blocks_decrypted'; From 9bf50a0eec111739b896e1e5d14d15abf21ffae5 Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Mon, 11 Dec 2023 12:27:11 +0700 Subject: [PATCH 03/34] MDEV-32965: Assertion `thd->active_stmt_arena_to_use()-> is_stmt_prepare_or_first_sp_execute() || thd->active_stmt_arena_to_use()-> is_conventional() || thd->active_stmt_arena_to_use()->state == Query_arena::STMT_SP_QUERY_ARGUMENTS' failed This patch fixes too strong condition in assert at the method Item_func_group_concat::fix_fields that is true in case of a stored routine and obviously broken for a prepared statement. --- mysql-test/main/ps.result | 10 ++++++++++ mysql-test/main/ps.test | 12 ++++++++++++ sql/item_sum.cc | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/ps.result b/mysql-test/main/ps.result index 408b1ec26667d..32560ab2b2cd7 100644 --- a/mysql-test/main/ps.result +++ b/mysql-test/main/ps.result @@ -5805,5 +5805,15 @@ END; $ ERROR 42000: EXECUTE..USING does not support subqueries or stored functions # +# MDEV-32965: Assertion `thd->active_stmt_arena_to_use()-> is_stmt_prepare_or_first_sp_execute() || thd->active_stmt_arena_to_use()-> is_conventional() || thd->active_stmt_arena_to_use()->state == Query_arena::STMT_SP_QUERY_ARGUMENTS' failed +# +CREATE TABLE t (f VARCHAR(8)) CHARACTER SET utf8; +INSERT INTO t VALUES ('foo'),('bar'); +EXECUTE IMMEDIATE 'SELECT GROUP_CONCAT(@x) FROM t GROUP BY @x := f'; +GROUP_CONCAT(@x) +0 +0 +DROP TABLE t; +# # End of 10.4 tests # diff --git a/mysql-test/main/ps.test b/mysql-test/main/ps.test index a24d045d63b05..70213e053915a 100644 --- a/mysql-test/main/ps.test +++ b/mysql-test/main/ps.test @@ -5231,6 +5231,18 @@ $ delimiter ;$ +--echo # +--echo # MDEV-32965: Assertion `thd->active_stmt_arena_to_use()-> is_stmt_prepare_or_first_sp_execute() || thd->active_stmt_arena_to_use()-> is_conventional() || thd->active_stmt_arena_to_use()->state == Query_arena::STMT_SP_QUERY_ARGUMENTS' failed +--echo # +CREATE TABLE t (f VARCHAR(8)) CHARACTER SET utf8; + +INSERT INTO t VALUES ('foo'),('bar'); +EXECUTE IMMEDIATE 'SELECT GROUP_CONCAT(@x) FROM t GROUP BY @x := f'; + +# Cleanup + +DROP TABLE t; + --echo # --echo # End of 10.4 tests --echo # diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 048307fdeb276..30ed3f93437c0 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -4099,7 +4099,7 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref) String *new_separator; DBUG_ASSERT(thd->active_stmt_arena_to_use()-> - is_stmt_prepare_or_first_sp_execute() || + is_stmt_prepare_or_first_stmt_execute() || thd->active_stmt_arena_to_use()-> is_conventional() || thd->active_stmt_arena_to_use()->state == From 7e34bb5ce12c543dec96d07d30598154f9880d55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 11 Dec 2023 10:31:49 +0200 Subject: [PATCH 04/34] MDEV-11905: Simplify encryption.innodb_encrypt_discard_import The test was populating unnecessarily large tables and restarting the server several times for no real reason. Let us hope that a smaller version of the test will produce more stable results. Occasionally, some unencrypted contents in the table t2 was revealed in the old test. --- .../r/innodb_encryption_discard_import.result | 67 ++++++++----------- .../t/innodb_encryption_discard_import.test | 60 +++++------------ 2 files changed, 45 insertions(+), 82 deletions(-) diff --git a/mysql-test/suite/encryption/r/innodb_encryption_discard_import.result b/mysql-test/suite/encryption/r/innodb_encryption_discard_import.result index 7ee30423fe7a7..18082027660ec 100644 --- a/mysql-test/suite/encryption/r/innodb_encryption_discard_import.result +++ b/mysql-test/suite/encryption/r/innodb_encryption_discard_import.result @@ -13,11 +13,13 @@ set current_num = current_num + 1; end while; end// commit; -set autocommit=0; -call innodb_insert_proc(10000); +begin; +set statement unique_checks=0, foreign_key_checks=0 for +call innodb_insert_proc(100); commit; -set autocommit=1; +DROP PROCEDURE innodb_insert_proc; # Wait max 10 min for key encryption threads to encrypt all spaces +FLUSH TABLES t1, t2, t3 FOR EXPORT; # tablespaces should be now encrypted # t1 yes on expecting NOT FOUND NOT FOUND /foobar/ in t1.ibd @@ -25,15 +27,16 @@ NOT FOUND /foobar/ in t1.ibd NOT FOUND /temp/ in t2.ibd # t3 ... on expecting NOT FOUND NOT FOUND /barfoo/ in t3.ibd -# restart db.opt +t1.cfg t1.frm t1.ibd +t2.cfg t2.frm t2.ibd +t3.cfg t3.frm t3.ibd -FLUSH TABLES t1, t2, t3 FOR EXPORT; backup: t1 backup: t2 backup: t3 @@ -55,17 +58,18 @@ restore: t1 .ibd and .cfg files restore: t2 .ibd and .cfg files restore: t3 .ibd and .cfg files ALTER TABLE t1 IMPORT TABLESPACE; -SELECT COUNT(1) FROM t1; -COUNT(1) -10000 +SELECT COUNT(*) FROM t1; +COUNT(*) +100 ALTER TABLE t2 IMPORT TABLESPACE; -SELECT COUNT(1) FROM t2; -COUNT(1) -10000 +SELECT COUNT(*) FROM t2; +COUNT(*) +100 ALTER TABLE t3 IMPORT TABLESPACE; -SELECT COUNT(1) FROM t3; -COUNT(1) -10000 +SELECT COUNT(*) FROM t3; +COUNT(*) +100 +FLUSH TABLES t1, t2, t3 FOR EXPORT; # tablespaces should remain encrypted after import # t1 yes on expecting NOT FOUND NOT FOUND /foobar/ in t1.ibd @@ -73,8 +77,8 @@ NOT FOUND /foobar/ in t1.ibd NOT FOUND /temp/ in t2.ibd # t3 ... on expecting NOT FOUND NOT FOUND /barfoo/ in t3.ibd -# restart -ALTER TABLE t1 ENGINE InnoDB; +UNLOCK TABLES; +ALTER TABLE t1 FORCE; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -82,7 +86,7 @@ t1 CREATE TABLE `t1` ( `a` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci `encrypted`=yes -ALTER TABLE t2 ENGINE InnoDB; +ALTER TABLE t2 FORCE; SHOW CREATE TABLE t2; Table Create Table t2 CREATE TABLE `t2` ( @@ -90,7 +94,7 @@ t2 CREATE TABLE `t2` ( `a` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci -ALTER TABLE t3 ENGINE InnoDB; +ALTER TABLE t3 FORCE; SHOW CREATE TABLE t3; Table Create Table t3 CREATE TABLE `t3` ( @@ -98,30 +102,17 @@ t3 CREATE TABLE `t3` ( `a` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ROW_FORMAT=COMPRESSED `encrypted`=yes -# Restarting server -# restart -# Done restarting server # Verify that tables are still usable -SELECT COUNT(1) FROM t1; -COUNT(1) -10000 -SELECT COUNT(1) FROM t2; -COUNT(1) -10000 -SELECT COUNT(1) FROM t3; -COUNT(1) -10000 -# Tablespaces should be encrypted after restart +CHECK TABLE t1, t2, t3 EXTENDED; +Table Op Msg_type Msg_text +test.t1 check status OK +test.t2 check status OK +test.t3 check status OK +FLUSH TABLES t1, t2, t3 FOR EXPORT; # t1 yes on expecting NOT FOUND NOT FOUND /foobar/ in t1.ibd # t2 ... on expecting NOT FOUND NOT FOUND /temp/ in t2.ibd # t3 ... on expecting NOT FOUND -NOT FOUND /barfoo/ in t3.ibd -# restart -# Wait max 10 min for key encryption threads to encrypt all spaces -# Success! -# Restart mysqld --innodb_encrypt_tables=0 --innodb_encryption_threads=0 -# restart: --innodb_encrypt_tables=0 --innodb_encryption_threads=0 -DROP PROCEDURE innodb_insert_proc; +UNLOCK TABLES; DROP TABLE t1, t2, t3; diff --git a/mysql-test/suite/encryption/t/innodb_encryption_discard_import.test b/mysql-test/suite/encryption/t/innodb_encryption_discard_import.test index 227555716180a..5f02d966e7e75 100644 --- a/mysql-test/suite/encryption/t/innodb_encryption_discard_import.test +++ b/mysql-test/suite/encryption/t/innodb_encryption_discard_import.test @@ -6,7 +6,6 @@ let MYSQLD_DATADIR = `SELECT @@datadir`; --let SEARCH_RANGE = 10000000 ---let $id = `SELECT RAND()` --let t1_IBD = $MYSQLD_DATADIR/test/t1.ibd --let t2_IBD = $MYSQLD_DATADIR/test/t2.ibd --let t3_IBD = $MYSQLD_DATADIR/test/t3.ibd @@ -30,19 +29,18 @@ end// delimiter ;// commit; -set autocommit=0; -call innodb_insert_proc(10000); +begin; +set statement unique_checks=0, foreign_key_checks=0 for +call innodb_insert_proc(100); commit; -set autocommit=1; +DROP PROCEDURE innodb_insert_proc; --echo # Wait max 10 min for key encryption threads to encrypt all spaces --let $wait_timeout= 600 --let $wait_condition=SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND ROTATING_OR_FLUSHING <> 0 --source include/wait_condition.inc -# shutdown so that grep is safe ---source include/shutdown_mysqld.inc - +FLUSH TABLES t1, t2, t3 FOR EXPORT; --echo # tablespaces should be now encrypted --let SEARCH_PATTERN=foobar --echo # t1 yes on expecting NOT FOUND @@ -57,11 +55,8 @@ set autocommit=1; -- let SEARCH_FILE=$t3_IBD -- source include/search_pattern_in_file.inc ---source include/start_mysqld.inc let MYSQLD_DATADIR =`SELECT @@datadir`; - --list_files $MYSQLD_DATADIR/test -FLUSH TABLES t1, t2, t3 FOR EXPORT; perl; do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; ib_backup_tablespaces("test", "t1","t2","t3"); @@ -80,14 +75,13 @@ ib_restore_tablespaces("test", "t1","t2","t3"); EOF ALTER TABLE t1 IMPORT TABLESPACE; -SELECT COUNT(1) FROM t1; +SELECT COUNT(*) FROM t1; ALTER TABLE t2 IMPORT TABLESPACE; -SELECT COUNT(1) FROM t2; +SELECT COUNT(*) FROM t2; ALTER TABLE t3 IMPORT TABLESPACE; -SELECT COUNT(1) FROM t3; +SELECT COUNT(*) FROM t3; -# shutdown so that grep is safe ---source include/shutdown_mysqld.inc +FLUSH TABLES t1, t2, t3 FOR EXPORT; --echo # tablespaces should remain encrypted after import --let SEARCH_PATTERN=foobar @@ -103,28 +97,18 @@ SELECT COUNT(1) FROM t3; -- let SEARCH_FILE=$t3_IBD -- source include/search_pattern_in_file.inc ---source include/start_mysqld.inc - -ALTER TABLE t1 ENGINE InnoDB; +UNLOCK TABLES; +ALTER TABLE t1 FORCE; SHOW CREATE TABLE t1; -ALTER TABLE t2 ENGINE InnoDB; +ALTER TABLE t2 FORCE; SHOW CREATE TABLE t2; -ALTER TABLE t3 ENGINE InnoDB; +ALTER TABLE t3 FORCE; SHOW CREATE TABLE t3; ---echo # Restarting server --- source include/restart_mysqld.inc ---echo # Done restarting server - --echo # Verify that tables are still usable -SELECT COUNT(1) FROM t1; -SELECT COUNT(1) FROM t2; -SELECT COUNT(1) FROM t3; - -# shutdown so that grep is safe ---source include/shutdown_mysqld.inc +CHECK TABLE t1, t2, t3 EXTENDED; +FLUSH TABLES t1, t2, t3 FOR EXPORT; ---echo # Tablespaces should be encrypted after restart --let SEARCH_PATTERN=foobar --echo # t1 yes on expecting NOT FOUND -- let SEARCH_FILE=$t1_IBD @@ -136,19 +120,7 @@ SELECT COUNT(1) FROM t3; --echo # t3 ... on expecting NOT FOUND --let SEARCH_PATTERN=barfoo -- let SEARCH_FILE=$t3_IBD --- source include/search_pattern_in_file.inc - ---source include/start_mysqld.inc - ---echo # Wait max 10 min for key encryption threads to encrypt all spaces ---let $wait_timeout= 600 ---let $wait_condition=SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND ROTATING_OR_FLUSHING <> 0 ---source include/wait_condition.inc ---echo # Success! ---echo # Restart mysqld --innodb_encrypt_tables=0 --innodb_encryption_threads=0 --- let $restart_parameters=--innodb_encrypt_tables=0 --innodb_encryption_threads=0 --- source include/restart_mysqld.inc +UNLOCK TABLES; -DROP PROCEDURE innodb_insert_proc; DROP TABLE t1, t2, t3; From 50ce001afd6ca354fc679ce95c53194eeedbdd98 Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Mon, 11 Dec 2023 10:48:42 +0100 Subject: [PATCH 05/34] MDEV-13792: innodb.purge_thread_shutdown failed in buildbot with wrong result (sporadic) Omit `state` when selecting processlist to verify which threads are running. The state changes as threads are running (enter_state()), and this causes sporadic test failures. Signed-off-by: Kristian Nielsen --- .../innodb/r/purge_thread_shutdown.result | 40 +++++++++---------- .../suite/innodb/t/purge_thread_shutdown.test | 6 +-- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/mysql-test/suite/innodb/r/purge_thread_shutdown.result b/mysql-test/suite/innodb/r/purge_thread_shutdown.result index a87cba89917cb..e40c10561dccd 100644 --- a/mysql-test/suite/innodb/r/purge_thread_shutdown.result +++ b/mysql-test/suite/innodb/r/purge_thread_shutdown.result @@ -2,32 +2,32 @@ connect con1, localhost, root; create table t1 (a int) engine=innodb; insert t1 values (1),(2),(3),(4); delete from t1 where a=1; -select user,state from information_schema.processlist order by 2; -user state -root -root Filling schema table -system user InnoDB purge coordinator -system user InnoDB purge worker -system user InnoDB purge worker -system user InnoDB purge worker -system user InnoDB shutdown handler +select user from information_schema.processlist order by 1; +user +root +root +system user +system user +system user +system user +system user set global debug_dbug='+d,only_kill_system_threads'; set global innodb_fast_shutdown=0; shutdown; connection default; disconnect con1; -select user,state from information_schema.processlist order by 2; -user state -root Filling schema table -system user InnoDB purge coordinator -system user InnoDB purge worker -system user InnoDB purge worker -system user InnoDB purge worker -system user InnoDB slow shutdown wait +select user from information_schema.processlist order by 1; +user +root +system user +system user +system user +system user +system user set global innodb_fast_shutdown=1; -select user,state from information_schema.processlist order by 2; -user state -root Filling schema table +select user from information_schema.processlist order by 1; +user +root delete from t1 where a=3; set global innodb_fast_shutdown=0; ERROR 42000: Variable 'innodb_fast_shutdown' can't be set to the value of '0' diff --git a/mysql-test/suite/innodb/t/purge_thread_shutdown.test b/mysql-test/suite/innodb/t/purge_thread_shutdown.test index 762336cf0d14d..1cc8849f083a0 100644 --- a/mysql-test/suite/innodb/t/purge_thread_shutdown.test +++ b/mysql-test/suite/innodb/t/purge_thread_shutdown.test @@ -7,7 +7,7 @@ create table t1 (a int) engine=innodb; insert t1 values (1),(2),(3),(4); delete from t1 where a=1; -select user,state from information_schema.processlist order by 2; +select user from information_schema.processlist order by 1; set global debug_dbug='+d,only_kill_system_threads'; set global innodb_fast_shutdown=0; @@ -21,12 +21,12 @@ connection default; disconnect con1; sleep 5; -select user,state from information_schema.processlist order by 2; +select user from information_schema.processlist order by 1; set global innodb_fast_shutdown=1; let $wait_condition=select count(*) = 0 from information_schema.processlist where user='system user'; source include/wait_condition.inc; -select user,state from information_schema.processlist order by 2; +select user from information_schema.processlist order by 1; delete from t1 where a=3; error ER_WRONG_VALUE_FOR_VAR; From 5ca63b2b8b4fafd82314f6d6595128b3b12a2311 Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Mon, 11 Dec 2023 11:14:53 +0100 Subject: [PATCH 06/34] MDEV-26632: multi source replication filters breaking GTID semantic Add a test case that demonstrates a working setup as described in MDEV-26632. This requires --gtid-ignore-duplicates=1 and --gtid-strict-mode=0. In A->B->C, B filters some (but not all) events from A. C is promoted to create A->C->B, and the current GTID position in B contains a GTID from A that is not present in C (due to filtering). Demonstrate that B can still connect with GTID to C, starting at the "hole" in the binlog stream on C originating from A. Signed-off-by: Kristian Nielsen --- .../rpl/r/rpl_gtid_slave_filtering.result | 78 +++++++++++++ .../suite/rpl/t/rpl_gtid_slave_filtering.cnf | 28 +++++ .../suite/rpl/t/rpl_gtid_slave_filtering.test | 109 ++++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 mysql-test/suite/rpl/r/rpl_gtid_slave_filtering.result create mode 100644 mysql-test/suite/rpl/t/rpl_gtid_slave_filtering.cnf create mode 100644 mysql-test/suite/rpl/t/rpl_gtid_slave_filtering.test diff --git a/mysql-test/suite/rpl/r/rpl_gtid_slave_filtering.result b/mysql-test/suite/rpl/r/rpl_gtid_slave_filtering.result new file mode 100644 index 0000000000000..84080b94de88d --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_gtid_slave_filtering.result @@ -0,0 +1,78 @@ +include/rpl_init.inc [topology=1->2->3] +*** Test GTID master switch in a topology with filtered events. +*** With --gtid-ignore-duplicate and --gtid-strict-mode, should allow +*** GTID connect at a GTID position that is filtered on the new master. +connection server_1; +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,1); +CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t3 VALUES (1,1); +INSERT INTO t1 VALUES (2,1); +INSERT INTO t3 VALUES (2,1); +include/save_master_gtid.inc +connection server_2; +CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1,2); +include/sync_with_master_gtid.inc +include/save_master_gtid.inc +connection server_3; +include/sync_with_master_gtid.inc +*** Promote 3 as new master, demote 2 as slave of 3. +*** GTID position of 2 in domain 0 is filtered on 3. +connection server_2; +include/stop_slave.inc +connection server_3; +include/stop_slave.inc +CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_1, +MASTER_USE_GTID=SLAVE_POS; +connection server_2; +CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_3, +MASTER_USE_GTID=SLAVE_POS; +include/start_slave.inc +connection server_3; +include/start_slave.inc +connection server_1; +INSERT INTO t1 VALUES (3,1); +INSERT INTO t3 VALUES (3,1); +include/save_master_gtid.inc +connection server_3; +INSERT INTO t2 VALUES (2,2); +include/sync_with_master_gtid.inc +include/save_master_gtid.inc +connection server_2; +include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +a b +1 1 +2 1 +3 1 +SELECT * FROM t3 ORDER BY a; +ERROR 42S02: Table 'test.t3' doesn't exist +SELECT * FROM t2 ORDER BY a; +a b +1 2 +2 2 +*** Restore original topology. +connection server_3; +include/stop_slave.inc +connection server_2; +include/stop_slave.inc +CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_1, +MASTER_USE_GTID=SLAVE_POS; +include/start_slave.inc +connection server_3; +CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_2, +MASTER_USE_GTID=SLAVE_POS; +include/start_slave.inc +connection server_1; +DROP TABLE t1; +DROP TABLE t3; +include/save_master_gtid.inc +connection server_2; +DROP TABLE t2; +include/sync_with_master_gtid.inc +include/save_master_gtid.inc +connection server_3; +include/sync_with_master_gtid.inc +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_slave_filtering.cnf b/mysql-test/suite/rpl/t/rpl_gtid_slave_filtering.cnf new file mode 100644 index 0000000000000..a57dbbf3f566c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_slave_filtering.cnf @@ -0,0 +1,28 @@ +!include ../my.cnf + +[mysqld.1] +log-slave-updates +loose-innodb +gtid-domain-id=1 +gtid-strict-mode=0 +gtid-ignore-duplicates=1 + +[mysqld.2] +log-slave-updates +loose-innodb +gtid-domain-id=0 +replicate-ignore-table=test.t3 +gtid-strict-mode=0 +gtid-ignore-duplicates=1 + +[mysqld.3] +log-slave-updates +loose-innodb +gtid-domain-id=0 +replicate-ignore-table=test.t3 +gtid-strict-mode=0 +gtid-ignore-duplicates=1 + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket diff --git a/mysql-test/suite/rpl/t/rpl_gtid_slave_filtering.test b/mysql-test/suite/rpl/t/rpl_gtid_slave_filtering.test new file mode 100644 index 0000000000000..842bae8234c42 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_slave_filtering.test @@ -0,0 +1,109 @@ +--source include/have_innodb.inc +--source include/have_binlog_format_mixed.inc + +--let $rpl_topology=1->2->3 +--source include/rpl_init.inc + +--echo *** Test GTID master switch in a topology with filtered events. +--echo *** With --gtid-ignore-duplicate and --gtid-strict-mode, should allow +--echo *** GTID connect at a GTID position that is filtered on the new master. + +--connection server_1 + +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,1); +CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t3 VALUES (1,1); +INSERT INTO t1 VALUES (2,1); +INSERT INTO t3 VALUES (2,1); +--source include/save_master_gtid.inc + +--connection server_2 +CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1,2); + +--let $slave_timeout= 10 +--source include/sync_with_master_gtid.inc +--source include/save_master_gtid.inc + +--connection server_3 +--source include/sync_with_master_gtid.inc + +--echo *** Promote 3 as new master, demote 2 as slave of 3. +--echo *** GTID position of 2 in domain 0 is filtered on 3. + +--connection server_2 +--source include/stop_slave.inc + +--connection server_3 +--source include/stop_slave.inc +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_1, + MASTER_USE_GTID=SLAVE_POS; + +--connection server_2 +--replace_result $SERVER_MYPORT_3 SERVER_MYPORT_3 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_3, + MASTER_USE_GTID=SLAVE_POS; +--source include/start_slave.inc + +--connection server_3 +--source include/start_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES (3,1); +INSERT INTO t3 VALUES (3,1); +--source include/save_master_gtid.inc + +--connection server_3 +INSERT INTO t2 VALUES (2,2); + +--source include/sync_with_master_gtid.inc +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc + +SELECT * FROM t1 ORDER BY a; +# Verify that table t3 is being filtered. +--error 1146 +SELECT * FROM t3 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + + +--echo *** Restore original topology. + +--connection server_3 +--source include/stop_slave.inc + +--connection server_2 +--source include/stop_slave.inc +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_1, + MASTER_USE_GTID=SLAVE_POS; +--source include/start_slave.inc + +--connection server_3 +--replace_result $SERVER_MYPORT_2 SERVER_MYPORT_2 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_2, + MASTER_USE_GTID=SLAVE_POS; +--source include/start_slave.inc + + +# Cleanup + +--connection server_1 +DROP TABLE t1; +DROP TABLE t3; +--source include/save_master_gtid.inc + +--connection server_2 +DROP TABLE t2; +--source include/sync_with_master_gtid.inc +--source include/save_master_gtid.inc + +--connection server_3 +--source include/sync_with_master_gtid.inc + +--source include/rpl_end.inc From 8dad51481b1e3f02e025bf06b4af7f699d76f58c Mon Sep 17 00:00:00 2001 From: Brandon Nesterenko Date: Wed, 29 Nov 2023 06:53:31 -0700 Subject: [PATCH 07/34] MDEV-10653: SHOW SLAVE STATUS Can Deadlock an Errored Slave MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AKA rpl.rpl_parallel, binlog_encryption.rpl_parallel fails in buildbot with timeout in include A replication parallel worker thread can deadlock with another connection running SHOW SLAVE STATUS. That is, if the replication worker thread is in do_gco_wait() and is killed, it will already hold the LOCK_parallel_entry, and during error reporting, try to grab the err_lock. SHOW SLAVE STATUS, however, grabs these locks in reverse order. It will initially grab the err_lock, and then try to grab LOCK_parallel_entry. This leads to a deadlock when both threads have grabbed their first lock without the second. This patch implements the MDEV-31894 proposed fix to optimize the workers_idle() check to compare the last in-use relay log’s queued_count==dequeued_count for idleness. This removes the need for workers_idle() to grab LOCK_parallel_entry, as these values are atomically updated. Huge thanks to Kristian Nielsen for diagnosing the problem! Reviewed By: ============ Kristian Nielsen Andrei Elkin --- .../r/rpl_deadlock_show_slave_status.result | 66 ++++++++++ .../rpl/t/rpl_deadlock_show_slave_status.test | 121 ++++++++++++++++++ sql/rpl_parallel.cc | 19 +-- sql/rpl_parallel.h | 3 +- sql/rpl_rli.h | 2 +- sql/slave.cc | 11 +- 6 files changed, 203 insertions(+), 19 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_deadlock_show_slave_status.result create mode 100644 mysql-test/suite/rpl/t/rpl_deadlock_show_slave_status.test diff --git a/mysql-test/suite/rpl/r/rpl_deadlock_show_slave_status.result b/mysql-test/suite/rpl/r/rpl_deadlock_show_slave_status.result new file mode 100644 index 0000000000000..12ad5870d4a13 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_deadlock_show_slave_status.result @@ -0,0 +1,66 @@ +include/master-slave.inc +[connection master] +# +# Initialize test data +connection master; +create table t1 (a int) engine=innodb; +insert into t1 values (1); +include/save_master_gtid.inc +connection slave; +include/sync_with_master_gtid.inc +include/stop_slave.inc +call mtr.add_suppression("Connection was killed"); +call mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends"); +set @save_parallel_threads= @@global.slave_parallel_threads; +set @save_parallel_mode= @@global.slave_parallel_mode; +set @save_transaction_retries= @@global.slave_transaction_retries; +set @save_innodb_lock_wait_timeout= @@global.innodb_lock_wait_timeout; +set @@global.slave_parallel_threads= 2; +set @@global.slave_parallel_mode= CONSERVATIVE; +set @@global.slave_transaction_retries= 0; +set @@global.innodb_lock_wait_timeout= 10; +# Grabbing lock on innodb row to force future replication transaction to wait (and eventually timeout) +BEGIN; +select * from t1 where a=1 for update; +a +1 +connection master; +set @old_dbug= @@session.debug_dbug; +set @@session.debug_dbug="+d,binlog_force_commit_id"; +SET @commit_id= 10000; +update t1 set a=2 where a=1; +SET @commit_id= 10001; +insert into t1 values (3); +set @@session.debug_dbug= @old_dbug; +connection slave; +start slave; +# Waiting for first transaction to start (and be held at innodb row lock).. +# Waiting for next transaction to start and hold at do_gco_wait().. +connection slave1; +set @@session.debug_dbug="+d,hold_sss_with_err_lock"; +show slave status; +connection slave; +set debug_sync="now wait_for sss_got_err_lock"; +kill ; +set debug_sync="now signal sss_continue"; +connection slave1; +# Waiting for SHOW SLAVE STATUS to complete.. +# ..done +connection slave; +ROLLBACK; +include/wait_for_slave_sql_error.inc [errno=1927] +# +# Cleanup +connection master; +drop table t1; +include/save_master_gtid.inc +connection slave; +set debug_sync= "RESET"; +set @@global.slave_parallel_threads= @save_parallel_threads; +set @@global.slave_parallel_mode= @save_parallel_mode; +set @@global.slave_transaction_retries= @save_transaction_retries; +set @@global.innodb_lock_wait_timeout= @save_innodb_lock_wait_timeout; +start slave sql_thread; +include/sync_with_master_gtid.inc +include/rpl_end.inc +# End of rpl_deadlock_show_slave_status.test diff --git a/mysql-test/suite/rpl/t/rpl_deadlock_show_slave_status.test b/mysql-test/suite/rpl/t/rpl_deadlock_show_slave_status.test new file mode 100644 index 0000000000000..ecf3b62ba3604 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_deadlock_show_slave_status.test @@ -0,0 +1,121 @@ +# +# Verify that SHOW SLAVE STATUS will not cause deadlocks on the replica. +# A deadlock has been seen in do_gco_wait if the thread is killed, as it will +# hold the LOCK_parallel_entry, and during error reporting, try to grab the +# err_lock. Prior to MDEV-10653, SHOW SLAVE STATUS would grab these locks in +# the reverse order, as calling workers_idle() used to grab LOCK_parallel_entry +# with the err_lock already grabbed (though the MDEV-10653 patch changed the +# workles_idle() implementation to remove the need for locking the +# parallel_entry). +# +# References: +# MDEV-10653: SHOW SLAVE STATUS Can Deadlock an Errored Slave +# + +--source include/master-slave.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_binlog_format_row.inc + +--echo # +--echo # Initialize test data +--connection master +create table t1 (a int) engine=innodb; +insert into t1 values (1); +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc + +call mtr.add_suppression("Connection was killed"); +call mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends"); + +set @save_parallel_threads= @@global.slave_parallel_threads; +set @save_parallel_mode= @@global.slave_parallel_mode; +set @save_transaction_retries= @@global.slave_transaction_retries; +set @save_innodb_lock_wait_timeout= @@global.innodb_lock_wait_timeout; + +set @@global.slave_parallel_threads= 2; +set @@global.slave_parallel_mode= CONSERVATIVE; +set @@global.slave_transaction_retries= 0; +set @@global.innodb_lock_wait_timeout= 10; + +--echo # Grabbing lock on innodb row to force future replication transaction to wait (and eventually timeout) +BEGIN; +select * from t1 where a=1 for update; + +--connection master + +set @old_dbug= @@session.debug_dbug; +set @@session.debug_dbug="+d,binlog_force_commit_id"; + + +# GCO 1 +SET @commit_id= 10000; +# T1 +update t1 set a=2 where a=1; + +# GCO 2 +SET @commit_id= 10001; +# T2 +insert into t1 values (3); + +set @@session.debug_dbug= @old_dbug; + +--connection slave +start slave; + +--echo # Waiting for first transaction to start (and be held at innodb row lock).. +--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Update_rows_log_event::find_row(%)' and command LIKE 'Slave_worker'; +--source include/wait_condition.inc + +--echo # Waiting for next transaction to start and hold at do_gco_wait().. +--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for prior transaction to start commit%' and command LIKE 'Slave_worker'; +--source include/wait_condition.inc + +--connection slave1 +set @@session.debug_dbug="+d,hold_sss_with_err_lock"; +--send show slave status + +--connection slave +set debug_sync="now wait_for sss_got_err_lock"; + +--let $t2_tid= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'Waiting for prior transaction to start commit%'` +--replace_result $t2_tid "" +--eval kill $t2_tid +--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE command LIKE 'Killed'; +--source include/wait_condition.inc + +set debug_sync="now signal sss_continue"; + +--connection slave1 +--echo # Waiting for SHOW SLAVE STATUS to complete.. +--disable_result_log +--reap +--enable_result_log +--echo # ..done + +--connection slave +ROLLBACK; +--let $slave_sql_errno= 1927 +--source include/wait_for_slave_sql_error.inc + + +--echo # +--echo # Cleanup +--connection master +drop table t1; +--source include/save_master_gtid.inc + +--connection slave +set debug_sync= "RESET"; +set @@global.slave_parallel_threads= @save_parallel_threads; +set @@global.slave_parallel_mode= @save_parallel_mode; +set @@global.slave_transaction_retries= @save_transaction_retries; +set @@global.innodb_lock_wait_timeout= @save_innodb_lock_wait_timeout; +start slave sql_thread; +--source include/sync_with_master_gtid.inc + +--source include/rpl_end.inc +--echo # End of rpl_deadlock_show_slave_status.test diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index fc4434b75de23..397b45c4eef9d 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -2537,23 +2537,10 @@ rpl_parallel::stop_during_until() bool -rpl_parallel::workers_idle() +rpl_parallel::workers_idle(Relay_log_info *rli) { - struct rpl_parallel_entry *e; - uint32 i, max_i; - - max_i= domain_hash.records; - for (i= 0; i < max_i; ++i) - { - bool active; - e= (struct rpl_parallel_entry *)my_hash_element(&domain_hash, i); - mysql_mutex_lock(&e->LOCK_parallel_entry); - active= e->current_sub_id > e->last_committed_sub_id; - mysql_mutex_unlock(&e->LOCK_parallel_entry); - if (active) - break; - } - return (i == max_i); + return rli->last_inuse_relaylog->queued_count == + rli->last_inuse_relaylog->dequeued_count; } diff --git a/sql/rpl_parallel.h b/sql/rpl_parallel.h index 6b03306692b62..07ff7f70293b4 100644 --- a/sql/rpl_parallel.h +++ b/sql/rpl_parallel.h @@ -369,9 +369,10 @@ struct rpl_parallel { rpl_parallel_entry *find(uint32 domain_id); void wait_for_done(THD *thd, Relay_log_info *rli); void stop_during_until(); - bool workers_idle(); int wait_for_workers_idle(THD *thd); int do_event(rpl_group_info *serial_rgi, Log_event *ev, ulonglong event_size); + + static bool workers_idle(Relay_log_info *rli); }; diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 1391c5cde8221..9fc1a384355ec 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -622,7 +622,7 @@ struct inuse_relaylog { rpl_gtid *relay_log_state; uint32 relay_log_state_count; /* Number of events in this relay log queued for worker threads. */ - int64 queued_count; + Atomic_counter queued_count; /* Number of events completed by worker threads. */ Atomic_counter dequeued_count; /* Set when all events have been read from a relaylog. */ diff --git a/sql/slave.cc b/sql/slave.cc index 84b245fa1bef6..2cc11b9ed4241 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3123,6 +3123,14 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full, mysql_mutex_lock(&mi->err_lock); /* err_lock is to protect mi->rli.last_error() */ mysql_mutex_lock(&mi->rli.err_lock); + + DBUG_EXECUTE_IF("hold_sss_with_err_lock", { + DBUG_ASSERT(!debug_sync_set_action( + thd, STRING_WITH_LEN("now SIGNAL sss_got_err_lock " + "WAIT_FOR sss_continue"))); + DBUG_SET("-d,hold_sss_with_err_lock"); + }); + protocol->store(mi->host, &my_charset_bin); protocol->store(mi->user, &my_charset_bin); protocol->store((uint32) mi->port); @@ -3197,7 +3205,8 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full, while the slave is processing ignored events, such as those skipped due to slave_skip_counter. */ - if (mi->using_parallel() && idle && !mi->rli.parallel.workers_idle()) + if (mi->using_parallel() && idle && + !rpl_parallel::workers_idle(&mi->rli)) idle= false; } if (idle) From bd010292557a571089c91e75b77fe773ab4ee2d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 11 Dec 2023 15:26:22 +0200 Subject: [PATCH 08/34] MDEV-29972 Crash emitting "Unsupported meta-data version number" error message row_import_read_meta_data(): Use ER_NOT_SUPPORTED_YET instead of ER_IO_READ_ERROR to have a matching error message pattern. --- mysql-test/std_data/mysql80/t2.cfg | Bin 0 -> 637 bytes mysql-test/std_data/mysql80/t2.ibd | Bin 0 -> 114688 bytes .../suite/innodb/r/innodb-wl5522-1.result | 14 +++++++++++- .../suite/innodb/t/innodb-wl5522-1.test | 21 +++++++++++++++++- storage/innobase/row/row0import.cc | 13 +++-------- 5 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 mysql-test/std_data/mysql80/t2.cfg create mode 100644 mysql-test/std_data/mysql80/t2.ibd diff --git a/mysql-test/std_data/mysql80/t2.cfg b/mysql-test/std_data/mysql80/t2.cfg new file mode 100644 index 0000000000000000000000000000000000000000..81f92978393cb4d9af715bc26b68af49349169dd GIT binary patch literal 637 zcmb7>-Acni5QR6X(I8dv5qts-NWr_Rxd}vD(ujJs1d~8PYccDEFXOA$`Su4Qc;kWD zojr5rFHuSzD5Z{OS=0B~tm&^VF6FIK(+%d_WcVI)?lZAH96>ZPODHubo=oJ}7Yjmy zh(WwoyPb0#m&yY%2qOH${6<%cM_uHS0Ei`nK?d~G{NxhWtg>o!oV z4Kj?Q^=t__f<}I+$3GYP0oII3?f?J) literal 0 HcmV?d00001 diff --git a/mysql-test/std_data/mysql80/t2.ibd b/mysql-test/std_data/mysql80/t2.ibd new file mode 100644 index 0000000000000000000000000000000000000000..be2b46a7af1d52f803c88f381759f35557d88f48 GIT binary patch literal 114688 zcmeI*e^kwB0>|<1y-A88l8k21hz%u0#uX-7(aDcOGPP+Z{n(psjq)Qk5gMh`FeUzt8i1?sK2# z)#<-JPouoG>jbID#-~el%Wdt38A3PduC2($tMrnJj`*?@zfHuew)he>Vrj3%X3GqM zT6)r2zwlh@|4;9e3&X^xt+h1n#ku7<&C+cDE-izo5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0;rH!L9i>7v$ec>io20R#|0009ILKmY** z5I_I{1Q0*~0R#|0;Pn?6CFcHRV$MI&+qMOVW$Ts3 zc7ERG-=%%7S8;7yf0wrFbL)F?y)U+ZMgHx}=ZXLV2q1s}0tg_000IagfB*srAbKfKppoT?*{FHI|}-Em>su}&W#7v$PbQ7wsWS-Kz-zdF+Mt@-lSjCo71 zT(~d3Q+h5Jti^${iOL{9rE0lKJW-&#AcQXeFvM4EHAM-6zUE%rQ1K$@v{b#;iJz}6 zD;DcSv7;$0Rh3jW`^0GdX&T>3SL3|c>F)&V8;{#}*~Dkob)}7~w@!q6@64yRi5~AH zExZ;py)HaDD0a|(8-Kmc$HoL^9JP!~b6@LO9jID4GIqNrtihz}qsUzjn|e%|qWi_d zyuJ~E-B#~*POSNBO82QQ<1*)7Z8|U{*?PwD$6Fdtncg*3PyRU7W^>UDBg6b*Jrq@z zt_=>>ku_uV-i%*Yf415K0F-Pw@*W_1Lv}GHXRCcbefQn*6Z!V4?IJ3 zR*bok8`@mIbZL*cE(hjJHL9HS`9|l$gqrofG5hNyeM&T$qwX!g6&{*aaPw-jlUn&f zc>12;aRo7s@#_Vle{+pU(00&*Ox4+^S`d1k5`S#*VX3#>oPrIk^qVas5{n!6D7QK& zqQbL_v*N-96CXvv)`aY;MS;P8+WX{(H~*dzdCAaOU!JWvIp)#CqG0R%_|o;w$3wr= z*}bE0^p6*Qo|yP~iD{`vw!!Z29Cw9|OB&jJ<*cB|_I|O7`TA+otCpQGX&9dQpkPLM zMZ?T>dUe*dR`cxMs8J+*H`ej`s*n0v`t7ZmZ#*?$W?0dGNWnTJ2 zi~97;99`ggw9Dpf`yaFZaLn`CH){iroC%8c`$2eUR&MHl)gk>xe&*hJNshjAt~zJw z?oas2x-@se9_9N>2OC=0W$8aCGyTHJxcG15f;V`3skb^7kL_(!cVK3nN2$&DEAKjo zl#Rbr7Lf72Nnl0V8SQUJ8=Fn}tkCcLwrr*UPOtu-j+vs!-sN}d(D}-U>8|qzPt3Br zIMi(WX1!3K!ZOF|jW)v)O+FbqDy34HXfbwQbm8Xlra|f}UFYtLHB|&E&sq)13RrS_ zP>K3}c&+`&gd<9y=EFv-+@8fOe45;t>ppF9%AqUgbQ}ie+*@^LM@(|^rB7!m2bcQP zdwBQK?&f@Pgl@HWg?rxPbvf#So+oDxzG*dJONo2`UY4pQryo@+9PBLqV!mzkFRp#k z&)qf*9ByE@*D6jGpmlAZ!|3?b94+0SCI#vCktr$%S_FP_@PqM{6IPzi6*RR6mZryB zteKFaF!NrN>U$<>!S`eDtghH{{kmcPqN3j=8(ApKFE>xHtKe5UGdQo1J*VB=A(-UjfJnEtG zZ_>z`Zgfw(y>r)*X)0CC&aRNXJ7vtF6HuN;|JM<+E*E9OrEGW z>=@|Tczn0w++_o|3C^RcT{4VEls5E>@LBWwb;eFhhI^)(&puyq(%h$_t}5@dXp7nD zK~{%mu2kJu{dBomu93SBz2EI_RawuJ8)gTKPi;2&%4ORjgFV{+Sp3V)XU|p!3@}TO zem^M)Ablzy_V4N-`hJzsl~gN)W1BW{Z96!bWp&6_WZwg=ls8z{ula1wWZs2 zjMj>G-DUb>=Dnp?SDLoH_iaHK+|oOubFbJi(;SSFnY(rFeOGEw5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILcr66P{J)g@mva8E#d=vJ0tg_000IagfB*srAb Date: Thu, 16 Nov 2023 14:56:56 +0100 Subject: [PATCH 09/34] MDEV-28971 SEQUENCEs do not work with streaming replication Return an error if user attempts to use SEQUENCEs in combination with streaming replication in a Galera cluster. This is currently not supported. Signed-off-by: Julius Goryavsky --- .../suite/galera_sr/r/MDEV-28971.result | 17 ++++++++++++ mysql-test/suite/galera_sr/t/MDEV-28971.test | 20 ++++++++++++++ sql/ha_sequence.cc | 27 ++++++++++++++----- 3 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 mysql-test/suite/galera_sr/r/MDEV-28971.result create mode 100644 mysql-test/suite/galera_sr/t/MDEV-28971.test diff --git a/mysql-test/suite/galera_sr/r/MDEV-28971.result b/mysql-test/suite/galera_sr/r/MDEV-28971.result new file mode 100644 index 0000000000000..0826f5e6b66b6 --- /dev/null +++ b/mysql-test/suite/galera_sr/r/MDEV-28971.result @@ -0,0 +1,17 @@ +connection node_2; +connection node_1; +CREATE SEQUENCE SEQ NOCACHE ENGINE=InnoDB; +SET SESSION wsrep_trx_fragment_size=1; +SET collation_connection=utf16_thai_520_w2; +SET autocommit=0; +CREATE TABLE t1 (a BLOB UNIQUE); +INSERT INTO t1 VALUES ('AAF'); +SELECT SETVAL (SEQ, 100); +ERROR 42000: This version of MariaDB doesn't yet support 'SEQUENCEs with streaming replication in Galera cluster' +ALTER TABLE t1 ADD CONSTRAINT constraint_1 UNIQUE (a); +Warnings: +Note 1831 Duplicate index `constraint_1`. This is deprecated and will be disallowed in a future release +INSERT INTO t1 VALUES(); +ALTER TABLE t1 ADD KEY(b (50)); +ERROR 42000: Key column 'b' doesn't exist in table +DROP TABLE t1,SEQ; diff --git a/mysql-test/suite/galera_sr/t/MDEV-28971.test b/mysql-test/suite/galera_sr/t/MDEV-28971.test new file mode 100644 index 0000000000000..81238f94b4ab1 --- /dev/null +++ b/mysql-test/suite/galera_sr/t/MDEV-28971.test @@ -0,0 +1,20 @@ +# +# MDEV-28971 - Assertion `total_length + thd->wsrep_sr().log_position() == saved_pos' +# failed in int wsrep_write_cache_inc(THD*, IO_CACHE*, size_t*) +# + +--source include/galera_cluster.inc + +CREATE SEQUENCE SEQ NOCACHE ENGINE=InnoDB; +SET SESSION wsrep_trx_fragment_size=1; +SET collation_connection=utf16_thai_520_w2; +SET autocommit=0; +CREATE TABLE t1 (a BLOB UNIQUE); +INSERT INTO t1 VALUES ('AAF'); +--error ER_NOT_SUPPORTED_YET +SELECT SETVAL (SEQ, 100); +ALTER TABLE t1 ADD CONSTRAINT constraint_1 UNIQUE (a); +INSERT INTO t1 VALUES(); +--error ER_KEY_COLUMN_DOES_NOT_EXITS +ALTER TABLE t1 ADD KEY(b (50)); +DROP TABLE t1,SEQ; diff --git a/sql/ha_sequence.cc b/sql/ha_sequence.cc index 03aee6a43dc7e..5afc37134d210 100644 --- a/sql/ha_sequence.cc +++ b/sql/ha_sequence.cc @@ -261,13 +261,26 @@ int ha_sequence::write_row(const uchar *buf) } #ifdef WITH_WSREP - /* We need to start Galera transaction for select NEXT VALUE FOR - sequence if it is not yet started. Note that ALTER is handled - as TOI. */ - if (WSREP_ON && WSREP(thd) && - !thd->wsrep_trx().active() && - wsrep_thd_is_local(thd)) - wsrep_start_transaction(thd, thd->wsrep_next_trx_id()); + if (WSREP_ON && WSREP(thd) && wsrep_thd_is_local(thd)) + { + if (sequence_locked && + (wsrep_thd_is_SR(thd) || wsrep_streaming_enabled(thd))) + { + my_error(ER_NOT_SUPPORTED_YET, MYF(0), + "SEQUENCEs with streaming replication in Galera cluster"); + DBUG_RETURN(HA_ERR_UNSUPPORTED); + } + + /* + We need to start Galera transaction for select NEXT VALUE FOR + sequence if it is not yet started. Note that ALTER is handled + as TOI. + */ + if (!thd->wsrep_trx().active()) + { + wsrep_start_transaction(thd, thd->wsrep_next_trx_id()); + } + } #endif if (likely(!(error= file->update_first_row(buf)))) From 61daac54d62491fac9b699bccd639494da38a72f Mon Sep 17 00:00:00 2001 From: Daniele Sciascia Date: Tue, 12 Dec 2023 02:53:36 +0100 Subject: [PATCH 10/34] MDEV-27806 GTIDs diverge in Galera cluster after CTAS Add OPTION_GTID_BEGIN to applying side thread. This is needed to avoid intermediate commits when CREATE TABLE AS SELECT is applied, causing one more GTID to be consumed with respect to executing node. Signed-off-by: Julius Goryavsky --- mysql-test/suite/galera/r/MDEV-27806.result | 52 +++++++++++++++++++ .../suite/galera/r/galera_as_master.result | 2 + mysql-test/suite/galera/t/MDEV-27806.opt | 1 + mysql-test/suite/galera/t/MDEV-27806.test | 51 ++++++++++++++++++ .../suite/galera/t/galera_as_master.test | 6 +++ sql/wsrep_applier.cc | 5 ++ sql/wsrep_high_priority_service.cc | 3 ++ 7 files changed, 120 insertions(+) create mode 100644 mysql-test/suite/galera/r/MDEV-27806.result create mode 100644 mysql-test/suite/galera/t/MDEV-27806.opt create mode 100644 mysql-test/suite/galera/t/MDEV-27806.test diff --git a/mysql-test/suite/galera/r/MDEV-27806.result b/mysql-test/suite/galera/r/MDEV-27806.result new file mode 100644 index 0000000000000..0f7ac79e4cdcf --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-27806.result @@ -0,0 +1,52 @@ +connection node_2; +connection node_1; +connection node_1; +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY); +INSERT INTO t1 VALUES (1),(2),(3); +CREATE TABLE ts1 AS SELECT * FROM t1; +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +mysqld-bin.000002 # Gtid # # BEGIN GTID #-#-# +mysqld-bin.000002 # Query # # use `test`; CREATE TABLE `ts1` ( + `f1` int(11) NOT NULL +) +mysqld-bin.000002 # Annotate_rows # # CREATE TABLE ts1 AS SELECT * FROM t1 +mysqld-bin.000002 # Table_map # # table_id: # (test.ts1) +mysqld-bin.000002 # Write_rows_v1 # # table_id: # flags: STMT_END_F +mysqld-bin.000002 # Xid # # COMMIT /* XID */ +connection node_2; +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +mysqld-bin.000003 # Gtid # # BEGIN GTID #-#-# +mysqld-bin.000003 # Query # # use `test`; CREATE TABLE `ts1` ( + `f1` int(11) NOT NULL +) +mysqld-bin.000003 # Annotate_rows # # CREATE TABLE ts1 AS SELECT * FROM t1 +mysqld-bin.000003 # Table_map # # table_id: # (test.ts1) +mysqld-bin.000003 # Write_rows_v1 # # table_id: # flags: STMT_END_F +mysqld-bin.000003 # Xid # # COMMIT /* XID */ +BINLOG_POSITIONS_MATCH +1 +DROP TABLE t1,ts1; +connection node_1; +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY); +CREATE TABLE ts1 AS SELECT * FROM t1; +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +mysqld-bin.000002 # Gtid # # BEGIN GTID #-#-# +mysqld-bin.000002 # Query # # use `test`; CREATE TABLE `ts1` ( + `f1` int(11) NOT NULL +) +mysqld-bin.000002 # Xid # # COMMIT /* XID */ +connection node_2; +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +mysqld-bin.000003 # Gtid # # BEGIN GTID #-#-# +mysqld-bin.000003 # Query # # use `test`; CREATE TABLE `ts1` ( + `f1` int(11) NOT NULL +) +mysqld-bin.000003 # Query # # COMMIT +BINLOG_POSITIONS_MATCH +1 +DROP TABLE t1,ts1; +CALL mtr.add_suppression("Ignoring server id for non bootstrap node"); diff --git a/mysql-test/suite/galera/r/galera_as_master.result b/mysql-test/suite/galera/r/galera_as_master.result index 4aca328be56d7..dd3e017379c54 100644 --- a/mysql-test/suite/galera/r/galera_as_master.result +++ b/mysql-test/suite/galera/r/galera_as_master.result @@ -52,6 +52,8 @@ DROP TABLE t1, t4; SET SQL_LOG_BIN=OFF; DROP TABLE t2, t3; connection node_3; +BINLOG_POSITIONS_MATCH +1 STOP SLAVE; RESET SLAVE ALL; CALL mtr.add_suppression('You need to use --log-bin to make --binlog-format work'); diff --git a/mysql-test/suite/galera/t/MDEV-27806.opt b/mysql-test/suite/galera/t/MDEV-27806.opt new file mode 100644 index 0000000000000..009e761eb2c86 --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-27806.opt @@ -0,0 +1 @@ +--log-bin --log-slave-updates --gtid-strict-mode --wsrep_gtid_mode=on diff --git a/mysql-test/suite/galera/t/MDEV-27806.test b/mysql-test/suite/galera/t/MDEV-27806.test new file mode 100644 index 0000000000000..62a0ca483e02c --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-27806.test @@ -0,0 +1,51 @@ +# +# MDEV-27806 GTIDs diverge after CTAS +# +--source include/galera_cluster.inc + +--connection node_1 +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY); +INSERT INTO t1 VALUES (1),(2),(3); +CREATE TABLE ts1 AS SELECT * FROM t1; +--let binlog_pos= `SELECT @@gtid_binlog_pos` + +--let $MASTER_MYPORT=$NODE_MYPORT_1 +--let $binlog_file=LAST +--let $binlog_limit=8,20 +--source include/show_binlog_events.inc + +--connection node_2 +--let $binlog_limit=7,20 +--source include/show_binlog_events.inc + +--disable_query_log +--eval SELECT STRCMP(@@gtid_binlog_pos, "$binlog_pos") = 0 AS BINLOG_POSITIONS_MATCH; +--enable_query_log + +DROP TABLE t1,ts1; + + +# +# Same as above, with empty CREATE TABLE AS SELECT +# +--connection node_1 +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY); +CREATE TABLE ts1 AS SELECT * FROM t1; +--let binlog_pos= `SELECT @@gtid_binlog_pos` + +--let $MASTER_MYPORT=$NODE_MYPORT_1 +--let $binlog_file=LAST +--let $binlog_limit=18,20 +--source include/show_binlog_events.inc + +--connection node_2 +--let $binlog_limit=17,20 +--source include/show_binlog_events.inc + +--disable_query_log +--eval SELECT STRCMP(@@gtid_binlog_pos, "$binlog_pos") = 0 AS BINLOG_POSITIONS_MATCH; +--enable_query_log + +DROP TABLE t1,ts1; + +CALL mtr.add_suppression("Ignoring server id for non bootstrap node"); diff --git a/mysql-test/suite/galera/t/galera_as_master.test b/mysql-test/suite/galera/t/galera_as_master.test index 1c439ffff6341..a5554a735fef8 100644 --- a/mysql-test/suite/galera/t/galera_as_master.test +++ b/mysql-test/suite/galera/t/galera_as_master.test @@ -52,12 +52,18 @@ DROP TABLE t1, t4; SET SQL_LOG_BIN=OFF; DROP TABLE t2, t3; +--let binlog_pos=`SELECT @@gtid_binlog_pos;` + --connection node_3 --let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; --source include/wait_condition.inc --let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't4'; --source include/wait_condition.inc +--disable_query_log +--eval SELECT STRCMP(@@gtid_binlog_pos, "$binlog_pos") = 0 AS BINLOG_POSITIONS_MATCH; +--enable_query_log + STOP SLAVE; RESET SLAVE ALL; diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc index fd51dbf9439d1..ff6a0a7f60ea7 100644 --- a/sql/wsrep_applier.cc +++ b/sql/wsrep_applier.cc @@ -196,6 +196,11 @@ int wsrep_apply_events(THD* thd, (thd->variables.option_bits & ~OPTION_SKIP_REPLICATION) | (ev->flags & LOG_EVENT_SKIP_REPLICATION_F ? OPTION_SKIP_REPLICATION : 0); + if (ev->get_type_code() == GTID_EVENT) + { + thd->variables.option_bits &= ~OPTION_GTID_BEGIN; + } + ev->thd= thd; exec_res= ev->apply_event(thd->wsrep_rgi); DBUG_PRINT("info", ("exec_event result: %d", exec_res)); diff --git a/sql/wsrep_high_priority_service.cc b/sql/wsrep_high_priority_service.cc index d1e58ed5bad11..1988088d0a807 100644 --- a/sql/wsrep_high_priority_service.cc +++ b/sql/wsrep_high_priority_service.cc @@ -534,6 +534,7 @@ int Wsrep_applier_service::apply_write_set(const wsrep::ws_meta& ws_meta, THD* thd= m_thd; thd->variables.option_bits |= OPTION_BEGIN; + thd->variables.option_bits |= OPTION_GTID_BEGIN; thd->variables.option_bits |= OPTION_NOT_AUTOCOMMIT; DBUG_ASSERT(thd->wsrep_trx().active()); DBUG_ASSERT(thd->wsrep_trx().state() == wsrep::transaction::s_executing); @@ -570,6 +571,8 @@ int Wsrep_applier_service::apply_write_set(const wsrep::ws_meta& ws_meta, thd->wsrep_cs().fragment_applied(ws_meta.seqno()); } thd_proc_info(thd, "wsrep applied write set"); + + thd->variables.option_bits &= ~OPTION_GTID_BEGIN; DBUG_RETURN(ret); } From 9f5078a1d79031c4a781d378af18df9c8c9d2321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 12 Dec 2023 11:43:23 +0200 Subject: [PATCH 11/34] MDEV-20139 innodb.innodb_buffer_pool_dump_pct failed in buildbot with timeout This test was using a sleep of 1 second in an attempt to ensure that the timestamp that is part of an InnoDB status string would increase. This not only prolongs the test execution time by 1+1 seconds, but it also is inaccurate. It is possible that the actual sleep duration is less than a second. Let us wait for the creation of the file ib_buffer_pool and then wait for the buffer pool dump completion. In that way, the test can complete in a dozen or two milliseconds (1% of the previous duration) and work more reliably. --- .../r/innodb_buffer_pool_dump_pct.result | 9 ---- .../innodb/t/innodb_buffer_pool_dump_pct.test | 47 +++++++++---------- 2 files changed, 21 insertions(+), 35 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb_buffer_pool_dump_pct.result b/mysql-test/suite/innodb/r/innodb_buffer_pool_dump_pct.result index fa17487df9767..33adf9baebbda 100644 --- a/mysql-test/suite/innodb/r/innodb_buffer_pool_dump_pct.result +++ b/mysql-test/suite/innodb/r/innodb_buffer_pool_dump_pct.result @@ -3,17 +3,8 @@ col2 VARCHAR(25), col3 varchar(25)) ENGINE=InnoDB; CREATE INDEX idx1 ON tab5(col2(10)); CREATE INDEX idx2 ON tab5(col3(10)); SET GLOBAL innodb_buffer_pool_dump_pct=100; -SELECT variable_value INTO @IBPDS -FROM information_schema.global_status -WHERE variable_name = 'INNODB_BUFFER_POOL_DUMP_STATUS'; SET GLOBAL innodb_buffer_pool_dump_now=ON; SET GLOBAL innodb_buffer_pool_dump_pct=1; -SELECT @@global.innodb_buffer_pool_dump_pct; -@@global.innodb_buffer_pool_dump_pct -1 -SELECT variable_value INTO @IBPDS -FROM information_schema.global_status -WHERE variable_name = 'INNODB_BUFFER_POOL_DUMP_STATUS'; SET GLOBAL innodb_buffer_pool_dump_now=ON; SET GLOBAL innodb_buffer_pool_dump_pct=DEFAULT; DROP TABLE tab5; diff --git a/mysql-test/suite/innodb/t/innodb_buffer_pool_dump_pct.test b/mysql-test/suite/innodb/t/innodb_buffer_pool_dump_pct.test index 381091165ef08..b393ca707785a 100644 --- a/mysql-test/suite/innodb/t/innodb_buffer_pool_dump_pct.test +++ b/mysql-test/suite/innodb/t/innodb_buffer_pool_dump_pct.test @@ -35,49 +35,44 @@ SET GLOBAL innodb_buffer_pool_dump_pct=100; # - The granularity of the timestamp is one second. # - There could have been some dump caused by some previous test # just a few milliseconds before. -# In order to avoid conflict with previous tests, read the current value -# of INNODB_BUFFER_POOL_DUMP_STATUS -# and confirm that the timestamp is different after the dump #*********************************************************** -# Read the current value to compare with the new value. -SELECT variable_value INTO @IBPDS -FROM information_schema.global_status -WHERE variable_name = 'INNODB_BUFFER_POOL_DUMP_STATUS'; -SET GLOBAL innodb_buffer_pool_dump_now=ON; - -# Sleep one second in order to ensure that the time stamp is -# different at next dump ---sleep 1 +--error 0,1 +--remove_file $MYSQLD_DATADIR/ib_buffer_pool +SET GLOBAL innodb_buffer_pool_dump_now=ON; +perl; +my $f="$ENV{MYSQLD_DATADIR}/ib_buffer_pool"; +my $count=300; +until (-e $f) +{ + select(undef, undef, undef, .1); + die "File $f was not created\n" if (0 > --$count); +} +EOF let $wait_condition = SELECT count(*) = 1 FROM information_schema.global_status WHERE variable_name = 'INNODB_BUFFER_POOL_DUMP_STATUS' -AND variable_value != @IBPDS AND variable_value like 'Buffer pool(s) dump completed at%'; --source include/wait_condition.inc --move_file $MYSQLD_DATADIR/ib_buffer_pool $MYSQLD_DATADIR/ib_buffer_pool100 SET GLOBAL innodb_buffer_pool_dump_pct=1; -SELECT @@global.innodb_buffer_pool_dump_pct; - -# Read the current value to compare with the new value. ---disable_warnings -SELECT variable_value INTO @IBPDS -FROM information_schema.global_status -WHERE variable_name = 'INNODB_BUFFER_POOL_DUMP_STATUS'; ---enable_warnings - SET GLOBAL innodb_buffer_pool_dump_now=ON; -# Sleep one second in order to ensure that the time stamp is -# different at next dump ---sleep 1 +perl; +my $f="$ENV{MYSQLD_DATADIR}/ib_buffer_pool"; +my $count=300; +until (-e $f) +{ + select(undef, undef, undef, .1); + die "File $f was not created\n" if (0 > --$count); +} +EOF let $wait_condition = SELECT count(*) = 1 FROM information_schema.global_status WHERE variable_name = 'INNODB_BUFFER_POOL_DUMP_STATUS' -AND variable_value != @IBPDS AND variable_value like 'Buffer pool(s) dump completed at%'; --source include/wait_condition.inc From 68e7909be945895dd0bee1b9d069d8a50488fab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 12 Dec 2023 14:40:45 +0200 Subject: [PATCH 12/34] MDEV-31000 Assertion failed on ALTER TABLE...page_compressed=1 ha_innobase::check_if_supported_inplace_alter(): On ALTER_OPTIONS, if innodb_file_per_table=1 and the table resides in the system tablespace, require that the table be rebuilt (and moved to an .ibd file). Reviewed by: Thirunarayanan Balathandayuthapani Tested by: Matthias Leich --- mysql-test/suite/innodb/r/alter_table.result | 13 ++++++++++++- mysql-test/suite/innodb/t/alter_table.test | 12 +++++++++++- storage/innobase/handler/handler0alter.cc | 8 ++++++-- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/innodb/r/alter_table.result b/mysql-test/suite/innodb/r/alter_table.result index fc0d447e48d8e..015507f230360 100644 --- a/mysql-test/suite/innodb/r/alter_table.result +++ b/mysql-test/suite/innodb/r/alter_table.result @@ -117,5 +117,16 @@ ERROR 42000: Incorrect column specifier for column 'c' CREATE TABLE t1 (c DATETIME AUTO_INCREMENT UNIQUE) ENGINE=InnoDB; ERROR 42000: Incorrect column specifier for column 'c' # +# MDEV-31000 Assertion failed on ALTER TABLE...page_compressed=1 +# +SET @save_file_per_table=@@GLOBAL.innodb_file_per_table; +SET GLOBAL innodb_file_per_table=0; +CREATE TABLE t (c INT PRIMARY KEY) ENGINE=INNODB; +SET GLOBAL innodb_file_per_table=1; +ALTER TABLE t page_compressed=1; +SET GLOBAL innodb_file_per_table=@save_file_per_table; +SELECT space>0 FROM information_schema.innodb_sys_tables WHERE name='test/t'; +space>0 +1 +DROP TABLE t; # End of 10.4 tests -# diff --git a/mysql-test/suite/innodb/t/alter_table.test b/mysql-test/suite/innodb/t/alter_table.test index ae247e7cada59..3ab5199025b85 100644 --- a/mysql-test/suite/innodb/t/alter_table.test +++ b/mysql-test/suite/innodb/t/alter_table.test @@ -121,6 +121,16 @@ CREATE TABLE t1 (c TIMESTAMP AUTO_INCREMENT UNIQUE) ENGINE=InnoDB; CREATE TABLE t1 (c DATETIME AUTO_INCREMENT UNIQUE) ENGINE=InnoDB; --echo # ---echo # End of 10.4 tests +--echo # MDEV-31000 Assertion failed on ALTER TABLE...page_compressed=1 --echo # +SET @save_file_per_table=@@GLOBAL.innodb_file_per_table; +SET GLOBAL innodb_file_per_table=0; +CREATE TABLE t (c INT PRIMARY KEY) ENGINE=INNODB; +SET GLOBAL innodb_file_per_table=1; +ALTER TABLE t page_compressed=1; +SET GLOBAL innodb_file_per_table=@save_file_per_table; +SELECT space>0 FROM information_schema.innodb_sys_tables WHERE name='test/t'; +DROP TABLE t; + +--echo # End of 10.4 tests diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index b61949620f787..74c2703218d3c 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -2155,12 +2155,16 @@ ha_innobase::check_if_supported_inplace_alter( } } + bool need_rebuild = false; + switch (ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE) { case ALTER_OPTIONS: - if (alter_options_need_rebuild(ha_alter_info, table)) { + if ((srv_file_per_table && !m_prebuilt->table->space_id) + || alter_options_need_rebuild(ha_alter_info, table)) { reason_rebuild = my_get_err_msg( ER_ALTER_OPERATION_TABLE_OPTIONS_NEED_REBUILD); ha_alter_info->unsupported_reason = reason_rebuild; + need_rebuild= true; break; } /* fall through */ @@ -2272,7 +2276,7 @@ ha_innobase::check_if_supported_inplace_alter( /* We should be able to do the operation in-place. See if we can do it online (LOCK=NONE) or without rebuild. */ - bool online = true, need_rebuild = false; + bool online = true; const uint fulltext_indexes = innobase_fulltext_exist(altered_table); /* Fix the key parts. */ From 6193d0cabb241478984ea7ba8a6f7e5d4015b627 Mon Sep 17 00:00:00 2001 From: Sergei Glushchenko Date: Thu, 22 Jun 2023 16:52:40 +1000 Subject: [PATCH 13/34] MDEV-20286 mariabackup fails when innodb_max_dirty_pages_pct contains a fraction (is not an integer) This is a port of the Percona Server commit 5265f42e290573e9591f8ca28ab66afc051f89a3 which is the same as their bug PXB-1807: xtrabackup does not accept fractional values for innodb_max_dirty_pages_pct Problem: Variable specified as double in MySQL server, but read as long in the xtrabackup. This causes xtrabackup to fail at startup when the value contains decimal point. Fix: Make xtrabackup to interpret the value as double to be compatible with server. --- extra/mariabackup/xtrabackup.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 0c018b97d29d4..b8d3d729d88a2 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -1647,8 +1647,11 @@ struct my_option xb_server_options[] = "Path to InnoDB log files.", &srv_log_group_home_dir, &srv_log_group_home_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"innodb_max_dirty_pages_pct", OPT_INNODB_MAX_DIRTY_PAGES_PCT, - "Percentage of dirty pages allowed in bufferpool.", (G_PTR*) &srv_max_buf_pool_modified_pct, - (G_PTR*) &srv_max_buf_pool_modified_pct, 0, GET_ULONG, REQUIRED_ARG, 90, 0, 100, 0, 0, 0}, + "Percentage of dirty pages allowed in bufferpool.", + (G_PTR*) &srv_max_buf_pool_modified_pct, + (G_PTR*) &srv_max_buf_pool_modified_pct, 0, GET_DOUBLE, REQUIRED_ARG, + (longlong)getopt_double2ulonglong(90), (longlong)getopt_double2ulonglong(0), + getopt_double2ulonglong(100), 0, 0, 0}, {"innodb_use_native_aio", OPT_INNODB_USE_NATIVE_AIO, "Use native AIO if supported on this platform.", (G_PTR*) &srv_use_native_aio, From 7504985dafe0724f09ac07c0514623ba6c39eaee Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 5 Oct 2023 16:55:34 +0300 Subject: [PATCH 14/34] MDEV-21587: disk.disk{_notembedded} test result MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow for a CI system to be almost out of space, or having so little use, that the Total space is the same as available or used. Thanks Otto Kekäläinen for the bug report and testing. --- plugin/disks/mysql-test/disks/disks.result | 4 ++-- plugin/disks/mysql-test/disks/disks.test | 2 +- plugin/disks/mysql-test/disks/disks_notembedded.result | 8 ++++---- plugin/disks/mysql-test/disks/disks_notembedded.test | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/plugin/disks/mysql-test/disks/disks.result b/plugin/disks/mysql-test/disks/disks.result index 229f8dbf353c6..2c124faa91f59 100644 --- a/plugin/disks/mysql-test/disks/disks.result +++ b/plugin/disks/mysql-test/disks/disks.result @@ -7,6 +7,6 @@ DISKS CREATE TEMPORARY TABLE `DISKS` ( `Used` bigint(32) NOT NULL, `Available` bigint(32) NOT NULL ) ENGINE=MEMORY DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci -select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks; -sum(Total) > sum(Available) sum(Total)>sum(Used) +select sum(Total) >= sum(Available), sum(Total)>=sum(Used) from information_schema.disks; +sum(Total) >= sum(Available) sum(Total)>=sum(Used) 1 1 diff --git a/plugin/disks/mysql-test/disks/disks.test b/plugin/disks/mysql-test/disks/disks.test index 7189c54834279..9adc3f01ebc6c 100644 --- a/plugin/disks/mysql-test/disks/disks.test +++ b/plugin/disks/mysql-test/disks/disks.test @@ -1,3 +1,3 @@ --replace_regex /varchar\([0-9]+\)/varchar(pathlen)/ show create table information_schema.disks; -select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks; +select sum(Total) >= sum(Available), sum(Total)>=sum(Used) from information_schema.disks; diff --git a/plugin/disks/mysql-test/disks/disks_notembedded.result b/plugin/disks/mysql-test/disks/disks_notembedded.result index 974294744cc1b..ea2ccc85bfbb1 100644 --- a/plugin/disks/mysql-test/disks/disks_notembedded.result +++ b/plugin/disks/mysql-test/disks/disks_notembedded.result @@ -6,16 +6,16 @@ CREATE USER user1@localhost; GRANT SELECT ON *.* TO user1@localhost; connect con1,localhost,user1,,; connection con1; -select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks; -sum(Total) > sum(Available) sum(Total)>sum(Used) +select sum(Total) >= sum(Available), sum(Total) >= sum(Used) from information_schema.disks; +sum(Total) >= sum(Available) sum(Total) >= sum(Used) NULL NULL disconnect con1; connection default; GRANT FILE ON *.* TO user1@localhost; connect con1,localhost,user1,,; connection con1; -select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks; -sum(Total) > sum(Available) sum(Total)>sum(Used) +select sum(Total) >= sum(Available), sum(Total) >= sum(Used) from information_schema.disks; +sum(Total) >= sum(Available) sum(Total) >= sum(Used) 1 1 connection default; DROP USER user1@localhost; diff --git a/plugin/disks/mysql-test/disks/disks_notembedded.test b/plugin/disks/mysql-test/disks/disks_notembedded.test index a0f6c2e5887ff..4481da9f17646 100644 --- a/plugin/disks/mysql-test/disks/disks_notembedded.test +++ b/plugin/disks/mysql-test/disks/disks_notembedded.test @@ -10,7 +10,7 @@ GRANT SELECT ON *.* TO user1@localhost; connect (con1,localhost,user1,,); connection con1; -select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks; +select sum(Total) >= sum(Available), sum(Total) >= sum(Used) from information_schema.disks; disconnect con1; connection default; @@ -18,7 +18,7 @@ GRANT FILE ON *.* TO user1@localhost; connect (con1,localhost,user1,,); connection con1; -select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks; +select sum(Total) >= sum(Available), sum(Total) >= sum(Used) from information_schema.disks; connection default; DROP USER user1@localhost; From fbe604d88396db5214008a784061b501a9a93445 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 14 Nov 2023 10:01:08 +1100 Subject: [PATCH 15/34] MDEV-32795: ALTER SEQUENCE IF NOT EXISTS non_existing_seq Errors rather than note Like all IF NOT EXISTS syntax, a Note should be generated. The original commit of Seqeuences cleared the IF NOT EXISTS part in the sql/sql_yacc.yy with lex->create_info.init(). Without this bit set there was no way it could do anything other than error. To remedy this removal, the sql_yacc.yy components have been minimised as they where all set at the beginning of the ALTER. This way the opt_if_not_exists correctly set the IF_EXISTS flag. In MDEV-13005 (bb4dd70e7c65) the error code changed, requiring ER_UNKNOWN_SEQUENCES to be handled in the function No_such_table_error_handler::handle_condition. --- mysql-test/suite/sql_sequence/alter.result | 6 +++++- mysql-test/suite/sql_sequence/alter.test | 6 +++++- sql/sql_base.cc | 4 +++- sql/sql_yacc.yy | 4 ---- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/sql_sequence/alter.result b/mysql-test/suite/sql_sequence/alter.result index 90de2ebfcc0c7..68d42e5278479 100644 --- a/mysql-test/suite/sql_sequence/alter.result +++ b/mysql-test/suite/sql_sequence/alter.result @@ -210,8 +210,12 @@ create table t1 (a int); alter sequence t1 minvalue=100; ERROR 42S02: 'test.t1' is not a SEQUENCE drop table t1; +# +# MDEV-32795: ALTER SEQUENCE IF NOT EXISTS non_existing_seq Errors rather than note +# alter sequence if exists t1 minvalue=100; -ERROR 42S02: Unknown SEQUENCE: 't1' +Warnings: +Note 4091 Unknown SEQUENCE: 'test.t1' alter sequence t1 minvalue=100; ERROR 42S02: Unknown SEQUENCE: 't1' create sequence t1; diff --git a/mysql-test/suite/sql_sequence/alter.test b/mysql-test/suite/sql_sequence/alter.test index e6bbaba614a84..a771c9bba2f78 100644 --- a/mysql-test/suite/sql_sequence/alter.test +++ b/mysql-test/suite/sql_sequence/alter.test @@ -120,8 +120,12 @@ create table t1 (a int); alter sequence t1 minvalue=100; drop table t1; ---error ER_UNKNOWN_SEQUENCES +--echo # +--echo # MDEV-32795: ALTER SEQUENCE IF NOT EXISTS non_existing_seq Errors rather than note +--echo # + alter sequence if exists t1 minvalue=100; + --error ER_UNKNOWN_SEQUENCES alter sequence t1 minvalue=100; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 627dc6ff5f666..4e8598a8d6569 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -77,7 +77,9 @@ No_such_table_error_handler::handle_condition(THD *, Sql_condition ** cond_hdl) { *cond_hdl= NULL; - if (sql_errno == ER_NO_SUCH_TABLE || sql_errno == ER_NO_SUCH_TABLE_IN_ENGINE) + if (sql_errno == ER_NO_SUCH_TABLE + || sql_errno == ER_NO_SUCH_TABLE_IN_ENGINE + || sql_errno == ER_UNKNOWN_SEQUENCES) { m_handled_errors++; return TRUE; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0b893c952bd6c..f6f826e3e072b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -8128,11 +8128,7 @@ alter: | ALTER SEQUENCE_SYM opt_if_exists { LEX *lex= Lex; - lex->name= null_clex_str; - lex->table_type= TABLE_TYPE_UNKNOWN; lex->sql_command= SQLCOM_ALTER_SEQUENCE; - lex->create_info.init(); - lex->no_write_to_binlog= 0; DBUG_ASSERT(!lex->m_sql_cmd); if (Lex->main_select_push()) MYSQL_YYABORT; From c17aca2f11c21ed53c7f0ce5f0cb39403e20feb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 13 Dec 2023 15:01:50 +0200 Subject: [PATCH 16/34] MDEV-18322 Assertion "wrong page type" on instant ALTER TABLE row_ins_clust_index_entry_low(): Invoke btr_set_instant() in the same mini-transaction that has successfully inserted the metadata record. In this way, if inserting the metadata record fails before any undo log record was written for it, the index root page will remain consistent. innobase_instant_try(): Remove the btr_set_instant() call. Reviewed by: Thirunarayanan Balathandayuthapani Tested by: Matthias Leich --- .../suite/innodb/r/instant_alter_bugs.result | 24 ++++++++++++++++++ .../suite/innodb/t/instant_alter_bugs.test | 25 +++++++++++++++++++ storage/innobase/handler/handler0alter.cc | 4 --- storage/innobase/row/row0ins.cc | 20 ++++++++++----- 4 files changed, 63 insertions(+), 10 deletions(-) diff --git a/mysql-test/suite/innodb/r/instant_alter_bugs.result b/mysql-test/suite/innodb/r/instant_alter_bugs.result index 92c27a35bd4d0..ded6cc671ef44 100644 --- a/mysql-test/suite/innodb/r/instant_alter_bugs.result +++ b/mysql-test/suite/innodb/r/instant_alter_bugs.result @@ -495,4 +495,28 @@ SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency; CREATE TABLE t1 (i int AS (0) STORED, j INT) ENGINE=InnoDB; ALTER TABLE t1 ADD COLUMN i INT GENERATED ALWAYS AS (1), DROP COLUMN i; DROP TABLE t1; +# +# MDEV-18322 Assertion "wrong_page_type" on instant ALTER +# +BEGIN NOT ATOMIC +DECLARE c TEXT +DEFAULT(SELECT CONCAT('CREATE TABLE t1 (c', +GROUP_CONCAT(seq SEPARATOR ' CHAR(200), c'), +' CHAR(211)) ENGINE=InnoDB ROW_FORMAT=REDUNDANT') +FROM seq_1_to_40); +EXECUTE IMMEDIATE c; +END; +$$ +INSERT INTO t1 SET c1=NULL; +ALTER TABLE t1 ADD c41 INT FIRST; +ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8123. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs +ALTER TABLE t1 ADD c41 INT FIRST; +ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8123. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +SELECT COUNT(*) FROM t1; +COUNT(*) +1 +DROP TABLE t1; # End of 10.4 tests diff --git a/mysql-test/suite/innodb/t/instant_alter_bugs.test b/mysql-test/suite/innodb/t/instant_alter_bugs.test index debd5d305620d..88b2549623b6c 100644 --- a/mysql-test/suite/innodb/t/instant_alter_bugs.test +++ b/mysql-test/suite/innodb/t/instant_alter_bugs.test @@ -1,4 +1,5 @@ --source include/have_innodb.inc +--source include/have_sequence.inc SET @save_frequency= @@GLOBAL.innodb_purge_rseg_truncate_frequency; SET GLOBAL innodb_purge_rseg_truncate_frequency=1; @@ -526,4 +527,28 @@ CREATE TABLE t1 (i int AS (0) STORED, j INT) ENGINE=InnoDB; ALTER TABLE t1 ADD COLUMN i INT GENERATED ALWAYS AS (1), DROP COLUMN i; DROP TABLE t1; +--echo # +--echo # MDEV-18322 Assertion "wrong_page_type" on instant ALTER +--echo # + +DELIMITER $$; +BEGIN NOT ATOMIC + DECLARE c TEXT + DEFAULT(SELECT CONCAT('CREATE TABLE t1 (c', + GROUP_CONCAT(seq SEPARATOR ' CHAR(200), c'), + ' CHAR(211)) ENGINE=InnoDB ROW_FORMAT=REDUNDANT') + FROM seq_1_to_40); + EXECUTE IMMEDIATE c; +END; +$$ +DELIMITER ;$$ +INSERT INTO t1 SET c1=NULL; +--error ER_TOO_BIG_ROWSIZE +ALTER TABLE t1 ADD c41 INT FIRST; +--error ER_TOO_BIG_ROWSIZE +ALTER TABLE t1 ADD c41 INT FIRST; +CHECK TABLE t1; +SELECT COUNT(*) FROM t1; +DROP TABLE t1; + --echo # End of 10.4 tests diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 74c2703218d3c..be02fc9e0a6d4 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -6130,10 +6130,6 @@ static bool innobase_instant_try( goto err_exit; } - btr_set_instant(root, *index, &mtr); - mtr.commit(); - mtr.start(); - index->set_modified(mtr); err = row_ins_clust_index_entry_low( BTR_NO_LOCKING_FLAG, BTR_MODIFY_TREE, index, index->n_uniq, entry, 0, thr); diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 6765ba546d585..088981e5b5b08 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -2657,14 +2657,17 @@ row_ins_clust_index_entry_low( ut_ad(!dict_index_is_online_ddl(index)); ut_ad(!index->table->persistent_autoinc); ut_ad(!index->is_instant()); + ut_ad(!entry->info_bits); mtr.set_log_mode(MTR_LOG_NO_REDO); } else { index->set_modified(mtr); - if (UNIV_UNLIKELY(entry->is_metadata())) { + if (UNIV_UNLIKELY(entry->info_bits != 0)) { + ut_ad(entry->is_metadata()); ut_ad(index->is_instant()); ut_ad(!dict_index_is_online_ddl(index)); ut_ad(mode == BTR_MODIFY_TREE); + ut_ad(flags == BTR_NO_LOCKING_FLAG); } else { if (mode == BTR_MODIFY_LEAF && dict_index_is_online_ddl(index)) { @@ -2716,11 +2719,6 @@ row_ins_clust_index_entry_low( #endif /* UNIV_DEBUG */ if (UNIV_UNLIKELY(entry->info_bits != 0)) { - ut_ad(entry->is_metadata()); - ut_ad(flags == BTR_NO_LOCKING_FLAG); - ut_ad(index->is_instant()); - ut_ad(!dict_index_is_online_ddl(index)); - const rec_t* rec = btr_cur_get_rec(cursor); if (rec_get_info_bits(rec, page_rec_is_comp(rec)) @@ -2830,7 +2828,17 @@ row_ins_clust_index_entry_low( } } + if (err == DB_SUCCESS && entry->info_bits) { + if (buf_block_t* root + = btr_root_block_get(index, RW_X_LATCH, &mtr)) { + btr_set_instant(root, *index, &mtr); + } else { + ut_ad("cannot find root page" == 0); + } + } + if (big_rec != NULL) { + ut_ad(err == DB_SUCCESS); mtr_commit(&mtr); /* Online table rebuild could read (and From b4712242dd6d2a50ebe3eb01d22a076820c6a65e Mon Sep 17 00:00:00 2001 From: Rex Date: Wed, 11 Oct 2023 15:05:58 +1200 Subject: [PATCH 17/34] MDEV-31279 Crash when lateral derived is guaranteed to return no rows Consider this query SELECT t1.* FROM t1, (SELECT t2.b FROM t2 WHERE NOT EXISTS (SELECT 1 FROM t3) GROUP BY b) sq where sq.b = t1.a; If SELECT 1 FROM t3 is expensive, for example t3 has > thd->variables.expensive_subquery_limit, first evaluation is deferred to mysql_derived_fill(). There it is noted that, in the above case NOT EXISTS (SELECT 1 FROM t3) is constant and false. This causes the join variable zero_result_cause to be set to "Impossible WHERE noticed after reading const tables" and the handler for this join is never "opened" via handler::ha_open. When mysql_derived_fill() is called for the next group of results, this unopened handler is not taken into account. reviewed by Igor Babaev (igor@mariadb.com) --- mysql-test/main/derived_split_innodb.result | 15 +++++++++++++++ mysql-test/main/derived_split_innodb.test | 18 ++++++++++++++++++ sql/sql_derived.cc | 3 +++ 3 files changed, 36 insertions(+) diff --git a/mysql-test/main/derived_split_innodb.result b/mysql-test/main/derived_split_innodb.result index 22974251c56f7..91241627b73d8 100644 --- a/mysql-test/main/derived_split_innodb.result +++ b/mysql-test/main/derived_split_innodb.result @@ -826,4 +826,19 @@ SELECT * FROM t1 JOIN t2 WHERE (t1.a, t2.b) IN (SELECT * FROM v); a b DROP VIEW v; DROP TABLE t1, t2, t3; +# +# MDEV-31279 Crash when lateral derived is guaranteed to return no rows +# +CREATE TABLE t1 (a CHAR(1)) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('1'),('2'); +CREATE TABLE t2 (b INT, KEY(b)) ENGINE=MyISAM; +ALTER TABLE t2 DISABLE KEYS; +INSERT INTO t2 VALUES (1),(2),(3); +ALTER TABLE t2 ENABLE KEYS; +CREATE TABLE t3 (c INT) ENGINE=MyISAM; +INSERT INTO t3 (c) SELECT seq FROM seq_1_to_101; +SELECT * FROM t1 WHERE t1.a IN (SELECT b FROM +(SELECT t2.b FROM t2 WHERE NOT EXISTS (SELECT 1 FROM t3) GROUP BY b) sq); +a +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 3c51f54fe0221..e2f41a1799408 100644 --- a/mysql-test/main/derived_split_innodb.test +++ b/mysql-test/main/derived_split_innodb.test @@ -483,4 +483,22 @@ SELECT * FROM t1 JOIN t2 WHERE (t1.a, t2.b) IN (SELECT * FROM v); DROP VIEW v; DROP TABLE t1, t2, t3; +--echo # +--echo # MDEV-31279 Crash when lateral derived is guaranteed to return no rows +--echo # + +CREATE TABLE t1 (a CHAR(1)) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('1'),('2'); +CREATE TABLE t2 (b INT, KEY(b)) ENGINE=MyISAM; +ALTER TABLE t2 DISABLE KEYS; +INSERT INTO t2 VALUES (1),(2),(3); +ALTER TABLE t2 ENABLE KEYS; +CREATE TABLE t3 (c INT) ENGINE=MyISAM; +INSERT INTO t3 (c) SELECT seq FROM seq_1_to_101; + +SELECT * FROM t1 WHERE t1.a IN (SELECT b FROM + (SELECT t2.b FROM t2 WHERE NOT EXISTS (SELECT 1 FROM t3) GROUP BY b) sq); + +DROP TABLE t1, t2, t3; + --echo # End of 10.4 tests diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 54ef1c3a59fdb..782894444dff9 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -1227,6 +1227,9 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) goto err; JOIN *join= unit->first_select()->join; join->first_record= false; + if (join->zero_result_cause) + goto err; + for (uint i= join->top_join_tab_count; i < join->top_join_tab_count + join->aggr_tables; i++) From 852e1383e305d5b88e62b7246a914ee1e16e4b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 13 Dec 2023 15:40:29 +0200 Subject: [PATCH 18/34] MDEV-21245 InnoDB: Using a partial-field key prefix in search ha_innobase::compare_key_parts(): If a full column index is being replaced with a column prefix index, return Compare_keys::NotEqual. --- .../r/innodb_prefix_index_restart_server.result | 16 ++++++++++++++++ .../t/innodb_prefix_index_restart_server.test | 14 ++++++++++++++ storage/innobase/handler/ha_innodb.cc | 4 ++++ 3 files changed, 34 insertions(+) diff --git a/mysql-test/suite/innodb/r/innodb_prefix_index_restart_server.result b/mysql-test/suite/innodb/r/innodb_prefix_index_restart_server.result index 1e97c21c2536c..1ccf79e451710 100644 --- a/mysql-test/suite/innodb/r/innodb_prefix_index_restart_server.result +++ b/mysql-test/suite/innodb/r/innodb_prefix_index_restart_server.result @@ -90,3 +90,19 @@ worklog5743; col_1_text = REPEAT("a", 3500) col_2_text = REPEAT("o", 3500) 1 1 DROP TABLE worklog5743; +# +# MDEV-21245 InnoDB: Using a partial-field key prefix in search +# +CREATE TABLE t1 (a VARCHAR(255), KEY k(a)) DEFAULT CHARSET=utf8mb3 +ENGINE=InnoDB; +INSERT INTO t1 set a=''; +alter table t1 change a a varchar(3000); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 1 +Warnings: +Note 1071 Specified key was too long; max key length is 3072 bytes +SELECT * FROM t1 WHERE a IN (''); +a + +DROP TABLE t1; +# End of 10.4 tests diff --git a/mysql-test/suite/innodb/t/innodb_prefix_index_restart_server.test b/mysql-test/suite/innodb/t/innodb_prefix_index_restart_server.test index 1fb7c6d0f7740..fa93e95c64225 100644 --- a/mysql-test/suite/innodb/t/innodb_prefix_index_restart_server.test +++ b/mysql-test/suite/innodb/t/innodb_prefix_index_restart_server.test @@ -93,3 +93,17 @@ SELECT col_1_text = REPEAT("a", 3500) , col_2_text = REPEAT("o", 3500) FROM worklog5743; DROP TABLE worklog5743; + +--echo # +--echo # MDEV-21245 InnoDB: Using a partial-field key prefix in search +--echo # +CREATE TABLE t1 (a VARCHAR(255), KEY k(a)) DEFAULT CHARSET=utf8mb3 +ENGINE=InnoDB; +INSERT INTO t1 set a=''; +--enable_info +alter table t1 change a a varchar(3000); +--disable_info +SELECT * FROM t1 WHERE a IN (''); +DROP TABLE t1; + +--echo # End of 10.4 tests diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 086f30e119e59..4c27a70a0f3d5 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -21199,6 +21199,10 @@ Compare_keys ha_innobase::compare_key_parts( if (old_part.length >= new_part.length) return Compare_keys::NotEqual; + if (old_part.length == old_field.key_length() && + new_part.length != new_field.key_length) + return Compare_keys::NotEqual; + return Compare_keys::EqualButKeyPartLength; } From 4eca64e33105d2495ebebd028405998e79b5cc5a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 14 Dec 2023 20:25:58 +0100 Subject: [PATCH 19/34] add missing result file --- .../spider/bugfix/r/mdev_28739_simple.result | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_28739_simple.result diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_28739_simple.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_28739_simple.result new file mode 100644 index 0000000000000..db232f8a6d373 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_28739_simple.result @@ -0,0 +1,20 @@ +# +# MDEV-28739 Trying to lock uninitialized mutex or hang upon shutdown after using Spider with query_cache +# +for master_1 +for child2 +for child3 +set global query_cache_type= on; +CREATE SERVER srv FOREIGN DATA WRAPPER mysql +OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root'); +create table t2 (c int); +create table t1 (c int) ENGINE=Spider +COMMENT='WRAPPER "mysql", srv "srv",TABLE "t2"'; +SELECT * FROM t1; +c +# restart +drop table t1, t2; +drop server srv; +for master_1 +for child2 +for child3 From c5d7036e1aa1e9aa91946506ee81d6d02881e710 Mon Sep 17 00:00:00 2001 From: Sisi Huang Date: Sun, 10 Dec 2023 08:16:48 -0800 Subject: [PATCH 20/34] MDEV-32942 Fix Memory Leak in my_print_defaults with Non-Existing Config Files --- extra/my_print_defaults.c | 1 + 1 file changed, 1 insertion(+) diff --git a/extra/my_print_defaults.c b/extra/my_print_defaults.c index 9880d4d60d7cf..f62ae86ae53b8 100644 --- a/extra/my_print_defaults.c +++ b/extra/my_print_defaults.c @@ -183,6 +183,7 @@ int main(int argc, char **argv) if ((error= load_defaults(config_file, (const char **) load_default_groups, &count, &arguments))) { + my_free(load_default_groups); my_end(0); if (error == 4) return 0; From a2c6d61db82654de61133bb5de2ae79340e96a67 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 15 Dec 2023 00:33:54 +0100 Subject: [PATCH 21/34] don't use dynstr_append() in mysqltest.cc followup for ad796aaa943 --- client/mysqltest.cc | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index d3af3c216a94d..b25f4621ec0a0 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -91,6 +91,8 @@ static my_bool non_blocking_api_enabled= 0; #define CLOSED_CONNECTION "-closed_connection-" +#define dynstr_append DO_NO_USE + #ifndef HAVE_SETENV static int setenv(const char *name, const char *value, int overwrite); #endif @@ -1864,7 +1866,7 @@ static int run_tool(const char *tool_path, DYNAMIC_STRING *ds_res, ...) if (strncmp(arg, "--", 2) == 0) dynstr_append_os_quoted(&ds_cmdline, arg, NullS); else - dynstr_append(&ds_cmdline, arg); + dynstr_append_mem(&ds_cmdline, arg, strlen(arg)); dynstr_append_mem(&ds_cmdline, STRING_WITH_LEN(" ")); } @@ -2021,11 +2023,11 @@ void show_diff(DYNAMIC_STRING* ds, dynstr_append_mem(&ds_tmp, message, sizeof(message)); dynstr_append_mem(&ds_tmp, STRING_WITH_LEN(" --- ")); - dynstr_append(&ds_tmp, filename1); + dynstr_append_mem(&ds_tmp, filename1, strlen(filename1)); dynstr_append_mem(&ds_tmp, STRING_WITH_LEN(" >>>\n")); cat_file(&ds_tmp, filename1); dynstr_append_mem(&ds_tmp, STRING_WITH_LEN("<<<\n --- ")); - dynstr_append(&ds_tmp, filename1); + dynstr_append_mem(&ds_tmp, filename1, strlen(filename1)); dynstr_append_mem(&ds_tmp, STRING_WITH_LEN(" >>>\n")); cat_file(&ds_tmp, filename2); dynstr_append_mem(&ds_tmp, STRING_WITH_LEN("<<<<\n")); @@ -3276,13 +3278,15 @@ static int replace(DYNAMIC_STRING *ds_str, { DYNAMIC_STRING ds_tmp; const char *start= strstr(ds_str->str, search_str); + size_t prefixlen= start - ds_str->str; if (!start) return 1; init_dynamic_string(&ds_tmp, "", ds_str->length + replace_len, 256); - dynstr_append_mem(&ds_tmp, ds_str->str, start - ds_str->str); + dynstr_append_mem(&ds_tmp, ds_str->str, prefixlen); dynstr_append_mem(&ds_tmp, replace_str, replace_len); - dynstr_append(&ds_tmp, start + search_len); + dynstr_append_mem(&ds_tmp, start + search_len, + ds_str->length - prefixlen - search_len); dynstr_set(ds_str, ds_tmp.str); dynstr_free(&ds_tmp); return 0; @@ -3737,7 +3741,7 @@ void do_remove_files_wildcard(struct st_command *command) wild_compare(file->name, ds_wild.str, 0)) continue; ds_file_to_remove.length= directory_length; - dynstr_append(&ds_file_to_remove, file->name); + dynstr_append_mem(&ds_file_to_remove, file->name, strlen(file->name)); DBUG_PRINT("info", ("removing file: %s", ds_file_to_remove.str)); if ((error= (my_delete(ds_file_to_remove.str, MYF(MY_WME)) != 0))) sys_errno= my_errno; @@ -7575,7 +7579,7 @@ void append_field(DYNAMIC_STRING *ds, uint col_idx, MYSQL_FIELD* field, } else { - dynstr_append(ds, field->name); + dynstr_append_mem(ds, field->name, strlen(field->name)); dynstr_append_mem(ds, "\t", 1); replace_dynstr_append_mem(ds, val, len); dynstr_append_mem(ds, "\n", 1); @@ -7736,12 +7740,12 @@ void append_info(DYNAMIC_STRING *ds, ulonglong affected_rows, const char *info) { char buf[40], buff2[21]; - sprintf(buf,"affected rows: %s\n", llstr(affected_rows, buff2)); - dynstr_append(ds, buf); + size_t len= sprintf(buf,"affected rows: %s\n", llstr(affected_rows, buff2)); + dynstr_append_mem(ds, buf, len); if (info) { dynstr_append_mem(ds, STRING_WITH_LEN("info: ")); - dynstr_append(ds, info); + dynstr_append_mem(ds, info, strlen(info)); dynstr_append_mem(ds, STRING_WITH_LEN("\n")); } } @@ -9613,7 +9617,7 @@ void mark_progress(struct st_command* command __attribute__((unused)), dynstr_append_mem(&ds_progress, "\t", 1); /* Filename */ - dynstr_append(&ds_progress, cur_file->file_name); + dynstr_append_mem(&ds_progress, cur_file->file_name, strlen(cur_file->file_name)); dynstr_append_mem(&ds_progress, ":", 1); /* Line in file */ @@ -11895,7 +11899,7 @@ void dynstr_append_sorted(DYNAMIC_STRING* ds, DYNAMIC_STRING *ds_input, for (i= 0; i < lines.elements ; i++) { const char **line= dynamic_element(&lines, i, const char**); - dynstr_append(ds, *line); + dynstr_append_mem(ds, *line, strlen(*line)); dynstr_append_mem(ds, STRING_WITH_LEN("\n")); } From 59a984b4d87aab8214218d187ddb10744c864600 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Fri, 15 Dec 2023 15:43:19 +0530 Subject: [PATCH 22/34] MDEV-32725 innodb.import_update_stats accesses uninitialized ib_table->stat_n_rows - InnoDB should write all zeros into a table and its indexes statistics members when table is unreadable. --- mysql-test/suite/innodb/t/import_update_stats.test | 1 - storage/innobase/dict/dict0stats.cc | 11 ++--------- storage/innobase/handler/ha_innodb.cc | 2 +- storage/innobase/include/dict0stats.h | 9 +++++++++ 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/mysql-test/suite/innodb/t/import_update_stats.test b/mysql-test/suite/innodb/t/import_update_stats.test index 128213c77b2a1..e1b1ae5d87f3f 100644 --- a/mysql-test/suite/innodb/t/import_update_stats.test +++ b/mysql-test/suite/innodb/t/import_update_stats.test @@ -4,7 +4,6 @@ --source include/not_embedded.inc --source include/have_innodb.inc ---source include/not_valgrind.inc # MDEV-32725 FIXME let MYSQLD_DATADIR =`SELECT @@datadir`; SET @old_innodb_file_per_table = @@innodb_file_per_table; diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index 5371fe50dbc63..16f4adb70d939 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -530,16 +530,9 @@ dict_stats_empty_index( } } -/*********************************************************************//** -Write all zeros (or 1 where it makes sense) into a table and its indexes' -statistics members. The resulting stats correspond to an empty table. */ -static -void -dict_stats_empty_table( -/*===================*/ - dict_table_t* table, /*!< in/out: table */ +void dict_stats_empty_table( + dict_table_t* table, bool empty_defrag_stats) - /*!< in: whether to empty defrag stats */ { mutex_enter(&dict_sys.mutex); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 4c27a70a0f3d5..1f1810323338d 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -14316,7 +14316,7 @@ ha_innobase::info_low( DBUG_ASSERT(ib_table->get_ref_count() > 0); if (!ib_table->is_readable()) { - ib_table->stat_initialized = true; + dict_stats_empty_table(ib_table, true); } if (flag & HA_STATUS_TIME) { diff --git a/storage/innobase/include/dict0stats.h b/storage/innobase/include/dict0stats.h index dccb354f803aa..441e3613b729e 100644 --- a/storage/innobase/include/dict0stats.h +++ b/storage/innobase/include/dict0stats.h @@ -240,4 +240,13 @@ dict_stats_report_error(dict_table_t* table, bool defragment = false) void test_dict_stats_all(); #endif /* UNIV_ENABLE_UNIT_TEST_DICT_STATS */ +/** Write all zeros (or 1 where it makes sense) into a table +and its indexes'statistics members. The resulting stats +correspond to an empty table. +@param table table stats to be emptied +@param empty_defrag_stats empty the defrag stats */ +void +dict_stats_empty_table( + dict_table_t* table, + bool empty_defrag_stats); #endif /* dict0stats_h */ From 87a5d16911bb94d383480fdd49e20876ed1400f2 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 15 Dec 2023 12:06:54 +0100 Subject: [PATCH 23/34] add another missing result file see also 4eca64e3310 --- .../spider/bugfix/r/mdev_28683.result | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_28683.result diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_28683.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_28683.result new file mode 100644 index 0000000000000..358c794ef868d --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_28683.result @@ -0,0 +1,22 @@ +# +# MDEV-28683 Spider: SIGSEGV in spider_db_direct_delete, SIGSEGV in spider_db_connect, ASAN: heap-use-after-free in spider_db_direct_delete +# +for master_1 +for child2 +for child3 +CREATE TABLE t (c INT) ENGINE=Spider; +SELECT * FROM t; +ERROR HY000: Unable to connect to foreign data source: localhost +INSERT INTO t (SELECT 1 FROM t); +ERROR HY000: Unable to connect to foreign data source: localhost +LOCK TABLES t WRITE CONCURRENT; +DELETE FROM t; +ERROR HY000: Unable to connect to foreign data source: localhost +UNLOCK TABLES; +DROP TABLE t; +for master_1 +for child2 +for child3 +# +# end of test mdev_28683 +# From f98d2ef5b4ab633d74fb245a8b6520fe86514de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 15 Dec 2023 15:38:31 +0200 Subject: [PATCH 24/34] MDEV-33009 Server hangs for a long time with innodb_undo_log_truncate=ON trx_purge_truncate_history(): Release buf_pool.flush_list_mutex before starting a rescan of buf_pool.flush_list, to ensure that the buf_flush_page_cleaner thread (which may be holding buf_pool.mutex) will be able to proceed. This fixes up commit a0f02f743848fb6ef6d2a51960f77e1e38da1682 (MDEV-32757). Tested by: Axel Schwenke Reviewed by: Vladislav Lesin --- storage/innobase/trx/trx0purge.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index b06e3cb3e1b19..702e76fc28483 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -681,6 +681,13 @@ void trx_purge_truncate_history() if (prev != buf_pool.flush_hp.get()) { + /* The functions buf_pool_t::release_freed_page() or + buf_do_flush_list_batch() may be right now holding + buf_pool.mutex and waiting to acquire + buf_pool.flush_list_mutex. Ensure that they can proceed, + to avoid extreme waits. */ + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + mysql_mutex_lock(&buf_pool.flush_list_mutex); /* Rescan, because we may have lost the position. */ bpage= UT_LIST_GET_LAST(buf_pool.flush_list); continue; From 4c2e9718413e754715e9836ea603511fc6fec0e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 18 Dec 2023 10:37:11 +0200 Subject: [PATCH 25/34] MDEV-33052 MSAN use-of-uninitialized-value in buf_read_ahead_linear() buf_read_ahead_linear(): Suppress a warning of comparing potentially uninitialized FIL_PAGE_PREV and FIL_PAGE_NEXT fields. --- storage/innobase/buf/buf0rea.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc index c81017bb02465..26bfb7eb0fc2c 100644 --- a/storage/innobase/buf/buf0rea.cc +++ b/storage/innobase/buf/buf0rea.cc @@ -643,6 +643,12 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf) uint32_t prev= mach_read_from_4(my_assume_aligned<4>(f + FIL_PAGE_PREV)); uint32_t next= mach_read_from_4(my_assume_aligned<4>(f + FIL_PAGE_NEXT)); + /* The underlying file page of this buffer pool page could actually + be marked as freed, or a read of the page into the buffer pool might + be in progress. We may read uninitialized data here. + Suppress warnings of comparing uninitialized values. */ + MEM_MAKE_DEFINED(&prev, sizeof prev); + MEM_MAKE_DEFINED(&next, sizeof next); if (prev == FIL_NULL || next == FIL_NULL) goto hard_fail; page_id_t id= page_id; From be694384d41d33934eb36cb0b722c3ac109d04d0 Mon Sep 17 00:00:00 2001 From: hsser Date: Sat, 16 Dec 2023 21:54:01 -0800 Subject: [PATCH 26/34] MDEV-31925 Fix for File Leak in mysql_upgrade with --check-if-upgrade-is-needed Option This commit addresses the file leakage problem encountered with the mysql_upgrade --check-if-upgrade-is-needed command. --- client/mysql_upgrade.c | 7 +++++- .../main/mysql_upgrade_file_leak.result | 4 ++++ mysql-test/main/mysql_upgrade_file_leak.test | 24 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 mysql-test/main/mysql_upgrade_file_leak.result create mode 100644 mysql-test/main/mysql_upgrade_file_leak.test diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index ea18c1c5ba7fb..70e2d341c5b9b 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -1374,7 +1374,12 @@ int main(int argc, char **argv) open_mysql_upgrade_file(); if (opt_check_upgrade) - exit(upgrade_already_done(0) == 0); + { + int upgrade_needed = upgrade_already_done(0); + free_used_memory(); + my_end(my_end_arg); + exit(upgrade_needed == 0); + } /* Find mysqlcheck */ find_tool(mysqlcheck_path, IF_WIN("mysqlcheck.exe", "mysqlcheck"), self_name); diff --git a/mysql-test/main/mysql_upgrade_file_leak.result b/mysql-test/main/mysql_upgrade_file_leak.result new file mode 100644 index 0000000000000..648a0c97802a0 --- /dev/null +++ b/mysql-test/main/mysql_upgrade_file_leak.result @@ -0,0 +1,4 @@ +Running mysql_upgrade with --check-if-upgrade-is-needed +Checking for absence of temporary files by mysql_upgrade +No temporary files found +End of 10.4 tests diff --git a/mysql-test/main/mysql_upgrade_file_leak.test b/mysql-test/main/mysql_upgrade_file_leak.test new file mode 100644 index 0000000000000..44f178322b44d --- /dev/null +++ b/mysql-test/main/mysql_upgrade_file_leak.test @@ -0,0 +1,24 @@ +-- source include/mysql_upgrade_preparation.inc + +# +# MDEV-31925 mysqld_upgrade --check-if-upgrade-is-needed leaks files +# + +# Run mysql_upgrade with --check-if-upgrade-is-needed +--echo Running mysql_upgrade with --check-if-upgrade-is-needed +--exec $MYSQL_UPGRADE --check-if-upgrade-is-needed 2>&1 + +# Check if temporary files related to mysql_upgrade are cleared +--echo Checking for absence of temporary files by mysql_upgrade +--perl + +# Use the temporary directory path from the MySQL configuration +my $tmpdir = "$ENV{MYSQL_TMP_DIR}"; + +die "Test failed: Found temporary file left by mysql_upgrade\n" if (glob("$tmpdir/mysql_upgrade-*")); +print "No temporary files found\n"; +EOF + +let $MYSQLD_DATADIR= `select @@datadir`; +--remove_file $MYSQLD_DATADIR/mysql_upgrade_info +--echo End of 10.4 tests From 98287bd2d6877969514469ebfbf27f9951b99657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 19 Dec 2023 11:15:08 +0200 Subject: [PATCH 27/34] MDEV-33009 Server hangs for a long time with innodb_undo_log_truncate=ON trx_purge_truncate_history(): Release buf_pool.flush_list_mutex and 'dummily' acquire and release buf_pool.mutex before starting a rescan of buf_pool.flush_list, to ensure that the buf_flush_page_cleaner thread (which may be holding buf_pool.mutex) will be able to proceed. This fixes up commit 5dbe7a8c9aa88b7ed17311c2f1df651c9da7783b (MDEV-32757). Tested by: Axel Schwenke (on Ubuntu 18.04 and Ubuntu 20.04) Reviewed by: Vladislav Lesin --- storage/innobase/trx/trx0purge.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index be9ee4793bae6..e4bcf21f94a97 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -687,8 +687,8 @@ TRANSACTIONAL_TARGET void trx_purge_truncate_history() mini-transaction commit and the server was killed, then discarding the to-be-trimmed pages without flushing would break crash recovery. */ - mysql_mutex_lock(&buf_pool.flush_list_mutex); 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()); @@ -730,7 +730,17 @@ TRANSACTIONAL_TARGET void trx_purge_truncate_history() mysql_mutex_lock(&buf_pool.flush_list_mutex); if (prev != buf_pool.flush_hp.get()) + { + /* The functions buf_pool_t::release_freed_page() or + buf_do_flush_list_batch() may be right now holding + buf_pool.mutex and waiting to acquire + buf_pool.flush_list_mutex. Ensure that they can proceed, + to avoid extreme waits. */ + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + mysql_mutex_lock(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); goto rescan; + } } bpage= prev; From a204ce2788987a611bb3b6798afdc7f4f2553556 Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Sun, 17 Dec 2023 13:57:26 +0100 Subject: [PATCH 28/34] MDEV-33045: Server crashes in Item_func_binlog_gtid_pos::val_str / Binary_string::c_ptr_safe Item::val_str() sets the Item::null_value flag, so call it before checking the flag, not after. Signed-off-by: Kristian Nielsen --- mysql-test/suite/binlog_encryption/rpl_gtid_basic.result | 7 +++++++ mysql-test/suite/rpl/r/rpl_gtid_basic.result | 7 +++++++ mysql-test/suite/rpl/t/rpl_gtid_basic.test | 7 +++++++ sql/item_strfunc.cc | 6 +++--- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/binlog_encryption/rpl_gtid_basic.result b/mysql-test/suite/binlog_encryption/rpl_gtid_basic.result index 5771b0f405f14..997218131596d 100644 --- a/mysql-test/suite/binlog_encryption/rpl_gtid_basic.result +++ b/mysql-test/suite/binlog_encryption/rpl_gtid_basic.result @@ -182,6 +182,13 @@ BINLOG_GTID_POS('master-bin.000001',18446744073709551616) NULL Warnings: Warning 1916 Got overflow when converting '18446744073709551616' to INT. Value truncated +SET sql_log_bin= 0; +CREATE TABLE t1 AS SELECT MASTER_POS_WAIT(@binlog_file, 4, 0); +SELECT BINLOG_GTID_POS(@binlog_file, 4); +BINLOG_GTID_POS(@binlog_file, 4) +NULL +DROP TABLE t1; +SET sql_log_bin= 1; *** Some tests of @@GLOBAL.gtid_binlog_state *** connection server_2; include/sync_with_master_gtid.inc diff --git a/mysql-test/suite/rpl/r/rpl_gtid_basic.result b/mysql-test/suite/rpl/r/rpl_gtid_basic.result index aefb80a7c13ba..afc700a72c551 100644 --- a/mysql-test/suite/rpl/r/rpl_gtid_basic.result +++ b/mysql-test/suite/rpl/r/rpl_gtid_basic.result @@ -182,6 +182,13 @@ BINLOG_GTID_POS('master-bin.000001',18446744073709551616) NULL Warnings: Warning 1916 Got overflow when converting '18446744073709551616' to INT. Value truncated +SET sql_log_bin= 0; +CREATE TABLE t1 AS SELECT MASTER_POS_WAIT(@binlog_file, 4, 0); +SELECT BINLOG_GTID_POS(@binlog_file, 4); +BINLOG_GTID_POS(@binlog_file, 4) +NULL +DROP TABLE t1; +SET sql_log_bin= 1; *** Some tests of @@GLOBAL.gtid_binlog_state *** connection server_2; include/sync_with_master_gtid.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_basic.test b/mysql-test/suite/rpl/t/rpl_gtid_basic.test index 70bd0087f7a00..a7af234d47e87 100644 --- a/mysql-test/suite/rpl/t/rpl_gtid_basic.test +++ b/mysql-test/suite/rpl/t/rpl_gtid_basic.test @@ -162,6 +162,13 @@ eval SELECT BINLOG_GTID_POS('$valid_binlog_name',0); eval SELECT BINLOG_GTID_POS('$valid_binlog_name',18446744073709551615); eval SELECT BINLOG_GTID_POS('$valid_binlog_name',18446744073709551616); +# MDEV-33045: Server crashes in Item_func_binlog_gtid_pos::val_str / Binary_string::c_ptr_safe +SET sql_log_bin= 0; +CREATE TABLE t1 AS SELECT MASTER_POS_WAIT(@binlog_file, 4, 0); +SELECT BINLOG_GTID_POS(@binlog_file, 4); +DROP TABLE t1; +SET sql_log_bin= 1; + --echo *** Some tests of @@GLOBAL.gtid_binlog_state *** --connection server_2 diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 92d5e196da433..0373d2a94a6bf 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -3232,12 +3232,12 @@ String *Item_func_binlog_gtid_pos::val_str(String *str) String name_str, *name; longlong pos; - if (args[0]->null_value || args[1]->null_value) - goto err; - name= args[0]->val_str(&name_str); pos= args[1]->val_int(); + if (args[0]->null_value || args[1]->null_value) + goto err; + if (pos < 0 || pos > UINT_MAX32) goto err; From 1cbba45e6ed1dd4f08614198f9596ef828a8ada4 Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Sun, 17 Dec 2023 18:30:38 +0100 Subject: [PATCH 29/34] Attempt to fix rare race in test for MDEV-8031 The error-injection inject_mdev8031 simulates a deadlock kill in a specific place, by setting killed_for_retry to RETRY_KILL_KILLED directly. If a real deadlock kill triggers at the same time, it is possible for the thread to complete its transaction retry and set rgi_slave to NULL before the real readlock kill can complete in the background. This will cause a segfault due to null-pointer access. Fix by changing the error injection to do a real background deadlock kill, which ensures that the thread will wait for any pending background kills to complete. Signed-off-by: Kristian Nielsen --- sql/rpl_parallel.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 397b45c4eef9d..d9ff07fa740bd 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -856,8 +856,7 @@ retry_event_group(rpl_group_info *rgi, rpl_parallel_thread *rpt, thd->wait_for_commit_ptr->unregister_wait_for_prior_commit(); DBUG_EXECUTE_IF("inject_mdev8031", { /* Simulate that we get deadlock killed at this exact point. */ - rgi->killed_for_retry= rpl_group_info::RETRY_KILL_KILLED; - thd->set_killed(KILL_CONNECTION); + slave_background_kill_request(thd); }); #ifdef ENABLED_DEBUG_SYNC DBUG_EXECUTE_IF("rpl_parallel_simulate_wait_at_retry", { From eaa4968fc564444ce9c8803da87f685fb182b447 Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Sun, 17 Dec 2023 18:35:14 +0100 Subject: [PATCH 30/34] MDEV-10653: Fix segfault in SHOW MASTER STATUS with NULL inuse_relaylog The previous patch for MDEV-10653 changes the rpl_parallel::workers_idle() function to use Relay_log_info::last_inuse_relaylog to check for idle workers. But the code was missing a NULL check. Also, there was one place during SQL slave thread start which was missing mutex synchronisation when updating inuse_relaylog. Signed-off-by: Kristian Nielsen --- sql/rpl_parallel.cc | 6 ++++-- sql/slave.cc | 8 +++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index d9ff07fa740bd..ac96d92eb5d76 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -2538,8 +2538,10 @@ rpl_parallel::stop_during_until() bool rpl_parallel::workers_idle(Relay_log_info *rli) { - return rli->last_inuse_relaylog->queued_count == - rli->last_inuse_relaylog->dequeued_count; + mysql_mutex_assert_owner(&rli->data_lock); + return !rli->last_inuse_relaylog || + rli->last_inuse_relaylog->queued_count == + rli->last_inuse_relaylog->dequeued_count; } diff --git a/sql/slave.cc b/sql/slave.cc index 2cc11b9ed4241..f4d76e447cd67 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -5369,19 +5369,25 @@ pthread_handler_t handle_slave_sql(void *arg) } else rli->gtid_skip_flag = GTID_SKIP_NOT; + mysql_mutex_lock(&rli->data_lock); if (init_relay_log_pos(rli, rli->group_relay_log_name, rli->group_relay_log_pos, - 1 /*need data lock*/, &errmsg, + 0 /*need data lock*/, &errmsg, 1 /*look for a description_event*/)) { rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, NULL, "Error initializing relay log position: %s", errmsg); + mysql_mutex_unlock(&rli->data_lock); goto err_before_start; } rli->reset_inuse_relaylog(); if (rli->alloc_inuse_relaylog(rli->group_relay_log_name)) + { + mysql_mutex_unlock(&rli->data_lock); goto err_before_start; + } + mysql_mutex_unlock(&rli->data_lock); strcpy(rli->future_event_master_log_name, rli->group_master_log_name); THD_CHECK_SENTRY(thd); From 476ff0927ac4487b9c5ea64916b94f2bb5246dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 19 Dec 2023 14:45:39 +0200 Subject: [PATCH 31/34] MDEV-33062 innodb_undo_log_truncate=ON prevents fast shutdown trx_purge_truncate_history(): If a fast shutdown has been initiated, disregard innodb_undo_log_truncate=ON and return. --- storage/innobase/trx/trx0purge.cc | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 702e76fc28483..a7e3e7367b1d1 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -645,6 +645,16 @@ void trx_purge_truncate_history() mini-transaction commit and the server was killed, then discarding the to-be-trimmed pages without flushing would break crash recovery. */ + + rescan: + if (UNIV_UNLIKELY(srv_shutdown_state != SRV_SHUTDOWN_NONE) && + srv_fast_shutdown) + { + fast_shutdown: + mtr.commit(); + return; + } + mysql_mutex_lock(&buf_pool.flush_list_mutex); for (buf_page_t *bpage= UT_LIST_GET_LAST(buf_pool.flush_list); bpage; ) @@ -687,10 +697,7 @@ void trx_purge_truncate_history() buf_pool.flush_list_mutex. Ensure that they can proceed, to avoid extreme waits. */ mysql_mutex_unlock(&buf_pool.flush_list_mutex); - mysql_mutex_lock(&buf_pool.flush_list_mutex); - /* Rescan, because we may have lost the position. */ - bpage= UT_LIST_GET_LAST(buf_pool.flush_list); - continue; + goto rescan; } } @@ -699,6 +706,10 @@ void trx_purge_truncate_history() mysql_mutex_unlock(&buf_pool.flush_list_mutex); + if (UNIV_UNLIKELY(srv_shutdown_state != SRV_SHUTDOWN_NONE) && + srv_fast_shutdown) + goto fast_shutdown; + /* Adjust the tablespace metadata. */ if (!fil_truncate_prepare(space.id)) { From a057a6e41f22035a8f2b53f9602f33e15f941680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 20 Dec 2023 09:21:27 +1100 Subject: [PATCH 32/34] MDEV-24670 memory pressure - mariadb-backup postfix mariadb-backup wasn't meant to have memory pressure sensors so restrict the operation to SRV_OPERATIONAL_NORMAL mode. Reviewed by Daniel Black. --- storage/innobase/buf/buf0buf.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index a55048e83df05..e8274b4a8563b 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -1309,7 +1309,8 @@ bool buf_pool_t::create() btr_search_sys_create(); #ifdef __linux__ - buf_mem_pressure_detect_init(); + if (srv_operation == SRV_OPERATION_NORMAL) + buf_mem_pressure_detect_init(); #endif ut_ad(is_initialised()); return false; From 9d2c3d388ecbf89b636b93ab56a7a7b36984637d Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Wed, 20 Dec 2023 09:48:36 +1100 Subject: [PATCH 33/34] MDEV-24670 memory pressure - warnings/notes Errors outputted as notes are weird, and when a user cannot do anything about them, why output them at all. Point taken, removed these, and left positive message on initialization (from Marko). Thanks Elena Stepanova. --- storage/innobase/buf/buf0buf.cc | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index e8274b4a8563b..0ca556f1c8ec0 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -786,16 +786,7 @@ class mem_pressure if ((m_fds[m_num_fds].fd= open(memcgroup.c_str(), O_RDWR | O_NONBLOCK | O_CLOEXEC)) < 0) { - switch (errno) { - case EPERM: - /* https://lore.kernel.org/all/CAMw=ZnQ56cm4Txgy5EhGYvR+Jt4s-KVgoA9_65HKWVMOXp7a9A@mail.gmail.com/T/#m3bd2a73c5ee49965cb73a830b1ccaa37ccf4e427 */ - sql_print_information("InnoDB: Failed to initialize memory pressure EPERM, " - "file permissions."); - break; - default: - sql_print_information("InnoDB: Failed to initialize memory pressure: %s", - strerror(errno)); - } + /* User can't do anything about it, no point giving warning */ shutdown(); return false; } @@ -803,7 +794,7 @@ class mem_pressure ssize_t slen= strlen(*trig); if (write(m_fds[m_num_fds].fd, *trig, slen) < slen) { - sql_print_warning("InnoDB: Failed create trigger for memory pressure \"%s\"", *trig); + /* we may fail this one, but continue to the next */ my_close(m_fds[m_num_fds].fd, MYF(MY_WME)); continue; } @@ -815,7 +806,7 @@ class mem_pressure if ((m_event_fd= eventfd(0, EFD_CLOEXEC|EFD_NONBLOCK)) == -1) { - sql_print_warning("InnoDB: No memory pressure - can't create eventfd"); + /* User can't do anything about it, no point giving warning */ shutdown(); return false; } @@ -824,6 +815,7 @@ class mem_pressure m_fds[m_num_fds].events= POLLIN; m_num_fds++; m_thd= std::thread(pressure_routine, this); + sql_print_information("InnoDB: Initialized memory pressure event listener"); return true; } From f9ae553067143a9db496e49929488c4b87bb2d24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 20 Dec 2023 15:56:00 +0200 Subject: [PATCH 34/34] MDEV-33098: Disable the test --- mysql-test/suite/innodb/disabled.def | 1 + 1 file changed, 1 insertion(+) create mode 100644 mysql-test/suite/innodb/disabled.def diff --git a/mysql-test/suite/innodb/disabled.def b/mysql-test/suite/innodb/disabled.def new file mode 100644 index 0000000000000..e78d33745b226 --- /dev/null +++ b/mysql-test/suite/innodb/disabled.def @@ -0,0 +1 @@ +doublewrite_debug : MDEV-33098 occasionally fails to start up InnoDB