diff options
Diffstat (limited to 'sql/sql_partition.cc')
-rw-r--r-- | sql/sql_partition.cc | 163 |
1 files changed, 109 insertions, 54 deletions
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index c29f5ef5650..114ac273d52 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5244,7 +5244,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 1) Write the new frm, pack it and then delete it 2) Perform the change within the handler */ - if ((mysql_write_frm(lpt, WFRM_INITIAL_WRITE | WFRM_PACK_FRM)) || + if ((mysql_write_frm(lpt, WFRM_WRITE_SHADOW | WFRM_PACK_FRM)) || (mysql_change_partitions(lpt))) { fast_alter_partition_error_handler(lpt); @@ -5275,29 +5275,56 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, after a DROP PARTITION) if one ensured that failed accesses to the dropped partitions was aborted for sure (thus only possible for transactional engines). - - 1) Lock the table in TL_WRITE_ONLY to ensure all other accesses to + + 0) Write an entry that removes the shadow frm file if crash occurs + 1) Write the new frm file as a shadow frm + 2) Write the table log to ensure that the operation is completed + even in the presence of a MySQL Server crash + 3) Lock the table in TL_WRITE_ONLY to ensure all other accesses to the table have completed - 2) Write the new frm file where the partitions have changed but are - still remaining with the state PART_TO_BE_DROPPED - 3) Write the bin log - 4) Prepare MyISAM handlers for drop of partitions - 5) Ensure that any users that has opened the table but not yet + 4) Write the bin log + Unfortunately the writing of the binlog is not synchronised with + other logging activities. So no matter in which order the binlog + is written compared to other activities there will always be cases + where crashes make strange things occur. In this placement it can + happen that the ALTER TABLE DROP PARTITION gets performed in the + master but not in the slaves if we have a crash, after writing the + table log but before writing the binlog. A solution to this would + require writing the statement first in the table log and then + when recovering from the crash read the binlog and insert it into + the binlog if not written already. + 5) Install the previously written shadow frm file + 6) Ensure that any users that has opened the table but not yet reached the abort lock do that before downgrading the lock. - 6) Drop the partitions - 7) Write the frm file that the partition has been dropped - 8) Wait until all accesses using the old frm file has completed - 9) Complete query + 7) Prepare MyISAM handlers for drop of partitions + 8) Drop the partitions + 9) Remove entries from table log + 10) Wait until all accesses using the old frm file has completed + 11) Complete query + + We insert Error injections at all places where it could be interesting + to test if recovery is properly done. */ - if ((abort_and_upgrade_lock(lpt)) || - (mysql_write_frm(lpt, WFRM_INITIAL_WRITE)) || + if (write_log_shadow_frm(lpt) || + ERROR_INJECTOR_CRASH(1000) || + mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || + ERROR_INJECTOR_CRASH(1001) || + write_log_drop_partition(lpt) || + ERROR_INJECTOR_CRASH(1002) || + abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && - (write_bin_log(thd, FALSE, - thd->query, thd->query_length), FALSE)) || - (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE)) || + write_bin_log(thd, FALSE, + thd->query, thd->query_length), FALSE) || + ERROR_INJECTOR_CRASH(1003) || + mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || (close_open_tables_and_downgrade(lpt), FALSE) || - (mysql_drop_partitions(lpt)) || - (mysql_write_frm(lpt, WFRM_CREATE_HANDLER_FILES)) || + ERROR_INJECTOR_CRASH(1004) || + table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE) || + ERROR_INJECTOR_CRASH(1005) || + mysql_drop_partitions(lpt) || + ERROR_INJECTOR_CRASH(1006) || + write_log_completed(lpt) || + ERROR_INJECTOR_CRASH(1007) || (mysql_wait_completed_table(lpt, table), FALSE)) { fast_alter_partition_error_handler(lpt); @@ -5317,26 +5344,38 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, miss updates made by a transaction serialised before it that are inserted into the new partition. - 1) Write the new frm file where state of added partitions is - changed to PART_TO_BE_ADDED + 0) Write an entry that removes the shadow frm file if crash occurs + 1) Write the new frm file as a shadow frm file + 2) Log the changes to happen in table log 2) Add the new partitions 3) Lock all partitions in TL_WRITE_ONLY to ensure that no users are still using the old partitioning scheme. Wait until all ongoing users have completed before progressing. - 4) Write a new frm file of the table where the partitions are added - to the table. - 5) Write binlog + 4) Write binlog + 5) Install the new frm file of the table where the partitions are + added to the table. 6) Wait until all accesses using the old frm file has completed - 7) Complete query + 7) Remove entries from table log + 8) Complete query */ - if ((mysql_write_frm(lpt, WFRM_INITIAL_WRITE)) || - (mysql_change_partitions(lpt)) || - (abort_and_upgrade_lock(lpt)) || - (mysql_write_frm(lpt, WFRM_CREATE_HANDLER_FILES)) || + if (write_log_shadow_frm(lpt) || + ERROR_INJECTED_CRASH(1010) || + mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || + ERROR_INJECTED_CRASH(1011) || + write_log_add_partition(lpt) || + ERROR_INJECTED_CRASH(1012) || + mysql_change_partitions(lpt) || + ERROR_INJECTED_CRASH(1013) || + abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - (close_open_tables_and_downgrade(lpt), FALSE)) + ERROR_INJECTED_CRASH(1014) || + mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || + ERROR_INJECTED_CRASH(1015) || + (close_open_tables_and_downgrade(lpt), FALSE) || + write_log_completed(lpt) || + ERROR_INJECTED_CRASH(1016)) { fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); @@ -5375,40 +5414,56 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, use a lower lock level. This can be handled inside store_lock in the respective handler. - 1) Write the new frm file where state of added partitions is - changed to PART_TO_BE_ADDED and the reorganised partitions - are set in state PART_TO_BE_REORGED. - 2) Add the new partitions + 0) Write an entry that removes the shadow frm file if crash occurs + 1) Write the shadow frm file of new partitioning + 2) Log such that temporary partitions added in change phase are + removed in a crash situation + 3) Add the new partitions Copy from the reorganised partitions to the new partitions - 3) Lock all partitions in TL_WRITE_ONLY to ensure that no users + 4) Log that operation is completed and log all complete actions + needed to complete operation from here + 5) Lock all partitions in TL_WRITE_ONLY to ensure that no users are still using the old partitioning scheme. Wait until all ongoing users have completed before progressing. - 4) Prepare MyISAM handlers for rename and delete of partitions - 5) Write a new frm file of the table where the partitions are - reorganised. - 6) Rename the reorged partitions such that they are no longer + 6) Prepare MyISAM handlers for rename and delete of partitions + 7) Rename the reorged partitions such that they are no longer used and rename those added to their real new names. - 7) Write bin log - 8) Wait until all accesses using the old frm file has completed - 9) Drop the reorganised partitions - 10)Write a new frm file of the table where the partitions are - reorganised. - 11)Wait until all accesses using the old frm file has completed - 12)Complete query + 8) Write bin log + 9) Install the shadow frm file + 10) Wait until all accesses using the old frm file has completed + 11) Drop the reorganised partitions + 12) Remove log entry + 13)Wait until all accesses using the old frm file has completed + 14)Complete query */ - if ((mysql_write_frm(lpt, WFRM_INITIAL_WRITE)) || - (mysql_change_partitions(lpt)) || - (abort_and_upgrade_lock(lpt)) || - (mysql_write_frm(lpt, WFRM_CREATE_HANDLER_FILES)) || - (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE)) || - (mysql_rename_partitions(lpt)) || + if (write_log_shadow_frm(lpt) || + ERROR_INJECT_CRASH(1020) || + mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || + ERROR_INJECT_CRASH(1021) || + write_log_ph1_change_partition(lpt) || + ERROR_INJECT_CRASH(1022) || + mysql_change_partitions(lpt) || + ERROR_INJECT_CRASH(1023) || + write_log_ph2_change_partition(lpt) || + ERROR_INJECT_CRASH(1024) || + abort_and_upgrade_lock(lpt) || + table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE) || + ERROR_INJECT_CRASH(1025) || + mysql_rename_partitions(lpt) || + ERROR_INJECT_CRASH(1026) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || + ERROR_INJECT_CRASH(1027) || + mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || + ERROR_INJECT_CRASH(1028) || (close_open_tables_and_downgrade(lpt), FALSE) || - (mysql_drop_partitions(lpt)) || - (mysql_write_frm(lpt, 0UL)) || + ERROR_INJECT_CRASH(1029) || + mysql_drop_partitions(lpt) || + ERROR_INJECT_CRASH(1030) || + write_log_completed(lpt) || + ERROR_INJECT_CRASH(1031) || (mysql_wait_completed_table(lpt, table), FALSE)) { fast_alter_partition_error_handler(lpt); |