403Webshell
Server IP : 172.67.216.182  /  Your IP : 172.71.82.50
Web Server : Apache
System : Linux krdc-ubuntu-s-2vcpu-4gb-amd-blr1-01.localdomain 5.15.0-142-generic #152-Ubuntu SMP Mon May 19 10:54:31 UTC 2025 x86_64
User : www ( 1000)
PHP Version : 7.4.33
Disable Function : passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /www/server/mysql/src/mysql-test/suite/rpl/t/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /www/server/mysql/src/mysql-test/suite/rpl/t/rpl_mts_slave_preserve_commit_order_deadlock.test
################################################################################
# BUG#20136704 --SLAVE-PRESERVE-COMMIT-ORDER CAUSES SLAVE TO DEADLOCK AND
#              BREAK FOR SOME QUERIE
#
# A corner case of deadlock:
# INSERT INTO t1 (7, NULL);
# DELETE FROM t1 WHERE c2 <= 3;
# They are executed parallel on master and INSERT is binlogged before DELETE.
#
# On slave, they are applied parallel by w0 and w1. And the deadlock is:
#   w0                                         w1
# -------------------------         --------------------------
#  applying DELETE                    applying INSERT
#  get the row locks first.
#                                     waiting for w1 to release the row lock.
#  waiting for w2 to commit
#
#  For this two special statements, INSERT doesn't block DELETE, but DELETE does
#  block the INSERT since some innodb internal reasons.
#
# This test verifies the deadlock can be found and handled correctly.
# When it finds the deadlock, it will rollback the the transaction which should
# commit after the waiting transaction.
################################################################################
--source include/have_debug.inc
--source include/have_binlog_format_statement.inc
--source include/master-slave.inc
#
# Initialize
#
CREATE TABLE t1(c1 INT PRIMARY KEY, c2 INT, INDEX(c2)) ENGINE = InnoDB;
INSERT INTO t1 VALUES(1, NULL),(2, 2), (3, NULL), (4, 4), (5, NULL), (6, 6);

--source include/sync_slave_sql_with_master.inc
--source include/stop_slave_sql.inc
SET @saved_slave_parallel_type = @@GLOBAL.slave_parallel_type;
SET @saved_slave_parallel_workers = @@GLOBAL.slave_parallel_workers;
SET @saved_slave_preserve_commit_order = @@GLOBAL.slave_preserve_commit_order;
SET @saved_innodb_lock_wait_timeout = @@GLOBAL.innodb_lock_wait_timeout;
SET @saved_slave_transaction_retries = @@GLOBAL.slave_transaction_retries;

SET GLOBAL slave_transaction_retries = 2;
SET GLOBAL slave_parallel_type = "LOGICAL_CLOCK";
SET GLOBAL slave_parallel_workers = 3;
SET GLOBAL slave_preserve_commit_order = ON;
# Set it a long time to guarantee it doens't report an timeout error
SET GLOBAL innodb_lock_wait_timeout = 1000;


--echo #
--echo # Case 1: Verify slave can find the deadlock when DELETE is waiting
--echo # for its turn to commit
--echo #
--source include/rpl_connection_master.inc
# There is a bug that the first two transactions cannot be applied parallel.
# So we need to an extra transaction here.
INSERT INTO t1 VALUES(10, 10);

SET debug = "d,set_commit_parent_100";
INSERT INTO t1 VALUES(11, NULL);
DELETE FROM t1 WHERE c2 <= 3;

--source include/rpl_connection_slave.inc
# It blocks above INSERT statement
BEGIN;
INSERT INTO t1 VALUES(11, 11);

--source include/rpl_connection_slave1.inc
--source include/start_slave_sql.inc

# It guarantees the DELETE statement is waiting for
# the transaction before it to commit
--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE STATE = "Waiting for preceding transaction to commit"
--source include/wait_condition.inc

# Resume the INSERT statement and trigger the deadlock
--source include/rpl_connection_slave.inc
ROLLBACK;

--let $rpl_diff_statement= SELECT * FROM t1;
--source include/rpl_diff.inc

--source include/rpl_connection_master.inc
SET debug = "";
TRUNCATE t1;
INSERT INTO t1 VALUES(1, NULL),(2, 2), (3, NULL), (4, 4), (5, NULL), (6, 6);
--source include/sync_slave_sql_with_master.inc
--source include/stop_slave_sql.inc

