diff options
author | Aleksey Midenkov <midenok@gmail.com> | 2021-12-05 22:20:20 +0300 |
---|---|---|
committer | Aleksey Midenkov <midenok@gmail.com> | 2022-06-16 01:39:01 +0300 |
commit | 312a5ecdc41b1a5771bdbb3015eb2a928f03b89c (patch) | |
tree | 8578831b23276edd8ba5f927820d53042f03e639 /sql/sql_partition_admin.cc | |
parent | 18df0f35ab696e2ffb2dcc8a1cdefcdfd2898276 (diff) | |
download | mariadb-git-bb-10.7-midenok-MDEV-27180.tar.gz |
MDEV-27180 Fully atomic partitioning DDL operationsbb-10.7-midenok-MDEV-27180
Atomic DDL for partitioning originally covers crash-safety but it does
not recover fully from failures. F.ex. if error happened during the
rename or drop of partitions the ALTER operation does not return the
table to its original state.
The patch solves the above problem similarly to MDEV-25292 (atomic
CREATE OR REPLACE): new partitions are created as temporary, old
partitions are backed up, everything is guarded by two DDL log chains:
rollback and cleanup. Rollback chain contains the actions that bring
back the original table. Cleanup chain deletes the backup files.
The generic operation of alter partition is as follows:
1. Create new partitions as tmp partitions;
2. Fill TMP partitions with data;
3. Rename old and not needed partitions to backup partitions;
4. Rename tmp partitions to original partititions;
5. Do any required logging (mariabackup, binary);
6. If everything is ok, drop the backup partitions;
7. In the case any of pp.1-5 fails drop new partitions, rename back
backup partitions.
Each rename operation is executed right after the corresponding DDL
logging. Originally they were done in different loops:
write_log_changed_partitions(), mysql_change_partitions(), etc. The
actual table operations were done in ha_partition handler:
ha_change_partitions(), ha_drop_partitions(),
ha_rename_partitions(). Now these calls are deprecated and removed.
Instead the above deprecated interfaces the following classes now
handle DDL logging and table operations:
Alter_partition_logger
Alter_partition_add
Alter_partition_change
Alter_partition_logger handles the basic operation, DDL logging and
table renames. Alter_partition_add does the stuff for adding the
partitions. Alter_partition_change combines Alter_partition_logger and
Alter_partition_add for complex operations such as REORGANIZE.
ha_partition::change_partitions() call was not fully removed. Stages
1-4 from that call was renamed to allocate_partitions() and that is
used by Alter_partition_add for initializing file handler arrays
(m_added_file, m_reorged_file). ha_partition::prepare_new_partition()
is renamed to create_partition() because it actually does ha_create()
and the new name better describes what it does.
DDL_LOG_DELETE/DDL_LOG_RENAME/DDL_LOG_REPLACE are now pure file
operations. To process both .par and .frm files we now issue two
actions instead of one. That makes interface more simple and that will
be used by MDEV-16417 in future. All the table operations are done via
other actions, such as DDL_LOG_RENAME_TABLE, DDL_LOG_DROP_TABLE, etc.
DDL_LOG_RENAME_TABLE has new alter_partition option. With this option
it does simple ha_rename_table() which is needed for renaming the
partitions. The action for renaming the partitions must start from
phase DDL_RENAME_PHASE_TABLE.
The testing was refactored a bit. Many new fail/crash points was
added, the test was powered by binary and mariabackup logging, it
tests more ALTER commands with variations of partitions-only and
subpartitions, without and under LOCK TABLES.
EXCHANGE PARTITION was fixed: after failure under LOCK TABLES the
table became unlocked. Fixed by correcting place of
reopen_tables(). Tested by partition_debug.
Diffstat (limited to 'sql/sql_partition_admin.cc')
-rw-r--r-- | sql/sql_partition_admin.cc | 61 |
1 files changed, 3 insertions, 58 deletions
diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc index 134a01e4e0e..09dd0c5689b 100644 --- a/sql/sql_partition_admin.cc +++ b/sql/sql_partition_admin.cc @@ -396,7 +396,7 @@ static bool exchange_name_with_ddl_log(THD *thd, */ /* call rename table from table to tmp-name */ DBUG_EXECUTE_IF("exchange_partition_fail_3", - my_error(ER_ERROR_ON_RENAME, MYF(0), name, tmp_name, 0); + my_error(ER_ERROR_ON_RENAME, MYF(0), name, "#TMP", 0); error_set= TRUE; goto err_rename;); DBUG_EXECUTE_IF("exchange_partition_abort_3", DBUG_SUICIDE();); @@ -430,7 +430,7 @@ static bool exchange_name_with_ddl_log(THD *thd, /* call rename table from tmp-nam to partition */ DBUG_EXECUTE_IF("exchange_partition_fail_7", - my_error(ER_ERROR_ON_RENAME, MYF(0), tmp_name, from_name, 0); + my_error(ER_ERROR_ON_RENAME, MYF(0), "#TMP", from_name, 0); error_set= TRUE; goto err_rename;); DBUG_EXECUTE_IF("exchange_partition_abort_7", DBUG_SUICIDE();); @@ -719,13 +719,6 @@ bool Sql_cmd_alter_table_exchange_partition:: temp_file_name, table_hton))) goto err; - /* - Reopen tables under LOCK TABLES. Ignore the return value for now. It's - better to keep master/slave in consistent state. Alternative would be to - try to revert the exchange operation and issue error. - */ - (void) thd->locked_tables_list.reopen_tables(thd, false); - if (force_if_exists) thd->variables.option_bits|= OPTION_IF_EXISTS; @@ -753,6 +746,7 @@ bool Sql_cmd_alter_table_exchange_partition:: err: if (thd->locked_tables_mode) { + (void) thd->locked_tables_list.reopen_tables(thd, false); if (swap_table_mdl_ticket) swap_table_mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE); if (part_table_mdl_ticket) @@ -999,53 +993,4 @@ bool Sql_cmd_alter_table_truncate_partition::execute(THD *thd) DBUG_RETURN(error); } - -/** - Move a table specified in the CONVERT TABLE <table_name> TO PARTITION ... - to the new partition. - - @param lpt A structure containing parameters regarding to the statement - ALTER TABLE ... TO PARTITION ... - @param part_file_name a file name of the partition being added - - @return false on success, true on error -*/ - -bool alter_partition_convert_in(ALTER_PARTITION_PARAM_TYPE *lpt) -{ - char part_file_name[2*FN_REFLEN+1]; - THD *thd= lpt->thd; - const char *path= lpt->table_list->table->s->path.str; - TABLE_LIST *table_from= lpt->table_list->next_local; - - const char *partition_name= - thd->lex->part_info->curr_part_elem->partition_name; - - if (create_partition_name(part_file_name, sizeof(part_file_name), path, - partition_name, NORMAL_PART_NAME, false)) - return true; - - char from_file_name[FN_REFLEN+1]; - - build_table_filename(from_file_name, sizeof(from_file_name), - table_from->db.str, table_from->table_name.str, "", 0); - - handler *file= get_new_handler(nullptr, thd->mem_root, - table_from->table->file->ht); - if (unlikely(!file)) - return true; - - close_all_tables_for_name(thd, table_from->table->s, - HA_EXTRA_PREPARE_FOR_RENAME, nullptr); - - bool res= file->ha_rename_table(from_file_name, part_file_name); - - if (res) - my_error(ER_ERROR_ON_RENAME, MYF(0), from_file_name, - part_file_name, my_errno); - - delete file; - return res; -} - #endif /* WITH_PARTITION_STORAGE_ENGINE */ |