diff --git a/sql/log_event.cc b/sql/log_event.cc index a484123b4c7..cd94ee2804d 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1805,10 +1805,21 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) position to store is of the END of the current log event. */ #if MYSQL_VERSION_ID < 40100 - rli->future_master_log_pos= log_pos + get_event_len(); + /* + If the event was converted from a 3.23 format, get_event_len() has grown by + 6 bytes (at least for most events, except LOAD DATA INFILE which is already + a big problem for 3.23->4.0 replication); 6 bytes is the difference between + the header's size in 4.0 (LOG_EVENT_HEADER_LEN) and the header's size in + 3.23 (OLD_HEADER_LEN). Note that using mi->old_format will not help if the + I/O thread has not started yet. + */ + rli->future_master_log_pos= log_pos + get_event_len() - + (rli->mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0); #elif MYSQL_VERSION_ID < 50000 - rli->future_group_master_log_pos= log_pos + get_event_len(); + rli->future_group_master_log_pos= log_pos + get_event_len() - + (rli->mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0); #else + /* In 5.0 we store the end_log_pos in the relay log so no problem */ rli->future_group_master_log_pos= log_pos; #endif clear_all_errors(thd, rli); @@ -1960,9 +1971,11 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, if (!use_rli_only_for_errors) { #if MYSQL_VERSION_ID < 40100 - rli->future_master_log_pos= log_pos + get_event_len(); + rli->future_master_log_pos= log_pos + get_event_len() - + (rli->mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0); #elif MYSQL_VERSION_ID < 50000 - rli->future_group_master_log_pos= log_pos + get_event_len(); + rli->future_group_master_log_pos= log_pos + get_event_len() - + (rli->mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0); #else rli->future_group_master_log_pos= log_pos; #endif @@ -2133,6 +2146,11 @@ Fatal error running LOAD DATA INFILE on table '%s'. Default database: '%s'", int Start_log_event::exec_event(struct st_relay_log_info* rli) { + /* + If the I/O thread has not started, mi->old_format is BINLOG_FORMAT_CURRENT + (that's what the MASTER_INFO constructor does), so the test below is not + perfect at all. + */ switch (rli->mi->old_format) { case BINLOG_FORMAT_CURRENT : /* @@ -2427,9 +2445,11 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) */ #if MYSQL_VERSION_ID < 40100 - rli->future_master_log_pos= log_pos + get_event_len(); + rli->future_master_log_pos= log_pos + get_event_len() - + (rli->mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0); #elif MYSQL_VERSION_ID < 50000 - rli->future_group_master_log_pos= log_pos + get_event_len(); + rli->future_group_master_log_pos= log_pos + get_event_len() - + (rli->mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0); #else rli->future_group_master_log_pos= log_pos; #endif diff --git a/sql/slave.cc b/sql/slave.cc index d6dda473be0..9e82a521cb3 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -329,6 +329,52 @@ void init_slave_skip_errors(const char* arg) } } +void st_relay_log_info::inc_pending(ulonglong val) +{ + pending += val; +} + +/* TODO: this probably needs to be fixed */ +void st_relay_log_info::inc_pos(ulonglong val, ulonglong log_pos, bool skip_lock) +{ + if (!skip_lock) + pthread_mutex_lock(&data_lock); + relay_log_pos += val+pending; + pending = 0; + if (log_pos) +#if MYSQL_VERSION_ID < 50000 + /* + If the event was converted from a 3.23 format, get_event_len() has + grown by 6 bytes (at least for most events, except LOAD DATA INFILE + which is already a big problem for 3.23->4.0 replication); 6 bytes is + the difference between the header's size in 4.0 (LOG_EVENT_HEADER_LEN) + and the header's size in 3.23 (OLD_HEADER_LEN). Note that using + mi->old_format will not help if the I/O thread has not started yet. + Yes this is a hack but it's just to make 3.23->4.x replication work; + 3.23->5.0 replication is working much better. + + The line "mi->old_format ? : " below should NOT BE MERGED to 5.0 which + already works. But it SHOULD be merged to 4.1. + */ + master_log_pos= log_pos + val - + (mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0); +#endif + pthread_cond_broadcast(&data_cond); + if (!skip_lock) + pthread_mutex_unlock(&data_lock); +} + +/* + thread safe read of position - not needed if we are in the slave thread, + but required otherwise as var is a longlong +*/ +void st_relay_log_info::read_pos(ulonglong& var) +{ + pthread_mutex_lock(&data_lock); + var = relay_log_pos; + pthread_mutex_unlock(&data_lock); +} + void st_relay_log_info::close_temporary_tables() { TABLE *table,*next; diff --git a/sql/slave.h b/sql/slave.h index 4a6389e9f87..979c63af201 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -210,34 +210,9 @@ typedef struct st_relay_log_info st_relay_log_info(); ~st_relay_log_info(); - inline void inc_pending(ulonglong val) - { - pending += val; - } - /* TODO: this probably needs to be fixed */ - inline void inc_pos(ulonglong val, ulonglong log_pos, bool skip_lock=0) - { - if (!skip_lock) - pthread_mutex_lock(&data_lock); - relay_log_pos += val+pending; - pending = 0; - if (log_pos) - master_log_pos = log_pos+ val; - pthread_cond_broadcast(&data_cond); - if (!skip_lock) - pthread_mutex_unlock(&data_lock); - } - /* - thread safe read of position - not needed if we are in the slave thread, - but required otherwise as var is a longlong - */ - inline void read_pos(ulonglong& var) - { - pthread_mutex_lock(&data_lock); - var = relay_log_pos; - pthread_mutex_unlock(&data_lock); - } - + void inc_pending(ulonglong val); + void inc_pos(ulonglong val, ulonglong log_pos, bool skip_lock=0); + void read_pos(ulonglong& var); int wait_for_pos(THD* thd, String* log_name, longlong log_pos, longlong timeout); void close_temporary_tables();