mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
Merge branch '10.5' into 10.6
This commit is contained in:
commit
10aa576483
63 changed files with 2033 additions and 437 deletions
|
@ -25,21 +25,24 @@
|
|||
#define DBUG_ASSERT_IF_WSREP(A) DBUG_ASSERT(A)
|
||||
|
||||
#define WSREP_MYSQL_DB (char *)"mysql"
|
||||
#define WSREP_TO_ISOLATION_BEGIN_IF(db_, table_, table_list_) \
|
||||
if (WSREP_ON && WSREP(thd) && wsrep_to_isolation_begin(thd, db_, table_, table_list_))
|
||||
|
||||
#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) \
|
||||
if (WSREP(thd) && wsrep_to_isolation_begin(thd, db_, table_, table_list_)) \
|
||||
#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) \
|
||||
if (WSREP_ON && WSREP(thd) && wsrep_to_isolation_begin(thd, db_, table_, table_list_)) \
|
||||
goto wsrep_error_label;
|
||||
|
||||
#define WSREP_TO_ISOLATION_BEGIN_CREATE(db_, table_, table_list_, create_info_) \
|
||||
if (WSREP(thd) && \
|
||||
if (WSREP_ON && WSREP(thd) && \
|
||||
wsrep_to_isolation_begin(thd, db_, table_, \
|
||||
table_list_, NULL, create_info_)) \
|
||||
table_list_, nullptr, nullptr, create_info_))\
|
||||
goto wsrep_error_label;
|
||||
|
||||
#define WSREP_TO_ISOLATION_BEGIN_ALTER(db_, table_, table_list_, alter_info_, create_info_) \
|
||||
if (WSREP(thd) && wsrep_thd_is_local(thd) && \
|
||||
wsrep_to_isolation_begin(thd, db_, table_, \
|
||||
table_list_, alter_info_, create_info_)) \
|
||||
#define WSREP_TO_ISOLATION_BEGIN_ALTER(db_, table_, table_list_, alter_info_, fk_tables_, create_info_) \
|
||||
if (WSREP(thd) && wsrep_thd_is_local(thd) && \
|
||||
wsrep_to_isolation_begin(thd, db_, table_, \
|
||||
table_list_, alter_info_, \
|
||||
fk_tables_, create_info_)) \
|
||||
goto wsrep_error_label;
|
||||
|
||||
#define WSREP_TO_ISOLATION_END \
|
||||
|
@ -55,6 +58,10 @@
|
|||
if (WSREP(thd) && !thd->lex->no_write_to_binlog \
|
||||
&& wsrep_to_isolation_begin(thd, db_, table_, table_list_)) goto wsrep_error_label;
|
||||
|
||||
#define WSREP_TO_ISOLATION_BEGIN_FK_TABLES(db_, table_, table_list_, fk_tables) \
|
||||
if (WSREP(thd) && !thd->lex->no_write_to_binlog \
|
||||
&& wsrep_to_isolation_begin(thd, db_, table_, table_list_, NULL, fk_tables))
|
||||
|
||||
#define WSREP_SYNC_WAIT(thd_, before_) \
|
||||
{ if (WSREP_CLIENT(thd_) && \
|
||||
wsrep_sync_wait(thd_, before_)) goto wsrep_error_label; }
|
||||
|
@ -68,7 +75,8 @@
|
|||
#define WSREP_DEBUG(...)
|
||||
#define WSREP_ERROR(...)
|
||||
#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) do { } while(0)
|
||||
#define WSREP_TO_ISOLATION_BEGIN_ALTER(db_, table_, table_list_, alter_info_, create_info_)
|
||||
#define WSREP_TO_ISOLATION_BEGIN_ALTER(db_, table_, table_list_, alter_info_, fk_tables_, create_info_)
|
||||
#define WSREP_TO_ISOLATION_BEGIN_FK_TABLES(db_, table_, table_list_, fk_tables_)
|
||||
#define WSREP_TO_ISOLATION_END
|
||||
#define WSREP_TO_ISOLATION_BEGIN_CREATE(db_, table_, table_list_, create_info_)
|
||||
#define WSREP_TO_ISOLATION_BEGIN_WRTCHK(db_, table_, table_list_)
|
||||
|
|
|
@ -3998,6 +3998,240 @@ YEAR d1 d2
|
|||
DROP PROCEDURE p;
|
||||
DROP TABLE t1,t2,t3,t4;
|
||||
#
|
||||
# MDEV-23619: recursive CTE used only in the second operand of UNION
|
||||
#
|
||||
create table t1 (
|
||||
a bigint(10) not null auto_increment,
|
||||
b int(5) not null,
|
||||
c bigint(10) default null,
|
||||
primary key (a)
|
||||
) engine myisam;
|
||||
insert into t1 values
|
||||
(1,3,12), (2,7,15), (3,1,3), (4,3,1);
|
||||
explain with recursive r_cte as
|
||||
( select * from t1 as s
|
||||
union
|
||||
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||
select 0 as b FROM dual union all select b FROM r_cte as t;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
2 DERIVED s ALL NULL NULL NULL NULL 4
|
||||
3 RECURSIVE UNION t1 ALL NULL NULL NULL NULL 4 Using where
|
||||
3 RECURSIVE UNION <derived2> ref key0 key0 9 test.t1.c 2
|
||||
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL
|
||||
4 RECURSIVE UNION <derived2> ALL NULL NULL NULL NULL 4
|
||||
with recursive r_cte as
|
||||
( select * from t1 as s
|
||||
union
|
||||
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||
select 0 as b FROM dual union all select b FROM r_cte as t;
|
||||
b
|
||||
0
|
||||
3
|
||||
7
|
||||
1
|
||||
3
|
||||
analyze format=json with recursive r_cte as
|
||||
( select * from t1 as s
|
||||
union
|
||||
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||
select 0 as b FROM dual union all select b FROM r_cte as t;
|
||||
ANALYZE
|
||||
{
|
||||
"query_block": {
|
||||
"union_result": {
|
||||
"table_name": "<union1,4>",
|
||||
"access_type": "ALL",
|
||||
"r_loops": 0,
|
||||
"r_rows": null,
|
||||
"query_specifications": [
|
||||
{
|
||||
"query_block": {
|
||||
"select_id": 1,
|
||||
"table": {
|
||||
"message": "No tables used"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"query_block": {
|
||||
"select_id": 4,
|
||||
"operation": "UNION",
|
||||
"r_loops": 1,
|
||||
"r_total_time_ms": "REPLACED",
|
||||
"table": {
|
||||
"table_name": "<derived2>",
|
||||
"access_type": "ALL",
|
||||
"r_loops": 1,
|
||||
"rows": 4,
|
||||
"r_rows": 4,
|
||||
"r_table_time_ms": "REPLACED",
|
||||
"r_other_time_ms": "REPLACED",
|
||||
"filtered": 100,
|
||||
"r_filtered": 100,
|
||||
"materialized": {
|
||||
"query_block": {
|
||||
"recursive_union": {
|
||||
"table_name": "<union2,3>",
|
||||
"access_type": "ALL",
|
||||
"r_loops": 0,
|
||||
"r_rows": null,
|
||||
"query_specifications": [
|
||||
{
|
||||
"query_block": {
|
||||
"select_id": 2,
|
||||
"r_loops": 1,
|
||||
"r_total_time_ms": "REPLACED",
|
||||
"table": {
|
||||
"table_name": "s",
|
||||
"access_type": "ALL",
|
||||
"r_loops": 1,
|
||||
"rows": 4,
|
||||
"r_rows": 4,
|
||||
"r_table_time_ms": "REPLACED",
|
||||
"r_other_time_ms": "REPLACED",
|
||||
"filtered": 100,
|
||||
"r_filtered": 100
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"query_block": {
|
||||
"select_id": 3,
|
||||
"operation": "UNION",
|
||||
"r_loops": 1,
|
||||
"r_total_time_ms": "REPLACED",
|
||||
"table": {
|
||||
"table_name": "t1",
|
||||
"access_type": "ALL",
|
||||
"r_loops": 1,
|
||||
"rows": 4,
|
||||
"r_rows": 4,
|
||||
"r_table_time_ms": "REPLACED",
|
||||
"r_other_time_ms": "REPLACED",
|
||||
"filtered": 100,
|
||||
"r_filtered": 100,
|
||||
"attached_condition": "t1.c is not null"
|
||||
},
|
||||
"table": {
|
||||
"table_name": "<derived2>",
|
||||
"access_type": "ref",
|
||||
"possible_keys": ["key0"],
|
||||
"key": "key0",
|
||||
"key_length": "9",
|
||||
"used_key_parts": ["a"],
|
||||
"ref": ["test.t1.c"],
|
||||
"r_loops": 4,
|
||||
"rows": 2,
|
||||
"r_rows": 0.5,
|
||||
"r_table_time_ms": "REPLACED",
|
||||
"r_other_time_ms": "REPLACED",
|
||||
"filtered": 100,
|
||||
"r_filtered": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
prepare stmt from "with recursive r_cte as
|
||||
( select * from t1 as s
|
||||
union
|
||||
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||
select 0 as b FROM dual union all select b FROM r_cte as t";
|
||||
execute stmt;
|
||||
b
|
||||
0
|
||||
3
|
||||
7
|
||||
1
|
||||
3
|
||||
execute stmt;
|
||||
b
|
||||
0
|
||||
3
|
||||
7
|
||||
1
|
||||
3
|
||||
deallocate prepare stmt;
|
||||
#checking hanging cte that uses a recursive cte
|
||||
explain with h_cte as
|
||||
( with recursive r_cte as
|
||||
( select * from t1 as s
|
||||
union
|
||||
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||
select 0 as b FROM dual union all select b FROM r_cte as t)
|
||||
select * from t1 as tt;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY tt ALL NULL NULL NULL NULL 4
|
||||
with h_cte as
|
||||
( with recursive r_cte as
|
||||
( select * from t1 as s
|
||||
union
|
||||
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||
select 0 as b FROM dual union all select b FROM r_cte as t)
|
||||
select * from t1 as tt;
|
||||
a b c
|
||||
1 3 12
|
||||
2 7 15
|
||||
3 1 3
|
||||
4 3 1
|
||||
analyze format=json with h_cte as
|
||||
( with recursive r_cte as
|
||||
( select * from t1 as s
|
||||
union
|
||||
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||
select 0 as b FROM dual union all select b FROM r_cte as t)
|
||||
select * from t1 as tt;
|
||||
ANALYZE
|
||||
{
|
||||
"query_block": {
|
||||
"select_id": 1,
|
||||
"r_loops": 1,
|
||||
"r_total_time_ms": "REPLACED",
|
||||
"table": {
|
||||
"table_name": "tt",
|
||||
"access_type": "ALL",
|
||||
"r_loops": 1,
|
||||
"rows": 4,
|
||||
"r_rows": 4,
|
||||
"r_table_time_ms": "REPLACED",
|
||||
"r_other_time_ms": "REPLACED",
|
||||
"filtered": 100,
|
||||
"r_filtered": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
prepare stmt from "with h_cte as
|
||||
( with recursive r_cte as
|
||||
( select * from t1 as s
|
||||
union
|
||||
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||
select 0 as b FROM dual union all select b FROM r_cte as t)
|
||||
select * from t1 as tt";
|
||||
execute stmt;
|
||||
a b c
|
||||
1 3 12
|
||||
2 7 15
|
||||
3 1 3
|
||||
4 3 1
|
||||
execute stmt;
|
||||
a b c
|
||||
1 3 12
|
||||
2 7 15
|
||||
3 1 3
|
||||
4 3 1
|
||||
deallocate prepare stmt;
|
||||
drop table t1;
|
||||
#
|
||||
# End of 10.2 tests
|
||||
#
|
||||
#
|
||||
|
|
|
@ -2675,6 +2675,56 @@ SELECT * FROM t4;
|
|||
DROP PROCEDURE p;
|
||||
DROP TABLE t1,t2,t3,t4;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-23619: recursive CTE used only in the second operand of UNION
|
||||
--echo #
|
||||
|
||||
create table t1 (
|
||||
a bigint(10) not null auto_increment,
|
||||
b int(5) not null,
|
||||
c bigint(10) default null,
|
||||
primary key (a)
|
||||
) engine myisam;
|
||||
insert into t1 values
|
||||
(1,3,12), (2,7,15), (3,1,3), (4,3,1);
|
||||
|
||||
let $q=
|
||||
with recursive r_cte as
|
||||
( select * from t1 as s
|
||||
union
|
||||
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||
select 0 as b FROM dual union all select b FROM r_cte as t;
|
||||
|
||||
eval explain $q;
|
||||
eval $q;
|
||||
--source include/analyze-format.inc
|
||||
eval analyze format=json $q;
|
||||
eval prepare stmt from "$q";
|
||||
execute stmt;
|
||||
execute stmt;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #checking hanging cte that uses a recursive cte
|
||||
let $q1=
|
||||
with h_cte as
|
||||
( with recursive r_cte as
|
||||
( select * from t1 as s
|
||||
union
|
||||
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||
select 0 as b FROM dual union all select b FROM r_cte as t)
|
||||
select * from t1 as tt;
|
||||
|
||||
eval explain $q1;
|
||||
eval $q1;
|
||||
--source include/analyze-format.inc
|
||||
eval analyze format=json $q1;
|
||||
eval prepare stmt from "$q1";
|
||||
execute stmt;
|
||||
execute stmt;
|
||||
deallocate prepare stmt;
|
||||
|
||||
drop table t1;
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.2 tests
|
||||
--echo #
|
||||
|
|
|
@ -130,5 +130,42 @@ connection default;
|
|||
#
|
||||
alter user user1@localhost account lock;
|
||||
ERROR HY000: Access denied, this account is locked
|
||||
#
|
||||
# MDEV-24098 SHOW CREATE USER invalid for both PASSWORD EXPIRE and
|
||||
# and LOCKED
|
||||
#
|
||||
alter user user1@localhost PASSWORD EXPIRE;
|
||||
show create user user1@localhost;
|
||||
CREATE USER for user1@localhost
|
||||
CREATE USER `user1`@`localhost` ACCOUNT LOCK PASSWORD EXPIRE
|
||||
drop user user1@localhost;
|
||||
#
|
||||
# MDEV-24098 CREATE USER/ALTER USER PASSWORD EXPIRE/LOCK in
|
||||
# either order.
|
||||
#
|
||||
create user user1@localhost PASSWORD EXPIRE ACCOUNT LOCK;
|
||||
show create user user1@localhost;
|
||||
CREATE USER for user1@localhost
|
||||
CREATE USER `user1`@`localhost` ACCOUNT LOCK PASSWORD EXPIRE
|
||||
drop user user1@localhost;
|
||||
create user user1@localhost ACCOUNT LOCK PASSWORD EXPIRE;
|
||||
show create user user1@localhost;
|
||||
CREATE USER for user1@localhost
|
||||
CREATE USER `user1`@`localhost` ACCOUNT LOCK PASSWORD EXPIRE
|
||||
alter user user1@localhost PASSWORD EXPIRE NEVER ACCOUNT UNLOCK ;
|
||||
show create user user1@localhost;
|
||||
CREATE USER for user1@localhost
|
||||
CREATE USER `user1`@`localhost` PASSWORD EXPIRE
|
||||
alter user user1@localhost ACCOUNT LOCK PASSWORD EXPIRE DEFAULT;
|
||||
show create user user1@localhost;
|
||||
CREATE USER for user1@localhost
|
||||
CREATE USER `user1`@`localhost` ACCOUNT LOCK PASSWORD EXPIRE
|
||||
alter user user1@localhost PASSWORD EXPIRE INTERVAL 60 DAY ACCOUNT UNLOCK;
|
||||
select * from mysql.global_priv where user='user1';
|
||||
Host User Priv
|
||||
localhost user1 {"access":0,"version_id":XXX,"plugin":"mysql_native_password","authentication_string":"","account_locked":false,"password_last_changed":0,"password_lifetime":60}
|
||||
show create user user1@localhost;
|
||||
CREATE USER for user1@localhost
|
||||
CREATE USER `user1`@`localhost` PASSWORD EXPIRE
|
||||
drop user user1@localhost;
|
||||
drop user user2@localhost;
|
||||
|
|
|
@ -137,6 +137,33 @@ alter user user1@localhost account lock;
|
|||
--error ER_ACCOUNT_HAS_BEEN_LOCKED
|
||||
--change_user user1
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-24098 SHOW CREATE USER invalid for both PASSWORD EXPIRE and
|
||||
--echo # and LOCKED
|
||||
--echo #
|
||||
alter user user1@localhost PASSWORD EXPIRE;
|
||||
show create user user1@localhost;
|
||||
drop user user1@localhost;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-24098 CREATE USER/ALTER USER PASSWORD EXPIRE/LOCK in
|
||||
--echo # either order.
|
||||
--echo #
|
||||
create user user1@localhost PASSWORD EXPIRE ACCOUNT LOCK;
|
||||
show create user user1@localhost;
|
||||
drop user user1@localhost;
|
||||
create user user1@localhost ACCOUNT LOCK PASSWORD EXPIRE;
|
||||
show create user user1@localhost;
|
||||
alter user user1@localhost PASSWORD EXPIRE NEVER ACCOUNT UNLOCK ;
|
||||
show create user user1@localhost;
|
||||
alter user user1@localhost ACCOUNT LOCK PASSWORD EXPIRE DEFAULT;
|
||||
show create user user1@localhost;
|
||||
# note output needs to be corrected by MDEV-24114: password expire users cannot be unexpired
|
||||
alter user user1@localhost PASSWORD EXPIRE INTERVAL 60 DAY ACCOUNT UNLOCK;
|
||||
--replace_regex /"version_id":[0-9]*,/"version_id":XXX,/
|
||||
select * from mysql.global_priv where user='user1';
|
||||
show create user user1@localhost;
|
||||
|
||||
drop user user1@localhost;
|
||||
drop user user2@localhost;
|
||||
|
||||
|
|
|
@ -647,6 +647,7 @@ sub run_test_server ($$$) {
|
|||
# Client disconnected
|
||||
mtr_verbose("Child closed socket");
|
||||
$s->remove($sock);
|
||||
$sock->close;
|
||||
if (--$childs == 0){
|
||||
return ("Completed", $test_failure, $completed, $extra_warnings);
|
||||
}
|
||||
|
@ -816,6 +817,7 @@ sub run_test_server ($$$) {
|
|||
# Test failure due to warnings, force is off
|
||||
return ("Warnings in log", 1, $completed, $extra_warnings);
|
||||
}
|
||||
next;
|
||||
}
|
||||
elsif ($line =~ /^SPENT/) {
|
||||
add_total_times($line);
|
||||
|
@ -4102,6 +4104,7 @@ sub run_testcase ($$) {
|
|||
if (start_servers($tinfo))
|
||||
{
|
||||
report_failure_and_restart($tinfo);
|
||||
unlink $path_current_testlog;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
8
mysql-test/suite/galera/r/MDEV-24063.result
Normal file
8
mysql-test/suite/galera/r/MDEV-24063.result
Normal file
|
@ -0,0 +1,8 @@
|
|||
connection node_2;
|
||||
connection node_1;
|
||||
connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
|
||||
connection node_2a;
|
||||
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY);
|
||||
connection node_2;
|
||||
SET GLOBAL wsrep_on=OFF;
|
||||
DROP TABLE t1;
|
657
mysql-test/suite/galera/r/galera_ddl_fk_conflict.result
Normal file
657
mysql-test/suite/galera/r/galera_ddl_fk_conflict.result
Normal file
|
@ -0,0 +1,657 @@
|
|||
connection node_2;
|
||||
connection node_1;
|
||||
connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
|
||||
connection node_1a;
|
||||
SET SESSION wsrep_sync_wait=0;
|
||||
connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1;
|
||||
connection node_1b;
|
||||
SET SESSION wsrep_sync_wait=0;
|
||||
######################################################################
|
||||
# Test for OPTIMIZE
|
||||
######################################################################
|
||||
######################################################################
|
||||
#
|
||||
# Scenario #1: DML working on FK parent table BF aborted by DDL
|
||||
# over child table
|
||||
#
|
||||
######################################################################
|
||||
connection node_1;
|
||||
SET SESSION wsrep_sync_wait=0;
|
||||
CREATE TABLE p1 (pk INTEGER PRIMARY KEY, f2 CHAR(30));
|
||||
INSERT INTO p1 VALUES (1, 'INITIAL VALUE');
|
||||
CREATE TABLE p2 (pk INTEGER PRIMARY KEY, f2 CHAR(30));
|
||||
INSERT INTO p2 VALUES (1, 'INITIAL VALUE');
|
||||
INSERT INTO p2 VALUES (2, 'INITIAL VALUE');
|
||||
CREATE TABLE c1 (pk INTEGER PRIMARY KEY, fk INTEGER, FOREIGN KEY (fk) REFERENCES p1(pk));
|
||||
INSERT INTO c1 VALUES (1,1);
|
||||
CREATE TABLE c2 (pk INTEGER PRIMARY KEY, fk1 INTEGER, fk2 INTEGER, FOREIGN KEY (fk1) REFERENCES p1(pk), FOREIGN KEY (fk2) REFERENCES p2(pk));
|
||||
INSERT INTO c2 VALUES (1,1,1), (2,1,2);
|
||||
connection node_1;
|
||||
SET AUTOCOMMIT=ON;
|
||||
START TRANSACTION;
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
connection node_2;
|
||||
SET SESSION wsrep_sync_wait=0;
|
||||
OPTIMIZE TABLE c1 ;
|
||||
Table Op Msg_type Msg_text
|
||||
test.c1 optimize note Table does not support optimize, doing recreate + analyze instead
|
||||
test.c1 optimize status OK
|
||||
connection node_1;
|
||||
COMMIT;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
connection node_2;
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
######################################################################
|
||||
#
|
||||
# Scenario #2: DML working on FK parent table tries to replicate, but
|
||||
# fails in certification for earlier DDL on child table
|
||||
#
|
||||
######################################################################
|
||||
connection node_1;
|
||||
BEGIN;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
|
||||
connection node_2;
|
||||
OPTIMIZE TABLE c1 ;
|
||||
Table Op Msg_type Msg_text
|
||||
test.c1 optimize note Table does not support optimize, doing recreate + analyze instead
|
||||
test.c1 optimize status OK
|
||||
connection node_1a;
|
||||
SET SESSION wsrep_on = 0;
|
||||
SET SESSION wsrep_on = 1;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=';
|
||||
connection node_1;
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
COMMIT;
|
||||
connection node_1a;
|
||||
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
|
||||
connection node_1;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT 'I deadlocked';
|
||||
I deadlocked
|
||||
I deadlocked
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
connection node_2;
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
######################################################################
|
||||
#
|
||||
# Scenario #3: 2 DMLs working on two FK parent tables try to replicate,
|
||||
# but fails in certification for earlier DDL on child table
|
||||
# which is child to both FK parents
|
||||
#
|
||||
######################################################################
|
||||
connection node_1;
|
||||
BEGIN;
|
||||
connection node_1b;
|
||||
BEGIN;
|
||||
connection node_1a;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
|
||||
connection node_2;
|
||||
OPTIMIZE TABLE c2 ;
|
||||
Table Op Msg_type Msg_text
|
||||
test.c2 optimize note Table does not support optimize, doing recreate + analyze instead
|
||||
test.c2 optimize status OK
|
||||
connection node_1a;
|
||||
SET SESSION wsrep_on = 0;
|
||||
SET SESSION wsrep_on = 1;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=';
|
||||
connection node_1;
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
COMMIT;
|
||||
connection node_1b;
|
||||
UPDATE p2 SET f2 = 'TO DEADLOCK' WHERE pk = 2;
|
||||
COMMIT;
|
||||
connection node_1a;
|
||||
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
|
||||
connection node_1;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT 'I deadlocked';
|
||||
I deadlocked
|
||||
I deadlocked
|
||||
connection node_1b;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT 'I deadlocked';
|
||||
I deadlocked
|
||||
I deadlocked
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
connection node_2;
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
DROP TABLE c1, c2;
|
||||
DROP TABLE p1, p2;
|
||||
######################################################################
|
||||
# Test for OPTIMIZE
|
||||
######################################################################
|
||||
connection node_1;
|
||||
SET SESSION wsrep_sync_wait=0;
|
||||
CREATE TABLE p1 (pk INTEGER PRIMARY KEY, f2 CHAR(30));
|
||||
INSERT INTO p1 VALUES (1, 'INITIAL VALUE');
|
||||
CREATE TABLE c1 (pk INTEGER PRIMARY KEY, fk INTEGER, FOREIGN KEY (fk) REFERENCES p1(pk));
|
||||
INSERT INTO c1 VALUES (1,1);
|
||||
######################################################################
|
||||
#
|
||||
# Scenario #4: DML working on FK parent table tries to replicate, but
|
||||
# fails in certification for earlier DDL on child table
|
||||
# and another temporary table. TMP table should be skipped
|
||||
# but FK child table should be replicated with proper keys
|
||||
#
|
||||
######################################################################
|
||||
connection node_1;
|
||||
BEGIN;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
|
||||
connection node_2;
|
||||
CREATE TEMPORARY TABLE tmp (i int);
|
||||
OPTIMIZE TABLE c1, tmp ;
|
||||
Table Op Msg_type Msg_text
|
||||
test.c1 optimize note Table does not support optimize, doing recreate + analyze instead
|
||||
test.c1 optimize status OK
|
||||
test.tmp optimize note Table does not support optimize, doing recreate + analyze instead
|
||||
test.tmp optimize status OK
|
||||
DROP TABLE tmp;
|
||||
connection node_1a;
|
||||
SET SESSION wsrep_on = 0;
|
||||
SET SESSION wsrep_on = 1;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=';
|
||||
connection node_1;
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
COMMIT;
|
||||
connection node_1a;
|
||||
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
|
||||
connection node_1;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT 'I deadlocked';
|
||||
I deadlocked
|
||||
I deadlocked
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
connection node_2;
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
DROP TABLE c1;
|
||||
DROP TABLE p1;
|
||||
######################################################################
|
||||
# Test for REPAIR
|
||||
######################################################################
|
||||
######################################################################
|
||||
#
|
||||
# Scenario #1: DML working on FK parent table BF aborted by DDL
|
||||
# over child table
|
||||
#
|
||||
######################################################################
|
||||
connection node_1;
|
||||
SET SESSION wsrep_sync_wait=0;
|
||||
CREATE TABLE p1 (pk INTEGER PRIMARY KEY, f2 CHAR(30));
|
||||
INSERT INTO p1 VALUES (1, 'INITIAL VALUE');
|
||||
CREATE TABLE p2 (pk INTEGER PRIMARY KEY, f2 CHAR(30));
|
||||
INSERT INTO p2 VALUES (1, 'INITIAL VALUE');
|
||||
INSERT INTO p2 VALUES (2, 'INITIAL VALUE');
|
||||
CREATE TABLE c1 (pk INTEGER PRIMARY KEY, fk INTEGER, FOREIGN KEY (fk) REFERENCES p1(pk));
|
||||
INSERT INTO c1 VALUES (1,1);
|
||||
CREATE TABLE c2 (pk INTEGER PRIMARY KEY, fk1 INTEGER, fk2 INTEGER, FOREIGN KEY (fk1) REFERENCES p1(pk), FOREIGN KEY (fk2) REFERENCES p2(pk));
|
||||
INSERT INTO c2 VALUES (1,1,1), (2,1,2);
|
||||
connection node_1;
|
||||
SET AUTOCOMMIT=ON;
|
||||
START TRANSACTION;
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
connection node_2;
|
||||
SET SESSION wsrep_sync_wait=0;
|
||||
REPAIR TABLE c1 ;
|
||||
Table Op Msg_type Msg_text
|
||||
test.c1 repair note The storage engine for the table doesn't support repair
|
||||
connection node_1;
|
||||
COMMIT;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
connection node_2;
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
######################################################################
|
||||
#
|
||||
# Scenario #2: DML working on FK parent table tries to replicate, but
|
||||
# fails in certification for earlier DDL on child table
|
||||
#
|
||||
######################################################################
|
||||
connection node_1;
|
||||
BEGIN;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
|
||||
connection node_2;
|
||||
REPAIR TABLE c1 ;
|
||||
Table Op Msg_type Msg_text
|
||||
test.c1 repair note The storage engine for the table doesn't support repair
|
||||
connection node_1a;
|
||||
SET SESSION wsrep_on = 0;
|
||||
SET SESSION wsrep_on = 1;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=';
|
||||
connection node_1;
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
COMMIT;
|
||||
connection node_1a;
|
||||
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
|
||||
connection node_1;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT 'I deadlocked';
|
||||
I deadlocked
|
||||
I deadlocked
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
connection node_2;
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
######################################################################
|
||||
#
|
||||
# Scenario #3: 2 DMLs working on two FK parent tables try to replicate,
|
||||
# but fails in certification for earlier DDL on child table
|
||||
# which is child to both FK parents
|
||||
#
|
||||
######################################################################
|
||||
connection node_1;
|
||||
BEGIN;
|
||||
connection node_1b;
|
||||
BEGIN;
|
||||
connection node_1a;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
|
||||
connection node_2;
|
||||
REPAIR TABLE c2 ;
|
||||
Table Op Msg_type Msg_text
|
||||
test.c2 repair note The storage engine for the table doesn't support repair
|
||||
connection node_1a;
|
||||
SET SESSION wsrep_on = 0;
|
||||
SET SESSION wsrep_on = 1;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=';
|
||||
connection node_1;
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
COMMIT;
|
||||
connection node_1b;
|
||||
UPDATE p2 SET f2 = 'TO DEADLOCK' WHERE pk = 2;
|
||||
COMMIT;
|
||||
connection node_1a;
|
||||
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
|
||||
connection node_1;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT 'I deadlocked';
|
||||
I deadlocked
|
||||
I deadlocked
|
||||
connection node_1b;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT 'I deadlocked';
|
||||
I deadlocked
|
||||
I deadlocked
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
connection node_2;
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
DROP TABLE c1, c2;
|
||||
DROP TABLE p1, p2;
|
||||
######################################################################
|
||||
# Test for REPAIR
|
||||
######################################################################
|
||||
connection node_1;
|
||||
SET SESSION wsrep_sync_wait=0;
|
||||
CREATE TABLE p1 (pk INTEGER PRIMARY KEY, f2 CHAR(30));
|
||||
INSERT INTO p1 VALUES (1, 'INITIAL VALUE');
|
||||
CREATE TABLE c1 (pk INTEGER PRIMARY KEY, fk INTEGER, FOREIGN KEY (fk) REFERENCES p1(pk));
|
||||
INSERT INTO c1 VALUES (1,1);
|
||||
######################################################################
|
||||
#
|
||||
# Scenario #4: DML working on FK parent table tries to replicate, but
|
||||
# fails in certification for earlier DDL on child table
|
||||
# and another temporary table. TMP table should be skipped
|
||||
# but FK child table should be replicated with proper keys
|
||||
#
|
||||
######################################################################
|
||||
connection node_1;
|
||||
BEGIN;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
|
||||
connection node_2;
|
||||
CREATE TEMPORARY TABLE tmp (i int);
|
||||
REPAIR TABLE c1, tmp ;
|
||||
Table Op Msg_type Msg_text
|
||||
test.c1 repair note The storage engine for the table doesn't support repair
|
||||
test.tmp repair note The storage engine for the table doesn't support repair
|
||||
DROP TABLE tmp;
|
||||
connection node_1a;
|
||||
SET SESSION wsrep_on = 0;
|
||||
SET SESSION wsrep_on = 1;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=';
|
||||
connection node_1;
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
COMMIT;
|
||||
connection node_1a;
|
||||
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
|
||||
connection node_1;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT 'I deadlocked';
|
||||
I deadlocked
|
||||
I deadlocked
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
connection node_2;
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
DROP TABLE c1;
|
||||
DROP TABLE p1;
|
||||
######################################################################
|
||||
# Test for ALTER ENGINE=INNODB
|
||||
######################################################################
|
||||
######################################################################
|
||||
#
|
||||
# Scenario #1: DML working on FK parent table BF aborted by DDL
|
||||
# over child table
|
||||
#
|
||||
######################################################################
|
||||
connection node_1;
|
||||
SET SESSION wsrep_sync_wait=0;
|
||||
CREATE TABLE p1 (pk INTEGER PRIMARY KEY, f2 CHAR(30));
|
||||
INSERT INTO p1 VALUES (1, 'INITIAL VALUE');
|
||||
CREATE TABLE p2 (pk INTEGER PRIMARY KEY, f2 CHAR(30));
|
||||
INSERT INTO p2 VALUES (1, 'INITIAL VALUE');
|
||||
INSERT INTO p2 VALUES (2, 'INITIAL VALUE');
|
||||
CREATE TABLE c1 (pk INTEGER PRIMARY KEY, fk INTEGER, FOREIGN KEY (fk) REFERENCES p1(pk));
|
||||
INSERT INTO c1 VALUES (1,1);
|
||||
CREATE TABLE c2 (pk INTEGER PRIMARY KEY, fk1 INTEGER, fk2 INTEGER, FOREIGN KEY (fk1) REFERENCES p1(pk), FOREIGN KEY (fk2) REFERENCES p2(pk));
|
||||
INSERT INTO c2 VALUES (1,1,1), (2,1,2);
|
||||
connection node_1;
|
||||
SET AUTOCOMMIT=ON;
|
||||
START TRANSACTION;
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
connection node_2;
|
||||
SET SESSION wsrep_sync_wait=0;
|
||||
ALTER TABLE c1 ENGINE=INNODB;
|
||||
connection node_1;
|
||||
COMMIT;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
connection node_2;
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
######################################################################
|
||||
#
|
||||
# Scenario #2: DML working on FK parent table tries to replicate, but
|
||||
# fails in certification for earlier DDL on child table
|
||||
#
|
||||
######################################################################
|
||||
connection node_1;
|
||||
BEGIN;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
|
||||
connection node_2;
|
||||
ALTER TABLE c1 ENGINE=INNODB;
|
||||
connection node_1a;
|
||||
SET SESSION wsrep_on = 0;
|
||||
SET SESSION wsrep_on = 1;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=';
|
||||
connection node_1;
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
COMMIT;
|
||||
connection node_1a;
|
||||
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
|
||||
connection node_1;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT 'I deadlocked';
|
||||
I deadlocked
|
||||
I deadlocked
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
connection node_2;
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
######################################################################
|
||||
#
|
||||
# Scenario #3: 2 DMLs working on two FK parent tables try to replicate,
|
||||
# but fails in certification for earlier DDL on child table
|
||||
# which is child to both FK parents
|
||||
#
|
||||
######################################################################
|
||||
connection node_1;
|
||||
BEGIN;
|
||||
connection node_1b;
|
||||
BEGIN;
|
||||
connection node_1a;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
|
||||
connection node_2;
|
||||
ALTER TABLE c2 ENGINE=INNODB;
|
||||
connection node_1a;
|
||||
SET SESSION wsrep_on = 0;
|
||||
SET SESSION wsrep_on = 1;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=';
|
||||
connection node_1;
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
COMMIT;
|
||||
connection node_1b;
|
||||
UPDATE p2 SET f2 = 'TO DEADLOCK' WHERE pk = 2;
|
||||
COMMIT;
|
||||
connection node_1a;
|
||||
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
|
||||
connection node_1;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT 'I deadlocked';
|
||||
I deadlocked
|
||||
I deadlocked
|
||||
connection node_1b;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT 'I deadlocked';
|
||||
I deadlocked
|
||||
I deadlocked
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
connection node_2;
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
DROP TABLE c1, c2;
|
||||
DROP TABLE p1, p2;
|
||||
######################################################################
|
||||
# Test for TRUNCATE
|
||||
######################################################################
|
||||
######################################################################
|
||||
#
|
||||
# Scenario #1: DML working on FK parent table BF aborted by DDL
|
||||
# over child table
|
||||
#
|
||||
######################################################################
|
||||
connection node_1;
|
||||
SET SESSION wsrep_sync_wait=0;
|
||||
CREATE TABLE p1 (pk INTEGER PRIMARY KEY, f2 CHAR(30));
|
||||
INSERT INTO p1 VALUES (1, 'INITIAL VALUE');
|
||||
CREATE TABLE p2 (pk INTEGER PRIMARY KEY, f2 CHAR(30));
|
||||
INSERT INTO p2 VALUES (1, 'INITIAL VALUE');
|
||||
INSERT INTO p2 VALUES (2, 'INITIAL VALUE');
|
||||
CREATE TABLE c1 (pk INTEGER PRIMARY KEY, fk INTEGER, FOREIGN KEY (fk) REFERENCES p1(pk));
|
||||
INSERT INTO c1 VALUES (1,1);
|
||||
CREATE TABLE c2 (pk INTEGER PRIMARY KEY, fk1 INTEGER, fk2 INTEGER, FOREIGN KEY (fk1) REFERENCES p1(pk), FOREIGN KEY (fk2) REFERENCES p2(pk));
|
||||
INSERT INTO c2 VALUES (1,1,1), (2,1,2);
|
||||
connection node_1;
|
||||
SET AUTOCOMMIT=ON;
|
||||
START TRANSACTION;
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
connection node_2;
|
||||
SET SESSION wsrep_sync_wait=0;
|
||||
TRUNCATE TABLE c1 ;
|
||||
connection node_1;
|
||||
COMMIT;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
connection node_2;
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
######################################################################
|
||||
#
|
||||
# Scenario #2: DML working on FK parent table tries to replicate, but
|
||||
# fails in certification for earlier DDL on child table
|
||||
#
|
||||
######################################################################
|
||||
connection node_1;
|
||||
BEGIN;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
|
||||
connection node_2;
|
||||
TRUNCATE TABLE c1 ;
|
||||
connection node_1a;
|
||||
SET SESSION wsrep_on = 0;
|
||||
SET SESSION wsrep_on = 1;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=';
|
||||
connection node_1;
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
COMMIT;
|
||||
connection node_1a;
|
||||
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
|
||||
connection node_1;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT 'I deadlocked';
|
||||
I deadlocked
|
||||
I deadlocked
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
connection node_2;
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
######################################################################
|
||||
#
|
||||
# Scenario #3: 2 DMLs working on two FK parent tables try to replicate,
|
||||
# but fails in certification for earlier DDL on child table
|
||||
# which is child to both FK parents
|
||||
#
|
||||
######################################################################
|
||||
connection node_1;
|
||||
BEGIN;
|
||||
connection node_1b;
|
||||
BEGIN;
|
||||
connection node_1a;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
|
||||
connection node_2;
|
||||
TRUNCATE TABLE c2 ;
|
||||
connection node_1a;
|
||||
SET SESSION wsrep_on = 0;
|
||||
SET SESSION wsrep_on = 1;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=';
|
||||
connection node_1;
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
COMMIT;
|
||||
connection node_1b;
|
||||
UPDATE p2 SET f2 = 'TO DEADLOCK' WHERE pk = 2;
|
||||
COMMIT;
|
||||
connection node_1a;
|
||||
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
|
||||
connection node_1;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT 'I deadlocked';
|
||||
I deadlocked
|
||||
I deadlocked
|
||||
connection node_1b;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
SELECT 'I deadlocked';
|
||||
I deadlocked
|
||||
I deadlocked
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
connection node_2;
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_1
|
||||
1
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
EXPECT_2
|
||||
2
|
||||
DROP TABLE c1, c2;
|
||||
DROP TABLE p1, p2;
|
|
@ -45,34 +45,34 @@ connection node_2;
|
|||
set session wsrep_sync_wait=15;
|
||||
insert into t1(value) values (3);
|
||||
insert into t1(value) values (4);
|
||||
select * from t2;
|
||||
id tbl action
|
||||
1 t1 INSERT
|
||||
3 t1 INSERT
|
||||
4 t1 INSERT
|
||||
6 t1 INSERT
|
||||
select tbl, action from t2;
|
||||
tbl action
|
||||
t1 INSERT
|
||||
t1 INSERT
|
||||
t1 INSERT
|
||||
t1 INSERT
|
||||
connection node_1;
|
||||
drop trigger if exists log_insert;
|
||||
insert into t1(value) values (5);
|
||||
select * from t2;
|
||||
id tbl action
|
||||
1 t1 INSERT
|
||||
3 t1 INSERT
|
||||
4 t1 INSERT
|
||||
6 t1 INSERT
|
||||
select tbl, action from t2;
|
||||
tbl action
|
||||
t1 INSERT
|
||||
t1 INSERT
|
||||
t1 INSERT
|
||||
t1 INSERT
|
||||
connection node_2;
|
||||
insert into t1(value) values (6);
|
||||
select * from t2;
|
||||
id tbl action
|
||||
1 t1 INSERT
|
||||
3 t1 INSERT
|
||||
4 t1 INSERT
|
||||
6 t1 INSERT
|
||||
select tbl, action from t2;
|
||||
tbl action
|
||||
t1 INSERT
|
||||
t1 INSERT
|
||||
t1 INSERT
|
||||
t1 INSERT
|
||||
connection node_1;
|
||||
select * from t2;
|
||||
id tbl action
|
||||
1 t1 INSERT
|
||||
3 t1 INSERT
|
||||
4 t1 INSERT
|
||||
6 t1 INSERT
|
||||
select tbl, action from t2;
|
||||
tbl action
|
||||
t1 INSERT
|
||||
t1 INSERT
|
||||
t1 INSERT
|
||||
t1 INSERT
|
||||
drop table t1, t2;
|
||||
|
|
20
mysql-test/suite/galera/t/MDEV-24063.test
Normal file
20
mysql-test/suite/galera/t/MDEV-24063.test
Normal file
|
@ -0,0 +1,20 @@
|
|||
#
|
||||
# MDEV-24063
|
||||
#
|
||||
# my_bool wsrep_thd_is_aborting(const THD*):
|
||||
# Assertion `((&(&thd->LOCK_thd_data)->m_mutex)->count > 0 &&
|
||||
# pthread_equal(pthread_self(), (&(&thd->LOCK_thd_data)->m_mutex)->thread))' failed.
|
||||
#
|
||||
|
||||
--source include/galera_cluster.inc
|
||||
|
||||
--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
|
||||
--connection node_2a
|
||||
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY);
|
||||
|
||||
--connection node_2
|
||||
SET GLOBAL wsrep_on=OFF;
|
||||
--source include/shutdown_mysqld.inc
|
||||
--source include/start_mysqld.inc
|
||||
|
||||
DROP TABLE t1;
|
192
mysql-test/suite/galera/t/galera_ddl_fk_conflict.inc
Normal file
192
mysql-test/suite/galera/t/galera_ddl_fk_conflict.inc
Normal file
|
@ -0,0 +1,192 @@
|
|||
#
|
||||
# Test for MDL BF-BF lock conflict
|
||||
# There are some DDL statements, which take extensive MDL lock for
|
||||
# a table referenced by foreign key constraint from the actual affetec table.
|
||||
# This extensive MDL lock may cause MDL BF-BF confclict situations, if the
|
||||
# FK parent table is not listed as certification key in the replication write set.
|
||||
# i.e. if replication allows such DDL to apply in parallel with regular DML operating
|
||||
# on the FK parent table.
|
||||
#
|
||||
# This test has two scenarios, where DML modifies FK parent table in node 1,
|
||||
# and offending DDL for FK child table is sent from node 2.
|
||||
#
|
||||
# param: $table_admin_command
|
||||
# DDL table command to test, script will build full SQL statement:
|
||||
# $table_admin_command TABLE c;
|
||||
#
|
||||
# param: $table_admin_command_end
|
||||
# Optional additional SQL syntax to end the SQL statement, if any
|
||||
# $table_admin_command TABLE c $table_admin_command_end;
|
||||
#
|
||||
# scenario 1, can be used to test if a DDL statement causes such MDL locking vulnerability.
|
||||
# call this test script with some table DDL command in $table_admin_command
|
||||
# if scenario 1 passes (especially COMMIT does fail for ER_LOCK_DEADLOCK),
|
||||
# then this particular DDL is vulnerable. scenraio 2 should fail for this DDL
|
||||
# unless code has not been fixed to append parent table certification keys for it.
|
||||
#
|
||||
|
||||
--echo ######################################################################
|
||||
--echo # Test for $table_admin_command $table_admin_command_end
|
||||
--echo ######################################################################
|
||||
|
||||
|
||||
--echo ######################################################################
|
||||
--echo #
|
||||
--echo # Scenario #1: DML working on FK parent table BF aborted by DDL
|
||||
--echo # over child table
|
||||
--echo #
|
||||
--echo ######################################################################
|
||||
|
||||
--connection node_1
|
||||
SET SESSION wsrep_sync_wait=0;
|
||||
|
||||
CREATE TABLE p1 (pk INTEGER PRIMARY KEY, f2 CHAR(30));
|
||||
INSERT INTO p1 VALUES (1, 'INITIAL VALUE');
|
||||
|
||||
|
||||
CREATE TABLE p2 (pk INTEGER PRIMARY KEY, f2 CHAR(30));
|
||||
INSERT INTO p2 VALUES (1, 'INITIAL VALUE');
|
||||
INSERT INTO p2 VALUES (2, 'INITIAL VALUE');
|
||||
|
||||
CREATE TABLE c1 (pk INTEGER PRIMARY KEY, fk INTEGER, FOREIGN KEY (fk) REFERENCES p1(pk));
|
||||
INSERT INTO c1 VALUES (1,1);
|
||||
|
||||
CREATE TABLE c2 (pk INTEGER PRIMARY KEY, fk1 INTEGER, fk2 INTEGER, FOREIGN KEY (fk1) REFERENCES p1(pk), FOREIGN KEY (fk2) REFERENCES p2(pk));
|
||||
INSERT INTO c2 VALUES (1,1,1), (2,1,2);
|
||||
|
||||
--connection node_1
|
||||
SET AUTOCOMMIT=ON;
|
||||
START TRANSACTION;
|
||||
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
|
||||
--connection node_2
|
||||
SET SESSION wsrep_sync_wait=0;
|
||||
# wait for tables to be created in node 2 and all rows inserted as well
|
||||
--let $wait_condition = SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'test/c%'
|
||||
--source include/wait_condition.inc
|
||||
--let $wait_condition = SELECT COUNT(*) = 2 FROM c2
|
||||
--source include/wait_condition.inc
|
||||
|
||||
# replicate the DDL to be tested
|
||||
--eval $table_admin_command TABLE c1 $table_admin_command_end
|
||||
|
||||
--connection node_1
|
||||
--error ER_LOCK_DEADLOCK
|
||||
COMMIT;
|
||||
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
|
||||
--connection node_2
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
|
||||
--echo ######################################################################
|
||||
--echo #
|
||||
--echo # Scenario #2: DML working on FK parent table tries to replicate, but
|
||||
--echo # fails in certification for earlier DDL on child table
|
||||
--echo #
|
||||
--echo ######################################################################
|
||||
|
||||
--connection node_1
|
||||
BEGIN;
|
||||
|
||||
# Block the applier on node #1 and issue DDL on node 2
|
||||
--let $galera_sync_point = apply_monitor_slave_enter_sync
|
||||
--source include/galera_set_sync_point.inc
|
||||
|
||||
--connection node_2
|
||||
--eval $table_admin_command TABLE c1 $table_admin_command_end
|
||||
|
||||
--connection node_1a
|
||||
--source include/galera_wait_sync_point.inc
|
||||
--source include/galera_clear_sync_point.inc
|
||||
--let $expected_cert_failures = `SELECT VARIABLE_VALUE+1 FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_cert_failures'`
|
||||
|
||||
--connection node_1
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
--send COMMIT
|
||||
|
||||
--connection node_1a
|
||||
--let $wait_condition = SELECT VARIABLE_VALUE = $expected_cert_failures FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_cert_failures'
|
||||
--source include/wait_condition.inc
|
||||
|
||||
--let $galera_sync_point = apply_monitor_slave_enter_sync
|
||||
--source include/galera_signal_sync_point.inc
|
||||
|
||||
--connection node_1
|
||||
--error ER_LOCK_DEADLOCK
|
||||
--reap
|
||||
|
||||
SELECT 'I deadlocked';
|
||||
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
|
||||
--connection node_2
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
|
||||
|
||||
--echo ######################################################################
|
||||
--echo #
|
||||
--echo # Scenario #3: 2 DMLs working on two FK parent tables try to replicate,
|
||||
--echo # but fails in certification for earlier DDL on child table
|
||||
--echo # which is child to both FK parents
|
||||
--echo #
|
||||
--echo ######################################################################
|
||||
|
||||
--connection node_1
|
||||
BEGIN;
|
||||
|
||||
--connection node_1b
|
||||
BEGIN;
|
||||
|
||||
--connection node_1a
|
||||
# Block the applier on node #1 and issue DDL on node 2
|
||||
--let $galera_sync_point = apply_monitor_slave_enter_sync
|
||||
--source include/galera_set_sync_point.inc
|
||||
|
||||
--connection node_2
|
||||
--eval $table_admin_command TABLE c2 $table_admin_command_end
|
||||
|
||||
--connection node_1a
|
||||
--source include/galera_wait_sync_point.inc
|
||||
--source include/galera_clear_sync_point.inc
|
||||
--let $expected_cert_failures = `SELECT VARIABLE_VALUE+2 FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_cert_failures'`
|
||||
|
||||
--connection node_1
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
--send COMMIT
|
||||
|
||||
--connection node_1b
|
||||
UPDATE p2 SET f2 = 'TO DEADLOCK' WHERE pk = 2;
|
||||
--send COMMIT
|
||||
|
||||
--connection node_1a
|
||||
--let $wait_condition = SELECT VARIABLE_VALUE = $expected_cert_failures FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_cert_failures'
|
||||
--source include/wait_condition.inc
|
||||
|
||||
--let $galera_sync_point = apply_monitor_slave_enter_sync
|
||||
--source include/galera_signal_sync_point.inc
|
||||
|
||||
--connection node_1
|
||||
--error ER_LOCK_DEADLOCK
|
||||
--reap
|
||||
SELECT 'I deadlocked';
|
||||
|
||||
--connection node_1b
|
||||
--error ER_LOCK_DEADLOCK
|
||||
--reap
|
||||
SELECT 'I deadlocked';
|
||||
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
|
||||
--connection node_2
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM p2 WHERE f2 = 'INITIAL VALUE';
|
||||
|
||||
DROP TABLE c1, c2;
|
||||
DROP TABLE p1, p2;
|
37
mysql-test/suite/galera/t/galera_ddl_fk_conflict.test
Normal file
37
mysql-test/suite/galera/t/galera_ddl_fk_conflict.test
Normal file
|
@ -0,0 +1,37 @@
|
|||
#
|
||||
# MDL BF-BF lock conflict
|
||||
#
|
||||
|
||||
--source include/galera_cluster.inc
|
||||
--source include/have_innodb.inc
|
||||
--source include/have_debug_sync.inc
|
||||
--source include/galera_have_debug_sync.inc
|
||||
|
||||
# sync point controlling session
|
||||
--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
|
||||
--connection node_1a
|
||||
SET SESSION wsrep_sync_wait=0;
|
||||
|
||||
# secondary conflicting DML victim session
|
||||
--connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1
|
||||
--connection node_1b
|
||||
SET SESSION wsrep_sync_wait=0;
|
||||
|
||||
--let $table_admin_command = OPTIMIZE
|
||||
--source galera_ddl_fk_conflict.inc
|
||||
--source galera_ddl_fk_conflict_with_tmp.inc
|
||||
|
||||
--let $table_admin_command = REPAIR
|
||||
--source galera_ddl_fk_conflict.inc
|
||||
--source galera_ddl_fk_conflict_with_tmp.inc
|
||||
|
||||
--let $table_admin_command = ALTER
|
||||
--let $table_admin_command_end = ENGINE=INNODB
|
||||
--source galera_ddl_fk_conflict.inc
|
||||
|
||||
--let $table_admin_command = TRUNCATE
|
||||
--let $table_admin_command_end =
|
||||
--source galera_ddl_fk_conflict.inc
|
||||
|
||||
# CHECK and ANALYZE are not affected
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
--echo ######################################################################
|
||||
--echo # Test for $table_admin_command $table_admin_command_end
|
||||
--echo ######################################################################
|
||||
|
||||
|
||||
--connection node_1
|
||||
SET SESSION wsrep_sync_wait=0;
|
||||
|
||||
CREATE TABLE p1 (pk INTEGER PRIMARY KEY, f2 CHAR(30));
|
||||
INSERT INTO p1 VALUES (1, 'INITIAL VALUE');
|
||||
|
||||
|
||||
CREATE TABLE c1 (pk INTEGER PRIMARY KEY, fk INTEGER, FOREIGN KEY (fk) REFERENCES p1(pk));
|
||||
INSERT INTO c1 VALUES (1,1);
|
||||
|
||||
--echo ######################################################################
|
||||
--echo #
|
||||
--echo # Scenario #4: DML working on FK parent table tries to replicate, but
|
||||
--echo # fails in certification for earlier DDL on child table
|
||||
--echo # and another temporary table. TMP table should be skipped
|
||||
--echo # but FK child table should be replicated with proper keys
|
||||
--echo #
|
||||
--echo ######################################################################
|
||||
|
||||
--connection node_1
|
||||
BEGIN;
|
||||
|
||||
# Block the applier on node #1 and issue DDL on node 2
|
||||
--let $galera_sync_point = apply_monitor_slave_enter_sync
|
||||
--source include/galera_set_sync_point.inc
|
||||
|
||||
--connection node_2
|
||||
# wait for tables to be created in node 2 and all rows inserted as well
|
||||
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'test/c1'
|
||||
--source include/wait_condition.inc
|
||||
--let $wait_condition = SELECT COUNT(*) = 1 FROM c1
|
||||
--source include/wait_condition.inc
|
||||
CREATE TEMPORARY TABLE tmp (i int);
|
||||
--eval $table_admin_command TABLE c1, tmp $table_admin_command_end
|
||||
DROP TABLE tmp;
|
||||
|
||||
--connection node_1a
|
||||
--source include/galera_wait_sync_point.inc
|
||||
--source include/galera_clear_sync_point.inc
|
||||
--let $expected_cert_failures = `SELECT VARIABLE_VALUE+1 FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_cert_failures'`
|
||||
|
||||
--connection node_1
|
||||
UPDATE p1 SET f2 = 'TO DEADLOCK' WHERE pk = 1;
|
||||
--send COMMIT
|
||||
|
||||
--connection node_1a
|
||||
--let $wait_condition = SELECT VARIABLE_VALUE = $expected_cert_failures FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_cert_failures'
|
||||
--source include/wait_condition.inc
|
||||
|
||||
--let $galera_sync_point = apply_monitor_slave_enter_sync
|
||||
--source include/galera_signal_sync_point.inc
|
||||
|
||||
--connection node_1
|
||||
--error ER_LOCK_DEADLOCK
|
||||
--reap
|
||||
|
||||
SELECT 'I deadlocked';
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
|
||||
--connection node_2
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM p1 WHERE f2 = 'INITIAL VALUE';
|
||||
|
||||
DROP TABLE c1;
|
||||
DROP TABLE p1;
|
|
@ -55,18 +55,18 @@ insert into t1(value) values (2);
|
|||
set session wsrep_sync_wait=15;
|
||||
insert into t1(value) values (3);
|
||||
insert into t1(value) values (4);
|
||||
select * from t2;
|
||||
select tbl, action from t2;
|
||||
|
||||
--connection node_1
|
||||
drop trigger if exists log_insert;
|
||||
insert into t1(value) values (5);
|
||||
select * from t2;
|
||||
select tbl, action from t2;
|
||||
|
||||
--connection node_2
|
||||
insert into t1(value) values (6);
|
||||
select * from t2;
|
||||
select tbl, action from t2;
|
||||
|
||||
--connection node_1
|
||||
select * from t2;
|
||||
select tbl, action from t2;
|
||||
|
||||
drop table t1, t2;
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
--log-bin
|
9
mysql-test/suite/galera/t/mysql-wsrep#198.cnf
Normal file
9
mysql-test/suite/galera/t/mysql-wsrep#198.cnf
Normal file
|
@ -0,0 +1,9 @@
|
|||
!include ../galera_2nodes.cnf
|
||||
|
||||
[mysqld.1]
|
||||
log-bin
|
||||
wsrep-debug=1
|
||||
|
||||
[mysqld.1]
|
||||
log-bin
|
||||
wsrep-debug=1
|
|
@ -1,5 +1,6 @@
|
|||
--source include/galera_cluster.inc
|
||||
--source include/have_innodb.inc
|
||||
--source include/force_restart.inc
|
||||
|
||||
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
CREATE TABLE t2 (id INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
|
|
|
@ -22,3 +22,19 @@ i
|
|||
1
|
||||
UNLOCK TABLES;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# MDEV-23824 SIGSEGV in end_io_cache on REPAIR LOCAL TABLE for Aria table
|
||||
#
|
||||
CREATE TABLE t1 (i INT) ENGINE=Aria;
|
||||
INSERT INTO t1 VALUES (1);
|
||||
SET max_session_mem_used=50000;
|
||||
REPAIR LOCAL TABLE t1 USE_FRM;
|
||||
Table Op Msg_type Msg_text
|
||||
t1 repair error Failed to open partially repaired table
|
||||
Warnings:
|
||||
Error 1290 The MariaDB server is running with the --max-thread-mem-used=50000 option so it cannot execute this statement
|
||||
REPAIR LOCAL TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 repair Error The MariaDB server is running with the --max-thread-mem-used=50000 option so it cannot execute this statement
|
||||
test.t1 repair error Corrupt
|
||||
DROP TABLE t1;
|
||||
|
|
|
@ -22,3 +22,14 @@ SELECT * FROM INFORMATION_SCHEMA.TABLES;
|
|||
SELECT * FROM t1;
|
||||
UNLOCK TABLES;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-23824 SIGSEGV in end_io_cache on REPAIR LOCAL TABLE for Aria table
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (i INT) ENGINE=Aria;
|
||||
INSERT INTO t1 VALUES (1);
|
||||
SET max_session_mem_used=50000;
|
||||
REPAIR LOCAL TABLE t1 USE_FRM;
|
||||
REPAIR LOCAL TABLE t1;
|
||||
DROP TABLE t1;
|
||||
|
|
|
@ -16,7 +16,6 @@ wait/synch/sxlock/innodb/dict_operation_lock
|
|||
wait/synch/sxlock/innodb/fil_space_latch
|
||||
wait/synch/sxlock/innodb/fts_cache_init_rw_lock
|
||||
wait/synch/sxlock/innodb/fts_cache_rw_lock
|
||||
wait/synch/sxlock/innodb/index_online_log
|
||||
wait/synch/sxlock/innodb/index_tree_rw_lock
|
||||
wait/synch/sxlock/innodb/trx_i_s_cache_lock
|
||||
wait/synch/sxlock/innodb/trx_purge_latch
|
||||
|
|
|
@ -45,6 +45,10 @@ ERROR 42000: Incorrect column specifier for column 's'
|
|||
create or replace table t (id int primary key, s date, e date,
|
||||
period for mytime(s,x));
|
||||
ERROR 42S22: Unknown column 'x' in 'mytime'
|
||||
# MDEV-18842: Unfortunate error message when the same column is used
|
||||
# for application period start and end
|
||||
create or replace table t (s date, t date, period for apt(s,s));
|
||||
ERROR 42000: Column 's' specified twice
|
||||
create or replace table t (id int primary key, s date, e date,
|
||||
period for mytime(s,e),
|
||||
period for mytime2(s,e));
|
||||
|
|
|
@ -31,6 +31,12 @@ create or replace table t (id int primary key, s time, e time,
|
|||
--error ER_BAD_FIELD_ERROR
|
||||
create or replace table t (id int primary key, s date, e date,
|
||||
period for mytime(s,x));
|
||||
|
||||
--echo # MDEV-18842: Unfortunate error message when the same column is used
|
||||
--echo # for application period start and end
|
||||
--error ER_FIELD_SPECIFIED_TWICE
|
||||
create or replace table t (s date, t date, period for apt(s,s));
|
||||
|
||||
--error ER_MORE_THAN_ONE_PERIOD
|
||||
create or replace table t (id int primary key, s date, e date,
|
||||
period for mytime(s,e),
|
||||
|
|
|
@ -22,7 +22,7 @@ START SLAVE IO_THREAD;
|
|||
include/wait_for_slave_io_error.inc [errno=1236]
|
||||
connection master;
|
||||
FLUSH BINARY LOGS;
|
||||
PURGE BINARY LOGS TO 'master-bin.000002';;
|
||||
include/wait_for_purge.inc "master-bin.000002"
|
||||
FLUSH BINARY LOGS DELETE_DOMAIN_ID=(11);
|
||||
SELECT @@global.gtid_binlog_pos, @@global.gtid_binlog_state;
|
||||
@@global.gtid_binlog_pos @@global.gtid_binlog_state
|
||||
|
|
|
@ -53,17 +53,11 @@ START SLAVE IO_THREAD;
|
|||
# adjust the master binlog state
|
||||
FLUSH BINARY LOGS;
|
||||
--let $purge_to_binlog= query_get_value(SHOW MASTER STATUS, File, 1)
|
||||
--eval PURGE BINARY LOGS TO '$purge_to_binlog';
|
||||
--let $purge_binlogs_to=$purge_to_binlog
|
||||
--source include/wait_for_purge.inc
|
||||
|
||||
# with final removal of the extra domain
|
||||
###adding to debug info to catch the failure (1076):
|
||||
--error 0,1076
|
||||
--eval FLUSH BINARY LOGS DELETE_DOMAIN_ID=($extra_domain_id)
|
||||
|
||||
if ($mysql_errno == 1076) {
|
||||
--echo ### Failure "Could not delete gtid domain"
|
||||
--source include/show_rpl_debug_info.inc
|
||||
}
|
||||
|
||||
SELECT @@global.gtid_binlog_pos, @@global.gtid_binlog_state;
|
||||
|
||||
--connection slave
|
||||
|
|
|
@ -449,7 +449,8 @@ mysqld_ld_preload_text() {
|
|||
set_malloc_lib() {
|
||||
malloc_lib="$1"
|
||||
if expr "$malloc_lib" : "\(tcmalloc\|jemalloc\)" > /dev/null ; then
|
||||
if ! my_which ldconfig > /dev/null 2>&1
|
||||
export PATH=$PATH:/sbin
|
||||
if ! command -v ldconfig > /dev/null 2>&1
|
||||
then
|
||||
log_error "ldconfig command not found, required for ldconfig -p"
|
||||
exit 1
|
||||
|
|
|
@ -728,7 +728,7 @@ public:
|
|||
{
|
||||
bytes_written = 0;
|
||||
}
|
||||
void harvest_bytes_written(ulonglong* counter)
|
||||
void harvest_bytes_written(Atomic_counter<uint64> *counter)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
char buf1[22],buf2[22];
|
||||
|
|
|
@ -461,7 +461,7 @@ static inline int add_relay_log(Relay_log_info* rli,LOG_INFO* linfo)
|
|||
DBUG_RETURN(1);
|
||||
}
|
||||
rli->log_space_total += s.st_size;
|
||||
DBUG_PRINT("info",("log_space_total: %llu", rli->log_space_total));
|
||||
DBUG_PRINT("info",("log_space_total: %llu", uint64(rli->log_space_total)));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
@ -1254,7 +1254,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
|
|||
mysql_mutex_unlock(rli->relay_log.get_log_lock());
|
||||
}
|
||||
err:
|
||||
DBUG_PRINT("info",("log_space_total: %llu",rli->log_space_total));
|
||||
DBUG_PRINT("info",("log_space_total: %llu", uint64(rli->log_space_total)));
|
||||
mysql_mutex_unlock(&rli->data_lock);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
|
|
@ -240,7 +240,8 @@ public:
|
|||
threads, the SQL thread sets it to unblock the I/O thread and make it
|
||||
temporarily forget about the constraint.
|
||||
*/
|
||||
ulonglong log_space_limit,log_space_total;
|
||||
ulonglong log_space_limit;
|
||||
Atomic_counter<uint64> log_space_total;
|
||||
bool ignore_log_space_limit;
|
||||
|
||||
/*
|
||||
|
|
|
@ -2818,7 +2818,7 @@ static bool wait_for_relay_log_space(Relay_log_info* rli)
|
|||
DBUG_PRINT("info", ("log_space_limit=%llu log_space_total=%llu "
|
||||
"ignore_log_space_limit=%d "
|
||||
"sql_force_rotate_relay=%d",
|
||||
rli->log_space_limit, rli->log_space_total,
|
||||
rli->log_space_limit, uint64(rli->log_space_total),
|
||||
(int) rli->ignore_log_space_limit,
|
||||
(int) rli->sql_force_rotate_relay));
|
||||
}
|
||||
|
@ -5084,7 +5084,7 @@ Stopping slave I/O thread due to out-of-memory error from master");
|
|||
{
|
||||
DBUG_PRINT("info", ("log_space_limit=%llu log_space_total=%llu "
|
||||
"ignore_log_space_limit=%d",
|
||||
rli->log_space_limit, rli->log_space_total,
|
||||
rli->log_space_limit, uint64(rli->log_space_total),
|
||||
(int) rli->ignore_log_space_limit));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -9087,6 +9087,9 @@ bool mysql_show_create_user(THD *thd, LEX_USER *lex_user)
|
|||
append_identifier(thd, &result, username, strlen(username));
|
||||
add_user_parameters(thd, &result, acl_user, false);
|
||||
|
||||
if (acl_user->account_locked)
|
||||
result.append(STRING_WITH_LEN(" ACCOUNT LOCK"));
|
||||
|
||||
if (acl_user->password_expired)
|
||||
result.append(STRING_WITH_LEN(" PASSWORD EXPIRE"));
|
||||
else if (!acl_user->password_lifetime)
|
||||
|
@ -9098,9 +9101,6 @@ bool mysql_show_create_user(THD *thd, LEX_USER *lex_user)
|
|||
result.append(STRING_WITH_LEN(" DAY"));
|
||||
}
|
||||
|
||||
if (acl_user->account_locked)
|
||||
result.append(STRING_WITH_LEN(" ACCOUNT LOCK"));
|
||||
|
||||
protocol->prepare_for_resend();
|
||||
protocol->store(result.ptr(), result.length(), result.charset());
|
||||
if (protocol->write())
|
||||
|
|
108
sql/sql_admin.cc
108
sql/sql_admin.cc
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (c) 2010, 2015, Oracle and/or its affiliates.
|
||||
Copyright (c) 2011, 2019, MariaDB
|
||||
Copyright (c) 2011, 2020, MariaDB
|
||||
|
||||
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
|
||||
|
@ -31,7 +31,7 @@
|
|||
#include "strfunc.h"
|
||||
#include "sql_admin.h"
|
||||
#include "sql_statistics.h"
|
||||
|
||||
#include "wsrep_mysqld.h"
|
||||
/* Prepare, run and cleanup for mysql_recreate_table() */
|
||||
|
||||
static bool admin_recreate_table(THD *thd, TABLE_LIST *table_list)
|
||||
|
@ -90,10 +90,10 @@ static int send_check_errmsg(THD *thd, TABLE_LIST* table,
|
|||
static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
|
||||
HA_CHECK_OPT *check_opt)
|
||||
{
|
||||
int error= 0;
|
||||
int error= 0, create_error= 0;
|
||||
TABLE tmp_table, *table;
|
||||
TABLE_LIST *pos_in_locked_tables= 0;
|
||||
TABLE_SHARE *share;
|
||||
TABLE_SHARE *share= 0;
|
||||
bool has_mdl_lock= FALSE;
|
||||
char from[FN_REFLEN],tmp[FN_REFLEN+32];
|
||||
const char **ext;
|
||||
|
@ -206,6 +206,17 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
|
|||
HA_EXTRA_NOT_USED, NULL);
|
||||
table_list->table= 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Table open failed, maybe because we run out of memory.
|
||||
Close all open tables and relaese all MDL locks
|
||||
*/
|
||||
tdc_release_share(share);
|
||||
share->tdc->flush(thd, true);
|
||||
share= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
After this point we have an exclusive metadata lock on our table
|
||||
in both cases when table was successfully open in mysql_admin_table()
|
||||
|
@ -219,11 +230,8 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
|
|||
goto end;
|
||||
}
|
||||
if (dd_recreate_table(thd, table_list->db.str, table_list->table_name.str))
|
||||
{
|
||||
error= send_check_errmsg(thd, table_list, "repair",
|
||||
"Failed generating table from .frm file");
|
||||
goto end;
|
||||
}
|
||||
create_error= send_check_errmsg(thd, table_list, "repair",
|
||||
"Failed generating table from .frm file");
|
||||
/*
|
||||
'FALSE' for 'using_transactions' means don't postpone
|
||||
invalidation till the end of a transaction, but do it
|
||||
|
@ -236,6 +244,8 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
|
|||
"Failed restoring .MYD file");
|
||||
goto end;
|
||||
}
|
||||
if (create_error)
|
||||
goto end;
|
||||
|
||||
if (thd->locked_tables_list.locked_tables())
|
||||
{
|
||||
|
@ -263,7 +273,8 @@ end:
|
|||
if (table == &tmp_table)
|
||||
{
|
||||
closefrm(table);
|
||||
tdc_release_share(table->s);
|
||||
if (share)
|
||||
tdc_release_share(share);
|
||||
}
|
||||
/* In case of a temporary table there will be no metadata lock. */
|
||||
if (unlikely(error) && has_mdl_lock)
|
||||
|
@ -418,6 +429,50 @@ dbug_err:
|
|||
return open_error;
|
||||
}
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
/*
|
||||
OPTIMIZE, REPAIR and ALTER may take MDL locks not only for the affected table, but
|
||||
also for the table referenced by foreign key constraint.
|
||||
This wsrep_toi_replication() function handles TOI replication for OPTIMIZE and REPAIR
|
||||
so that certification keys for potential FK parent tables are also appended in the
|
||||
write set.
|
||||
ALTER TABLE case is handled elsewhere.
|
||||
*/
|
||||
static bool wsrep_toi_replication(THD *thd, TABLE_LIST *tables)
|
||||
{
|
||||
if (!WSREP(thd) || !WSREP_CLIENT(thd)) return false;
|
||||
|
||||
LEX *lex= thd->lex;
|
||||
/* only handle OPTIMIZE and REPAIR here */
|
||||
switch (lex->sql_command)
|
||||
{
|
||||
case SQLCOM_OPTIMIZE:
|
||||
case SQLCOM_REPAIR:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
close_thread_tables(thd);
|
||||
wsrep::key_array keys;
|
||||
|
||||
wsrep_append_fk_parent_table(thd, tables, &keys);
|
||||
|
||||
/* now TOI replication, with no locks held */
|
||||
if (keys.empty())
|
||||
{
|
||||
WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, tables);
|
||||
} else {
|
||||
WSREP_TO_ISOLATION_BEGIN_FK_TABLES(NULL, NULL, tables, &keys) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
wsrep_error_label:
|
||||
return true;
|
||||
}
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
/*
|
||||
RETURN VALUES
|
||||
|
@ -486,6 +541,13 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
|
|||
close_thread_tables(thd);
|
||||
for (table= tables; table; table= table->next_local)
|
||||
table->table= NULL;
|
||||
#ifdef WITH_WSREP
|
||||
if (wsrep_toi_replication(thd, tables))
|
||||
{
|
||||
WSREP_INFO("wsrep TOI replication of has failed, skipping OPTIMIZE");
|
||||
goto err;
|
||||
}
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
for (table= tables; table; table= table->next_local)
|
||||
{
|
||||
|
@ -592,6 +654,12 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
|
|||
#endif
|
||||
DBUG_PRINT("admin", ("table: %p", table->table));
|
||||
|
||||
if (table->schema_table)
|
||||
{
|
||||
result_code= HA_ADMIN_NOT_IMPLEMENTED;
|
||||
goto send_result;
|
||||
}
|
||||
|
||||
if (prepare_func)
|
||||
{
|
||||
DBUG_PRINT("admin", ("calling prepare_func"));
|
||||
|
@ -650,12 +718,6 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
|
|||
goto send_result;
|
||||
}
|
||||
|
||||
if (table->schema_table)
|
||||
{
|
||||
result_code= HA_ADMIN_NOT_IMPLEMENTED;
|
||||
goto send_result;
|
||||
}
|
||||
|
||||
if ((table->table->db_stat & HA_READ_ONLY) && open_for_modify)
|
||||
{
|
||||
/* purecov: begin inspected */
|
||||
|
@ -1338,10 +1400,10 @@ bool Sql_cmd_analyze_table::execute(THD *thd)
|
|||
m_lex->first_select_lex()->table_list.first= first_table;
|
||||
m_lex->query_tables= first_table;
|
||||
|
||||
error:
|
||||
#ifdef WITH_WSREP
|
||||
wsrep_error_label:
|
||||
#endif
|
||||
wsrep_error_label:
|
||||
#endif /* WITH_WSREP */
|
||||
error:
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
|
@ -1380,7 +1442,6 @@ bool Sql_cmd_optimize_table::execute(THD *thd)
|
|||
if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table,
|
||||
FALSE, UINT_MAX, FALSE))
|
||||
goto error; /* purecov: inspected */
|
||||
WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table);
|
||||
|
||||
res= (specialflag & SPECIAL_NO_NEW_FUNC) ?
|
||||
mysql_recreate_table(thd, first_table, true) :
|
||||
|
@ -1399,9 +1460,6 @@ bool Sql_cmd_optimize_table::execute(THD *thd)
|
|||
m_lex->query_tables= first_table;
|
||||
|
||||
error:
|
||||
#ifdef WITH_WSREP
|
||||
wsrep_error_label:
|
||||
#endif
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
|
@ -1416,7 +1474,6 @@ bool Sql_cmd_repair_table::execute(THD *thd)
|
|||
if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table,
|
||||
FALSE, UINT_MAX, FALSE))
|
||||
goto error; /* purecov: inspected */
|
||||
WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table);
|
||||
res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "repair",
|
||||
TL_WRITE, 1,
|
||||
MY_TEST(m_lex->check_opt.sql_flags & TT_USEFRM),
|
||||
|
@ -1435,8 +1492,5 @@ bool Sql_cmd_repair_table::execute(THD *thd)
|
|||
m_lex->query_tables= first_table;
|
||||
|
||||
error:
|
||||
#ifdef WITH_WSREP
|
||||
wsrep_error_label:
|
||||
#endif
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
|
|
@ -490,6 +490,25 @@ bool Sql_cmd_alter_table::execute(THD *thd)
|
|||
|
||||
if (check_grant(thd, priv_needed, first_table, FALSE, UINT_MAX, FALSE))
|
||||
DBUG_RETURN(TRUE); /* purecov: inspected */
|
||||
#ifdef WITH_WSREP
|
||||
if (WSREP(thd) && WSREP_CLIENT(thd) &&
|
||||
(!thd->is_current_stmt_binlog_format_row() ||
|
||||
!thd->find_temporary_table(first_table)))
|
||||
{
|
||||
wsrep::key_array keys;
|
||||
wsrep_append_fk_parent_table(thd, first_table, &keys);
|
||||
|
||||
WSREP_TO_ISOLATION_BEGIN_ALTER(lex->name.str ? select_lex->db.str
|
||||
: first_table->db.str,
|
||||
lex->name.str ? lex->name.str
|
||||
: first_table->table_name.str,
|
||||
first_table, &alter_info, &keys,
|
||||
used_engine ? &create_info : nullptr);
|
||||
|
||||
thd->variables.auto_increment_offset = 1;
|
||||
thd->variables.auto_increment_increment = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lex->name.str && !test_all_bits(priv, INSERT_ACL | CREATE_ACL))
|
||||
{
|
||||
|
@ -517,20 +536,6 @@ bool Sql_cmd_alter_table::execute(THD *thd)
|
|||
thd->work_part_info= 0;
|
||||
#endif
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
if (WSREP(thd) &&
|
||||
(!thd->is_current_stmt_binlog_format_row() ||
|
||||
!thd->find_temporary_table(first_table)))
|
||||
{
|
||||
WSREP_TO_ISOLATION_BEGIN_ALTER((lex->name.str ? select_lex->db.str : first_table->db.str),
|
||||
(lex->name.str ? lex->name.str : first_table->table_name.str),
|
||||
first_table, &alter_info, used_engine ? &create_info : NULL);
|
||||
|
||||
thd->variables.auto_increment_offset = 1;
|
||||
thd->variables.auto_increment_increment = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
result= mysql_alter_table(thd, &select_lex->db, &lex->name,
|
||||
&create_info,
|
||||
first_table,
|
||||
|
|
|
@ -3447,7 +3447,7 @@ public:
|
|||
void awake_no_mutex(killed_state state_to_set);
|
||||
void awake(killed_state state_to_set)
|
||||
{
|
||||
bool wsrep_on_local= WSREP_NNULL(this);
|
||||
bool wsrep_on_local= variables.wsrep_on;
|
||||
/*
|
||||
mutex locking order (LOCK_thd_data - LOCK_thd_kill)) requires
|
||||
to grab LOCK_thd_data here
|
||||
|
|
|
@ -5430,12 +5430,14 @@ void st_select_lex::set_explain_type(bool on_the_fly)
|
|||
/*
|
||||
pos_in_table_list=NULL for e.g. post-join aggregation JOIN_TABs.
|
||||
*/
|
||||
if (tab->table && tab->table->pos_in_table_list &&
|
||||
tab->table->pos_in_table_list->with &&
|
||||
tab->table->pos_in_table_list->with->is_recursive)
|
||||
if (!tab->table);
|
||||
else if (const TABLE_LIST *pos= tab->table->pos_in_table_list)
|
||||
{
|
||||
uses_cte= true;
|
||||
break;
|
||||
if (pos->with && pos->with->is_recursive)
|
||||
{
|
||||
uses_cte= true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uses_cte)
|
||||
|
|
|
@ -4469,6 +4469,12 @@ public:
|
|||
|
||||
int add_period(Lex_ident name, Lex_ident_sys_st start, Lex_ident_sys_st end)
|
||||
{
|
||||
if (lex_string_cmp(system_charset_info, &start, &end) == 0)
|
||||
{
|
||||
my_error(ER_FIELD_SPECIFIED_TWICE, MYF(0), start.str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Table_period_info &info= create_info.period_info;
|
||||
|
||||
if (check_exists && info.name.streq(name))
|
||||
|
|
|
@ -13778,6 +13778,9 @@ void JOIN::join_free()
|
|||
for (tmp_unit= select_lex->first_inner_unit();
|
||||
tmp_unit;
|
||||
tmp_unit= tmp_unit->next_unit())
|
||||
{
|
||||
if (tmp_unit->with_element && tmp_unit->with_element->is_recursive)
|
||||
continue;
|
||||
for (sl= tmp_unit->first_select(); sl; sl= sl->next_select())
|
||||
{
|
||||
Item_subselect *subselect= sl->master_unit()->item;
|
||||
|
@ -13795,7 +13798,7 @@ void JOIN::join_free()
|
|||
/* Can't unlock if at least one JOIN is still needed */
|
||||
can_unlock= can_unlock && full_local;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
We are not using tables anymore
|
||||
Unlock all tables. We may be in an INSERT .... SELECT statement.
|
||||
|
|
|
@ -427,9 +427,23 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
|
|||
bool hton_can_recreate;
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
if (WSREP(thd) &&
|
||||
wsrep_to_isolation_begin(thd, table_ref->db.str, table_ref->table_name.str, NULL))
|
||||
DBUG_RETURN(TRUE);
|
||||
if (WSREP(thd))
|
||||
{
|
||||
wsrep::key_array keys;
|
||||
wsrep_append_fk_parent_table(thd, table_ref, &keys);
|
||||
if (keys.empty())
|
||||
{
|
||||
WSREP_TO_ISOLATION_BEGIN_IF(table_ref->db.str, table_ref->table_name.str, NULL)
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
} else {
|
||||
WSREP_TO_ISOLATION_BEGIN_FK_TABLES(NULL, NULL, table_ref, &keys)
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
if (lock_table(thd, table_ref, &hton_can_recreate))
|
||||
|
|
|
@ -2541,13 +2541,7 @@ bool st_select_lex_unit::cleanup()
|
|||
{
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
/*
|
||||
When processing a PS/SP or an EXPLAIN command cleanup of a unit can
|
||||
be performed immediately when the unit is reached in the cleanup
|
||||
traversal initiated by the cleanup of the main unit.
|
||||
*/
|
||||
if (!thd->stmt_arena->is_stmt_prepare() && !thd->lex->describe &&
|
||||
with_element && with_element->is_recursive && union_result)
|
||||
if (with_element && with_element->is_recursive && union_result)
|
||||
{
|
||||
select_union_recursive *result= with_element->rec_result;
|
||||
if (++result->cleanup_count == with_element->rec_outer_references)
|
||||
|
@ -2729,27 +2723,31 @@ bool st_select_lex::cleanup()
|
|||
|
||||
if (join)
|
||||
{
|
||||
List_iterator<TABLE_LIST> ti(leaf_tables);
|
||||
TABLE_LIST *tbl;
|
||||
while ((tbl= ti++))
|
||||
{
|
||||
if (tbl->is_recursive_with_table() &&
|
||||
!tbl->is_with_table_recursive_reference())
|
||||
{
|
||||
/*
|
||||
If query is killed before open_and_process_table() for tbl
|
||||
is called then 'with' is already set, but 'derived' is not.
|
||||
*/
|
||||
st_select_lex_unit *unit= tbl->with->spec;
|
||||
error|= (bool) error | (uint) unit->cleanup();
|
||||
}
|
||||
}
|
||||
DBUG_ASSERT((st_select_lex*)join->select_lex == this);
|
||||
error= join->destroy();
|
||||
delete join;
|
||||
join= 0;
|
||||
}
|
||||
for (TABLE_LIST *tbl= get_table_list(); tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->is_recursive_with_table() &&
|
||||
!tbl->is_with_table_recursive_reference())
|
||||
{
|
||||
/*
|
||||
If query is killed before open_and_process_table() for tbl
|
||||
is called then 'with' is already set, but 'derived' is not.
|
||||
*/
|
||||
st_select_lex_unit *unit= tbl->with->spec;
|
||||
error|= (bool) error | (uint) unit->cleanup();
|
||||
}
|
||||
}
|
||||
for (SELECT_LEX_UNIT *lex_unit= first_inner_unit(); lex_unit ;
|
||||
lex_unit= lex_unit->next_unit())
|
||||
{
|
||||
if (lex_unit->with_element && lex_unit->with_element->is_recursive)
|
||||
continue;
|
||||
error= (bool) ((uint) error | (uint) lex_unit->cleanup());
|
||||
}
|
||||
inner_refs_list.empty();
|
||||
|
@ -2769,8 +2767,12 @@ void st_select_lex::cleanup_all_joins(bool full)
|
|||
join->cleanup(full);
|
||||
|
||||
for (unit= first_inner_unit(); unit; unit= unit->next_unit())
|
||||
{
|
||||
if (unit->with_element && unit->with_element->is_recursive)
|
||||
continue;
|
||||
for (sl= unit->first_select(); sl; sl= sl->next_select())
|
||||
sl->cleanup_all_joins(full);
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
|
|
@ -2501,7 +2501,7 @@ create:
|
|||
Lex->pop_select(); //main select
|
||||
}
|
||||
| create_or_replace USER_SYM opt_if_not_exists clear_privileges
|
||||
grant_list opt_require_clause opt_resource_options opt_account_locking opt_password_expiration
|
||||
grant_list opt_require_clause opt_resource_options opt_account_locking_and_opt_password_expiration
|
||||
{
|
||||
if (unlikely(Lex->set_command_with_check(SQLCOM_CREATE_USER,
|
||||
$1 | $3)))
|
||||
|
@ -7312,7 +7312,7 @@ alter:
|
|||
} OPTIONS_SYM '(' server_options_list ')' { }
|
||||
/* ALTER USER foo is allowed for MySQL compatibility. */
|
||||
| ALTER USER_SYM opt_if_exists clear_privileges grant_list
|
||||
opt_require_clause opt_resource_options opt_account_locking opt_password_expiration
|
||||
opt_require_clause opt_resource_options opt_account_locking_and_opt_password_expiration
|
||||
{
|
||||
Lex->create_info.set($3);
|
||||
Lex->sql_command= SQLCOM_ALTER_USER;
|
||||
|
@ -7348,39 +7348,46 @@ alter:
|
|||
} stmt_end {}
|
||||
;
|
||||
|
||||
opt_account_locking:
|
||||
/* Nothing */ {}
|
||||
| ACCOUNT_SYM LOCK_SYM
|
||||
account_locking_option:
|
||||
LOCK_SYM
|
||||
{
|
||||
Lex->account_options.account_locked= ACCOUNTLOCK_LOCKED;
|
||||
}
|
||||
| ACCOUNT_SYM UNLOCK_SYM
|
||||
| UNLOCK_SYM
|
||||
{
|
||||
Lex->account_options.account_locked= ACCOUNTLOCK_UNLOCKED;
|
||||
}
|
||||
;
|
||||
opt_password_expiration:
|
||||
/* Nothing */ {}
|
||||
| PASSWORD_SYM EXPIRE_SYM
|
||||
|
||||
opt_password_expire_option:
|
||||
/* empty */
|
||||
{
|
||||
Lex->account_options.password_expire= PASSWORD_EXPIRE_NOW;
|
||||
}
|
||||
| PASSWORD_SYM EXPIRE_SYM NEVER_SYM
|
||||
| NEVER_SYM
|
||||
{
|
||||
Lex->account_options.password_expire= PASSWORD_EXPIRE_NEVER;
|
||||
}
|
||||
| PASSWORD_SYM EXPIRE_SYM DEFAULT
|
||||
| DEFAULT
|
||||
{
|
||||
Lex->account_options.password_expire= PASSWORD_EXPIRE_DEFAULT;
|
||||
}
|
||||
| PASSWORD_SYM EXPIRE_SYM INTERVAL_SYM NUM DAY_SYM
|
||||
| INTERVAL_SYM NUM DAY_SYM
|
||||
{
|
||||
Lex->account_options.password_expire= PASSWORD_EXPIRE_INTERVAL;
|
||||
if (!(Lex->account_options.num_expiration_days= atoi($4.str)))
|
||||
my_yyabort_error((ER_WRONG_VALUE, MYF(0), "DAY", $4.str));
|
||||
if (!(Lex->account_options.num_expiration_days= atoi($2.str)))
|
||||
my_yyabort_error((ER_WRONG_VALUE, MYF(0), "DAY", $2.str));
|
||||
}
|
||||
;
|
||||
|
||||
opt_account_locking_and_opt_password_expiration:
|
||||
/* empty */
|
||||
| ACCOUNT_SYM account_locking_option
|
||||
| PASSWORD_SYM EXPIRE_SYM opt_password_expire_option
|
||||
| ACCOUNT_SYM account_locking_option PASSWORD_SYM EXPIRE_SYM opt_password_expire_option
|
||||
| PASSWORD_SYM EXPIRE_SYM opt_password_expire_option ACCOUNT_SYM account_locking_option
|
||||
;
|
||||
|
||||
ev_alter_on_schedule_completion:
|
||||
/* empty */ { $$= 0;}
|
||||
| ON SCHEDULE_SYM ev_schedule_time { $$= 1; }
|
||||
|
|
|
@ -245,6 +245,16 @@ void Wsrep_client_service::will_replay()
|
|||
mysql_mutex_unlock(&LOCK_wsrep_replaying);
|
||||
}
|
||||
|
||||
void Wsrep_client_service::signal_replayed()
|
||||
{
|
||||
DBUG_ASSERT(m_thd == current_thd);
|
||||
mysql_mutex_lock(&LOCK_wsrep_replaying);
|
||||
--wsrep_replaying;
|
||||
DBUG_ASSERT(wsrep_replaying >= 0);
|
||||
mysql_cond_broadcast(&COND_wsrep_replaying);
|
||||
mysql_mutex_unlock(&LOCK_wsrep_replaying);
|
||||
}
|
||||
|
||||
enum wsrep::provider::status Wsrep_client_service::replay()
|
||||
{
|
||||
|
||||
|
@ -273,14 +283,15 @@ enum wsrep::provider::status Wsrep_client_service::replay()
|
|||
}
|
||||
|
||||
delete replayer_thd;
|
||||
|
||||
mysql_mutex_lock(&LOCK_wsrep_replaying);
|
||||
--wsrep_replaying;
|
||||
mysql_cond_broadcast(&COND_wsrep_replaying);
|
||||
mysql_mutex_unlock(&LOCK_wsrep_replaying);
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
|
||||
enum wsrep::provider::status Wsrep_client_service::replay_unordered()
|
||||
{
|
||||
DBUG_ASSERT(0);
|
||||
return wsrep::provider::error_not_implemented;
|
||||
}
|
||||
|
||||
void Wsrep_client_service::wait_for_replayers(wsrep::unique_lock<wsrep::mutex>& lock)
|
||||
{
|
||||
DBUG_ASSERT(m_thd == current_thd);
|
||||
|
@ -300,6 +311,12 @@ void Wsrep_client_service::wait_for_replayers(wsrep::unique_lock<wsrep::mutex>&
|
|||
lock.lock();
|
||||
}
|
||||
|
||||
enum wsrep::provider::status Wsrep_client_service::commit_by_xid()
|
||||
{
|
||||
DBUG_ASSERT(0);
|
||||
return wsrep::provider::error_not_implemented;
|
||||
}
|
||||
|
||||
void Wsrep_client_service::debug_sync(const char* sync_point)
|
||||
{
|
||||
DBUG_ASSERT(m_thd == current_thd);
|
||||
|
|
|
@ -48,8 +48,19 @@ public:
|
|||
void emergency_shutdown()
|
||||
{ throw wsrep::not_implemented_error(); }
|
||||
void will_replay();
|
||||
void signal_replayed();
|
||||
enum wsrep::provider::status replay();
|
||||
enum wsrep::provider::status replay_unordered();
|
||||
void wait_for_replayers(wsrep::unique_lock<wsrep::mutex>&);
|
||||
enum wsrep::provider::status commit_by_xid();
|
||||
bool is_explicit_xa()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool is_xa_rollback()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void debug_sync(const char*);
|
||||
void debug_crash(const char*);
|
||||
int bf_rollback();
|
||||
|
|
|
@ -1261,6 +1261,51 @@ void wsrep_keys_free(wsrep_key_arr_t* key_arr)
|
|||
key_arr->keys_len= 0;
|
||||
}
|
||||
|
||||
void
|
||||
wsrep_append_fk_parent_table(THD* thd, TABLE_LIST* tables, wsrep::key_array* keys)
|
||||
{
|
||||
if (!WSREP(thd) || !WSREP_CLIENT(thd)) return;
|
||||
TABLE_LIST *table;
|
||||
|
||||
thd->mdl_context.release_transactional_locks();
|
||||
uint counter;
|
||||
MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
|
||||
|
||||
if (thd->open_temporary_tables(tables) ||
|
||||
open_tables(thd, &tables, &counter, MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL))
|
||||
{
|
||||
WSREP_DEBUG("unable to open table for FK checks for %s", thd->query());
|
||||
}
|
||||
|
||||
for (table= tables; table; table= table->next_local)
|
||||
{
|
||||
if (!is_temporary_table(table) && table->table)
|
||||
{
|
||||
FOREIGN_KEY_INFO *f_key_info;
|
||||
List<FOREIGN_KEY_INFO> f_key_list;
|
||||
|
||||
table->table->file->get_foreign_key_list(thd, &f_key_list);
|
||||
List_iterator_fast<FOREIGN_KEY_INFO> it(f_key_list);
|
||||
while ((f_key_info=it++))
|
||||
{
|
||||
WSREP_DEBUG("appended fkey %s", f_key_info->referenced_table->str);
|
||||
keys->push_back(wsrep_prepare_key_for_toi(f_key_info->referenced_db->str,
|
||||
f_key_info->referenced_table->str,
|
||||
wsrep::key::shared));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* close the table and release MDL locks */
|
||||
close_thread_tables(thd);
|
||||
thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
|
||||
for (table= tables; table; table= table->next_local)
|
||||
{
|
||||
table->table= NULL;
|
||||
table->mdl_request.ticket= NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @param db Database string
|
||||
* @param table Table string
|
||||
|
@ -1511,10 +1556,11 @@ wsrep_prepare_keys_for_alter_add_fk(const char* child_table_db,
|
|||
return ret;
|
||||
}
|
||||
|
||||
wsrep::key_array wsrep_prepare_keys_for_toi(const char* db,
|
||||
const char* table,
|
||||
const TABLE_LIST* table_list,
|
||||
const Alter_info* alter_info)
|
||||
wsrep::key_array wsrep_prepare_keys_for_toi(const char *db,
|
||||
const char *table,
|
||||
const TABLE_LIST *table_list,
|
||||
const Alter_info *alter_info,
|
||||
const wsrep::key_array *fk_tables)
|
||||
{
|
||||
wsrep::key_array ret;
|
||||
if (db || table)
|
||||
|
@ -1534,8 +1580,13 @@ wsrep::key_array wsrep_prepare_keys_for_toi(const char* db,
|
|||
ret.insert(ret.end(), fk.begin(), fk.end());
|
||||
}
|
||||
}
|
||||
if (fk_tables && !fk_tables->empty())
|
||||
{
|
||||
ret.insert(ret.end(), fk_tables->begin(), fk_tables->end());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct Query_log_Event from thd query and serialize it
|
||||
* into buffer.
|
||||
|
@ -2069,9 +2120,10 @@ fail:
|
|||
-1: TOI replication failed
|
||||
*/
|
||||
static int wsrep_TOI_begin(THD *thd, const char *db, const char *table,
|
||||
const TABLE_LIST* table_list,
|
||||
const Alter_info* alter_info,
|
||||
const HA_CREATE_INFO* create_info)
|
||||
const TABLE_LIST *table_list,
|
||||
const Alter_info *alter_info,
|
||||
const wsrep::key_array *fk_tables,
|
||||
const HA_CREATE_INFO *create_info)
|
||||
{
|
||||
DBUG_ASSERT(wsrep_OSU_method_get(thd) == WSREP_OSU_TOI);
|
||||
|
||||
|
@ -2102,7 +2154,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table,
|
|||
struct wsrep_buf buff= { buf, buf_len };
|
||||
|
||||
wsrep::key_array key_array=
|
||||
wsrep_prepare_keys_for_toi(db, table, table_list, alter_info);
|
||||
wsrep_prepare_keys_for_toi(db, table, table_list, alter_info, fk_tables);
|
||||
|
||||
if (thd->has_read_only_protection())
|
||||
{
|
||||
|
@ -2250,8 +2302,9 @@ static void wsrep_RSU_end(THD *thd)
|
|||
|
||||
int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_,
|
||||
const TABLE_LIST* table_list,
|
||||
const Alter_info* alter_info,
|
||||
const HA_CREATE_INFO* create_info)
|
||||
const Alter_info *alter_info,
|
||||
const wsrep::key_array *fk_tables,
|
||||
const HA_CREATE_INFO *create_info)
|
||||
{
|
||||
/*
|
||||
No isolation for applier or replaying threads.
|
||||
|
@ -2305,7 +2358,8 @@ int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_,
|
|||
{
|
||||
switch (wsrep_OSU_method_get(thd)) {
|
||||
case WSREP_OSU_TOI:
|
||||
ret= wsrep_TOI_begin(thd, db_, table_, table_list, alter_info, create_info);
|
||||
ret= wsrep_TOI_begin(thd, db_, table_, table_list, alter_info, fk_tables,
|
||||
create_info);
|
||||
break;
|
||||
case WSREP_OSU_RSU:
|
||||
ret= wsrep_RSU_begin(thd, db_, table_);
|
||||
|
|
|
@ -215,6 +215,7 @@ wsrep_sync_wait_upto (THD* thd, wsrep_gtid_t* upto, int timeout);
|
|||
extern void wsrep_last_committed_id (wsrep_gtid_t* gtid);
|
||||
extern int wsrep_check_opts();
|
||||
extern void wsrep_prepend_PATH (const char* path);
|
||||
void wsrep_append_fk_parent_table(THD* thd, TABLE_LIST* table, wsrep::key_array* keys);
|
||||
|
||||
/* Other global variables */
|
||||
extern wsrep_seqno_t wsrep_locked_seqno;
|
||||
|
@ -362,8 +363,9 @@ struct HA_CREATE_INFO;
|
|||
|
||||
int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_,
|
||||
const TABLE_LIST* table_list,
|
||||
const Alter_info* alter_info= NULL,
|
||||
const HA_CREATE_INFO* create_info= NULL);
|
||||
const Alter_info* alter_info= nullptr,
|
||||
const wsrep::key_array *fk_tables= nullptr,
|
||||
const HA_CREATE_INFO* create_info= nullptr);
|
||||
|
||||
bool wsrep_should_replicate_ddl(THD* thd, const enum legacy_db_type db_type);
|
||||
bool wsrep_should_replicate_ddl_iterate(THD* thd, const TABLE_LIST* table_list);
|
||||
|
@ -607,6 +609,9 @@ void wsrep_deinit_server();
|
|||
*/
|
||||
enum wsrep::streaming_context::fragment_unit wsrep_fragment_unit(ulong unit);
|
||||
|
||||
wsrep::key wsrep_prepare_key_for_toi(const char* db, const char* table,
|
||||
enum wsrep::key::type type);
|
||||
|
||||
#else /* !WITH_WSREP */
|
||||
|
||||
/* These macros are needed to compile MariaDB without WSREP support
|
||||
|
|
|
@ -3483,7 +3483,7 @@ re_evict:
|
|||
if (fix_block->page.ibuf_exist) {
|
||||
fix_block->page.ibuf_exist = false;
|
||||
ibuf_merge_or_delete_for_page(fix_block, page_id,
|
||||
zip_size, true);
|
||||
zip_size);
|
||||
}
|
||||
|
||||
if (rw_latch == RW_X_LATCH) {
|
||||
|
@ -3550,7 +3550,7 @@ buf_page_get_gen(
|
|||
{
|
||||
rw_lock_x_lock_inline(&block->lock, 0, file, line);
|
||||
block->page.ibuf_exist= false;
|
||||
ibuf_merge_or_delete_for_page(block, page_id, block->zip_size(), true);
|
||||
ibuf_merge_or_delete_for_page(block, page_id, block->zip_size());
|
||||
|
||||
if (rw_latch == RW_X_LATCH)
|
||||
{
|
||||
|
@ -3772,18 +3772,29 @@ loop:
|
|||
ut_ad(0);
|
||||
break;
|
||||
case BUF_BLOCK_FILE_PAGE:
|
||||
buf_block_buf_fix_inc(block, __FILE__, __LINE__);
|
||||
if (!mtr->have_x_latch(*block))
|
||||
{
|
||||
const auto num_fix_count= mtr->get_fix_count(block) + 1;
|
||||
while (block->page.io_fix() != BUF_IO_NONE ||
|
||||
num_fix_count != block->page.buf_fix_count())
|
||||
buf_block_buf_fix_inc(block, __FILE__, __LINE__);
|
||||
{
|
||||
mysql_mutex_unlock(&buf_pool.mutex);
|
||||
os_thread_yield();
|
||||
mysql_mutex_lock(&buf_pool.mutex);
|
||||
while (block->page.io_fix() != BUF_IO_NONE ||
|
||||
block->page.buf_fix_count() != 1)
|
||||
{
|
||||
timespec abstime;
|
||||
set_timespec_nsec(abstime, 1000000);
|
||||
mysql_cond_timedwait(&buf_pool.done_flush_list, &buf_pool.mutex,
|
||||
&abstime);
|
||||
}
|
||||
}
|
||||
rw_lock_x_lock(&block->lock);
|
||||
mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX);
|
||||
}
|
||||
else
|
||||
{
|
||||
ut_ad(!block->page.ibuf_exist);
|
||||
#ifdef BTR_CUR_HASH_ADAPT
|
||||
ut_ad(!block->index);
|
||||
#endif
|
||||
}
|
||||
rw_lock_x_lock(&block->lock);
|
||||
#ifdef BTR_CUR_HASH_ADAPT
|
||||
drop_hash_entry= block->index;
|
||||
#endif
|
||||
|
@ -3808,6 +3819,7 @@ loop:
|
|||
buf_page_free_descriptor(&block->page);
|
||||
block= free_block;
|
||||
buf_block_buf_fix_inc(block, __FILE__, __LINE__);
|
||||
mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3818,12 +3830,10 @@ loop:
|
|||
btr_search_drop_page_hash_index(block);
|
||||
#endif /* BTR_CUR_HASH_ADAPT */
|
||||
|
||||
mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX);
|
||||
|
||||
if (block->page.ibuf_exist)
|
||||
{
|
||||
if (!recv_recovery_is_on())
|
||||
ibuf_merge_or_delete_for_page(nullptr, page_id, zip_size, true);
|
||||
ibuf_merge_or_delete_for_page(nullptr, page_id, zip_size);
|
||||
block->page.ibuf_exist= false;
|
||||
}
|
||||
|
||||
|
@ -3885,7 +3895,7 @@ loop:
|
|||
/* Delete possible entries for the page from the insert buffer:
|
||||
such can exist if the page belonged to an index which was dropped */
|
||||
if (!recv_recovery_is_on())
|
||||
ibuf_merge_or_delete_for_page(nullptr, page_id, zip_size, true);
|
||||
ibuf_merge_or_delete_for_page(nullptr, page_id, zip_size);
|
||||
|
||||
static_assert(FIL_PAGE_PREV + 4 == FIL_PAGE_NEXT, "adjacent");
|
||||
memset_aligned<8>(block->frame + FIL_PAGE_PREV, 0xff, 8);
|
||||
|
|
|
@ -528,6 +528,7 @@ static PSI_mutex_info all_innodb_mutexes[] = {
|
|||
PSI_KEY(ibuf_bitmap_mutex),
|
||||
PSI_KEY(ibuf_mutex),
|
||||
PSI_KEY(ibuf_pessimistic_insert_mutex),
|
||||
PSI_KEY(index_online_log),
|
||||
PSI_KEY(log_sys_mutex),
|
||||
PSI_KEY(page_zip_stat_per_index_mutex),
|
||||
PSI_KEY(purge_sys_pq_mutex),
|
||||
|
@ -574,7 +575,6 @@ static PSI_rwlock_info all_innodb_rwlocks[] = {
|
|||
PSI_RWLOCK_KEY(trx_i_s_cache_lock),
|
||||
PSI_RWLOCK_KEY(trx_purge_latch),
|
||||
PSI_RWLOCK_KEY(index_tree_rw_lock),
|
||||
PSI_RWLOCK_KEY(index_online_log),
|
||||
};
|
||||
# endif /* UNIV_PFS_RWLOCK */
|
||||
|
||||
|
@ -15005,24 +15005,6 @@ struct table_list_item {
|
|||
const char* name;
|
||||
};
|
||||
|
||||
/** Structure to compare two st_tablename objects using their
|
||||
db and tablename. It is used in the ordering of cascade_fk_set.
|
||||
It returns true if the first argument precedes the second argument
|
||||
and false otherwise. */
|
||||
struct tablename_compare {
|
||||
|
||||
bool operator()(const st_handler_tablename lhs,
|
||||
const st_handler_tablename rhs) const
|
||||
{
|
||||
int cmp = strcmp(lhs.db, rhs.db);
|
||||
if (cmp == 0) {
|
||||
cmp = strcmp(lhs.tablename, rhs.tablename);
|
||||
}
|
||||
|
||||
return(cmp < 0);
|
||||
}
|
||||
};
|
||||
|
||||
/*****************************************************************//**
|
||||
Checks if ALTER TABLE may change the storage engine of the table.
|
||||
Changing storage engines is not allowed for tables for which there
|
||||
|
|
|
@ -51,12 +51,7 @@ struct ha_table_option_struct
|
|||
uint encryption; /*!< DEFAULT, ON, OFF */
|
||||
ulonglong encryption_key_id; /*!< encryption key id */
|
||||
};
|
||||
/* JAN: TODO: MySQL 5.7 handler.h */
|
||||
struct st_handler_tablename
|
||||
{
|
||||
const char *db;
|
||||
const char *tablename;
|
||||
};
|
||||
|
||||
/** The class defining a handle to an Innodb table */
|
||||
class ha_innobase final : public handler
|
||||
{
|
||||
|
|
|
@ -4170,19 +4170,11 @@ insert buffer. If the page is not read, but created in the buffer pool, this
|
|||
function deletes its buffered entries from the insert buffer; there can
|
||||
exist entries for such a page if the page belonged to an index which
|
||||
subsequently was dropped.
|
||||
@param[in,out] block if page has been read from disk,
|
||||
pointer to the page x-latched, else NULL
|
||||
@param[in] page_id page id of the index page
|
||||
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
|
||||
@param[in] update_ibuf_bitmap normally this is set, but
|
||||
if we have deleted or are deleting the tablespace, then we naturally do not
|
||||
want to update a non-existent bitmap page */
|
||||
void
|
||||
ibuf_merge_or_delete_for_page(
|
||||
buf_block_t* block,
|
||||
const page_id_t page_id,
|
||||
ulint zip_size,
|
||||
bool update_ibuf_bitmap)
|
||||
@param block X-latched page to try to apply changes to, or NULL to discard
|
||||
@param page_id page identifier
|
||||
@param zip_size ROW_FORMAT=COMPRESSED page size, or 0 */
|
||||
void ibuf_merge_or_delete_for_page(buf_block_t *block, const page_id_t page_id,
|
||||
ulint zip_size)
|
||||
{
|
||||
btr_pcur_t pcur;
|
||||
#ifdef UNIV_IBUF_DEBUG
|
||||
|
@ -4211,47 +4203,33 @@ ibuf_merge_or_delete_for_page(
|
|||
return;
|
||||
}
|
||||
|
||||
fil_space_t* space;
|
||||
fil_space_t* space = fil_space_t::get(page_id.space());
|
||||
|
||||
if (update_ibuf_bitmap) {
|
||||
space = fil_space_t::get(page_id.space());
|
||||
|
||||
if (UNIV_UNLIKELY(!space)) {
|
||||
/* Do not try to read the bitmap page from the
|
||||
non-existent tablespace, delete the ibuf records */
|
||||
block = NULL;
|
||||
update_ibuf_bitmap = false;
|
||||
} else {
|
||||
ulint bitmap_bits = 0;
|
||||
|
||||
ibuf_mtr_start(&mtr);
|
||||
|
||||
buf_block_t* bitmap_page = ibuf_bitmap_get_map_page(
|
||||
page_id, zip_size, &mtr);
|
||||
|
||||
if (bitmap_page
|
||||
&& fil_page_get_type(bitmap_page->frame)
|
||||
!= FIL_PAGE_TYPE_ALLOCATED) {
|
||||
bitmap_bits = ibuf_bitmap_page_get_bits(
|
||||
bitmap_page->frame, page_id, zip_size,
|
||||
IBUF_BITMAP_BUFFERED, &mtr);
|
||||
}
|
||||
|
||||
ibuf_mtr_commit(&mtr);
|
||||
|
||||
if (!bitmap_bits) {
|
||||
/* No changes are buffered for this page. */
|
||||
space->release();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (block != NULL
|
||||
&& (ibuf_fixed_addr_page(page_id, physical_size)
|
||||
|| fsp_descr_page(page_id, physical_size))) {
|
||||
|
||||
return;
|
||||
if (UNIV_UNLIKELY(!space)) {
|
||||
block = NULL;
|
||||
} else {
|
||||
space = NULL;
|
||||
ulint bitmap_bits = 0;
|
||||
|
||||
ibuf_mtr_start(&mtr);
|
||||
|
||||
buf_block_t* bitmap_page = ibuf_bitmap_get_map_page(
|
||||
page_id, zip_size, &mtr);
|
||||
|
||||
if (bitmap_page
|
||||
&& fil_page_get_type(bitmap_page->frame)
|
||||
!= FIL_PAGE_TYPE_ALLOCATED) {
|
||||
bitmap_bits = ibuf_bitmap_page_get_bits(
|
||||
bitmap_page->frame, page_id, zip_size,
|
||||
IBUF_BITMAP_BUFFERED, &mtr);
|
||||
}
|
||||
|
||||
ibuf_mtr_commit(&mtr);
|
||||
|
||||
if (!bitmap_bits) {
|
||||
/* No changes are buffered for this page. */
|
||||
space->release();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mem_heap_t* heap = mem_heap_create(512);
|
||||
|
@ -4297,12 +4275,11 @@ loop:
|
|||
ibuf.index, search_tuple, PAGE_CUR_GE, BTR_MODIFY_LEAF,
|
||||
&pcur, &mtr);
|
||||
|
||||
if (block != NULL) {
|
||||
if (block) {
|
||||
ut_ad(rw_lock_own(&block->lock, RW_LOCK_X));
|
||||
buf_block_buf_fix_inc(block, __FILE__, __LINE__);
|
||||
rw_lock_x_lock(&block->lock);
|
||||
|
||||
mtr.set_named_space(space);
|
||||
mtr.memo_push(block, MTR_MEMO_PAGE_X_FIX);
|
||||
/* This is a user page (secondary index leaf page),
|
||||
but we pretend that it is a change buffer page in
|
||||
|
@ -4311,7 +4288,9 @@ loop:
|
|||
the block is io-fixed. Other threads must not try to
|
||||
latch an io-fixed block. */
|
||||
buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE);
|
||||
} else if (update_ibuf_bitmap) {
|
||||
}
|
||||
|
||||
if (space) {
|
||||
mtr.set_named_space(space);
|
||||
}
|
||||
|
||||
|
@ -4467,7 +4446,7 @@ loop:
|
|||
}
|
||||
|
||||
reset_bit:
|
||||
if (!update_ibuf_bitmap) {
|
||||
if (!space) {
|
||||
} else if (buf_block_t* bitmap = ibuf_bitmap_get_map_page(
|
||||
page_id, zip_size, &mtr)) {
|
||||
/* FIXME: update the bitmap byte only once! */
|
||||
|
|
|
@ -910,19 +910,6 @@ inline ulint dict_tf_get_zip_size(ulint flags)
|
|||
: 0;
|
||||
}
|
||||
|
||||
/** Determine the extent size (in pages) for the given table
|
||||
@param[in] table the table whose extent size is being
|
||||
calculated.
|
||||
@return extent size in pages (256, 128 or 64) */
|
||||
inline ulint dict_table_extent_size(const dict_table_t* table)
|
||||
{
|
||||
if (ulint zip_size = table->space->zip_size()) {
|
||||
return (1U << 20) / zip_size;
|
||||
}
|
||||
|
||||
return FSP_EXTENT_SIZE;
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Checks if a column is in the ordering columns of the clustered index of a
|
||||
table. Column prefixes are treated like whole columns.
|
||||
|
|
|
@ -330,6 +330,24 @@ public:
|
|||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
Iterate over each block and call the functor.
|
||||
@return false if iteration was terminated. */
|
||||
template <typename Functor>
|
||||
bool for_each_block(const Functor& functor) const
|
||||
{
|
||||
for (typename list_t::iterator it = m_list.begin(),
|
||||
end = m_list.end();
|
||||
it != end; ++it) {
|
||||
|
||||
if (!functor(&*it)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
Iterate over all the blocks in reverse and call the iterator
|
||||
@return false if iteration was terminated. */
|
||||
|
|
|
@ -329,19 +329,11 @@ insert buffer. If the page is not read, but created in the buffer pool, this
|
|||
function deletes its buffered entries from the insert buffer; there can
|
||||
exist entries for such a page if the page belonged to an index which
|
||||
subsequently was dropped.
|
||||
@param[in,out] block if page has been read from disk,
|
||||
pointer to the page x-latched, else NULL
|
||||
@param[in] page_id page id of the index page
|
||||
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
|
||||
@param[in] update_ibuf_bitmap normally this is set, but
|
||||
if we have deleted or are deleting the tablespace, then we naturally do not
|
||||
want to update a non-existent bitmap page */
|
||||
void
|
||||
ibuf_merge_or_delete_for_page(
|
||||
buf_block_t* block,
|
||||
const page_id_t page_id,
|
||||
ulint zip_size,
|
||||
bool update_ibuf_bitmap);
|
||||
@param block X-latched page to try to apply changes to, or NULL to discard
|
||||
@param page_id page identifier
|
||||
@param zip_size ROW_FORMAT=COMPRESSED page size, or 0 */
|
||||
void ibuf_merge_or_delete_for_page(buf_block_t *block, const page_id_t page_id,
|
||||
ulint zip_size);
|
||||
|
||||
/** Delete all change buffer entries for a tablespace,
|
||||
in DISCARD TABLESPACE, IMPORT TABLESPACE, or crash recovery.
|
||||
|
|
|
@ -151,6 +151,10 @@ struct mtr_t {
|
|||
return old_mode;
|
||||
}
|
||||
|
||||
/** Check if we are holding a block latch in exclusive mode
|
||||
@param block buffer pool block to search for */
|
||||
bool have_x_latch(const buf_block_t &block) const;
|
||||
|
||||
/** Copy the tablespaces associated with the mini-transaction
|
||||
(needed for generating FILE_MODIFY records)
|
||||
@param[in] mtr mini-transaction that may modify
|
||||
|
|
|
@ -506,7 +506,7 @@ the pass value == 0. */
|
|||
bool
|
||||
rw_lock_own(
|
||||
/*========*/
|
||||
rw_lock_t* lock, /*!< in: rw-lock */
|
||||
const rw_lock_t*lock, /*!< in: rw-lock */
|
||||
ulint lock_type) /*!< in: lock type: RW_LOCK_S,
|
||||
RW_LOCK_X */
|
||||
MY_ATTRIBUTE((warn_unused_result));
|
||||
|
|
|
@ -985,20 +985,6 @@ public:
|
|||
/*------------------------------*/
|
||||
char* detailed_error; /*!< detailed error message for last
|
||||
error, or empty. */
|
||||
/* Lock wait statistics */
|
||||
ulint n_rec_lock_waits;
|
||||
/*!< Number of record lock waits,
|
||||
might not be exactly correct. */
|
||||
ulint n_table_lock_waits;
|
||||
/*!< Number of table lock waits,
|
||||
might not be exactly correct. */
|
||||
ulint total_rec_lock_wait_time;
|
||||
/*!< Total rec lock wait time up
|
||||
to this moment. */
|
||||
ulint total_table_lock_wait_time;
|
||||
/*!< Total table lock wait time
|
||||
up to this moment. */
|
||||
|
||||
rw_trx_hash_element_t *rw_trx_hash_element;
|
||||
LF_PINS *rw_trx_hash_pins;
|
||||
ulint magic_n;
|
||||
|
|
|
@ -893,29 +893,48 @@ inline std::pair<lsn_t,bool> mtr_t::finish_write(ulint len)
|
|||
return std::make_pair(start_lsn, flush);
|
||||
}
|
||||
|
||||
/** Find buffer fix count of the given block acquired by the
|
||||
mini-transaction */
|
||||
struct FindBlock
|
||||
/** Find out whether a block was X-latched by the mini-transaction */
|
||||
struct FindBlockX
|
||||
{
|
||||
int32_t num_fix;
|
||||
const buf_block_t *const block;
|
||||
const buf_block_t █
|
||||
|
||||
FindBlock(const buf_block_t *block_buf): num_fix(0), block(block_buf) {}
|
||||
FindBlockX(const buf_block_t &block): block(block) {}
|
||||
|
||||
bool operator()(const mtr_memo_slot_t* slot)
|
||||
/** @return whether the block was not found x-latched */
|
||||
bool operator()(const mtr_memo_slot_t *slot) const
|
||||
{
|
||||
if (slot->object == block)
|
||||
num_fix++;
|
||||
return true;
|
||||
return slot->object != &block || slot->type == MTR_MEMO_PAGE_X_FIX;
|
||||
}
|
||||
};
|
||||
|
||||
uint32_t mtr_t::get_fix_count(const buf_block_t *block) const
|
||||
#ifdef UNIV_DEBUG
|
||||
/** Assert that the block is not present in the mini-transaction */
|
||||
struct FindNoBlock
|
||||
{
|
||||
Iterate<FindBlock> iteration((FindBlock(block)));
|
||||
if (m_memo.for_each_block(iteration))
|
||||
return iteration.functor.num_fix;
|
||||
return 0;
|
||||
const buf_block_t █
|
||||
|
||||
FindNoBlock(const buf_block_t &block): block(block) {}
|
||||
|
||||
/** @return whether the block was not found */
|
||||
bool operator()(const mtr_memo_slot_t *slot) const
|
||||
{
|
||||
return slot->object != █
|
||||
}
|
||||
};
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
bool mtr_t::have_x_latch(const buf_block_t &block) const
|
||||
{
|
||||
if (m_memo.for_each_block(CIterate<FindBlockX>(FindBlockX(block))))
|
||||
{
|
||||
ut_ad(m_memo.for_each_block(CIterate<FindNoBlock>(FindNoBlock(block))));
|
||||
ut_ad(!memo_contains_flagged(&block,
|
||||
MTR_MEMO_PAGE_S_FIX | MTR_MEMO_PAGE_SX_FIX |
|
||||
MTR_MEMO_BUF_FIX | MTR_MEMO_MODIFY));
|
||||
return false;
|
||||
}
|
||||
ut_ad(rw_lock_own(&block.lock, RW_LOCK_X));
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
|
@ -931,13 +950,13 @@ bool mtr_t::memo_contains(const rw_lock_t &lock, mtr_memo_type_t type)
|
|||
|
||||
switch (type) {
|
||||
case MTR_MEMO_X_LOCK:
|
||||
ut_ad(rw_lock_own(const_cast<rw_lock_t*>(&lock), RW_LOCK_X));
|
||||
ut_ad(rw_lock_own(&lock, RW_LOCK_X));
|
||||
break;
|
||||
case MTR_MEMO_SX_LOCK:
|
||||
ut_ad(rw_lock_own(const_cast<rw_lock_t*>(&lock), RW_LOCK_SX));
|
||||
ut_ad(rw_lock_own(&lock, RW_LOCK_SX));
|
||||
break;
|
||||
case MTR_MEMO_S_LOCK:
|
||||
ut_ad(rw_lock_own(const_cast<rw_lock_t*>(&lock), RW_LOCK_S));
|
||||
ut_ad(rw_lock_own(&lock, RW_LOCK_S));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -4262,72 +4262,152 @@ os_file_set_umask(ulint umask)
|
|||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static int win32_get_block_size(HANDLE volume_handle, const char *volume_name)
|
||||
|
||||
/* Checks whether physical drive is on SSD.*/
|
||||
static bool is_drive_on_ssd(DWORD nr)
|
||||
{
|
||||
STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR disk_alignment;
|
||||
STORAGE_PROPERTY_QUERY storage_query;
|
||||
DWORD tmp;
|
||||
char physical_drive_path[32];
|
||||
snprintf(physical_drive_path, sizeof(physical_drive_path),
|
||||
"\\\\.\\PhysicalDrive%lu", nr);
|
||||
|
||||
memset(&storage_query, 0, sizeof(storage_query));
|
||||
storage_query.PropertyId = StorageAccessAlignmentProperty;
|
||||
storage_query.QueryType = PropertyStandardQuery;
|
||||
HANDLE h= CreateFile(physical_drive_path, 0,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
if (os_win32_device_io_control(volume_handle,
|
||||
IOCTL_STORAGE_QUERY_PROPERTY,
|
||||
&storage_query,
|
||||
sizeof storage_query,
|
||||
&disk_alignment,
|
||||
sizeof disk_alignment,
|
||||
&tmp) && tmp == sizeof disk_alignment) {
|
||||
return disk_alignment.BytesPerPhysicalSector;
|
||||
}
|
||||
|
||||
switch (GetLastError()) {
|
||||
case ERROR_INVALID_FUNCTION:
|
||||
case ERROR_NOT_SUPPORTED:
|
||||
break;
|
||||
default:
|
||||
os_file_handle_error_no_exit(
|
||||
volume_name,
|
||||
"DeviceIoControl(IOCTL_STORAGE_QUERY_PROPERTY / StorageAccessAlignmentProperty)",
|
||||
FALSE);
|
||||
}
|
||||
return 512;
|
||||
}
|
||||
|
||||
static bool win32_is_ssd(HANDLE volume_handle)
|
||||
{
|
||||
DWORD tmp;
|
||||
DEVICE_SEEK_PENALTY_DESCRIPTOR seek_penalty;
|
||||
STORAGE_PROPERTY_QUERY storage_query;
|
||||
memset(&storage_query, 0, sizeof(storage_query));
|
||||
STORAGE_PROPERTY_QUERY storage_query{};
|
||||
storage_query.PropertyId= StorageDeviceSeekPenaltyProperty;
|
||||
storage_query.QueryType= PropertyStandardQuery;
|
||||
|
||||
storage_query.PropertyId = StorageDeviceSeekPenaltyProperty;
|
||||
storage_query.QueryType = PropertyStandardQuery;
|
||||
|
||||
if (os_win32_device_io_control(volume_handle,
|
||||
IOCTL_STORAGE_QUERY_PROPERTY,
|
||||
&storage_query,
|
||||
sizeof storage_query,
|
||||
&seek_penalty,
|
||||
sizeof seek_penalty,
|
||||
&tmp) && tmp == sizeof(seek_penalty)){
|
||||
return !seek_penalty.IncursSeekPenalty;
|
||||
bool on_ssd= false;
|
||||
DWORD bytes_written;
|
||||
if (DeviceIoControl(h, IOCTL_STORAGE_QUERY_PROPERTY, &storage_query,
|
||||
sizeof storage_query, &seek_penalty, sizeof seek_penalty,
|
||||
&bytes_written, nullptr))
|
||||
{
|
||||
on_ssd= seek_penalty.IncursSeekPenalty;
|
||||
}
|
||||
|
||||
DEVICE_TRIM_DESCRIPTOR trim;
|
||||
storage_query.PropertyId = StorageDeviceTrimProperty;
|
||||
if (os_win32_device_io_control(volume_handle,
|
||||
IOCTL_STORAGE_QUERY_PROPERTY,
|
||||
&storage_query,
|
||||
sizeof storage_query,
|
||||
&trim,
|
||||
sizeof trim,
|
||||
&tmp) && tmp == sizeof trim) {
|
||||
return trim.TrimEnabled;
|
||||
else
|
||||
{
|
||||
on_ssd= false;
|
||||
}
|
||||
return false;
|
||||
CloseHandle(h);
|
||||
return on_ssd;
|
||||
}
|
||||
|
||||
/*
|
||||
Checks whether volume is on SSD, by checking all physical drives
|
||||
in that volume.
|
||||
*/
|
||||
static bool is_volume_on_ssd(const char *volume_mount_point)
|
||||
{
|
||||
char volume_name[MAX_PATH];
|
||||
|
||||
if (!GetVolumeNameForVolumeMountPoint(volume_mount_point, volume_name,
|
||||
array_elements(volume_name)))
|
||||
{
|
||||
/* This can fail, e.g if file is on network share */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Chomp last backslash, this is needed to open volume.*/
|
||||
size_t length= strlen(volume_name);
|
||||
if (length && volume_name[length - 1] == '\\')
|
||||
volume_name[length - 1]= 0;
|
||||
|
||||
/* Open volume handle */
|
||||
HANDLE volume_handle= CreateFile(
|
||||
volume_name, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||
|
||||
if (volume_handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
/*
|
||||
Enumerate all volume extends, check whether all of them are on SSD
|
||||
*/
|
||||
|
||||
/* Anticipate common case where there is only one extent.*/
|
||||
VOLUME_DISK_EXTENTS single_extent;
|
||||
|
||||
/* But also have a place to manage allocated data.*/
|
||||
std::unique_ptr<BYTE[]> lifetime;
|
||||
|
||||
DWORD bytes_written;
|
||||
VOLUME_DISK_EXTENTS *extents= nullptr;
|
||||
if (DeviceIoControl(volume_handle, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
|
||||
nullptr, 0, &single_extent, sizeof(single_extent),
|
||||
&bytes_written, nullptr))
|
||||
{
|
||||
/* Worked on the first try. Use the preallocated buffer.*/
|
||||
extents= &single_extent;
|
||||
}
|
||||
else
|
||||
{
|
||||
VOLUME_DISK_EXTENTS *last_query= &single_extent;
|
||||
while (GetLastError() == ERROR_MORE_DATA)
|
||||
{
|
||||
DWORD extentCount= last_query->NumberOfDiskExtents;
|
||||
DWORD allocatedSize=
|
||||
FIELD_OFFSET(VOLUME_DISK_EXTENTS, Extents[extentCount]);
|
||||
lifetime.reset(new BYTE[allocatedSize]);
|
||||
last_query= (VOLUME_DISK_EXTENTS *) lifetime.get();
|
||||
if (DeviceIoControl(volume_handle, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
|
||||
nullptr, 0, last_query, allocatedSize,
|
||||
&bytes_written, nullptr))
|
||||
{
|
||||
extents= last_query;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
CloseHandle(volume_handle);
|
||||
if (!extents)
|
||||
return false;
|
||||
|
||||
for (DWORD i= 0; i < extents->NumberOfDiskExtents; i++)
|
||||
if (!is_drive_on_ssd(extents->Extents[i].DiskNumber))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#include <unordered_map>
|
||||
static bool is_file_on_ssd(char *file_path)
|
||||
{
|
||||
/* Cache of volume_path => volume_info, protected by rwlock.*/
|
||||
static std::unordered_map<std::string, bool> cache;
|
||||
static SRWLOCK lock= SRWLOCK_INIT;
|
||||
|
||||
/* Preset result, in case something fails, e.g we're on network drive.*/
|
||||
char volume_path[MAX_PATH];
|
||||
if (!GetVolumePathName(file_path, volume_path, array_elements(volume_path)))
|
||||
return false;
|
||||
|
||||
/* Try cached volume info first.*/
|
||||
std::string volume_path_str(volume_path);
|
||||
bool found;
|
||||
bool result;
|
||||
AcquireSRWLockShared(&lock);
|
||||
auto e= cache.find(volume_path_str);
|
||||
if ((found= e != cache.end()))
|
||||
result= e->second;
|
||||
ReleaseSRWLockShared(&lock);
|
||||
|
||||
if (found)
|
||||
return result;
|
||||
|
||||
result= is_volume_on_ssd(volume_path);
|
||||
|
||||
/* Update cache */
|
||||
AcquireSRWLockExclusive(&lock);
|
||||
cache[volume_path_str]= result;
|
||||
ReleaseSRWLockExclusive(&lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/** Determine some file metadata when creating or reading the file.
|
||||
|
@ -4364,48 +4444,12 @@ void fil_node_t::find_metadata(os_file_t file
|
|||
space->atomic_write_supported = space->purpose == FIL_TYPE_TEMPORARY
|
||||
|| space->purpose == FIL_TYPE_IMPORT;
|
||||
#ifdef _WIN32
|
||||
block_size = 512;
|
||||
on_ssd = false;
|
||||
// Open volume for this file, find out it "physical bytes per sector"
|
||||
char volume[MAX_PATH + 4];
|
||||
if (!GetVolumePathName(name, volume + 4, MAX_PATH)) {
|
||||
os_file_handle_error_no_exit(name,
|
||||
"GetVolumePathName()", FALSE);
|
||||
return;
|
||||
}
|
||||
// Special prefix required for volume names.
|
||||
memcpy(volume, "\\\\.\\", 4);
|
||||
|
||||
size_t len = strlen(volume);
|
||||
if (volume[len - 1] == '\\') {
|
||||
// Trim trailing backslash from volume name.
|
||||
volume[len - 1] = 0;
|
||||
}
|
||||
|
||||
HANDLE volume_handle = CreateFile(volume, FILE_READ_ATTRIBUTES,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
0, OPEN_EXISTING, 0, 0);
|
||||
|
||||
if (volume_handle != INVALID_HANDLE_VALUE) {
|
||||
block_size = win32_get_block_size(volume_handle, volume);
|
||||
on_ssd = win32_is_ssd(volume_handle);
|
||||
CloseHandle(volume_handle);
|
||||
on_ssd = is_file_on_ssd(name);
|
||||
FILE_STORAGE_INFO info;
|
||||
if (GetFileInformationByHandleEx(
|
||||
file, FileStorageInfo, &info, sizeof(info))) {
|
||||
block_size = info.PhysicalBytesPerSectorForAtomicity;
|
||||
} else {
|
||||
/*
|
||||
Report error, unless it is expected, e.g
|
||||
missing permissions, or error when trying to
|
||||
open volume for UNC share.
|
||||
*/
|
||||
if (GetLastError() != ERROR_ACCESS_DENIED
|
||||
&& GetDriveType(volume) == DRIVE_FIXED) {
|
||||
os_file_handle_error_no_exit(volume, "CreateFile()", FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Currently we support file block size up to 4KiB */
|
||||
if (block_size > 4096) {
|
||||
block_size = 4096;
|
||||
} else if (block_size < 512) {
|
||||
block_size = 512;
|
||||
}
|
||||
#else
|
||||
|
|
|
@ -990,7 +990,7 @@ the pass value == 0.
|
|||
bool
|
||||
rw_lock_own(
|
||||
/*========*/
|
||||
rw_lock_t* lock, /*!< in: rw-lock */
|
||||
const rw_lock_t*lock, /*!< in: rw-lock */
|
||||
ulint lock_type) /*!< in: lock type: RW_LOCK_S,
|
||||
RW_LOCK_X */
|
||||
{
|
||||
|
|
|
@ -59,12 +59,12 @@ const dtuple_t trx_undo_metadata = {
|
|||
static ulint trx_undo_left(const buf_block_t *undo_block, const byte *ptr)
|
||||
{
|
||||
ut_ad(ptr >= &undo_block->frame[TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE]);
|
||||
ut_ad(ptr <= &undo_block->frame[srv_page_size - 10 - FIL_PAGE_DATA_END]);
|
||||
|
||||
/* The 10 is supposed to be an extra safety margin (and needed for
|
||||
compatibility with older versions) */
|
||||
return srv_page_size - ulint(ptr - undo_block->frame) -
|
||||
lint left= srv_page_size - (ptr - undo_block->frame) -
|
||||
(10 + FIL_PAGE_DATA_END);
|
||||
ut_ad(left >= 0);
|
||||
return left < 0 ? 0 : static_cast<ulint>(left);
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
|
|
|
@ -460,10 +460,6 @@ void trx_t::free()
|
|||
MEM_NOACCESS(&xid, sizeof xid);
|
||||
MEM_NOACCESS(&mod_tables, sizeof mod_tables);
|
||||
MEM_NOACCESS(&detailed_error, sizeof detailed_error);
|
||||
MEM_NOACCESS(&n_rec_lock_waits, sizeof n_rec_lock_waits);
|
||||
MEM_NOACCESS(&n_table_lock_waits, sizeof n_table_lock_waits);
|
||||
MEM_NOACCESS(&total_rec_lock_wait_time, sizeof total_rec_lock_wait_time);
|
||||
MEM_NOACCESS(&total_table_lock_wait_time, sizeof total_table_lock_wait_time);
|
||||
MEM_NOACCESS(&magic_n, sizeof magic_n);
|
||||
trx_pools->mem_free(this);
|
||||
}
|
||||
|
|
|
@ -2360,6 +2360,14 @@ static int initialize_variables_for_repair(HA_CHECK *param,
|
|||
{
|
||||
MARIA_SHARE *share= info->s;
|
||||
|
||||
/*
|
||||
We have to clear these variables first, as the cleanup-in-case-of-error
|
||||
handling may touch these.
|
||||
*/
|
||||
bzero((char*) sort_info, sizeof(*sort_info));
|
||||
bzero((char*) sort_param, sizeof(*sort_param));
|
||||
bzero(&info->rec_cache, sizeof(info->rec_cache));
|
||||
|
||||
if (share->data_file_type == NO_RECORD)
|
||||
{
|
||||
_ma_check_print_error(param,
|
||||
|
@ -2374,9 +2382,6 @@ static int initialize_variables_for_repair(HA_CHECK *param,
|
|||
if (share->lock.update_status)
|
||||
(*share->lock.update_status)(info->lock.status_param);
|
||||
|
||||
bzero((char*) sort_info, sizeof(*sort_info));
|
||||
bzero((char*) sort_param, sizeof(*sort_param));
|
||||
|
||||
param->testflag|= T_REP; /* for easy checking */
|
||||
if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
|
||||
param->testflag|= T_CALC_CHECKSUM;
|
||||
|
@ -2404,7 +2409,6 @@ static int initialize_variables_for_repair(HA_CHECK *param,
|
|||
set_data_file_type(sort_info, info->s);
|
||||
sort_info->org_data_file_type= share->data_file_type;
|
||||
|
||||
bzero(&info->rec_cache, sizeof(info->rec_cache));
|
||||
info->rec_cache.file= info->dfile.file;
|
||||
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
|
||||
|
||||
|
@ -2891,9 +2895,13 @@ err:
|
|||
_ma_reset_state(info);
|
||||
|
||||
end_io_cache(¶m->read_cache);
|
||||
end_io_cache(&sort_info.new_info->rec_cache);
|
||||
if (sort_info.new_info)
|
||||
{
|
||||
end_io_cache(&sort_info.new_info->rec_cache);
|
||||
sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
|
||||
}
|
||||
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
|
||||
sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
|
||||
|
||||
sort_param.sort_info->info->in_check_table= 0;
|
||||
/* this below could fail, shouldn't we detect error? */
|
||||
if (got_error)
|
||||
|
@ -4110,10 +4118,13 @@ err:
|
|||
maria_scan_end(sort_info.info);
|
||||
_ma_reset_state(info);
|
||||
|
||||
end_io_cache(&sort_info.new_info->rec_cache);
|
||||
if (sort_info.new_info)
|
||||
{
|
||||
end_io_cache(&sort_info.new_info->rec_cache);
|
||||
sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
|
||||
}
|
||||
end_io_cache(¶m->read_cache);
|
||||
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
|
||||
sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
|
||||
if (got_error)
|
||||
{
|
||||
if (! param->error_printed)
|
||||
|
@ -4642,10 +4653,13 @@ err:
|
|||
the share by remove_io_thread() or it was not yet started (if the
|
||||
error happend before creating the thread).
|
||||
*/
|
||||
end_io_cache(&sort_info.new_info->rec_cache);
|
||||
if (sort_info.new_info)
|
||||
{
|
||||
end_io_cache(&sort_info.new_info->rec_cache);
|
||||
sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
|
||||
}
|
||||
end_io_cache(¶m->read_cache);
|
||||
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
|
||||
sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
|
||||
/*
|
||||
Destroy the new data cache in case of non-quick repair. All slave
|
||||
threads did either detach from the share by remove_io_thread()
|
||||
|
|
|
@ -30,6 +30,7 @@ int maria_delete_table(const char *name)
|
|||
{
|
||||
MARIA_HA *info;
|
||||
myf sync_dir;
|
||||
int got_error= 0, error;
|
||||
DBUG_ENTER("maria_delete_table");
|
||||
|
||||
#ifdef EXTRA_DEBUG
|
||||
|
@ -41,9 +42,13 @@ int maria_delete_table(const char *name)
|
|||
Unfortunately it is necessary to open the table just to check this. We use
|
||||
'open_for_repair' to be able to open even a crashed table.
|
||||
*/
|
||||
my_errno= 0;
|
||||
if (!(info= maria_open(name, O_RDONLY, HA_OPEN_FOR_REPAIR, 0)))
|
||||
{
|
||||
sync_dir= 0;
|
||||
/* Ignore not found errors and wrong symlink errors */
|
||||
if (my_errno != ENOENT && my_errno != HA_WRONG_CREATE_OPTION)
|
||||
got_error= my_errno;;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -78,7 +83,9 @@ int maria_delete_table(const char *name)
|
|||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
DBUG_RETURN(maria_delete_table_files(name, 0, sync_dir | MY_WME));
|
||||
if (!(error= maria_delete_table_files(name, 0, sync_dir | MY_WME)))
|
||||
error= got_error;
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1476,7 +1476,7 @@ static void setup_key_functions(register MARIA_KEYDEF *keyinfo)
|
|||
|
||||
|
||||
/**
|
||||
@brief Function to save and store the header in the index file (.MYI)
|
||||
@brief Function to save and store the header in the index file (.MAI)
|
||||
|
||||
Operates under MARIA_SHARE::intern_lock if requested.
|
||||
Sets MARIA_SHARE::MARIA_STATE_INFO::is_of_horizon if transactional table.
|
||||
|
|
|
@ -96,7 +96,7 @@ void sql_print_error(const char *format, ...)
|
|||
|
||||
/*** end of encryption tweaks and stubs ****************************/
|
||||
|
||||
IO_CACHE info;
|
||||
static IO_CACHE info;
|
||||
#define CACHE_SIZE 16384
|
||||
|
||||
#define INFO_TAIL ", pos_in_file = %llu, pos_in_mem = %lu", \
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 2da6e4894e1df5d1db51db2bbc49255e02251b9d
|
||||
Subproject commit 41a6e9dad79c921134e44cf974b6b7ca3b84e538
|
Loading…
Reference in a new issue