Merge 10.2 into 10.3, except MDEV-25682

This commit is contained in:
Marko Mäkelä 2021-05-18 08:40:19 +03:00
commit ca3f497564
21 changed files with 722 additions and 45 deletions

View File

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

View File

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

View File

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

View File

@ -0,0 +1,4 @@
connect con1,localhost,root,,;
SET DEBUG_DBUG='+d,mark_busy_mdev_22370';
FLUSH TABLES WITH READ LOCK;
connection default;

View File

@ -0,0 +1,17 @@
#
# MDEV-22370 safe_mutex: Trying to lock uninitialized mutex at
# /data/src/10.4-bug/sql/rpl_parallel.cc, line 470 upon shutdown during FTWRL
#
# Purpose of this test case to test crash while FTWRL and shutdown is in race
# condition
# Shutdown can execute first and destroy the mutex making mutex_lock in pool_mark_busy
# to crash
--source include/have_debug.inc
--connect (con1,localhost,root,,)
SET DEBUG_DBUG='+d,mark_busy_mdev_22370';
--send
FLUSH TABLES WITH READ LOCK;
--connection default
--source include/restart_mysqld.inc

View File

@ -0,0 +1,40 @@
#
# 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

View File

@ -0,0 +1,95 @@
# ==== 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

View File

@ -0,0 +1,77 @@
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 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 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

View File

@ -0,0 +1,79 @@
include/rpl_init.inc [topology=1->3]
connection server_3;
set default_master_connection = '';
include/start_slave.inc
Warnings:
Note 1254 Slave is already running
set default_master_connection = 'm2';
change master to master_host='127.0.0.1', master_port=SERVER_MYPORT_2, master_user='root', master_use_gtid=slave_pos;
include/start_slave.inc
select @@global.slave_parallel_workers as two;
two
2
connection server_3;
SHUTDOWN;
connection server_3;
connection server_3;
connection server_1;
create table t1 (i int primary key) engine=Innodb;
connection server_2;
create table t2 (i int primary key) engine=Innodb;
connection server_3;
set default_master_connection = '';
include/start_slave.inc
Warnings:
Note 1254 Slave is already running
set default_master_connection = 'm2';
include/start_slave.inc
Warnings:
Note 1254 Slave is already running
connection server_2;
insert into t2 values (1);
connection server_3;
connection server_1;
insert into t1 values (1);
connection server_3;
connection server_3;
SHUTDOWN;
connection server_3;
connection server_3;
connection server_3;
set default_master_connection = '';
include/start_slave.inc
Warnings:
Note 1254 Slave is already running
set default_master_connection = 'm2';
include/start_slave.inc
Warnings:
Note 1254 Slave is already running
connect conn_block_server3, 127.0.0.1, root,, test, $SERVER_MYPORT_3,;
begin;
insert into t1 values (2);
insert into t2 values (2);
connection server_1;
insert into t1 values (2);
connection server_2;
insert into t2 values (2);
connection server_3;
SHUTDOWN;
connection server_3;
connection server_3;
connection server_3;
set default_master_connection = '';
include/start_slave.inc
Warnings:
Note 1254 Slave is already running
set default_master_connection = 'm2';
include/start_slave.inc
Warnings:
Note 1254 Slave is already running
connection server_1;
drop table t1;
connection server_2;
drop table t2;
connection server_3;
set default_master_connection = 'm2';
include/stop_slave.inc
RESET SLAVE ALL;
set default_master_connection = '';
include/rpl_end.inc

View File

@ -0,0 +1,142 @@
# ==== 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

View File

@ -0,0 +1,19 @@
!include suite/rpl/rpl_1slave_base.cnf
!include include/default_client.cnf
[mysqld.1]
log-slave-updates
gtid-domain-id=1
[mysqld.2]
log-slave-updates
gtid-domain-id=2
[mysqld.3]
log-slave-updates
gtid-domain-id=3
slave_parallel_threads=2
[ENV]
SERVER_MYPORT_3= @mysqld.3.port
SERVER_MYSOCK_3= @mysqld.3.socket

