Commit 510ca9b6 authored by Sergei Golubchik's avatar Sergei Golubchik

MDEV-7402 'reset master' hangs, waits for signalled COND_xid_list

Using a boolean flag for 'there is a RESET MASTER in progress' doesn't
work very well for multiple concurrent RESET MASTER statements.
Changed to a counter.
parent 73ebabd2
...@@ -112,6 +112,18 @@ master-bin.000003 # ...@@ -112,6 +112,18 @@ master-bin.000003 #
master-bin.000004 # master-bin.000004 #
master-bin.000005 # master-bin.000005 #
master-bin.000006 # master-bin.000006 #
SET debug_sync = 'reset';
*** MDEV-7402: 'reset master' hangs, waits for signalled COND_xid_list ***
SET debug_sync="reset_logs_after_set_reset_master_pending SIGNAL reset_master_ready WAIT_FOR reset_master_cont";
RESET MASTER;
SET @old_dbug= @@global.DEBUG_DBUG;
SET GLOBAL debug_dbug="+d,inject_binlog_background_thread_before_mark_xid_done";
SET debug_sync="now WAIT_FOR reset_master_ready";
RESET MASTER;
SET debug_sync="now WAIT_FOR injected_binlog_background_thread";
SET GLOBAL debug_dbug=@old_dbug;
SET debug_sync="now SIGNAL reset_master_cont";
SET debug_sync = 'reset';
DROP TABLE t1, t2; DROP TABLE t1, t2;
SET GLOBAL max_binlog_size= @old_max_binlog_size; SET GLOBAL max_binlog_size= @old_max_binlog_size;
SET GLOBAL innodb_flush_log_at_trx_commit= @old_innodb_flush_log_at_trx_commit; SET GLOBAL innodb_flush_log_at_trx_commit= @old_innodb_flush_log_at_trx_commit;
......
...@@ -138,8 +138,39 @@ SET DEBUG_SYNC= "now WAIT_FOR injected_binlog_background_thread"; ...@@ -138,8 +138,39 @@ SET DEBUG_SYNC= "now WAIT_FOR injected_binlog_background_thread";
SET GLOBAL debug_dbug= @old_dbug; SET GLOBAL debug_dbug= @old_dbug;
INSERT INTO t1 VALUES (31, REPEAT("x", 4100)); INSERT INTO t1 VALUES (31, REPEAT("x", 4100));
--source include/show_binary_logs.inc --source include/show_binary_logs.inc
SET debug_sync = 'reset';
--echo *** MDEV-7402: 'reset master' hangs, waits for signalled COND_xid_list ***
--source include/wait_for_binlog_checkpoint.inc
connect(con3,localhost,root,,);
# Make the binlog background thread wait before clearing the pending checkpoint.
# The bug was that one RESET MASTER would clear the reset_master_pending
# flag set by another RESET MASTER; this could cause the wakeup from the
# binlog background thread not to be sent, and thus the second RESET MASTER
# to wait infinitely.
SET debug_sync="reset_logs_after_set_reset_master_pending SIGNAL reset_master_ready WAIT_FOR reset_master_cont";
send RESET MASTER;
--connection default
SET @old_dbug= @@global.DEBUG_DBUG;
SET GLOBAL debug_dbug="+d,inject_binlog_background_thread_before_mark_xid_done";
SET debug_sync="now WAIT_FOR reset_master_ready";
RESET MASTER;
SET debug_sync="now WAIT_FOR injected_binlog_background_thread";
SET GLOBAL debug_dbug=@old_dbug;
SET debug_sync="now SIGNAL reset_master_cont";
--connection con3
REAP;
--connection default
SET debug_sync = 'reset';
# Clean up.
DROP TABLE t1, t2; DROP TABLE t1, t2;
SET GLOBAL max_binlog_size= @old_max_binlog_size; SET GLOBAL max_binlog_size= @old_max_binlog_size;
SET GLOBAL innodb_flush_log_at_trx_commit= @old_innodb_flush_log_at_trx_commit; SET GLOBAL innodb_flush_log_at_trx_commit= @old_innodb_flush_log_at_trx_commit;
......
...@@ -3031,7 +3031,7 @@ const char *MYSQL_LOG::generate_name(const char *log_name, ...@@ -3031,7 +3031,7 @@ const char *MYSQL_LOG::generate_name(const char *log_name,
MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period) MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period)
:reset_master_pending(false), mark_xid_done_waiting(0), :reset_master_pending(0), mark_xid_done_waiting(0),
bytes_written(0), file_id(1), open_count(1), bytes_written(0), file_id(1), open_count(1),
group_commit_queue(0), group_commit_queue_busy(FALSE), group_commit_queue(0), group_commit_queue_busy(FALSE),
num_commits(0), num_group_commits(0), num_commits(0), num_group_commits(0),
...@@ -3867,12 +3867,13 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd, bool create_new_log, ...@@ -3867,12 +3867,13 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd, bool create_new_log,
do this before we take the LOCK_log to not deadlock. do this before we take the LOCK_log to not deadlock.
*/ */
mysql_mutex_lock(&LOCK_xid_list); mysql_mutex_lock(&LOCK_xid_list);
reset_master_pending= true; reset_master_pending++;
while (mark_xid_done_waiting > 0) while (mark_xid_done_waiting > 0)
mysql_cond_wait(&COND_xid_list, &LOCK_xid_list); mysql_cond_wait(&COND_xid_list, &LOCK_xid_list);
mysql_mutex_unlock(&LOCK_xid_list); mysql_mutex_unlock(&LOCK_xid_list);
} }
DEBUG_SYNC(thd, "reset_logs_after_set_reset_master_pending");
if (thd) if (thd)
ha_reset_logs(thd); ha_reset_logs(thd);
/* /*
...@@ -4054,7 +4055,7 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd, bool create_new_log, ...@@ -4054,7 +4055,7 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd, bool create_new_log,
DBUG_ASSERT(b->xid_count == 0); DBUG_ASSERT(b->xid_count == 0);
my_free(binlog_xid_count_list.get()); my_free(binlog_xid_count_list.get());
} }
reset_master_pending= false; reset_master_pending--;
mysql_mutex_unlock(&LOCK_xid_list); mysql_mutex_unlock(&LOCK_xid_list);
} }
......
...@@ -470,7 +470,7 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG ...@@ -470,7 +470,7 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
anyway). Instead we should signal COND_xid_list whenever a new binlog anyway). Instead we should signal COND_xid_list whenever a new binlog
checkpoint arrives - when all have arrived, RESET MASTER will complete. checkpoint arrives - when all have arrived, RESET MASTER will complete.
*/ */
bool reset_master_pending; uint reset_master_pending;
ulong mark_xid_done_waiting; ulong mark_xid_done_waiting;
/* LOCK_log and LOCK_index are inited by init_pthread_objects() */ /* LOCK_log and LOCK_index are inited by init_pthread_objects() */
......
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