commit 512dc1588e140d6d13b020621634565c904ae817 Author: GAO Xiaoxin Date: Mon Mar 9 14:30:05 2020 +0800 Bug #98877 Binary log rotate not wait for xa prepare and xa commit and xa rollback to finish Binary log rotate will not wait for xa prepare and xa commit and xa rollback to finish In current mysql code, mysql will not do inc_prep_xids for xa prepare and xa commit, so that the MYSQL_BIN_LOG::new_file_impl will not waiting for xa prepre and xa commit to finish the engine operation. If the binlog rotate during xa prepare/ xa commit execution(after flush binlog before engine commit), and mysql crash, the xa prepare and xa commit may lost due to the latest binlog file does not contain the related binlog events. For fix: 1. add with_xa_prepare and with_xa_commit and with_xa_rollback flag for binlog_cache_data::flags 2. do inc_prep_xids for with_xa_prepare and with_xa_commit and with_xa_rollback flag diff --git a/sql/binlog.cc b/sql/binlog.cc index 6ee0e69..88ff4c3 100644 --- a/sql/binlog.cc +++ b/sql/binlog.cc @@ -489,6 +489,9 @@ public: flags.incident= false; flags.with_xid= false; + flags.with_xa_prepare= false; + flags.with_xa_commit= false; + flags.with_xa_rollback= false; flags.immediate= false; flags.finalized= false; flags.with_sbr= false; @@ -593,6 +596,9 @@ public: !flags.with_rbr && // No rows changing content !flags.immediate && // Not a DDL !flags.with_xid && // Not a XID transaction and not an atomic DDL Query + !flags.with_xa_prepare && + !flags.with_xa_commit && + !flags.with_xa_rollback && !flags.with_content)// Does not have any content { DBUG_ASSERT(!flags.with_sbr); // No statements changing content @@ -707,6 +713,21 @@ protected: bool with_xid:1; /* + This indicates that the cache contain an XA PREPARE event. + */ + bool with_xa_prepare:1; + + /* + This indicates that the cache contain an XA COMMIT event. + */ + bool with_xa_commit:1; + + /* + This indicates that the cache contain an XA ROLLBACK event AFTER PREPARE. + */ + bool with_xa_rollback:1; + + /* This indicates that the cache contain statements changing content. */ bool with_sbr:1; @@ -1400,6 +1421,17 @@ int binlog_cache_data::write_event(THD *thd, Log_event *ev) } if (ev->get_type_code() == binary_log::XID_EVENT) flags.with_xid= true; + else if (ev->get_type_code() == binary_log::XA_PREPARE_LOG_EVENT) + flags.with_xa_prepare= true; + else if (ev->get_type_code() == binary_log::QUERY_EVENT && + !native_strncasecmp(((Query_log_event *)ev)->query, + STRING_WITH_LEN("XA COMMIT"))) + flags.with_xa_commit= true; + else if (ev->get_type_code() == binary_log::QUERY_EVENT && + !native_strncasecmp(((Query_log_event *)ev)->query, + STRING_WITH_LEN("XA ROLLBACK"))) + flags.with_xa_rollback= true; + if (ev->is_using_immediate_logging()) flags.immediate= true; /* With respect to the event type being written */ @@ -1756,7 +1788,7 @@ binlog_cache_data::flush(THD *thd, my_off_t *bytes_written, bool *wrote_xid) if (!error) error= mysql_bin_log.write_cache(thd, this, &writer); - if (flags.with_xid && error == 0) + if ((flags.with_xid || flags.with_xa_prepare || flags.with_xa_commit || flags.with_xa_rollback) && error == 0) *wrote_xid= true; /*