Commit cc2651b7 authored by Marko Mäkelä's avatar Marko Mäkelä

Merge 10.4 into 10.5

parents 81402c13 4240704a
...@@ -775,7 +775,7 @@ call p_verify_status_increment(2, 0, 2, 0); ...@@ -775,7 +775,7 @@ call p_verify_status_increment(2, 0, 2, 0);
commit; commit;
call p_verify_status_increment(0, 0, 0, 0); call p_verify_status_increment(0, 0, 0, 0);
check table t1, t2, t3; check table t1, t2, t3;
call p_verify_status_increment(6, 0, 6, 0); call p_verify_status_increment(4, 0, 4, 0);
commit; commit;
call p_verify_status_increment(0, 0, 0, 0); call p_verify_status_increment(0, 0, 0, 0);
drop view v1; drop view v1;
......
...@@ -139,7 +139,7 @@ sub do_args($$$$$) { ...@@ -139,7 +139,7 @@ sub do_args($$$$$) {
my $v = $debuggers{$k}; my $v = $debuggers{$k};
# on windows mtr args are quoted (for system), otherwise not (for exec) # on windows mtr args are quoted (for system), otherwise not (for exec)
sub quote($) { $_[0] =~ / / ? "\"$_[0]\"" : $_[0] } sub quote($) { $_[0] =~ /[; ]/ ? "\"$_[0]\"" : $_[0] }
sub unquote($) { $_[0] =~ s/^"(.*)"$/$1/; $_[0] } sub unquote($) { $_[0] =~ s/^"(.*)"$/$1/; $_[0] }
sub quote_from_mtr($) { IS_WINDOWS() ? $_[0] : quote($_[0]) } sub quote_from_mtr($) { IS_WINDOWS() ? $_[0] : quote($_[0]) }
sub unquote_for_mtr($) { IS_WINDOWS() ? $_[0] : unquote($_[0]) } sub unquote_for_mtr($) { IS_WINDOWS() ? $_[0] : unquote($_[0]) }
......
...@@ -879,7 +879,7 @@ Table Op Msg_type Msg_text ...@@ -879,7 +879,7 @@ Table Op Msg_type Msg_text
test.t1 check status OK test.t1 check status OK
test.t2 check status OK test.t2 check status OK
test.t3 check status OK test.t3 check status OK
call p_verify_status_increment(6, 0, 6, 0); call p_verify_status_increment(4, 0, 4, 0);
SUCCESS SUCCESS
commit; commit;
......
#
# Kill OPTIMIZE command prior to table modification
#
RESET MASTER;
CREATE TABLE t1 (f INT) ENGINE=INNODB;
CREATE TABLE t2 (f INT) ENGINE=INNODB;
connect con1,127.0.0.1,root,,test,$MASTER_MYPORT,;
connection con1;
SET debug_sync='admin_command_kill_before_modify SIGNAL ready_to_be_killed WAIT_FOR master_cont';
OPTIMIZE TABLE t1,t2;
connection default;
SET debug_sync='now WAIT_FOR ready_to_be_killed';
KILL THD_ID;
SET debug_sync = 'reset';
disconnect con1;
include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (f INT) ENGINE=INNODB
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (f INT) ENGINE=INNODB
DROP TABLE t1,t2;
FLUSH LOGS;
#
# Kill OPTIMIZE command after table modification
#
CREATE TABLE t1 (f INT) ENGINE=INNODB;
CREATE TABLE t2 (f INT) ENGINE=INNODB;
connect con1,127.0.0.1,root,,test,$MASTER_MYPORT,;
connection con1;
SET debug_sync='admin_command_kill_after_modify SIGNAL ready_to_be_killed WAIT_FOR master_cont';
OPTIMIZE TABLE t1,t2;
connection default;
SET debug_sync='now WAIT_FOR ready_to_be_killed';
KILL THD_ID;
SET debug_sync = 'reset';
disconnect con1;
DROP TABLE t1,t2;
FLUSH LOGS;
FOUND 1 /OPTIMIZE TABLE t1,t2/ in mysqlbinlog.out
# ==== Purpose ====
#
# Test verifies that when an admin command execution is interrupted by KILL
# command it should stop its execution. The admin command in binary log should
# contain only the list of tables which have successfully executed admin
# command prior to kill.
#
# ==== Implementation ====
#
# Steps:
# 0 - Create two table t1,t2.
# 1 - Execute OPTIMIZE TABLE t1,t2 command.
# 2 - Using debug sync mechanism kill OPTIMIZE TABLE command at a stage
# where it has not optimized any table.
# 3 - Check that OPTIMIZE TABLE command is not written to binary log.
# 4 - Using debug sync mechanism hold the execution of OPTIMIZE TABLE after
# t1 table optimization. Now kill the OPTIMIZE TABLE command.
# 5 - Observe the binlog output, the OPTIMIZE TABLE command should display `t1,t2`.
# 6 - Please note that, we binlog the entire query even if at least one
# table is modified as admin commands are safe to replicate and they will
# not make the slave to diverge.
#
# ==== References ====
#
# MDEV-22530: Aborting OPTIMIZE TABLE still logs in binary log and replicates to the Slave server.
#
--source include/have_log_bin.inc
--source include/have_debug.inc
--source include/have_debug_sync.inc
--source include/have_innodb.inc
--echo #
--echo # Kill OPTIMIZE command prior to table modification
--echo #
RESET MASTER;
CREATE TABLE t1 (f INT) ENGINE=INNODB;
CREATE TABLE t2 (f INT) ENGINE=INNODB;
--connect(con1,127.0.0.1,root,,test,$MASTER_MYPORT,)
--connection con1
SET debug_sync='admin_command_kill_before_modify SIGNAL ready_to_be_killed WAIT_FOR master_cont';
--send OPTIMIZE TABLE t1,t2
--connection default
SET debug_sync='now WAIT_FOR ready_to_be_killed';
--let $thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%OPTIMIZE TABLE %'`
# Now kill.
--replace_result $thd_id THD_ID
eval KILL $thd_id;
SET debug_sync = 'reset';
--disconnect con1
--source include/show_binlog_events.inc
DROP TABLE t1,t2;
FLUSH LOGS;
--echo #
--echo # Kill OPTIMIZE command after table modification
--echo #
CREATE TABLE t1 (f INT) ENGINE=INNODB;
CREATE TABLE t2 (f INT) ENGINE=INNODB;
--connect(con1,127.0.0.1,root,,test,$MASTER_MYPORT,)
--connection con1
SET debug_sync='admin_command_kill_after_modify SIGNAL ready_to_be_killed WAIT_FOR master_cont';
--send OPTIMIZE TABLE t1,t2
--connection default
SET debug_sync='now WAIT_FOR ready_to_be_killed';
--let $thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%OPTIMIZE TABLE %'`
# Now kill.
--replace_result $thd_id THD_ID
eval KILL $thd_id;
SET debug_sync = 'reset';
--disconnect con1
DROP TABLE t1,t2;
let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
FLUSH LOGS;
--let $MYSQLD_DATADIR= `select @@datadir`
--exec $MYSQL_BINLOG $MYSQLD_DATADIR/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
--let SEARCH_PATTERN= OPTIMIZE TABLE t1,t2
--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
--source include/search_pattern_in_file.inc
--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
...@@ -15,7 +15,6 @@ galera_gtid_2_cluster : MDEV-23775 Galera test failure on galera_3nodes.galera_g ...@@ -15,7 +15,6 @@ galera_gtid_2_cluster : MDEV-23775 Galera test failure on galera_3nodes.galera_g
galera_ist_gcache_rollover : MDEV-23578 WSREP: exception caused by message: {v=0,t=1,ut=255,o=4,s=0,sr=0,as=1,f=6,src=50524cfe,srcvid=view_id(REG,50524cfe,4),insvid=view_id(UNKNOWN,00000000,0),ru=00000000,r=[-1,-1],fs=75,nl=(} galera_ist_gcache_rollover : MDEV-23578 WSREP: exception caused by message: {v=0,t=1,ut=255,o=4,s=0,sr=0,as=1,f=6,src=50524cfe,srcvid=view_id(REG,50524cfe,4),insvid=view_id(UNKNOWN,00000000,0),ru=00000000,r=[-1,-1],fs=75,nl=(}
galera_load_data_ist : MDEV-24639 galera_3nodes.galera_load_data_ist MTR failed with SIGABRT: query 'reap' failed: 2013: Lost connection to MySQL server during query galera_load_data_ist : MDEV-24639 galera_3nodes.galera_load_data_ist MTR failed with SIGABRT: query 'reap' failed: 2013: Lost connection to MySQL server during query
galera_load_data_ist : MDEV-24639 galera_3nodes.galera_load_data_ist MTR failed with SIGABRT: query 'reap' failed: 2013: Lost connection to MySQL server during query galera_load_data_ist : MDEV-24639 galera_3nodes.galera_load_data_ist MTR failed with SIGABRT: query 'reap' failed: 2013: Lost connection to MySQL server during query
galera_pc_bootstrap : MDEV-24650 galera_pc_bootstrap MTR failed: Could not execute 'check-testcase' before testcase
galera_safe_to_bootstrap : MDEV-24097 galera_3nodes.galera_safe_to_bootstrap MTR sporadaically fails: Failed to start mysqld or mysql_shutdown failed galera_safe_to_bootstrap : MDEV-24097 galera_3nodes.galera_safe_to_bootstrap MTR sporadaically fails: Failed to start mysqld or mysql_shutdown failed
galera_slave_options_do : MDEV-8798 galera_slave_options_do : MDEV-8798
galera_slave_options_ignore : MDEV-8798 galera_slave_options_ignore : MDEV-8798
......
include/rpl_init.inc [topology=1->2]
connection server_1;
FLUSH TABLES;
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
connection server_2;
SET @save_slave_parallel_threads= @@GLOBAL.slave_parallel_threads;
SET @save_slave_parallel_mode= @@GLOBAL.slave_parallel_mode;
include/stop_slave.inc
SET GLOBAL slave_parallel_threads=2;
SET GLOBAL slave_parallel_mode=optimistic;
include/start_slave.inc
connection server_1;
CREATE TABLE t1(a INT) ENGINE=INNODB;
OPTIMIZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
test.t1 optimize status OK
INSERT INTO t1 VALUES(1);
INSERT INTO t1 SELECT 1+a FROM t1;
INSERT INTO t1 SELECT 2+a FROM t1;
connection server_2;
#
# Verify that following admin commands are marked as ddl
# 'OPTIMIZE TABLE', 'REPAIR TABLE' and 'ANALYZE TABLE'
#
connection server_1;
OPTIMIZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
test.t1 optimize status OK
REPAIR TABLE t1;
Table Op Msg_type Msg_text
test.t1 repair note The storage engine for the table doesn't support repair
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
FLUSH LOGS;
FOUND 1 /GTID 0-1-8 ddl/ in mysqlbinlog.out
FOUND 1 /GTID 0-1-9 ddl/ in mysqlbinlog.out
FOUND 1 /GTID 0-1-10 ddl/ in mysqlbinlog.out
#
# Clean up
#
DROP TABLE t1;
connection server_2;
FLUSH LOGS;
#
# Check that ALTER TABLE commands with ANALYZE, OPTIMIZE and REPAIR on
# partitions will be marked as DDL in binary log.
#
connection server_1;
CREATE TABLE t1(id INT) PARTITION BY RANGE (id) (PARTITION p0 VALUES LESS THAN (100),
PARTITION pmax VALUES LESS THAN (MAXVALUE));
INSERT INTO t1 VALUES (1), (10), (100), (1000);
ALTER TABLE t1 ANALYZE PARTITION p0;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
ALTER TABLE t1 OPTIMIZE PARTITION p0;
Table Op Msg_type Msg_text
test.t1 optimize status OK
ALTER TABLE t1 REPAIR PARTITION p0;
Table Op Msg_type Msg_text
test.t1 repair status OK
FLUSH LOGS;
FOUND 1 /GTID 0-1-14 ddl/ in mysqlbinlog.out
FOUND 1 /GTID 0-1-15 ddl/ in mysqlbinlog.out
FOUND 1 /GTID 0-1-16 ddl/ in mysqlbinlog.out
#
# Clean up
#
DROP TABLE t1;
connection server_2;
include/stop_slave.inc
SET GLOBAL slave_parallel_threads= @save_slave_parallel_threads;
SET GLOBAL slave_parallel_mode= @save_slave_parallel_mode;
include/start_slave.inc
include/rpl_end.inc
# ==== Purpose ====
#
# Test verifies that there is no deadlock or assertion in
# slave_parallel_mode=optimistic configuration while applying admin command
# like 'OPTIMIZE TABLE', 'REPAIR TABLE' and 'ANALYZE TABLE'.
#
# ==== Implementation ====
#
# Steps:
# 0 - Create a table, execute OPTIMIZE TABLE command on the table followed
# by some DMLS.
# 1 - No assert should happen on slave server.
# 2 - Assert that 'OPTIMIZE TABLE', 'REPAIR TABLE' and 'ANALYZE TABLE' are
# marked as 'DDL' in the binary log.
#
# ==== References ====
#
# MDEV-17515: GTID Replication in optimistic mode deadlock
#
--source include/have_partition.inc
--source include/have_innodb.inc
--let $rpl_topology=1->2
--source include/rpl_init.inc
--connection server_1
FLUSH TABLES;
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
--connection server_2
SET @save_slave_parallel_threads= @@GLOBAL.slave_parallel_threads;
SET @save_slave_parallel_mode= @@GLOBAL.slave_parallel_mode;
--source include/stop_slave.inc
SET GLOBAL slave_parallel_threads=2;
SET GLOBAL slave_parallel_mode=optimistic;
--source include/start_slave.inc
--connection server_1
CREATE TABLE t1(a INT) ENGINE=INNODB;
OPTIMIZE TABLE t1;
INSERT INTO t1 VALUES(1);
INSERT INTO t1 SELECT 1+a FROM t1;
INSERT INTO t1 SELECT 2+a FROM t1;
--save_master_pos
--connection server_2
--sync_with_master
--echo #
--echo # Verify that following admin commands are marked as ddl
--echo # 'OPTIMIZE TABLE', 'REPAIR TABLE' and 'ANALYZE TABLE'
--echo #
--connection server_1
OPTIMIZE TABLE t1;
--let optimize_gtid= `SELECT @@GLOBAL.gtid_binlog_pos`
REPAIR TABLE t1;
--let repair_gtid= `SELECT @@GLOBAL.gtid_binlog_pos`
ANALYZE TABLE t1;
--let analyze_gtid= `SELECT @@GLOBAL.gtid_binlog_pos`
let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
FLUSH LOGS;
--let $MYSQLD_DATADIR= `select @@datadir`
--exec $MYSQL_BINLOG $MYSQLD_DATADIR/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
--let SEARCH_PATTERN= GTID $optimize_gtid ddl
--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
--source include/search_pattern_in_file.inc
--let SEARCH_PATTERN= GTID $repair_gtid ddl
--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
--source include/search_pattern_in_file.inc
--let SEARCH_PATTERN= GTID $analyze_gtid ddl
--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
--source include/search_pattern_in_file.inc
--echo #
--echo # Clean up
--echo #
DROP TABLE t1;
--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
--save_master_pos
--connection server_2
--sync_with_master
FLUSH LOGS;
--echo #
--echo # Check that ALTER TABLE commands with ANALYZE, OPTIMIZE and REPAIR on
--echo # partitions will be marked as DDL in binary log.
--echo #
--connection server_1
CREATE TABLE t1(id INT) PARTITION BY RANGE (id) (PARTITION p0 VALUES LESS THAN (100),
PARTITION pmax VALUES LESS THAN (MAXVALUE));
INSERT INTO t1 VALUES (1), (10), (100), (1000);
ALTER TABLE t1 ANALYZE PARTITION p0;
--let analyze_gtid= `SELECT @@GLOBAL.gtid_binlog_pos`
ALTER TABLE t1 OPTIMIZE PARTITION p0;
--let optimize_gtid= `SELECT @@GLOBAL.gtid_binlog_pos`
ALTER TABLE t1 REPAIR PARTITION p0;
--let repair_gtid= `SELECT @@GLOBAL.gtid_binlog_pos`
let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
FLUSH LOGS;
--exec $MYSQL_BINLOG $MYSQLD_DATADIR/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
--let SEARCH_PATTERN= GTID $analyze_gtid ddl
--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
--source include/search_pattern_in_file.inc
--let SEARCH_PATTERN= GTID $optimize_gtid ddl
--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
--source include/search_pattern_in_file.inc
--let SEARCH_PATTERN= GTID $repair_gtid ddl
--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
--source include/search_pattern_in_file.inc
--echo #
--echo # Clean up
--echo #
DROP TABLE t1;
--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
--save_master_pos
--connection server_2
--sync_with_master
--source include/stop_slave.inc
SET GLOBAL slave_parallel_threads= @save_slave_parallel_threads;
SET GLOBAL slave_parallel_mode= @save_slave_parallel_mode;
--source include/start_slave.inc
--source include/rpl_end.inc
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
# hang when the parallel workers were idle. # hang when the parallel workers were idle.
# The bug reported scenario is extented to cover the multi-sources case as well as # The bug reported scenario is extented to cover the multi-sources case as well as
# checking is done for both the idle and busy workers cases. # checking is done for both the idle and busy workers cases.
#
# MDEV-25336 Parallel replication causes failed assert while restarting
# Since this test case involves slave restart this will help in testing
# Mdev-25336 too.
--source include/have_innodb.inc --source include/have_innodb.inc
--source include/have_binlog_format_mixed.inc --source include/have_binlog_format_mixed.inc
...@@ -26,7 +30,7 @@ select @@global.slave_parallel_workers as two; ...@@ -26,7 +30,7 @@ select @@global.slave_parallel_workers as two;
# At this point worker threads have no assignement. # At this point worker threads have no assignement.
# Shutdown must not hang. # Shutdown must not hang.
# In 10.2/10.3 there should not be any assert failure `prev != 0 && next != 0'
--connection server_3 --connection server_3
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.3.expect --write_file $MYSQLTEST_VARDIR/tmp/mysqld.3.expect
wait wait
...@@ -75,6 +79,7 @@ insert into t1 values (1); ...@@ -75,6 +79,7 @@ insert into t1 values (1);
--connection server_3 --connection server_3
--sync_with_master 0,'' --sync_with_master 0,''
# In 10.2/10.3 there should not be any assert failure `prev != 0 && next != 0'
# At this point worker threads have no assignement. # At this point worker threads have no assignement.
# Shutdown must not hang. # Shutdown must not hang.
...@@ -117,6 +122,7 @@ insert into t1 values (2); ...@@ -117,6 +122,7 @@ insert into t1 values (2);
insert into t2 values (2); insert into t2 values (2);
# In 10.2/10.3 there should not be any assert failure `prev != 0 && next != 0'
# At this point there's a good chance the worker threads are busy. # At this point there's a good chance the worker threads are busy.
# SHUTDOWN must proceed without any delay as above. # SHUTDOWN must proceed without any delay as above.
--connection server_3 --connection server_3
......
...@@ -1865,9 +1865,19 @@ struct THD_TRANS ...@@ -1865,9 +1865,19 @@ struct THD_TRANS
CREATED_TEMP_TABLE= 2, CREATED_TEMP_TABLE= 2,
DROPPED_TEMP_TABLE= 4, DROPPED_TEMP_TABLE= 4,
DID_WAIT= 8, DID_WAIT= 8,
DID_DDL= 0x10 DID_DDL= 0x10,
EXECUTED_TABLE_ADMIN_CMD= 0x20
}; };
void mark_executed_table_admin_cmd()
{
DBUG_PRINT("debug", ("mark_executed_table_admin_cmd"));
m_unsafe_rollback_flags|= EXECUTED_TABLE_ADMIN_CMD;
}
bool trans_executed_admin_cmd()
{
return (m_unsafe_rollback_flags & EXECUTED_TABLE_ADMIN_CMD) != 0;
}
void mark_created_temp_table() void mark_created_temp_table()
{ {
DBUG_PRINT("debug", ("mark_created_temp_table")); DBUG_PRINT("debug", ("mark_created_temp_table"));
......
...@@ -3263,8 +3263,10 @@ Gtid_log_event::Gtid_log_event(THD *thd_arg, uint64 seq_no_arg, ...@@ -3263,8 +3263,10 @@ Gtid_log_event::Gtid_log_event(THD *thd_arg, uint64 seq_no_arg,
flags2|= FL_WAITED; flags2|= FL_WAITED;
if (thd_arg->transaction->stmt.trans_did_ddl() || if (thd_arg->transaction->stmt.trans_did_ddl() ||
thd_arg->transaction->stmt.has_created_dropped_temp_table() || thd_arg->transaction->stmt.has_created_dropped_temp_table() ||
thd_arg->transaction->stmt.trans_executed_admin_cmd() ||
thd_arg->transaction->all.trans_did_ddl() || thd_arg->transaction->all.trans_did_ddl() ||
thd_arg->transaction->all.has_created_dropped_temp_table()) thd_arg->transaction->all.has_created_dropped_temp_table() ||
thd_arg->transaction->all.trans_executed_admin_cmd())
flags2|= FL_DDL; flags2|= FL_DDL;
else if (is_transactional && !is_tmp_table) else if (is_transactional && !is_tmp_table)
flags2|= FL_TRANSACTIONAL; flags2|= FL_TRANSACTIONAL;
......
...@@ -209,8 +209,8 @@ a file name for --relay-log-index option", opt_relaylog_index_name); ...@@ -209,8 +209,8 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
*/ */
sql_print_warning("Neither --relay-log nor --relay-log-index were used;" sql_print_warning("Neither --relay-log nor --relay-log-index were used;"
" so replication " " so replication "
"may break when this MySQL server acts as a " "may break when this MariaDB server acts as a "
"slave and has his hostname changed!! Please " "replica and has its hostname changed. Please "
"use '--log-basename=#' or '--relay-log=%s' to avoid " "use '--log-basename=#' or '--relay-log=%s' to avoid "
"this problem.", ln); "this problem.", ln);
name_warning_sent= 1; name_warning_sent= 1;
......
/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. /* Copyright (c) 2010, 2015, Oracle and/or its affiliates.
Copyright (c) 2011, 2020, MariaDB Copyright (c) 2011, 2021, MariaDB
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -490,7 +490,8 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, ...@@ -490,7 +490,8 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
int (handler::*operator_func)(THD *, int (handler::*operator_func)(THD *,
HA_CHECK_OPT *), HA_CHECK_OPT *),
int (view_operator_func)(THD *, TABLE_LIST*, int (view_operator_func)(THD *, TABLE_LIST*,
HA_CHECK_OPT *)) HA_CHECK_OPT *),
bool is_cmd_replicated)
{ {
TABLE_LIST *table; TABLE_LIST *table;
List<Item> field_list; List<Item> field_list;
...@@ -501,6 +502,8 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, ...@@ -501,6 +502,8 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
int compl_result_code; int compl_result_code;
bool need_repair_or_alter= 0; bool need_repair_or_alter= 0;
wait_for_commit* suspended_wfc; wait_for_commit* suspended_wfc;
bool is_table_modified= false;
DBUG_ENTER("mysql_admin_table"); DBUG_ENTER("mysql_admin_table");
DBUG_PRINT("enter", ("extra_open_options: %u", extra_open_options)); DBUG_PRINT("enter", ("extra_open_options: %u", extra_open_options));
...@@ -560,6 +563,10 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, ...@@ -560,6 +563,10 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
bool open_for_modify= org_open_for_modify; bool open_for_modify= org_open_for_modify;
DBUG_PRINT("admin", ("table: '%s'.'%s'", db, table->table_name.str)); DBUG_PRINT("admin", ("table: '%s'.'%s'", db, table->table_name.str));
DEBUG_SYNC(thd, "admin_command_kill_before_modify");
if (thd->is_killed())
break;
strxmov(table_name, db, ".", table->table_name.str, NullS); strxmov(table_name, db, ".", table->table_name.str, NullS);
thd->open_options|= extra_open_options; thd->open_options|= extra_open_options;
table->lock_type= lock_type; table->lock_type= lock_type;
...@@ -1212,6 +1219,13 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, ...@@ -1212,6 +1219,13 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
break; break;
} }
} }
/*
Admin commands acquire table locks and these locks are not detected by
parallel replication deadlock detection-and-handling mechanism. Hence
they must be marked as DDL so that they are not scheduled in parallel
with conflicting DMLs resulting in deadlock.
*/
thd->transaction->stmt.mark_executed_table_admin_cmd();
if (table->table && !table->view) if (table->table && !table->view)
{ {
/* /*
...@@ -1253,10 +1267,9 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, ...@@ -1253,10 +1267,9 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
} }
else else
{ {
if (trans_commit_stmt(thd) || if (trans_commit_stmt(thd))
(stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END) &&
trans_commit_implicit(thd)))
goto err; goto err;
is_table_modified= true;
} }
close_thread_tables(thd); close_thread_tables(thd);
thd->release_transactional_locks(); thd->release_transactional_locks();
...@@ -1279,6 +1292,16 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, ...@@ -1279,6 +1292,16 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
if (protocol->write()) if (protocol->write())
goto err; goto err;
DEBUG_SYNC(thd, "admin_command_kill_after_modify");
}
if (is_table_modified && is_cmd_replicated &&
(!opt_readonly || thd->slave_thread) && !thd->lex->no_write_to_binlog)
{
thd->get_stmt_da()->set_overwrite_status(true);
auto res= write_bin_log(thd, true, thd->query(), thd->query_length());
thd->get_stmt_da()->set_overwrite_status(false);
if (res)
goto err;
} }
my_eof(thd); my_eof(thd);
...@@ -1341,7 +1364,7 @@ bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* tables, ...@@ -1341,7 +1364,7 @@ bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* tables,
check_opt.key_cache= key_cache; check_opt.key_cache= key_cache;
DBUG_RETURN(mysql_admin_table(thd, tables, &check_opt, DBUG_RETURN(mysql_admin_table(thd, tables, &check_opt,
"assign_to_keycache", TL_READ_NO_INSERT, 0, 0, "assign_to_keycache", TL_READ_NO_INSERT, 0, 0,
0, 0, &handler::assign_to_keycache, 0)); 0, 0, &handler::assign_to_keycache, 0, false));
} }
...@@ -1368,7 +1391,7 @@ bool mysql_preload_keys(THD* thd, TABLE_LIST* tables) ...@@ -1368,7 +1391,7 @@ bool mysql_preload_keys(THD* thd, TABLE_LIST* tables)
*/ */
DBUG_RETURN(mysql_admin_table(thd, tables, 0, DBUG_RETURN(mysql_admin_table(thd, tables, 0,
"preload_keys", TL_READ_NO_INSERT, 0, 0, 0, 0, "preload_keys", TL_READ_NO_INSERT, 0, 0, 0, 0,
&handler::preload_keys, 0)); &handler::preload_keys, 0, false));
} }
...@@ -1389,17 +1412,8 @@ bool Sql_cmd_analyze_table::execute(THD *thd) ...@@ -1389,17 +1412,8 @@ bool Sql_cmd_analyze_table::execute(THD *thd)
WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table); WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table);
res= mysql_admin_table(thd, first_table, &m_lex->check_opt, res= mysql_admin_table(thd, first_table, &m_lex->check_opt,
"analyze", lock_type, 1, 0, 0, 0, "analyze", lock_type, 1, 0, 0, 0,
&handler::ha_analyze, 0); &handler::ha_analyze, 0, true);
/* ! we write after unlocking the table */
if (!res && !m_lex->no_write_to_binlog && (!opt_readonly || thd->slave_thread))
{
/*
Presumably, ANALYZE and binlog writing doesn't require synchronization
*/
thd->get_stmt_da()->set_overwrite_status(true);
res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
thd->get_stmt_da()->set_overwrite_status(false);
}
m_lex->first_select_lex()->table_list.first= first_table; m_lex->first_select_lex()->table_list.first= first_table;
m_lex->query_tables= first_table; m_lex->query_tables= first_table;
...@@ -1425,7 +1439,7 @@ bool Sql_cmd_check_table::execute(THD *thd) ...@@ -1425,7 +1439,7 @@ bool Sql_cmd_check_table::execute(THD *thd)
res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "check", res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "check",
lock_type, 0, 0, HA_OPEN_FOR_REPAIR, 0, lock_type, 0, 0, HA_OPEN_FOR_REPAIR, 0,
&handler::ha_check, &view_check); &handler::ha_check, &view_check, false);
m_lex->first_select_lex()->table_list.first= first_table; m_lex->first_select_lex()->table_list.first= first_table;
m_lex->query_tables= first_table; m_lex->query_tables= first_table;
...@@ -1450,17 +1464,8 @@ bool Sql_cmd_optimize_table::execute(THD *thd) ...@@ -1450,17 +1464,8 @@ bool Sql_cmd_optimize_table::execute(THD *thd)
mysql_recreate_table(thd, first_table, true) : mysql_recreate_table(thd, first_table, true) :
mysql_admin_table(thd, first_table, &m_lex->check_opt, mysql_admin_table(thd, first_table, &m_lex->check_opt,
"optimize", TL_WRITE, 1, 0, 0, 0, "optimize", TL_WRITE, 1, 0, 0, 0,
&handler::ha_optimize, 0); &handler::ha_optimize, 0, true);
/* ! we write after unlocking the table */
if (!res && !m_lex->no_write_to_binlog && (!opt_readonly || thd->slave_thread))
{
/*
Presumably, OPTIMIZE and binlog writing doesn't require synchronization
*/
thd->get_stmt_da()->set_overwrite_status(true);
res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
thd->get_stmt_da()->set_overwrite_status(false);
}
m_lex->first_select_lex()->table_list.first= first_table; m_lex->first_select_lex()->table_list.first= first_table;
m_lex->query_tables= first_table; m_lex->query_tables= first_table;
...@@ -1483,18 +1488,8 @@ bool Sql_cmd_repair_table::execute(THD *thd) ...@@ -1483,18 +1488,8 @@ bool Sql_cmd_repair_table::execute(THD *thd)
TL_WRITE, 1, TL_WRITE, 1,
MY_TEST(m_lex->check_opt.sql_flags & TT_USEFRM), MY_TEST(m_lex->check_opt.sql_flags & TT_USEFRM),
HA_OPEN_FOR_REPAIR, &prepare_for_repair, HA_OPEN_FOR_REPAIR, &prepare_for_repair,
&handler::ha_repair, &view_repair); &handler::ha_repair, &view_repair, true);
/* ! we write after unlocking the table */
if (!res && !m_lex->no_write_to_binlog && (!opt_readonly || thd->slave_thread))
{
/*
Presumably, REPAIR and binlog writing doesn't require synchronization
*/
thd->get_stmt_da()->set_overwrite_status(true);
res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
thd->get_stmt_da()->set_overwrite_status(false);
}
m_lex->first_select_lex()->table_list.first= first_table; m_lex->first_select_lex()->table_list.first= first_table;
m_lex->query_tables= first_table; m_lex->query_tables= first_table;
......
...@@ -5155,7 +5155,8 @@ class THD: public THD_count, /* this must be first */ ...@@ -5155,7 +5155,8 @@ class THD: public THD_count, /* this must be first */
transaction->all.m_unsafe_rollback_flags|= transaction->all.m_unsafe_rollback_flags|=
(transaction->stmt.m_unsafe_rollback_flags & (transaction->stmt.m_unsafe_rollback_flags &
(THD_TRANS::DID_WAIT | THD_TRANS::CREATED_TEMP_TABLE | (THD_TRANS::DID_WAIT | THD_TRANS::CREATED_TEMP_TABLE |
THD_TRANS::DROPPED_TEMP_TABLE | THD_TRANS::DID_DDL)); THD_TRANS::DROPPED_TEMP_TABLE | THD_TRANS::DID_DDL |
THD_TRANS::EXECUTED_TABLE_ADMIN_CMD));
} }
......
...@@ -8810,8 +8810,12 @@ ha_innobase::index_read( ...@@ -8810,8 +8810,12 @@ ha_innobase::index_read(
/* For R-Tree index, we will always place the page lock to /* For R-Tree index, we will always place the page lock to
pages being searched */ pages being searched */
if (dict_index_is_spatial(index)) { if (index->is_spatial() && !m_prebuilt->trx->will_lock) {
++m_prebuilt->trx->will_lock; if (trx_is_started(m_prebuilt->trx)) {
DBUG_RETURN(HA_ERR_READ_ONLY_TRANSACTION);
} else {
m_prebuilt->trx->will_lock = true;
}
} }
/* Note that if the index for which the search template is built is not /* Note that if the index for which the search template is built is not
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment