-
Sven Sandberg authored
Bug#18095502: NO EMPTY TRANSACTION IS CREATED FOR REPLICATE-IGNORE-DB OR REPLICATE-DO-DB Background: When gtid_mode=on, and a transaction is filtered out on the slave, the GTID of the transaction is still logged on the slave as a so-called empty transaction (just a GTID followed by BEGIN and then COMMIT). This is necessary to prevent the transaction from being re-transmitted next time the slave reconnects or does a fail-over. Symptom: 1. If a CREATE TEMPORARY TABLE or DROP TEMPORARY TABLE statement was filtered out, no empty transaction was generated. 2. If the slave has a database filter (--replicate-[do|ignore]-db), no empty transaction was generated. Analysis: 1. Empty transactions are normally generated after a committing statement ends, i.e., after an explicit COMMIT statement or after a statement that causes an implicit commit. However, CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE have very special semantics when it comes to implicit commit. The statements do not have the implicit commit flag set and will not commit an ongoing transaction. However, they cannot be rolled back. So when executed out of transactional context, they effectively perform a commit after execution. When GTID_MODE=ON, these statements are only allowed outside transactional context, and they are not written to the binary log within BEGIN/COMMIT statements. Therefore, when such a statement has been executed and filtered out, an empty transaction must be explicitly committed. The reason for the bug is that the current condition for checking if empty transaction should be generated is that stmt_causes_implicit_commit returns true. 2. Empty transactions are generated in mysql_parse. However, database filters were evaluated before mysql_parse was even called. Fix: 1. When checking if an empty transaction should be generated, also check explicitly for CREATE/DROP TEMPORARY. 2. Move database filter checking into mysql_parse. Further bugs: 3. In the special case that a statement has an 'unexpected' error code according to the check in log_event.cc:unexpected_error_code(), mysql_parse() is not executed and instead mysql_test_parse_for_slave() is executed. This is for the sole purpose of parsing without executing, so that an error is only generated on the slave for non-filtered tables. Thus, when moving the filter rule checking from do_apply_event() into mysql_parse(), we also need to perform the same check in mysql_test_parse_for_slave(). Test framework fixes: - To ease testing of this and other GTID-related bugs, I added the test framework files gtid_step_reset.inc and gtid_step_assert.inc. gtid_step_assert.inc asserts that the statements executed since last gtid_step_reset.inc generated a given number of GTIDs. This in turn needed some extra functions in gtid_utils.inc, and I also cleaned up and simplified gtid_utils a little and added a test case for it. - Small improvement in mysql-test/include/wait_for_slave_sql_to_stop.inc to allow comments after the error code(s).
Sven Sandberg authoredBug#18095502: NO EMPTY TRANSACTION IS CREATED FOR REPLICATE-IGNORE-DB OR REPLICATE-DO-DB Background: When gtid_mode=on, and a transaction is filtered out on the slave, the GTID of the transaction is still logged on the slave as a so-called empty transaction (just a GTID followed by BEGIN and then COMMIT). This is necessary to prevent the transaction from being re-transmitted next time the slave reconnects or does a fail-over. Symptom: 1. If a CREATE TEMPORARY TABLE or DROP TEMPORARY TABLE statement was filtered out, no empty transaction was generated. 2. If the slave has a database filter (--replicate-[do|ignore]-db), no empty transaction was generated. Analysis: 1. Empty transactions are normally generated after a committing statement ends, i.e., after an explicit COMMIT statement or after a statement that causes an implicit commit. However, CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE have very special semantics when it comes to implicit commit. The statements do not have the implicit commit flag set and will not commit an ongoing transaction. However, they cannot be rolled back. So when executed out of transactional context, they effectively perform a commit after execution. When GTID_MODE=ON, these statements are only allowed outside transactional context, and they are not written to the binary log within BEGIN/COMMIT statements. Therefore, when such a statement has been executed and filtered out, an empty transaction must be explicitly committed. The reason for the bug is that the current condition for checking if empty transaction should be generated is that stmt_causes_implicit_commit returns true. 2. Empty transactions are generated in mysql_parse. However, database filters were evaluated before mysql_parse was even called. Fix: 1. When checking if an empty transaction should be generated, also check explicitly for CREATE/DROP TEMPORARY. 2. Move database filter checking into mysql_parse. Further bugs: 3. In the special case that a statement has an 'unexpected' error code according to the check in log_event.cc:unexpected_error_code(), mysql_parse() is not executed and instead mysql_test_parse_for_slave() is executed. This is for the sole purpose of parsing without executing, so that an error is only generated on the slave for non-filtered tables. Thus, when moving the filter rule checking from do_apply_event() into mysql_parse(), we also need to perform the same check in mysql_test_parse_for_slave(). Test framework fixes: - To ease testing of this and other GTID-related bugs, I added the test framework files gtid_step_reset.inc and gtid_step_assert.inc. gtid_step_assert.inc asserts that the statements executed since last gtid_step_reset.inc generated a given number of GTIDs. This in turn needed some extra functions in gtid_utils.inc, and I also cleaned up and simplified gtid_utils a little and added a test case for it. - Small improvement in mysql-test/include/wait_for_slave_sql_to_stop.inc to allow comments after the error code(s).
Loading