-
Joao Gramacho authored
TEMPORARY TABLES Problem: ======= DROP TABLE statement may be split before be sent to binlog if it contains regular tables and temporary tables or if it contains temporary tables with transactional and non-transactional storage engines. Issuing a DROP TABLE like the described above with GTIDs enables and having only one GTID associated to the statement (like the SQL thread does after issuing a SET GTID_NEXT='UUID:NUMBER') would lead to a problem as there is no GTIDs for all statements after splitting the original DROP TABLE. Analysis: ======== DROP TABLE statements might be split because the behavior of the command in respect to the current transaction vary depending on table characteristics as follows: a) DROP TABLE <regular table> will be committed immediately; b) DROP TABLE <temp trans table> will be committed with the current transaction (after COMMIT); c) DROP TABLE <temp non-trans table> will be committed immediately. So, mixing these types of tables in a single DROP statement will make MySQL server to split the statement in up to three DROP statements in the binlog. Without using GTID, there is no problem with this approach. If GTIDs are enabled, and it is not in AUTOMATIC mode, issuing a DROP TABLE statement that mixes table types above described would lead the server to have no GTIDs enough to log all split statements into binlog. Also, DROP TABLE using IF EXISTS will always binlog the drop for all tables specified in the statement, even if the tables doesn't exist. With regular tables it doesn't represent a problem, but with temporary tables this was leading to the following problem: as temporary tables are split into transactional and non-transactional ones, the non-existent tables of a DROP TEMPORARY TABLE statement were assumed as transactional ones. So, if a DROP TEMPORARY TABLE with two non-transactional temporary tables were issued at the master server, it would binlog only one DROP statement containing the two tables. But if a filter made one of the temporary tables inexistent on the slave, when the SQL thread executes the statement it would try to split the statement as it would have a non-transactional existent temporary table and a transactional non-existent temporary table. And this split will be a problem because the SQL thread will have only one GTID for the original DROP statement but having to binlog two DROP statements. Found also a problem with the slave dropping temporary tables when it detects that the master has restarted, by calling close_temporary_tables()@sql_base.cc, as it was "binlogging" one DROP statement per pseudo-thread and per database, but was mixing transactional and non-transactional temporary tables in a single DROP statement. Fix: === The first part of the patch was to throw an error in the client session if GTID_NEXT is set to an 'UUID:NUMBER' and a DROP TABLE statement is issued mixing the table types above described. The second part of the patch was to group the inexistent temporary tables and only assume them as transactional if at least one transactional temporary table is dropped. If no transactional temporary tables are dropped, the inexistent temporary tables are assumed as non-transactional temporary tables. The third part of the patch fixed the problem with close_temporary_tables(). @ mysql-test/include/save_master_pos.inc Moved the code that saved the master position to a place that it will always be executed. @ mysql-test/include/sync_slave_sql.inc Added a new parameter to permit forcing the sync using master position instead of GTID_EXECUTED, even if the use_gtids option is enabled. Added a code before the sync to verify is the SQL slave is in the current master position (it is already synced). If the SQL slave is assumed as already synced, we reduce the sync timeout to only 1 second. So, if the test is using GTIDs and not specified to force sync using master position, the sync command will use the master GTID_EXECUTED to sync and will timeout only if there is a discrepancy between master and slave GTID_EXECUTED. @ mysql-test/*/rpl/?/rpl_gtid_drop_table* mtr files for testing the bug/patch. @ mysql-test/suite/rpl/r/*.result Some tests had their result file changed because they listed the binlog events for DROP TABLE statements that were split both at master and slave and now some of these statements do not split anymore. @ sql/share/errmsg-utf8.txt Added a new error message for statements that would be split in the binary log when @@SESSION.GTID_NEXT is set to 'UUID:NUMBER'. @ sql/sql_table.cc Added code to mysql_rm_table() to verify if the statement is safe to be executed (if it is not mixing table types or if @@SESSION.GTID_NEXT is not set to 'UUID:NUMBER'). Added code to mysql_rm_table_no_locks() to group the inexistent temporary tables and assume them as non-transactional if there is no transactional temporary tables dropped in the statement. @sql/sql_base.cc Changed close_temporary_tables() function to binlog transactional and non-transactional temporary tables in distinct DROP statements.
Joao Gramacho authoredTEMPORARY TABLES Problem: ======= DROP TABLE statement may be split before be sent to binlog if it contains regular tables and temporary tables or if it contains temporary tables with transactional and non-transactional storage engines. Issuing a DROP TABLE like the described above with GTIDs enables and having only one GTID associated to the statement (like the SQL thread does after issuing a SET GTID_NEXT='UUID:NUMBER') would lead to a problem as there is no GTIDs for all statements after splitting the original DROP TABLE. Analysis: ======== DROP TABLE statements might be split because the behavior of the command in respect to the current transaction vary depending on table characteristics as follows: a) DROP TABLE <regular table> will be committed immediately; b) DROP TABLE <temp trans table> will be committed with the current transaction (after COMMIT); c) DROP TABLE <temp non-trans table> will be committed immediately. So, mixing these types of tables in a single DROP statement will make MySQL server to split the statement in up to three DROP statements in the binlog. Without using GTID, there is no problem with this approach. If GTIDs are enabled, and it is not in AUTOMATIC mode, issuing a DROP TABLE statement that mixes table types above described would lead the server to have no GTIDs enough to log all split statements into binlog. Also, DROP TABLE using IF EXISTS will always binlog the drop for all tables specified in the statement, even if the tables doesn't exist. With regular tables it doesn't represent a problem, but with temporary tables this was leading to the following problem: as temporary tables are split into transactional and non-transactional ones, the non-existent tables of a DROP TEMPORARY TABLE statement were assumed as transactional ones. So, if a DROP TEMPORARY TABLE with two non-transactional temporary tables were issued at the master server, it would binlog only one DROP statement containing the two tables. But if a filter made one of the temporary tables inexistent on the slave, when the SQL thread executes the statement it would try to split the statement as it would have a non-transactional existent temporary table and a transactional non-existent temporary table. And this split will be a problem because the SQL thread will have only one GTID for the original DROP statement but having to binlog two DROP statements. Found also a problem with the slave dropping temporary tables when it detects that the master has restarted, by calling close_temporary_tables()@sql_base.cc, as it was "binlogging" one DROP statement per pseudo-thread and per database, but was mixing transactional and non-transactional temporary tables in a single DROP statement. Fix: === The first part of the patch was to throw an error in the client session if GTID_NEXT is set to an 'UUID:NUMBER' and a DROP TABLE statement is issued mixing the table types above described. The second part of the patch was to group the inexistent temporary tables and only assume them as transactional if at least one transactional temporary table is dropped. If no transactional temporary tables are dropped, the inexistent temporary tables are assumed as non-transactional temporary tables. The third part of the patch fixed the problem with close_temporary_tables(). @ mysql-test/include/save_master_pos.inc Moved the code that saved the master position to a place that it will always be executed. @ mysql-test/include/sync_slave_sql.inc Added a new parameter to permit forcing the sync using master position instead of GTID_EXECUTED, even if the use_gtids option is enabled. Added a code before the sync to verify is the SQL slave is in the current master position (it is already synced). If the SQL slave is assumed as already synced, we reduce the sync timeout to only 1 second. So, if the test is using GTIDs and not specified to force sync using master position, the sync command will use the master GTID_EXECUTED to sync and will timeout only if there is a discrepancy between master and slave GTID_EXECUTED. @ mysql-test/*/rpl/?/rpl_gtid_drop_table* mtr files for testing the bug/patch. @ mysql-test/suite/rpl/r/*.result Some tests had their result file changed because they listed the binlog events for DROP TABLE statements that were split both at master and slave and now some of these statements do not split anymore. @ sql/share/errmsg-utf8.txt Added a new error message for statements that would be split in the binary log when @@SESSION.GTID_NEXT is set to 'UUID:NUMBER'. @ sql/sql_table.cc Added code to mysql_rm_table() to verify if the statement is safe to be executed (if it is not mixing table types or if @@SESSION.GTID_NEXT is not set to 'UUID:NUMBER'). Added code to mysql_rm_table_no_locks() to group the inexistent temporary tables and assume them as non-transactional if there is no transactional temporary tables dropped in the statement. @sql/sql_base.cc Changed close_temporary_tables() function to binlog transactional and non-transactional temporary tables in distinct DROP statements.
Loading