View File

@ -0,0 +1,171 @@
# MDEV-20821 parallel slave server shutdown hang
#
# Test the bug condition of a parallel slave server shutdown
# hang when the parallel workers were idle.
# 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.
#
# 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_binlog_format_mixed.inc
--let $rpl_topology= 1->3
--source include/rpl_init.inc
#
# A. idle workers.
#
--connection server_3
set default_master_connection = '';
--source include/start_slave.inc
set default_master_connection = 'm2';
--replace_result $SERVER_MYPORT_2 SERVER_MYPORT_2
eval change master to master_host='127.0.0.1', master_port=$SERVER_MYPORT_2, master_user='root', master_use_gtid=slave_pos;
--source include/start_slave.inc
select @@global.slave_parallel_workers as two;
# At this point worker threads have no assignement.
# Shutdown must not hang.
# In 10.2/10.3 there should not be any assert failure `prev != 0 && next != 0'
--connection server_3
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.3.expect
wait
EOF
--send SHUTDOWN
--reap
--source include/wait_until_disconnected.inc
--connection server_3
--append_file $MYSQLTEST_VARDIR/tmp/mysqld.3.expect
restart
EOF
# No hang is *proved* to occur when this point is reached.
--connection server_3
--enable_reconnect
--source include/wait_until_connected_again.inc
#
# B. resting workers after some busy time
#
--connection server_1
create table t1 (i int primary key) engine=Innodb;
--connection server_2
create table t2 (i int primary key) engine=Innodb;
--connection server_3
set default_master_connection = '';
--source include/start_slave.inc
set default_master_connection = 'm2';
--source include/start_slave.inc
--connection server_2
insert into t2 values (1);
--save_master_pos
--connection server_3
--sync_with_master 0,'m2'
--connection server_1
insert into t1 values (1);
--save_master_pos
--connection server_3
--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.
# Shutdown must not hang.
--connection server_3
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.3.expect
wait
EOF
--send SHUTDOWN
--reap
--source include/wait_until_disconnected.inc
--connection server_3
--append_file $MYSQLTEST_VARDIR/tmp/mysqld.3.expect
restart
EOF
# No hang is *proved* to occur when this point is reached.
--connection server_3
--enable_reconnect
--source include/wait_until_connected_again.inc
#
# C. busy workers
#
--connection server_3
set default_master_connection = '';
--source include/start_slave.inc
set default_master_connection = 'm2';
--source include/start_slave.inc
--connect (conn_block_server3, 127.0.0.1, root,, test, $SERVER_MYPORT_3,)
begin;
insert into t1 values (2);
insert into t2 values (2);
--connection server_1
insert into t1 values (2);
--connection server_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.
# SHUTDOWN must proceed without any delay as above.
--connection server_3
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.3.expect
wait
EOF
--send SHUTDOWN
--reap
--source include/wait_until_disconnected.inc
--connection server_3
--append_file $MYSQLTEST_VARDIR/tmp/mysqld.3.expect
restart
EOF
# No hang is *proved* to occur when this point is reached.
--connection server_3
--enable_reconnect
--source include/wait_until_connected_again.inc
# Cleanup
--connection server_3
set default_master_connection = '';
--source include/start_slave.inc
set default_master_connection = 'm2';
--source include/start_slave.inc
--connection server_1
drop table t1;
--connection server_2
drop table t2;
--save_master_pos
# (!) The following block is critical to avoid check-mysqld_3.reject by mtr:
--connection server_3
--sync_with_master 0,'m2'
set default_master_connection = 'm2';
--source include/stop_slave.inc
RESET SLAVE ALL;
set default_master_connection = '';
--source include/rpl_end.inc

View File

@ -1733,9 +1733,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"));

View File

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

View File