--echo #
--echo # Case 2: Verify slave can find the deadlock when it begins to applying
--echo # second DELETE statement.
--echo #
--source include/rpl_connection_master.inc
INSERT INTO t1 VALUES(20, NULL);

SET debug = "d,set_commit_parent_100";
INSERT INTO t1 VALUES(21, NULL);

BEGIN;
INSERT INTO t1 VALUES(22, 22);
DELETE FROM t1 WHERE c2 <= 3;
INSERT INTO t1 VALUES(23, 23);
INSERT INTO t1 VALUES(24, 24);
INSERT INTO t1 VALUES(25, 25);
COMMIT;

--source include/rpl_connection_slave.inc
# Use it to block the worker applying 'INSERT INTO t1 VALUES(21, NULL)';
BEGIN;
INSERT INTO t1 VALUES(21, 21);

--let $rpl_connection_name= server_2_1
--source include/rpl_connection.inc
# Use it to block the worker applying 'INSERT INTO t1 VALUES(23, 23)';
BEGIN;
INSERT INTO t1 VALUES(23, 23);

--source include/rpl_connection_slave1.inc
--source include/start_slave_sql.inc

# It guarantees 'DELETE FROM t1 WHERE c2 <= 3;' is applied.
--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE info = "INSERT INTO t1 VALUES(23, 23)"
--source include/wait_condition.inc

# Resume "INSERT INTO t1 VALUES(21, 21);" to trigger the lock conflict
--source include/rpl_connection_slave.inc
ROLLBACK;

# It guarantees that both workers are waiting for locks
# hold by above two transactions
--let $status_var= Innodb_row_lock_current_waits
--let $status_var_value= 2
--source include/wait_for_status_var.inc

# Resume "INSERT INTO t1 VALUES(23, 23);". It will be rolled back.
--let $rpl_connection_name= server_2_1
--source include/rpl_connection.inc
ROLLBACK;

--let $rpl_diff_statement= SELECT * FROM t1;
--source include/rpl_diff.inc

--source include/rpl_connection_master.inc
SET debug = "";
TRUNCATE t1;
INSERT INTO t1 VALUES(1, NULL),(2, 2), (3, NULL), (4, 4), (5, NULL), (32, 32);
--source include/sync_slave_sql_with_master.inc
--source include/stop_slave_sql.inc


--echo #
--echo # Test case 3: Verify the worker can handle it correctly when it is
--echo # retrying a transaction.
--echo #
--source include/rpl_connection_master.inc
INSERT INTO t1 VALUES(30, NULL);

SET debug = "d,set_commit_parent_100";
INSERT INTO t1 VALUES(31, NULL);
INSERT INTO t1 VALUES(33, NULL);

DELETE FROM t1 WHERE c2 <= 3;

--source include/rpl_connection_slave.inc
# Use it to block the worker applying 'INSERT INTO t1 VALUES(31, NULL)';
BEGIN;
INSERT INTO t1 VALUES(31, 31);

--let $rpl_connection_name= server_2_1
--source include/rpl_connection.inc
# Use it to block the worker applying 'INSERT INTO t1 VALUES(33, NULL)';
BEGIN;
INSERT INTO t1 VALUES(33, 33);

--source include/rpl_connection_slave1.inc
--source include/start_slave_sql.inc

# It guarantees 'DELETE' statement is waiting for the transactions before it.
--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE STATE = "Waiting for preceding transaction to commit"
--source include/wait_condition.inc

# Trigger one deadlock
--source include/rpl_connection_slave.inc
ROLLBACK;

# It guarantees "INSERT INTO t1 VALUES(31, 31);" is already applied.
--let $wait_condition= SELECT count(*) = 1 FROM t1 WHERE c1 = 31
--source include/wait_condition.inc

# It guarantees 'DELETE' statement is waiting for the transactions before it.
--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE STATE = "Waiting for preceding transaction to commit"
--source include/wait_condition.inc

# Trigger another deadlock
--let $rpl_connection_name= server_2_1
--source include/rpl_connection.inc
ROLLBACK;

--let $rpl_diff_statement= SELECT * FROM t1
--source include/rpl_diff.inc
SET debug = "";

