Skip to content
  • Joao Gramacho's avatar
    6b8c5373
    BUG#25040331: INTERLEAVED XA TRANSACTIONS MAY DEADLOCK SLAVE APPLIER · 6b8c5373
    Joao Gramacho 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.
    6b8c5373
    BUG#25040331: INTERLEAVED XA TRANSACTIONS MAY DEADLOCK SLAVE APPLIER
    Joao Gramacho 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