Skip to content

Commit a8ba02f

Browse files
author
Sujatha Sivakumar
committed
Merge branch 'mysql-5.5' into mysql-5.6
2 parents 5e0b6b3 + 8361151 commit a8ba02f

6 files changed

Lines changed: 147 additions & 23 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
include/master-slave.inc
2+
Warnings:
3+
Note #### Sending passwords in plain text without SSL/TLS is extremely insecure.
4+
Note #### Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information.
5+
[connection master]
6+
CREATE TABLE t1(a INT);
7+
INSERT INTO t1 VALUES(1);
8+
CALL mtr.add_suppression("Disk is full writing");
9+
CALL mtr.add_suppression("Retry in 60 secs");
10+
include/stop_slave_sql.inc
11+
SET @@GLOBAL.DEBUG= 'd,simulate_io_thd_wait_for_disk_space';
12+
INSERT INTO t1 VALUES(2);
13+
include/wait_for_slave_param.inc [Slave_IO_State]
14+
SET @@GLOBAL.DEBUG= '$debug_saved';
15+
include/assert_grep.inc [Found the disk full error message on the slave]
16+
include/start_slave_sql.inc
17+
DROP TABLE t1;
18+
include/rpl_end.inc
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# ==== Purpose ====
2+
#
3+
# Check that the execution of SHOW SLAVE STATUS command is not blocked when IO
4+
# thread is blocked waiting for disk space.
5+
#
6+
# ==== Implementation ====
7+
#
8+
# Simulate a scenario where IO thread is waiting for disk space while writing
9+
# into the relay log. Execute SHOW SLAVE STATUS command after IO thread is
10+
# blocked waiting for space. The command should not be blocked.
11+
#
12+
# ==== References ====
13+
#
14+
# Bug#21753696: MAKE SHOW SLAVE STATUS NON BLOCKING IF IO THREAD WAITS FOR
15+
# DISK SPACE
16+
# Bug#20685029: SLAVE IO THREAD SHOULD STOP WHEN DISK IS FULL
17+
#
18+
###############################################################################
19+
--source include/have_debug.inc
20+
--source include/master-slave.inc
21+
22+
# Generate events to be replicated to the slave
23+
CREATE TABLE t1(a INT);
24+
INSERT INTO t1 VALUES(1);
25+
--sync_slave_with_master
26+
27+
# Those errors will only happen in the slave
28+
CALL mtr.add_suppression("Disk is full writing");
29+
CALL mtr.add_suppression("Retry in 60 secs");
30+
31+
# Stop the SQL thread to avoid writing on disk
32+
--source include/stop_slave_sql.inc
33+
34+
# Set the debug option that will simulate disk full
35+
--let $debug_saved= `SELECT @@GLOBAL.DEBUG`
36+
SET @@GLOBAL.DEBUG= 'd,simulate_io_thd_wait_for_disk_space';
37+
38+
# Generate events to be replicated to the slave
39+
--connection master
40+
INSERT INTO t1 VALUES(2);
41+
42+
--connection slave
43+
# Wait until IO thread is queuing events from master
44+
# Notice that this is performed by querying SHOW SLAVE STATUS
45+
--let $slave_param= Slave_IO_State
46+
--let $slave_param_value= Queueing master event to the relay log
47+
--source include/wait_for_slave_param.inc
48+
49+
# Get the relay log file name, also using SHOW SLAVE STATUS
50+
--let $relay_log_file= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1)
51+
52+
# Restore the debug options to "simulate" freed space on disk
53+
SET @@GLOBAL.DEBUG= '$debug_saved';
54+
55+
# There should be a message in the error log of the slave stating
56+
# that it was waiting for space to write on the relay log.
57+
--let $assert_file=$MYSQLTEST_VARDIR/log/mysqld.2.err
58+
# Grep only after the message that the I/O thread has started
59+
--let $assert_only_after= Slave I/O .* connected to master .*replication started in log .* at position
60+
--let $assert_count= 1
61+
--let $assert_select=Disk is full writing .*$relay_log_file.* No space left on device
62+
--let $assert_text= Found the disk full error message on the slave
63+
--source include/assert_grep.inc
64+
65+
# Start the SQL thread to let the slave to sync and finish gracefully
66+
--source include/start_slave_sql.inc
67+
68+
# Cleanup
69+
--connection master
70+
DROP TABLE t1;
71+
--source include/rpl_end.inc

mysys/errors.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -109,6 +109,7 @@ void init_glob_errs()
109109
*/
110110
void wait_for_free_space(const char *filename, int errors)
111111
{
112+
size_t time_to_sleep= MY_WAIT_FOR_USER_TO_FIX_PANIC;
112113
if (!(errors % MY_WAIT_GIVE_USER_A_MESSAGE))
113114
{
114115
char errbuf[MYSYS_STRERROR_SIZE];
@@ -120,10 +121,14 @@ void wait_for_free_space(const char *filename, int errors)
120121
}
121122
DBUG_EXECUTE_IF("simulate_no_free_space_error",
122123
{
123-
(void) sleep(1);
124-
return;
124+
time_to_sleep= 1;
125125
});
126-
(void) sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC);
126+
DBUG_EXECUTE_IF("simulate_io_thd_wait_for_disk_space",
127+
{
128+
time_to_sleep= 1;
129+
});
130+
131+
(void) sleep(time_to_sleep);
127132
}
128133

