summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro Gomes <pedro.gomes@oracle.com>2013-02-15 21:57:35 +0000
committerPedro Gomes <pedro.gomes@oracle.com>2013-02-15 21:57:35 +0000
commit99374f92022d21192b4db25074a6f08a4a1f06c0 (patch)
tree76e93daf7767dbb400bbf4724d4e52c5f9285a16
parent2a690f651d18d9554f662e88046cf3979595fe7d (diff)
downloadmariadb-git-99374f92022d21192b4db25074a6f08a4a1f06c0.tar.gz
BUG#13545447: RPL_ROTATE_LOGS FAILS DUE TO CONCURRENCY ISSUES IN REP. CODE
In method mysql_binlog_send, right after detecting a EOF in the read event loop, and before deciding if we should change to a new binlog file there is a execution window where new events can be written to the binlog and a rotation can happen. When reaching the test, the function will then change to a new binlog file ignoring all the events written in this window. This will result in events not being replicated. Only when the binlog is detected as deactivated in the event loop of the dump thread, can we really know that no more events remain. For this reason, this test is now made under the log lock in the beginning of the event loop when reading the events.
-rw-r--r--sql/log_event.cc8
-rw-r--r--sql/log_event.h30
-rw-r--r--sql/sql_repl.cc21
3 files changed, 52 insertions, 7 deletions
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 8abd95bba0a..7d2a80fdaf9 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1012,7 +1012,9 @@ bool Log_event::write_header(IO_CACHE* file, ulong event_data_length)
*/
int Log_event::read_log_event(IO_CACHE* file, String* packet,
- pthread_mutex_t* log_lock)
+ pthread_mutex_t* log_lock,
+ const char *log_file_name_arg,
+ bool* is_binlog_active)
{
ulong data_len;
int result=0;
@@ -1021,6 +1023,10 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
if (log_lock)
pthread_mutex_lock(log_lock);
+
+ if (log_file_name_arg)
+ *is_binlog_active= mysql_bin_log.is_active(log_file_name_arg);
+
if (my_b_read(file, (uchar*) buf, sizeof(buf)))
{
/*
diff --git a/sql/log_event.h b/sql/log_event.h
index 4c8580eb2fd..4fabb83aac7 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
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
@@ -945,8 +945,34 @@ public:
pthread_mutex_t* log_lock,
const Format_description_log_event
*description_event);
+
+ /**
+ Reads an event from a binlog or relay log. Used by the dump thread
+ this method reads the event into a raw buffer without parsing it.
+
+ @Note If mutex is 0, the read will proceed without mutex.
+
+ @Note If a log name is given than the method will check if the
+ given binlog is still active.
+
+ @param[in] file log file to be read
+ @param[out] packet packet to hold the event
+ @param[in] lock the lock to be used upon read
+ @param[in] log_file_name_arg the log's file name
+ @param[out] is_binlog_active is the current log still active
+
+ @retval 0 success
+ @retval LOG_READ_EOF end of file, nothing was read
+ @retval LOG_READ_BOGUS malformed event
+ @retval LOG_READ_IO io error while reading
+ @retval LOG_READ_MEM packet memory allocation failed
+ @retval LOG_READ_TRUNC only a partial event could be read
+ @retval LOG_READ_TOO_LARGE event too large
+ */
static int read_log_event(IO_CACHE* file, String* packet,
- pthread_mutex_t* log_lock);
+ pthread_mutex_t* log_lock,
+ const char *log_file_name_arg= NULL,
+ bool* is_binlog_active= false);
/*
init_show_field_list() prepares the column names and types for the
output of SHOW BINLOG EVENTS; it is used only by SHOW BINLOG
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index c15382c669e..6894eaa48b5 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
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
@@ -548,7 +548,10 @@ impossible position";
while (!net->error && net->vio != 0 && !thd->killed)
{
my_off_t prev_pos= pos;
- while (!(error = Log_event::read_log_event(&log, packet, log_lock)))
+ bool is_active_binlog= false;
+ while (!(error= Log_event::read_log_event(&log, packet, log_lock,
+ log_file_name,
+ &is_active_binlog)))
{
prev_pos= my_b_tell(&log);
#ifndef DBUG_OFF
@@ -624,6 +627,13 @@ impossible position";
error=LOG_READ_EOF;
}
+ DBUG_EXECUTE_IF("wait_after_binlog_EOF",
+ {
+ const char act[]= "now wait_for signal.rotate_finished";
+ DBUG_ASSERT(!debug_sync_set_action(current_thd,
+ STRING_WITH_LEN(act)));
+ };);
+
/*
TODO: now that we are logging the offset, check to make sure
the recorded offset and the actual match.
@@ -634,8 +644,11 @@ impossible position";
if (test_for_non_eof_log_read_errors(error, &errmsg))
goto err;
- if (!(flags & BINLOG_DUMP_NON_BLOCK) &&
- mysql_bin_log.is_active(log_file_name))
+ /*
+ We should only move to the next binlog when the last read event
+ came from a already deactivated binlog.
+ */
+ if (!(flags & BINLOG_DUMP_NON_BLOCK) && is_active_binlog)
{
/*
Block until there is more data in the log