@ -454,6 +454,7 @@ pool_mark_busy(rpl_parallel_thread_pool *pool, THD *thd)
So we protect the infrequent operations of FLUSH TABLES WITH READ LOCK and So we protect the infrequent operations of FLUSH TABLES WITH READ LOCK and
pool size changes with this condition wait. pool size changes with this condition wait.
*/ */
DBUG_EXECUTE_IF("mark_busy_mdev_22370",my_sleep(1000000););
mysql_mutex_lock(&pool->LOCK_rpl_thread_pool); mysql_mutex_lock(&pool->LOCK_rpl_thread_pool);
if (thd) if (thd)
{ {
@ -1999,10 +2000,24 @@ rpl_parallel_thread_pool::init(uint32 size)
void void
rpl_parallel_thread_pool::destroy() rpl_parallel_thread_pool::destroy()
{
deactivate();
destroy_cond_mutex();
}
void
rpl_parallel_thread_pool::deactivate()
{ {
if (!inited) if (!inited)
return; return;
rpl_parallel_change_thread_count(this, 0, 1); rpl_parallel_change_thread_count(this, 0, 1);
}
void
rpl_parallel_thread_pool::destroy_cond_mutex()
{
if (!inited)
return;
mysql_mutex_destroy(&LOCK_rpl_thread_pool); mysql_mutex_destroy(&LOCK_rpl_thread_pool);
mysql_cond_destroy(&COND_rpl_thread_pool); mysql_cond_destroy(&COND_rpl_thread_pool);
inited= false; inited= false;

View File

@ -244,6 +244,8 @@ struct rpl_parallel_thread_pool {
rpl_parallel_thread_pool(); rpl_parallel_thread_pool();
int init(uint32 size); int init(uint32 size);
void destroy(); void destroy();
void deactivate();
void destroy_cond_mutex();
struct rpl_parallel_thread *get_thread(rpl_parallel_thread **owner, struct rpl_parallel_thread *get_thread(rpl_parallel_thread **owner,
rpl_parallel_entry *entry); rpl_parallel_entry *entry);
void release_thread(rpl_parallel_thread *rpt); void release_thread(rpl_parallel_thread *rpt);

View File

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

View File

@ -1261,6 +1261,9 @@ void slave_prepare_for_shutdown()
mysql_mutex_lock(&LOCK_active_mi); mysql_mutex_lock(&LOCK_active_mi);
master_info_index->free_connections(); master_info_index->free_connections();
mysql_mutex_unlock(&LOCK_active_mi); mysql_mutex_unlock(&LOCK_active_mi);
// It's safe to destruct worker pool now when
// all driver threads are gone.
global_rpl_thread_pool.deactivate();
} }
/* /*

View File

@ -1,5 +1,5 @@
/* 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
@ -455,7 +455,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;
@ -466,6 +467,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));
@ -515,6 +518,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;
@ -1167,6 +1174,13 @@ send_result_message:
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)
{ {
if (table->table->s->tmp_table) if (table->table->s->tmp_table)
@ -1202,10 +1216,9 @@ send_result_message:
} }
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();
@ -1228,6 +1241,13 @@ send_result_message:
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)
{
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
goto err;
} }
my_eof(thd); my_eof(thd);
@ -1290,7 +1310,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));
} }
@ -1317,7 +1337,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));
} }
@ -1335,15 +1355,7 @@ 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
*/
res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
}
m_lex->select_lex.table_list.first= first_table; m_lex->select_lex.table_list.first= first_table;
m_lex->query_tables= first_table; m_lex->query_tables= first_table;
@ -1367,7 +1379,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->select_lex.table_list.first= first_table; m_lex->select_lex.table_list.first= first_table;
m_lex->query_tables= first_table; m_lex->query_tables= first_table;
@ -1393,15 +1405,7 @@ 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
*/
res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
}
m_lex->select_lex.table_list.first= first_table; m_lex->select_lex.table_list.first= first_table;
m_lex->query_tables= first_table; m_lex->query_tables= first_table;
@ -1426,16 +1430,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
*/
res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
}
m_lex->select_lex.table_list.first= first_table; m_lex->select_lex.table_list.first= first_table;
m_lex->query_tables= first_table; m_lex->query_tables= first_table;

View File

@ -4823,7 +4823,8 @@ public:
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));
} }
/* /*
Reset current_linfo Reset current_linfo

View File

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