Skip to content
  • Venkatesh Duggirala's avatar
    2a47f6ea
    BUG#25040331: INTERLEAVED XA TRANSACTIONS MAY DEADLOCK SLAVE APPLIER · 2a47f6ea
    Venkatesh Duggirala authored
                  WITH REPEATABLE READ
    
    Problem and Analysis
    --------------------
    
        Because of the use of MTS and/or XA transactions, the order statements
        from distinct transactions were originally applied on the master may not
        be the same order they are applied on the slave.
    
        On those cases, using RBR with a transaction isolation level other than
        READ COMMITTED might might lead to blocking conditions that didn't
        happened on the original workload (see BUG#25082593).
    
    Fix
    ---
    
        We are now using a flag on the [Anonymous_gtid|Gtid]_log_event stating
        if the transaction might have changes logged with statements.
    
        When this flag is set (default for non-fixed servers) the slave will not
        change the applier thread transaction isolation level.
    
        When the flag is not set, the applier will set the transaction isolation
        level of the current transaction to READ COMMITTED if necessary (it will
        not change it when the applier session isolation level be equal or less
        restrictive than READ COMMITTED).
    
        In this way, we are forcing that all transactions replicated using row
        based replication will always use the READ COMMITTED transaction
        isolation level on the slave side, regardless of any server transaction
        isolation level configuration.
    
        The fix also restored the applier session transaction isolation level
        after applying a Xid_log_event (after committing a replicated
        transaction), a XA_prepare_log_event (after preparing a replicated
        transaction) and in the cases of aborted/failed transactions.
    
        The mysqlbinlog dump of a transaction flagged as "rbr_only" will also
        include a "SET TRANSACTION ISOLATION LEVEL" statement when dumping the
        GTID event.
    
    Changed files:
    
        @ libbinlogevents/include/control_events.h
    
          We gave a meaning to the already logged flag information.
    
        @ libbinlogevents/src/control_events.cpp
    
          Processed the GTID flags, collecting the "might_have_sbr_stmts" info.
    
        @ plugin/replication_observers_example/replication_observers_example.cc
        @ rapid/plugin/group_replication/src/observer_trans.cc
        @ rapid/plugin/group_replication/src/handlers/certification_handler.cc
    
          Fixed calls to GTID constructor.
    
        @ sql/binlog.cc
    
          Created a new flag at "binlog_cache_data" named "with_sbr" that is
          set true when the cache is fed with non-terminal query event.
    
          Created a new flag at "binlog_cache_data" named "with_rbr" that is
          set true when the cache is fed with Table_map or Rows event.
    
          Created also the "might_have_sbr_stmts" function, that returns false
          for "pure RBR" transactions. This new function was implemented for
          the "binlog_cache_data".
    
          Added the logic to reset and set the new flags at
          "binlog_cache_data::reset" and "binlog_cache_data::write_event", and
          also to preserve the flags upon "SAVEPOINT/ROLLBACK TO SAVEPOINT".
    
          Made "MYSQL_BIN_LOG::write_gtid" to consider the cache information
          about the binary log content when creating the Gtid_log_event.
    
        @ sql/log_event.h
    
          Updated "Query_log_event::is_trans_keyword()" to recognize XA
          transactions terminal keywords that should not be considered as
          statements changing content.
    
          Created a new function "Log_event::is_sbr_logging_format()" that
          will return true if the event was/has to be logged using SBR and
          does not contains a transaction control statement.
    
          Created a new function "Log_event::is_rbr_logging_format()" that
          will return true if the event was/has to be logged using RBR.
    
        @ sql/log_event.cc
    
          We will stop the applier with an error when we assumed the
          transaction as "rbr_only" and some statement changing content be
          applied.
    
          Restored the applier session transaction isolation level
          after applying a Xid_log_event (after committing a replicated
          transaction), a XA_prepare_log_event (after preparing a replicated
          transaction) and in the cases of aborted/failed transactions.
    
          "Gtid_log_event::print" will now also print "rbr_only=[yes|no]" when
          dumping a Gtid_log_event with mysqlbinlog. It will also include a
          "SET TRANSACTION ISOLATION LEVEL READ COMMITTED" statement when
          dumping the GTID event with "rbr_only=yes".
    
          "Gtid_log_event::write_post_header_to_memory" now computes the GTID
          flags field instead of just writing "1" to it.
    
          "Gtid_log_event::do_apply_event" now set the transaction isolation
          level to READ COMMITTED when the "might_have_sbr_stmts" flag be false.
          Note that we don't change the isolation level for skipped GTID and
          when the isolation level be less restrictive than READ COMMITTED.
    2a47f6ea
    BUG#25040331: INTERLEAVED XA TRANSACTIONS MAY DEADLOCK SLAVE APPLIER
    Venkatesh Duggirala authored
                  WITH REPEATABLE READ
    
    Problem and Analysis
    --------------------
    
        Because of the use of MTS and/or XA transactions, the order statements
        from distinct transactions were originally applied on the master may not
        be the same order they are applied on the slave.
    
        On those cases, using RBR with a transaction isolation level other than
        READ COMMITTED might might lead to blocking conditions that didn't
        happened on the original workload (see BUG#25082593).
    
    Fix
    ---
    
        We are now using a flag on the [Anonymous_gtid|Gtid]_log_event stating
        if the transaction might have changes logged with statements.
    
        When this flag is set (default for non-fixed servers) the slave will not
        change the applier thread transaction isolation level.
    
        When the flag is not set, the applier will set the transaction isolation
        level of the current transaction to READ COMMITTED if necessary (it will
        not change it when the applier session isolation level be equal or less
        restrictive than READ COMMITTED).
    
        In this way, we are forcing that all transactions replicated using row
        based replication will always use the READ COMMITTED transaction
        isolation level on the slave side, regardless of any server transaction
        isolation level configuration.
    
        The fix also restored the applier session transaction isolation level
        after applying a Xid_log_event (after committing a replicated
        transaction), a XA_prepare_log_event (after preparing a replicated
        transaction) and in the cases of aborted/failed transactions.
    
        The mysqlbinlog dump of a transaction flagged as "rbr_only" will also
        include a "SET TRANSACTION ISOLATION LEVEL" statement when dumping the
        GTID event.
    
    Changed files:
    
        @ libbinlogevents/include/control_events.h
    
          We gave a meaning to the already logged flag information.
    
        @ libbinlogevents/src/control_events.cpp
    
          Processed the GTID flags, collecting the "might_have_sbr_stmts" info.
    
        @ plugin/replication_observers_example/replication_observers_example.cc
        @ rapid/plugin/group_replication/src/observer_trans.cc
        @ rapid/plugin/group_replication/src/handlers/certification_handler.cc
    
          Fixed calls to GTID constructor.
    
        @ sql/binlog.cc
    
          Created a new flag at "binlog_cache_data" named "with_sbr" that is
          set true when the cache is fed with non-terminal query event.
    
          Created a new flag at "binlog_cache_data" named "with_rbr" that is
          set true when the cache is fed with Table_map or Rows event.
    
          Created also the "might_have_sbr_stmts" function, that returns false
          for "pure RBR" transactions. This new function was implemented for
          the "binlog_cache_data".
    
          Added the logic to reset and set the new flags at
          "binlog_cache_data::reset" and "binlog_cache_data::write_event", and
          also to preserve the flags upon "SAVEPOINT/ROLLBACK TO SAVEPOINT".
    
          Made "MYSQL_BIN_LOG::write_gtid" to consider the cache information
          about the binary log content when creating the Gtid_log_event.
    
        @ sql/log_event.h
    
          Updated "Query_log_event::is_trans_keyword()" to recognize XA
          transactions terminal keywords that should not be considered as
          statements changing content.
    
          Created a new function "Log_event::is_sbr_logging_format()" that
          will return true if the event was/has to be logged using SBR and
          does not contains a transaction control statement.
    
          Created a new function "Log_event::is_rbr_logging_format()" that
          will return true if the event was/has to be logged using RBR.
    
        @ sql/log_event.cc
    
          We will stop the applier with an error when we assumed the
          transaction as "rbr_only" and some statement changing content be
          applied.
    
          Restored the applier session transaction isolation level
          after applying a Xid_log_event (after committing a replicated
          transaction), a XA_prepare_log_event (after preparing a replicated
          transaction) and in the cases of aborted/failed transactions.
    
          "Gtid_log_event::print" will now also print "rbr_only=[yes|no]" when
          dumping a Gtid_log_event with mysqlbinlog. It will also include a
          "SET TRANSACTION ISOLATION LEVEL READ COMMITTED" statement when
          dumping the GTID event with "rbr_only=yes".
    
          "Gtid_log_event::write_post_header_to_memory" now computes the GTID
          flags field instead of just writing "1" to it.
    
          "Gtid_log_event::do_apply_event" now set the transaction isolation
          level to READ COMMITTED when the "might_have_sbr_stmts" flag be false.
          Note that we don't change the isolation level for skipped GTID and
          when the isolation level be less restrictive than READ COMMITTED.
Loading