Merge branch '10.6' into 10.7

This commit is contained in:
Oleksandr Byelkin 2023-01-18 16:36:13 +01:00
commit 795ff0daf0
46 changed files with 740 additions and 114 deletions

View file

@ -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)

View file

@ -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"

View file

@ -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()

@ -1 +1 @@
Subproject commit f1e2165c591f074feb47872a8ff712713ec411e1
Subproject commit 4fbd4fd36a21efd9d1a7e17aba390e91c78693b1

@ -1 +1 @@
Subproject commit 72b40bfaa869f3fe84242471dda989d13983d84c
Subproject commit 12bd1d5511fc2ff766ff6256c71b79a95739533f

View file

@ -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;

View file

@ -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;

View file

@ -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));

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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]

View file

@ -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;

View file

@ -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]

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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.");

View file

@ -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

View file

@ -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.");

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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, ...) */

View file

@ -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)

View file

@ -3476,7 +3476,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;

View file

@ -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)
{
@ -5593,7 +5594,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;
@ -5949,7 +5950,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)
@ -7830,7 +7831,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)

View file

@ -1064,7 +1064,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;
}
}
@ -1688,7 +1688,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];
}

View file

@ -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;
}

View file

@ -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
@ -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));
@ -368,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;
}

View file

@ -5448,8 +5448,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;

View file

@ -4397,7 +4397,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;
}

View file

@ -409,7 +409,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;
@ -2476,7 +2476,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)
{
@ -5863,7 +5863,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,

View file

@ -1254,6 +1254,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;
ha_rows send_records,found_records,join_examined_rows, accepted_rows;
/*

View file

@ -3741,7 +3741,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);
}
}
@ -6186,10 +6186,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++)
{

View file

@ -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);
}
}

View file

@ -362,10 +362,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))

View file

@ -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);

View file

@ -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.

View file

@ -18686,7 +18686,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);
}

View file

@ -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;
}
/* 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));
/* 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));
#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);
}
}