diff --git a/sql/partition_info.h b/sql/partition_info.h index 0656238ec07..995147d6766 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -79,7 +79,7 @@ struct Vers_part_info : public Sql_alloc partition_element *hist_part; }; -class partition_info : public Sql_alloc +class partition_info : public DDL_LOG_STATE, public Sql_alloc Please add DDL_LOG_STATE into the class instead of using double inheritance! Makes the code, like bzero below, easier to understand! @@ -319,6 +314,7 @@ class partition_info : public Sql_alloc is_auto_partitioned(FALSE), has_null_value(FALSE), column_list(FALSE) { + bzero((DDL_LOG_STATE *) this, sizeof(DDL_LOG_STATE)); all_fields_in_PF.clear_all(); all_fields_in_PPF.clear_all(); all_fields_in_SPF.clear_all(); @@ -6166,50 +6201,84 @@ static void release_part_info_log_entries(DDL_LOG_MEMORY_ENTRY *log_entry) /* - Log an delete/rename frm file + Log an delete frm file + SYNOPSIS + write_log_delete_frm() + lpt Struct for parameters + to_path Name to delete + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Support routine that writes a delete of an frm file into the + ddl log. It also inserts an entry that keeps track of used space into + the partition info object +*/ + + +/* + TODO: Partitioning atomic DDL refactoring: this should be replaced with + ddl_log_create_table(). +*/ +static bool write_log_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, + const char *to_path) +{ + DDL_LOG_ENTRY ddl_log_entry; + DDL_LOG_MEMORY_ENTRY *log_entry; + bzero(&ddl_log_entry, sizeof(ddl_log_entry)); + ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION; + ddl_log_entry.next_entry= lpt->part_info->list ? lpt->part_info->list->entry_pos : 0; + + lex_string_set(&ddl_log_entry.handler_name, reg_ext); + lex_string_set(&ddl_log_entry.name, to_path); + + if (ddl_log_write_entry(&ddl_log_entry, &log_entry)) + { + return true; + } + ddl_log_add_entry(lpt->part_info, log_entry); + return false; +} Please create a function in ddl_log.cc that does the above logic. (Normal users should not have to know or manpulate next_entry). See ddl_log_delete_tmp_file() as an example of how to do this! bzero(&ddl_log_entry, sizeof(ddl_log_entry)); - if (replace_flag) - ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION; - else - ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION; + ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION; ddl_log_entry.next_entry= next_entry; lex_string_set(&ddl_log_entry.handler_name, reg_ext); lex_string_set(&ddl_log_entry.name, to_path); + lex_string_set(&ddl_log_entry.from_name, from_path); - if (replace_flag) - lex_string_set(&ddl_log_entry.from_name, from_path); if (ddl_log_write_entry(&ddl_log_entry, &log_entry)) { - DBUG_RETURN(TRUE); + return true; } - insert_part_info_log_entry_list(lpt->part_info, log_entry); - DBUG_RETURN(FALSE); + ddl_log_add_entry(lpt->part_info, log_entry); + return false; } Move to ddl_log.cc. Better to have all functions related to ddl log entry adding there! @@ -6767,11 +6910,11 @@ static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, static void release_log_entries(partition_info *part_info) { mysql_mutex_lock(&LOCK_gdl); - release_part_info_log_entries(part_info->first_log_entry); - release_part_info_log_entries(part_info->exec_log_entry); + release_part_info_log_entries(part_info->list); + release_part_info_log_entries(part_info->execute_entry); I think we should be able to replace the above two calls with. ddl_log_release_entries((DDL_LOG_STATE*) part_info) or preferabley ddl_log_release_entries(&part_info->ddl_log_state); This would allow us to delete release_part_info_log_entries() mysql_mutex_unlock(&LOCK_gdl); - part_info->first_log_entry= NULL; - part_info->exec_log_entry= NULL; + part_info->list= NULL; + part_info->execute_entry= NULL; The above two statemetns can also be deleted if we use ddl_log_release_entries() } + + thd->work_part_info= work_part_info; + create_info->db_type= db_type; + + debug_crash_here("ddl_log_alter_partition_after_create_frm"); + + error= writefile(frm_name, alter_ctx->new_db.str, alter_ctx->new_name.str, + create_info->tmp_table(), frm.str, frm.length); + my_free((void *) frm.str); + if (unlikely(error) || + ERROR_INJECT_ERROR("fail_alter_partition_after_write_frm")) + { + mysql_file_delete(key_file_frm, frm_name, MYF(0)); + DBUG_RETURN(TRUE); + } + + debug_crash_here("ddl_log_alter_partition_after_write_frm"); + DBUG_RETURN(false); + } + if (flags & WFRM_BACKUP_ORIGINAL) + { + build_table_filename(path, sizeof(path) - 1, lpt->db.str, + lpt->table_name.str, "", 0); + strxnmov(frm_name, sizeof(frm_name), path, reg_ext, NullS); + + build_table_shadow_filename(bak_path, sizeof(bak_path) - 1, lpt, true); + strxmov(bak_frm_name, bak_path, reg_ext, NullS); + + DDL_LOG_MEMORY_ENTRY *main_entry= part_info->main_entry; + mysql_mutex_lock(&LOCK_gdl); + if (write_log_replace_frm(lpt, part_info->list->entry_pos, + (const char*) bak_path, + (const char*) path) || + ddl_log_write_execute_entry(part_info->list->entry_pos, + &part_info->execute_entry)) Wouldn't it be better to move ddl_log_write_execute_entry() to write_log_replace_frm(), similar to ddl_log_write(). Note that if write_log_replace_frm() worked and ddl_log_write_execute_entry() failed one should release the first log entry (as in ddl_log_write()) + { + mysql_mutex_unlock(&LOCK_gdl); + DBUG_RETURN(TRUE); + } Better to store the if () in a variable, do the mutex unlock and then test. Even better to move the lock/unlock to write_log_replace_frm()