# ==== Purpose ====
#
# Test if sql thread doesn't assert when it is killed at
# 'Waiting for commit lock' state.
#
# Test if killing sql thread which is waiting for commit lock and restarting
# it doesn't cause a transaction to be skipped on slave.
#
# ==== Related Bugs and Worklogs ====
#
# BUG#16861624: KILLING WAITING SLAVE SQL THREAD:
#               M_STATUS == DA_ERROR || M_STATUS == DA_OK
#
# ==== Implementation ====
#
# In order to get the sql thread in the 'Waiting for commit lock' state
# we have to put some data into the master and, then, while replication
# is happening, lock the slave with 'FLUSH TABLES WITH READ LOCK'.
#
# Debug sync points were created to allow us to precisely put the
# sql thread in the desired state.
#
# After having the sql thread waiting for the commit lock, the test kills
# it identifying its ID by querying information_schema.processlist table.
#
# Bug#17450876: REPLICATION STOP WITH "ERROR IN XID_LOG_EVENT: COMMIT COULD
# NOT BE COMPLETED"
#
# Killing the sql thread that is waiting for a commit lock and restarting it
# will cause one transaction to be skipped on the slave. When sql thread is
# killed at this state its positions are updated in rli object but the
# transaction is yet to be committed. At the time of restart the rli object is
# read back causing a transaction to be missed. Post fix the positions in rli
# object will be rolled back. Test script ensures that rli's memory contents
# are in sync with the positions in rli repository.

--source include/not_gtid_enabled.inc
--source include/have_binlog_format_mixed.inc
--source include/master-slave.inc
--source include/have_debug.inc
--source include/have_innodb.inc
--source include/have_debug_sync.inc

call mtr.add_suppression("Query execution was interrupted.");
call mtr.add_suppression("The slave coordinator and worker threads are stopped, possibly leaving data in inconsistent state");

--echo # Let master and slave synced with t1 table created
CREATE TABLE t1 (f INT) ENGINE= INNODB;
--source include/sync_slave_sql_with_master.inc

--echo # Setup GLOBAL.DEBUG at slave to reach commit
--source include/rpl_connection_slave.inc
--let $debug_saved= `SELECT @@GLOBAL.DEBUG`
SET @@GLOBAL.DEBUG= '+d,dbug.reached_commit';

--echo # Do some DML operation on master so that it will be blocked on
--echo # slave as global read lock is in place.
--source include/rpl_connection_master.inc
INSERT INTO t1 VALUES (10);

--echo # Issue FLUSH TABLES WITH READ LOCK after Reached is signaled
--source include/rpl_connection_slave.inc
SET DEBUG_SYNC='now WAIT_FOR Reached';
FLUSH TABLES WITH READ LOCK;
--echo # Let sql thread continue to try to obtain commit lock
SET DEBUG_SYNC= 'now SIGNAL signal.commit_continue';

--echo # Wait until sql thread enters "Waiting for commit lock" state
let $wait_condition= SELECT COUNT(*) = 1 FROM information_schema.processlist
                     WHERE state = "Waiting for commit lock";
--source include/wait_condition.inc

--echo # Kill sql thread
let $sql_thread_id= `SELECT ID FROM information_schema.processlist
                     WHERE state= "Waiting for commit lock"`;
--disable_query_log
--eval KILL $sql_thread_id
--enable_query_log
--let $er_query_interrupted= convert_error(ER_QUERY_INTERRUPTED)
--let $er_mts_inconsistent_data= convert_error(ER_MTS_INCONSISTENT_DATA)
--let $slave_sql_errno= $er_query_interrupted, $er_mts_inconsistent_data
--source include/wait_for_slave_sql_error.inc

--echo # Restart sql thread to let it finish the replication
SET @@GLOBAL.DEBUG= '-d,dbug.reached_commit';
UNLOCK TABLES;
# Check to ensure that in memory rli positions are equal to the positions in
# slave's repository table.
if (`SELECT @@GLOBAL.relay_log_info_repository = 'TABLE'`)
{
  --let $slave_master_log_pos_in_repo= `SELECT Master_log_pos FROM mysql.slave_relay_log_info LIMIT 1`
}
if (`SELECT @@GLOBAL.relay_log_info_repository = 'FILE'`)
{
  --disable_query_log
  CREATE TABLE rli_table(rli_info VARCHAR(100));
  --let $MYSQLD_DATADIR= `select @@datadir`
  --let $rli_file=$MYSQLD_DATADIR/relay-log.info
  --replace_result $rli_file rli_file
  --eval LOAD DATA LOCAL INFILE '$rli_file' INTO TABLE rli_table
  --let $slave_master_log_pos_in_repo= `SELECT * FROM rli_table LIMIT 4,1`
  DROP TABLE rli_table;
  --enable_query_log
}

--let $slave_master_log_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1)
--let $assert_text= Exec_Master_Log_Pos in SHOW SLAVE STATUS must be equal to mater_log_pos in slave's repository
--let $assert_cond= $slave_master_log_pos = $slave_master_log_pos_in_repo
--source include/assert.inc
--source include/start_slave_sql.inc

# Check consistency
--source include/rpl_connection_master.inc
--source include/sync_slave_sql_with_master.inc
--let $diff_tables= master:t1, slave:t1
--source include/diff_tables.inc

# Cleanup
SET @@GLOBAL.DEBUG= '$debug_saved';
--source include/rpl_connection_master.inc
DROP TABLE t1;
--source include/rpl_end.inc
