From: Frazer Clement Date: March 9 2012 3:26pm Subject: bzr push into mysql-trunk branch (frazer.clement:3744 to 3745) Bug#54854 List-Archive: http://lists.mysql.com/commits/143150 X-Bug: 54854 Message-Id: <201203091526.q29FQvpU005656@acsmt356.oracle.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 3745 Frazer Clement 2012-03-09 Bug#54854 Can't find good position for replication break between DDL statements Commit of mysql-trunk patches for PB2 test-build modified: sql/binlog.cc sql/binlog.h sql/log.h sql/log_event.h sql/rpl_injector.cc sql/rpl_injector.h sql/sql_class.cc sql/sql_class.h 3744 Jorgen Loland 2012-03-09 Bug#13810145: FIX WARNINGS BY FORTIFY @ sql/opt_range.cc Fix Fortify warning modified: sql/opt_range.cc === modified file 'sql/binlog.cc' --- a/sql/binlog.cc 2012-03-06 14:29:42 +0000 +++ b/sql/binlog.cc 2012-03-09 15:24:52 +0000 @@ -4160,6 +4160,19 @@ MYSQL_BIN_LOG::remove_pending_rows_event } /* + Updates thd's position-of-next-event variables + after a *real* write a file. + */ +void MYSQL_BIN_LOG::update_thd_next_event_pos(THD* thd) +{ + if (likely(thd != NULL)) + { + thd->set_next_event_pos(log_file_name, + my_b_tell(&log_file)); + } +} + +/* Moves the last bunch of rows from the pending Rows event to a cache (either transactional cache if is_transaction is @c true, or the non-transactional cache otherwise. Sets a new pending event. @@ -4924,12 +4937,14 @@ bool MYSQL_BIN_LOG::write_cache(THD *thd mysql_mutex_lock(&LOCK_prep_xids); prepared_xids++; mysql_mutex_unlock(&LOCK_prep_xids); + update_thd_next_event_pos(thd); mysql_mutex_unlock(&LOCK_log); } else { if (rotate(false, &check_purge)) goto err; + update_thd_next_event_pos(thd); mysql_mutex_unlock(&LOCK_log); if (check_purge) purge(); === modified file 'sql/binlog.h' --- a/sql/binlog.h 2012-01-26 10:53:34 +0000 +++ b/sql/binlog.h 2012-03-09 15:24:52 +0000 @@ -213,6 +213,7 @@ public: int recover(IO_CACHE *log, Format_description_log_event *fdle); #if !defined(MYSQL_CLIENT) + void update_thd_next_event_pos(THD *thd); int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event, bool is_transactional); int remove_pending_rows_event(THD *thd, bool is_transactional); === modified file 'sql/log.h' --- a/sql/log.h 2011-12-09 21:08:37 +0000 +++ b/sql/log.h 2012-03-09 15:24:52 +0000 @@ -19,6 +19,21 @@ #include "unireg.h" // REQUIRED: for other includes #include "handler.h" /* my_xid */ +/** + the struct aggregates two paramenters that identify an event + uniquely in scope of communication of a particular master and slave couple. + I.e there can not be 2 events from the same staying connected master which + have the same coordinates. + @note + Such identifier is not yet unique generally as the event originating master + is resetable. Also the crashed master can be replaced with some other. +*/ +typedef struct event_coordinates +{ + char * file_name; // binlog file name (directories stripped) + my_off_t pos; // event's position in the binlog file +} LOG_POS_COORD; + /* Transaction Coordinator log - a base abstract class for two different implementations === modified file 'sql/log_event.h' --- a/sql/log_event.h 2012-03-06 14:29:42 +0000 +++ b/sql/log_event.h 2012-03-09 15:24:52 +0000 @@ -812,21 +812,6 @@ typedef struct st_print_event_info #endif /** - the struct aggregates two paramenters that identify an event - uniquely in scope of communication of a particular master and slave couple. - I.e there can not be 2 events from the same staying connected master which - have the same coordinates. - @note - Such identifier is not yet unique generally as the event originating master - is resetable. Also the crashed master can be replaced with some other. -*/ -typedef struct event_coordinates -{ - char * file_name; // binlog file name (directories stripped) - my_off_t pos; // event's position in the binlog file -} LOG_POS_COORD; - -/** @class Log_event This is the abstract base class for binary log events. === modified file 'sql/rpl_injector.cc' --- a/sql/rpl_injector.cc 2012-03-06 14:29:42 +0000 +++ b/sql/rpl_injector.cc 2012-03-09 15:24:52 +0000 @@ -41,6 +41,28 @@ injector::transaction::transaction(MYSQL m_start_pos.m_file_name= my_strdup(log_info.log_file_name, MYF(0)); m_start_pos.m_file_pos= log_info.pos; + if (unlikely(m_start_pos.m_file_name == NULL)) + { + m_thd= NULL; + return; + } + + /* + Next pos is unknown until after commit of the Binlog transaction + */ + m_next_pos.m_file_name= 0; + m_next_pos.m_file_pos= 0; + + /* + Ensure we don't pick up this thd's last written Binlog pos in + empty-transaction-commit cases. + This is not ideal, as it zaps this information for any other + usage (e.g. WL4047) + Potential improvement : save the 'old' next pos prior to + commit, and restore on error. + */ + m_thd->clear_next_event_pos(); + trans_begin(m_thd); } @@ -50,16 +72,18 @@ injector::transaction::~transaction() return; /* Needed since my_free expects a 'char*' (instead of 'void*'). */ - char* const the_memory= const_cast(m_start_pos.m_file_name); + char* const start_pos_memory= const_cast(m_start_pos.m_file_name); - /* - We set the first character to null just to give all the copies of the - start position a (minimal) chance of seening that the memory is lost. - All assuming the my_free does not step over the memory, of course. - */ - *the_memory= '\0'; - - my_free(the_memory); + if (start_pos_memory) + { + my_free(start_pos_memory); + } + + char* const next_pos_memory= const_cast(m_next_pos.m_file_name); + if (next_pos_memory) + { + my_free(next_pos_memory); + } } /** @@ -95,6 +119,22 @@ int injector::transaction::commit() close_thread_tables(m_thd); m_thd->mdl_context.release_transactional_locks(); } + + /* Copy next position out into our next pos member */ + if ((error == 0) && + (m_thd->binlog_next_event_pos.file_name != NULL) && + ((m_next_pos.m_file_name= + my_strdup(m_thd->binlog_next_event_pos.file_name, MYF(0))) != NULL)) + { + m_next_pos.m_file_pos= m_thd->binlog_next_event_pos.pos; + } + else + { + /* Error, problem copying etc. */ + m_next_pos.m_file_name= NULL; + m_next_pos.m_file_pos= 0; + } + DBUG_RETURN(error); } @@ -199,6 +239,10 @@ injector::transaction::binlog_pos inject return m_start_pos; } +injector::transaction::binlog_pos injector::transaction::next_pos() const +{ + return m_next_pos; +} /* injector - member definitions === modified file 'sql/rpl_injector.h' --- a/sql/rpl_injector.h 2011-09-28 09:12:47 +0000 +++ b/sql/rpl_injector.h 2012-03-09 15:24:52 +0000 @@ -241,14 +241,30 @@ public: /* Get the position for the start of the transaction. - Returns the position in the binary log of the first event in this - transaction. If no event is yet written, the position where the event - *will* be written is returned. This position is known, since a - new_transaction() will lock the binary log and prevent any other - writes to the binary log. + This is the current 'tail of Binlog' at the time the transaction + was started. The first event recorded by the transaction may + be at this, or some subsequent position. The first event recorded + by the transaction will not be before this position. */ binlog_pos start_pos() const; + /* + Get the next position after the end of the transaction + + This call is only valid after a transaction has been committed. + It returns the next Binlog position after the committed transaction. + It is guaranteed that no other events will be recorded between the + COMMIT event of the Binlog transaction, and this position. + Note that this position may be in a different log file to the COMMIT + event. + + If the commit had an error, or the transaction was empty and nothing + was binlogged then the next_pos will have a NULL file_name(), and + 0 file_pos(). + + */ + binlog_pos next_pos() const; + private: /* Only the injector may construct these object */ transaction(MYSQL_BIN_LOG *, THD *); @@ -261,6 +277,13 @@ public: o.m_start_pos= tmp; } + /* std::swap(m_end_pos, o.m_end_pos); */ + { + binlog_pos const tmp= m_next_pos; + m_next_pos= o.m_next_pos; + o.m_next_pos= tmp; + } + /* std::swap(m_thd, o.m_thd); */ { THD* const tmp= m_thd; @@ -333,6 +356,7 @@ public: binlog_pos m_start_pos; + binlog_pos m_next_pos; THD *m_thd; }; === modified file 'sql/sql_class.cc' --- a/sql/sql_class.cc 2012-03-06 14:29:42 +0000 +++ b/sql/sql_class.cc 2012-03-09 15:24:52 +0000 @@ -930,6 +930,9 @@ THD::THD(bool enable_plugins) m_binlog_invoker= FALSE; memset(&invoker_user, 0, sizeof(invoker_user)); memset(&invoker_host, 0, sizeof(invoker_host)); + + binlog_next_event_pos.file_name= NULL; + binlog_next_event_pos.pos= 0; } @@ -1418,6 +1421,8 @@ THD::~THD() if (m_enable_plugins) plugin_thdvar_cleanup(this); + clear_next_event_pos(); + DBUG_PRINT("info", ("freeing security context")); main_security_ctx.destroy(); my_free(db); @@ -4538,3 +4543,30 @@ void COPY_INFO::set_function_defaults(TA } DBUG_VOID_RETURN; } + +void THD::set_next_event_pos(const char* _filename, ulonglong _pos) +{ + char*& filename= binlog_next_event_pos.file_name; + if (filename == NULL) + { + /* First time, allocate maximal buffer */ + filename= (char*) my_malloc(FN_REFLEN+1, MYF(MY_WME)); + if (filename == NULL) return; + } + + assert(strlen(_filename) <= FN_REFLEN); + strcpy(filename, _filename); + filename[ FN_REFLEN ]= 0; + + binlog_next_event_pos.pos= _pos; +}; + +void THD::clear_next_event_pos() +{ + if (binlog_next_event_pos.file_name != NULL) + { + my_free(binlog_next_event_pos.file_name); + } + binlog_next_event_pos.file_name= NULL; + binlog_next_event_pos.pos= 0; +}; === modified file 'sql/sql_class.h' --- a/sql/sql_class.h 2012-03-06 14:29:42 +0000 +++ b/sql/sql_class.h 2012-03-09 15:24:52 +0000 @@ -2348,6 +2348,15 @@ public: /* container for handler's private per-connection data */ Ha_data ha_data[MAX_HA]; + /* + Position of first event in Binlog + *after* last event written by this + thread. + */ + event_coordinates binlog_next_event_pos; + void set_next_event_pos(const char* _filename, ulonglong _pos); + void clear_next_event_pos(); + #ifndef MYSQL_CLIENT int binlog_setup_trx_data(); No bundle (reason: useless for push emails).