--echo #
--echo # Test Case 4: Innodb internal transaction deadlock
--echo #
--source include/rpl_connection_master.inc
CREATE TABLE t2 LIKE mysql.innodb_table_stats;
--source include/sync_slave_sql_with_master.inc
--source include/stop_slave_sql.inc
CALL mtr.add_suppression(".*InnoDB: Cannot save table statistics for table.*");
LOCK TABLE t1 WRITE;

--source include/rpl_connection_master.inc
# There is a bug that the first two transactions cannot be applied parallel.
# So we need to an extra transaction here.
TRUNCATE t2;
SET debug = "d,set_commit_parent_100";
ANALYZE TABLE t1;
INSERT INTO t2 SELECT * FROM mysql.innodb_table_stats;

--source include/rpl_connection_slave.inc
--source include/start_slave_sql.inc

# It guarantees 'INSERT' statement is waiting for the transactions before it.
--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE STATE = "Waiting for preceding transaction to commit"
--source include/wait_condition.inc

UNLOCK TABLES;

--echo #
--echo # Test Case 5: It won't cause transaction rollback if
--echo #              slave_preserve_commit_order is OFF
--echo #
--source include/rpl_connection_master.inc
SET debug = "";
TRUNCATE t1;
INSERT INTO t1 VALUES(1, NULL),(2, 2), (3, NULL), (4, 4), (5, NULL), (6, 6);
--source include/sync_slave_sql_with_master.inc
--source include/stop_slave_sql.inc

--source include/rpl_connection_master.inc
INSERT INTO t1 VALUES(50, 50);

SET debug = "d,set_commit_parent_100";
INSERT INTO t1 VALUES(51, NULL);
BEGIN;
INSERT INTO t1 VALUES(52, 52);
DELETE FROM t1 WHERE c2 <= 3;
INSERT INTO t1 VALUES(53, 53);
INSERT INTO t1 VALUES(54, 54);
INSERT INTO t1 VALUES(55, 55);
COMMIT;

--source include/rpl_connection_slave.inc
# Use it to block the worker applying 'INSERT INTO t1 VALUES(51, NULL)';
BEGIN;
INSERT INTO t1 VALUES(51, 51);

--let $rpl_connection_name= server_2_1
--source include/rpl_connection.inc
# Use it to block the worker applying 'INSERT INTO t1 VALUES(53, 53)';
BEGIN;
INSERT INTO t1 VALUES(53, 53);

--source include/rpl_connection_slave1.inc
SET GLOBAL slave_preserve_commit_order = OFF;
# It will make slave to stop if order commit deadlock happens
SET GLOBAL slave_transaction_retries = 0;
--source include/start_slave_sql.inc

# It guarantees 'DELETE FROM t1 WHERE c2 <= 3;' is applied.
--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE info = "INSERT INTO t1 VALUES(53, 53)"
--source include/wait_condition.inc

# Resume "INSERT INTO t1 VALUES(51, 51);" to trigger the lock conflict
--source include/rpl_connection_slave.inc
ROLLBACK;

# It guarantees that both workers are waiting for locks
# hold by above two transactions
--let $status_var= Innodb_row_lock_current_waits
--let $status_var_value= 2
--source include/wait_for_status_var.inc

# Resume "INSERT INTO t1 VALUES(53, 53);" to continue its transaction.
--let $rpl_connection_name= server_2_1
--source include/rpl_connection.inc
ROLLBACK;

--let $rpl_diff_statement= SELECT * FROM t1;
--source include/rpl_diff.inc

--echo #
--echo # Deinitialize
--echo #
--source include/rpl_connection_master.inc
SET debug = "";
DROP TABLE t1, t2;
--source include/sync_slave_sql_with_master.inc

--source include/stop_slave.inc
SET GLOBAL slave_transaction_retries = @saved_slave_transaction_retries;
SET GLOBAL slave_parallel_type = @saved_slave_parallel_type;
SET GLOBAL slave_parallel_workers = @saved_slave_parallel_workers;
SET GLOBAL slave_preserve_commit_order = @saved_slave_preserve_commit_order;
SET GLOBAL innodb_lock_wait_timeout = @saved_innodb_lock_wait_timeout;

--let $rpl_only_running_threads= 1
--source include/rpl_end.inc

Youez - 2016 - github.com/yon3zu
LinuXploit