diff options
author | Oleksandr Byelkin <sanja@mariadb.com> | 2023-01-18 16:58:28 +0100 |
---|---|---|
committer | Oleksandr Byelkin <sanja@mariadb.com> | 2023-01-18 16:58:28 +0100 |
commit | 66bd8cd6c3fcfe1a46b992d71ef8af1c17ba0769 (patch) | |
tree | 9e2ad7a512c469a54166cffa5d97be13c98e041d | |
parent | bb3a63903e5192d39d93259ce2bb7635fcfca7a0 (diff) | |
parent | 45087dd0b349062d4924ef932696dc674f10c396 (diff) | |
download | mariadb-git-66bd8cd6c3fcfe1a46b992d71ef8af1c17ba0769.tar.gz |
Merge branch '10.10' into 10.11
53 files changed, 825 insertions, 129 deletions
@@ -9,10 +9,8 @@ MariaDB Corporation https://www.mariadb.com (2013) Microsoft https://microsoft.com/ (2017) ServiceNow https://servicenow.com (2019) SIT https://sit.org (2022) -Tencent Cloud https://cloud.tencent.com (2017) Development Bank of Singapore https://dbs.com (2016) IBM https://www.ibm.com (2017) -Visma https://visma.com (2015) Automattic https://automattic.com (2019) Galera Cluster https://galeracluster.com (2020) Percona https://www.percona.com (2018) diff --git a/cmake/pcre.cmake b/cmake/pcre.cmake index 0ac834f44a6..65dc2ae28f6 100644 --- a/cmake/pcre.cmake +++ b/cmake/pcre.cmake @@ -54,8 +54,8 @@ MACRO(BUNDLE_PCRE2) ExternalProject_Add( pcre2 PREFIX "${dir}" - URL "https://github.com/PhilipHazel/pcre2/releases/download/pcre2-10.40/pcre2-10.40.zip" - URL_MD5 798698846982ce171d881ed0d7535c2a + URL "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.42/pcre2-10.42.zip" + URL_MD5 fe90992fbfb03f854bd9f344074f49eb INSTALL_COMMAND "" CMAKE_ARGS "-DCMAKE_WARN_DEPRECATED=FALSE" diff --git a/extra/wolfssl/CMakeLists.txt b/extra/wolfssl/CMakeLists.txt index 1672f82fc6d..5f446663dc8 100644 --- a/extra/wolfssl/CMakeLists.txt +++ b/extra/wolfssl/CMakeLists.txt @@ -157,6 +157,8 @@ IF(WOLFSSL_X86_64_BUILD) ${WOLFCRYPT_SRCDIR}/sha512_asm.S ${WOLFCRYPT_SRCDIR}/sha256_asm.S) ADD_DEFINITIONS(-maes -msse4.2 -mpclmul) + # WolfSSL 5.5.4 bug - user_settings.h not included into aes_asm.S + SET_PROPERTY(SOURCE ${WOLFCRYPT_SRCDIR}/aes_asm.S APPEND PROPERTY COMPILE_OPTIONS "-DWOLFSSL_X86_64_BUILD") ENDIF() ENDIF() diff --git a/extra/wolfssl/wolfssl b/extra/wolfssl/wolfssl -Subproject f1e2165c591f074feb47872a8ff712713ec411e +Subproject 4fbd4fd36a21efd9d1a7e17aba390e91c78693b diff --git a/libmariadb b/libmariadb -Subproject d9af4fcbc6a7c0ab72b38bb47e0d4fa1f1f8331 +Subproject 12bd1d5511fc2ff766ff6256c71b79a95739533 diff --git a/mysql-test/main/constraints.result b/mysql-test/main/constraints.result index ca4b762fa5c..143c22321ab 100644 --- a/mysql-test/main/constraints.result +++ b/mysql-test/main/constraints.result @@ -183,7 +183,9 @@ t1 CREATE TABLE `t1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP PROCEDURE sp; DROP TABLE t1; +# # End of 10.2 tests +# create table t1 (a int check (a>10)) select 100 as 'a'; show create table t1; Table Create Table @@ -201,3 +203,35 @@ a 19 ccc drop table t1; +create table t1 (a int, b int); +create procedure sp() alter table t1 add constraint if not exists foo check (b > 0); +call sp; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + CONSTRAINT `foo` CHECK (`b` > 0) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +call sp; +Warnings: +Note 1826 Duplicate CHECK constraint name 'foo' +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + CONSTRAINT `foo` CHECK (`b` > 0) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +call sp; +Warnings: +Note 1826 Duplicate CHECK constraint name 'foo' +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + CONSTRAINT `foo` CHECK (`b` > 0) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +drop procedure sp; +drop table t1; diff --git a/mysql-test/main/constraints.test b/mysql-test/main/constraints.test index 2f4dadcee9d..5c673f9be81 100644 --- a/mysql-test/main/constraints.test +++ b/mysql-test/main/constraints.test @@ -151,7 +151,9 @@ show create table t1; DROP PROCEDURE sp; DROP TABLE t1; +--echo # --echo # End of 10.2 tests +--echo # # # Check that we don't lose constraints as part of CREATE ... SELECT @@ -172,3 +174,18 @@ insert into t1 values ("ccc"); insert into t1 values (""); select * from t1; drop table t1; + +# +# add if not exists in SP +# + +create table t1 (a int, b int); +create procedure sp() alter table t1 add constraint if not exists foo check (b > 0); +call sp; +show create table t1; +call sp; +show create table t1; +call sp; +show create table t1; +drop procedure sp; +drop table t1; diff --git a/mysql-test/main/func_json.result b/mysql-test/main/func_json.result index 7ce5d70f9fc..8456b71c4dc 100644 --- a/mysql-test/main/func_json.result +++ b/mysql-test/main/func_json.result @@ -1611,6 +1611,18 @@ SELECT json_object('a', coalesce(json_object('b', 'c'))); json_object('a', coalesce(json_object('b', 'c'))) {"a": {"b": "c"}} # +# MDEV-26392: Crash with json_get_path_next and 10.5.12 +# +CREATE TABLE arrNestTest ( +id VARCHAR(80) AS (JSON_COMPACT(JSON_EXTRACT(doc, "$._id"))) UNIQUE KEY, +doc JSON, +CONSTRAINT id_not_null CHECK(id IS NOT NULL)); +INSERT INTO test.arrNestTest (doc) VALUES ('{ "_id" : { "$oid" : "611c0a463b150154132f6636" }, "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : 1.0 } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] }'); +SELECT * FROM arrNestTest; +id doc +{"$oid":"611c0a463b150154132f6636"} { "_id" : { "$oid" : "611c0a463b150154132f6636" }, "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : 1.0 } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] } +DROP TABLE arrNestTest; +# # MDEV-26054 Server crashes in Item_func_json_arrayagg::get_str_from_field # CREATE TABLE t (a VARCHAR(8)); @@ -2506,6 +2518,24 @@ SELECT JSON_OVERLAPS(@json1, @json2); JSON_OVERLAPS(@json1, @json2) 0 # +# MDEV-30304: Json Range only affects first row of the result set +# +CREATE TABLE t1 ( j JSON ); +INSERT INTO t1 (j) VALUES ('[{"key1": 1, "key2": 1}, {"key3": 1, "key4": 1}]'); +INSERT INTO t1 (j) VALUES ('[{"key1": 2, "key2": 2}, {"key3": 2, "key4": 2}, {"key5": 2, "key6": 2}]'); +INSERT INTO t1 (j) VALUES ('[{"key1": 3, "key2": 3}, {"key3": 3, "key4": 3}, {"key5": 3}]'); +SELECT JSON_EXTRACT(j, '$[0 to 1]') FROM t1 ; +JSON_EXTRACT(j, '$[0 to 1]') +[{"key1": 1, "key2": 1}, {"key3": 1, "key4": 1}] +[{"key1": 2, "key2": 2}, {"key3": 2, "key4": 2}] +[{"key1": 3, "key2": 3}, {"key3": 3, "key4": 3}] +SELECT JSON_EXTRACT(j, '$[*]') FROM t1 ; +JSON_EXTRACT(j, '$[*]') +[{"key1": 1, "key2": 1}, {"key3": 1, "key4": 1}] +[{"key1": 2, "key2": 2}, {"key3": 2, "key4": 2}, {"key5": 2, "key6": 2}] +[{"key1": 3, "key2": 3}, {"key3": 3, "key4": 3}, {"key5": 3}] +DROP TABLE t1; +# # End of 10.9 Test # # diff --git a/mysql-test/main/func_json.test b/mysql-test/main/func_json.test index da830ed08fd..d00ceeb83e2 100644 --- a/mysql-test/main/func_json.test +++ b/mysql-test/main/func_json.test @@ -1054,6 +1054,18 @@ DROP TABLE t2; SELECT json_object('a', if(1, json_object('b', 'c'), json_object('e', 'f'))); SELECT json_object('a', coalesce(json_object('b', 'c'))); +--echo # +--echo # MDEV-26392: Crash with json_get_path_next and 10.5.12 +--echo # + +CREATE TABLE arrNestTest ( + id VARCHAR(80) AS (JSON_COMPACT(JSON_EXTRACT(doc, "$._id"))) UNIQUE KEY, + doc JSON, + CONSTRAINT id_not_null CHECK(id IS NOT NULL)); + +INSERT INTO test.arrNestTest (doc) VALUES ('{ "_id" : { "$oid" : "611c0a463b150154132f6636" }, "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : [ { "a" : 1.0 } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] } ] }'); +SELECT * FROM arrNestTest; +DROP TABLE arrNestTest; --echo # --echo # MDEV-26054 Server crashes in Item_func_json_arrayagg::get_str_from_field @@ -1707,6 +1719,21 @@ SELECT JSON_OVERLAPS(@json2, @json1); SELECT JSON_OVERLAPS(@json1, @json2); --echo # +--echo # MDEV-30304: Json Range only affects first row of the result set +--echo # + +CREATE TABLE t1 ( j JSON ); + +INSERT INTO t1 (j) VALUES ('[{"key1": 1, "key2": 1}, {"key3": 1, "key4": 1}]'); +INSERT INTO t1 (j) VALUES ('[{"key1": 2, "key2": 2}, {"key3": 2, "key4": 2}, {"key5": 2, "key6": 2}]'); +INSERT INTO t1 (j) VALUES ('[{"key1": 3, "key2": 3}, {"key3": 3, "key4": 3}, {"key5": 3}]'); + +SELECT JSON_EXTRACT(j, '$[0 to 1]') FROM t1 ; +SELECT JSON_EXTRACT(j, '$[*]') FROM t1 ; + +DROP TABLE t1; + +--echo # --echo # End of 10.9 Test --echo # diff --git a/mysql-test/main/join.result b/mysql-test/main/join.result index 65dccc6b9a3..59d6ae98ff3 100644 --- a/mysql-test/main/join.result +++ b/mysql-test/main/join.result @@ -3407,3 +3407,20 @@ id select_type table type possible_keys key key_len ref rows Extra drop table t1,t2,t3; drop table t1000,t10,t03; # End of 10.3 tests +# +# MDEV-30080 Wrong result with LEFT JOINs involving constant tables +# +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1); +CREATE TABLE t2 (b INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1),(1); +CREATE TABLE t3 (c INT PRIMARY KEY) ENGINE=MyISAM; +SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b = t3.c) ON t1.a = t2.b; +a b c +1 1 NULL +1 1 NULL +SELECT COUNT(*) FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b = t3.c) ON t1.a = t2.b; +COUNT(*) +2 +DROP TABLE t1, t2, t3; +# End of 10.5 tests diff --git a/mysql-test/main/join.test b/mysql-test/main/join.test index e929854251a..1668787d33e 100644 --- a/mysql-test/main/join.test +++ b/mysql-test/main/join.test @@ -1820,3 +1820,18 @@ drop table t1,t2,t3; drop table t1000,t10,t03; --echo # End of 10.3 tests + +--echo # +--echo # MDEV-30080 Wrong result with LEFT JOINs involving constant tables +--echo # + +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1); +CREATE TABLE t2 (b INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1),(1); +CREATE TABLE t3 (c INT PRIMARY KEY) ENGINE=MyISAM; +SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b = t3.c) ON t1.a = t2.b; +SELECT COUNT(*) FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b = t3.c) ON t1.a = t2.b; +DROP TABLE t1, t2, t3; + +--echo # End of 10.5 tests diff --git a/mysql-test/suite/federated/federatedx.result b/mysql-test/suite/federated/federatedx.result index c18665e4d99..49deff81c4c 100644 --- a/mysql-test/suite/federated/federatedx.result +++ b/mysql-test/suite/federated/federatedx.result @@ -2325,6 +2325,38 @@ DROP TABLE federated.t1; connection slave; DROP TABLE federated.t1; connection default; +# +# MDEV-30395 Wrong result with semijoin and Federated as outer table +# +create server s foreign data wrapper mysql options (host "127.0.0.1", database "test", user "root", port MASTER_PORT); +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (3),(2),(3); +CREATE TABLE t2 (pk INT PRIMARY KEY); +INSERT INTO t2 VALUES (1),(2),(3),(4); +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch="materialization=off"; +CREATE TABLE t2_fed ENGINE=FEDERATED CONNECTION='s/t2'; +explain SELECT * FROM t2_fed WHERE pk IN ( SELECT a FROM t1 ); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2_fed ALL NULL NULL NULL NULL 4 Using where +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where +SELECT * FROM t2_fed WHERE pk IN ( SELECT a FROM t1 ); +pk +2 +3 +SET optimizer_switch='semijoin=off'; +explain SELECT * FROM t2_fed WHERE pk IN ( SELECT a FROM t1 ); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2_fed ALL NULL NULL NULL NULL 4 Using where +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where +SELECT * FROM t2_fed WHERE pk IN ( SELECT a FROM t1 ); +pk +2 +3 +DROP TABLE t2_fed, t1, t2; +set @@optimizer_switch=@save_optimizer_switch; +DROP SERVER s; +# End of 10.5 tests connection master; DROP TABLE IF EXISTS federated.t1; DROP DATABASE IF EXISTS federated; diff --git a/mysql-test/suite/federated/federatedx.test b/mysql-test/suite/federated/federatedx.test index 51d34298626..7e5a335b786 100644 --- a/mysql-test/suite/federated/federatedx.test +++ b/mysql-test/suite/federated/federatedx.test @@ -2060,4 +2060,34 @@ connection slave; DROP TABLE federated.t1; connection default; +--echo # +--echo # MDEV-30395 Wrong result with semijoin and Federated as outer table +--echo # + + +--replace_result $MASTER_MYPORT MASTER_PORT +eval create server s foreign data wrapper mysql options (host "127.0.0.1", database "test", user "root", port $MASTER_MYPORT); + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (3),(2),(3); +CREATE TABLE t2 (pk INT PRIMARY KEY); +INSERT INTO t2 VALUES (1),(2),(3),(4); + +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch="materialization=off"; + +CREATE TABLE t2_fed ENGINE=FEDERATED CONNECTION='s/t2'; +explain SELECT * FROM t2_fed WHERE pk IN ( SELECT a FROM t1 ); +SELECT * FROM t2_fed WHERE pk IN ( SELECT a FROM t1 ); +SET optimizer_switch='semijoin=off'; +explain SELECT * FROM t2_fed WHERE pk IN ( SELECT a FROM t1 ); +SELECT * FROM t2_fed WHERE pk IN ( SELECT a FROM t1 ); + +DROP TABLE t2_fed, t1, t2; +set @@optimizer_switch=@save_optimizer_switch; + +DROP SERVER s; + +--echo # End of 10.5 tests + source include/federated_cleanup.inc; diff --git a/mysql-test/suite/galera/r/galera_MDEV-29512.result b/mysql-test/suite/galera/r/galera_MDEV-29512.result new file mode 100644 index 00000000000..aaf24df920e --- /dev/null +++ b/mysql-test/suite/galera/r/galera_MDEV-29512.result @@ -0,0 +1,40 @@ +connection node_2; +connection node_1; +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 int, f3 varchar(2000)); +INSERT INTO t1 VALUES (1, 0, REPEAT('1234567890', 200)); +INSERT INTO t1 VALUES (3, 3, REPEAT('1234567890', 200)); +SET SESSION wsrep_sync_wait=0; +SET GLOBAL DEBUG_DBUG = "d,sync.wsrep_apply_cb"; +connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; +connection node_1a; +SET SESSION wsrep_sync_wait=0; +connection node_1; +begin; +select f1,f2 from t1; +f1 f2 +1 0 +3 3 +connection node_2; +UPDATE t1 SET f2=2 WHERE f1=3; +connection node_1a; +SET SESSION DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached"; +connection node_1; +UPDATE t1 SET f2=1 WHERE f1=3; +SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_master_enter_sync'; +COMMIT; +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_master_enter_sync'; +SET GLOBAL DEBUG_DBUG = ""; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb"; +SET GLOBAL debug_dbug = NULL; +SET debug_sync='RESET'; +connection node_1; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +select f1,f2 from t1; +f1 f2 +1 0 +3 2 +DROP TABLE t1; diff --git a/mysql-test/suite/galera/r/galera_gcache_recover.result b/mysql-test/suite/galera/r/galera_gcache_recover.result index 819c595ece3..72088a5447b 100644 --- a/mysql-test/suite/galera/r/galera_gcache_recover.result +++ b/mysql-test/suite/galera/r/galera_gcache_recover.result @@ -20,8 +20,6 @@ connection node_1; include/diff_servers.inc [servers=1 2] connection node_1; CALL mtr.add_suppression("Skipped GCache ring buffer recovery"); -include/assert_grep.inc [async IST sender starting to serve] connection node_2; CALL mtr.add_suppression("Skipped GCache ring buffer recovery"); -include/assert_grep.inc [Recovering GCache ring buffer: found gapless sequence] DROP TABLE t1; diff --git a/mysql-test/suite/galera/r/galera_gcache_recover_manytrx.result b/mysql-test/suite/galera/r/galera_gcache_recover_manytrx.result index 63b16165970..5caf22b39ca 100644 --- a/mysql-test/suite/galera/r/galera_gcache_recover_manytrx.result +++ b/mysql-test/suite/galera/r/galera_gcache_recover_manytrx.result @@ -134,8 +134,6 @@ connection node_1; call mtr.add_suppression("Error in Log_event::read_log_event():.*"); CALL mtr.add_suppression("conflict state 7 after post commit"); CALL mtr.add_suppression("Skipped GCache ring buffer recovery"); -include/assert_grep.inc [async IST sender starting to serve] connection node_2; call mtr.add_suppression("Error in Log_event::read_log_event():.*"); CALL mtr.add_suppression("Skipped GCache ring buffer recovery"); -include/assert_grep.inc [Recovering GCache ring buffer: found gapless sequence] diff --git a/mysql-test/suite/galera/r/galera_savepoint_replay.result b/mysql-test/suite/galera/r/galera_savepoint_replay.result new file mode 100644 index 00000000000..afea5f82e3c --- /dev/null +++ b/mysql-test/suite/galera/r/galera_savepoint_replay.result @@ -0,0 +1,53 @@ +connection node_2; +connection node_1; +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1)); +INSERT INTO t1 VALUES (1, 'a'); +INSERT INTO t1 VALUES (2, 'a'); +connection node_1; +SET AUTOCOMMIT=ON; +START TRANSACTION; +UPDATE t1 SET f2 = 'b' WHERE f1 = 1; +SELECT * FROM t1 WHERE f1 = 2 FOR UPDATE; +f1 f2 +2 a +SAVEPOINT my_sp; +connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; +SET SESSION wsrep_sync_wait=0; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; +UPDATE t1 SET f2 = 'c' WHERE f1 = 2; +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_master_enter_sync'; +connection node_1; +COMMIT; +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end'; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end'; +SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_master_enter_sync'; +connection node_1; +SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b'; +COUNT(*) = 1 +1 +SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c'; +COUNT(*) = 1 +1 +wsrep_local_replays +1 +connection node_2; +SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b'; +COUNT(*) = 1 +1 +SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c'; +COUNT(*) = 1 +1 +DROP TABLE t1; diff --git a/mysql-test/suite/galera/r/galera_var_wsrep_mode.result b/mysql-test/suite/galera/r/galera_var_wsrep_mode.result index 8682ad685a5..b5b33fe8ae5 100644 --- a/mysql-test/suite/galera/r/galera_var_wsrep_mode.result +++ b/mysql-test/suite/galera/r/galera_var_wsrep_mode.result @@ -20,8 +20,8 @@ SET GLOBAL wsrep_mode='A'; ERROR 42000: Variable 'wsrep_mode' can't be set to the value of 'A' SET GLOBAL wsrep_mode=NULL; ERROR 42000: Variable 'wsrep_mode' can't be set to the value of 'NULL' -SET GLOBAL wsrep_mode=64; -ERROR 42000: Variable 'wsrep_mode' can't be set to the value of '64' +SET GLOBAL wsrep_mode=128; +ERROR 42000: Variable 'wsrep_mode' can't be set to the value of '128' SET GLOBAL wsrep_mode=REQUIRED_PRIMARY_KEY,REPLICATE_MYISAM; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1 SET GLOBAL wsrep_mode=1; diff --git a/mysql-test/suite/galera/t/galera_MDEV-29512.cnf b/mysql-test/suite/galera/t/galera_MDEV-29512.cnf new file mode 100644 index 00000000000..bf8e0c37984 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_MDEV-29512.cnf @@ -0,0 +1,15 @@ +!include ../galera_2nodes.cnf + +[mysqld] +log-bin +log-slave-updates + +[mysqld.1] +log_bin +log_slave_updates +max-binlog-size=4096 +expire-logs-days=1 + + +[mysqld.2] + diff --git a/mysql-test/suite/galera/t/galera_MDEV-29512.test b/mysql-test/suite/galera/t/galera_MDEV-29512.test new file mode 100644 index 00000000000..ffcef792f85 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_MDEV-29512.test @@ -0,0 +1,91 @@ +# +# This test is for reproducing the issue in: +# https://jira.mariadb.org/browse/MDEV-29512 +# +# The hanging in MDEV-29512 happens when binlog purging is attempted, and there is +# one local BF aborted transaction waiting for commit monitor. +# +# The test will launch two node cluster and enable binlogging with expire log days, +# to force binlog purging to happen. +# A local transaction is executed so that will become BF abort victim, and has advanced +# to replication stage waiting for commit monitor for final cleanup (to mark position in innodb) +# after that, applier is released to complete the BF abort and due to binlog configuration, +# starting the binlog purging. This is where the hanging would occur, if code is buggy +# +--source include/galera_cluster.inc +--source include/have_innodb.inc +--source include/have_debug_sync.inc +--source include/galera_have_debug_sync.inc + +# +# binlog size is limited to 4096 bytes, we will create enough events to +# cause binlog rotation +# +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 int, f3 varchar(2000)); +INSERT INTO t1 VALUES (1, 0, REPEAT('1234567890', 200)); +INSERT INTO t1 VALUES (3, 3, REPEAT('1234567890', 200)); + +SET SESSION wsrep_sync_wait=0; + +# set sync point for replication applier +SET GLOBAL DEBUG_DBUG = "d,sync.wsrep_apply_cb"; + +# Control connection to manage sync points for appliers +--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1 +--connection node_1a +SET SESSION wsrep_sync_wait=0; + +# starting local transaction, only select so far, +# write will happen later and this will be ordered after the transaction in node_2 +--connection node_1 +begin; +select f1,f2 from t1; + +# send from node 2 an UPDATE transaction, which will BF abort the transaction in node_1 +--connection node_2 +--let $wait_condition=select count(*)=2 from t1 +--source include/wait_condition.inc + +UPDATE t1 SET f2=2 WHERE f1=3; + +--connection node_1a +# wait to see the UPDATE from node_2 in apply_cb sync point +SET SESSION DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached"; + +--connection node_1 +# now issuing conflicting update +UPDATE t1 SET f2=1 WHERE f1=3; + +# Block the local commit, send final COMMIT and wait until it gets blocked +--let $galera_sync_point = commit_monitor_master_enter_sync +--source include/galera_set_sync_point.inc +--send COMMIT + +--connection node_1a +# wait for the local commit to enter in commit monitor wait state +--let $galera_sync_point = commit_monitor_master_enter_sync +--source include/galera_wait_sync_point.inc +--source include/galera_clear_sync_point.inc + +# release the local transaction to continue with commit +--let $galera_sync_point = commit_monitor_master_enter_sync +--source include/galera_signal_sync_point.inc + +# and now release the applier, it should force local trx to abort +SET GLOBAL DEBUG_DBUG = ""; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb"; +SET GLOBAL debug_dbug = NULL; +SET debug_sync='RESET'; + +--connection node_1 +--error ER_LOCK_DEADLOCK +--reap + +# wait until applying is complete +--let $wait_condition = SELECT COUNT(*)=1 FROM t1 WHERE f2=2 +--source include/wait_condition.inc + +# final read to verify what we got +select f1,f2 from t1; + +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_gcache_recover.test b/mysql-test/suite/galera/t/galera_gcache_recover.test index e1bfe517d27..fe2a65ee14e 100644 --- a/mysql-test/suite/galera/t/galera_gcache_recover.test +++ b/mysql-test/suite/galera/t/galera_gcache_recover.test @@ -54,24 +54,7 @@ INSERT INTO t1 VALUES (3); # Warning happens when the cluster is started for the first time CALL mtr.add_suppression("Skipped GCache ring buffer recovery"); -# Confirm that IST took place ---let $assert_text = async IST sender starting to serve ---let $assert_select = async IST sender starting to serve ---let $assert_count = 1 ---let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.1.err ---let $assert_only_after = starting as process ---source include/assert_grep.inc - --connection node_2 CALL mtr.add_suppression("Skipped GCache ring buffer recovery"); -# Confirm that gcache recovery took place - ---let $assert_text = Recovering GCache ring buffer: found gapless sequence ---let $assert_select = Recovering GCache ring buffer: found gapless sequence ---let $assert_count = 1 ---let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.2.err ---let $assert_only_after = starting as process ---source include/assert_grep.inc - DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_gcache_recover_manytrx.test b/mysql-test/suite/galera/t/galera_gcache_recover_manytrx.test index d92288b7881..8f0f0ed65ea 100644 --- a/mysql-test/suite/galera/t/galera_gcache_recover_manytrx.test +++ b/mysql-test/suite/galera/t/galera_gcache_recover_manytrx.test @@ -206,23 +206,7 @@ CALL mtr.add_suppression("conflict state 7 after post commit"); # Warning happens when the cluster is started for the first time CALL mtr.add_suppression("Skipped GCache ring buffer recovery"); -# Confirm that IST took place ---let $assert_text = async IST sender starting to serve ---let $assert_select = async IST sender starting to serve ---let $assert_count = 1 ---let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.1.err ---let $assert_only_after = starting as process ---source include/assert_grep.inc - --connection node_2 call mtr.add_suppression("Error in Log_event::read_log_event():.*"); CALL mtr.add_suppression("Skipped GCache ring buffer recovery"); -# Confirm that gcache recovery took place - ---let $assert_text = Recovering GCache ring buffer: found gapless sequence ---let $assert_select = Recovering GCache ring buffer: found gapless sequence ---let $assert_count = 1 ---let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.2.err ---let $assert_only_after = starting as process ---source include/assert_grep.inc diff --git a/mysql-test/suite/galera/t/galera_savepoint_replay.test b/mysql-test/suite/galera/t/galera_savepoint_replay.test new file mode 100644 index 00000000000..cff26f4a94f --- /dev/null +++ b/mysql-test/suite/galera/t/galera_savepoint_replay.test @@ -0,0 +1,86 @@ +# +# This test tests replaying a transaction with savepoint +# + +--source include/galera_cluster.inc +--source include/have_innodb.inc +--source include/have_debug_sync.inc +--source include/galera_have_debug_sync.inc + +--let $wsrep_local_replays_old = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays'` + +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1)); +INSERT INTO t1 VALUES (1, 'a'); +INSERT INTO t1 VALUES (2, 'a'); + +--connection node_1 +SET AUTOCOMMIT=ON; +START TRANSACTION; + +UPDATE t1 SET f2 = 'b' WHERE f1 = 1; +SELECT * FROM t1 WHERE f1 = 2 FOR UPDATE; +SAVEPOINT my_sp; + +# Block the applier on node #1 and issue a conflicting update on node #2 +--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1 +SET SESSION wsrep_sync_wait=0; +--let $galera_sync_point = apply_monitor_slave_enter_sync +--source include/galera_set_sync_point.inc + +--connection node_2 +UPDATE t1 SET f2 = 'c' WHERE f1 = 2; + +--connection node_1a +--source include/galera_wait_sync_point.inc +--source include/galera_clear_sync_point.inc + +# Block the commit, send the COMMIT and wait until it gets blocked + +--let $galera_sync_point = commit_monitor_master_enter_sync +--source include/galera_set_sync_point.inc + +--connection node_1 +--send COMMIT + +--connection node_1a + +--let $galera_sync_point = apply_monitor_slave_enter_sync commit_monitor_master_enter_sync +--source include/galera_wait_sync_point.inc +--source include/galera_clear_sync_point.inc + +# Let the conflicting UPDATE proceed and wait until it hits abort_trx_end. +# The victim transaction still sits in commit_monitor_master_sync_point. + +--let $galera_sync_point = abort_trx_end +--source include/galera_set_sync_point.inc +--let $galera_sync_point = apply_monitor_slave_enter_sync +--source include/galera_signal_sync_point.inc +--let $galera_sync_point = abort_trx_end commit_monitor_master_enter_sync +--source include/galera_wait_sync_point.inc + +# Let the transactions proceed +--source include/galera_clear_sync_point.inc +--let $galera_sync_point = abort_trx_end +--source include/galera_signal_sync_point.inc +--let $galera_sync_point = commit_monitor_master_enter_sync +--source include/galera_signal_sync_point.inc + +# Commit succeeds +--connection node_1 +--reap + +SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b'; +SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c'; + +# wsrep_local_replays has increased by 1 +--let $wsrep_local_replays_new = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--disable_query_log +--eval SELECT $wsrep_local_replays_new - $wsrep_local_replays_old = 1 AS wsrep_local_replays; +--enable_query_log + +--connection node_2 +SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b'; +SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c'; + +DROP TABLE t1; + diff --git a/mysql-test/suite/galera/t/galera_var_wsrep_mode.test b/mysql-test/suite/galera/t/galera_var_wsrep_mode.test index 56953b1e71b..002dce0a05a 100644 --- a/mysql-test/suite/galera/t/galera_var_wsrep_mode.test +++ b/mysql-test/suite/galera/t/galera_var_wsrep_mode.test @@ -22,7 +22,7 @@ SET GLOBAL wsrep_mode='A'; --error ER_WRONG_VALUE_FOR_VAR SET GLOBAL wsrep_mode=NULL; --error ER_WRONG_VALUE_FOR_VAR -SET GLOBAL wsrep_mode=64; +SET GLOBAL wsrep_mode=128; --error ER_PARSE_ERROR SET GLOBAL wsrep_mode=REQUIRED_PRIMARY_KEY,REPLICATE_MYISAM; # diff --git a/mysql-test/suite/galera_3nodes/r/MDEV-29171.result b/mysql-test/suite/galera_3nodes/r/MDEV-29171.result new file mode 100644 index 00000000000..151be86d9cc --- /dev/null +++ b/mysql-test/suite/galera_3nodes/r/MDEV-29171.result @@ -0,0 +1,41 @@ +connection node_2; +connection node_1; +connection node_1; +select @@wsrep_gtid_domain_id,@@wsrep_node_name; +@@wsrep_gtid_domain_id @@wsrep_node_name +100 node1 +connection node_2; +select @@wsrep_gtid_domain_id,@@wsrep_node_name; +@@wsrep_gtid_domain_id @@wsrep_node_name +100 node2 +connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3; +connection node_3; +select @@wsrep_gtid_domain_id,@@wsrep_node_name; +@@wsrep_gtid_domain_id @@wsrep_node_name +100 node3 +connection node_3; +connection node_2; +connection node_1; +connection node_1; +# restart: --wsrep_new_cluster --wsrep_gtid_domain_id=200 +show variables like 'wsrep_gtid_domain_id'; +Variable_name Value +wsrep_gtid_domain_id 200 +connection node_2; +# restart +show variables like 'wsrep_gtid_domain_id'; +Variable_name Value +wsrep_gtid_domain_id 200 +connection node_3; +# restart: --wsrep_sst_donor=node2 +show variables like 'wsrep_gtid_domain_id'; +Variable_name Value +wsrep_gtid_domain_id 200 +connection node_1; +set global wsrep_gtid_domain_id=100; +connection node_2; +set global wsrep_gtid_domain_id=100; +CALL mtr.add_suppression("WSREP: Ignoring server id for non bootstrap node."); +connection node_3; +set global wsrep_gtid_domain_id=100; +CALL mtr.add_suppression("WSREP: Ignoring server id for non bootstrap node."); diff --git a/mysql-test/suite/galera_3nodes/t/MDEV-29171.cnf b/mysql-test/suite/galera_3nodes/t/MDEV-29171.cnf new file mode 100644 index 00000000000..27f1c29f999 --- /dev/null +++ b/mysql-test/suite/galera_3nodes/t/MDEV-29171.cnf @@ -0,0 +1,14 @@ +!include ../galera_3nodes.cnf + +[mysqld.1] +wsrep-node-name="node1" +wsrep-gtid-mode=ON +wsrep-gtid-domain-id=100 + +[mysqld.2] +wsrep-node-name="node2" +wsrep-gtid-mode=ON + +[mysqld.3] +wsrep-node-name="node3" +wsrep-gtid-mode=ON diff --git a/mysql-test/suite/galera_3nodes/t/MDEV-29171.test b/mysql-test/suite/galera_3nodes/t/MDEV-29171.test new file mode 100644 index 00000000000..33fa4d722ae --- /dev/null +++ b/mysql-test/suite/galera_3nodes/t/MDEV-29171.test @@ -0,0 +1,83 @@ +# +# MDEV-29171: changing the value of wsrep_gtid_domain_id +# with full cluster restart fails on some nodes +# + +--source include/galera_cluster.inc +--source include/have_innodb.inc + +# +# Initially wsrep gtid domain id is 100 +# +--connection node_1 +select @@wsrep_gtid_domain_id,@@wsrep_node_name; + +--connection node_2 +select @@wsrep_gtid_domain_id,@@wsrep_node_name; + +--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3 +--connection node_3 +select @@wsrep_gtid_domain_id,@@wsrep_node_name; + + +# +# Shutdown all nodes +# +--connection node_3 +--source include/shutdown_mysqld.inc + +--connection node_2 +--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +--source include/wait_condition.inc +--source include/shutdown_mysqld.inc + +--connection node_1 +--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +--source include/wait_condition.inc +--source include/shutdown_mysqld.inc + + +# +# Bootstrap from node_1 and change wsrep_gtid_domain_id to 200 +# +--connection node_1 +--let $restart_parameters = --wsrep_new_cluster --wsrep_gtid_domain_id=200 +--source include/start_mysqld.inc +show variables like 'wsrep_gtid_domain_id'; + + +# +# Restart node_2, expect that wsrep_gtid_domain_id has changed to 200 +# +--connection node_2 +--let $restart_parameters = +--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +--source include/start_mysqld.inc +show variables like 'wsrep_gtid_domain_id'; + + +# +# Restart node_3, select node_2 as donor +# If bug is present, node_3 remains on domain id 100 +# +--connection node_3 +--let $restart_parameters = --wsrep_sst_donor="node2" +--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.3.expect +--source include/start_mysqld.inc +# Expect domain id 200 +show variables like 'wsrep_gtid_domain_id'; + + +# +# Cleanup +# +--connection node_1 +set global wsrep_gtid_domain_id=100; + +--connection node_2 +set global wsrep_gtid_domain_id=100; +CALL mtr.add_suppression("WSREP: Ignoring server id for non bootstrap node."); + +--connection node_3 +set global wsrep_gtid_domain_id=100; +CALL mtr.add_suppression("WSREP: Ignoring server id for non bootstrap node."); diff --git a/mysql-test/suite/galera_3nodes_sr/t/galera_vote_sr.inc b/mysql-test/suite/galera_3nodes_sr/t/galera_vote_sr.inc index 776291cc9c0..9fe33e78eb5 100644 --- a/mysql-test/suite/galera_3nodes_sr/t/galera_vote_sr.inc +++ b/mysql-test/suite/galera_3nodes_sr/t/galera_vote_sr.inc @@ -8,6 +8,8 @@ CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 BLOB) ENGINE=InnoDB; # Introduce inconsistency --connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1' +--source include/wait_condition.inc SET SESSION wsrep_on=OFF; --eval INSERT INTO t1 VALUES ($inconsistent_fragment, 'X') SET SESSION wsrep_on=ON; diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result index 0b85048b650..acf021db22c 100644 --- a/mysql-test/suite/innodb/r/foreign_key.result +++ b/mysql-test/suite/innodb/r/foreign_key.result @@ -944,6 +944,8 @@ DROP TABLE t1; # # TODO: enable them after MDEV-16417 is finished create or replace table t1 (a int primary key) engine=innodb; +create or replace table t2 (a int, constraint foo check(a > 0), foreign key(a) references t1(a) on update cascade) engine=innodb; +ERROR HY000: Function or expression 'a' cannot be used in the CHECK clause of `foo` create or replace table t2 (a int, check(a > 0), foreign key(a) references t1(a) on update cascade) engine=innodb; ERROR HY000: Function or expression 'a' cannot be used in the CHECK clause of `CONSTRAINT_1` create or replace table t1 (f1 int, f2 date, f3 date, key(f1,f3,f2)) engine=innodb; diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test index 918d8e8df20..4b047ea4d4a 100644 --- a/mysql-test/suite/innodb/t/foreign_key.test +++ b/mysql-test/suite/innodb/t/foreign_key.test @@ -970,6 +970,8 @@ DROP TABLE t1; --echo # TODO: enable them after MDEV-16417 is finished create or replace table t1 (a int primary key) engine=innodb; --error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create or replace table t2 (a int, constraint foo check(a > 0), foreign key(a) references t1(a) on update cascade) engine=innodb; +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED create or replace table t2 (a int, check(a > 0), foreign key(a) references t1(a) on update cascade) engine=innodb; create or replace table t1 (f1 int, f2 date, f3 date, key(f1,f3,f2)) engine=innodb; diff --git a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result index 305c0e88e5e..4ca95338e56 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result +++ b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result @@ -357,7 +357,7 @@ VARIABLE_COMMENT Set of WSREP features that are enabled. NUMERIC_MIN_VALUE NULL NUMERIC_MAX_VALUE NULL NUMERIC_BLOCK_SIZE NULL -ENUM_VALUE_LIST STRICT_REPLICATION,BINLOG_ROW_FORMAT_ONLY,REQUIRED_PRIMARY_KEY,REPLICATE_MYISAM,REPLICATE_ARIA,DISALLOW_LOCAL_GTID +ENUM_VALUE_LIST STRICT_REPLICATION,BINLOG_ROW_FORMAT_ONLY,REQUIRED_PRIMARY_KEY,REPLICATE_MYISAM,REPLICATE_ARIA,DISALLOW_LOCAL_GTID,BF_ABORT_MARIABACKUP READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED GLOBAL_VALUE_PATH NULL diff --git a/sql/backup.cc b/sql/backup.cc index e38e5995845..3e0986e944f 100644 --- a/sql/backup.cc +++ b/sql/backup.cc @@ -35,9 +35,10 @@ #include "sql_handler.h" // mysql_ha_cleanup_no_free #include <my_sys.h> #include <strfunc.h> // strconvert() -#include "wsrep_mysqld.h" +#include "debug_sync.h" #ifdef WITH_WSREP #include "wsrep_server_state.h" +#include "wsrep_mysqld.h" #endif /* WITH_WSREP */ static const char *stage_names[]= @@ -292,16 +293,26 @@ static bool backup_block_ddl(THD *thd) #ifdef WITH_WSREP /* - We desync the node for BACKUP STAGE because applier threads + if user is specifically choosing to allow BF aborting for BACKUP STAGE BLOCK_DDL lock + holder, then do not desync and pause the node from cluster replication. + e.g. mariabackup uses BACKUP STATE BLOCK_DDL; and will be abortable by this. + But, If node is processing as SST donor or WSREP_MODE_BF_MARIABACKUP mode is not set, + we desync the node for BACKUP STAGE because applier threads bypass backup MDL locks (see MDL_lock::can_grant_lock) */ if (WSREP_NNULL(thd)) { Wsrep_server_state &server_state= Wsrep_server_state::instance(); - if (server_state.desync_and_pause().is_undefined()) { - DBUG_RETURN(1); + if (!wsrep_check_mode(WSREP_MODE_BF_MARIABACKUP) || + server_state.state() == Wsrep_server_state::s_donor) + { + if (server_state.desync_and_pause().is_undefined()) { + DBUG_RETURN(1); + } + thd->wsrep_desynced_backup_stage= true; } - thd->wsrep_desynced_backup_stage= true; + else + WSREP_INFO("Server not desynched from group because WSREP_MODE_BF_MARIABACKUP used."); } #endif /* WITH_WSREP */ @@ -341,6 +352,18 @@ static bool backup_block_ddl(THD *thd) /* There can't be anything more that needs to be logged to ddl log */ THD_STAGE_INFO(thd, org_stage); stop_ddl_logging(); +#ifdef WITH_WSREP + // Allow tests to block the applier thread using the DBUG facilities + DBUG_EXECUTE_IF("sync.wsrep_after_mdl_block_ddl", + { + const char act[]= + "now " + "signal signal.wsrep_apply_toi"; + DBUG_ASSERT(!debug_sync_set_action(thd, + STRING_WITH_LEN(act))); + };); +#endif /* WITH_WSREP */ + DBUG_RETURN(0); err: THD_STAGE_INFO(thd, org_stage); @@ -400,7 +423,8 @@ bool backup_end(THD *thd) thd->current_backup_stage= BACKUP_FINISHED; thd->mdl_context.release_lock(old_ticket); #ifdef WITH_WSREP - if (WSREP_NNULL(thd) && thd->wsrep_desynced_backup_stage) + if (WSREP_NNULL(thd) && thd->wsrep_desynced_backup_stage && + !wsrep_check_mode(WSREP_MODE_BF_MARIABACKUP)) { Wsrep_server_state &server_state= Wsrep_server_state::instance(); THD_STAGE_INFO(thd, stage_waiting_flow); diff --git a/sql/field.h b/sql/field.h index 05feb7a4275..4036f032257 100644 --- a/sql/field.h +++ b/sql/field.h @@ -558,7 +558,6 @@ static inline const char *vcol_type_name(enum_vcol_info_type type) #define VCOL_AUTO_INC 16 #define VCOL_IMPOSSIBLE 32 #define VCOL_NEXTVAL 64 /* NEXTVAL is not implemented for vcols */ -#define VCOL_CHECK_CONSTRAINT_IF_NOT_EXISTS 128 #define VCOL_NOT_STRICTLY_DETERMINISTIC \ (VCOL_NON_DETERMINISTIC | VCOL_TIME_FUNC | VCOL_SESSION_FUNC) @@ -590,6 +589,7 @@ public: bool stored_in_db; bool utf8; /* Already in utf8 */ bool automatic_name; + bool if_not_exists; Item *expr; Lex_ident name; /* Name of constraint */ /* see VCOL_* (VCOL_FIELD_REF, ...) */ diff --git a/sql/handler.h b/sql/handler.h index 51266185e59..6b05da2ca98 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -357,9 +357,9 @@ enum chf_create_flags { Rowid's are not comparable. This is set if the rowid is unique to the current open handler, like it is with federated where the rowid is a pointer to a local result set buffer. The effect of having this set is - that the optimizer will not consirer the following optimizations for + that the optimizer will not consider the following optimizations for the table: - ror scans or filtering + ror scans, filtering or duplicate weedout */ #define HA_NON_COMPARABLE_ROWID (1ULL << 60) diff --git a/sql/item.cc b/sql/item.cc index 59be33cb77f..5bcddb5cd67 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3479,7 +3479,7 @@ bool Item_field::is_null_result() bool Item_field::eq(const Item *item, bool binary_cmp) const { - Item *real_item2= ((Item *) item)->real_item(); + const Item *real_item2= item->real_item(); if (real_item2->type() != FIELD_ITEM) return 0; diff --git a/sql/item.h b/sql/item.h index 7c440e76be1..706360c48f1 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2103,6 +2103,7 @@ public: virtual Item *copy_or_same(THD *thd) { return this; } virtual Item *copy_andor_structure(THD *thd) { return this; } virtual Item *real_item() { return this; } + const Item *real_item() const { return const_cast<Item*>(this)->real_item(); } virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); } virtual Item *make_odbc_literal(THD *thd, const LEX_CSTRING *typestr) { @@ -5580,7 +5581,7 @@ public: { return ref ? (*ref)->type() : REF_ITEM; } bool eq(const Item *item, bool binary_cmp) const override { - Item *it= ((Item *) item)->real_item(); + const Item *it= item->real_item(); return ref && (*ref)->eq(it, binary_cmp); } void save_val(Field *to) override; @@ -5936,7 +5937,7 @@ public: { orig_item->make_send_field(thd, field); } bool eq(const Item *item, bool binary_cmp) const override { - Item *it= const_cast<Item*>(item)->real_item(); + const Item *it= item->real_item(); return orig_item->eq(it, binary_cmp); } void fix_after_pullout(st_select_lex *new_parent, Item **refptr, bool merge) @@ -7817,7 +7818,7 @@ public: { m_item->make_send_field(thd, field); } bool eq(const Item *item, bool binary_cmp) const { - Item *it= ((Item *) item)->real_item(); + const Item *it= item->real_item(); return m_item->eq(it, binary_cmp); } void fix_after_pullout(st_select_lex *new_parent, Item **refptr, bool merge) diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 2efb8e39439..89f1c9c8221 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -1019,9 +1019,9 @@ String *Item_func_json_extract::read_json(String *str, for (n_arg=1; n_arg < arg_count; n_arg++) { json_path_with_flags *c_path= paths + n_arg - 1; - c_path->p.types_used= JSON_PATH_KEY_NULL; if (!c_path->parsed) { + c_path->p.types_used= JSON_PATH_KEY_NULL; String *s_p= args[n_arg]->val_str(tmp_paths + (n_arg-1)); if (s_p) { @@ -1104,7 +1104,7 @@ String *Item_func_json_extract::read_json(String *str, if (!possible_multiple_values) { /* Loop to the end of the JSON just to make sure it's valid. */ - while (json_get_path_next(&je, &p) == 0) {} + while (json_scan_next(&je) == 0) {} break; } } @@ -1744,7 +1744,7 @@ bool is_json_type(const Item *item) if (Type_handler_json_common::is_json_type_handler(item->type_handler())) return true; const Item_func_conv_charset *func; - if (!(func= dynamic_cast<const Item_func_conv_charset*>(item))) + if (!(func= dynamic_cast<const Item_func_conv_charset*>(item->real_item()))) return false; item= func->arguments()[0]; } diff --git a/sql/mdl.cc b/sql/mdl.cc index 2f5fdd0d60a..c426dbe143b 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -1747,10 +1747,9 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, #ifdef WITH_WSREP /* Approve lock request in BACKUP namespace for BF threads. - We should get rid of this code and forbid FTWRL/BACKUP statements - when wsrep is active. */ - if ((wsrep_thd_is_toi(requestor_ctx->get_thd()) || + if (!wsrep_check_mode(WSREP_MODE_BF_MARIABACKUP) && + (wsrep_thd_is_toi(requestor_ctx->get_thd()) || wsrep_thd_is_applying(requestor_ctx->get_thd())) && key.mdl_namespace() == MDL_key::BACKUP) { diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index da871e099dd..3e2531b90cd 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -664,6 +664,17 @@ int check_and_do_in_subquery_rewrites(JOIN *join) DBUG_RETURN(-1); } } + /* Check if any table is not supporting comparable rowids */ + { + List_iterator_fast<TABLE_LIST> li(select_lex->outer_select()->leaf_tables); + TABLE_LIST *tbl; + while ((tbl = li++)) + { + TABLE *table= tbl->table; + if (table && table->file->ha_table_flags() & HA_NON_COMPARABLE_ROWID) + join->not_usable_rowid_map|= table->map; + } + } DBUG_PRINT("info", ("Checking if subq can be converted to semi-join")); /* @@ -683,8 +694,11 @@ int check_and_do_in_subquery_rewrites(JOIN *join) 9. Parent select is not a table-less select 10. Neither parent nor child select have STRAIGHT_JOIN option. 11. It is first optimisation (the subquery could be moved from ON - clause during first optimisation and then be considered for SJ - on the second when it is too late) + clause during first optimisation and then be considered for SJ + on the second when it is too late) + 12. All tables supports comparable rowids. + This is needed for DuplicateWeedout strategy to work (which + is the catch-all semi-join strategy so it must be applicable). */ if (optimizer_flag(thd, OPTIMIZER_SWITCH_SEMIJOIN) && in_subs && // 1 @@ -699,7 +713,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join) !((join->select_options | // 10 select_lex->outer_select()->join->select_options) // 10 & SELECT_STRAIGHT_JOIN) && // 10 - select_lex->first_cond_optimization) // 11 + select_lex->first_cond_optimization && // 11 + join->not_usable_rowid_map == 0) // 12 { DBUG_PRINT("info", ("Subquery is semi-join conversion candidate")); @@ -3556,6 +3571,9 @@ bool Duplicate_weedout_picker::check_qep(JOIN *join, } else { + /* Ensure that table supports comparable rowids */ + DBUG_ASSERT(!(p->table->table->file->ha_table_flags() & HA_NON_COMPARABLE_ROWID)); + sj_outer_fanout= COST_MULT(sj_outer_fanout, p->records_read); temptable_rec_size += p->table->table->file->ref_length; } diff --git a/sql/service_wsrep.cc b/sql/service_wsrep.cc index 43183ff7595..943db803242 100644 --- a/sql/service_wsrep.cc +++ b/sql/service_wsrep.cc @@ -1,4 +1,4 @@ -/* Copyright 2018 Codership Oy <info@codership.com> +/* Copyright 2018-2023 Codership Oy <info@codership.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -241,7 +241,7 @@ extern "C" my_bool wsrep_thd_bf_abort(THD *bf_thd, THD *victim_thd, victim_thd->awake_no_mutex(KILL_QUERY); mysql_mutex_unlock(&victim_thd->LOCK_thd_data); } else { - WSREP_DEBUG("wsrep_thd_bf_abort skipped awake"); + WSREP_DEBUG("wsrep_thd_bf_abort skipped awake, signal %d", signal); } return ret; } @@ -253,7 +253,9 @@ extern "C" my_bool wsrep_thd_skip_locking(const THD *thd) extern "C" my_bool wsrep_thd_order_before(const THD *left, const THD *right) { - if (wsrep_thd_trx_seqno(left) < wsrep_thd_trx_seqno(right)) { + if (wsrep_thd_is_BF(left, false) && + wsrep_thd_is_BF(right, false) && + wsrep_thd_trx_seqno(left) < wsrep_thd_trx_seqno(right)) { WSREP_DEBUG("BF conflict, order: %lld %lld\n", (long long)wsrep_thd_trx_seqno(left), (long long)wsrep_thd_trx_seqno(right)); @@ -277,7 +279,6 @@ extern "C" my_bool wsrep_thd_is_aborting(const MYSQL_THD thd) return (cs.state() == wsrep::client_state::s_exec || cs.state() == wsrep::client_state::s_result); case wsrep::transaction::s_aborting: - case wsrep::transaction::s_aborted: return true; default: return false; @@ -369,13 +370,20 @@ extern "C" ulong wsrep_OSU_method_get(const MYSQL_THD thd) extern "C" bool wsrep_thd_set_wsrep_aborter(THD *bf_thd, THD *victim_thd) { - WSREP_DEBUG("wsrep_thd_set_wsrep_aborter called"); mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data); + if (!bf_thd) + { + victim_thd->wsrep_aborter= 0; + WSREP_DEBUG("wsrep_thd_set_wsrep_aborter resetting wsrep_aborter"); + return false; + } if (victim_thd->wsrep_aborter && victim_thd->wsrep_aborter != bf_thd->thread_id) { return true; } - victim_thd->wsrep_aborter = bf_thd->thread_id; + victim_thd->wsrep_aborter= bf_thd->thread_id; + WSREP_DEBUG("wsrep_thd_set_wsrep_aborter setting wsrep_aborter %u", + victim_thd->wsrep_aborter); return false; } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d85de205836..28119b54ddf 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -5457,8 +5457,8 @@ thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd) the caller should guarantee that the BF state won't change. (e.g. InnoDB does it by keeping lock_sys.mutex locked) */ - if (WSREP_ON && wsrep_thd_is_BF(thd, false) && - wsrep_thd_is_BF(other_thd, false)) + if (WSREP_ON && + wsrep_thd_order_before(thd, other_thd)) return 0; #endif /* WITH_WSREP */ rgi= thd->rgi_slave; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 942e2075ff1..95ed308103d 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -4402,7 +4402,7 @@ public: bool if_not_exists) { constr->name= name; - constr->flags= if_not_exists ? VCOL_CHECK_CONSTRAINT_IF_NOT_EXISTS : 0; + constr->if_not_exists= if_not_exists; alter_info.check_constraint_list.push_back(constr); return false; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f56ab1dd874..9b9d93d182e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -435,7 +435,7 @@ void JOIN::init(THD *thd_arg, List<Item> &fields_arg, table_count= 0; top_join_tab_count= 0; const_tables= 0; - const_table_map= found_const_table_map= 0; + const_table_map= found_const_table_map= not_usable_rowid_map= 0; aggr_tables= 0; eliminated_tables= 0; join_list= 0; @@ -2506,7 +2506,7 @@ JOIN::optimize_inner() /* We have to remove constants and duplicates from group_list before calling make_join_statistics() as this may call get_best_group_min_max() - which needs a simplfied group_list. + which needs a simplified group_list. */ if (group_list && table_count == 1) { @@ -5915,7 +5915,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list, caller to abort with a zero row result. */ TABLE_LIST *emb= s->table->pos_in_table_list->embedding; - if (emb && !emb->sj_on_expr) + if (emb && !emb->sj_on_expr && !*s->on_expr_ref) { /* Mark all tables in a multi-table join nest as const */ mark_join_nest_as_const(join, emb, &found_const_table_map, diff --git a/sql/sql_select.h b/sql/sql_select.h index 2cd32d73e38..fa4d373d556 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1261,6 +1261,8 @@ public: table_map outer_join; /* Bitmap of tables used in the select list items */ table_map select_list_used_tables; + /* Tables that has HA_NON_COMPARABLE_ROWID (does not support rowid) set */ + table_map not_usable_rowid_map; /* Tables that have a possiblity to use EQ_ref */ table_map eq_ref_tables; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3ca70ff93f0..9a60da58022 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3796,7 +3796,7 @@ without_overlaps_err: my_error(ER_TOO_LONG_IDENT, MYF(0), check->name.str); DBUG_RETURN(TRUE); } - if (check_expression(check, &check->name, VCOL_CHECK_TABLE)) + if (check_expression(check, &check->name, VCOL_CHECK_TABLE, alter_info)) DBUG_RETURN(TRUE); } } @@ -6222,10 +6222,8 @@ remove_key: while ((check=it++)) { - if (!(check->flags & VCOL_CHECK_CONSTRAINT_IF_NOT_EXISTS) && - check->name.length) + if (!check->if_not_exists && check->name.length) continue; - check->flags= 0; for (c= share->field_check_constraints; c < share->table_check_constraints ; c++) { diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 338f0f23c2c..1ed3d61bcf8 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -6167,6 +6167,7 @@ static const char *wsrep_mode_names[]= "REPLICATE_MYISAM", "REPLICATE_ARIA", "DISALLOW_LOCAL_GTID", + "BF_ABORT_MARIABACKUP", NullS }; static Sys_var_set Sys_wsrep_mode( diff --git a/sql/wsrep_high_priority_service.cc b/sql/wsrep_high_priority_service.cc index 708eb552866..93d4738212d 100644 --- a/sql/wsrep_high_priority_service.cc +++ b/sql/wsrep_high_priority_service.cc @@ -1,4 +1,4 @@ -/* Copyright 2018-2021 Codership Oy <info@codership.com> +/* Copyright 2018-2023 Codership Oy <info@codership.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -639,6 +639,9 @@ Wsrep_replayer_service::Wsrep_replayer_service(THD* replayer_thd, THD* orig_thd) transactional locks */ DBUG_ASSERT(!orig_thd->mdl_context.has_transactional_locks()); + replayer_thd->system_thread_info.rpl_sql_info= + new rpl_sql_thread_info(replayer_thd->wsrep_rgi->rli->mi->rpl_filter); + /* Make a shadow copy of diagnostics area and reset */ m_da_shadow.status= orig_thd->get_stmt_da()->status(); if (m_da_shadow.status == Diagnostics_area::DA_OK) @@ -677,35 +680,35 @@ Wsrep_replayer_service::Wsrep_replayer_service(THD* replayer_thd, THD* orig_thd) Wsrep_replayer_service::~Wsrep_replayer_service() { - THD* replayer_thd= m_thd; - THD* orig_thd= m_orig_thd; - /* Switch execution context back to original. */ - wsrep_after_apply(replayer_thd); - wsrep_after_command_ignore_result(replayer_thd); - wsrep_close(replayer_thd); - wsrep_reset_threadvars(replayer_thd); - wsrep_store_threadvars(orig_thd); + wsrep_after_apply(m_thd); + wsrep_after_command_ignore_result(m_thd); + wsrep_close(m_thd); + wsrep_reset_threadvars(m_thd); + wsrep_store_threadvars(m_orig_thd); - DBUG_ASSERT(!orig_thd->get_stmt_da()->is_sent()); - DBUG_ASSERT(!orig_thd->get_stmt_da()->is_set()); + DBUG_ASSERT(!m_orig_thd->get_stmt_da()->is_sent()); + DBUG_ASSERT(!m_orig_thd->get_stmt_da()->is_set()); + + delete m_thd->system_thread_info.rpl_sql_info; + m_thd->system_thread_info.rpl_sql_info= nullptr; if (m_replay_status == wsrep::provider::success) { - DBUG_ASSERT(replayer_thd->wsrep_cs().current_error() == wsrep::e_success); - orig_thd->reset_kill_query(); - my_ok(orig_thd, m_da_shadow.affected_rows, m_da_shadow.last_insert_id); + DBUG_ASSERT(m_thd->wsrep_cs().current_error() == wsrep::e_success); + m_orig_thd->reset_kill_query(); + my_ok(m_orig_thd, m_da_shadow.affected_rows, m_da_shadow.last_insert_id); } else if (m_replay_status == wsrep::provider::error_certification_failed) { - wsrep_override_error(orig_thd, ER_LOCK_DEADLOCK); + wsrep_override_error(m_orig_thd, ER_LOCK_DEADLOCK); } else { DBUG_ASSERT(0); WSREP_ERROR("trx_replay failed for: %d, schema: %s, query: %s", m_replay_status, - orig_thd->db.str, wsrep_thd_query(orig_thd)); + m_orig_thd->db.str, wsrep_thd_query(m_orig_thd)); unireg_abort(1); } } diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 43e694f6367..371b7de27c5 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -365,10 +365,12 @@ static void wsrep_log_cb(wsrep::log::level level, void wsrep_init_gtid() { wsrep_server_gtid_t stored_gtid= wsrep_get_SE_checkpoint<wsrep_server_gtid_t>(); + // Domain id may have changed, use the one + // received during state transfer. + stored_gtid.domain_id= wsrep_gtid_server.domain_id; if (stored_gtid.server_id == 0) { rpl_gtid wsrep_last_gtid; - stored_gtid.domain_id= wsrep_gtid_server.domain_id; if (mysql_bin_log.is_open() && mysql_bin_log.lookup_domain_in_binlog_state(stored_gtid.domain_id, &wsrep_last_gtid)) @@ -3131,6 +3133,11 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx, THD_STAGE_INFO(request_thd, stage_waiting_ddl); ticket->wsrep_report(wsrep_debug); mysql_mutex_unlock(&granted_thd->LOCK_thd_data); + if (granted_thd->current_backup_stage != BACKUP_FINISHED && + wsrep_check_mode(WSREP_MODE_BF_MARIABACKUP)) + { + wsrep_abort_thd(request_thd, granted_thd, 1); + } } else if (request_thd->lex->sql_command == SQLCOM_DROP_TABLE) { diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 0d2fcd559ef..9001b62d013 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -130,7 +130,8 @@ enum enum_wsrep_mode { WSREP_MODE_REQUIRED_PRIMARY_KEY= (1ULL << 2), WSREP_MODE_REPLICATE_MYISAM= (1ULL << 3), WSREP_MODE_REPLICATE_ARIA= (1ULL << 4), - WSREP_MODE_DISALLOW_LOCAL_GTID= (1ULL << 5) + WSREP_MODE_DISALLOW_LOCAL_GTID= (1ULL << 5), + WSREP_MODE_BF_MARIABACKUP= (1ULL << 6) }; // Streaming Replication diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index e610d3a6c2b..420a25dd2ae 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2022 Codership Oy <info@codership.com> +/* Copyright (C) 2013-2023 Codership Oy <info@codership.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -308,32 +308,37 @@ void wsrep_fire_rollbacker(THD *thd) } -int wsrep_abort_thd(THD *bf_thd_ptr, THD *victim_thd_ptr, my_bool signal) +int wsrep_abort_thd(THD *bf_thd, + THD *victim_thd, + my_bool signal) { DBUG_ENTER("wsrep_abort_thd"); - THD *victim_thd= (THD *) victim_thd_ptr; - THD *bf_thd= (THD *) bf_thd_ptr; mysql_mutex_lock(&victim_thd->LOCK_thd_data); /* Note that when you use RSU node is desynced from cluster, thus WSREP(thd) might not be true. */ - if ((WSREP(bf_thd) || + if ((WSREP_NNULL(bf_thd) || ((WSREP_ON || bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU) && wsrep_thd_is_toi(bf_thd))) && - victim_thd && !wsrep_thd_is_aborting(victim_thd)) { - WSREP_DEBUG("wsrep_abort_thd, by: %llu, victim: %llu", (bf_thd) ? - (long long)bf_thd->real_id : 0, (long long)victim_thd->real_id); + WSREP_DEBUG("wsrep_abort_thd, by: %llu, victim: %llu", + (long long)bf_thd->real_id, (long long)victim_thd->real_id); mysql_mutex_unlock(&victim_thd->LOCK_thd_data); ha_abort_transaction(bf_thd, victim_thd, signal); - mysql_mutex_lock(&victim_thd->LOCK_thd_data); + DBUG_RETURN(1); } else { - WSREP_DEBUG("wsrep_abort_thd not effective: %p %p", bf_thd, victim_thd); + WSREP_DEBUG("wsrep_abort_thd not effective: bf %llu victim %llu " + "wsrep %d wsrep_on %d RSU %d TOI %d aborting %d", + (long long)bf_thd->real_id, (long long)victim_thd->real_id, + WSREP_NNULL(bf_thd), WSREP_ON, + bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU, + wsrep_thd_is_toi(bf_thd), + wsrep_thd_is_aborting(victim_thd)); } mysql_mutex_unlock(&victim_thd->LOCK_thd_data); @@ -375,6 +380,14 @@ bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd) have acquired MDL locks (due to DDL execution), and this has caused BF conflict. such case does not require aborting in wsrep or replication provider state. */ + if (victim_thd->current_backup_stage != BACKUP_FINISHED && + wsrep_check_mode(WSREP_MODE_BF_MARIABACKUP)) + { + WSREP_DEBUG("killing connection for non wsrep session"); + mysql_mutex_lock(&victim_thd->LOCK_thd_data); + victim_thd->awake_no_mutex(KILL_CONNECTION); + mysql_mutex_unlock(&victim_thd->LOCK_thd_data); + } return false; } diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h index fd48df1494f..3d1bf3733a8 100644 --- a/sql/wsrep_thd.h +++ b/sql/wsrep_thd.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2022 Codership Oy <info@codership.com> +/* Copyright (C) 2013-2023 Codership Oy <info@codership.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -88,7 +88,9 @@ bool wsrep_create_appliers(long threads, bool mutex_protected=false); void wsrep_create_rollbacker(); bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd); -int wsrep_abort_thd(THD *bf_thd_ptr, THD *victim_thd_ptr, my_bool signal); +int wsrep_abort_thd(THD *bf_thd, + THD *victim_thd, + my_bool signal) __attribute__((nonnull(1,2))); /* Helper methods to deal with thread local storage. diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 57ab80fe9f7..2620ec326f1 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -18618,7 +18618,15 @@ void lock_wait_wsrep_kill(trx_t *bf_trx, ulong thd_id, trx_id_t trx_id) lock_sys.cancel_lock_wait_for_trx(vtrx); DEBUG_SYNC(bf_thd, "before_wsrep_thd_abort"); - wsrep_thd_bf_abort(bf_thd, vthd, true); + if (!wsrep_thd_bf_abort(bf_thd, vthd, true)) + { + wsrep_thd_LOCK(vthd); + wsrep_thd_set_wsrep_aborter(NULL, vthd); + wsrep_thd_UNLOCK(vthd); + + WSREP_DEBUG("wsrep_thd_bf_abort has failed, victim %lu will survive", + thd_get_thread_id(vthd)); + } } wsrep_thd_kill_UNLOCK(vthd); } diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 46cfb6e5c88..9577dfc62aa 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -693,22 +693,31 @@ lock_rec_has_to_wait( #endif /* HAVE_REPLICATION */ #ifdef WITH_WSREP - /* New lock request from a transaction is using unique key - scan and this transaction is a wsrep high priority transaction - (brute force). If conflicting transaction is also wsrep high - priority transaction we should avoid lock conflict because - ordering of these transactions is already decided and - conflicting transaction will be later replayed. */ - if (trx->is_wsrep_UK_scan() - && wsrep_thd_is_BF(lock2->trx->mysql_thd, false)) { - return false; - } + /* New lock request from a transaction is using unique key + scan and this transaction is a wsrep high priority transaction + (brute force). If conflicting transaction is also wsrep high + priority transaction we should avoid lock conflict because + ordering of these transactions is already decided and + conflicting transaction will be later replayed. */ + if (trx->is_wsrep_UK_scan() + && wsrep_thd_is_BF(lock2->trx->mysql_thd, false)) { + return false; + } + + /* if BF-BF conflict, we have to look at write set order */ + if (trx->is_wsrep() && + (type_mode & LOCK_MODE_MASK) == LOCK_X && + (lock2->type_mode & LOCK_MODE_MASK) == LOCK_X && + wsrep_thd_order_before(trx->mysql_thd, + lock2->trx->mysql_thd)) { + return false; + } - /* We very well can let bf to wait normally as other - BF will be replayed in case of conflict. For debug - builds we will do additional sanity checks to catch - unsupported bf wait if any. */ - ut_d(wsrep_assert_no_bf_bf_wait(lock2, trx)); + /* We very well can let bf to wait normally as other + BF will be replayed in case of conflict. For debug + builds we will do additional sanity checks to catch + unsupported bf wait if any. */ + ut_d(wsrep_assert_no_bf_bf_wait(lock2, trx)); #endif /* WITH_WSREP */ return true; @@ -1600,6 +1609,14 @@ lock_rec_has_to_wait_in_queue(const hash_cell_t &cell, const lock_t *wait_lock) if (heap_no < lock_rec_get_n_bits(lock) && (p[bit_offset] & bit_mask) && lock_has_to_wait(wait_lock, lock)) { +#ifdef WITH_WSREP + if (lock->trx->is_wsrep() && + wsrep_thd_order_before(wait_lock->trx->mysql_thd, + lock->trx->mysql_thd)) { + /* don't wait for another BF lock */ + continue; + } +#endif return(lock); } } |