129134
const char **get_global_errmsgs()

mysys/my_write.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -40,6 +40,7 @@ size_t my_write(File Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
4040
size_t writtenbytes;
4141
size_t sum_written= 0;
4242
uint errors= 0;
43+
size_t ToWriteCount;
4344
const size_t initial_count= Count;
4445

4546
DBUG_ENTER("my_write");
@@ -55,11 +56,14 @@ size_t my_write(File Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
5556
for (;;)
5657
{
5758
errno= 0;
59+
ToWriteCount= Count;
60+
DBUG_EXECUTE_IF("simulate_io_thd_wait_for_disk_space", { ToWriteCount= 1; });
5861
#ifdef _WIN32
59-
writtenbytes= my_win_write(Filedes, Buffer, Count);
62+
writtenbytes= my_win_write(Filedes, Buffer, ToWriteCount);
6063
#else
61-
writtenbytes= write(Filedes, Buffer, Count);
64+
writtenbytes= write(Filedes, Buffer, ToWriteCount);
6265
#endif
66+
DBUG_EXECUTE_IF("simulate_io_thd_wait_for_disk_space", { errno= ENOSPC; });
6367
DBUG_EXECUTE_IF("simulate_file_write_error",
6468
{
6569
errno= ENOSPC;

sql/binlog.cc

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -5067,9 +5067,6 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock_log, Format_description_log_even
50675067
@note The caller must hold LOCK_log before invoking this function.
50685068
50695069
@param mi Master_info for the IO thread.
5070-
@param need_data_lock If true, mi->data_lock will be acquired if a
5071-
rotation is needed. Otherwise, mi->data_lock must be held by the
5072-
caller.
50735070
50745071
@retval false success
50755072
@retval true error
@@ -5081,7 +5078,6 @@ bool MYSQL_BIN_LOG::after_append_to_relay_log(Master_info *mi)
50815078

50825079
// Check pre-conditions
50835080
mysql_mutex_assert_owner(&LOCK_log);
5084-
mysql_mutex_assert_owner(&mi->data_lock);
50855081
DBUG_ASSERT(is_relay_log);
50865082
DBUG_ASSERT(current_thd->system_thread == SYSTEM_THREAD_SLAVE_IO);
50875083

@@ -5095,13 +5091,28 @@ bool MYSQL_BIN_LOG::after_append_to_relay_log(Master_info *mi)
50955091
if ((uint) my_b_append_tell(&log_file) >
50965092
DBUG_EVALUATE_IF("rotate_slave_debug_group", 500, max_size))
50975093
{
5094+
/*
5095+
If rotation is required we must acquire data_lock to protect
5096+
description_event from clients executing FLUSH LOGS in parallel.
5097+
In order do that we must release the existing LOCK_log so that we
5098+
get it once again in proper locking order to avoid dead locks.
5099+
i.e data_lock , LOCK_log.
5100+
*/
5101+
mysql_mutex_unlock(&LOCK_log);
5102+
mysql_mutex_lock(&mi->data_lock);
5103+
mysql_mutex_lock(&LOCK_log);
50985104
error= new_file_without_locking(mi->get_mi_description_event());
50995105
DBUG_EXECUTE_IF ("set_max_size_zero",
51005106
{
51015107
max_size=1073741824;
51025108
DBUG_SET("-d,set_max_size_zero");
51035109
DBUG_SET("-d,flush_after_reading_gtid_event");
51045110
});
5111+
/*
5112+
After rotation release data_lock, we need the LOCK_log till we signal
5113+
the updation.
5114+
*/
5115+
mysql_mutex_unlock(&mi->data_lock);
51055116
}
51065117
}
51075118

@@ -5113,14 +5124,21 @@ bool MYSQL_BIN_LOG::after_append_to_relay_log(Master_info *mi)
51135124

51145125
bool MYSQL_BIN_LOG::append_event(Log_event* ev, Master_info *mi)
51155126
{
5116-
DBUG_ENTER("MYSQL_BIN_LOG::append");
5127+
DBUG_ENTER("MYSQL_BIN_LOG::append_event");
51175128

5129+
mysql_mutex_assert_owner(&mi->data_lock);
5130+
mysql_mutex_lock(&LOCK_log);
51185131
// check preconditions
51195132
DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
51205133
DBUG_ASSERT(is_relay_log);
51215134

5122-
// acquire locks
5123-
mysql_mutex_lock(&LOCK_log);
5135+
/*
5136+
Release data_lock by holding LOCK_log, while writing into the relay log.
5137+
If slave IO thread waits here for free space, we don't want
5138+
SHOW SLAVE STATUS to hang on mi->data_lock. Note LOCK_log mutex is
5139+
sufficient to block SQL thread when IO thread is updating relay log here.
5140+
*/
5141+
mysql_mutex_unlock(&mi->data_lock);
51245142

51255143
// write data
51265144
bool error = false;
@@ -5133,6 +5151,7 @@ bool MYSQL_BIN_LOG::append_event(Log_event* ev, Master_info *mi)
51335151
error= true;
51345152

51355153
mysql_mutex_unlock(&LOCK_log);
5154+
mysql_mutex_lock(&mi->data_lock);
51365155
DBUG_RETURN(error);
51375156
}
51385157

@@ -5141,11 +5160,18 @@ bool MYSQL_BIN_LOG::append_buffer(const char* buf, uint len, Master_info *mi)
51415160
{
51425161
DBUG_ENTER("MYSQL_BIN_LOG::append_buffer");
51435162

5163+
mysql_mutex_assert_owner(&mi->data_lock);
5164+
mysql_mutex_lock(&LOCK_log);
51445165
// check preconditions
51455166
DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
51465167
DBUG_ASSERT(is_relay_log);
5147-
mysql_mutex_assert_owner(&LOCK_log);
5148-
5168+
/*
5169+
Release data_lock by holding LOCK_log, while writing into the relay log.
5170+
If slave IO thread waits here for free space, we don't want
5171+
SHOW SLAVE STATUS to hang on mi->data_lock. Note LOCK_log mutex is
5172+
sufficient to block SQL thread when IO thread is updating relay log here.
5173+
*/
5174+
mysql_mutex_unlock(&mi->data_lock);
51495175
// write data
51505176
bool error= false;
51515177
if (my_b_append(&log_file,(uchar*) buf,len) == 0)
@@ -5156,6 +5182,8 @@ bool MYSQL_BIN_LOG::append_buffer(const char* buf, uint len, Master_info *mi)
51565182
else
51575183
error= true;
51585184

5185+
mysql_mutex_unlock(&LOCK_log);
5186+
mysql_mutex_lock(&mi->data_lock);
51595187
DBUG_RETURN(error);
51605188
}
51615189
#endif // ifdef HAVE_REPLICATION

sql/rpl_slave.cc

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7114,7 +7114,6 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
71147114
direct master (an unsupported, useless setup!).
71157115
*/
71167116

7117-
mysql_mutex_lock(log_lock);
71187117
s_id= uint4korr(buf + SERVER_ID_OFFSET);
71197118

71207119
/*
@@ -7155,6 +7154,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
71557154
IGNORE_SERVER_IDS it increments mi->get_master_log_pos()
71567155
as well as rli->group_relay_log_pos.
71577156
*/
7157+
mysql_mutex_lock(log_lock);
71587158
if (!(s_id == ::server_id && !mi->rli->replicate_same_server_id) ||
71597159
(event_type != FORMAT_DESCRIPTION_EVENT &&
71607160
event_type != ROTATE_EVENT &&
@@ -7166,6 +7166,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
71667166
rli->ign_master_log_pos_end= mi->get_master_log_pos();
71677167
}
71687168
rli->relay_log.signal_update(); // the slave SQL thread needs to re-check
7169+
mysql_mutex_unlock(log_lock);
71697170
DBUG_PRINT("info", ("master_log_pos: %lu, event originating from %u server, ignored",
71707171
(ulong) mi->get_master_log_pos(), uint4korr(buf + SERVER_ID_OFFSET)));
71717172
}
@@ -7194,10 +7195,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
71947195
rli->set_last_retrieved_gtid(gtid);
71957196
global_sid_lock->unlock();
71967197
if (ret != 0)
7197-
{
7198-
mysql_mutex_unlock(log_lock);
71997198
goto err;
7200-
}
72017199
}
72027200
/* write the event to the relay log */
72037201
if (!DBUG_EVALUATE_IF("simulate_append_buffer_error", 1, 0) &&
@@ -7216,7 +7214,6 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
72167214
if (retrieved_set->_remove_gtid(gtid) != RETURN_STATUS_OK)
72177215
{
72187216
global_sid_lock->unlock();
7219-
mysql_mutex_unlock(log_lock);
72207217
goto err;
72217218
}
72227219
if (!old_retrieved_gtid.empty())
@@ -7225,11 +7222,12 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
72257222
}
72267223
error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE;
72277224
}
7225+
mysql_mutex_lock(log_lock);
72287226
rli->ign_master_log_name_end[0]= 0; // last event is not ignored
7227+
mysql_mutex_unlock(log_lock);
72297228
if (save_buf != NULL)
72307229
buf= save_buf;
72317230
}
7232-
mysql_mutex_unlock(log_lock);
72337231

72347232
skip_relay_logging:
72357233

0 commit comments

Comments
 (0)