From 520dffb5204a471030c3e43494cd3419136bce05 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Feb 2006 10:06:07 +0100 Subject: [PATCH 01/48] WL 2826: First step in error handling of ALTER TABLE for partitioning BUILD/SETUP.sh: Add possibility for BUILD scripts to add error inject flag BUILD/compile-pentium-debug-max: Add error inject flag to this script configure.in: Add handling of --with-error-inject in configure script sql/ha_ndbcluster.cc: Add possibility to rename handler file sql/ha_ndbcluster.h: Add possibility to rename handler file sql/ha_partition.cc: Add possibility to rename handler file sql/ha_partition.h: Add possibility to rename handler file sql/handler.h: Add possibility to rename handler file sql/mysql_priv.h: Add error inject macros sql/mysqld.cc: Add error inject system variables sql/set_var.cc: Add error inject system variables sql/sql_class.h: Add error inject system variables sql/sql_table.cc: Start modifying code for introducing table log, Step 1 sql/unireg.cc: Add rename flag to handler file call sql/sql_partition.cc: Changes to ADD/DROP/CHANGE partitions --- BUILD/SETUP.sh | 1 + BUILD/compile-pentium-debug-max | 2 +- configure.in | 13 +++ sql/ha_ndbcluster.cc | 8 +- sql/ha_ndbcluster.h | 3 +- sql/ha_partition.cc | 27 +++++- sql/ha_partition.h | 3 +- sql/handler.h | 6 +- sql/mysql_priv.h | 30 +++++- sql/mysqld.cc | 6 ++ sql/set_var.cc | 10 ++ sql/sql_class.h | 4 + sql/sql_partition.cc | 163 ++++++++++++++++++++----------- sql/sql_table.cc | 167 ++++++++++++++++++-------------- sql/unireg.cc | 2 +- 15 files changed, 307 insertions(+), 138 deletions(-) diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index eece41d72e6..e76507b1a77 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -71,6 +71,7 @@ pentium_cflags="$check_cpu_cflags" pentium64_cflags="$check_cpu_cflags -m64" ppc_cflags="$check_cpu_cflags" sparc_cflags="" +error_inject_flag="--with-error-inject " # be as fast as we can be without losing our ability to backtrace fast_cflags="-O3 -fno-omit-frame-pointer" diff --git a/BUILD/compile-pentium-debug-max b/BUILD/compile-pentium-debug-max index 7a11ad24c44..d065ed2bf71 100755 --- a/BUILD/compile-pentium-debug-max +++ b/BUILD/compile-pentium-debug-max @@ -3,7 +3,7 @@ path=`dirname $0` . "$path/SETUP.sh" $@ --with-debug=full -extra_flags="$pentium_cflags $debug_cflags $max_cflags" +extra_flags="$pentium_cflags $debug_cflags $max_cflags $error_inject_flag" c_warnings="$c_warnings $debug_extra_warnings" cxx_warnings="$cxx_warnings $debug_extra_warnings" extra_configs="$pentium_configs $debug_configs $max_configs" diff --git a/configure.in b/configure.in index ffc311a7857..ad69365a1b9 100644 --- a/configure.in +++ b/configure.in @@ -654,6 +654,7 @@ else AC_MSG_RESULT([no]) fi + MYSQL_SYS_LARGEFILE # Types that must be checked AFTER large file support is checked @@ -1554,6 +1555,18 @@ then DEBUG_OPTIMIZE_CXX="" fi +# If we should allow error injection tests +AC_ARG_WITH(error-inject, + [ --with-error-inject Enable error injection in MySQL Server], + [ with_error_inject=$withval ], + [ with_error_inject=no ]) + +if test "$with_error_inject" = "yes" +then + CFLAGS="-DERROR_INJECT_SUPPORT $CFLAGS" + CXXFLAGS="-DERROR_INJECT_SUPPORT $CXXFLAGS" +fi + AC_ARG_WITH(debug, [ --without-debug Build a production version without debugging code], [with_debug=$withval], diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 85f43ba2757..deea59b8074 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -4399,7 +4399,9 @@ int ha_ndbcluster::create(const char *name, DBUG_RETURN(my_errno); } -int ha_ndbcluster::create_handler_files(const char *file) +int ha_ndbcluster::create_handler_files(const char *file, + const char *old_name, + bool rename_flag) { const char *name; Ndb* ndb; @@ -4410,6 +4412,10 @@ int ha_ndbcluster::create_handler_files(const char *file) DBUG_ENTER("create_handler_files"); + if (rename_flag) + { + DBUG_RETURN(FALSE); + } if (!(ndb= get_ndb())) DBUG_RETURN(HA_ERR_NO_CONNECTION); diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index a62356d41ab..3ec6ada9a98 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -588,7 +588,8 @@ class ha_ndbcluster: public handler int rename_table(const char *from, const char *to); int delete_table(const char *name); int create(const char *name, TABLE *form, HA_CREATE_INFO *info); - int create_handler_files(const char *file); + int create_handler_files(const char *file, const char *old_name, + bool rename_flag); int get_default_no_partitions(ulonglong max_rows); bool get_no_parts(const char *name, uint *no_parts); void set_auto_partitions(partition_info *part_info); diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 50299dffd85..d318c4ab348 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -563,7 +563,9 @@ int ha_partition::rename_table(const char *from, const char *to) and types of engines in the partitions. */ -int ha_partition::create_handler_files(const char *name) +int ha_partition::create_handler_files(const char *path, + const char *old_path, + bool rename_flag) { DBUG_ENTER("ha_partition::create_handler_files()"); @@ -571,10 +573,27 @@ int ha_partition::create_handler_files(const char *name) We need to update total number of parts since we might write the handler file as part of a partition management command */ - if (create_handler_file(name)) + if (rename_flag) { - my_error(ER_CANT_CREATE_HANDLER_FILE, MYF(0)); - DBUG_RETURN(1); + char name[FN_REFLEN]; + char old_name[FN_REFLEN]; + char *par_str= ".par"; + + strxmov(name, path, par_str, NullS); + strxmov(old_name, old_path, par_str, NullS); + if (my_delete(name, MYF(MY_WME)) || + my_rename(old_name, name, MYF(MY_WME))) + { + DBUG_RETURN(TRUE); + } + } + else + { + if (create_handler_file(path)) + { + my_error(ER_CANT_CREATE_HANDLER_FILE, MYF(0)); + DBUG_RETURN(1); + } } DBUG_RETURN(0); } diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 35435844064..f62231bb11e 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -179,7 +179,8 @@ public: virtual int rename_table(const char *from, const char *to); virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info); - virtual int create_handler_files(const char *name); + virtual int create_handler_files(const char *name, + const char *old_name, bool rename_flag); virtual void update_create_info(HA_CREATE_INFO *create_info); virtual char *update_table_comment(const char *comment); virtual int change_partitions(HA_CREATE_INFO *create_info, diff --git a/sql/handler.h b/sql/handler.h index d29c499f954..b6a925695b8 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1779,7 +1779,11 @@ public: virtual void drop_table(const char *name); virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0; - virtual int create_handler_files(const char *name) { return FALSE;} + virtual int create_handler_files(const char *name, const char *old_name, + bool rename_flag) + { + return FALSE; + } virtual int change_partitions(HA_CREATE_INFO *create_info, const char *path, diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 589ca1349c1..b501e4c7663 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -603,6 +603,29 @@ struct Query_cache_query_flags #define query_cache_invalidate_by_MyISAM_filename_ref NULL #endif /*HAVE_QUERY_CACHE*/ +/* + Error injector Macros to enable easy testing of recovery after failures + in various error cases. +*/ +#ifndef ERROR_INJECT_SUPPORT +#define ERROR_INJECTOR(x) +#define ERROR_INJECTOR_ACTION(x) +#define ERROR_INJECTOR_CRASH(x) +#else + +inline bool +my_error_inject(int error) +{ + return (current_thd->variables.error_inject_code == error) ? 1 : 0; +} + +#define ERROR_INJECTOR_CRASH(code) \ + (my_error_inject((code)) ? ((DBUG_ASSERT(0)), 0) : 0 +#define ERROR_INJECTOR_ACTION(code, action) \ + (my_error_inject((code)) ? ((action), 0) : 0 +#define ERROR_INJECT(code) \ + (my_error_inject((code)) ? 1 : 0) +#endif uint build_table_path(char *buff, size_t bufflen, const char *db, const char *table, const char *ext); void write_bin_log(THD *thd, bool clear_error, @@ -1099,9 +1122,10 @@ typedef struct st_lock_param_type } ALTER_PARTITION_PARAM_TYPE; void mem_alloc_error(size_t size); -#define WFRM_INITIAL_WRITE 1 -#define WFRM_CREATE_HANDLER_FILES 2 -#define WFRM_PACK_FRM 4 +bool write_table_log(ALTER_PARTITION_PARAM_TYPE *lpt); +#define WFRM_WRITE_SHADOW 1 +#define WFRM_INSTALL_SHADOW 2 +#define WFRM_PACK_FRM bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags); bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt); void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f5b93e6a5e5..07e2abc1de5 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -7055,6 +7055,12 @@ static void mysql_init_variables(void) max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; global_system_variables.old_passwords= 0; global_system_variables.old_alter_table= 0; +#ifdef ERROR_INJECT_SUPPORT + global_system_variables.error_inject_code= 0; + global_system_variables.error_inject_value= 0; + max_system_variables.error_inject_code= ~0; + max_system_variables.error_inject_value= ~0; +#endif /* Default behavior for 4.1 and 5.0 is to treat NULL values as unequal diff --git a/sql/set_var.cc b/sql/set_var.cc index b85b2576b83..bc6c68e87f6 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -215,6 +215,12 @@ sys_var_long_ptr sys_delayed_insert_timeout("delayed_insert_timeout", &delayed_insert_timeout); sys_var_long_ptr sys_delayed_queue_size("delayed_queue_size", &delayed_queue_size); +#ifdef ERROR_INJECT_SUPPORT +sys_var_long_ptr sys_error_inject_code("error_inject_code", + &error_inject_code); +sys_var_long_ptr sys_error_inject_value("error_inject_value", + &error_inject_value); +#endif sys_var_event_executor sys_event_executor("event_scheduler", &event_executor_running_global_var); sys_var_long_ptr sys_expire_logs_days("expire_logs_days", @@ -729,6 +735,10 @@ SHOW_VAR init_vars[]= { {sys_div_precincrement.name,(char*) &sys_div_precincrement,SHOW_SYS}, {sys_engine_condition_pushdown.name, (char*) &sys_engine_condition_pushdown, SHOW_SYS}, +#ifdef ERROR_INJECT_SUPPORT + {sys_error_inject_code.name,(char*) &sys_error_inject_code, SHOW_SYS}, + {sys_error_inject_value.name,(char*)&sys_error_inject_value, SHOW_SYS}, +#endif {sys_event_executor.name, (char*) &sys_event_executor, SHOW_SYS}, {sys_expire_logs_days.name, (char*) &sys_expire_logs_days, SHOW_SYS}, {sys_flush.name, (char*) &sys_flush, SHOW_SYS}, diff --git a/sql/sql_class.h b/sql/sql_class.h index 00440449be8..bf6633f98ed 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -186,6 +186,10 @@ struct system_variables ha_rows max_join_size; ulong auto_increment_increment, auto_increment_offset; ulong bulk_insert_buff_size; +#ifdef ERROR_INJECT_SUPPORT + ulong error_inject_code; + ulong error_inject_value; +#endif ulong join_buff_size; ulong long_query_time; ulong max_allowed_packet; 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); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 2938f27c58d..809a70a0d45 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -245,6 +245,28 @@ static int mysql_copy_key_list(List *orig_key, } +/* + SYNOPSIS + write_table_log() + lpt Struct carrying parameters to the function + + RETURN VALUES + TRUE Failure in writing the log + FALSE Success + + DESCRIPTION + A careful write of the table log is performed to ensure that we can + handle crashes occurring during CREATE and ALTER TABLE processing. +*/ + +bool +write_table_log(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DBUG_ENTER("write_table_log"); + DBUG_RETURN(FALSE); +} + + /* SYNOPSIS mysql_write_frm() @@ -277,83 +299,66 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) */ int error= 0; char path[FN_REFLEN+1]; + char shadow_path[FN_REFLEN+1]; + char shadow_frm_name[FN_REFLEN+1]; char frm_name[FN_REFLEN+1]; DBUG_ENTER("mysql_write_frm"); - if (flags & WFRM_INITIAL_WRITE) + /* + Build shadow frm file name + */ + build_table_filename(shadow_path, sizeof(path), lpt->db, + lpt->table_name, "#"); + strxmov(shadow_frm_name, path, reg_ext, NullS); + if (flags & WFRM_WRITE_SHADOW) { - error= mysql_copy_create_list(lpt->create_list, - &lpt->new_create_list); - error+= mysql_copy_key_list(lpt->key_list, - &lpt->new_key_list); - if (error) + if (mysql_copy_create_list(lpt->create_list, + &lpt->new_create_list) || + mysql_copy_key_list(lpt->key_list, + &lpt->new_key_list) || + mysql_prepare_table(lpt->thd, lpt->create_info, + &lpt->new_create_list, + &lpt->new_key_list, + /*tmp_table*/ 1, + &lpt->db_options, + lpt->table->file, + &lpt->key_info_buffer, + &lpt->key_count, + /*select_field_count*/ 0))) { DBUG_RETURN(TRUE); } - } - build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); - strxmov(frm_name, path, reg_ext, NullS); - if ((flags & WFRM_INITIAL_WRITE) && - (mysql_prepare_table(lpt->thd, lpt->create_info, &lpt->new_create_list, - &lpt->new_key_list,/*tmp_table*/ 1, &lpt->db_options, - lpt->table->file, &lpt->key_info_buffer, - &lpt->key_count, /*select_field_count*/ 0))) - { - DBUG_RETURN(TRUE); - } #ifdef WITH_PARTITION_STORAGE_ENGINE - { - partition_info *part_info= lpt->table->part_info; - char *part_syntax_buf; - uint syntax_len, i; - bool any_unnormal_state= FALSE; - - if (part_info) { - uint max_part_state_len= part_info->partitions.elements + - part_info->temp_partitions.elements; - if (!(part_info->part_state= (uchar*)sql_alloc(max_part_state_len))) + partition_info *part_info= lpt->table->part_info; + char *part_syntax_buf; + uint syntax_len; + + if (part_info) { - DBUG_RETURN(TRUE); + if (!(part_syntax_buf= generate_partition_syntax(part_info, + &syntax_len, + TRUE, FALSE))) + { + DBUG_RETURN(TRUE); + } + part_info->part_info_string= part_syntax_buf; + part_info->part_info_len= syntax_len; } - part_info->part_state_len= 0; - if (!(part_syntax_buf= generate_partition_syntax(part_info, - &syntax_len, - TRUE, FALSE))) - { - DBUG_RETURN(TRUE); - } - for (i= 0; i < part_info->part_state_len; i++) - { - enum partition_state part_state= - (enum partition_state)part_info->part_state[i]; - if (part_state != PART_NORMAL && part_state != PART_IS_ADDED) - any_unnormal_state= TRUE; - } - if (!any_unnormal_state) - { - part_info->part_state= NULL; - part_info->part_state_len= 0; - } - part_info->part_info_string= part_syntax_buf; - part_info->part_info_len= syntax_len; } - } #endif - /* - We write the frm file with the LOCK_open mutex since otherwise we could - overwrite the frm file as another is reading it in open_table. - */ - lpt->create_info->table_options= lpt->db_options; - VOID(pthread_mutex_lock(&LOCK_open)); - if ((mysql_create_frm(lpt->thd, frm_name, lpt->db, lpt->table_name, - lpt->create_info, lpt->new_create_list, lpt->key_count, - lpt->key_info_buffer, lpt->table->file)) || - ((flags & WFRM_CREATE_HANDLER_FILES) && - lpt->table->file->create_handler_files(path))) - { - error= 1; - goto end; + /* Write shadow frm file */ + lpt->create_info->table_options= lpt->db_options; + if ((mysql_create_frm(lpt->thd, shadow_frm_name, lpt->db, + lpt->table_name, lpt->create_info, + lpt->new_create_list, lpt->key_count, + lpt->key_info_buffer, lpt->table->file)) || + lpt->table->file->create_handler_files(shadow_path, NULL, FALSE)) + { + my_delete(shadow_frm_name, MYF(0)); + error= 1; + goto end; + } } if (flags & WFRM_PACK_FRM) { @@ -365,7 +370,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) */ const void *data= 0; uint length= 0; - if (readfrm(path, &data, &length) || + if (readfrm(shadow_path, &data, &length) || packfrm(data, length, &lpt->pack_frm_data, &lpt->pack_frm_len)) { my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR)); @@ -374,11 +379,31 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) error= 1; goto end; } - error= my_delete(frm_name, MYF(MY_WME)); + error= my_delete(shadow_frm_name, MYF(MY_WME)); } - /* Frm file have been updated to reflect the change about to happen. */ + if (flags & WFRM_INSTALL_SHADOW) + { + /* + Build frm file name + */ + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); + strxmov(frm_name, path, reg_ext, NullS); + /* + When we are changing to use new frm file we need to ensure that we + don't collide with another thread in process to open the frm file. + */ + VOID(pthread_mutex_lock(&LOCK_open)); + if (my_delete(frm_name, MYF(MY_WME)) || + my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || + lpt->table->file->create_handler_files(path, shadow_path, TRUE)) + { + error= 1; + } + VOID(pthread_mutex_unlock(&LOCK_open)); + } + end: - VOID(pthread_mutex_unlock(&LOCK_open)); DBUG_RETURN(error); } @@ -4631,7 +4656,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, error= (mysql_create_frm(thd, reg_path, db, table_name, create_info, prepared_create_list, key_count, key_info_buffer, table->file) || - table->file->create_handler_files(reg_path)); + table->file->create_handler_files(reg_path, NULL, FALSE)); VOID(pthread_mutex_unlock(&LOCK_open)); if (error) goto err; @@ -4677,7 +4702,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, error= (mysql_create_frm(thd, reg_path, db, table_name, create_info, prepared_create_list, key_count, key_info_buffer, table->file) || - table->file->create_handler_files(reg_path)); + table->file->create_handler_files(reg_path, NULL, FALSE)); VOID(pthread_mutex_unlock(&LOCK_open)); if (error) goto err; @@ -4900,7 +4925,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, VOID(pthread_mutex_lock(&LOCK_open)); } /* Tell the handler that a new frm file is in place. */ - if (table->file->create_handler_files(reg_path)) + if (table->file->create_handler_files(reg_path, NULL, FALSE)) { VOID(pthread_mutex_unlock(&LOCK_open)); goto err; diff --git a/sql/unireg.cc b/sql/unireg.cc index 2c5f4b34091..ab362b130b0 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -330,7 +330,7 @@ int rea_create_table(THD *thd, const char *path, // Make sure mysql_create_frm din't remove extension DBUG_ASSERT(*fn_rext(frm_name)); - if (file->create_handler_files(path)) + if (file->create_handler_files(path, NULL, FALSE)) goto err_handler; if (!create_info->frm_only && ha_create_table(thd, path, db, table_name, create_info,0)) From 9b6c2bc2bf0747b9d3d0546d07fa43e75589bed2 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Feb 2006 14:00:00 +0100 Subject: [PATCH 02/48] WL 2826: Another step sql/mysql_priv.h: Set error_inject_code to zero after firing error injection sql/sql_partition.cc: New entries for new functions --- sql/mysql_priv.h | 8 ++- sql/sql_partition.cc | 163 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 161 insertions(+), 10 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b501e4c7663..fd5c2c019de 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -616,7 +616,13 @@ struct Query_cache_query_flags inline bool my_error_inject(int error) { - return (current_thd->variables.error_inject_code == error) ? 1 : 0; + THD *thd= current_thd; + if (thd->variables.error_inject_code == error) + { + thd->variables.error_inject_code= 0; + return 1; + } + return 0; } #define ERROR_INJECTOR_CRASH(code) \ diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 114ac273d52..e9e5fa3fb73 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5114,6 +5114,146 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) } +/* + Write the log entry to ensure that the shadow frm file is removed at + crash. + SYNOPSIS + write_log_shadow_frm() + lpt Struct containing parameters + install_frm Should we log action to install shadow frm or should + the action be to remove the shadow frm file. + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Prepare an entry to the table log indicating a drop/install of the shadow frm + file and its corresponding handler file. +*/ + +bool +write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) +{ + DBUG_ENTER("write_log_shadow_frm"); + DBUG_RETURN(FALSE); +} + + +/* + Write the log entries to ensure that the drop partition command is completed + even in the presence of a crash. + + SYNOPSIS + write_log_drop_partition() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Prepare entries to the table log indicating all partitions to drop and to + install the shadow frm file and remove the old frm file. +*/ + +bool +write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DBUG_ENTER("write_log_drop_partition"); + DBUG_RETURN(FALSE); +} + + +/* + Write the log entries to ensure that the drop partition command is completed + even in the presence of a crash. + + SYNOPSIS + write_log_drop_partition() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Prepare entries to the table log indicating all partitions to drop and to + install the shadow frm file and remove the old frm file. +*/ + +bool +write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DBUG_ENTER("write_log_drop_partition"); + DBUG_RETURN(FALSE); +} + + +/* + Write the log entries to ensure that the add partition command is not + executed at all if a crash before it has completed + + SYNOPSIS + write_log_add_partition() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Prepare entries to the table log indicating all partitions to drop and to + remove the shadow frm file. +*/ + +bool +write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DBUG_ENTER("write_log_add_partition"); + DBUG_RETURN(FALSE); +} + + +/* + Write indicator of how to abort in first phase of change partitions + SYNOPSIS + write_log_ph1_change_partition() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Write the log entries to remove partitions in creation when changing + partitions in an ADD/REORGANIZE/COALESCE command. These commands will + abort the entire operation if the system crashes before the next phase + is done. +*/ + +bool +write_log_ph1_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DBUG_ENTER("write_log_ph1_change_partition"); + DBUG_RETURN(FALSE); +} + + +/* + Write description of how to complete the operation after first phase of + change partitions. + + SYNOPSIS + write_log_ph2_change_partition() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + We will write log entries that specify to remove all partitions reorganised, + to rename others to reflect the new naming scheme and to install the shadow + frm file. +*/ + +bool +write_log_ph2_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DBUG_ENTER("write_log_ph2_change_partition"); + DBUG_RETURN(FALSE); +} + + /* Actually perform the change requested by ALTER TABLE of partitions previously prepared. @@ -5305,7 +5445,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, We insert Error injections at all places where it could be interesting to test if recovery is properly done. */ - if (write_log_shadow_frm(lpt) || + if (write_log_shadow_frm(lpt, FALSE) || ERROR_INJECTOR_CRASH(1000) || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECTOR_CRASH(1001) || @@ -5352,13 +5492,16 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, are still using the old partitioning scheme. Wait until all ongoing users have completed before progressing. 4) Write binlog - 5) Install the new frm file of the table where the partitions are + 5) Now the change is completed except for the installation of the + new frm file. We thus write an action in the log to change to + the shadow frm file + 6) 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) Remove entries from table log - 8) Complete query + 7) Wait until all accesses using the old frm file has completed + 8) Remove entries from table log + 9) Complete query */ - if (write_log_shadow_frm(lpt) || + if (write_log_shadow_frm(lpt, FALSE) || ERROR_INJECTED_CRASH(1010) || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECTED_CRASH(1011) || @@ -5371,11 +5514,13 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || ERROR_INJECTED_CRASH(1014) || - mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || + write_log_shadow_frm(lpt, TRUE) || ERROR_INJECTED_CRASH(1015) || + mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || + ERROR_INJECTED_CRASH(1016) || (close_open_tables_and_downgrade(lpt), FALSE) || write_log_completed(lpt) || - ERROR_INJECTED_CRASH(1016)) + ERROR_INJECTED_CRASH(1017)) { fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); @@ -5437,7 +5582,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 14)Complete query */ - if (write_log_shadow_frm(lpt) || + if (write_log_shadow_frm(lpt, FALSE) || ERROR_INJECT_CRASH(1020) || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECT_CRASH(1021) || From 83d418a25f21931e1f1ac79c8c27b5e893a87d4e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Feb 2006 16:38:08 +0100 Subject: [PATCH 03/48] WL 2826: A third step, fixing generate_partition_syntax sql/mysql_priv.h: Make it possible to set injector code and value Declare header part of a set of new functions sql/sql_partition.cc: Fix generate_partition_syntax to handle shadow variant of frm file --- sql/mysql_priv.h | 15 ++++++++ sql/sql_partition.cc | 86 +++----------------------------------------- 2 files changed, 20 insertions(+), 81 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index fd5c2c019de..22fb67ff3fb 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -611,8 +611,15 @@ struct Query_cache_query_flags #define ERROR_INJECTOR(x) #define ERROR_INJECTOR_ACTION(x) #define ERROR_INJECTOR_CRASH(x) +#define SET_ERROR_INJECT_CODE(x) +#define SET_ERROR_INJECT_VALUE(x) #else +#define SET_ERROR_INJECT_CODE(x) \ + current_thd->variables.error_inject_code= (x) +#define SET_ERROR_INJECT_VALUE(x) \ + current_thd->variables.error_inject_value= (x) + inline bool my_error_inject(int error) { @@ -632,6 +639,7 @@ my_error_inject(int error) #define ERROR_INJECT(code) \ (my_error_inject((code)) ? 1 : 0) #endif + uint build_table_path(char *buff, size_t bufflen, const char *db, const char *table, const char *ext); void write_bin_log(THD *thd, bool clear_error, @@ -1128,7 +1136,14 @@ typedef struct st_lock_param_type } ALTER_PARTITION_PARAM_TYPE; void mem_alloc_error(size_t size); + bool write_table_log(ALTER_PARTITION_PARAM_TYPE *lpt); +bool write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_flag); +bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt); +bool write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt); +bool write_log_ph1_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt); +bool write_log_ph2_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt); + #define WFRM_WRITE_SHADOW 1 #define WFRM_INSTALL_SHADOW 2 #define WFRM_PACK_FRM diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index e9e5fa3fb73..d2a4579f53b 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2388,15 +2388,10 @@ char *generate_partition_syntax(partition_info *part_info, char path[FN_REFLEN]; int err= 0; List_iterator part_it(part_info->partitions); - List_iterator temp_it(part_info->temp_partitions); File fptr; char *buf= NULL; //Return buffer - uint use_temp= 0; - uint no_temp_parts= part_info->temp_partitions.elements; - bool write_part_state; DBUG_ENTER("generate_partition_syntax"); - write_part_state= (part_info->part_state && !part_info->part_state_len); if (unlikely(((fptr= create_temp_file(path,mysql_tmpdir,"psy", 0,0))) < 0)) DBUG_RETURN(NULL); #ifndef __WIN__ @@ -2459,8 +2454,7 @@ char *generate_partition_syntax(partition_info *part_info, err+= add_space(fptr); } } - no_parts= part_info->no_parts; - tot_no_parts= no_parts + no_temp_parts; + tot_no_parts= part_info->partitions.elements; no_subparts= part_info->no_subparts; if (write_all || (!part_info->use_default_partitions)) @@ -2469,57 +2463,10 @@ char *generate_partition_syntax(partition_info *part_info, i= 0; do { - /* - We need to do some clever list manipulation here since we have two - different needs for our list processing and here we take some of the - cost of using a simpler list processing for the other parts of the - code. - - ALTER TABLE REORGANIZE PARTITIONS has the list of partitions to be - the final list as the main list and the reorganised partitions is in - the temporary partition list. Thus when finding the first part added - we insert the temporary list if there is such a list. If there is no - temporary list we are performing an ADD PARTITION. - */ - if (use_temp && use_temp <= no_temp_parts) + part_elem= part_it++; + if (part_elem->part_state != PART_TO_BE_DROPPED && + part_elem->part_state != PART_REORGED_DROPPED) { - part_elem= temp_it++; - DBUG_ASSERT(no_temp_parts); - no_temp_parts--; - } - else if (use_temp) - { - DBUG_ASSERT(no_parts); - part_elem= save_part_elem; - use_temp= 0; - no_parts--; - } - else - { - part_elem= part_it++; - if ((part_elem->part_state == PART_TO_BE_ADDED || - part_elem->part_state == PART_IS_ADDED) && no_temp_parts) - { - save_part_elem= part_elem; - part_elem= temp_it++; - no_temp_parts--; - use_temp= 1; - } - else - { - DBUG_ASSERT(no_parts); - no_parts--; - } - } - - if (part_elem->part_state != PART_IS_DROPPED) - { - if (write_part_state) - { - uint32 part_state_id= part_info->part_state_len; - part_info->part_state[part_state_id]= (uchar)part_elem->part_state; - part_info->part_state_len= part_state_id+1; - } err+= add_partition(fptr); err+= add_string(fptr, part_elem->partition_name); err+= add_space(fptr); @@ -2558,7 +2505,6 @@ char *generate_partition_syntax(partition_info *part_info, if (i == (tot_no_parts-1)) err+= add_end_parenthesis(fptr); } while (++i < tot_no_parts); - DBUG_ASSERT(!no_parts && !no_temp_parts); } if (err) goto close_file; @@ -4576,6 +4522,7 @@ that are reorganised. my_error(ER_ROW_IS_REFERENCED, MYF(0)); DBUG_RETURN(TRUE); } + tab_part_info->no_parts-= no_parts_dropped; } else if ((alter_info->flags & ALTER_OPTIMIZE_PARTITION) || (alter_info->flags & ALTER_ANALYZE_PARTITION) || @@ -5138,29 +5085,6 @@ write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) } -/* - Write the log entries to ensure that the drop partition command is completed - even in the presence of a crash. - - SYNOPSIS - write_log_drop_partition() - lpt Struct containing parameters - RETURN VALUES - TRUE Error - FALSE Success - DESCRIPTION - Prepare entries to the table log indicating all partitions to drop and to - install the shadow frm file and remove the old frm file. -*/ - -bool -write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) -{ - DBUG_ENTER("write_log_drop_partition"); - DBUG_RETURN(FALSE); -} - - /* Write the log entries to ensure that the drop partition command is completed even in the presence of a crash. From c31c4eec46819d67fa9f1f78d9091c9e616ec5fb Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Feb 2006 17:05:22 +0100 Subject: [PATCH 04/48] WL 2826: Fourth step Remove partition state from frm file Ensure we can still load tables created in 5.1.6 for the time being sql/table.cc: Remove partition state from frm file Ensure we can still load tables created in 5.1.6 for the time being sql/unireg.cc: Remove partition state from frm file Ensure we can still load tables created in 5.1.6 for the time being --- sql/table.cc | 35 ++++++----------------------------- sql/unireg.cc | 7 ------- 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/sql/table.cc b/sql/table.cc index b912683d371..046ed6d1add 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -638,38 +638,15 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, #endif next_chunk+= 5 + partition_info_len; } - if (share->mysql_version > 50105 && next_chunk + 5 < buff_end) + if (share->mysql_version == 50106) { /* - Partition state was introduced to support partition management in version 5.1.5 - */ - uint32 part_state_len= uint4korr(next_chunk); -#ifdef WITH_PARTITION_STORAGE_ENGINE - if ((share->part_state_len= part_state_len)) - if (!(share->part_state= - (uchar*) memdup_root(&share->mem_root, next_chunk + 4, - part_state_len))) - { - my_free(buff, MYF(0)); - goto err; - } -#else - if (part_state_len) - { - DBUG_PRINT("info", ("WITH_PARTITION_STORAGE_ENGINE is not defined")); - my_free(buff, MYF(0)); - goto err; - } -#endif - next_chunk+= 4 + part_state_len; + Partition state array was here in version 5.1.6, this code makes + it possible to load a 5.1.6 table in later versions. Can most + likely be removed at some point in time. + */ + next_chunk+= 4; } -#ifdef WITH_PARTITION_STORAGE_ENGINE - else - { - share->part_state_len= 0; - share->part_state= NULL; - } -#endif keyinfo= share->key_info; for (i= 0; i < keys; i++, keyinfo++) { diff --git a/sql/unireg.cc b/sql/unireg.cc index ab362b130b0..ce886253554 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -136,7 +136,6 @@ bool mysql_create_frm(THD *thd, const char *file_name, if (part_info) { create_info->extra_size+= part_info->part_info_len; - create_info->extra_size+= part_info->part_state_len; } #endif @@ -209,12 +208,6 @@ bool mysql_create_frm(THD *thd, const char *file_name, my_write(file, (const byte*)part_info->part_info_string, part_info->part_info_len + 1, MYF_RW)) goto err; - DBUG_PRINT("info", ("Part state len = %d", part_info->part_state_len)); - int4store(buff, part_info->part_state_len); - if (my_write(file, (const byte*)buff, 4, MYF_RW) || - my_write(file, (const byte*)part_info->part_state, - part_info->part_state_len, MYF_RW)) - goto err; } else #endif From 04c95dc23a659e0abbd4aa1e8159ae350754dfbf Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Feb 2006 21:38:35 +0100 Subject: [PATCH 05/48] WL 2826: Fifth step Removed partition state from parser sql/sql_yacc.yy: Removed partition state from parser --- sql/sql_yacc.yy | 71 ++++--------------------------------------------- 1 file changed, 5 insertions(+), 66 deletions(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a86eccb493f..03a6ba4baca 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3582,75 +3582,14 @@ part_definition: LEX *lex= Lex; partition_info *part_info= lex->part_info; partition_element *p_elem= new partition_element(); - uint part_id= part_info->partitions.elements + - part_info->temp_partitions.elements; - enum partition_state part_state; + uint part_id= part_info->partitions.elements; - if (part_info->part_state) - part_state= (enum partition_state)part_info->part_state[part_id]; - else - part_state= PART_NORMAL; - switch (part_state) + if (!p_elem || part_info->partitions.push_back(p_elem)) { - case PART_TO_BE_DROPPED: - /* - This part is currently removed so we keep it in a - temporary list for REPAIR TABLE to be able to handle - failures during drop partition process. - */ - case PART_TO_BE_ADDED: - /* - This part is currently being added so we keep it in a - temporary list for REPAIR TABLE to be able to handle - failures during add partition process. - */ - if (!p_elem || part_info->temp_partitions.push_back(p_elem)) - { - mem_alloc_error(sizeof(partition_element)); - YYABORT; - } - break; - case PART_IS_ADDED: - /* - Part has been added and is now a normal partition - */ - case PART_TO_BE_REORGED: - /* - This part is currently reorganised, it is still however - used so we keep it in the list of partitions. We do - however need the state to be able to handle REPAIR TABLE - after failures in the reorganisation process. - */ - case PART_REORGED_DROPPED: - /* - This part is currently reorganised as part of a - COALESCE PARTITION and it will be dropped without a new - replacement partition after completing the reorganisation. - */ - case PART_CHANGED: - /* - This part is currently split or merged as part of ADD - PARTITION for a hash partition or as part of COALESCE - PARTITION for a hash partitioned table. - */ - case PART_IS_CHANGED: - /* - This part has been split or merged as part of ADD - PARTITION for a hash partition or as part of COALESCE - PARTITION for a hash partitioned table. - */ - case PART_NORMAL: - if (!p_elem || part_info->partitions.push_back(p_elem)) - { - mem_alloc_error(sizeof(partition_element)); - YYABORT; - } - break; - default: - mem_alloc_error((part_id * 1000) + part_state); - YYABORT; + mem_alloc_error(sizeof(partition_element)); + YYABORT; } - p_elem->part_state= part_state; + p_elem->part_state= PART_NORMAL; part_info->curr_part_elem= p_elem; part_info->current_partition= p_elem; part_info->use_default_partitions= FALSE; From e254606f0bbf993a21b6f1f0ad5fe12be8739cbe Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Feb 2006 12:05:29 -0500 Subject: [PATCH 06/48] WL #2826: Sixth step, made it work with test cases BUILD/SETUP.sh: Fixed BUILD scripts BUILD/compile-pentium-debug-max: Fixed BUILD scripts sql/ha_partition.cc: Need to handle states differently when creating handler files sql/mysql_priv.h: Some error inject fixes sql/mysqld.cc: Some error inject fixes sql/set_var.cc: Some error inject fixes sql/sql_partition.cc: Fixing a bug with generate partition syntax A number of fixes sql/sql_table.cc: Fix a few bugs sql/table.cc: fix --- BUILD/SETUP.sh | 2 +- BUILD/compile-pentium-debug-max | 4 +- sql/ha_partition.cc | 8 ++-- sql/mysql_priv.h | 21 +++++----- sql/mysqld.cc | 4 ++ sql/set_var.cc | 3 +- sql/sql_partition.cc | 71 +++++++++++++++++++++------------ sql/sql_table.cc | 6 +-- sql/table.cc | 2 + 9 files changed, 76 insertions(+), 45 deletions(-) diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index e76507b1a77..00e78d0719d 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -71,7 +71,7 @@ pentium_cflags="$check_cpu_cflags" pentium64_cflags="$check_cpu_cflags -m64" ppc_cflags="$check_cpu_cflags" sparc_cflags="" -error_inject_flag="--with-error-inject " +error_inject="--with-error-inject " # be as fast as we can be without losing our ability to backtrace fast_cflags="-O3 -fno-omit-frame-pointer" diff --git a/BUILD/compile-pentium-debug-max b/BUILD/compile-pentium-debug-max index d065ed2bf71..9aa71239bd8 100755 --- a/BUILD/compile-pentium-debug-max +++ b/BUILD/compile-pentium-debug-max @@ -3,9 +3,9 @@ path=`dirname $0` . "$path/SETUP.sh" $@ --with-debug=full -extra_flags="$pentium_cflags $debug_cflags $max_cflags $error_inject_flag" +extra_flags="$pentium_cflags $debug_cflags $max_cflags" c_warnings="$c_warnings $debug_extra_warnings" cxx_warnings="$cxx_warnings $debug_extra_warnings" -extra_configs="$pentium_configs $debug_configs $max_configs" +extra_configs="$pentium_configs $debug_configs $max_configs $error_inject" . "$path/FINISH.sh" diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index d318c4ab348..193fe863f8c 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1879,8 +1879,8 @@ bool ha_partition::create_handler_file(const char *name) { part_elem= part_it++; if (part_elem->part_state != PART_NORMAL && - part_elem->part_state != PART_IS_ADDED && - part_elem->part_state != PART_IS_CHANGED) + part_elem->part_state != PART_TO_BE_ADDED && + part_elem->part_state != PART_CHANGED) continue; tablename_to_filename(part_elem->partition_name, part_name, FN_REFLEN); @@ -1931,8 +1931,8 @@ bool ha_partition::create_handler_file(const char *name) { part_elem= part_it++; if (part_elem->part_state != PART_NORMAL && - part_elem->part_state != PART_IS_ADDED && - part_elem->part_state != PART_IS_CHANGED) + part_elem->part_state != PART_TO_BE_ADDED && + part_elem->part_state != PART_CHANGED) continue; if (!m_is_sub_partitioned) { diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 22fb67ff3fb..8c207992d5e 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -608,9 +608,9 @@ struct Query_cache_query_flags in various error cases. */ #ifndef ERROR_INJECT_SUPPORT -#define ERROR_INJECTOR(x) -#define ERROR_INJECTOR_ACTION(x) -#define ERROR_INJECTOR_CRASH(x) +#define ERROR_INJECT(x) 0 +#define ERROR_INJECT_ACTION(x) 0 +#define ERROR_INJECT_CRASH(x) 0 #define SET_ERROR_INJECT_CODE(x) #define SET_ERROR_INJECT_VALUE(x) #else @@ -624,7 +624,7 @@ inline bool my_error_inject(int error) { THD *thd= current_thd; - if (thd->variables.error_inject_code == error) + if (thd->variables.error_inject_code == (uint)error) { thd->variables.error_inject_code= 0; return 1; @@ -632,10 +632,10 @@ my_error_inject(int error) return 0; } -#define ERROR_INJECTOR_CRASH(code) \ - (my_error_inject((code)) ? ((DBUG_ASSERT(0)), 0) : 0 -#define ERROR_INJECTOR_ACTION(code, action) \ - (my_error_inject((code)) ? ((action), 0) : 0 +#define ERROR_INJECT_CRASH(code) \ + (my_error_inject((code)) ? ((DBUG_ASSERT(0)), 0) : 0) +#define ERROR_INJECT_ACTION(code, action) \ + (my_error_inject((code)) ? ((action), 0) : 0) #define ERROR_INJECT(code) \ (my_error_inject((code)) ? 1 : 0) #endif @@ -1146,7 +1146,7 @@ bool write_log_ph2_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt); #define WFRM_WRITE_SHADOW 1 #define WFRM_INSTALL_SHADOW 2 -#define WFRM_PACK_FRM +#define WFRM_PACK_FRM 4 bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags); bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt); void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt); @@ -1317,6 +1317,9 @@ extern ulong delayed_insert_timeout; extern ulong delayed_insert_limit, delayed_queue_size; extern ulong delayed_insert_threads, delayed_insert_writes; extern ulong delayed_rows_in_use,delayed_insert_errors; +#ifdef ERROR_INJECT_SUPPORT +extern ulong error_inject_code, error_inject_value; +#endif extern ulong slave_open_temp_tables; extern ulong query_cache_size, query_cache_min_res_unit; extern ulong slow_launch_threads, slow_launch_time; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 07e2abc1de5..d9853e26197 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -503,6 +503,10 @@ ulong aborted_threads, aborted_connects; ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size; ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use; ulong delayed_insert_errors,flush_time; +#ifdef ERROR_INJECT_SUPPORT +ulong error_inject_code= 0; +ulong error_inject_value= 0; +#endif ulong specialflag=0; ulong binlog_cache_use= 0, binlog_cache_disk_use= 0; ulong max_connections, max_connect_errors; diff --git a/sql/set_var.cc b/sql/set_var.cc index bc6c68e87f6..4c156c134cf 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -217,10 +217,11 @@ sys_var_long_ptr sys_delayed_queue_size("delayed_queue_size", &delayed_queue_size); #ifdef ERROR_INJECT_SUPPORT sys_var_long_ptr sys_error_inject_code("error_inject_code", - &error_inject_code); + &error_inject_code); sys_var_long_ptr sys_error_inject_value("error_inject_value", &error_inject_value); #endif + sys_var_event_executor sys_event_executor("event_scheduler", &event_executor_running_global_var); sys_var_long_ptr sys_expire_logs_days("expire_logs_days", diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index d2a4579f53b..ed8b62cc300 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2459,6 +2459,7 @@ char *generate_partition_syntax(partition_info *part_info, if (write_all || (!part_info->use_default_partitions)) { + bool first= TRUE; err+= add_begin_parenthesis(fptr); i= 0; do @@ -2467,6 +2468,12 @@ char *generate_partition_syntax(partition_info *part_info, if (part_elem->part_state != PART_TO_BE_DROPPED && part_elem->part_state != PART_REORGED_DROPPED) { + if (!first) + { + err+= add_comma(fptr); + err+= add_space(fptr); + } + first= FALSE; err+= add_partition(fptr); err+= add_string(fptr, part_elem->partition_name); err+= add_space(fptr); @@ -2496,11 +2503,6 @@ char *generate_partition_syntax(partition_info *part_info, err+= add_end_parenthesis(fptr); } while (++j < no_subparts); } - if (i != (tot_no_parts-1)) - { - err+= add_comma(fptr); - err+= add_space(fptr); - } } if (i == (tot_no_parts-1)) err+= add_end_parenthesis(fptr); @@ -5178,6 +5180,25 @@ write_log_ph2_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) } +/* + Remove entry from table log and release resources for others to use + + SYNOPSIS + write_log_completed() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success +*/ +static +bool +write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DBUG_ENTER("write_log_ph2_change_partition"); + DBUG_RETURN(FALSE); +} + + /* Actually perform the change requested by ALTER TABLE of partitions previously prepared. @@ -5308,8 +5329,8 @@ 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_WRITE_SHADOW | WFRM_PACK_FRM)) || - (mysql_change_partitions(lpt))) + if (mysql_write_frm(lpt, WFRM_WRITE_SHADOW | WFRM_PACK_FRM) || + mysql_change_partitions(lpt)) { fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); @@ -5370,25 +5391,25 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, to test if recovery is properly done. */ if (write_log_shadow_frm(lpt, FALSE) || - ERROR_INJECTOR_CRASH(1000) || + ERROR_INJECT_CRASH(1000) || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || - ERROR_INJECTOR_CRASH(1001) || + ERROR_INJECT_CRASH(1001) || write_log_drop_partition(lpt) || - ERROR_INJECTOR_CRASH(1002) || + ERROR_INJECT_CRASH(1002) || abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && - write_bin_log(thd, FALSE, - thd->query, thd->query_length), FALSE) || - ERROR_INJECTOR_CRASH(1003) || + (write_bin_log(thd, FALSE, + thd->query, thd->query_length), FALSE)) || + ERROR_INJECT_CRASH(1003) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || (close_open_tables_and_downgrade(lpt), FALSE) || - ERROR_INJECTOR_CRASH(1004) || + ERROR_INJECT_CRASH(1004) || table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE) || - ERROR_INJECTOR_CRASH(1005) || + ERROR_INJECT_CRASH(1005) || mysql_drop_partitions(lpt) || - ERROR_INJECTOR_CRASH(1006) || + ERROR_INJECT_CRASH(1006) || write_log_completed(lpt) || - ERROR_INJECTOR_CRASH(1007) || + ERROR_INJECT_CRASH(1007) || (mysql_wait_completed_table(lpt, table), FALSE)) { fast_alter_partition_error_handler(lpt); @@ -5426,25 +5447,25 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 9) Complete query */ if (write_log_shadow_frm(lpt, FALSE) || - ERROR_INJECTED_CRASH(1010) || + ERROR_INJECT_CRASH(1010) || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || - ERROR_INJECTED_CRASH(1011) || + ERROR_INJECT_CRASH(1011) || write_log_add_partition(lpt) || - ERROR_INJECTED_CRASH(1012) || + ERROR_INJECT_CRASH(1012) || mysql_change_partitions(lpt) || - ERROR_INJECTED_CRASH(1013) || + ERROR_INJECT_CRASH(1013) || abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - ERROR_INJECTED_CRASH(1014) || + ERROR_INJECT_CRASH(1014) || write_log_shadow_frm(lpt, TRUE) || - ERROR_INJECTED_CRASH(1015) || + ERROR_INJECT_CRASH(1015) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || - ERROR_INJECTED_CRASH(1016) || + ERROR_INJECT_CRASH(1016) || (close_open_tables_and_downgrade(lpt), FALSE) || write_log_completed(lpt) || - ERROR_INJECTED_CRASH(1017)) + ERROR_INJECT_CRASH(1017)) { fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 809a70a0d45..fe37b70c3b3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -307,9 +307,9 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) /* Build shadow frm file name */ - build_table_filename(shadow_path, sizeof(path), lpt->db, + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); - strxmov(shadow_frm_name, path, reg_ext, NullS); + strxmov(shadow_frm_name, shadow_path, reg_ext, NullS); if (flags & WFRM_WRITE_SHADOW) { if (mysql_copy_create_list(lpt->create_list, @@ -324,7 +324,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) lpt->table->file, &lpt->key_info_buffer, &lpt->key_count, - /*select_field_count*/ 0))) + /*select_field_count*/ 0)) { DBUG_RETURN(TRUE); } diff --git a/sql/table.cc b/sql/table.cc index 046ed6d1add..ed34273334d 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -638,6 +638,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, #endif next_chunk+= 5 + partition_info_len; } +#if 0 if (share->mysql_version == 50106) { /* @@ -647,6 +648,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, */ next_chunk+= 4; } +#endif keyinfo= share->key_info; for (i= 0; i < keys; i++, keyinfo++) { From 7ea92dcc3cd1bde451ebd63a9ea0b85aa89cbe53 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Feb 2006 18:05:30 +0100 Subject: [PATCH 07/48] WL 2826: Seventh step, more fixes for error injects Removed session variables for error injects started using DBUG macros for error injects include/my_dbug.h: Added new DBUG macros sql/sql_class.cc: Removed session variables for error injects sql/sql_class.h: Removed session variables for error injects sql/mysql_priv.h: Changed ERROR INJECT macros to use DBUG macros sql/mysqld.cc: Removed session variables for error injects sql/set_var.cc: Removed session variables for error injects --- include/my_dbug.h | 6 ++++++ sql/mysql_priv.h | 31 ++++++++++++++++++++----------- sql/mysqld.cc | 10 ---------- sql/set_var.cc | 11 ----------- sql/sql_class.cc | 3 +++ sql/sql_class.h | 7 +++---- 6 files changed, 32 insertions(+), 36 deletions(-) diff --git a/include/my_dbug.h b/include/my_dbug.h index b76a3fcc8c9..f20ba696a95 100644 --- a/include/my_dbug.h +++ b/include/my_dbug.h @@ -72,6 +72,10 @@ extern void _db_unlock_file(void); #define DBUG_ASSERT(A) assert(A) #define DBUG_EXECUTE_IF(keyword,a1) \ {if (_db_on_) {if (_db_strict_keyword_ (keyword)) { a1 }}} +#define DBUG_EXECUTE_COND(keyword, a1) \ + (_db_on_ ? ((_db_strict_keyword_ (keyword)) ? ((a1), 0) : 0) : 0) +#define DBUG_COND(keyword) \ + ((_db_on_ && _db_strict_keyword_ (keyword)) ? 1 : 0) #else /* No debugger */ #define DBUG_ENTER(a1) @@ -79,6 +83,8 @@ extern void _db_unlock_file(void); #define DBUG_VOID_RETURN return #define DBUG_EXECUTE(keyword,a1) {} #define DBUG_EXECUTE_IF(keyword,a1) {} +#define DBUG_EXECUTE_COND(keyword, a1) 0 +#define DBUG_COND(keyword) 0 #define DBUG_PRINT(keyword,arglist) {} #define DBUG_PUSH(a1) {} #define DBUG_POP() {} diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 8c207992d5e..2324af23442 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -608,36 +608,45 @@ struct Query_cache_query_flags in various error cases. */ #ifndef ERROR_INJECT_SUPPORT + #define ERROR_INJECT(x) 0 -#define ERROR_INJECT_ACTION(x) 0 +#define ERROR_INJECT_ACTION(x,action) 0 #define ERROR_INJECT_CRASH(x) 0 -#define SET_ERROR_INJECT_CODE(x) +#define ERROR_INJECT_VALUE(x) 0 +#define ERROR_INJECT_VALUE_ACTION(x,action) 0 +#define ERROR_INJECT_VALUE_CRASH(x) 0 #define SET_ERROR_INJECT_VALUE(x) + #else -#define SET_ERROR_INJECT_CODE(x) \ - current_thd->variables.error_inject_code= (x) #define SET_ERROR_INJECT_VALUE(x) \ - current_thd->variables.error_inject_value= (x) + current_thd->error_inject_value= (x) inline bool -my_error_inject(int error) +my_error_inject(int value) { THD *thd= current_thd; - if (thd->variables.error_inject_code == (uint)error) + if (thd->error_inject_value == (uint)value) { - thd->variables.error_inject_code= 0; + thd->error_inject_value= 0; return 1; } return 0; } #define ERROR_INJECT_CRASH(code) \ - (my_error_inject((code)) ? ((DBUG_ASSERT(0)), 0) : 0) + DBUG_EXECUTE_COND(code, abort();) #define ERROR_INJECT_ACTION(code, action) \ - (my_error_inject((code)) ? ((action), 0) : 0) + DBUG_EXECUTE_COND(code, action) #define ERROR_INJECT(code) \ - (my_error_inject((code)) ? 1 : 0) + DBUG_COND(code) +#define ERROR_INJECT_VALUE(value) \ + my_error_inject(value) +#define ERROR_INJECT_VALUE_ACTION(value,action) \ + (my_error_inject(value) ? (action) : 0) +#define ERROR_INJECT_VALUE_CRASH(value) \ + (my_error_inject(value) ? abort() : 0) + #endif uint build_table_path(char *buff, size_t bufflen, const char *db, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d9853e26197..f5b93e6a5e5 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -503,10 +503,6 @@ ulong aborted_threads, aborted_connects; ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size; ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use; ulong delayed_insert_errors,flush_time; -#ifdef ERROR_INJECT_SUPPORT -ulong error_inject_code= 0; -ulong error_inject_value= 0; -#endif ulong specialflag=0; ulong binlog_cache_use= 0, binlog_cache_disk_use= 0; ulong max_connections, max_connect_errors; @@ -7059,12 +7055,6 @@ static void mysql_init_variables(void) max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; global_system_variables.old_passwords= 0; global_system_variables.old_alter_table= 0; -#ifdef ERROR_INJECT_SUPPORT - global_system_variables.error_inject_code= 0; - global_system_variables.error_inject_value= 0; - max_system_variables.error_inject_code= ~0; - max_system_variables.error_inject_value= ~0; -#endif /* Default behavior for 4.1 and 5.0 is to treat NULL values as unequal diff --git a/sql/set_var.cc b/sql/set_var.cc index 4c156c134cf..b85b2576b83 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -215,13 +215,6 @@ sys_var_long_ptr sys_delayed_insert_timeout("delayed_insert_timeout", &delayed_insert_timeout); sys_var_long_ptr sys_delayed_queue_size("delayed_queue_size", &delayed_queue_size); -#ifdef ERROR_INJECT_SUPPORT -sys_var_long_ptr sys_error_inject_code("error_inject_code", - &error_inject_code); -sys_var_long_ptr sys_error_inject_value("error_inject_value", - &error_inject_value); -#endif - sys_var_event_executor sys_event_executor("event_scheduler", &event_executor_running_global_var); sys_var_long_ptr sys_expire_logs_days("expire_logs_days", @@ -736,10 +729,6 @@ SHOW_VAR init_vars[]= { {sys_div_precincrement.name,(char*) &sys_div_precincrement,SHOW_SYS}, {sys_engine_condition_pushdown.name, (char*) &sys_engine_condition_pushdown, SHOW_SYS}, -#ifdef ERROR_INJECT_SUPPORT - {sys_error_inject_code.name,(char*) &sys_error_inject_code, SHOW_SYS}, - {sys_error_inject_value.name,(char*)&sys_error_inject_value, SHOW_SYS}, -#endif {sys_event_executor.name, (char*) &sys_event_executor, SHOW_SYS}, {sys_expire_logs_days.name, (char*) &sys_expire_logs_days, SHOW_SYS}, {sys_flush.name, (char*) &sys_flush, SHOW_SYS}, diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 959e4912c1c..bb110bef31f 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -222,6 +222,9 @@ THD::THD() cuted_fields= sent_row_count= 0L; limit_found_rows= 0; statement_id_counter= 0UL; +#ifdef ERROR_INJECT_SUPPORT + error_inject_value= 0UL; +#endif // Must be reset to handle error with THD's created for init of mysqld lex->current_select= 0; start_time=(time_t) 0; diff --git a/sql/sql_class.h b/sql/sql_class.h index bf6633f98ed..e78dfed30ab 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -186,10 +186,6 @@ struct system_variables ha_rows max_join_size; ulong auto_increment_increment, auto_increment_offset; ulong bulk_insert_buff_size; -#ifdef ERROR_INJECT_SUPPORT - ulong error_inject_code; - ulong error_inject_value; -#endif ulong join_buff_size; ulong long_query_time; ulong max_allowed_packet; @@ -1103,6 +1099,9 @@ public: query_id_t query_id, warn_id; ulong thread_id, col_access; +#ifdef ERROR_INJECT_SUPPORT + ulong error_inject_value; +#endif /* Statement id is thread-wide. This counter is used to generate ids */ ulong statement_id_counter; ulong rand_saved_seed1, rand_saved_seed2; From 846adac5e932d0f12e149a813cea8816064cf635 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Feb 2006 18:05:31 +0100 Subject: [PATCH 08/48] WL 2826: Eigth step Inserted monty patch to allow for adding and dropping DBUG keywords per thread dbug/dbug.c: Inserted monty patch to allow for adding and dropping DBUG keywords per thread include/my_dbug.h: Inserted monty patch to allow for adding and dropping DBUG keywords per thread --- dbug/dbug.c | 87 ++++++++++++++++++++++++++++++++++++++++++++--- include/my_dbug.h | 8 ++++- 2 files changed, 89 insertions(+), 6 deletions(-) diff --git a/dbug/dbug.c b/dbug/dbug.c index 91b7e7b6c4c..6604b8bdb98 100644 --- a/dbug/dbug.c +++ b/dbug/dbug.c @@ -249,6 +249,7 @@ typedef struct st_code_state { uint u_line; /* User source code line number */ int locked; /* If locked with _db_lock_file */ const char *u_keyword; /* Keyword for current macro */ + struct link *keywords; /* Thread specific, active keywords */ } CODE_STATE; /* Parse a debug command string */ @@ -1252,7 +1253,9 @@ static BOOLEAN DoProfile () BOOLEAN _db_strict_keyword_ ( const char *keyword) { - if (stack -> keywords == NULL) + CODE_STATE *state; + if (stack->keywords == NULL && + (!(state= code_state()) || state->keywords == NULL)) return FALSE; return _db_keyword_ (keyword); } @@ -1288,16 +1291,15 @@ const char *keyword) REGISTER BOOLEAN result; CODE_STATE *state; - if (!init_done) - _db_push_ (""); - /* Sasha: pre-my_thread_init() safety */ if (!(state=code_state())) return FALSE; result = FALSE; if (DEBUGGING && !state->disable_output && state->level <= stack -> maxdepth && InList (stack -> functions, state->func) && - InList (stack -> keywords, keyword) && + (InList (stack -> keywords, keyword) || + (state -> keywords && + InList (state -> keywords, keyword))) && InList (stack -> processes, _db_process_)) result = TRUE; return (result); @@ -1373,6 +1375,81 @@ struct link *linkp) } +/* + * FUNCTION + * + * Add key word to _db_strict_keyword_ list + * + * SYNOPSIS + * + * VOID _db_add_strict_keyword(keyword) + * const char *keyword; + * + * DESCRIPTION + * + * Add key word to _db_strict_keyword_ to active DEBUG_EXECUTE_IF + * statements for this thread only + * + * Returns TRUE if keyword accepted, FALSE otherwise. + * + */ + +BOOLEAN _db_add_strict_keyword_(const char *keyword) +{ + CODE_STATE *state; + struct link *tmp; + uint length; + + if (!(state=code_state()) || + !(tmp= (struct link *) DbugMalloc(sizeof(struct link) + + (length= strlen(keyword)+1)))) + return FALSE; + tmp->str= (char*) (tmp+1); + memcpy(tmp->str, keyword, length); + tmp->next_link= state->keywords; + state->keywords= tmp; + return TRUE; +} + +/* + * FUNCTION + * + * Remove key word from thread specific _db_strict_keyword_ list + * + * SYNOPSIS + * + * VOID _db_del_strict_keyword_(keyword) + * const char *keyword; + * + * DESCRIPTION + * + * Delete key word from _db_strict_keyword_ to decative DEBUG_EXECUTE_IF + * statements for this thread only + * + * Returns TRUE if keyword deleted, FALSE otherwise. + * + */ + +BOOLEAN _db_del_strict_keyword_(const char *keyword) +{ + CODE_STATE *state; + struct link *link, **linkp; + + if (!(state=code_state())) + return FALSE; + + for (linkp= &state->keywords; (link= *linkp); linkp= &link->next_link) + { + if (STREQ(link->str, keyword)) + { + *linkp= link->next_link; + free(link); + return TRUE; + } + } + return (FALSE); +} + /* * FUNCTION * diff --git a/include/my_dbug.h b/include/my_dbug.h index f20ba696a95..ac6eec46716 100644 --- a/include/my_dbug.h +++ b/include/my_dbug.h @@ -24,8 +24,10 @@ extern "C" { extern int _db_on_,_no_db_; extern FILE *_db_fp_; extern char *_db_process_; -extern int _db_keyword_(const char *keyword); +extern int _db_keyword_(const char *keyword); extern int _db_strict_keyword_(const char *keyword); +extern int _db_add_strict_keyword_(const char *keyword); +extern int _db_del_strict_keyword_(const char *keyword); extern void _db_setjmp_(void); extern void _db_longjmp_(void); extern void _db_push_(const char *control); @@ -76,6 +78,8 @@ extern void _db_unlock_file(void); (_db_on_ ? ((_db_strict_keyword_ (keyword)) ? ((a1), 0) : 0) : 0) #define DBUG_COND(keyword) \ ((_db_on_ && _db_strict_keyword_ (keyword)) ? 1 : 0) +#define DBUG_ADD_KEYWORD(key) _db_add_strict_keyword_(key) +#define DBUG_DEL_KEYWORD(key) _db_del_strict_keyword_(key) #else /* No debugger */ #define DBUG_ENTER(a1) @@ -85,6 +89,8 @@ extern void _db_unlock_file(void); #define DBUG_EXECUTE_IF(keyword,a1) {} #define DBUG_EXECUTE_COND(keyword, a1) 0 #define DBUG_COND(keyword) 0 +#define DBUG_ADD_KEYWORD(key) +#define DBUG_DEL_KEYWORD(key) #define DBUG_PRINT(keyword,arglist) {} #define DBUG_PUSH(a1) {} #define DBUG_POP() {} From dde234ae1d7b4762149cc6e2a931e7d035899061 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 4 Feb 2006 13:03:35 +0100 Subject: [PATCH 09/48] WL 2826: Nineth step Updated error inject scripts dbug/dbug_long.h: Updated scripts in dub_long.h as well sql/mysql_priv.h: Updated error inject scripts --- dbug/dbug_long.h | 13 +++++++++++++ sql/mysql_priv.h | 16 ++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/dbug/dbug_long.h b/dbug/dbug_long.h index 829df181ef1..4035ca56b66 100644 --- a/dbug/dbug_long.h +++ b/dbug/dbug_long.h @@ -127,6 +127,11 @@ # define DBUG_SETJMP setjmp # define DBUG_LONGJMP longjmp # define DBUG_DUMP(keyword,a1) +# define DBUG_EXECUTE_IF(keyword, a1) +# define DBUG_EXECUTE_COND(keyword, a1) 0 +# define DBUG_COND(keyword) 0 +# define DBUG_ADD_KEYWORD(key) +# define DBUG_DEL_KEYWORD(key) # else # define DBUG_ENTER(a) \ auto char *_db_func_; auto char *_db_file_; auto int _db_level_; \ @@ -157,4 +162,12 @@ # define DBUG_SETJMP(a1) (_db_setjmp_ (), setjmp (a1)) # define DBUG_LONGJMP(a1,a2) (_db_longjmp_ (), longjmp (a1, a2)) # define DBUG_DUMP(keyword,a1,a2) _db_dump_(__LINE__,keyword,a1,a2) +# define DBUG_EXECUTE_IF(keyword,a1) \ + {if (_db_on_) {if (_db_strict_keyword_ (keyword)) { a1 }}} +# define DBUG_EXECUTE_COND(keyword, a1) \ + (_db_on_ ? ((_db_strict_keyword_ (keyword)) ? ((a1), 0) : 0) : 0) +# define DBUG_COND(keyword) \ + ((_db_on_ && _db_strict_keyword_ (keyword)) ? 1 : 0) +# define DBUG_ADD_KEYWORD(key) _db_add_strict_keyword_(key) +# define DBUG_DEL_KEYWORD(key) _db_del_strict_keyword_(key) # endif diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2324af23442..2718f5d855d 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -622,6 +622,18 @@ struct Query_cache_query_flags #define SET_ERROR_INJECT_VALUE(x) \ current_thd->error_inject_value= (x) +inline bool +my_error_inject_name(const char *dbug_str) +{ + if (_db_on_ && _db_strict_keyword_ (dbug_str)) + { + DBUG_DEL_KEYWORD(dbug_str); + return 1; + } + return 0; +} + + inline bool my_error_inject(int value) { @@ -637,9 +649,9 @@ my_error_inject(int value) #define ERROR_INJECT_CRASH(code) \ DBUG_EXECUTE_COND(code, abort();) #define ERROR_INJECT_ACTION(code, action) \ - DBUG_EXECUTE_COND(code, action) + (my_error_inject_name(code) ? ((action), 0) : 0) #define ERROR_INJECT(code) \ - DBUG_COND(code) + my_error_inject_name(code) #define ERROR_INJECT_VALUE(value) \ my_error_inject(value) #define ERROR_INJECT_VALUE_ACTION(value,action) \ From 84627f5bc7756860d4d6641df15f8d966dca9738 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 6 Feb 2006 21:47:03 +0100 Subject: [PATCH 10/48] WL 2826: Step 10 New methods to read/write/initialise table log sql/mysql_priv.h: New methods to read/write/initialise table log sql/sql_table.cc: New methods to read/write/initialise table log --- sql/mysql_priv.h | 19 +++++++- sql/sql_table.cc | 120 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 133 insertions(+), 6 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2718f5d855d..e48fb7c7536 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1158,7 +1158,24 @@ typedef struct st_lock_param_type void mem_alloc_error(size_t size); -bool write_table_log(ALTER_PARTITION_PARAM_TYPE *lpt); +typedef struct st_table_log_entry +{ + const char *name; + const char *from_name; + const char *handler_type; + char action_type; +} TABLE_LOG_ENTRY; + + +bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, + uint next_entry, + uint *entry_written); +bool write_execute_table_log_entry(uint first_entry, uint *exec_entry); +uint read_table_log_header(); +bool read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry); +bool init_table_log(); +void release_table_log(); + bool write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_flag); bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt); bool write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index fe37b70c3b3..9fece576f63 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -247,11 +247,12 @@ static int mysql_copy_key_list(List *orig_key, /* SYNOPSIS - write_table_log() - lpt Struct carrying parameters to the function + write_table_log_entry() + table_log_entry Information about log entry + out:entry_written Entry information written into RETURN VALUES - TRUE Failure in writing the log + TRUE Error FALSE Success DESCRIPTION @@ -260,13 +261,122 @@ static int mysql_copy_key_list(List *orig_key, */ bool -write_table_log(ALTER_PARTITION_PARAM_TYPE *lpt) +write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, + uint next_entry, + uint *entry_written) { - DBUG_ENTER("write_table_log"); + DBUG_ENTER("write_table_log_entry"); DBUG_RETURN(FALSE); } +/* + Write final entry in the table log + SYNOPSIS + write_execute_table_log_entry() + first_entry First entry in linked list of entries + to execute, if 0 = NULL it means that + the entry is removed and the entries + are put into the free list. + in:out:exec_entry Entry to execute, 0 = NULL if the entry + is written first time and needs to be + returned. In this case the entry written + is returned in this parameter + RETURN VALUES + TRUE Error + FALSE Success + + DESCRIPTION + This is the last write in the table log. The previous log entries have + already been written but not yet synched to disk. +*/ + +bool +write_execute_table_log_entry(uint first_entry, uint *exec_entry) +{ + DBUG_ENTER("write_execute_table_log_entry"); + DBUG_RETURN(FALSE); +} + + +/* + Read header of table log file + SYNOPSIS + read_table_log_header() + RETURN VALUES + > 0 Last entry in table log + 0 No entries in table log + DESCRIPTION + When we read the table log header we get information about maximum sizes + of names in the table log and we also get information about the number + of entries in the table log. +*/ + +uint +read_table_log_header() +{ + DBUG_ENTER("read_table_log_header"); + DBUG_RETURN(0); +} + + +/* + Read a table log entry + SYNOPSIS + read_table_log_entry() + read_entry Number of entry to read + out:entry_info Information from entry + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Read a specified entry in the table log +*/ + +bool +read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) +{ + DBUG_ENTER("read_table_log_entry"); + DBUG_RETURN(FALSE); +} + + +/* + Initialise table log + SYNOPSIS + init_table_log() + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Write the header of the table log file and length of names. Also set + number of entries to zero. +*/ + +bool +init_table_log() +{ + DBUG_ENTER("init_table_log"); + DBUG_RETURN(FALSE); +} + + +/* + Release all memory allocated to the table log + SYNOPSIS + release_table_log() + RETURN VALUES + NONE +*/ + +void +release_table_log() +{ + DBUG_ENTER("release_table_log"); + DBUG_RETURN_VOID; +} + + /* SYNOPSIS mysql_write_frm() From e4a92796f2d892d606f37abc468cadda5ef7c0d3 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 7 Feb 2006 10:45:07 +0100 Subject: [PATCH 11/48] WL 2826: Step 11 Lots of new code for table log include/my_sys.h: Spell error sql/mysql_priv.h: More structs and methods for table log sql/sql_partition.cc: lock/unlock global table log mutex sql/sql_table.cc: Lots of new code for table log --- include/my_sys.h | 2 +- sql/mysql_priv.h | 7 ++ sql/sql_partition.cc | 18 ++++ sql/sql_table.cc | 227 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 252 insertions(+), 2 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index 00c42fc5935..c2cdea2c54f 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -559,7 +559,7 @@ extern File my_register_filename(File fd, const char *FileName, enum file_type type_of_file, uint error_message_number, myf MyFlags); extern File my_create(const char *FileName,int CreateFlags, - int AccsesFlags, myf MyFlags); + int AccessFlags, myf MyFlags); extern int my_close(File Filedes,myf MyFlags); extern File my_dup(File file, myf MyFlags); extern int my_mkdir(const char *dir, int Flags, myf MyFlags); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index e48fb7c7536..7c7cc0b42d7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1163,7 +1163,9 @@ typedef struct st_table_log_entry const char *name; const char *from_name; const char *handler_type; + uint next_entry; char action_type; + char entry_type; } TABLE_LOG_ENTRY; @@ -1175,6 +1177,11 @@ uint read_table_log_header(); bool read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry); bool init_table_log(); void release_table_log(); +void execute_table_log_recovery(); +bool execute_table_log_entry(uint first_entry); +bool execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry); +void lock_global_table_log(); +void unlock_global_table_log(); bool write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_flag); bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index ed8b62cc300..816f2cda157 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5083,6 +5083,9 @@ bool write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) { DBUG_ENTER("write_log_shadow_frm"); + + lock_global_table_log(); + unlock_global_table_log(); DBUG_RETURN(FALSE); } @@ -5106,6 +5109,9 @@ bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { DBUG_ENTER("write_log_drop_partition"); + + lock_global_table_log(); + unlock_global_table_log(); DBUG_RETURN(FALSE); } @@ -5129,6 +5135,9 @@ bool write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { DBUG_ENTER("write_log_add_partition"); + + lock_global_table_log(); + unlock_global_table_log(); DBUG_RETURN(FALSE); } @@ -5152,6 +5161,9 @@ bool write_log_ph1_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { DBUG_ENTER("write_log_ph1_change_partition"); + + lock_global_table_log(); + unlock_global_table_log(); DBUG_RETURN(FALSE); } @@ -5176,6 +5188,9 @@ bool write_log_ph2_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { DBUG_ENTER("write_log_ph2_change_partition"); + + lock_global_table_log(); + unlock_global_table_log(); DBUG_RETURN(FALSE); } @@ -5195,6 +5210,9 @@ bool write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt) { DBUG_ENTER("write_log_ph2_change_partition"); + + lock_global_table_log(); + unlock_global_table_log(); DBUG_RETURN(FALSE); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9fece576f63..7fe130c5ec3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -244,6 +244,52 @@ static int mysql_copy_key_list(List *orig_key, DBUG_RETURN(FALSE); } +/* +-------------------------------------------------------------------------- + + MODULE: Table log + ----------------- + + This module is used to ensure that we can recover from crashes that occur + in the middle of a meta-data operation in MySQL. E.g. DROP TABLE t1, t2; + We need to ensure that both t1 and t2 are dropped and not only t1 and + also that each table drop is entirely done and not "half-baked". + + To support this we create log entries for each meta-data statement in the + table log while we are executing. These entries are dropped when the + operation is completed. + + At recovery those entries that were not completed will be executed. + + There is only one table log in the system and it is protected by a mutex + and there is a global struct that contains information about its current + state. + +-------------------------------------------------------------------------- +*/ + + +typedef struct st_table_log_memory_entry +{ + uint entry_pos; +} TABLE_LOG_MEMORY_ENTRY; + +typedef struct st_global_table_log +{ + char file_entry[IO_SIZE]; + char file_name_str[FN_REFLEN]; + char *file_name; + List free_entries; + List log_entries; + File file_id; + uint name_len; + uint handler_type_len; +} GLOBAL_TABLE_LOG; + +GLOBAL_TABLE_LOG global_table_log; + +pthread_mutex_t LOCK_gtl; + /* SYNOPSIS @@ -299,6 +345,31 @@ write_execute_table_log_entry(uint first_entry, uint *exec_entry) } +/* + Read one entry from table log file + SYNOPSIS + read_table_log_file_entry() + file_id File identifier + file_entry Memory area to read entry into + entry_no Entry number to read + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +read_table_log_file_entry(File file_id, byte *file_entry, uint entry_no) +{ + bool error= FALSE; + DBUG_ENTER("read_table_log_file_entry"); + + if (my_pread(file_id, file_entry, IO_SIZE, IO_SIZE * entry_no, MYF(0))) + error= TRUE; + DBUG_RETURN(error); +} + + /* Read header of table log file SYNOPSIS @@ -315,8 +386,20 @@ write_execute_table_log_entry(uint first_entry, uint *exec_entry) uint read_table_log_header() { + char *file_entry= (char*)&global_table_log.file_entry; DBUG_ENTER("read_table_log_header"); - DBUG_RETURN(0); + + if (read_table_log_file_entry(global_table_log.file_id, + (char*)&file_entry, 0UL)) + { + DBUG_RETURN(0); + } + entry_no= uint4korr(&file_entry[0]); + global_table_log.name_len= uint2korr(&file_entry[4]); + global_table_log.handler_type_len= uint2korr(&file_entry[6]); + global_table_log.free_entries.clear(); + VOID(pthread_mutex_init(&LOCK_gtl, MY_MUTEX_INIT_FAST)); + DBUG_RETURN(entry_no); } @@ -356,7 +439,17 @@ read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) bool init_table_log() { + uint no_entries= 0; + uint16 const_var; DBUG_ENTER("init_table_log"); + VOID(my_delete(global_table_log.file_name)); + global_table_log.file_id= my_open(global_table_log.file_name, + 0, 0, MYF(0)); + int4store(&global_table_log.file_entry[0], &no_entries); + const_var= NAMELEN; + int2store(&global_table_log.file_entry[4], &const_var); + const_var= 32; + int2store(&global_table_log.file_entry[6], &const_var); DBUG_RETURN(FALSE); } @@ -373,10 +466,142 @@ void release_table_log() { DBUG_ENTER("release_table_log"); + + VOID(pthread_mutex_destroy(&LOCK_gtl)); DBUG_RETURN_VOID; } +/* + Lock mutex for global table log + SYNOPSIS + lock_global_table_log() + RETURN VALUES + NONE +*/ + +void +lock_global_table_log() +{ + DBUG_ENTER("lock_global_table_log"); + + VOID(pthread_mutex_lock(&LOCK_gtl)); + DBUG_RETURN_VOID; +} + + +/* + Unlock mutex for global table log + SYNOPSIS + unlock_global_table_log() + RETURN VALUES + NONE +*/ + +void +unlock_global_table_log() +{ + DBUG_ENTER("unlock_global_table_log"); + + VOID(pthread_mutex_unlock(&LOCK_gtl)); + DBUG_RETURN_VOID; +} + + +/* + Execute one action in a table log entry + SYNOPSIS + execute_table_log_action() + table_log_entry Information in action entry to execute + RETURN VALUES + TRUE Error + FALSE Success +*/ + +bool +execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) +{ + DBUG_ENTER("execute_table_log_action"); + DBUG_RETURN(FALSE); +} + + +/* + Execute one entry in the table log. Executing an entry means executing + a linked list of actions. + SYNOPSIS + execute_table_log_entry() + first_entry Reference to first action in entry + RETURN VALUES + TRUE Error + FALSE Success +*/ + +bool +execute_table_log_entry(uint first_entry) +{ + TABLE_LOG_ENTRY table_log_entry; + uint read_entry= first_entry; + DBUG_ENTER("execute_table_log_entry"); + + do + { + read_table_log_entry(read_entry, &table_log_entry); + DBUG_ASSERT(table_log_entry.entry_type == 'i'); + if (execute_table_log_action(&table_log_entry)) + { + /* error handling */ + DBUG_RETURN(TRUE); + } + read_entry= table_log_entry.next_entry; + } while (read_entry); + DBUG_RETURN(FALSE); +} + + +/* + Execute the table log at recovery of MySQL Server + SYNOPSIS + execute_table_log_recovery() + RETURN VALUES + NONE +*/ + +void +execute_table_log_recovery() +{ + uint no_entries, i; + TABLE_LOG_ENTRY table_log_entry; + DBUG_ENTER("execute_table_log_recovery"); + + no_entries= read_log_header(); + for (i= 0; i < no_entries; i++) + { + read_table_log_entry(i, &table_log_entry); + if (table_log_entry.entry_type == 'e') + { + if (execute_table_log_entry(table_log_entry.next_entry)) + { + /* error handling */ + DBUG_RETURN_VOID; + } + } + } + init_table_log(); + DBUG_RETURN_VOID; +} + + +/* +--------------------------------------------------------------------------- + + END MODULE Table log + -------------------- + +--------------------------------------------------------------------------- +*/ + + /* SYNOPSIS mysql_write_frm() From e09fb5ceaa6761563675bc72d053a03e48ebf3c4 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 7 Feb 2006 16:26:34 +0100 Subject: [PATCH 12/48] WL 2826: Step 12 More table log code sql/mysql_priv.h: Added new call sql/sql_table.cc: New table log code --- sql/mysql_priv.h | 1 + sql/sql_table.cc | 121 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 113 insertions(+), 9 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 7c7cc0b42d7..a8f73ac1915 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1182,6 +1182,7 @@ bool execute_table_log_entry(uint first_entry); bool execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry); void lock_global_table_log(); void unlock_global_table_log(); +bool sync_table_log(); bool write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_flag); bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7fe130c5ec3..7a6b24c0b66 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -281,6 +281,7 @@ typedef struct st_global_table_log char *file_name; List free_entries; List log_entries; + uint no_entries; File file_id; uint name_len; uint handler_type_len; @@ -291,6 +292,52 @@ GLOBAL_TABLE_LOG global_table_log; pthread_mutex_t LOCK_gtl; +/* + Sync table log file + SYNOPSIS + sync_table_log() + RETURN VALUES + TRUE Error + FALSE Success +*/ + +bool +sync_table_log() +{ + bool error= FALSE; + DBUG_ENTER("sync_table_log"); + + if (my_sync(global_table_log.file_id, MYF(0))) + error= TRUE; + DBUG_RETURN(error); +} + + +/* + Write one entry from table log file + SYNOPSIS + write_table_log_file_entry() + file_id File identifier + file_entry Memory area to read entry into + entry_no Entry number to read + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +write_table_log_file_entry(File file_id, byte *file_entry, uint entry_no) +{ + bool error= FALSE; + DBUG_ENTER("read_table_log_file_entry"); + + if (my_pwrite(file_id, file_entry, IO_SIZE, IO_SIZE * entry_no, MYF(0))) + error= TRUE; + DBUG_RETURN(error); +} + + /* SYNOPSIS write_table_log_entry() @@ -308,10 +355,67 @@ pthread_mutex_t LOCK_gtl; bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, - uint next_entry, uint *entry_written) { + bool write_header, error; DBUG_ENTER("write_table_log_entry"); + + global_table_log.file_entry[0]= 'i'; + global_table_log.file_entry[1]= table_log_entry->action_type; + int4store(&global_table_log.file_entry[2], + table_log_entry->next_entry); + strcpy(&global_table_log.file_entry[6], table_log_entry->name); + if (table_log_entry.action_type == 'r') + global_table_log.file_entry[6 + NAMELEN]= 0; + else + strcpy(&global_table_log.file_entry[6 + NAMELEN], + table_log_entry->from_name); + strcpy(&global_table_log.file_entry[6 + (2*NAMELEN)], + table_log_entry->handler_type); + if (global_table_log.free_entries.is_empty()) + { + global_table_log.no_entries++; + entry_no= global_table_log.no_entries; + write_header= TRUE; + } + else + { + TABLE_LOG_MEMORY *tmp= global_table_log.free_entries.pop(); + global_table_log.log_entries.push_back(tmp); + entry_no= tmp->entry_pos; + write_header= FALSE; + } + error= FALSE; + if (write_table_log_entry(global_table_log.file_id, + global_table_log.file_entry, + entry_no)) + error= TRUE; + else if (write_header || !(write_table_log_header())) + error= TRUE; + DBUG_RETURN(error); +} + + +/* + Write table log header + SYNOPSIS + write_table_log_header() + RETURN VALUES + TRUE Error + FALSE Success +*/ + +bool +write_table_log_header() +{ + uint16 const_var; + DBUG_ENTER("write_table_log_header"); + + int4store(&global_table_log.file_entry[0], global_table_log.no_entries); + const_var= NAMELEN; + int2store(&global_table_log.file_entry[4], const_var); + const_var= 32; + int2store(&global_table_log.file_entry[6], const_var); DBUG_RETURN(FALSE); } @@ -398,6 +502,8 @@ read_table_log_header() global_table_log.name_len= uint2korr(&file_entry[4]); global_table_log.handler_type_len= uint2korr(&file_entry[6]); global_table_log.free_entries.clear(); + global_table_log.log_entries.clear(); + global_table_log.no_entries= 0; VOID(pthread_mutex_init(&LOCK_gtl, MY_MUTEX_INIT_FAST)); DBUG_RETURN(entry_no); } @@ -439,18 +545,15 @@ read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) bool init_table_log() { - uint no_entries= 0; - uint16 const_var; + bool error= FALSE; DBUG_ENTER("init_table_log"); + VOID(my_delete(global_table_log.file_name)); global_table_log.file_id= my_open(global_table_log.file_name, 0, 0, MYF(0)); - int4store(&global_table_log.file_entry[0], &no_entries); - const_var= NAMELEN; - int2store(&global_table_log.file_entry[4], &const_var); - const_var= 32; - int2store(&global_table_log.file_entry[6], &const_var); - DBUG_RETURN(FALSE); + if (write_table_log_header()) + error= TRUE; + DBUG_RETURN(error); } From 910bf3808a63693b6671db948a790297817968c4 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 8 Feb 2006 15:14:15 +0100 Subject: [PATCH 13/48] WL 2826: Error handling for ALTER TABLE for partitioning Most of the code for handling the table log is in place now, except the action part at recovery and proper error handling in some places. sql/mysql_priv.h: Removed internal methods from external table log interface Added and changed interface sql/mysqld.cc: Added call to execute table log recovery sql/sql_table.cc: Most of the code for handling the table log is in place now, except the action part at recovery and proper error handling in some places. --- sql/mysql_priv.h | 19 +- sql/mysqld.cc | 2 +- sql/sql_table.cc | 623 ++++++++++++++++++++++++++++++----------------- 3 files changed, 414 insertions(+), 230 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index a8f73ac1915..3be2b4508f1 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1168,21 +1168,24 @@ typedef struct st_table_log_entry char entry_type; } TABLE_LOG_ENTRY; +typedef struct st_table_log_memory_entry +{ + uint entry_pos; + TABLE_LOG_MEMORY *next_log_entry; + TABLE_LOG_MEMORY *prev_log_entry; + TABLE_LOG_MEMORY *next_active_log_entry; +} TABLE_LOG_MEMORY_ENTRY; bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, - uint next_entry, - uint *entry_written); -bool write_execute_table_log_entry(uint first_entry, uint *exec_entry); -uint read_table_log_header(); -bool read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry); -bool init_table_log(); + TABLE_LOG_MEMORY_ENTRY **active_entry); +bool write_execute_table_log_entry(uint first_entry, + TABLE_LOG_MEMORY_ENTRY **active_entry); +void release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry); void release_table_log(); void execute_table_log_recovery(); bool execute_table_log_entry(uint first_entry); -bool execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry); void lock_global_table_log(); void unlock_global_table_log(); -bool sync_table_log(); bool write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_flag); bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f5b93e6a5e5..7f7cf957477 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3676,7 +3676,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); unireg_abort(1); } } - + execute_table_log_recovery(); init_events(); create_shutdown_thread(); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7a6b24c0b66..8934f4be90f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -265,22 +265,19 @@ static int mysql_copy_key_list(List *orig_key, and there is a global struct that contains information about its current state. + History: + First version written in 2006 by Mikael Ronstrom -------------------------------------------------------------------------- */ -typedef struct st_table_log_memory_entry -{ - uint entry_pos; -} TABLE_LOG_MEMORY_ENTRY; - typedef struct st_global_table_log { char file_entry[IO_SIZE]; char file_name_str[FN_REFLEN]; char *file_name; - List free_entries; - List log_entries; + TABLE_LOG_MEMORY_ENTRY *first_free; + TABLE_LOG_MEMORY_ENTRY *first_used; uint no_entries; File file_id; uint name_len; @@ -301,6 +298,7 @@ pthread_mutex_t LOCK_gtl; FALSE Success */ +static bool sync_table_log() { @@ -308,7 +306,10 @@ sync_table_log() DBUG_ENTER("sync_table_log"); if (my_sync(global_table_log.file_id, MYF(0))) + { + /* Write to error log */ error= TRUE; + } DBUG_RETURN(error); } @@ -317,8 +318,6 @@ sync_table_log() Write one entry from table log file SYNOPSIS write_table_log_file_entry() - file_id File identifier - file_entry Memory area to read entry into entry_no Entry number to read RETURN VALUES TRUE Error @@ -327,10 +326,12 @@ sync_table_log() static bool -write_table_log_file_entry(File file_id, byte *file_entry, uint entry_no) +write_table_log_file_entry(uint entry_no) { bool error= FALSE; - DBUG_ENTER("read_table_log_file_entry"); + File file_id= global_table_log.file_id; + char *file_entry= (char*)global_table_log.file_entry; + DBUG_ENTER("write_table_log_file_entry"); if (my_pwrite(file_id, file_entry, IO_SIZE, IO_SIZE * entry_no, MYF(0))) error= TRUE; @@ -338,6 +339,264 @@ write_table_log_file_entry(File file_id, byte *file_entry, uint entry_no) } +/* + Write table log header + SYNOPSIS + write_table_log_header() + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +write_table_log_header() +{ + uint16 const_var; + bool error= FALSE; + DBUG_ENTER("write_table_log_header"); + + int4store(&global_table_log.file_entry[0], global_table_log.no_entries); + const_var= NAMELEN; + int2store(&global_table_log.file_entry[4], const_var); + const_var= 32; + int2store(&global_table_log.file_entry[6], const_var); + if (write_table_log_file_entry(0UL)) + error= TRUE; + DBUG_RETURN(error); +} + + +/* + Read one entry from table log file + SYNOPSIS + read_table_log_file_entry() + entry_no Entry number to read + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +read_table_log_file_entry(uint entry_no) +{ + bool error= FALSE; + File file_id= global_table_log.file_id; + char *file_entry= (char*)global_table_log.file_entry; + DBUG_ENTER("read_table_log_file_entry"); + + if (my_pread(file_id, file_entry, IO_SIZE, IO_SIZE * entry_no, MYF(0))) + error= TRUE; + DBUG_RETURN(error); +} + + +/* + Create table log file name + SYNOPSIS + create_table_log_file_name() + file_name Filename setup + RETURN VALUES + NONE +*/ + +static +void +create_table_log_file_name(char *file_name) +{ + strxmov(file_name, mysql_data_home, "/", "table_log.log", NullS); +} + + +/* + Read header of table log file + SYNOPSIS + read_table_log_header() + RETURN VALUES + > 0 Last entry in table log + 0 No entries in table log + DESCRIPTION + When we read the table log header we get information about maximum sizes + of names in the table log and we also get information about the number + of entries in the table log. +*/ + +static +uint +read_table_log_header() +{ + char *file_entry= (char*)global_table_log.file_entry; + char file_name[FN_REFLEN]; + DBUG_ENTER("read_table_log_header"); + + bzero(file_entry, sizeof(global_table_log.file_entry)); + create_table_log_file_name(file_name); + if (!(my_open(file_name, O_RDWR | O_TRUNC, MYF(0)))) + { + if (read_table_log_file_entry(0UL)) + { + /* Write message into error log */ + } + } + entry_no= uint4korr(&file_entry[0]); + global_table_log.name_len= uint2korr(&file_entry[4]); + global_table_log.handler_type_len= uint2korr(&file_entry[6]); + global_table_log.first_free= NULL; + global_table_log.first_used= NULL; + global_table_log.no_entries= 0; + VOID(pthread_mutex_init(&LOCK_gtl, MY_MUTEX_INIT_FAST)); + DBUG_RETURN(entry_no); +} + + +/* + Read a table log entry + SYNOPSIS + read_table_log_entry() + read_entry Number of entry to read + out:entry_info Information from entry + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Read a specified entry in the table log +*/ + +bool +read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) +{ + char *file_entry= (char*)&global_table_log.file_entry; + DBUG_ENTER("read_table_log_entry"); + + if (read_table_log_file_entry(global_table_log.file_id, + (char*)&file_entry, read_entry)) + { + /* Error handling */ + DBUG_RETURN(TRUE); + } + table_log_entry->entry_type= file_entry[0]; + table_log_entry->action_type= file_entry[1]; + table_log_entry->next_entry= uint4korr(&file_entry[2]); + table_log_entry->name= &file_entry[6]; + index= 6 + global_table_log->name_len; + table_log_entry->from_name= &file_entry[index]; + index+= global_table_log->name_len; + table_log_entry->handler_type= &file_entry[index]; + DBUG_RETURN(FALSE); +} + + +/* + Initialise table log + SYNOPSIS + init_table_log() + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Write the header of the table log file and length of names. Also set + number of entries to zero. +*/ + +static +bool +init_table_log() +{ + bool error= FALSE; + char file_name[FN_REFLEN]; + DBUG_ENTER("init_table_log"); + + create_table_log_file_name(file_name); + VOID(my_delete(file_name)); + if ((global_table_log.file_id= my_create(file_name, + CREATE_MODE, + create_flags, MYF(0))) < 0) + { + /* Couldn't create table log file, this is serious error */ + abort(); + } + if (write_table_log_header()) + { + /* Write to error log */ + error= TRUE; + } + DBUG_RETURN(error); +} + + +/* + Execute one action in a table log entry + SYNOPSIS + execute_table_log_action() + table_log_entry Information in action entry to execute + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) +{ + DBUG_ENTER("execute_table_log_action"); + DBUG_RETURN(FALSE); +} + + +/* + Get a free entry in the table log + SYNOPSIS + get_free_table_log_entry() + out:active_entry A table log memory entry returned + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +get_free_table_log_entry(TABLE_LOG_MEMORY_ENTRY **active_entry) +{ + bool write_header; + TABLE_LOG_MEMORY_ENTRY *used_entry; + TABLE_LOG_MEMORY_ENTRY *first_used= global_table_log.first_used; + if (global_table_log.first_free == NULL) + { + if (!(used_entry= my_malloc(sizeof(TABLE_LOG_MEMORY_ENTRY)))) + { + DBUG_RETURN(TRUE); + } + global_table_log.no_entries++; + used_entry->entry_no= entry_no= global_table_log.no_entries; + write_header= TRUE; + } + else + { + used_entry= global_table_log.first_free; + global_table_log.first_free= used_entry->next_log_entry; + entry_no= first_free->entry_pos; + used_entry= first_free; + write_header= FALSE; + } + /* + Move from free list to used list + */ + used_entry->next_log_entry= first_used; + used_entry->prev_log_entry= NULL; + global_table_log.first_used= used_entry; + if (first_used) + first_used->prev_log_entry= used_entry; + + *active_entry= used_entry; +} + + +/* + External interface methods for the Table log Module + --------------------------------------------------- +*/ + /* SYNOPSIS write_table_log_entry() @@ -355,9 +614,9 @@ write_table_log_file_entry(File file_id, byte *file_entry, uint entry_no) bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, - uint *entry_written) + TABLE_LOG_MEMORY_ENTRY **active_entry) { - bool write_header, error; + bool error; DBUG_ENTER("write_table_log_entry"); global_table_log.file_entry[0]= 'i'; @@ -372,54 +631,23 @@ write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, table_log_entry->from_name); strcpy(&global_table_log.file_entry[6 + (2*NAMELEN)], table_log_entry->handler_type); - if (global_table_log.free_entries.is_empty()) + if (get_free_table_log_entry(active_entry)) { - global_table_log.no_entries++; - entry_no= global_table_log.no_entries; - write_header= TRUE; - } - else - { - TABLE_LOG_MEMORY *tmp= global_table_log.free_entries.pop(); - global_table_log.log_entries.push_back(tmp); - entry_no= tmp->entry_pos; - write_header= FALSE; + DBUG_RETURN(TRUE); } error= FALSE; - if (write_table_log_entry(global_table_log.file_id, - global_table_log.file_entry, - entry_no)) + if (write_table_log_file_entry(global_table_log.file_id, + global_table_log.file_entry, + (*active_entry)->entry_pos)) error= TRUE; else if (write_header || !(write_table_log_header())) error= TRUE; + if (error) + release_table_log_memory_entry(*active_entry); DBUG_RETURN(error); } -/* - Write table log header - SYNOPSIS - write_table_log_header() - RETURN VALUES - TRUE Error - FALSE Success -*/ - -bool -write_table_log_header() -{ - uint16 const_var; - DBUG_ENTER("write_table_log_header"); - - int4store(&global_table_log.file_entry[0], global_table_log.no_entries); - const_var= NAMELEN; - int2store(&global_table_log.file_entry[4], const_var); - const_var= 32; - int2store(&global_table_log.file_entry[6], const_var); - DBUG_RETURN(FALSE); -} - - /* Write final entry in the table log SYNOPSIS @@ -442,118 +670,141 @@ write_table_log_header() */ bool -write_execute_table_log_entry(uint first_entry, uint *exec_entry) +write_execute_table_log_entry(uint first_entry, + TABLE_LOG_MEMORY_ENTRY **active_entry) { + char *file_entry= (char*)global_table_log.file_entry; DBUG_ENTER("write_execute_table_log_entry"); + + VOID(sync_table_log()); + file_entry[0]= 'e'; + file_entry[1]= 0; /* Ignored for execute entries */ + int4store(&file_entry[2], first_entry); + file_entry[6]= 0; + file_entry[6 + NAMELEN]= 0; + file_entry[6 + 2*NAMELEN]= 0; + if (get_free_table_log_entry(active_entry)) + { + DBUG_RETURN(TRUE); + } + if (write_table_log_file_entry((*active_entry)->entry_pos)) + { + release_table_log_memory_entry(*active_entry); + DBUG_RETURN(TRUE); + } + VOID(sync_table_log()); DBUG_RETURN(FALSE); } /* - Read one entry from table log file + Release a log memory entry SYNOPSIS - read_table_log_file_entry() - file_id File identifier - file_entry Memory area to read entry into - entry_no Entry number to read + release_table_log_memory_entry() + log_memory_entry Log memory entry to release RETURN VALUES - TRUE Error - FALSE Success + NONE +*/ + +void +release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry) +{ + TABLE_LOG_MEMORY_ENTRY *first_free= global_table_log.first_free; + TABLE_LOG_MEMORY_ENTRY *next_log_entry= log_entry->next_log_entry; + TABLE_LOG_MEMORY_ENTRY *prev_log_entry= log_entry->prev_log_entry; + DBUG_ENTER("release_table_log_memory_entry"); + + global_table_log.first_free= log_entry; + log_entry->next_log_entry= first_free; + + if (prev_log_entry) + prev_log_entry->next_log_entry= next_log_entry; + else + global_table_log.first_used= next_log_entry; + if (next_log_entry) + next_log_entry->prev_log_entry= prev_log_entry; + DBUG_RETURN_VOID; +} + + +/* + Execute one entry in the table log. Executing an entry means executing + a linked list of actions. + SYNOPSIS + execute_table_log_entry() + first_entry Reference to first action in entry + RETURN VALUES + TRUE Error + FALSE Success */ static bool -read_table_log_file_entry(File file_id, byte *file_entry, uint entry_no) +execute_table_log_entry(uint first_entry) { - bool error= FALSE; - DBUG_ENTER("read_table_log_file_entry"); + TABLE_LOG_ENTRY table_log_entry; + uint read_entry= first_entry; + DBUG_ENTER("execute_table_log_entry"); - if (my_pread(file_id, file_entry, IO_SIZE, IO_SIZE * entry_no, MYF(0))) - error= TRUE; - DBUG_RETURN(error); -} - - -/* - Read header of table log file - SYNOPSIS - read_table_log_header() - RETURN VALUES - > 0 Last entry in table log - 0 No entries in table log - DESCRIPTION - When we read the table log header we get information about maximum sizes - of names in the table log and we also get information about the number - of entries in the table log. -*/ - -uint -read_table_log_header() -{ - char *file_entry= (char*)&global_table_log.file_entry; - DBUG_ENTER("read_table_log_header"); - - if (read_table_log_file_entry(global_table_log.file_id, - (char*)&file_entry, 0UL)) + do { - DBUG_RETURN(0); - } - entry_no= uint4korr(&file_entry[0]); - global_table_log.name_len= uint2korr(&file_entry[4]); - global_table_log.handler_type_len= uint2korr(&file_entry[6]); - global_table_log.free_entries.clear(); - global_table_log.log_entries.clear(); - global_table_log.no_entries= 0; - VOID(pthread_mutex_init(&LOCK_gtl, MY_MUTEX_INIT_FAST)); - DBUG_RETURN(entry_no); -} - - -/* - Read a table log entry - SYNOPSIS - read_table_log_entry() - read_entry Number of entry to read - out:entry_info Information from entry - RETURN VALUES - TRUE Error - FALSE Success - DESCRIPTION - Read a specified entry in the table log -*/ - -bool -read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) -{ - DBUG_ENTER("read_table_log_entry"); + if (read_table_log_entry(read_entry, &table_log_entry)) + { + DBUG_ASSERT(0); + /* Write to error log and continue with next log entry */ + break; + } + DBUG_ASSERT(table_log_entry.entry_type == 'i'); + if (execute_table_log_action(&table_log_entry)) + { + DBUG_ASSERT(0); + /* Write to error log and continue with next log entry */ + break; + } + read_entry= table_log_entry.next_entry; + } while (read_entry); DBUG_RETURN(FALSE); } - /* - Initialise table log + Execute the table log at recovery of MySQL Server SYNOPSIS - init_table_log() + execute_table_log_recovery() RETURN VALUES - TRUE Error - FALSE Success - DESCRIPTION - Write the header of the table log file and length of names. Also set - number of entries to zero. + NONE */ -bool -init_table_log() +void +execute_table_log_recovery() { - bool error= FALSE; - DBUG_ENTER("init_table_log"); + uint no_entries, i; + TABLE_LOG_ENTRY table_log_entry; + DBUG_ENTER("execute_table_log_recovery"); - VOID(my_delete(global_table_log.file_name)); - global_table_log.file_id= my_open(global_table_log.file_name, - 0, 0, MYF(0)); - if (write_table_log_header()) - error= TRUE; - DBUG_RETURN(error); + no_entries= read_log_header(); + for (i= 0; i < no_entries; i++) + { + if (read_table_log_entry(i, &table_log_entry)) + { + DBUG_ASSERT(0); + /* Write to error log */ + break; + } + if (table_log_entry.entry_type == 'e') + { + if (execute_table_log_entry(table_log_entry.next_entry)) + { + /* + Currently errors are either crashing or ignored so we should + never end up here + */ + abort(); + DBUG_RETURN_VOID; + } + } + } + VOID(init_table_log()); + DBUG_RETURN_VOID; } @@ -568,9 +819,23 @@ init_table_log() void release_table_log() { + TABLE_LOG_MEMORY_ENTRY *free_list= global_table_log.first_free; + TABLE_LOG_MEMORY_ENTRY *used_list= global_table_log.first_used; DBUG_ENTER("release_table_log"); VOID(pthread_mutex_destroy(&LOCK_gtl)); + while (used_list) + { + TABLE_LOG_MEMORY_ENTRY tmp= used_list; + my_free(used_list, MYF(0)); + used_list= tmp->next_log_entry; + } + while (free_list) + { + TABLE_LOG_MEMORY_ENTRY tmp= free_list; + my_free(free_list, MYF(0)); + free_list= tmp->next_log_entry; + } DBUG_RETURN_VOID; } @@ -611,90 +876,6 @@ unlock_global_table_log() } -/* - Execute one action in a table log entry - SYNOPSIS - execute_table_log_action() - table_log_entry Information in action entry to execute - RETURN VALUES - TRUE Error - FALSE Success -*/ - -bool -execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) -{ - DBUG_ENTER("execute_table_log_action"); - DBUG_RETURN(FALSE); -} - - -/* - Execute one entry in the table log. Executing an entry means executing - a linked list of actions. - SYNOPSIS - execute_table_log_entry() - first_entry Reference to first action in entry - RETURN VALUES - TRUE Error - FALSE Success -*/ - -bool -execute_table_log_entry(uint first_entry) -{ - TABLE_LOG_ENTRY table_log_entry; - uint read_entry= first_entry; - DBUG_ENTER("execute_table_log_entry"); - - do - { - read_table_log_entry(read_entry, &table_log_entry); - DBUG_ASSERT(table_log_entry.entry_type == 'i'); - if (execute_table_log_action(&table_log_entry)) - { - /* error handling */ - DBUG_RETURN(TRUE); - } - read_entry= table_log_entry.next_entry; - } while (read_entry); - DBUG_RETURN(FALSE); -} - - -/* - Execute the table log at recovery of MySQL Server - SYNOPSIS - execute_table_log_recovery() - RETURN VALUES - NONE -*/ - -void -execute_table_log_recovery() -{ - uint no_entries, i; - TABLE_LOG_ENTRY table_log_entry; - DBUG_ENTER("execute_table_log_recovery"); - - no_entries= read_log_header(); - for (i= 0; i < no_entries; i++) - { - read_table_log_entry(i, &table_log_entry); - if (table_log_entry.entry_type == 'e') - { - if (execute_table_log_entry(table_log_entry.next_entry)) - { - /* error handling */ - DBUG_RETURN_VOID; - } - } - } - init_table_log(); - DBUG_RETURN_VOID; -} - - /* --------------------------------------------------------------------------- From e5200bc17d910718a5161ac590ccd49e80424ac5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 8 Feb 2006 18:04:58 -0500 Subject: [PATCH 14/48] WL 2826: Error handling for ALTER TABLE for partitioning Step 13 Lots of compilation fixes sql/mysql_priv.h: Lots of compilation fixes sql/sql_partition.cc: Lots of compilation fixes sql/sql_table.cc: Lots of compilation fixes --- sql/mysql_priv.h | 8 ++-- sql/sql_partition.cc | 56 +++++++++++------------ sql/sql_table.cc | 103 +++++++++++++++++++++++++------------------ 3 files changed, 91 insertions(+), 76 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 3be2b4508f1..9c52a4c8028 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -647,7 +647,7 @@ my_error_inject(int value) } #define ERROR_INJECT_CRASH(code) \ - DBUG_EXECUTE_COND(code, abort();) + DBUG_EXECUTE_COND(code, abort()) #define ERROR_INJECT_ACTION(code, action) \ (my_error_inject_name(code) ? ((action), 0) : 0) #define ERROR_INJECT(code) \ @@ -1171,9 +1171,9 @@ typedef struct st_table_log_entry typedef struct st_table_log_memory_entry { uint entry_pos; - TABLE_LOG_MEMORY *next_log_entry; - TABLE_LOG_MEMORY *prev_log_entry; - TABLE_LOG_MEMORY *next_active_log_entry; + struct st_table_log_memory_entry *next_log_entry; + struct st_table_log_memory_entry *prev_log_entry; + struct st_table_log_memory_entry *next_active_log_entry; } TABLE_LOG_MEMORY_ENTRY; bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 816f2cda157..deb47e76771 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5409,25 +5409,25 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, to test if recovery is properly done. */ if (write_log_shadow_frm(lpt, FALSE) || - ERROR_INJECT_CRASH(1000) || + ERROR_INJECT_CRASH("crash_drop_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || - ERROR_INJECT_CRASH(1001) || + ERROR_INJECT_CRASH("crash_drop_partition_2") || write_log_drop_partition(lpt) || - ERROR_INJECT_CRASH(1002) || + ERROR_INJECT_CRASH("crash_drop_partition_3") || abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - ERROR_INJECT_CRASH(1003) || + ERROR_INJECT_CRASH("crash_drop_partition_4") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || (close_open_tables_and_downgrade(lpt), FALSE) || - ERROR_INJECT_CRASH(1004) || + ERROR_INJECT_CRASH("crash_drop_partition_5") || table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE) || - ERROR_INJECT_CRASH(1005) || + ERROR_INJECT_CRASH("crash_drop_partition_6") || mysql_drop_partitions(lpt) || - ERROR_INJECT_CRASH(1006) || + ERROR_INJECT_CRASH("crash_drop_partition_7") || write_log_completed(lpt) || - ERROR_INJECT_CRASH(1007) || + ERROR_INJECT_CRASH("crash_drop_partition_8") || (mysql_wait_completed_table(lpt, table), FALSE)) { fast_alter_partition_error_handler(lpt); @@ -5465,25 +5465,25 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 9) Complete query */ if (write_log_shadow_frm(lpt, FALSE) || - ERROR_INJECT_CRASH(1010) || + ERROR_INJECT_CRASH("crash_add_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || - ERROR_INJECT_CRASH(1011) || + ERROR_INJECT_CRASH("crash_add_partition_2") || write_log_add_partition(lpt) || - ERROR_INJECT_CRASH(1012) || + ERROR_INJECT_CRASH("crash_add_partition_3") || mysql_change_partitions(lpt) || - ERROR_INJECT_CRASH(1013) || + ERROR_INJECT_CRASH("crash_add_partition_4") || abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - ERROR_INJECT_CRASH(1014) || + ERROR_INJECT_CRASH("crash_add_partition_5") || write_log_shadow_frm(lpt, TRUE) || - ERROR_INJECT_CRASH(1015) || + ERROR_INJECT_CRASH("crash_add_partition_6") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || - ERROR_INJECT_CRASH(1016) || + ERROR_INJECT_CRASH("crash_add_partition_7") || (close_open_tables_and_downgrade(lpt), FALSE) || write_log_completed(lpt) || - ERROR_INJECT_CRASH(1017)) + ERROR_INJECT_CRASH("crash_add_partition_8")) { fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); @@ -5546,32 +5546,32 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, */ if (write_log_shadow_frm(lpt, FALSE) || - ERROR_INJECT_CRASH(1020) || + ERROR_INJECT_CRASH("crash_change_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || - ERROR_INJECT_CRASH(1021) || + ERROR_INJECT_CRASH("crash_change_partition_2") || write_log_ph1_change_partition(lpt) || - ERROR_INJECT_CRASH(1022) || + ERROR_INJECT_CRASH("crash_change_partition_3") || mysql_change_partitions(lpt) || - ERROR_INJECT_CRASH(1023) || + ERROR_INJECT_CRASH("crash_change_partition_4") || write_log_ph2_change_partition(lpt) || - ERROR_INJECT_CRASH(1024) || + ERROR_INJECT_CRASH("crash_change_partition_5") || abort_and_upgrade_lock(lpt) || table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE) || - ERROR_INJECT_CRASH(1025) || + ERROR_INJECT_CRASH("crash_change_partition_6") || mysql_rename_partitions(lpt) || - ERROR_INJECT_CRASH(1026) || + ERROR_INJECT_CRASH("crash_change_partition_7") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - ERROR_INJECT_CRASH(1027) || + ERROR_INJECT_CRASH("crash_change_partition_8") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || - ERROR_INJECT_CRASH(1028) || + ERROR_INJECT_CRASH("crash_change_partition_9") || (close_open_tables_and_downgrade(lpt), FALSE) || - ERROR_INJECT_CRASH(1029) || + ERROR_INJECT_CRASH("crash_change_partition_10") || mysql_drop_partitions(lpt) || - ERROR_INJECT_CRASH(1030) || + ERROR_INJECT_CRASH("crash_change_partition_11") || write_log_completed(lpt) || - ERROR_INJECT_CRASH(1031) || + ERROR_INJECT_CRASH("crash_change_partition_12") || (mysql_wait_completed_table(lpt, table), FALSE)) { fast_alter_partition_error_handler(lpt); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8934f4be90f..f45ce41741a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -357,7 +357,7 @@ write_table_log_header() DBUG_ENTER("write_table_log_header"); int4store(&global_table_log.file_entry[0], global_table_log.no_entries); - const_var= NAMELEN; + const_var= FN_LEN; int2store(&global_table_log.file_entry[4], const_var); const_var= 32; int2store(&global_table_log.file_entry[6], const_var); @@ -428,11 +428,12 @@ read_table_log_header() { char *file_entry= (char*)global_table_log.file_entry; char file_name[FN_REFLEN]; + uint entry_no; DBUG_ENTER("read_table_log_header"); bzero(file_entry, sizeof(global_table_log.file_entry)); create_table_log_file_name(file_name); - if (!(my_open(file_name, O_RDWR | O_TRUNC, MYF(0)))) + if (!(my_open(file_name, O_RDWR | O_TRUNC | O_BINARY, MYF(0)))) { if (read_table_log_file_entry(0UL)) { @@ -467,10 +468,10 @@ bool read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) { char *file_entry= (char*)&global_table_log.file_entry; + uint inx; DBUG_ENTER("read_table_log_entry"); - if (read_table_log_file_entry(global_table_log.file_id, - (char*)&file_entry, read_entry)) + if (read_table_log_file_entry(read_entry)) { /* Error handling */ DBUG_RETURN(TRUE); @@ -479,10 +480,10 @@ read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) table_log_entry->action_type= file_entry[1]; table_log_entry->next_entry= uint4korr(&file_entry[2]); table_log_entry->name= &file_entry[6]; - index= 6 + global_table_log->name_len; - table_log_entry->from_name= &file_entry[index]; - index+= global_table_log->name_len; - table_log_entry->handler_type= &file_entry[index]; + inx= 6 + global_table_log.name_len; + table_log_entry->from_name= &file_entry[inx]; + inx+= global_table_log.name_len; + table_log_entry->handler_type= &file_entry[inx]; DBUG_RETURN(FALSE); } @@ -508,10 +509,11 @@ init_table_log() DBUG_ENTER("init_table_log"); create_table_log_file_name(file_name); - VOID(my_delete(file_name)); + VOID(my_delete(file_name, MYF(0))); if ((global_table_log.file_id= my_create(file_name, CREATE_MODE, - create_flags, MYF(0))) < 0) + O_RDWR | O_TRUNC | O_BINARY, + MYF(0))) < 0) { /* Couldn't create table log file, this is serious error */ abort(); @@ -556,28 +558,31 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) static bool -get_free_table_log_entry(TABLE_LOG_MEMORY_ENTRY **active_entry) +get_free_table_log_entry(TABLE_LOG_MEMORY_ENTRY **active_entry, + bool *write_header) { - bool write_header; + uint entry_no; TABLE_LOG_MEMORY_ENTRY *used_entry; TABLE_LOG_MEMORY_ENTRY *first_used= global_table_log.first_used; + DBUG_ENTER("get_free_table_log_entry"); + if (global_table_log.first_free == NULL) { - if (!(used_entry= my_malloc(sizeof(TABLE_LOG_MEMORY_ENTRY)))) + if (!(used_entry= (TABLE_LOG_MEMORY_ENTRY*)my_malloc( + sizeof(TABLE_LOG_MEMORY_ENTRY), MYF(0)))) { DBUG_RETURN(TRUE); } global_table_log.no_entries++; - used_entry->entry_no= entry_no= global_table_log.no_entries; - write_header= TRUE; + used_entry->entry_pos= entry_no= global_table_log.no_entries; + *write_header= TRUE; } else { used_entry= global_table_log.first_free; global_table_log.first_free= used_entry->next_log_entry; - entry_no= first_free->entry_pos; - used_entry= first_free; - write_header= FALSE; + entry_no= used_entry->entry_pos; + *write_header= FALSE; } /* Move from free list to used list @@ -589,6 +594,7 @@ get_free_table_log_entry(TABLE_LOG_MEMORY_ENTRY **active_entry) first_used->prev_log_entry= used_entry; *active_entry= used_entry; + DBUG_RETURN(FALSE); } @@ -616,7 +622,7 @@ bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, TABLE_LOG_MEMORY_ENTRY **active_entry) { - bool error; + bool error, write_header; DBUG_ENTER("write_table_log_entry"); global_table_log.file_entry[0]= 'i'; @@ -624,24 +630,25 @@ write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, int4store(&global_table_log.file_entry[2], table_log_entry->next_entry); strcpy(&global_table_log.file_entry[6], table_log_entry->name); - if (table_log_entry.action_type == 'r') - global_table_log.file_entry[6 + NAMELEN]= 0; + if (table_log_entry->action_type == 'r') + global_table_log.file_entry[6 + FN_LEN]= 0; else - strcpy(&global_table_log.file_entry[6 + NAMELEN], + strcpy(&global_table_log.file_entry[6 + FN_LEN], table_log_entry->from_name); - strcpy(&global_table_log.file_entry[6 + (2*NAMELEN)], + strcpy(&global_table_log.file_entry[6 + (2*FN_LEN)], table_log_entry->handler_type); - if (get_free_table_log_entry(active_entry)) + if (get_free_table_log_entry(active_entry, &write_header)) { DBUG_RETURN(TRUE); } error= FALSE; - if (write_table_log_file_entry(global_table_log.file_id, - global_table_log.file_entry, - (*active_entry)->entry_pos)) - error= TRUE; - else if (write_header || !(write_table_log_header())) + if (write_table_log_file_entry((*active_entry)->entry_pos)) error= TRUE; + if (write_header && !error) + { + if (sync_table_log() || write_table_log_header()) + error= TRUE; + } if (error) release_table_log_memory_entry(*active_entry); DBUG_RETURN(error); @@ -673,6 +680,7 @@ bool write_execute_table_log_entry(uint first_entry, TABLE_LOG_MEMORY_ENTRY **active_entry) { + bool write_header; char *file_entry= (char*)global_table_log.file_entry; DBUG_ENTER("write_execute_table_log_entry"); @@ -681,9 +689,9 @@ write_execute_table_log_entry(uint first_entry, file_entry[1]= 0; /* Ignored for execute entries */ int4store(&file_entry[2], first_entry); file_entry[6]= 0; - file_entry[6 + NAMELEN]= 0; - file_entry[6 + 2*NAMELEN]= 0; - if (get_free_table_log_entry(active_entry)) + file_entry[6 + FN_LEN]= 0; + file_entry[6 + 2*FN_LEN]= 0; + if (get_free_table_log_entry(active_entry, &write_header)) { DBUG_RETURN(TRUE); } @@ -693,6 +701,14 @@ write_execute_table_log_entry(uint first_entry, DBUG_RETURN(TRUE); } VOID(sync_table_log()); + if (write_header) + { + if (write_table_log_header()) + { + release_table_log_memory_entry(*active_entry); + DBUG_RETURN(TRUE); + } + } DBUG_RETURN(FALSE); } @@ -723,7 +739,7 @@ release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry) global_table_log.first_used= next_log_entry; if (next_log_entry) next_log_entry->prev_log_entry= prev_log_entry; - DBUG_RETURN_VOID; + DBUG_VOID_RETURN; } @@ -738,7 +754,6 @@ release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry) FALSE Success */ -static bool execute_table_log_entry(uint first_entry) { @@ -781,7 +796,7 @@ execute_table_log_recovery() TABLE_LOG_ENTRY table_log_entry; DBUG_ENTER("execute_table_log_recovery"); - no_entries= read_log_header(); + no_entries= read_table_log_header(); for (i= 0; i < no_entries; i++) { if (read_table_log_entry(i, &table_log_entry)) @@ -799,12 +814,12 @@ execute_table_log_recovery() never end up here */ abort(); - DBUG_RETURN_VOID; + DBUG_VOID_RETURN; } } } VOID(init_table_log()); - DBUG_RETURN_VOID; + DBUG_VOID_RETURN; } @@ -826,17 +841,17 @@ release_table_log() VOID(pthread_mutex_destroy(&LOCK_gtl)); while (used_list) { - TABLE_LOG_MEMORY_ENTRY tmp= used_list; - my_free(used_list, MYF(0)); + TABLE_LOG_MEMORY_ENTRY *tmp= used_list; + my_free((char*)used_list, MYF(0)); used_list= tmp->next_log_entry; } while (free_list) { - TABLE_LOG_MEMORY_ENTRY tmp= free_list; - my_free(free_list, MYF(0)); + TABLE_LOG_MEMORY_ENTRY *tmp= free_list; + my_free((char*)free_list, MYF(0)); free_list= tmp->next_log_entry; } - DBUG_RETURN_VOID; + DBUG_VOID_RETURN; } @@ -854,7 +869,7 @@ lock_global_table_log() DBUG_ENTER("lock_global_table_log"); VOID(pthread_mutex_lock(&LOCK_gtl)); - DBUG_RETURN_VOID; + DBUG_VOID_RETURN; } @@ -872,7 +887,7 @@ unlock_global_table_log() DBUG_ENTER("unlock_global_table_log"); VOID(pthread_mutex_unlock(&LOCK_gtl)); - DBUG_RETURN_VOID; + DBUG_VOID_RETURN; } From 256d85273205f1387e9b9faa4ded94080609ce64 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 8 Feb 2006 20:26:56 -0500 Subject: [PATCH 15/48] WL 2826: Error handling of ALTER TABLE for partitioning Close down table log also at exit of main thread sql/mysqld.cc: Close down table log also at exit of main thread sql/sql_table.cc: Close down table log also at exit of main thread --- sql/mysqld.cc | 1 + sql/sql_table.cc | 1 + 2 files changed, 2 insertions(+) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7f7cf957477..80cb4333725 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3708,6 +3708,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); /* (void) pthread_attr_destroy(&connection_attrib); */ DBUG_PRINT("quit",("Exiting main thread")); + release_table_log(); #ifndef __WIN__ #ifdef EXTRA_DEBUG2 diff --git a/sql/sql_table.cc b/sql/sql_table.cc index f45ce41741a..5477a8a33fa 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -851,6 +851,7 @@ release_table_log() my_free((char*)free_list, MYF(0)); free_list= tmp->next_log_entry; } + VOID(my_close(global_table_log.file_id, MYF(0))); DBUG_VOID_RETURN; } From 836912d1c7a8c1118786e791ebe8e514461dfa8b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2006 11:05:05 +0100 Subject: [PATCH 16/48] WL 2826: Error handling for ALTER TABLE for partitioning Step 14: First version of table log for add/Drop partition sql/ha_partition.cc: Moved create partition name code to sql_partition.cc sql/handler.h: Added entries in partition_info to keep track of table log entries sql/mysql_priv.h: Moved create partition name code to sql_partition.cc sql/sql_partition.cc: Moved create partition name code to sql_partition.cc First version of table log for add/drop partition sql/sql_table.cc: Add IO_SIZE to table log header --- sql/ha_partition.cc | 82 ------------ sql/handler.h | 6 +- sql/mysql_priv.h | 10 ++ sql/sql_partition.cc | 298 ++++++++++++++++++++++++++++++++++++++++++- sql/sql_table.cc | 11 +- 5 files changed, 321 insertions(+), 86 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 193fe863f8c..80047d438e1 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -391,88 +391,6 @@ int ha_partition::ha_initialise() /**************************************************************************** MODULE meta data changes ****************************************************************************/ -/* - Create partition names - - SYNOPSIS - create_partition_name() - out:out Created partition name string - in1 First part - in2 Second part - name_variant Normal, temporary or renamed partition name - - RETURN VALUE - NONE - - DESCRIPTION - This method is used to calculate the partition name, service routine to - the del_ren_cre_table method. -*/ - -#define NORMAL_PART_NAME 0 -#define TEMP_PART_NAME 1 -#define RENAMED_PART_NAME 2 -static void create_partition_name(char *out, const char *in1, - const char *in2, uint name_variant, - bool translate) -{ - char transl_part_name[FN_REFLEN]; - const char *transl_part; - - if (translate) - { - tablename_to_filename(in2, transl_part_name, FN_REFLEN); - transl_part= transl_part_name; - } - else - transl_part= in2; - if (name_variant == NORMAL_PART_NAME) - strxmov(out, in1, "#P#", transl_part, NullS); - else if (name_variant == TEMP_PART_NAME) - strxmov(out, in1, "#P#", transl_part, "#TMP#", NullS); - else if (name_variant == RENAMED_PART_NAME) - strxmov(out, in1, "#P#", transl_part, "#REN#", NullS); -} - -/* - Create subpartition name - - SYNOPSIS - create_subpartition_name() - out:out Created partition name string - in1 First part - in2 Second part - in3 Third part - name_variant Normal, temporary or renamed partition name - - RETURN VALUE - NONE - - DESCRIPTION - This method is used to calculate the subpartition name, service routine to - the del_ren_cre_table method. -*/ - -static void create_subpartition_name(char *out, const char *in1, - const char *in2, const char *in3, - uint name_variant) -{ - char transl_part_name[FN_REFLEN], transl_subpart_name[FN_REFLEN]; - - tablename_to_filename(in2, transl_part_name, FN_REFLEN); - tablename_to_filename(in3, transl_subpart_name, FN_REFLEN); - if (name_variant == NORMAL_PART_NAME) - strxmov(out, in1, "#P#", transl_part_name, - "#SP#", transl_subpart_name, NullS); - else if (name_variant == TEMP_PART_NAME) - strxmov(out, in1, "#P#", transl_part_name, - "#SP#", transl_subpart_name, "#TMP#", NullS); - else if (name_variant == RENAMED_PART_NAME) - strxmov(out, in1, "#P#", transl_part_name, - "#SP#", transl_subpart_name, "#REN#", NullS); -} - - /* Delete a table diff --git a/sql/handler.h b/sql/handler.h index b6a925695b8..205f137e28a 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -799,6 +799,8 @@ typedef int (*get_partitions_in_range_iter)(partition_info *part_info, PARTITION_ITERATOR *part_iter); +struct TABLE_LOG_MEMORY_ENTRY; + class partition_info : public Sql_alloc { public: @@ -845,7 +847,9 @@ public: Item *subpart_expr; Item *item_free_list; - + + TABLE_LOG_MEMORY_ENTRY *first_log_entry; + TABLE_LOG_MEMORY_ENTRY *exec_log_entry; /* A bitmap of partitions used by the current query. Usage pattern: diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 9c52a4c8028..fe6babaea66 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1135,6 +1135,16 @@ uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info, bool remove_table_from_cache(THD *thd, const char *db, const char *table, uint flags); +#define NORMAL_PART_NAME 0 +#define TEMP_PART_NAME 1 +#define RENAMED_PART_NAME 2 +void create_partition_name(char *out, const char *in1, + const char *in2, uint name_variant, + bool translate); +void create_subpartition_name(char *out, const char *in1, + const char *in2, const char *in3, + uint name_variant); + typedef struct st_lock_param_type { ulonglong copied; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index deb47e76771..8c5c1016097 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5063,6 +5063,50 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) } +/* + Insert log entry into list + SYNOPSIS + insert_part_info_log_entry_list() + log_entry + RETURN VALUES + NONE +*/ + +static +void +insert_part_info_log_entry_list(partition_info *part_info, + TABLE_LOG_MEMORY_ENTRY *log_entry) +{ + log_entry->next_active_log_entry= part_info->first_log_entry; + part_info->first_log_entry= log_entry; +} + + +/* + Release all log entries for this partition info struct + SYNOPSIS + release_part_info_log_entries() + first_log_entry First log entry in list to release + RETURN VALUES + NONE +*/ + +static +void +release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) +{ + DBUG_ENTER("release_part_info_log_entries"); + + while (log_entry) + { + release_table_log_memory_entry(log_entry); + log_entry= log_entry->next_log_entry; + } + part_info->first_log_entry= NULL; + DBUG_VOID_RETURN; +} + + /* Write the log entry to ensure that the shadow frm file is removed at crash. @@ -5082,11 +5126,111 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) bool write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) { + TABLE_LOG_ENTRY table_log_entry; + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry; + char shadow_path[FN_LEN]; DBUG_ENTER("write_log_shadow_frm"); lock_global_table_log(); + do + { + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); + table_log_entry.action_type= 'd'; + table_log_entry.next_entry= 0; + table_log_entry.handler_type= "frm"; + table_log_entry.name= shadow_path; + + if (write_table_log_entry(&table_log_entry, &log_entry)) + break; + insert_part_info_log_entry_list(part_info, log_entry); + if (write_execute_table_log_entry(log_entry->entry_pos, &log_entry)) + break; + part_info->exec_log_entry= log_entry; + unlock_global_table_log(); + DBUG_RETURN(FALSE); + } while (TRUE); + release_part_info_log_entries(part_info->first_log_entry); unlock_global_table_log(); + DBUG_RETURN(TRUE); +} + + +/* + Log dropped partitions + SYNOPSIS + write_log_dropped_partitions() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, + uint *next_entry, + const char *path) +{ + TABLE_LOG_ENTRY table_log_entry; + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry; + char tmp_path[FN_LEN]; + List_iterator part_it(part_info->partitions); + uint no_elements= part_info->partitions.elements; + DBUG_ENTER("write_log_dropped_partitions"); + + table_log_entry.action_type= 'd'; + do + { + partition_element part_elem= part_it++; + if (part_elem->part_state == PART_TO_BE_DROPPED || + part_elem->part_state == PART_TO_BE_ADDED) + { + if (is_sub_partitioned(part_info)) + { + List_iterator sub_it(part_elem->subpartitions); + uint no_subparts= part_info->no_subparts; + do + { + partition_element *sub_elem= sub_it++; + table_log_entry.next_entry= *next_entry; + table_log_entry.handler_type= + ha_resolve_storage_engine_name(sub_elem->engine_type); + create_subpartition_name(tmp_path, path, + part_elem->partition_name, + sub_elem->partition_name, + NORMAL_PART_NAME); + table_log_entry.name= tmp_path; + if (write_table_log_entry(&table_log_entry, &log_entry)) + { + DBUG_RETURN(TRUE); + } + *next_entry= log_entry->entry_pos; + insert_part_info_log_entry_list(part_info, log_entry); + } while (++i < no_subparts); + } + else + { + table_log_entry.next_entry= *next_entry; + table_log_entry.handler_type= + ha_resolve_storage_engine_name(part_elem->engine_type); + create_partition_name(tmp_path, path, + part_elem->partition_name, + NORMAL_PART_NAME, TRUE); + table_log_entry.name= tmp_path; + if (write_table_log_entry(&table_log_entry, &log_entry)) + { + DBUG_RETURN(TRUE); + } + *next_entry= log_entry->entry_pos; + insert_part_info_log_entry_list(part_info, log_entry); + } + } + } while (++i < no_elements); DBUG_RETURN(FALSE); +error: } @@ -5108,11 +5252,47 @@ write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { + TABLE_LOG_ENTRY table_log_entry; + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry; + char tmp_path[FN_LEN]; + char path[FN_LEN]; + uint next_entry= 0; + TABLE_LOG_MEMORY_ENTRY *old_log_entry= part_info->first_log_entry; DBUG_ENTER("write_log_drop_partition"); + part_info->first_log_entry= NULL; + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); lock_global_table_log(); + do + { + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path)) + break; + /* + At first we write an entry that installs the new frm file + */ + build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, + lpt->table_name, "#"); + table_log_entry.action_type= 'r'; + table_log_entry.next_entry= next_entry; + table_log_entry.handler_type= "frm"; + table_log_entry.name= path; + table_log_entry.from_name= tmp_path; + if (write_table_log_entry(&table_log_entry, &log_entry)) + break; + insert_part_info_log_entry_list(part_info, log_entry); + log_entry= part_info->exec_log_entry; + if (write_execute_table_log_entry(log_entry->entry_pos, NULL)) + break; + release_part_info_log_entries(old_first_log_entry); + unlock_global_table_log(); + DBUG_RETURN(FALSE); + } while (TRUE); + release_part_info_log_entries(part_info->first_log_entry); + part_info->first_log_entry= old_log_entry; unlock_global_table_log(); - DBUG_RETURN(FALSE); + DBUG_RETURN(TRUE); } @@ -5129,16 +5309,48 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) DESCRIPTION Prepare entries to the table log indicating all partitions to drop and to remove the shadow frm file. + The removal of the shadow frm file is already in the log file so we only + need to link the new entries to the existing and carefully ensure that + the new linked list has first the dropped partitions and then the + drop of the shadow frm file. + We always inject entries backwards in the list in the table log since we + don't know the entry position until we have written it. */ bool write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { DBUG_ENTER("write_log_add_partition"); + TABLE_LOG_ENTRY table_log_entry; + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry; + char tmp_path[FN_LEN]; + char path[FN_LEN]; + TABLE_LOG_MEMORY_ENTRY *old_log_entry= part_info->first_log_entry; + uint next_entry= old_log_entry->entry_pos; + /* Ensure we linked the existing entries at the back */ + DBUG_ENTER("write_log_add_partition"); + part_info->first_log_entry= NULL; + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); lock_global_table_log(); + do + { + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path)) + break; + log_entry= part_info->first_log_entry; + /* Ensure first entry is the last dropped partition */ + if (write_execute_table_log_entry(log_entry->entry_pos, NULL)) + break; + release_part_info_log_entries(old_first_log_entry); + unlock_global_table_log(); + DBUG_RETURN(FALSE); + } while (TRUE); + release_part_info_log_entries(part_info->first_log_entry); + part_info->first_log_entry= old_log_entry; unlock_global_table_log(); - DBUG_RETURN(FALSE); + DBUG_RETURN(TRUE); } @@ -6182,5 +6394,87 @@ static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR *part_iter) part_iter->field_vals.start++; return part_iter->part_info->get_subpartition_id(part_iter->part_info); } + + +/* + Create partition names + + SYNOPSIS + create_partition_name() + out:out Created partition name string + in1 First part + in2 Second part + name_variant Normal, temporary or renamed partition name + + RETURN VALUE + NONE + + DESCRIPTION + This method is used to calculate the partition name, service routine to + the del_ren_cre_table method. +*/ + +void +create_partition_name(char *out, const char *in1, + const char *in2, uint name_variant, + bool translate) +{ + char transl_part_name[FN_REFLEN]; + const char *transl_part; + + if (translate) + { + tablename_to_filename(in2, transl_part_name, FN_REFLEN); + transl_part= transl_part_name; + } + else + transl_part= in2; + if (name_variant == NORMAL_PART_NAME) + strxmov(out, in1, "#P#", transl_part, NullS); + else if (name_variant == TEMP_PART_NAME) + strxmov(out, in1, "#P#", transl_part, "#TMP#", NullS); + else if (name_variant == RENAMED_PART_NAME) + strxmov(out, in1, "#P#", transl_part, "#REN#", NullS); +} + + +/* + Create subpartition name + + SYNOPSIS + create_subpartition_name() + out:out Created partition name string + in1 First part + in2 Second part + in3 Third part + name_variant Normal, temporary or renamed partition name + + RETURN VALUE + NONE + + DESCRIPTION + This method is used to calculate the subpartition name, service routine to + the del_ren_cre_table method. +*/ + +void +create_subpartition_name(char *out, const char *in1, + const char *in2, const char *in3, + uint name_variant) +{ + char transl_part_name[FN_REFLEN], transl_subpart_name[FN_REFLEN]; + + tablename_to_filename(in2, transl_part_name, FN_REFLEN); + tablename_to_filename(in3, transl_subpart_name, FN_REFLEN); + if (name_variant == NORMAL_PART_NAME) + strxmov(out, in1, "#P#", transl_part_name, + "#SP#", transl_subpart_name, NullS); + else if (name_variant == TEMP_PART_NAME) + strxmov(out, in1, "#P#", transl_part_name, + "#SP#", transl_subpart_name, "#TMP#", NullS); + else if (name_variant == RENAMED_PART_NAME) + strxmov(out, in1, "#P#", transl_part_name, + "#SP#", transl_subpart_name, "#REN#", NullS); +} #endif diff --git a/sql/sql_table.cc b/sql/sql_table.cc index f45ce41741a..c6c76a833ab 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -282,6 +282,7 @@ typedef struct st_global_table_log File file_id; uint name_len; uint handler_type_len; + uint io_size; } GLOBAL_TABLE_LOG; GLOBAL_TABLE_LOG global_table_log; @@ -361,6 +362,8 @@ write_table_log_header() int2store(&global_table_log.file_entry[4], const_var); const_var= 32; int2store(&global_table_log.file_entry[6], const_var); + const_var= IO_SIZE; + int4store(&global_table_log.file_entry[8], const_var); if (write_table_log_file_entry(0UL)) error= TRUE; DBUG_RETURN(error); @@ -384,9 +387,10 @@ read_table_log_file_entry(uint entry_no) bool error= FALSE; File file_id= global_table_log.file_id; char *file_entry= (char*)global_table_log.file_entry; + uint io_size= global_table_log.io_size; DBUG_ENTER("read_table_log_file_entry"); - if (my_pread(file_id, file_entry, IO_SIZE, IO_SIZE * entry_no, MYF(0))) + if (my_pread(file_id, file_entry, io_size, io_size * entry_no, MYF(0))) error= TRUE; DBUG_RETURN(error); } @@ -429,6 +433,7 @@ read_table_log_header() char *file_entry= (char*)global_table_log.file_entry; char file_name[FN_REFLEN]; uint entry_no; + bool successful_open= FALSE; DBUG_ENTER("read_table_log_header"); bzero(file_entry, sizeof(global_table_log.file_entry)); @@ -439,10 +444,14 @@ read_table_log_header() { /* Write message into error log */ } + else + successful_open= TRUE; } entry_no= uint4korr(&file_entry[0]); global_table_log.name_len= uint2korr(&file_entry[4]); global_table_log.handler_type_len= uint2korr(&file_entry[6]); + if (successful_open) + global_table_log.io_size= uint4korr(&file_entry[8]); global_table_log.first_free= NULL; global_table_log.first_used= NULL; global_table_log.no_entries= 0; From cd653ed9ec12bcd125a0852fb0c0a58f95b4c354 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2006 14:13:22 -0500 Subject: [PATCH 17/48] WL 2826: Error handling of ALTER TABLE for partitioning A number of fixes sql/handler.h: A numbre of fixes sql/mysql_priv.h: A numbre of fixes sql/share/errmsg.txt: A numbre of fixes sql/sql_partition.cc: A numbre of fixes sql/sql_table.cc: A numbre of fixes --- sql/handler.h | 7 ++++--- sql/mysql_priv.h | 1 + sql/share/errmsg.txt | 2 ++ sql/sql_partition.cc | 33 +++++++++++++++++++-------------- sql/sql_table.cc | 14 +++++++++----- 5 files changed, 35 insertions(+), 22 deletions(-) diff --git a/sql/handler.h b/sql/handler.h index 205f137e28a..00bfaa77e91 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -799,7 +799,7 @@ typedef int (*get_partitions_in_range_iter)(partition_info *part_info, PARTITION_ITERATOR *part_iter); -struct TABLE_LOG_MEMORY_ENTRY; +struct st_table_log_memory_entry; class partition_info : public Sql_alloc { @@ -848,8 +848,8 @@ public: Item *item_free_list; - TABLE_LOG_MEMORY_ENTRY *first_log_entry; - TABLE_LOG_MEMORY_ENTRY *exec_log_entry; + st_table_log_memory_entry *first_log_entry; + st_table_log_memory_entry *exec_log_entry; /* A bitmap of partitions used by the current query. Usage pattern: @@ -961,6 +961,7 @@ public: part_field_array(NULL), subpart_field_array(NULL), full_part_field_array(NULL), part_expr(NULL), subpart_expr(NULL), item_free_list(NULL), + first_log_entry(NULL), exec_log_entry(NULL), list_array(NULL), part_info_string(NULL), part_func_string(NULL), subpart_func_string(NULL), diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index fe6babaea66..d22f894e43d 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1164,6 +1164,7 @@ typedef struct st_lock_param_type uint key_count; uint db_options; uint pack_frm_len; + partition_info *part_info; } ALTER_PARTITION_PARAM_TYPE; void mem_alloc_error(size_t size); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 80910a8fd81..017b7f5db05 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5798,3 +5798,5 @@ ER_CANT_WRITE_LOCK_LOG_TABLE eng "You can't write-lock a log table. Only read access is possible." ER_CANT_READ_LOCK_LOG_TABLE eng "You can't use usual read lock with log tables. Try READ LOCAL instead." +ER_TABLE_LOG_ERROR + eng "Error in table log" diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 8c5c1016097..71d6d7b200c 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5102,7 +5102,6 @@ release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) release_table_log_memory_entry(log_entry); log_entry= log_entry->next_log_entry; } - part_info->first_log_entry= NULL; DBUG_VOID_RETURN; } @@ -5129,6 +5128,7 @@ write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) TABLE_LOG_ENTRY table_log_entry; partition_info *part_info= lpt->part_info; TABLE_LOG_MEMORY_ENTRY *log_entry; + TABLE_LOG_MEMORY_ENTRY *exec_log_entry= NULL; char shadow_path[FN_LEN]; DBUG_ENTER("write_log_shadow_frm"); @@ -5145,14 +5145,16 @@ write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) if (write_table_log_entry(&table_log_entry, &log_entry)) break; insert_part_info_log_entry_list(part_info, log_entry); - if (write_execute_table_log_entry(log_entry->entry_pos, &log_entry)) + if (write_execute_table_log_entry(log_entry->entry_pos, &exec_log_entry)) break; - part_info->exec_log_entry= log_entry; + part_info->exec_log_entry= exec_log_entry; unlock_global_table_log(); DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); + part_info->first_log_entry= NULL; unlock_global_table_log(); + my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5179,12 +5181,13 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, char tmp_path[FN_LEN]; List_iterator part_it(part_info->partitions); uint no_elements= part_info->partitions.elements; + uint i; DBUG_ENTER("write_log_dropped_partitions"); table_log_entry.action_type= 'd'; do { - partition_element part_elem= part_it++; + partition_element *part_elem= part_it++; if (part_elem->part_state == PART_TO_BE_DROPPED || part_elem->part_state == PART_TO_BE_ADDED) { @@ -5230,7 +5233,6 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, } } while (++i < no_elements); DBUG_RETURN(FALSE); -error: } @@ -5255,10 +5257,11 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) TABLE_LOG_ENTRY table_log_entry; partition_info *part_info= lpt->part_info; TABLE_LOG_MEMORY_ENTRY *log_entry; + TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; char tmp_path[FN_LEN]; char path[FN_LEN]; uint next_entry= 0; - TABLE_LOG_MEMORY_ENTRY *old_log_entry= part_info->first_log_entry; + TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; DBUG_ENTER("write_log_drop_partition"); part_info->first_log_entry= NULL; @@ -5282,16 +5285,16 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_table_log_entry(&table_log_entry, &log_entry)) break; insert_part_info_log_entry_list(part_info, log_entry); - log_entry= part_info->exec_log_entry; - if (write_execute_table_log_entry(log_entry->entry_pos, NULL)) + if (write_execute_table_log_entry(log_entry->entry_pos, &exec_log_entry)) break; release_part_info_log_entries(old_first_log_entry); unlock_global_table_log(); DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= old_log_entry; + part_info->first_log_entry= old_first_log_entry; unlock_global_table_log(); + my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5320,14 +5323,14 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) bool write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { - DBUG_ENTER("write_log_add_partition"); TABLE_LOG_ENTRY table_log_entry; partition_info *part_info= lpt->part_info; TABLE_LOG_MEMORY_ENTRY *log_entry; char tmp_path[FN_LEN]; char path[FN_LEN]; - TABLE_LOG_MEMORY_ENTRY *old_log_entry= part_info->first_log_entry; - uint next_entry= old_log_entry->entry_pos; + TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; + uint next_entry= old_first_log_entry->entry_pos; /* Ensure we linked the existing entries at the back */ DBUG_ENTER("write_log_add_partition"); @@ -5341,15 +5344,16 @@ write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) break; log_entry= part_info->first_log_entry; /* Ensure first entry is the last dropped partition */ - if (write_execute_table_log_entry(log_entry->entry_pos, NULL)) + if (write_execute_table_log_entry(log_entry->entry_pos, &exec_log_entry)) break; release_part_info_log_entries(old_first_log_entry); unlock_global_table_log(); DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= old_log_entry; + part_info->first_log_entry= old_first_log_entry; unlock_global_table_log(); + my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5473,6 +5477,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, DBUG_ENTER("fast_alter_partition_table"); lpt->thd= thd; + lpt->part_info= part_info; lpt->create_info= create_info; lpt->create_list= create_list; lpt->key_list= key_list; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 37cd6397dbc..5699c404899 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -334,7 +334,8 @@ write_table_log_file_entry(uint entry_no) char *file_entry= (char*)global_table_log.file_entry; DBUG_ENTER("write_table_log_file_entry"); - if (my_pwrite(file_id, file_entry, IO_SIZE, IO_SIZE * entry_no, MYF(0))) + if (my_pwrite(file_id, file_entry, + IO_SIZE, IO_SIZE * entry_no, MYF(0)) != IO_SIZE) error= TRUE; DBUG_RETURN(error); } @@ -640,10 +641,10 @@ write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, table_log_entry->next_entry); strcpy(&global_table_log.file_entry[6], table_log_entry->name); if (table_log_entry->action_type == 'r') - global_table_log.file_entry[6 + FN_LEN]= 0; - else strcpy(&global_table_log.file_entry[6 + FN_LEN], table_log_entry->from_name); + else + global_table_log.file_entry[6 + FN_LEN]= 0; strcpy(&global_table_log.file_entry[6 + (2*FN_LEN)], table_log_entry->handler_type); if (get_free_table_log_entry(active_entry, &write_header)) @@ -700,9 +701,12 @@ write_execute_table_log_entry(uint first_entry, file_entry[6]= 0; file_entry[6 + FN_LEN]= 0; file_entry[6 + 2*FN_LEN]= 0; - if (get_free_table_log_entry(active_entry, &write_header)) + if (!(*active_entry)) { - DBUG_RETURN(TRUE); + if (get_free_table_log_entry(active_entry, &write_header)) + { + DBUG_RETURN(TRUE); + } } if (write_table_log_file_entry((*active_entry)->entry_pos)) { From d7bd607db0140960bc82415cc87c2d9b0cd824e4 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2006 14:20:20 -0500 Subject: [PATCH 18/48] WL 2826: Error handling of ALTER TABLE for partitioning More fixes sql/sql_partition.cc: More fixes --- sql/sql_partition.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 71d6d7b200c..c6498c6fa1b 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5181,7 +5181,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, char tmp_path[FN_LEN]; List_iterator part_it(part_info->partitions); uint no_elements= part_info->partitions.elements; - uint i; + uint i= 0; DBUG_ENTER("write_log_dropped_partitions"); table_log_entry.action_type= 'd'; @@ -5195,6 +5195,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, { List_iterator sub_it(part_elem->subpartitions); uint no_subparts= part_info->no_subparts; + uint j= 0; do { partition_element *sub_elem= sub_it++; @@ -5212,7 +5213,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, } *next_entry= log_entry->entry_pos; insert_part_info_log_entry_list(part_info, log_entry); - } while (++i < no_subparts); + } while (++j < no_subparts); } else { From 392b82a10a0ce5ef960d079db84233d626e6a7f3 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2006 20:20:21 +0100 Subject: [PATCH 19/48] WL 2826: Error handling of ALTER TABLE for partitioning A little more complete handling sql/mysql_priv.h: Complete flag sql/sql_table.cc: A little more complete handling sql/sql_partition.cc: A little more complete handling --- sql/mysql_priv.h | 1 + sql/sql_partition.cc | 25 ++++++++++++++++++++----- sql/sql_table.cc | 12 ++++++++++-- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index d22f894e43d..cde050e877b 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1190,6 +1190,7 @@ typedef struct st_table_log_memory_entry bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, TABLE_LOG_MEMORY_ENTRY **active_entry); bool write_execute_table_log_entry(uint first_entry, + bool complete, TABLE_LOG_MEMORY_ENTRY **active_entry); void release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry); void release_table_log(); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index c6498c6fa1b..f0f22b4d927 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5100,7 +5100,7 @@ release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) while (log_entry) { release_table_log_memory_entry(log_entry); - log_entry= log_entry->next_log_entry; + log_entry= log_entry->next_active_log_entry; } DBUG_VOID_RETURN; } @@ -5145,7 +5145,8 @@ write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) if (write_table_log_entry(&table_log_entry, &log_entry)) break; insert_part_info_log_entry_list(part_info, log_entry); - if (write_execute_table_log_entry(log_entry->entry_pos, &exec_log_entry)) + if (write_execute_table_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) break; part_info->exec_log_entry= exec_log_entry; unlock_global_table_log(); @@ -5286,7 +5287,8 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_table_log_entry(&table_log_entry, &log_entry)) break; insert_part_info_log_entry_list(part_info, log_entry); - if (write_execute_table_log_entry(log_entry->entry_pos, &exec_log_entry)) + if (write_execute_table_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) break; release_part_info_log_entries(old_first_log_entry); unlock_global_table_log(); @@ -5345,7 +5347,8 @@ write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) break; log_entry= part_info->first_log_entry; /* Ensure first entry is the last dropped partition */ - if (write_execute_table_log_entry(log_entry->entry_pos, &exec_log_entry)) + if (write_execute_table_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) break; release_part_info_log_entries(old_first_log_entry); unlock_global_table_log(); @@ -5426,9 +5429,21 @@ static bool write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt) { - DBUG_ENTER("write_log_ph2_change_partition"); + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry; + DBUG_ENTER("write_log_completed"); lock_global_table_log(); + DBUG_ASSERT(part_info->exec_log_entry); + if (write_execute_table_log_entry(0UL, TRUE, &part_info->exec_log_entry)) + { + DBUG_RETURN(TRUE); + } + release_part_info_log_entries(part_info->first_log_entry); + part_info->first_log_entry= NULL; + part_info->exec_log_entry->next_active_log_entry= NULL; + release_part_info_log_entries(part_info->exec_log_entry); + part_info->exec_log_entry= NULL; unlock_global_table_log(); DBUG_RETURN(FALSE); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 5699c404899..4568b6a92ae 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -367,6 +367,8 @@ write_table_log_header() int4store(&global_table_log.file_entry[8], const_var); if (write_table_log_file_entry(0UL)) error= TRUE; + if (!error) + error= sync_table_log(); DBUG_RETURN(error); } @@ -688,14 +690,20 @@ write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, bool write_execute_table_log_entry(uint first_entry, + bool complete, TABLE_LOG_MEMORY_ENTRY **active_entry) { bool write_header; char *file_entry= (char*)global_table_log.file_entry; DBUG_ENTER("write_execute_table_log_entry"); - VOID(sync_table_log()); - file_entry[0]= 'e'; + if (!complete) + { + VOID(sync_table_log()); + file_entry[0]= 'e'; + } + else + file_entry[0]= 'i'; file_entry[1]= 0; /* Ignored for execute entries */ int4store(&file_entry[2], first_entry); file_entry[6]= 0; From ddb14e0f238d92cd55dcd594815ae6bfa8f3577e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2006 20:20:22 +0100 Subject: [PATCH 20/48] WL 2826: Error handling of ALTER TABLE for partitioning More work on table logging of ALTER TABLE for partitioning sql/mysql_priv.h: More work on table logging of ALTER TABLE for partitioning sql/sql_partition.cc: More work on table logging of ALTER TABLE for partitioning --- sql/mysql_priv.h | 6 - sql/sql_partition.cc | 362 ++++++++++++++++++++++++++++--------------- 2 files changed, 233 insertions(+), 135 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index cde050e877b..e0875b06a0a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1199,12 +1199,6 @@ bool execute_table_log_entry(uint first_entry); void lock_global_table_log(); void unlock_global_table_log(); -bool write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_flag); -bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt); -bool write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt); -bool write_log_ph1_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt); -bool write_log_ph2_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt); - #define WFRM_WRITE_SHADOW 1 #define WFRM_INSTALL_SHADOW 2 #define WFRM_PACK_FRM 4 diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index f0f22b4d927..ea358154b1c 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5107,56 +5107,48 @@ release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) /* - Write the log entry to ensure that the shadow frm file is removed at - crash. + Log an delete/rename frm file SYNOPSIS - write_log_shadow_frm() - lpt Struct containing parameters - install_frm Should we log action to install shadow frm or should - the action be to remove the shadow frm file. + write_log_rename_delete_frm() + lpt Struct for parameters + next_entry Next reference to use in log record + path Name to rename from + rename_flag TRUE if rename, else delete RETURN VALUES - TRUE Error - FALSE Success + TRUE Error + FALSE Success DESCRIPTION - Prepare an entry to the table log indicating a drop/install of the shadow frm - file and its corresponding handler file. + Support routine that writes a rename or delete of an frm file into the + table log. It also inserts an entry that keeps track of used space into + the partition info object */ bool -write_log_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt, bool install_frm) +write_log_rename_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, + uint next_entry, + const char *from_path + const char *to_path, + bool rename_flag) { TABLE_LOG_ENTRY table_log_entry; - partition_info *part_info= lpt->part_info; TABLE_LOG_MEMORY_ENTRY *log_entry; - TABLE_LOG_MEMORY_ENTRY *exec_log_entry= NULL; - char shadow_path[FN_LEN]; - DBUG_ENTER("write_log_shadow_frm"); + DBUG_ENTER("write_log_rename_frm"); - lock_global_table_log(); - do - { - build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, - lpt->table_name, "#"); + if (rename_flag) + table_log_entry.action_type= 'r'; + else table_log_entry.action_type= 'd'; - table_log_entry.next_entry= 0; - table_log_entry.handler_type= "frm"; - table_log_entry.name= shadow_path; - - if (write_table_log_entry(&table_log_entry, &log_entry)) - break; - insert_part_info_log_entry_list(part_info, log_entry); - if (write_execute_table_log_entry(log_entry->entry_pos, - FALSE, &exec_log_entry)) - break; - part_info->exec_log_entry= exec_log_entry; - unlock_global_table_log(); - DBUG_RETURN(FALSE); - } while (TRUE); - release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= NULL; - unlock_global_table_log(); - my_error(ER_TABLE_LOG_ERROR, MYF(0)); - DBUG_RETURN(TRUE); + table_log_entry.next_entry= next_entry; + table_log_entry.handler_type= "frm"; + if (rename_flag) + table_log_entry.name= to_path; + table_log_entry.from_name= from_path; + if (write_table_log_entry(&table_log_entry, &log_entry)) + { + DBUG_RETURN(TRUE); + } + insert_part_info_log_entry_list(part_info, log_entry); + DBUG_RETURN(FALSE); } @@ -5174,24 +5166,41 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, uint *next_entry, - const char *path) + const char *path, + bool temp_list) { TABLE_LOG_ENTRY table_log_entry; partition_info *part_info= lpt->part_info; TABLE_LOG_MEMORY_ENTRY *log_entry; char tmp_path[FN_LEN]; List_iterator part_it(part_info->partitions); + List_iterator temp_it(part_info->temp_partitions); + uint no_temp_partitions= part_info->temp_partitions.elements; uint no_elements= part_info->partitions.elements; uint i= 0; DBUG_ENTER("write_log_dropped_partitions"); table_log_entry.action_type= 'd'; - do + if (temp_list) + no_elements= no_temp_partitions; + while (no_elements--) { - partition_element *part_elem= part_it++; + partition_element *part_elem; + if (temp_list) + part_elem= temp_it++; + else + part_elem= part_it++; if (part_elem->part_state == PART_TO_BE_DROPPED || - part_elem->part_state == PART_TO_BE_ADDED) + part_elem->part_state == PART_TO_BE_ADDED || + part_elem->part_state == PART_CHANGED) { + uint name_variant; + if (part_elem->part_state == PART_CHANGED || + (part_elem->part_state == PART_TO_BE_ADDED && + no_temp_partitions)) + name_variant= TEMP_PART_NAME; + else + name_variant= NORMAL_PART_NAME; if (is_sub_partitioned(part_info)) { List_iterator sub_it(part_elem->subpartitions); @@ -5202,11 +5211,11 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, partition_element *sub_elem= sub_it++; table_log_entry.next_entry= *next_entry; table_log_entry.handler_type= - ha_resolve_storage_engine_name(sub_elem->engine_type); + ha_resolve_storage_engine_name(sub_elem->engine_type); create_subpartition_name(tmp_path, path, part_elem->partition_name, sub_elem->partition_name, - NORMAL_PART_NAME); + name_variant); table_log_entry.name= tmp_path; if (write_table_log_entry(&table_log_entry, &log_entry)) { @@ -5223,7 +5232,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, ha_resolve_storage_engine_name(part_elem->engine_type); create_partition_name(tmp_path, path, part_elem->partition_name, - NORMAL_PART_NAME, TRUE); + name_variant, TRUE); table_log_entry.name= tmp_path; if (write_table_log_entry(&table_log_entry, &log_entry)) { @@ -5233,11 +5242,112 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, insert_part_info_log_entry_list(part_info, log_entry); } } - } while (++i < no_elements); + } DBUG_RETURN(FALSE); } +/* + Write the log entry to ensure that the shadow frm file is removed at + crash. + SYNOPSIS + write_log_drop_shadow_frm() + lpt Struct containing parameters + install_frm Should we log action to install shadow frm or should + the action be to remove the shadow frm file. + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Prepare an entry to the table log indicating a drop/install of the shadow frm + file and its corresponding handler file. +*/ + +static +bool +write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + TABLE_LOG_ENTRY table_log_entry; + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry; + TABLE_LOG_MEMORY_ENTRY *exec_log_entry= NULL; + char shadow_path[FN_LEN]; + DBUG_ENTER("write_log_drop_shadow_frm"); + + lock_global_table_log(); + do + { + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); + if (write_log_rename_delete_frm(lpt, 0UL, NULL, + (const char*)shadow_path, FALSE)) + break; + log_entry= part_info->first_log_entry; + if (write_execute_table_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + break; + part_info->exec_log_entry= exec_log_entry; + unlock_global_table_log(); + DBUG_RETURN(FALSE); + } while (TRUE); + release_part_info_log_entries(part_info->first_log_entry); + part_info->first_log_entry= NULL; + unlock_global_table_log(); + my_error(ER_TABLE_LOG_ERROR, MYF(0)); + DBUG_RETURN(TRUE); +} + + +/* + Log renaming of shadow frm to real frm name and dropping of old frm + SYNOPSIS + write_log_rename_frm() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Prepare an entry to ensure that we complete the renaming of the frm + file if failure occurs in the middle of the rename process. +*/ + +static +bool +write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + TABLE_LOG_ENTRY table_log_entry; + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry; + TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + char shadow_path[FN_LEN]; + TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; + DBUG_ENTER("write_log_drop_shadow_frm"); + + lock_global_table_log(); + do + { + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); + if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) + break; + log_entry= part_info->first_log_entry; + if (write_execute_table_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + break; + release_part_info_log_entries(old_first_log_entry); + unlock_global_table_log(); + DBUG_RETURN(FALSE); + } while (TRUE); + release_part_info_log_entries(part_info->first_log_entry); + part_info->first_log_entry= old_first_log_entry; + unlock_global_table_log(); + my_error(ER_TABLE_LOG_ERROR, MYF(0)); + DBUG_RETURN(TRUE); +} + + /* Write the log entries to ensure that the drop partition command is completed even in the presence of a crash. @@ -5253,6 +5363,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, install the shadow frm file and remove the old frm file. */ +static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { @@ -5269,24 +5380,18 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) part_info->first_log_entry= NULL; build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); + build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, + lpt->table_name, "#"); lock_global_table_log(); do { - if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path)) + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path), + FALSE) break; - /* - At first we write an entry that installs the new frm file - */ - build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, - lpt->table_name, "#"); - table_log_entry.action_type= 'r'; - table_log_entry.next_entry= next_entry; - table_log_entry.handler_type= "frm"; - table_log_entry.name= path; - table_log_entry.from_name= tmp_path; - if (write_table_log_entry(&table_log_entry, &log_entry)) + if (write_log_rename_delete_frm(lpt, next_entry, (const char*)path, + (const char*)tmp_path, TRUE)) break; - insert_part_info_log_entry_list(part_info, log_entry); + log_entry= part_info->first_log_entry; if (write_execute_table_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) break; @@ -5307,7 +5412,7 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) executed at all if a crash before it has completed SYNOPSIS - write_log_add_partition() + write_log_add_change_partition() lpt Struct containing parameters RETURN VALUES TRUE Error @@ -5315,85 +5420,55 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) DESCRIPTION Prepare entries to the table log indicating all partitions to drop and to remove the shadow frm file. - The removal of the shadow frm file is already in the log file so we only - need to link the new entries to the existing and carefully ensure that - the new linked list has first the dropped partitions and then the - drop of the shadow frm file. We always inject entries backwards in the list in the table log since we don't know the entry position until we have written it. */ +static bool -write_log_add_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { - TABLE_LOG_ENTRY table_log_entry; partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry; + TABLE_LOG_MEMORY_ENTRY *log_entry, *exec_log_entry; char tmp_path[FN_LEN]; char path[FN_LEN]; - TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; - TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; - uint next_entry= old_first_log_entry->entry_pos; - /* Ensure we linked the existing entries at the back */ - DBUG_ENTER("write_log_add_partition"); + uint next_entry= 0; + DBUG_ENTER("write_log_add_change_partition"); - part_info->first_log_entry= NULL; build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); lock_global_table_log(); do { - if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path)) + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path), + FALSE) + break; + build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, + lpt->table_name, "#"); + if (write_log_rename_delete_frm(lpt, next_entry, tmp_path, + NULL, FALSE)) break; log_entry= part_info->first_log_entry; - /* Ensure first entry is the last dropped partition */ if (write_execute_table_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) break; - release_part_info_log_entries(old_first_log_entry); unlock_global_table_log(); DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= old_first_log_entry; + part_info->first_log_entry= NULL; unlock_global_table_log(); my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } -/* - Write indicator of how to abort in first phase of change partitions - SYNOPSIS - write_log_ph1_change_partition() - lpt Struct containing parameters - RETURN VALUES - TRUE Error - FALSE Success - DESCRIPTION - Write the log entries to remove partitions in creation when changing - partitions in an ADD/REORGANIZE/COALESCE command. These commands will - abort the entire operation if the system crashes before the next phase - is done. -*/ - -bool -write_log_ph1_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) -{ - DBUG_ENTER("write_log_ph1_change_partition"); - - lock_global_table_log(); - unlock_global_table_log(); - DBUG_RETURN(FALSE); -} - - /* Write description of how to complete the operation after first phase of change partitions. SYNOPSIS - write_log_ph2_change_partition() + write_log_final_change_partition() lpt Struct containing parameters RETURN VALUES TRUE Error @@ -5404,14 +5479,46 @@ write_log_ph1_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) frm file. */ +static bool -write_log_ph2_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { - DBUG_ENTER("write_log_ph2_change_partition"); + TABLE_LOG_ENTRY table_log_entry; + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry; + TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + char shadow_path[FN_LEN]; + TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; + uint next_entry= 0; + DBUG_ENTER("write_log_final_change_partition"); lock_global_table_log(); + do + { + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path), + TRUE) + break; + if (write_log_changed_partitions(lpt, &next_entry, (const char*)path)) + break; + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); + if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) + break; + log_entry= part_info->first_log_entry; + if (write_execute_table_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + break; + release_part_info_log_entries(old_first_log_entry); + unlock_global_table_log(); + DBUG_RETURN(FALSE); + } while (TRUE); + release_part_info_log_entries(part_info->first_log_entry); + part_info->first_log_entry= old_first_log_entry; unlock_global_table_log(); - DBUG_RETURN(FALSE); + my_error(ER_TABLE_LOG_ERROR, MYF(0)); + DBUG_RETURN(TRUE); } @@ -5425,6 +5532,7 @@ write_log_ph2_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) TRUE Error FALSE Success */ + static bool write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt) @@ -5641,7 +5749,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, We insert Error injections at all places where it could be interesting to test if recovery is properly done. */ - if (write_log_shadow_frm(lpt, FALSE) || + if (write_log_drop_shadow_frm(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECT_CRASH("crash_drop_partition_2") || @@ -5697,26 +5805,24 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 8) Remove entries from table log 9) Complete query */ - if (write_log_shadow_frm(lpt, FALSE) || + if (write_log_add_change_partition(lpt) || ERROR_INJECT_CRASH("crash_add_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECT_CRASH("crash_add_partition_2") || - write_log_add_partition(lpt) || - ERROR_INJECT_CRASH("crash_add_partition_3") || mysql_change_partitions(lpt) || - ERROR_INJECT_CRASH("crash_add_partition_4") || + ERROR_INJECT_CRASH("crash_add_partition_3") || abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || + ERROR_INJECT_CRASH("crash_add_partition_4") || + write_log_rename_frm(lpt) || ERROR_INJECT_CRASH("crash_add_partition_5") || - write_log_shadow_frm(lpt, TRUE) || - ERROR_INJECT_CRASH("crash_add_partition_6") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || - ERROR_INJECT_CRASH("crash_add_partition_7") || + ERROR_INJECT_CRASH("crash_add_partition_6") || (close_open_tables_and_downgrade(lpt), FALSE) || write_log_completed(lpt) || - ERROR_INJECT_CRASH("crash_add_partition_8")) + ERROR_INJECT_CRASH("crash_add_partition_7")) { fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); @@ -5778,33 +5884,31 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 14)Complete query */ - if (write_log_shadow_frm(lpt, FALSE) || + if (write_log_add_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECT_CRASH("crash_change_partition_2") || - write_log_ph1_change_partition(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_3") || mysql_change_partitions(lpt) || + ERROR_INJECT_CRASH("crash_change_partition_3") || + write_log_final_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_4") || - write_log_ph2_change_partition(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_5") || abort_and_upgrade_lock(lpt) || table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE) || - ERROR_INJECT_CRASH("crash_change_partition_6") || + ERROR_INJECT_CRASH("crash_change_partition_5") || mysql_rename_partitions(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_7") || + ERROR_INJECT_CRASH("crash_change_partition_6") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - ERROR_INJECT_CRASH("crash_change_partition_8") || + ERROR_INJECT_CRASH("crash_change_partition_7") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || - ERROR_INJECT_CRASH("crash_change_partition_9") || + ERROR_INJECT_CRASH("crash_change_partition_8") || (close_open_tables_and_downgrade(lpt), FALSE) || - ERROR_INJECT_CRASH("crash_change_partition_10") || + ERROR_INJECT_CRASH("crash_change_partition_9") || mysql_drop_partitions(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_11") || + ERROR_INJECT_CRASH("crash_change_partition_10") || write_log_completed(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_12") || + ERROR_INJECT_CRASH("crash_change_partition_11") || (mysql_wait_completed_table(lpt, table), FALSE)) { fast_alter_partition_error_handler(lpt); From 4bef9c0e0104d7fd2eca52275de070257e63aac3 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2006 20:25:10 +0100 Subject: [PATCH 21/48] WL 2826: Error handling of ALTER TABLE for partitioning Error handling Crash if any error after reaching beyond certain point in ALTER TABLE processing sql/ha_partition.cc: Error handling Crash if any error after reaching beyond certain point in ALTER TABLE processing sql/sql_partition.cc: Error handling Crash if any error after reaching beyond certain point in ALTER TABLE processing --- sql/ha_partition.cc | 30 +++++++++++++++--------------- sql/sql_partition.cc | 27 +++++++++++++++++++-------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 80047d438e1..fade6803156 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -584,7 +584,7 @@ int ha_partition::drop_partitions(const char *path) uint no_subparts= m_part_info->no_subparts; uint i= 0; uint name_variant; - int error= 1; + int error= 0; bool reorged_parts= (m_reorged_parts > 0); bool temp_partitions= (m_part_info->temp_partitions.elements > 0); DBUG_ENTER("ha_partition::drop_partitions"); @@ -632,7 +632,7 @@ int ha_partition::drop_partitions(const char *path) else file= m_file[part]; DBUG_PRINT("info", ("Drop subpartition %s", part_name_buff)); - error= file->delete_table((const char *) part_name_buff); + error+= file->delete_table((const char *) part_name_buff); } while (++j < no_subparts); } else @@ -645,7 +645,7 @@ int ha_partition::drop_partitions(const char *path) else file= m_file[i]; DBUG_PRINT("info", ("Drop partition %s", part_name_buff)); - error= file->delete_table((const char *) part_name_buff); + error+= file->delete_table((const char *) part_name_buff); } if (part_elem->part_state == PART_IS_CHANGED) part_elem->part_state= PART_NORMAL; @@ -687,7 +687,7 @@ int ha_partition::rename_partitions(const char *path) uint no_subparts= m_part_info->no_subparts; uint i= 0; uint j= 0; - int error= 1; + int error= 0; uint temp_partitions= m_part_info->temp_partitions.elements; handler *file; partition_element *part_elem, *sub_elem; @@ -715,8 +715,8 @@ int ha_partition::rename_partitions(const char *path) NORMAL_PART_NAME); DBUG_PRINT("info", ("Rename subpartition from %s to %s", norm_name_buff, part_name_buff)); - error= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + error+= file->rename_table((const char *) norm_name_buff, + (const char *) part_name_buff); } while (++j < no_subparts); } else @@ -730,8 +730,8 @@ int ha_partition::rename_partitions(const char *path) TRUE); DBUG_PRINT("info", ("Rename partition from %s to %s", norm_name_buff, part_name_buff)); - error= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + error+= file->rename_table((const char *) norm_name_buff, + (const char *) part_name_buff); } } while (++i < temp_partitions); } @@ -765,8 +765,8 @@ int ha_partition::rename_partitions(const char *path) RENAMED_PART_NAME); DBUG_PRINT("info", ("Rename subpartition from %s to %s", norm_name_buff, part_name_buff)); - error= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + error+= file->rename_table((const char *) norm_name_buff, + (const char *) part_name_buff); } file= m_new_file[part]; create_subpartition_name(part_name_buff, path, @@ -775,8 +775,8 @@ int ha_partition::rename_partitions(const char *path) TEMP_PART_NAME); DBUG_PRINT("info", ("Rename subpartition from %s to %s", part_name_buff, norm_name_buff)); - error= file->rename_table((const char *) part_name_buff, - (const char *) norm_name_buff); + error+= file->rename_table((const char *) part_name_buff, + (const char *) norm_name_buff); } while (++j < no_subparts); } else @@ -792,8 +792,8 @@ int ha_partition::rename_partitions(const char *path) TRUE); DBUG_PRINT("info", ("Rename partition from %s to %s", norm_name_buff, part_name_buff)); - error= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + error+= file->rename_table((const char *) norm_name_buff, + (const char *) part_name_buff); } file= m_new_file[i]; create_partition_name(part_name_buff, path, @@ -801,7 +801,7 @@ int ha_partition::rename_partitions(const char *path) TRUE); DBUG_PRINT("info", ("Rename partition from %s to %s", part_name_buff, norm_name_buff)); - error= file->rename_table((const char *) part_name_buff, + error+= file->rename_table((const char *) part_name_buff, (const char *) norm_name_buff); } } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index ea358154b1c..95bcc6279ac 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5749,12 +5749,14 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, We insert Error injections at all places where it could be interesting to test if recovery is properly done. */ + bool not_completed= TRUE; if (write_log_drop_shadow_frm(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECT_CRASH("crash_drop_partition_2") || write_log_drop_partition(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_3") || + (not_completed= FALSE) || abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, @@ -5763,7 +5765,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || (close_open_tables_and_downgrade(lpt), FALSE) || ERROR_INJECT_CRASH("crash_drop_partition_5") || - table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE) || + (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) || ERROR_INJECT_CRASH("crash_drop_partition_6") || mysql_drop_partitions(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_7") || @@ -5771,6 +5773,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_drop_partition_8") || (mysql_wait_completed_table(lpt, table), FALSE)) { + if (!not_completed) + abort(); fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); } @@ -5805,6 +5809,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 8) Remove entries from table log 9) Complete query */ + bool not_completed= TRUE; if (write_log_add_change_partition(lpt) || ERROR_INJECT_CRASH("crash_add_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || @@ -5817,6 +5822,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, thd->query, thd->query_length), FALSE)) || ERROR_INJECT_CRASH("crash_add_partition_4") || write_log_rename_frm(lpt) || + (not_completed= FALSE) || ERROR_INJECT_CRASH("crash_add_partition_5") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || ERROR_INJECT_CRASH("crash_add_partition_6") || @@ -5824,6 +5830,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, write_log_completed(lpt) || ERROR_INJECT_CRASH("crash_add_partition_7")) { + if (!not_completed) + abort(); fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); } @@ -5883,7 +5891,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 13)Wait until all accesses using the old frm file has completed 14)Complete query */ - + bool not_completed= TRUE; if (write_log_add_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || @@ -5892,14 +5900,15 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_change_partition_3") || write_log_final_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_4") || + (not_completed= FALSE) || abort_and_upgrade_lock(lpt) || - table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE) || - ERROR_INJECT_CRASH("crash_change_partition_5") || - mysql_rename_partitions(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_6") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || + ERROR_INJECT_CRASH("crash_change_partition_5") || + (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) || + ERROR_INJECT_CRASH("crash_change_partition_6") || + mysql_rename_partitions(lpt) || ERROR_INJECT_CRASH("crash_change_partition_7") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || ERROR_INJECT_CRASH("crash_change_partition_8") || @@ -5911,8 +5920,10 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_change_partition_11") || (mysql_wait_completed_table(lpt, table), FALSE)) { - fast_alter_partition_error_handler(lpt); - DBUG_RETURN(TRUE); + if (!not_completed) + abort(); + fast_alter_partition_error_handler(lpt); + DBUG_RETURN(TRUE); } } /* From de3c77dfec05b6b7c8d985f46c2746bbe70e27bb Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2006 21:23:45 -0500 Subject: [PATCH 22/48] WL 2826: Error handling of ALTER TABLE for partitioning Bug fixes sql/sql_partition.cc: Bug fixes --- sql/sql_partition.cc | 51 ++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index ea358154b1c..98e13c1bca1 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5126,7 +5126,7 @@ release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) bool write_log_rename_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint next_entry, - const char *from_path + const char *from_path, const char *to_path, bool rename_flag) { @@ -5140,14 +5140,34 @@ write_log_rename_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, table_log_entry.action_type= 'd'; table_log_entry.next_entry= next_entry; table_log_entry.handler_type= "frm"; + table_log_entry.name= to_path; if (rename_flag) - table_log_entry.name= to_path; - table_log_entry.from_name= from_path; + table_log_entry.from_name= from_path; if (write_table_log_entry(&table_log_entry, &log_entry)) { DBUG_RETURN(TRUE); } - insert_part_info_log_entry_list(part_info, log_entry); + insert_part_info_log_entry_list(lpt->part_info, log_entry); + DBUG_RETURN(FALSE); +} + + +/* + Log final partition changes in change partition + SYNOPSIS + write_log_changed_partitions() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, + uint *next_entry, const char *path) +{ + DBUG_ENTER("write_log_changed_partitions"); DBUG_RETURN(FALSE); } @@ -5319,6 +5339,7 @@ write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) partition_info *part_info= lpt->part_info; TABLE_LOG_MEMORY_ENTRY *log_entry; TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + char path[FN_LEN]; char shadow_path[FN_LEN]; TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; DBUG_ENTER("write_log_drop_shadow_frm"); @@ -5385,8 +5406,8 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lock_global_table_log(); do { - if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path), - FALSE) + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, + FALSE)) break; if (write_log_rename_delete_frm(lpt, next_entry, (const char*)path, (const char*)tmp_path, TRUE)) @@ -5440,18 +5461,19 @@ write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lock_global_table_log(); do { - if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path), - FALSE) + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, + FALSE)) break; build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, lpt->table_name, "#"); - if (write_log_rename_delete_frm(lpt, next_entry, tmp_path, - NULL, FALSE)) + if (write_log_rename_delete_frm(lpt, next_entry, NULL, tmp_path, + FALSE)) break; log_entry= part_info->first_log_entry; if (write_execute_table_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) break; + part_info->exec_log_entry= exec_log_entry; unlock_global_table_log(); DBUG_RETURN(FALSE); } while (TRUE); @@ -5487,6 +5509,7 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) partition_info *part_info= lpt->part_info; TABLE_LOG_MEMORY_ENTRY *log_entry; TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + char path[FN_LEN]; char shadow_path[FN_LEN]; TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; uint next_entry= 0; @@ -5495,13 +5518,13 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lock_global_table_log(); do { - if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path), - TRUE) + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, + TRUE)) break; if (write_log_changed_partitions(lpt, &next_entry, (const char*)path)) break; - build_table_filename(path, sizeof(path), lpt->db, - lpt->table_name, ""); build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) From f99f322ea2df8932a551395b6b58623678d2b7c4 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2006 23:57:54 -0500 Subject: [PATCH 23/48] Bug fixes + debug stuff --- sql/sql_partition.cc | 12 ++++++++---- sql/sql_table.cc | 15 ++++++++++----- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index f68c4d862d5..95ed97bda05 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5450,7 +5450,8 @@ bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry, *exec_log_entry; + TABLE_LOG_MEMORY_ENTRY *log_entry; + TABLE_LOG_MEMORY_ENTRY *exec_log_entry= NULL; char tmp_path[FN_LEN]; char path[FN_LEN]; uint next_entry= 0; @@ -5779,7 +5780,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_drop_partition_2") || write_log_drop_partition(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_3") || - (not_completed= FALSE) || + ((not_completed= FALSE), FALSE) || abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, @@ -5796,6 +5797,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_drop_partition_8") || (mysql_wait_completed_table(lpt, table), FALSE)) { + abort(); if (!not_completed) abort(); fast_alter_partition_error_handler(lpt); @@ -5845,7 +5847,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, thd->query, thd->query_length), FALSE)) || ERROR_INJECT_CRASH("crash_add_partition_4") || write_log_rename_frm(lpt) || - (not_completed= FALSE) || + ((not_completed= FALSE), FALSE) || ERROR_INJECT_CRASH("crash_add_partition_5") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || ERROR_INJECT_CRASH("crash_add_partition_6") || @@ -5853,6 +5855,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, write_log_completed(lpt) || ERROR_INJECT_CRASH("crash_add_partition_7")) { + abort(); if (!not_completed) abort(); fast_alter_partition_error_handler(lpt); @@ -5923,7 +5926,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_change_partition_3") || write_log_final_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_4") || - (not_completed= FALSE) || + ((not_completed= FALSE), FALSE) || abort_and_upgrade_lock(lpt) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, @@ -5943,6 +5946,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_change_partition_11") || (mysql_wait_completed_table(lpt, table), FALSE)) { + abort(); if (!not_completed) abort(); fast_alter_partition_error_handler(lpt); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4568b6a92ae..260d1650f20 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -641,14 +641,19 @@ write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, global_table_log.file_entry[1]= table_log_entry->action_type; int4store(&global_table_log.file_entry[2], table_log_entry->next_entry); - strcpy(&global_table_log.file_entry[6], table_log_entry->name); + DBUG_ASSERT(strlen(table_log_entry->name) < FN_LEN); + strncpy(&global_table_log.file_entry[6], table_log_entry->name, FN_LEN); if (table_log_entry->action_type == 'r') - strcpy(&global_table_log.file_entry[6 + FN_LEN], - table_log_entry->from_name); + { + DBUG_ASSERT(strlen(table_log_entry->from_name) < FN_LEN); + strncpy(&global_table_log.file_entry[6 + FN_LEN], + table_log_entry->from_name, FN_LEN); + } else global_table_log.file_entry[6 + FN_LEN]= 0; - strcpy(&global_table_log.file_entry[6 + (2*FN_LEN)], - table_log_entry->handler_type); + DBUG_ASSERT(strlen(table_log_entry->handler_type) < FN_LEN); + strncpy(&global_table_log.file_entry[6 + (2*FN_LEN)], + table_log_entry->handler_type, FN_LEN); if (get_free_table_log_entry(active_entry, &write_header)) { DBUG_RETURN(TRUE); From 2287cee6938cf4e1dcc461cac31ea9cdf74a65d9 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 10 Feb 2006 12:30:51 +0100 Subject: [PATCH 24/48] WL 2826: Error handling of ALTER TABLE for partitioning New function to set exec_log_entry Moving code outside lock of table log Fixing some initialisations of list reference to avoid releasing wrong parts sql/sql_partition.cc: New function to set exec_log_entry Moving code outside lock of table log Fixing some initialisations of list reference to avoid releasing wrong parts sql/sql_table.cc: Initialisation of write_header needed --- sql/sql_partition.cc | 71 ++++++++++++++++++++++++++++---------------- sql/sql_table.cc | 2 +- 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 95ed97bda05..770d2c4ab39 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5267,6 +5267,26 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, } +/* + Set execute log entry in table log for this partitioned table + SYNOPSIS + set_part_info_exec_log_entry() + part_info Partition info object + exec_log_entry Log entry + RETURN VALUES + NONE +*/ + +static +void +set_part_info_exec_log_entry(partition_info *part_info, + TABLE_LOG_MEMORY_ENTRY *exec_log_entry) +{ + part_info->exec_log_entry= exec_log_entry; + exec_log_entry->next_active_log_entry= NULL; +} + + /* Write the log entry to ensure that the shadow frm file is removed at crash. @@ -5294,11 +5314,11 @@ write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) char shadow_path[FN_LEN]; DBUG_ENTER("write_log_drop_shadow_frm"); + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); lock_global_table_log(); do { - build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, - lpt->table_name, "#"); if (write_log_rename_delete_frm(lpt, 0UL, NULL, (const char*)shadow_path, FALSE)) break; @@ -5306,13 +5326,13 @@ write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_execute_table_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) break; - part_info->exec_log_entry= exec_log_entry; unlock_global_table_log(); + set_part_info_exec_log_entry(part_info, exec_log_entry); DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= NULL; unlock_global_table_log(); + part_info->first_log_entry= NULL; my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5342,15 +5362,16 @@ write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) char path[FN_LEN]; char shadow_path[FN_LEN]; TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; - DBUG_ENTER("write_log_drop_shadow_frm"); + DBUG_ENTER("write_log_rename_frm"); + part_info->first_log_entry= NULL; + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); lock_global_table_log(); do { - build_table_filename(path, sizeof(path), lpt->db, - lpt->table_name, ""); - build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, - lpt->table_name, "#"); if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) break; log_entry= part_info->first_log_entry; @@ -5362,8 +5383,8 @@ write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= old_first_log_entry; unlock_global_table_log(); + part_info->first_log_entry= old_first_log_entry; my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5421,8 +5442,8 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= old_first_log_entry; unlock_global_table_log(); + part_info->first_log_entry= old_first_log_entry; my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5459,14 +5480,14 @@ write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); + build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, + lpt->table_name, "#"); lock_global_table_log(); do { if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, FALSE)) break; - build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, - lpt->table_name, "#"); if (write_log_rename_delete_frm(lpt, next_entry, NULL, tmp_path, FALSE)) break; @@ -5474,13 +5495,13 @@ write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_execute_table_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) break; - part_info->exec_log_entry= exec_log_entry; unlock_global_table_log(); + set_part_info_exec_log_entry(part_info, exec_log_entry); DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= NULL; unlock_global_table_log(); + part_info->first_log_entry= NULL; my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5516,18 +5537,19 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) uint next_entry= 0; DBUG_ENTER("write_log_final_change_partition"); + part_info->first_log_entry= NULL; + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); lock_global_table_log(); do { - build_table_filename(path, sizeof(path), lpt->db, - lpt->table_name, ""); if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, TRUE)) break; if (write_log_changed_partitions(lpt, &next_entry, (const char*)path)) break; - build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, - lpt->table_name, "#"); if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) break; log_entry= part_info->first_log_entry; @@ -5539,8 +5561,8 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) DBUG_RETURN(FALSE); } while (TRUE); release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= old_first_log_entry; unlock_global_table_log(); + part_info->first_log_entry= old_first_log_entry; my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5565,18 +5587,17 @@ write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt) TABLE_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry; DBUG_ENTER("write_log_completed"); + DBUG_ASSERT(log_entry); lock_global_table_log(); - DBUG_ASSERT(part_info->exec_log_entry); - if (write_execute_table_log_entry(0UL, TRUE, &part_info->exec_log_entry)) + if (write_execute_table_log_entry(0UL, TRUE, &log_entry)) { DBUG_RETURN(TRUE); } release_part_info_log_entries(part_info->first_log_entry); - part_info->first_log_entry= NULL; - part_info->exec_log_entry->next_active_log_entry= NULL; release_part_info_log_entries(part_info->exec_log_entry); - part_info->exec_log_entry= NULL; unlock_global_table_log(); + part_info->exec_log_entry= NULL; + part_info->first_log_entry= NULL; DBUG_RETURN(FALSE); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 260d1650f20..285c848938e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -698,7 +698,7 @@ write_execute_table_log_entry(uint first_entry, bool complete, TABLE_LOG_MEMORY_ENTRY **active_entry) { - bool write_header; + bool write_header= FALSE; char *file_entry= (char*)global_table_log.file_entry; DBUG_ENTER("write_execute_table_log_entry"); From 8ae7ef461665ce121aeb13999f33797250875b2b Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 10 Feb 2006 13:33:08 -0500 Subject: [PATCH 25/48] Don't use free'd memory, bad idea Free all memory with mutex and destroy mutex as final step --- sql/sql_table.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 285c848938e..130dd5b9002 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -864,20 +864,22 @@ release_table_log() TABLE_LOG_MEMORY_ENTRY *used_list= global_table_log.first_used; DBUG_ENTER("release_table_log"); - VOID(pthread_mutex_destroy(&LOCK_gtl)); + lock_global_table_log(); while (used_list) { - TABLE_LOG_MEMORY_ENTRY *tmp= used_list; + TABLE_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry; my_free((char*)used_list, MYF(0)); - used_list= tmp->next_log_entry; + used_list= tmp; } while (free_list) { - TABLE_LOG_MEMORY_ENTRY *tmp= free_list; + TABLE_LOG_MEMORY_ENTRY *tmp= free_list->next_log_entry; my_free((char*)free_list, MYF(0)); - free_list= tmp->next_log_entry; + free_list= tmp; } VOID(my_close(global_table_log.file_id, MYF(0))); + unlock_global_table_log(); + VOID(pthread_mutex_destroy(&LOCK_gtl)); DBUG_VOID_RETURN; } From c6d1dee7e3decd33735d593d23f0ff280655f016 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 10 Feb 2006 22:36:01 +0100 Subject: [PATCH 26/48] WL 2826: Error handling of ALTER TABLE for partitioning Make lots of fixes to handle the most complex case of reorganising of partitions where two-phased processes are needed in some cases. sql/ha_partition.cc: Rewrote the rename partitions and drop partitions to align with how the table log handles things. sql/handler.h: Added new entry to partition_element to keep track of log entry for a partition during ALTER TABLE that reorganises existing partitions. sql/mysql_priv.h: Converted 'd', 'e' and so forth to constants with somewhat more descriptive names Added method to inactivate log entries sql/sql_partition.cc: Fix change of partitions sql/sql_table.cc: More constants with somewhat descriptive names Moved around some methods between internal part and external part Added new method to handle inactivation of log entries --- sql/ha_partition.cc | 132 +++++++++++++------------- sql/handler.h | 4 +- sql/mysql_priv.h | 13 +++ sql/sql_partition.cc | 103 +++++++++++++++++++-- sql/sql_table.cc | 214 +++++++++++++++++++++++++++++-------------- 5 files changed, 327 insertions(+), 139 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index fade6803156..22d092b486e 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -577,7 +577,6 @@ int ha_partition::create(const char *name, TABLE *table_arg, int ha_partition::drop_partitions(const char *path) { List_iterator part_it(m_part_info->partitions); - List_iterator temp_it(m_part_info->temp_partitions); char part_name_buff[FN_REFLEN]; uint no_parts= m_part_info->partitions.elements; uint part_count= 0; @@ -585,37 +584,18 @@ int ha_partition::drop_partitions(const char *path) uint i= 0; uint name_variant; int error= 0; - bool reorged_parts= (m_reorged_parts > 0); - bool temp_partitions= (m_part_info->temp_partitions.elements > 0); DBUG_ENTER("ha_partition::drop_partitions"); - if (temp_partitions) - no_parts= m_part_info->temp_partitions.elements; do { - partition_element *part_elem; - if (temp_partitions) - { - /* - We need to remove the reorganised partitions that were put in the - temp_partitions-list. - */ - part_elem= temp_it++; - DBUG_ASSERT(part_elem->part_state == PART_TO_BE_DROPPED); - } - else - part_elem= part_it++; - if (part_elem->part_state == PART_TO_BE_DROPPED || - part_elem->part_state == PART_IS_CHANGED) + partition_element *part_elem= part_it++; + if (part_elem->part_state == PART_TO_BE_DROPPED) { handler *file; /* This part is to be dropped, meaning the part or all its subparts. */ name_variant= NORMAL_PART_NAME; - if (part_elem->part_state == PART_IS_CHANGED || - (part_elem->part_state == PART_TO_BE_DROPPED && temp_partitions)) - name_variant= RENAMED_PART_NAME; if (m_is_sub_partitioned) { List_iterator sub_it(part_elem->subpartitions); @@ -627,10 +607,7 @@ int ha_partition::drop_partitions(const char *path) create_subpartition_name(part_name_buff, path, part_elem->partition_name, sub_elem->partition_name, name_variant); - if (reorged_parts) - file= m_reorged_file[part_count++]; - else - file= m_file[part]; + file= m_file[part]; DBUG_PRINT("info", ("Drop subpartition %s", part_name_buff)); error+= file->delete_table((const char *) part_name_buff); } while (++j < no_subparts); @@ -640,10 +617,7 @@ int ha_partition::drop_partitions(const char *path) create_partition_name(part_name_buff, path, part_elem->partition_name, name_variant, TRUE); - if (reorged_parts) - file= m_reorged_file[part_count++]; - else - file= m_file[i]; + file= m_file[i]; DBUG_PRINT("info", ("Drop partition %s", part_name_buff)); error+= file->delete_table((const char *) part_name_buff); } @@ -695,6 +669,14 @@ int ha_partition::rename_partitions(const char *path) if (temp_partitions) { + /* + These are the reorganised partitions that have already been copied. + We delete the partitions and log the delete by inactivating the + delete log entry in the table log. We only need to synchronise + these writes before moving to the next loop since there is no + interaction among reorganised partitions, they cannot have the + same name. + */ do { part_elem= temp_it++; @@ -705,39 +687,57 @@ int ha_partition::rename_partitions(const char *path) { sub_elem= sub_it++; file= m_reorged_file[part_count++]; - create_subpartition_name(part_name_buff, path, - part_elem->partition_name, - sub_elem->partition_name, - RENAMED_PART_NAME); create_subpartition_name(norm_name_buff, path, part_elem->partition_name, sub_elem->partition_name, NORMAL_PART_NAME); - DBUG_PRINT("info", ("Rename subpartition from %s to %s", - norm_name_buff, part_name_buff)); - error+= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); + if (file->delete_table((const char *) norm_name_buff) || + inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + error= 1; + else + sub_elem->log_entry= NULL; /* Indicate success */ } while (++j < no_subparts); } else { file= m_reorged_file[part_count++]; - create_partition_name(part_name_buff, path, - part_elem->partition_name, RENAMED_PART_NAME, - TRUE); create_partition_name(norm_name_buff, path, part_elem->partition_name, NORMAL_PART_NAME, TRUE); - DBUG_PRINT("info", ("Rename partition from %s to %s", - norm_name_buff, part_name_buff)); - error+= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); + if (file->delete_table((const char *) norm_name_buff) || + inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + error= 1; + else + sub_elem->log_entry= NULL; /* Indicate success */ } } while (++i < temp_partitions); + VOID(sync_table_log()); } i= 0; do { + /* + When state is PART_IS_CHANGED it means that we have created a new + TEMP partition that is to be renamed to normal partition name and + we are to delete the old partition with currently the normal name. + + We perform this operation by + 1) Delete old partition with normal partition name + 2) Signal this in table log entry + 3) Synch table log to ensure we have consistency in crashes + 4) Rename temporary partition name to normal partition name + 5) Signal this to table log entry + It is not necessary to synch the last state since a new rename + should not corrupt things if there was no temporary partition. + + The only other parts we need to cater for are new parts that + replace reorganised parts. The reorganised parts were deleted + by the code above that goes through the temp_partitions list. + Thus the synch above makes it safe to simply perform step 4 and 5 + for those entries. + */ part_elem= part_it++; if (part_elem->part_state == PART_IS_CHANGED || (part_elem->part_state == PART_IS_ADDED && temp_partitions)) @@ -759,14 +759,11 @@ int ha_partition::rename_partitions(const char *path) if (part_elem->part_state == PART_IS_CHANGED) { file= m_reorged_file[part_count++]; - create_subpartition_name(part_name_buff, path, - part_elem->partition_name, - sub_elem->partition_name, - RENAMED_PART_NAME); - DBUG_PRINT("info", ("Rename subpartition from %s to %s", - norm_name_buff, part_name_buff)); - error+= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); + if (file->delete_table((const char *) norm_name_buff) || + inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + error= 1; + VOID(synch_table_log()); } file= m_new_file[part]; create_subpartition_name(part_name_buff, path, @@ -775,8 +772,12 @@ int ha_partition::rename_partitions(const char *path) TEMP_PART_NAME); DBUG_PRINT("info", ("Rename subpartition from %s to %s", part_name_buff, norm_name_buff)); - error+= file->rename_table((const char *) part_name_buff, - (const char *) norm_name_buff); + if (file->rename_table((const char *) norm_name_buff, + (const char *) part_name_buff) || + inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + error= 1; + else + sub_elem->log_entry= NULL; } while (++j < no_subparts); } else @@ -787,13 +788,11 @@ int ha_partition::rename_partitions(const char *path) if (part_elem->part_state == PART_IS_CHANGED) { file= m_reorged_file[part_count++]; - create_partition_name(part_name_buff, path, - part_elem->partition_name, RENAMED_PART_NAME, - TRUE); - DBUG_PRINT("info", ("Rename partition from %s to %s", - norm_name_buff, part_name_buff)); - error+= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); + if (file->delete_table((const char *) norm_name_buff) || + inactivate_table_log_entry(part_elem->log_entry->entry_pos)) + error= 1; + VOID(synch_table_log()); } file= m_new_file[i]; create_partition_name(part_name_buff, path, @@ -801,11 +800,16 @@ int ha_partition::rename_partitions(const char *path) TRUE); DBUG_PRINT("info", ("Rename partition from %s to %s", part_name_buff, norm_name_buff)); - error+= file->rename_table((const char *) part_name_buff, - (const char *) norm_name_buff); + if (file->rename_table((const char *) norm_name_buff, + (const char *) part_name_buff) || + inactivate_table_log_entry(part_elem->log_entry->entry_pos)) + error= 1; + else + part_elem->log_entry= NULL; } } } while (++i < no_parts); + VOID(synch_table_log()); DBUG_RETURN(error); } diff --git a/sql/handler.h b/sql/handler.h index 00bfaa77e91..b54e7ff129b 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -667,6 +667,7 @@ public: ulonglong part_min_rows; char *partition_name; char *tablespace_name; + TABLE_LOG_MEMORY_ENTRY *log_entry; longlong range_value; char* part_comment; char* data_file_name; @@ -677,7 +678,8 @@ public: partition_element() : part_max_rows(0), part_min_rows(0), partition_name(NULL), - tablespace_name(NULL), range_value(0), part_comment(NULL), + tablespace_name(NULL), log_entry(0), + range_value(0), part_comment(NULL), data_file_name(NULL), index_file_name(NULL), engine_type(NULL),part_state(PART_NORMAL), nodegroup_id(UNDEF_NODEGROUP) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index e0875b06a0a..24c789a21e7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1177,6 +1177,8 @@ typedef struct st_table_log_entry uint next_entry; char action_type; char entry_type; + char phase; + char not_used; } TABLE_LOG_ENTRY; typedef struct st_table_log_memory_entry @@ -1187,11 +1189,22 @@ typedef struct st_table_log_memory_entry struct st_table_log_memory_entry *next_active_log_entry; } TABLE_LOG_MEMORY_ENTRY; +#define TLOG_EXECUTE_CODE 'e' +#define TLOG_LOG_ENTRY_CODE 'l' +#define TLOG_IGNORE_LOG_ENTRY_CODE 'i' + +#define TLOG_DELETE_ACTION_CODE 'd' +#define TLOG_RENAME_ACTION_CODE 'r' +#define TLOG_REPLACE_ACTION_CODE 's' + +#define TLOG_HANDLER_TYPE_LEN 32 + bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, TABLE_LOG_MEMORY_ENTRY **active_entry); bool write_execute_table_log_entry(uint first_entry, bool complete, TABLE_LOG_MEMORY_ENTRY **active_entry); +bool inactivate_table_log_entry(uint entry_no); void release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry); void release_table_log(); void execute_table_log_recovery(); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 770d2c4ab39..0e35a386f85 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5135,9 +5135,9 @@ write_log_rename_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, DBUG_ENTER("write_log_rename_frm"); if (rename_flag) - table_log_entry.action_type= 'r'; + table_log_entry.action_type= TLOG_RENAME_ACTION_CODE; else - table_log_entry.action_type= 'd'; + table_log_entry.action_type= TLOG_DELETE_ACTION_CODE; table_log_entry.next_entry= next_entry; table_log_entry.handler_type= "frm"; table_log_entry.name= to_path; @@ -5160,6 +5160,18 @@ write_log_rename_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, RETURN VALUES TRUE Error FALSE Success + DESCRIPTION + This code is used to perform safe ADD PARTITION for HASH partitions + and COALESCE for HASH partitions and REORGANIZE for any type of + partitions. + We prepare entries for all partitions except the reorganised partitions + in REORGANIZE partition, those are handled by + write_log_dropped_partitions. For those partitions that are replaced + special care is needed to ensure that this is performed correctly and + this requires a two-phased approach with this log as a helper for this. + + This code is closely intertwined with the code in rename_partitions in + the partition handler. */ static @@ -5167,7 +5179,84 @@ bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, uint *next_entry, const char *path) { + TABLE_LOG_ENTRY table_log_entry; + partition_info *part_info= lpt->part_info; + TABLE_LOG_MEMORY_ENTRY *log_entry; + char tmp_path[FN_LEN]; + char normal_path[FN_LEN]; + List_iterator part_it(part_info->partitions); + uint temp_partitions= part_info->temp_partitions.elements; + uint no_elements= part_info->partitions.elements; + uint i= 0; DBUG_ENTER("write_log_changed_partitions"); + + do + { + partition_element *part_elem= part_it++; + if (part_elem->part_state == PART_IS_CHANGED || + (part_elem->part_state == PART_IS_ADDED && temp_partitions)) + { + if (is_sub_partitioned(part_info)) + { + List_iterator sub_it(part_elem->subpartitions); + uint no_subparts= part_info->no_subparts; + uint j= 0; + do + { + partition_element *sub_elem= sub_it++; + table_log_entry.next_entry= *next_entry; + table_log_entry.handler_type= + ha_resolve_storage_engine_name(sub_elem->engine_type); + create_subpartition_name(tmp_path, path, + part_elem->partition_name, + sub_elem->partition_name, + TEMP_PART_NAME); + create_subpartition_name(normal_path, path, + part_elem->partition_name, + sub_elem->partition_name, + NORMAL_PART_NAME); + table_log_entry.name= norm_path; + table_log_entry.from_name= tmp_path; + if (part_elem->part_state == PART_IS_CHANGED) + table_log_entry->action_type= TLOG_REPLACE_ACTION_CODE; + else + table_log_entry->action_type= TLOG_RENAME_ACTION_CODE; + if (write_table_log_entry(&table_log_entry, &log_entry)) + { + DBUG_RETURN(TRUE); + } + *next_entry= log_entry->entry_pos; + sub_elem->log_entry= log_entry; + insert_part_info_log_entry_list(part_info, log_entry); + } while (++j < no_subparts); + } + else + { + table_log_entry.next_entry= *next_entry; + table_log_entry.handler_type= + ha_resolve_storage_engine_name(part_elem->engine_type); + create_partition_name(tmp_path, path, + part_elem->partition_name, + TEMP_PART_NAME, TRUE); + create_partition_name(normal_path, path, + part_elem->partition_name, + NORMAL_PART_NAME, TRUE); + table_log_entry.name= normal_path; + table_log_entry.from_name= tmp_path; + if (part_elem->part_state == PART_IS_CHANGED) + table_log_entry->action_type= TLOG_REPLACE_ACTION_CODE; + else + table_log_entry->action_type= TLOG_RENAME_ACTION_CODE; + if (write_table_log_entry(&table_log_entry, &log_entry)) + { + DBUG_RETURN(TRUE); + } + *next_entry= log_entry->entry_pos; + part_elem->table_log_entry= log_entry; + insert_part_info_log_entry_list(part_info, log_entry); + } + } + } while (++i < no_elements) DBUG_RETURN(FALSE); } @@ -5200,7 +5289,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, uint i= 0; DBUG_ENTER("write_log_dropped_partitions"); - table_log_entry.action_type= 'd'; + table_log_entry.action_type= TLOG_DELETE_ACTION_CODE; if (temp_list) no_elements= no_temp_partitions; while (no_elements--) @@ -5242,6 +5331,8 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, DBUG_RETURN(TRUE); } *next_entry= log_entry->entry_pos; + if (temp_list) + sub_elem->table_log_entry= log_entry; insert_part_info_log_entry_list(part_info, log_entry); } while (++j < no_subparts); } @@ -5259,6 +5350,8 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, DBUG_RETURN(TRUE); } *next_entry= log_entry->entry_pos; + if (temp_list) + part_elem->table_log_entry= log_entry; insert_part_info_log_entry_list(part_info, log_entry); } } @@ -5961,10 +6054,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_change_partition_8") || (close_open_tables_and_downgrade(lpt), FALSE) || ERROR_INJECT_CRASH("crash_change_partition_9") || - mysql_drop_partitions(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_10") || write_log_completed(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_11") || + ERROR_INJECT_CRASH("crash_change_partition_10") || (mysql_wait_completed_table(lpt, table), FALSE)) { abort(); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 130dd5b9002..47a5693f374 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -289,28 +289,38 @@ GLOBAL_TABLE_LOG global_table_log; pthread_mutex_t LOCK_gtl; +#define TLOG_ENTRY_TYPE_POS 0 +#define TLOG_ACTION_TYPE_POS 1 +#define TLOG_PHASE_POS 2 +#define TLOG_NEXT_ENTRY_POS 4 + +#define TLOG_NO_ENTRY_POS 0 +#define TLOG_NAME_LEN_POS 4 +#define TLOG_HANDLER_TYPE_POS 8 +#define TLOG_IO_SIZE_POS 12 /* - Sync table log file + Read one entry from table log file SYNOPSIS - sync_table_log() + read_table_log_file_entry() + entry_no Entry number to read RETURN VALUES - TRUE Error - FALSE Success + TRUE Error + FALSE Success */ static bool -sync_table_log() +read_table_log_file_entry(uint entry_no) { bool error= FALSE; - DBUG_ENTER("sync_table_log"); + File file_id= global_table_log.file_id; + char *file_entry= (char*)global_table_log.file_entry; + uint io_size= global_table_log.io_size; + DBUG_ENTER("read_table_log_file_entry"); - if (my_sync(global_table_log.file_id, MYF(0))) - { - /* Write to error log */ + if (my_pread(file_id, file_entry, io_size, io_size * entry_no, MYF(0))) error= TRUE; - } DBUG_RETURN(error); } @@ -358,13 +368,17 @@ write_table_log_header() bool error= FALSE; DBUG_ENTER("write_table_log_header"); - int4store(&global_table_log.file_entry[0], global_table_log.no_entries); + int4store(&global_table_log.file_entry[TLOG_NO_ENTRY_POS], + global_table_log.no_entries); const_var= FN_LEN; - int2store(&global_table_log.file_entry[4], const_var); - const_var= 32; - int2store(&global_table_log.file_entry[6], const_var); + int4store(&global_table_log.file_entry[TLOG_NAME_LEN_POS], + const_var); + const_var= TLOG_HANDLER_TYPE_LEN; + int4store(&global_table_log.file_entry[TLOG_HANDLER_TYPE_POS], + const_var); const_var= IO_SIZE; - int4store(&global_table_log.file_entry[8], const_var); + int4store(&global_table_log.file_entry[TLOG_IO_SIZE_POS], + const_var); if (write_table_log_file_entry(0UL)) error= TRUE; if (!error) @@ -373,32 +387,6 @@ write_table_log_header() } -/* - Read one entry from table log file - SYNOPSIS - read_table_log_file_entry() - entry_no Entry number to read - RETURN VALUES - TRUE Error - FALSE Success -*/ - -static -bool -read_table_log_file_entry(uint entry_no) -{ - bool error= FALSE; - File file_id= global_table_log.file_id; - char *file_entry= (char*)global_table_log.file_entry; - uint io_size= global_table_log.io_size; - DBUG_ENTER("read_table_log_file_entry"); - - if (my_pread(file_id, file_entry, io_size, io_size * entry_no, MYF(0))) - error= TRUE; - DBUG_RETURN(error); -} - - /* Create table log file name SYNOPSIS @@ -450,11 +438,12 @@ read_table_log_header() else successful_open= TRUE; } - entry_no= uint4korr(&file_entry[0]); - global_table_log.name_len= uint2korr(&file_entry[4]); - global_table_log.handler_type_len= uint2korr(&file_entry[6]); + entry_no= uint4korr(&file_entry[TLOG_NO_ENTRY_POS]); + global_table_log.name_len= uint4korr(&file_entry[TLOG_NAME_LEN_POS]); + global_table_log.handler_type_len= + uint4korr(&file_entry[TLOG_HANDLER_TYPE_POS]); if (successful_open) - global_table_log.io_size= uint4korr(&file_entry[8]); + global_table_log.io_size= uint4korr(&file_entry[TLOG_IO_SIZE_POS]); global_table_log.first_free= NULL; global_table_log.first_used= NULL; global_table_log.no_entries= 0; @@ -488,11 +477,12 @@ read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) /* Error handling */ DBUG_RETURN(TRUE); } - table_log_entry->entry_type= file_entry[0]; - table_log_entry->action_type= file_entry[1]; - table_log_entry->next_entry= uint4korr(&file_entry[2]); - table_log_entry->name= &file_entry[6]; - inx= 6 + global_table_log.name_len; + table_log_entry->entry_type= file_entry[TLOG_ENTRY_TYPE_POS]; + table_log_entry->action_type= file_entry[TLOG_ACTION_TYPE_POS]; + table_log_entry->phase= file_entry[TLOG_PHASE_POS]; + table_log_entry->next_entry= uint4korr(&file_entry[TLOG_NEXT_ENTRY_POS]); + table_log_entry->name= &file_entry[TLOG_NAME_POS]; + inx= TLOG_NAME_POS + global_table_log.name_len; table_log_entry->from_name= &file_entry[inx]; inx+= global_table_log.name_len; table_log_entry->handler_type= &file_entry[inx]; @@ -637,23 +627,27 @@ write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, bool error, write_header; DBUG_ENTER("write_table_log_entry"); - global_table_log.file_entry[0]= 'i'; - global_table_log.file_entry[1]= table_log_entry->action_type; - int4store(&global_table_log.file_entry[2], + global_table_log.file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_LOG_ENTRY_CODE; + global_table_log.file_entry[TLOG_ACTION_TYPE_POS]= + table_log_entry->action_type; + global_table_log.file_entry[TLOG_PHASE_POS]= 0; + int4store(&global_table_log.file_entry[TLOG_NEXT_ENTRY_POS], table_log_entry->next_entry); DBUG_ASSERT(strlen(table_log_entry->name) < FN_LEN); - strncpy(&global_table_log.file_entry[6], table_log_entry->name, FN_LEN); - if (table_log_entry->action_type == 'r') + strncpy(&global_table_log.file_entry[TLOG_NAME_POS], + table_log_entry->name, FN_LEN); + if (table_log_entry->action_type == TLOG_RENAME_ACTION_CODE || + table_log_entry->action_type == TLOG_REPLACE_ACTION_CODE) { DBUG_ASSERT(strlen(table_log_entry->from_name) < FN_LEN); - strncpy(&global_table_log.file_entry[6 + FN_LEN], + strncpy(&global_table_log.file_entry[TLOG_NAME_POS + FN_LEN], table_log_entry->from_name, FN_LEN); } else - global_table_log.file_entry[6 + FN_LEN]= 0; + global_table_log.file_entry[TLOG_NAME_POS + FN_LEN]= 0; DBUG_ASSERT(strlen(table_log_entry->handler_type) < FN_LEN); - strncpy(&global_table_log.file_entry[6 + (2*FN_LEN)], - table_log_entry->handler_type, FN_LEN); + strncpy(&global_table_log.file_entry[TLOG_NAME_POS + (2*FN_LEN)], + table_log_entry->handler_type, FN_LEN); if (get_free_table_log_entry(active_entry, &write_header)) { DBUG_RETURN(TRUE); @@ -705,15 +699,16 @@ write_execute_table_log_entry(uint first_entry, if (!complete) { VOID(sync_table_log()); - file_entry[0]= 'e'; + file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_EXECUTE_CODE; } else - file_entry[0]= 'i'; - file_entry[1]= 0; /* Ignored for execute entries */ - int4store(&file_entry[2], first_entry); - file_entry[6]= 0; - file_entry[6 + FN_LEN]= 0; - file_entry[6 + 2*FN_LEN]= 0; + file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_IGNORE_LOG_ENTRY_CODE; + file_entry[TLOG_ACTION_TYPE_POS]= 0; /* Ignored for execute entries */ + file_entry[TLOG_PHASE_POS]= 0; + int4store(&file_entry[TLOG_NEXT_ENTRY_POS], first_entry); + file_entry[TLOG_NAME_POS]= 0; + file_entry[TLOG_NAME_POS + FN_LEN]= 0; + file_entry[TLOG_NAME_POS + 2*FN_LEN]= 0; if (!(*active_entry)) { if (get_free_table_log_entry(active_entry, &write_header)) @@ -739,6 +734,88 @@ write_execute_table_log_entry(uint first_entry, } +/* + For complex rename operations we need to inactivate individual entries. + SYNOPSIS + inactivate_table_log_entry() + entry_no Entry position of record to change + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + During replace operations where we start with an existing table called + t1 and a replacement table called t1#temp or something else and where + we want to delete t1 and rename t1#temp to t1 this is not possible to + do in a safe manner unless the table log is informed of the phases in + the change. + + Delete actions are 1-phase actions that can be ignored immediately after + being executed. + Rename actions from x to y is also a 1-phase action since there is no + interaction with any other handlers named x and y. + Replace action where drop y and x -> y happens needs to be a two-phase + action. Thus the first phase will drop y and the second phase will + rename x -> y. +*/ + +bool +inactivate_table_log_entry(uint entry_no) +{ + bool error= TRUE; + const char *file_entry= (const char*)global_table_log.file_entry + DBUG_ENTER("inactivate_table_log_entry"); + + if (!read_table_log_file_entry(entry_no)) + { + if (file_entry[TLOG_ENTRY_POS] == TLOG_LOG_ENTRY_CODE) + { + if (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_DELETE_ACTION_CODE || + file_entry[TLOG_ACTION_TYPE_POS] == TLOG_RENAME_ACTION_CODE || + (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_REPLACE_ACTION_CODE && + file_entry[TLOG_PHASE_POS] == 1)) + file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_IGNORE_LOG_ENTRY_POS; + else if (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_REPLACE_ACTION_CODE) + { + DBUG_ASSERT(file_entry[TLOG_PHASE_POS] == 0); + file_entry[TLOG_PHASE_POS]= 1; + } + else + { + DBUG_ASSERT(0); + } + if (!write_table_log_file_entry(entry_no)) + error= FALSE; + } + } + DBUG_RETURN(error); +} + + +/* + Sync table log file + SYNOPSIS + sync_table_log() + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static +bool +sync_table_log() +{ + bool error= FALSE; + DBUG_ENTER("sync_table_log"); + + if (my_sync(global_table_log.file_id, MYF(0))) + { + /* Write to error log */ + error= TRUE; + } + DBUG_RETURN(error); +} + + /* Release a log memory entry SYNOPSIS @@ -795,7 +872,8 @@ execute_table_log_entry(uint first_entry) /* Write to error log and continue with next log entry */ break; } - DBUG_ASSERT(table_log_entry.entry_type == 'i'); + DBUG_ASSERT(table_log_entry.entry_type == TLOG_LOG_ENTRY_CODE || + table_log_entry.entry_type == TLOG_IGNORE_LOG_ENTRY_CODE); if (execute_table_log_action(&table_log_entry)) { DBUG_ASSERT(0); @@ -831,7 +909,7 @@ execute_table_log_recovery() /* Write to error log */ break; } - if (table_log_entry.entry_type == 'e') + if (table_log_entry.entry_type == TLOG_EXECUTE_CODE) { if (execute_table_log_entry(table_log_entry.next_entry)) { From b517dbf7183a16101b901f29f0a0d9acfac177ce Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 11 Feb 2006 00:41:52 -0500 Subject: [PATCH 27/48] Compile fixes --- sql/ha_partition.cc | 15 ++++++++------- sql/handler.h | 4 ++-- sql/mysql_priv.h | 1 + sql/sql_partition.cc | 18 +++++++++--------- sql/sql_table.cc | 8 ++++---- 5 files changed, 24 insertions(+), 22 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 22d092b486e..af6ce9cd1e0 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -101,7 +101,9 @@ handlerton partition_hton = { partition_flags, /* Partition flags */ alter_table_flags, /* Partition flags */ NULL, /* Alter Tablespace */ - HTON_NOT_USER_SELECTABLE | HTON_HIDDEN + HTON_NOT_USER_SELECTABLE | HTON_HIDDEN, + NULL, /* binlog function */ + NULL /* binlog query */ }; /* @@ -495,10 +497,9 @@ int ha_partition::create_handler_files(const char *path, { char name[FN_REFLEN]; char old_name[FN_REFLEN]; - char *par_str= ".par"; - strxmov(name, path, par_str, NullS); - strxmov(old_name, old_path, par_str, NullS); + strxmov(name, path, ha_par_ext, NullS); + strxmov(old_name, old_path, ha_par_ext, NullS); if (my_delete(name, MYF(MY_WME)) || my_rename(old_name, name, MYF(MY_WME))) { @@ -763,7 +764,7 @@ int ha_partition::rename_partitions(const char *path) if (file->delete_table((const char *) norm_name_buff) || inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) error= 1; - VOID(synch_table_log()); + VOID(sync_table_log()); } file= m_new_file[part]; create_subpartition_name(part_name_buff, path, @@ -792,7 +793,7 @@ int ha_partition::rename_partitions(const char *path) if (file->delete_table((const char *) norm_name_buff) || inactivate_table_log_entry(part_elem->log_entry->entry_pos)) error= 1; - VOID(synch_table_log()); + VOID(sync_table_log()); } file= m_new_file[i]; create_partition_name(part_name_buff, path, @@ -809,7 +810,7 @@ int ha_partition::rename_partitions(const char *path) } } } while (++i < no_parts); - VOID(synch_table_log()); + VOID(sync_table_log()); DBUG_RETURN(error); } diff --git a/sql/handler.h b/sql/handler.h index b54e7ff129b..543da947ebf 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -658,6 +658,7 @@ typedef struct { #define UNDEF_NODEGROUP 65535 class Item; +struct st_table_log_memory_entry; class partition_element :public Sql_alloc { public: @@ -667,7 +668,7 @@ public: ulonglong part_min_rows; char *partition_name; char *tablespace_name; - TABLE_LOG_MEMORY_ENTRY *log_entry; + st_table_log_memory_entry *log_entry; longlong range_value; char* part_comment; char* data_file_name; @@ -801,7 +802,6 @@ typedef int (*get_partitions_in_range_iter)(partition_info *part_info, PARTITION_ITERATOR *part_iter); -struct st_table_log_memory_entry; class partition_info : public Sql_alloc { diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 24c789a21e7..bcff8d65483 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1206,6 +1206,7 @@ bool write_execute_table_log_entry(uint first_entry, TABLE_LOG_MEMORY_ENTRY **active_entry); bool inactivate_table_log_entry(uint entry_no); void release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry); +bool sync_table_log(); void release_table_log(); void execute_table_log_recovery(); bool execute_table_log_entry(uint first_entry); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 0e35a386f85..809bd0fcfce 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5215,12 +5215,12 @@ write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, part_elem->partition_name, sub_elem->partition_name, NORMAL_PART_NAME); - table_log_entry.name= norm_path; + table_log_entry.name= normal_path; table_log_entry.from_name= tmp_path; if (part_elem->part_state == PART_IS_CHANGED) - table_log_entry->action_type= TLOG_REPLACE_ACTION_CODE; + table_log_entry.action_type= TLOG_REPLACE_ACTION_CODE; else - table_log_entry->action_type= TLOG_RENAME_ACTION_CODE; + table_log_entry.action_type= TLOG_RENAME_ACTION_CODE; if (write_table_log_entry(&table_log_entry, &log_entry)) { DBUG_RETURN(TRUE); @@ -5244,19 +5244,19 @@ write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, table_log_entry.name= normal_path; table_log_entry.from_name= tmp_path; if (part_elem->part_state == PART_IS_CHANGED) - table_log_entry->action_type= TLOG_REPLACE_ACTION_CODE; + table_log_entry.action_type= TLOG_REPLACE_ACTION_CODE; else - table_log_entry->action_type= TLOG_RENAME_ACTION_CODE; + table_log_entry.action_type= TLOG_RENAME_ACTION_CODE; if (write_table_log_entry(&table_log_entry, &log_entry)) { DBUG_RETURN(TRUE); } *next_entry= log_entry->entry_pos; - part_elem->table_log_entry= log_entry; + part_elem->log_entry= log_entry; insert_part_info_log_entry_list(part_info, log_entry); } } - } while (++i < no_elements) + } while (++i < no_elements); DBUG_RETURN(FALSE); } @@ -5332,7 +5332,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, } *next_entry= log_entry->entry_pos; if (temp_list) - sub_elem->table_log_entry= log_entry; + sub_elem->log_entry= log_entry; insert_part_info_log_entry_list(part_info, log_entry); } while (++j < no_subparts); } @@ -5351,7 +5351,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, } *next_entry= log_entry->entry_pos; if (temp_list) - part_elem->table_log_entry= log_entry; + part_elem->log_entry= log_entry; insert_part_info_log_entry_list(part_info, log_entry); } } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 47a5693f374..a5ef2a90b5d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -293,6 +293,7 @@ pthread_mutex_t LOCK_gtl; #define TLOG_ACTION_TYPE_POS 1 #define TLOG_PHASE_POS 2 #define TLOG_NEXT_ENTRY_POS 4 +#define TLOG_NAME_POS 8 #define TLOG_NO_ENTRY_POS 0 #define TLOG_NAME_LEN_POS 4 @@ -762,18 +763,18 @@ bool inactivate_table_log_entry(uint entry_no) { bool error= TRUE; - const char *file_entry= (const char*)global_table_log.file_entry + char *file_entry= (char*)global_table_log.file_entry; DBUG_ENTER("inactivate_table_log_entry"); if (!read_table_log_file_entry(entry_no)) { - if (file_entry[TLOG_ENTRY_POS] == TLOG_LOG_ENTRY_CODE) + if (file_entry[TLOG_ENTRY_TYPE_POS] == TLOG_LOG_ENTRY_CODE) { if (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_DELETE_ACTION_CODE || file_entry[TLOG_ACTION_TYPE_POS] == TLOG_RENAME_ACTION_CODE || (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_REPLACE_ACTION_CODE && file_entry[TLOG_PHASE_POS] == 1)) - file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_IGNORE_LOG_ENTRY_POS; + file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_IGNORE_LOG_ENTRY_CODE; else if (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_REPLACE_ACTION_CODE) { DBUG_ASSERT(file_entry[TLOG_PHASE_POS] == 0); @@ -800,7 +801,6 @@ inactivate_table_log_entry(uint entry_no) FALSE Success */ -static bool sync_table_log() { From 5d5eba2d3378f880331d439e4f3837b17f5f21e9 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 13 Feb 2006 13:52:23 +0100 Subject: [PATCH 28/48] WL 2826: Error handling of ALTER TABLE for partitioning Introduce log entry to handle replace of frm file sql/handler.h: Introduce log entry to handle replace of frm file sql/sql_partition.cc: Introduce log entry to handle replace of frm file sql/sql_table.cc: Introduce log entry to handle replace of frm file --- sql/handler.h | 3 ++- sql/sql_partition.cc | 22 ++++++++++++++-------- sql/sql_table.cc | 5 +++++ 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/sql/handler.h b/sql/handler.h index 543da947ebf..6df6b48b83a 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -852,6 +852,7 @@ public: st_table_log_memory_entry *first_log_entry; st_table_log_memory_entry *exec_log_entry; + st_table_log_memory_entry *frm_log_entry; /* A bitmap of partitions used by the current query. Usage pattern: @@ -963,7 +964,7 @@ public: part_field_array(NULL), subpart_field_array(NULL), full_part_field_array(NULL), part_expr(NULL), subpart_expr(NULL), item_free_list(NULL), - first_log_entry(NULL), exec_log_entry(NULL), + first_log_entry(NULL), exec_log_entry(NULL), frm_log_entry(NULL), list_array(NULL), part_info_string(NULL), part_func_string(NULL), subpart_func_string(NULL), diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 809bd0fcfce..6985adbac1a 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5109,7 +5109,7 @@ release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) /* Log an delete/rename frm file SYNOPSIS - write_log_rename_delete_frm() + write_log_replace_delete_frm() lpt Struct for parameters next_entry Next reference to use in log record path Name to rename from @@ -5118,30 +5118,30 @@ release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) TRUE Error FALSE Success DESCRIPTION - Support routine that writes a rename or delete of an frm file into the + Support routine that writes a replace or delete of an frm file into the table log. It also inserts an entry that keeps track of used space into the partition info object */ bool -write_log_rename_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, +write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint next_entry, const char *from_path, const char *to_path, - bool rename_flag) + bool replace_flag) { TABLE_LOG_ENTRY table_log_entry; TABLE_LOG_MEMORY_ENTRY *log_entry; - DBUG_ENTER("write_log_rename_frm"); + DBUG_ENTER("write_log_replace_frm"); - if (rename_flag) - table_log_entry.action_type= TLOG_RENAME_ACTION_CODE; + if (replace_flag) + table_log_entry.action_type= TLOG_REPLACE_ACTION_CODE; else table_log_entry.action_type= TLOG_DELETE_ACTION_CODE; table_log_entry.next_entry= next_entry; table_log_entry.handler_type= "frm"; table_log_entry.name= to_path; - if (rename_flag) + if (replace_flag) table_log_entry.from_name= from_path; if (write_table_log_entry(&table_log_entry, &log_entry)) { @@ -5468,6 +5468,7 @@ write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) break; log_entry= part_info->first_log_entry; + part_info->frm_log_entry= log_entry; if (write_execute_table_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) break; @@ -5478,6 +5479,7 @@ write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) release_part_info_log_entries(part_info->first_log_entry); unlock_global_table_log(); part_info->first_log_entry= old_first_log_entry; + part_info->frm_log_entry= NULL; my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5527,6 +5529,7 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) (const char*)tmp_path, TRUE)) break; log_entry= part_info->first_log_entry; + part_info->frm_log_entry= log_entry; if (write_execute_table_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) break; @@ -5537,6 +5540,7 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) release_part_info_log_entries(part_info->first_log_entry); unlock_global_table_log(); part_info->first_log_entry= old_first_log_entry; + part_info->frm_log_entry= NULL; my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5646,6 +5650,7 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) break; log_entry= part_info->first_log_entry; + part_info->frm_log_entry= log_entry; if (write_execute_table_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) break; @@ -5656,6 +5661,7 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) release_part_info_log_entries(part_info->first_log_entry); unlock_global_table_log(); part_info->first_log_entry= old_first_log_entry; + part_info->frm_log_entry= NULL; my_error(ER_TABLE_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index a5ef2a90b5d..593ba5c35e4 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1136,12 +1136,17 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) */ VOID(pthread_mutex_lock(&LOCK_open)); if (my_delete(frm_name, MYF(MY_WME)) || + inactivate_table_log_entry(part_info->frm_log_entry->entry_pos) || + sync_table_log() || my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || lpt->table->file->create_handler_files(path, shadow_path, TRUE)) { error= 1; } VOID(pthread_mutex_unlock(&LOCK_open)); + inactivate_table_log_entry(part_info->frm_log_entry->entry_pos); + part_info->frm_log_entry= NULL; + VOID(sync_table_log()); } end: From 897dd4794d18ccd77926baa224d0b99c5f441dd5 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 14 Feb 2006 11:08:58 +0100 Subject: [PATCH 29/48] WL 2826: Error handling of ALTER TABLE for partitioning Added action code for recovery sql/mysql_priv.h: Added entry in table log struct sql/sql_partition.cc: Some renames to replace sql/sql_table.cc: Added action code for recovery --- sql/mysql_priv.h | 1 + sql/sql_partition.cc | 12 +++--- sql/sql_table.cc | 99 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 104 insertions(+), 8 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index bcff8d65483..4a67ab650d9 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1175,6 +1175,7 @@ typedef struct st_table_log_entry const char *from_name; const char *handler_type; uint next_entry; + uint entry_pos; char action_type; char entry_type; char phase; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 6985adbac1a..56e64537fdf 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5132,7 +5132,7 @@ write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, { TABLE_LOG_ENTRY table_log_entry; TABLE_LOG_MEMORY_ENTRY *log_entry; - DBUG_ENTER("write_log_replace_frm"); + DBUG_ENTER("write_log_replace_delete_frm"); if (replace_flag) table_log_entry.action_type= TLOG_REPLACE_ACTION_CODE; @@ -5412,7 +5412,7 @@ write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) lock_global_table_log(); do { - if (write_log_rename_delete_frm(lpt, 0UL, NULL, + if (write_log_replace_delete_frm(lpt, 0UL, NULL, (const char*)shadow_path, FALSE)) break; log_entry= part_info->first_log_entry; @@ -5465,7 +5465,7 @@ write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) lock_global_table_log(); do { - if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) + if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) break; log_entry= part_info->first_log_entry; part_info->frm_log_entry= log_entry; @@ -5525,7 +5525,7 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, FALSE)) break; - if (write_log_rename_delete_frm(lpt, next_entry, (const char*)path, + if (write_log_replace_delete_frm(lpt, next_entry, (const char*)path, (const char*)tmp_path, TRUE)) break; log_entry= part_info->first_log_entry; @@ -5585,7 +5585,7 @@ write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, FALSE)) break; - if (write_log_rename_delete_frm(lpt, next_entry, NULL, tmp_path, + if (write_log_replace_delete_frm(lpt, next_entry, NULL, tmp_path, FALSE)) break; log_entry= part_info->first_log_entry; @@ -5647,7 +5647,7 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) break; if (write_log_changed_partitions(lpt, &next_entry, (const char*)path)) break; - if (write_log_rename_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) + if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) break; log_entry= part_info->first_log_entry; part_info->frm_log_entry= log_entry; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 593ba5c35e4..b2bd7494709 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -478,6 +478,7 @@ read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) /* Error handling */ DBUG_RETURN(TRUE); } + table_log_entry->entry_pos= read_entry; table_log_entry->entry_type= file_entry[TLOG_ENTRY_TYPE_POS]; table_log_entry->action_type= file_entry[TLOG_ACTION_TYPE_POS]; table_log_entry->phase= file_entry[TLOG_PHASE_POS]; @@ -544,8 +545,97 @@ static bool execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) { + bool frm_action= FALSE; + LEX_STRING handler_name; + handler *file; + MEMROOT mem_root; + bool= error= TRUE; + char path[FN_REFLEN]; + char from_path[FN_REFLEN]; + char *par_ext= ".par"; DBUG_ENTER("execute_table_log_action"); - DBUG_RETURN(FALSE); + + if (table_log_entry->entry_type == TLOG_IGNORE_LOG_ENTRY_CODE) + { + DBUG_RETURN(FALSE); + } + handler_name.str= table_log_entry->handler_type; + handler_name.length= strlen(table_log_entry->handler_type); + hton= ha_resolve_by_name(current_thd, handler_name); + if (!hton) + { + DBUG_RETURN(TRUE); + } + init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); + if (strcmp("frm", table_log_entry->handler_type)) + frm_action= TRUE; + else + { + file= get_new_handler(table_share, &mem_root, hton); + if (!file) + goto error; + } + switch (table_log_entry->action_type) + case TLOG_ACTION_DELETE_CODE: + case TLOG_ACTION_REPLACE_CODE: + if (table_log_entry->action_type == TLOG_ACTION_DELETE_CODE || + (table_log_entry->action_type == TLOG_ACTION_REPLACE_CODE && + table_log_entry->phase == 0UL)) + { + if (frm_action) + { + strxmov(path, table_log_entry->name, reg_ext, NullS); + VOID(my_delete(path, MYF(0))); + strxmov(path, table_log_entry->name, par_ext, NullS); + VOID(my_delete(path, MYF(0))); + } + else + { + if (file->delete_table(table_name)) + break; + } + if ((!inactivate_table_log_entry(table_log_entry->entry_pos)) && + (!sync_table_log())) + ; + else + error= FALSE; + break; + } + if (table_log_entry->action_type == TLOG_ACTION_DELETE_CODE) + break; + case TLOG_ACTION_RENAME_CODE: + error= TRUE; + if (frm_action) + { + strxmov(path, table_log_entry->name, reg_ext, NullS); + strxmov(from_path, table_log_entry->from_name, reg_ext, NullS); + if (my_rename(path, from_path, MYF(0))) + break; + strxmov(path, table_log_entry->name, par_ext, NullS); + strxmov(from_path, table_log_entry->from_name, par_ext, NullS); + if (my_rename(path, from_path, MYF(0))) + break; + } + else + { + if (file->rename_table(table_log_entry->name, + table_log_entry->from_name)) + break; + if ((!inactivate_table_log_entry(table_log_entry->entry_pos)) && + (!sync_table_log())) + ; + else + error= FALSE; + } + break; + default: + DBUG_ASSERT(0); + break; + } + delete file; +error: + free_root(&mem_root, MYF(0)); + DBUG_RETURN(error); } @@ -864,6 +954,7 @@ execute_table_log_entry(uint first_entry) uint read_entry= first_entry; DBUG_ENTER("execute_table_log_entry"); + lock_global_table_log(); do { if (read_table_log_entry(read_entry, &table_log_entry)) @@ -874,7 +965,8 @@ execute_table_log_entry(uint first_entry) } DBUG_ASSERT(table_log_entry.entry_type == TLOG_LOG_ENTRY_CODE || table_log_entry.entry_type == TLOG_IGNORE_LOG_ENTRY_CODE); - if (execute_table_log_action(&table_log_entry)) + + if (execute_table_log_action(file, &table_log_entry)) { DBUG_ASSERT(0); /* Write to error log and continue with next log entry */ @@ -882,9 +974,11 @@ execute_table_log_entry(uint first_entry) } read_entry= table_log_entry.next_entry; } while (read_entry); + unlock_global_table_log(); DBUG_RETURN(FALSE); } + /* Execute the table log at recovery of MySQL Server SYNOPSIS @@ -922,6 +1016,7 @@ execute_table_log_recovery() } } } + release_handler_objects(); VOID(init_table_log()); DBUG_VOID_RETURN; } From 5cecd1734e8736a7d29b193b6a6649d10cf9b764 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 14 Feb 2006 14:22:21 +0100 Subject: [PATCH 30/48] WL 2826: Error handling of ALTER TABLE for partitioning First step for handling errors in ALTER TABLE for partitioning sql/ha_partition.cc: First step for handling errors in ALTER TABLE for partitioning sql/sql_partition.cc: First step for handling errors in ALTER TABLE for partitioning sql/sql_table.cc: First step for handling errors in ALTER TABLE for partitioning --- sql/ha_partition.cc | 42 ++++++++++++++++++++++-------------- sql/sql_partition.cc | 51 ++++++++++++++++++++++++++++++++++++++------ sql/sql_table.cc | 44 ++++++++++++++++++++++++-------------- 3 files changed, 98 insertions(+), 39 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index af6ce9cd1e0..d65203e1b34 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -584,6 +584,7 @@ int ha_partition::drop_partitions(const char *path) uint no_subparts= m_part_info->no_subparts; uint i= 0; uint name_variant; + int ret_error; int error= 0; DBUG_ENTER("ha_partition::drop_partitions"); @@ -610,7 +611,8 @@ int ha_partition::drop_partitions(const char *path) sub_elem->partition_name, name_variant); file= m_file[part]; DBUG_PRINT("info", ("Drop subpartition %s", part_name_buff)); - error+= file->delete_table((const char *) part_name_buff); + if ((ret_error= file->delete_table((const char *) part_name_buff))) + error= ret_error; } while (++j < no_subparts); } else @@ -620,7 +622,8 @@ int ha_partition::drop_partitions(const char *path) TRUE); file= m_file[i]; DBUG_PRINT("info", ("Drop partition %s", part_name_buff)); - error+= file->delete_table((const char *) part_name_buff); + if ((ret_error= file->delete_table((const char *) part_name_buff))) + error= ret_error; } if (part_elem->part_state == PART_IS_CHANGED) part_elem->part_state= PART_NORMAL; @@ -663,6 +666,7 @@ int ha_partition::rename_partitions(const char *path) uint i= 0; uint j= 0; int error= 0; + int ret_error; uint temp_partitions= m_part_info->temp_partitions.elements; handler *file; partition_element *part_elem, *sub_elem; @@ -693,8 +697,9 @@ int ha_partition::rename_partitions(const char *path) sub_elem->partition_name, NORMAL_PART_NAME); DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); - if (file->delete_table((const char *) norm_name_buff) || - inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + if ((ret_error= file->delete_table((const char *) norm_name_buff))) + error= ret_error; + else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) error= 1; else sub_elem->log_entry= NULL; /* Indicate success */ @@ -707,8 +712,9 @@ int ha_partition::rename_partitions(const char *path) part_elem->partition_name, NORMAL_PART_NAME, TRUE); DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); - if (file->delete_table((const char *) norm_name_buff) || - inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + if ((ret_error= file->delete_table((const char *) norm_name_buff))) + error= ret_error; + else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) error= 1; else sub_elem->log_entry= NULL; /* Indicate success */ @@ -761,8 +767,9 @@ int ha_partition::rename_partitions(const char *path) { file= m_reorged_file[part_count++]; DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); - if (file->delete_table((const char *) norm_name_buff) || - inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + if ((ret_error= file->delete_table((const char *) norm_name_buff))) + error= ret_error; + else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) error= 1; VOID(sync_table_log()); } @@ -773,9 +780,10 @@ int ha_partition::rename_partitions(const char *path) TEMP_PART_NAME); DBUG_PRINT("info", ("Rename subpartition from %s to %s", part_name_buff, norm_name_buff)); - if (file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff) || - inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + if ((ret_error= file->rename_table((const char *) norm_name_buff, + (const char *) part_name_buff))) + error= ret_error; + else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) error= 1; else sub_elem->log_entry= NULL; @@ -790,8 +798,9 @@ int ha_partition::rename_partitions(const char *path) { file= m_reorged_file[part_count++]; DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); - if (file->delete_table((const char *) norm_name_buff) || - inactivate_table_log_entry(part_elem->log_entry->entry_pos)) + if ((ret_error= file->delete_table((const char *) norm_name_buff))) + error= ret_error; + else if (inactivate_table_log_entry(part_elem->log_entry->entry_pos)) error= 1; VOID(sync_table_log()); } @@ -801,9 +810,10 @@ int ha_partition::rename_partitions(const char *path) TRUE); DBUG_PRINT("info", ("Rename partition from %s to %s", part_name_buff, norm_name_buff)); - if (file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff) || - inactivate_table_log_entry(part_elem->log_entry->entry_pos)) + if ((ret_error= file->rename_table((const char *) norm_name_buff, + (const char *) part_name_buff))) + error= ret_error; + else if (inactivate_table_log_entry(part_elem->log_entry->entry_pos)) error= 1; else part_elem->log_entry= NULL; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 56e64537fdf..6a34fcaadde 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4975,14 +4975,17 @@ the generated partition syntax in a correct manner. static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) { char path[FN_REFLEN+1]; + int error; + handler *file= lpt->table->file; DBUG_ENTER("mysql_change_partitions"); build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); - DBUG_RETURN(lpt->table->file->change_partitions(lpt->create_info, path, - &lpt->copied, - &lpt->deleted, - lpt->pack_frm_data, - lpt->pack_frm_len)); + DBUG_RETURN(file->change_partitions(lpt->create_info, + path, + &lpt->copied, + &lpt->deleted, + lpt->pack_frm_data, + lpt->pack_frm_len)); } @@ -5008,10 +5011,17 @@ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) static bool mysql_rename_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) { char path[FN_REFLEN+1]; + int error; DBUG_ENTER("mysql_rename_partitions"); build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); - DBUG_RETURN(lpt->table->file->rename_partitions(path)); + if ((error= lpt->table->file->rename_partitions(path))) + { + if (error != 1) + lpt->table->file->print_error(error, MYF(0)); + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); } @@ -5042,11 +5052,13 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) List_iterator part_it(part_info->partitions); uint i= 0; uint remove_count= 0; + int error; DBUG_ENTER("mysql_drop_partitions"); build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); - if (lpt->table->file->drop_partitions(path)) + if ((error= lpt->table->file->drop_partitions(path))) { + lpt->table->file->print_error(error, MYF(0)); DBUG_RETURN(TRUE); } do @@ -5920,6 +5932,31 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, abort(); if (!not_completed) abort(); + if (!part_info->first_log_entry && + execute_table_log_entry(part_info->first_log_entry)) + { + /* + We couldn't recover from error + */ + } + else + { + if (not_completed) + { + /* + We hit an error before things were completed but managed + to recover from the error. + */ + } + else + { + /* + We hit an error after we had completed most of the operation + and were successful in a second attempt so the operation + actually is successful now. + */ + } + } fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b2bd7494709..8391a976679 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -320,7 +320,8 @@ read_table_log_file_entry(uint entry_no) uint io_size= global_table_log.io_size; DBUG_ENTER("read_table_log_file_entry"); - if (my_pread(file_id, file_entry, io_size, io_size * entry_no, MYF(0))) + if (my_pread(file_id, file_entry, io_size, io_size * entry_no, + MYF(MY_WME))) error= TRUE; DBUG_RETURN(error); } @@ -346,7 +347,7 @@ write_table_log_file_entry(uint entry_no) DBUG_ENTER("write_table_log_file_entry"); if (my_pwrite(file_id, file_entry, - IO_SIZE, IO_SIZE * entry_no, MYF(0)) != IO_SIZE) + IO_SIZE, IO_SIZE * entry_no, MYF(MY_WME)) != IO_SIZE) error= TRUE; DBUG_RETURN(error); } @@ -383,7 +384,7 @@ write_table_log_header() if (write_table_log_file_entry(0UL)) error= TRUE; if (!error) - error= sync_table_log(); + VOID(sync_table_log()); DBUG_RETURN(error); } @@ -430,7 +431,7 @@ read_table_log_header() bzero(file_entry, sizeof(global_table_log.file_entry)); create_table_log_file_name(file_name); - if (!(my_open(file_name, O_RDWR | O_TRUNC | O_BINARY, MYF(0)))) + if (!(my_open(file_name, O_RDWR | O_TRUNC | O_BINARY, MYF(MY_WME)))) { if (read_table_log_file_entry(0UL)) { @@ -517,7 +518,7 @@ init_table_log() if ((global_table_log.file_id= my_create(file_name, CREATE_MODE, O_RDWR | O_TRUNC | O_BINARY, - MYF(0))) < 0) + MYF(MY_WME))) < 0) { /* Couldn't create table log file, this is serious error */ abort(); @@ -564,6 +565,7 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) hton= ha_resolve_by_name(current_thd, handler_name); if (!hton) { + my_error(ER_ILLEGAL_HA, table_log_entry->handler_type); DBUG_RETURN(TRUE); } init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); @@ -573,7 +575,10 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) { file= get_new_handler(table_share, &mem_root, hton); if (!file) + { + mem_alloc_error(sizeof(handler)); goto error; + } } switch (table_log_entry->action_type) case TLOG_ACTION_DELETE_CODE: @@ -585,20 +590,24 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) if (frm_action) { strxmov(path, table_log_entry->name, reg_ext, NullS); - VOID(my_delete(path, MYF(0))); + if (my_delete(path, MYF(MY_WME))) + break; strxmov(path, table_log_entry->name, par_ext, NullS); - VOID(my_delete(path, MYF(0))); + if (my_delete(path, MYF(MY_WME))) + break; } else { if (file->delete_table(table_name)) break; } - if ((!inactivate_table_log_entry(table_log_entry->entry_pos)) && - (!sync_table_log())) + if ((!inactivate_table_log_entry(table_log_entry->entry_pos))) ; else + { + VOID(sync_table_log()); error= FALSE; + } break; } if (table_log_entry->action_type == TLOG_ACTION_DELETE_CODE) @@ -609,11 +618,11 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) { strxmov(path, table_log_entry->name, reg_ext, NullS); strxmov(from_path, table_log_entry->from_name, reg_ext, NullS); - if (my_rename(path, from_path, MYF(0))) + if (my_rename(path, from_path, MYF(MY_WME))) break; strxmov(path, table_log_entry->name, par_ext, NullS); strxmov(from_path, table_log_entry->from_name, par_ext, NullS); - if (my_rename(path, from_path, MYF(0))) + if (my_rename(path, from_path, MYF(MY_WME))) break; } else @@ -621,11 +630,13 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) if (file->rename_table(table_log_entry->name, table_log_entry->from_name)) break; - if ((!inactivate_table_log_entry(table_log_entry->entry_pos)) && - (!sync_table_log())) + if ((!inactivate_table_log_entry(table_log_entry->entry_pos))) ; else + { + VOID(sync_table_log()); error= FALSE; + } } break; default: @@ -662,7 +673,7 @@ get_free_table_log_entry(TABLE_LOG_MEMORY_ENTRY **active_entry, if (global_table_log.first_free == NULL) { if (!(used_entry= (TABLE_LOG_MEMORY_ENTRY*)my_malloc( - sizeof(TABLE_LOG_MEMORY_ENTRY), MYF(0)))) + sizeof(TABLE_LOG_MEMORY_ENTRY), MYF(MY_WME)))) { DBUG_RETURN(TRUE); } @@ -748,7 +759,8 @@ write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, error= TRUE; if (write_header && !error) { - if (sync_table_log() || write_table_log_header()) + VOID(sync_table_log()); + if (write_table_log_header()) error= TRUE; } if (error) @@ -1232,7 +1244,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) VOID(pthread_mutex_lock(&LOCK_open)); if (my_delete(frm_name, MYF(MY_WME)) || inactivate_table_log_entry(part_info->frm_log_entry->entry_pos) || - sync_table_log() || + (sync_table_log(), FALSE) || my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || lpt->table->file->create_handler_files(path, shadow_path, TRUE)) { From c8db62f64c51f75bb8314a71b145ff4689ec2543 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 14 Feb 2006 17:03:47 +0100 Subject: [PATCH 31/48] WL 2826: Error handling of ALTER TABLE for partitioning Some more error handling sql/sql_partition.cc: Some more error handling --- sql/sql_partition.cc | 74 ++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 6a34fcaadde..8f09edcf8cc 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5713,6 +5713,51 @@ write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt) } +/* + Handle errors for ALTER TABLE for partitioning + SYNOPSIS + handle_alter_part_error() + lpt Struct carrying parameters + not_completed Was request in complete phase when error occurred + RETURN VALUES + NONE +*/ + +void +handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed) +{ + partition_info *part_info= lpt->part_info; + DBUG_ENTER("handle_alter_part_error"); + + if (!part_info->first_log_entry && + execute_table_log_entry(part_info->first_log_entry)) + { + /* + We couldn't recover from error + */ + } + else + { + if (not_completed) + { + /* + We hit an error before things were completed but managed + to recover from the error. + */ + } + else + { + /* + We hit an error after we had completed most of the operation + and were successful in a second attempt so the operation + actually is successful now. + */ + } + } + DBUG_VOID_RETURN; +} + + /* Actually perform the change requested by ALTER TABLE of partitions previously prepared. @@ -5929,34 +5974,9 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_drop_partition_8") || (mysql_wait_completed_table(lpt, table), FALSE)) { + handle_alter_part_error(lpt, not_completed); + DBUG_RETURN(TRUE); abort(); - if (!not_completed) - abort(); - if (!part_info->first_log_entry && - execute_table_log_entry(part_info->first_log_entry)) - { - /* - We couldn't recover from error - */ - } - else - { - if (not_completed) - { - /* - We hit an error before things were completed but managed - to recover from the error. - */ - } - else - { - /* - We hit an error after we had completed most of the operation - and were successful in a second attempt so the operation - actually is successful now. - */ - } - } fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); } From e20cbe27de0b97ad585cc9a6cb002ecff05dea8a Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 15 Feb 2006 11:08:08 +0100 Subject: [PATCH 32/48] WL 2826: Error handling of ALTER TABLE for partitioning Started writing detailed error handler of ALTER TABLE for partitioning. Philosophical issue, should one always attempt to make recovery automatic or should one rely on manual means also. sql/mysql_priv.h: Flag to ensure we can't be killed in a very critical spot sql/sql_base.cc: Flag to ensure we can't be killed in a very critical spot sql/sql_partition.cc: Started writing detailed error handler of ALTER TABLE for partitioning. Philosophical issue, should one always attempt to make recovery automatic or should one rely on manual means also. --- sql/mysql_priv.h | 3 +- sql/sql_base.cc | 5 +- sql/sql_partition.cc | 177 +++++++++++++++++++++++++++++-------------- 3 files changed, 124 insertions(+), 61 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 4a67ab650d9..efdeed8d084 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1218,7 +1218,8 @@ void unlock_global_table_log(); #define WFRM_INSTALL_SHADOW 2 #define WFRM_PACK_FRM 4 bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags); -bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt); +bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt, + bool can_be_killed); void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt); void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 44b3a22ec52..707b593b044 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6107,7 +6107,8 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b) old_lock_level Old lock level */ -bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) +bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt, + bool can_be_killed) { uint flags= RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG; int error= FALSE; @@ -6117,7 +6118,7 @@ bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) VOID(pthread_mutex_lock(&LOCK_open)); mysql_lock_abort(lpt->thd, lpt->table, TRUE); VOID(remove_table_from_cache(lpt->thd, lpt->db, lpt->table_name, flags)); - if (lpt->thd->killed) + if (can_be_killed && lpt->thd->killed) { lpt->thd->no_warnings_for_error= 0; error= TRUE; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 8f09edcf8cc..a1b9b226f39 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -3910,27 +3910,6 @@ end: } -/* - SYNOPSIS - fast_alter_partition_error_handler() - lpt Container for parameters - - RETURN VALUES - None - - DESCRIPTION - Support routine to clean up after failures of on-line ALTER TABLE - for partition management. -*/ - -static void fast_alter_partition_error_handler(ALTER_PARTITION_PARAM_TYPE *lpt) -{ - DBUG_ENTER("fast_alter_partition_error_handler"); - /* TODO: WL 2826 Error handling */ - DBUG_VOID_RETURN; -} - - /* SYNOPSIS fast_end_partition() @@ -3952,6 +3931,7 @@ static void fast_alter_partition_error_handler(ALTER_PARTITION_PARAM_TYPE *lpt) static int fast_end_partition(THD *thd, ulonglong copied, ulonglong deleted, + TABLE *table, TABLE_LIST *table_list, bool is_empty, ALTER_PARTITION_PARAM_TYPE *lpt, bool written_bin_log) @@ -3979,7 +3959,7 @@ static int fast_end_partition(THD *thd, ulonglong copied, send_ok(thd,copied+deleted,0L,tmp_name); DBUG_RETURN(FALSE); } - fast_alter_partition_error_handler(lpt); + table->file->print_error(error, MYF(0)); DBUG_RETURN(TRUE); } @@ -4202,7 +4182,8 @@ uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info, after the change as before. Thus we can reply ok immediately without any changes at all. */ - DBUG_RETURN(fast_end_partition(thd, ULL(0), ULL(0), NULL, + DBUG_RETURN(fast_end_partition(thd, ULL(0), ULL(0), + table, NULL, TRUE, NULL, FALSE)); } else if (new_part_no > curr_part_no) @@ -5691,25 +5672,61 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) */ static -bool -write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt) +void +write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, bool dont_crash) { partition_info *part_info= lpt->part_info; + uint count_loop= 0; + bool success; TABLE_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry; DBUG_ENTER("write_log_completed"); DBUG_ASSERT(log_entry); lock_global_table_log(); - if (write_execute_table_log_entry(0UL, TRUE, &log_entry)) + do { - DBUG_RETURN(TRUE); + if (!(success= write_execute_table_log_entry(0UL, TRUE, &log_entry))) + break; + my_sleep(1); + } while (count_loop++ < 20); + if (!success && !dont_crash) + { + /* + Failed to write 20 consecutive attempts to write. Bad... + We have completed the operation but have log records to REMOVE + stuff that shouldn't be removed. What clever things could one do + here? + */ + abort(); } release_part_info_log_entries(part_info->first_log_entry); release_part_info_log_entries(part_info->exec_log_entry); unlock_global_table_log(); part_info->exec_log_entry= NULL; part_info->first_log_entry= NULL; - DBUG_RETURN(FALSE); + DBUG_VOID_RETURN; +} + + +/* + Release all log entries + SYNOPSIS + release_log_entries() + part_info Partition info struct + RETURN VALUES + NONE +*/ + +static +void +release_log_entries(partition *part_info) +{ + lock_global_table_log(); + release_part_info_log_entries(part_info->first_log_entry); + release_part_info_log_entries(part_info->exec_log_entry); + unlock_global_table_log(); + part_info->first_log_entry= NULL; + part_info->exec_log_entry= NULL; } @@ -5724,36 +5741,87 @@ write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt) */ void -handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed) +handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, + bool drop_partition, bool frm_install) { partition_info *part_info= lpt->part_info; DBUG_ENTER("handle_alter_part_error"); +#if 0 if (!part_info->first_log_entry && execute_table_log_entry(part_info->first_log_entry)) { /* We couldn't recover from error */ + if (not_completed) + { + if (drop_partition) + { + /* Table is still ok, but we left a shadow frm file behind. */ + write_log_completed(lpt, TRUE); + release_log_entries(part_info); + push_warning(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, +"Operation was unsuccessful, table still intact, shadow frm file left behind" + ); + } + } + else + { + if (frm_install && drop_partition) + { + /* + Failed during install of shadow frm file, table isn't intact + and dropped partitions are still there + */ + } + else if (drop_partition) + { + /* + Table is ok, we have switched to new table but left dropped partitions + still in their places. We remove the log records and ask the user to + perform the action manually. We remove the log records and ask the user to + perform the action manually. + */ + char *text1= "Failed during drop of partitions, table is intact, "; + char *text2= "Manual drop of remaining partitions is required"; + write_log_completed(lpt, TRUE); + release_log_entries(part_info); + push_warning_print(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s\n%s", text1, text2); + } + else (frm_install) + { + } + } + } else { + release_log_entries(part_info); if (not_completed) { /* We hit an error before things were completed but managed - to recover from the error. + to recover from the error. An error occurred and we have + restored things to original so no need for further action. */ + ; } else { /* We hit an error after we had completed most of the operation and were successful in a second attempt so the operation - actually is successful now. + actually is successful now. We need to issue a warning that + even though we reported an error the operation was successfully + completed. */ + push_warning(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "Operation was successfully completed after failure of normal operation"); } } +#endif DBUG_VOID_RETURN; } @@ -5799,6 +5867,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ALTER_PARTITION_PARAM_TYPE lpt_obj; ALTER_PARTITION_PARAM_TYPE *lpt= &lpt_obj; bool written_bin_log= TRUE; + bool not_completed= TRUE; + bool frm_install= FALSE; DBUG_ENTER("fast_alter_partition_table"); lpt->thd= thd; @@ -5844,7 +5914,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ((alter_info->flags & ALTER_REPAIR_PARTITION) && (table->file->repair_partitions(thd)))) { - fast_alter_partition_error_handler(lpt); + table->file->print_error(error, MYF(0)); DBUG_RETURN(TRUE); } } @@ -5892,7 +5962,6 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, if (mysql_write_frm(lpt, WFRM_WRITE_SHADOW | WFRM_PACK_FRM) || mysql_change_partitions(lpt)) { - fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); } } @@ -5950,7 +6019,6 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, We insert Error injections at all places where it could be interesting to test if recovery is properly done. */ - bool not_completed= TRUE; if (write_log_drop_shadow_frm(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || @@ -5958,26 +6026,25 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, write_log_drop_partition(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_3") || ((not_completed= FALSE), FALSE) || - abort_and_upgrade_lock(lpt) || + (abort_and_upgrade_lock(lpt, FALSE), FALSE) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || ERROR_INJECT_CRASH("crash_drop_partition_4") || - mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || - (close_open_tables_and_downgrade(lpt), FALSE) || - ERROR_INJECT_CRASH("crash_drop_partition_5") || (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) || + ERROR_INJECT_CRASH("crash_drop_partition_5") || + ((frm_install= TRUE), FALSE) || + mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || + ((frm_install= FALSE), FALSE) || + (close_open_tables_and_downgrade(lpt), FALSE) || ERROR_INJECT_CRASH("crash_drop_partition_6") || mysql_drop_partitions(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_7") || - write_log_completed(lpt) || + (write_log_completed(lpt, FALSE), FALSE) || ERROR_INJECT_CRASH("crash_drop_partition_8") || (mysql_wait_completed_table(lpt, table), FALSE)) { - handle_alter_part_error(lpt, not_completed); - DBUG_RETURN(TRUE); - abort(); - fast_alter_partition_error_handler(lpt); + handle_alter_part_error(lpt, not_completed, TRUE, frm_install); DBUG_RETURN(TRUE); } } @@ -6011,14 +6078,13 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 8) Remove entries from table log 9) Complete query */ - bool not_completed= TRUE; if (write_log_add_change_partition(lpt) || ERROR_INJECT_CRASH("crash_add_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECT_CRASH("crash_add_partition_2") || mysql_change_partitions(lpt) || ERROR_INJECT_CRASH("crash_add_partition_3") || - abort_and_upgrade_lock(lpt) || + (abort_and_upgrade_lock(lpt, FALSE), FALSE) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || @@ -6026,16 +6092,14 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, write_log_rename_frm(lpt) || ((not_completed= FALSE), FALSE) || ERROR_INJECT_CRASH("crash_add_partition_5") || + ((frm_install= TRUE), FALSE) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || ERROR_INJECT_CRASH("crash_add_partition_6") || (close_open_tables_and_downgrade(lpt), FALSE) || - write_log_completed(lpt) || + (write_log_completed(lpt, FALSE), FALSE) || ERROR_INJECT_CRASH("crash_add_partition_7")) { - abort(); - if (!not_completed) - abort(); - fast_alter_partition_error_handler(lpt); + handle_alter_part_error(lpt, not_completed, FALSE, frm_install); DBUG_RETURN(TRUE); } } @@ -6094,7 +6158,6 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 13)Wait until all accesses using the old frm file has completed 14)Complete query */ - bool not_completed= TRUE; if (write_log_add_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_1") || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || @@ -6104,7 +6167,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, write_log_final_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_4") || ((not_completed= FALSE), FALSE) || - abort_and_upgrade_lock(lpt) || + (abort_and_upgrade_lock(lpt, FALSE), FALSE) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || @@ -6112,19 +6175,17 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) || ERROR_INJECT_CRASH("crash_change_partition_6") || mysql_rename_partitions(lpt) || + ((frm_install= TRUE), FALSE) || ERROR_INJECT_CRASH("crash_change_partition_7") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || ERROR_INJECT_CRASH("crash_change_partition_8") || (close_open_tables_and_downgrade(lpt), FALSE) || ERROR_INJECT_CRASH("crash_change_partition_9") || - write_log_completed(lpt) || + (write_log_completed(lpt, FALSE), FALSE) || ERROR_INJECT_CRASH("crash_change_partition_10") || (mysql_wait_completed_table(lpt, table), FALSE)) { - abort(); - if (!not_completed) - abort(); - fast_alter_partition_error_handler(lpt); + handle_alter_part_error(lpt, not_completed, FALSE, frm_install); DBUG_RETURN(TRUE); } } @@ -6133,7 +6194,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, user */ DBUG_RETURN(fast_end_partition(thd, lpt->copied, lpt->deleted, - table_list, FALSE, lpt, + table, table_list, FALSE, lpt, written_bin_log)); } #endif From f52e37ada8bff017fdd1906d680240b7f4df360b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 15 Feb 2006 14:05:15 +0100 Subject: [PATCH 33/48] WL 2826: Error handling of ALTER TABLE for partitioning Final part of the error handling of ALTER TABLE for partitioning sql/sql_partition.cc: Final part of the error handling of ALTER TABLE for partitioning --- sql/sql_partition.cc | 48 +++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index a1b9b226f39..743bf4b56e5 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5747,51 +5747,72 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, partition_info *part_info= lpt->part_info; DBUG_ENTER("handle_alter_part_error"); -#if 0 if (!part_info->first_log_entry && execute_table_log_entry(part_info->first_log_entry)) { /* - We couldn't recover from error + We couldn't recover from error, most likely manual interaction is required. */ + write_log_completed(lpt, FALSE); + release_log_entries(part_info); if (not_completed) { + char *text1= "Operation was unsuccessful, table is still intact, "; if (drop_partition) { /* Table is still ok, but we left a shadow frm file behind. */ - write_log_completed(lpt, TRUE); - release_log_entries(part_info); - push_warning(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, -"Operation was unsuccessful, table still intact, shadow frm file left behind" - ); + char *text2= "but it is possible that a shadow frm file was left behind"; + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s \n %s", text1, text2); + } + else + { + char *text2= "but it is possible that a shadow frm file was left behind."; + char *text3= "It is also possible that temporary partitions are left behind, "; + char *text4= "these could be empty or more or less filled with records"; + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s \n %s \n %s \n %s", text1, text2, text3, text4); } } else { - if (frm_install && drop_partition) + if (frm_install) { /* Failed during install of shadow frm file, table isn't intact and dropped partitions are still there */ + char *text1= "Failed during alter of partitions, table is no longer intact, "; + char *text2= "The frm file is in an unknown state, and a backup"; + char *text3= " is required. + push_warning_print(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s \n %s%s\n", text1, text2, text3); } else if (drop_partition) { /* Table is ok, we have switched to new table but left dropped partitions still in their places. We remove the log records and ask the user to - perform the action manually. We remove the log records and ask the user to - perform the action manually. + perform the action manually. We remove the log records and ask the user + to perform the action manually. */ char *text1= "Failed during drop of partitions, table is intact, "; char *text2= "Manual drop of remaining partitions is required"; - write_log_completed(lpt, TRUE); - release_log_entries(part_info); push_warning_print(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, "%s\n%s", text1, text2); } - else (frm_install) + else { + /* + We failed during renaming of partitions. The table is most certainly in + a very bad state so we give user warning and disable the table by + writing an ancient frm version into it. + */ + char *text1= "Failed during renaming of partitions. We are now in a position" + char *text2= " where table is not reusable"; + char *text3= "Table is disabled by writing ancient frm file version into it"; + push_warning_print(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s%s\n%s", text1, text2, text3); } } @@ -5821,7 +5842,6 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, "Operation was successfully completed after failure of normal operation"); } } -#endif DBUG_VOID_RETURN; } From de717a9962e28df8541f7e0e0f92239ad697aeb7 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 20 Feb 2006 15:07:03 -0500 Subject: [PATCH 34/48] WL 2826: Error handling of ALTER TABLE for partitioning Fix compiler issues sql/ha_heap.cc: Fix compiler warnings sql/ha_myisammrg.cc: Fix compiler warnings sql/log.cc: Fix compiler warnings sql/sql_partition.cc: Fix compiler issues sql/sql_table.cc: Fix compiler issues --- sql/ha_heap.cc | 4 ++- sql/ha_myisammrg.cc | 4 ++- sql/log.cc | 4 ++- sql/sql_partition.cc | 67 +++++++++++++++++++++++++++----------------- sql/sql_table.cc | 48 ++++++++++++++++++++----------- 5 files changed, 81 insertions(+), 46 deletions(-) diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index 2fe4bc7aeb5..d3ab7bd9d25 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -57,7 +57,9 @@ handlerton heap_hton= { NULL, /* Partition flags */ NULL, /* Alter table flags */ NULL, /* Alter Tablespace */ - HTON_CAN_RECREATE + HTON_CAN_RECREATE, + NULL, /* binlog func */ + NULL /* binlog query */ }; static handler *heap_create_handler(TABLE_SHARE *table) diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 36de3dc64e0..1720c9fe0e7 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -67,7 +67,9 @@ handlerton myisammrg_hton= { NULL, /* Partition flags */ NULL, /* Alter table flags */ NULL, /* Alter Tablespace */ - HTON_CAN_RECREATE + HTON_CAN_RECREATE, + NULL, /* binlog func */ + NULL /* binlog query */ }; static handler *myisammrg_create_handler(TABLE_SHARE *table) diff --git a/sql/log.cc b/sql/log.cc index f6fc6d5cd74..3254fd1712a 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -101,7 +101,9 @@ handlerton binlog_hton = { NULL, /* Partition flags */ NULL, /* Alter table flags */ NULL, /* Alter Tablespace */ - HTON_NOT_USER_SELECTABLE | HTON_HIDDEN + HTON_NOT_USER_SELECTABLE | HTON_HIDDEN, + NULL, /* binlog func */ + NULL /* binlog query */ }; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 743bf4b56e5..c7b75c6548c 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5116,6 +5116,7 @@ release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) the partition info object */ +static bool write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint next_entry, @@ -5719,7 +5720,7 @@ write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, bool dont_crash) static void -release_log_entries(partition *part_info) +release_log_entries(partition_info *part_info) { lock_global_table_log(); release_part_info_log_entries(part_info->first_log_entry); @@ -5748,7 +5749,7 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, DBUG_ENTER("handle_alter_part_error"); if (!part_info->first_log_entry && - execute_table_log_entry(part_info->first_log_entry)) + execute_table_log_entry(part_info->first_log_entry->entry_pos)) { /* We couldn't recover from error, most likely manual interaction is required. @@ -5757,19 +5758,24 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, release_log_entries(part_info); if (not_completed) { - char *text1= "Operation was unsuccessful, table is still intact, "; + char *text1= + (char*)"Operation was unsuccessful, table is still intact, "; if (drop_partition) { /* Table is still ok, but we left a shadow frm file behind. */ - char *text2= "but it is possible that a shadow frm file was left behind"; + char *text2= + (char*)"but it is possible that a shadow frm file was left behind"; push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, "%s \n %s", text1, text2); } else { - char *text2= "but it is possible that a shadow frm file was left behind."; - char *text3= "It is also possible that temporary partitions are left behind, "; - char *text4= "these could be empty or more or less filled with records"; + char *text2= + (char*)"but it is possible that a shadow frm file was left behind."; + char *text3= + (char*)"It is also possible that temporary partitions are left behind, "; + char *text4= + (char*)"these could be empty or more or less filled with records"; push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, "%s \n %s \n %s \n %s", text1, text2, text3, text4); } @@ -5782,11 +5788,14 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, Failed during install of shadow frm file, table isn't intact and dropped partitions are still there */ - char *text1= "Failed during alter of partitions, table is no longer intact, "; - char *text2= "The frm file is in an unknown state, and a backup"; - char *text3= " is required. - push_warning_print(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "%s \n %s%s\n", text1, text2, text3); + char *text1= + (char*)"Failed during alter of partitions, table is no longer intact, "; + char *text2= + (char*)"The frm file is in an unknown state, and a backup"; + char *text3= + (char*)" is required."; + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s \n %s%s\n", text1, text2, text3); } else if (drop_partition) { @@ -5796,10 +5805,12 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, perform the action manually. We remove the log records and ask the user to perform the action manually. */ - char *text1= "Failed during drop of partitions, table is intact, "; - char *text2= "Manual drop of remaining partitions is required"; - push_warning_print(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "%s\n%s", text1, text2); + char *text1= + (char*)"Failed during drop of partitions, table is intact, "; + char *text2= + (char*)"Manual drop of remaining partitions is required"; + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s\n%s", text1, text2); } else { @@ -5808,11 +5819,14 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, a very bad state so we give user warning and disable the table by writing an ancient frm version into it. */ - char *text1= "Failed during renaming of partitions. We are now in a position" - char *text2= " where table is not reusable"; - char *text3= "Table is disabled by writing ancient frm file version into it"; - push_warning_print(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "%s%s\n%s", text1, text2, text3); + char *text1= + (char*)"Failed during renaming of partitions. We are now in a position"; + char *text2= + (char*)" where table is not reusable"; + char *text3= + (char*)"Table is disabled by writing ancient frm file version into it"; + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s%s\n%s", text1, text2, text3); } } @@ -5839,7 +5853,7 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, completed. */ push_warning(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "Operation was successfully completed after failure of normal operation"); + "Operation was successfully completed after failure of normal operation"); } } DBUG_VOID_RETURN; @@ -5924,15 +5938,16 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, In this case it is enough to call optimise_partitions, there is no need to change frm files or anything else. */ + int error; written_bin_log= FALSE; if (((alter_info->flags & ALTER_OPTIMIZE_PARTITION) && - (table->file->optimize_partitions(thd))) || + (error= table->file->optimize_partitions(thd))) || ((alter_info->flags & ALTER_ANALYZE_PARTITION) && - (table->file->analyze_partitions(thd))) || + (error= table->file->analyze_partitions(thd))) || ((alter_info->flags & ALTER_CHECK_PARTITION) && - (table->file->check_partitions(thd))) || + (error= table->file->check_partitions(thd))) || ((alter_info->flags & ALTER_REPAIR_PARTITION) && - (table->file->repair_partitions(thd)))) + (error= table->file->repair_partitions(thd)))) { table->file->print_error(error, MYF(0)); DBUG_RETURN(TRUE); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8391a976679..963c8e5171e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -321,7 +321,7 @@ read_table_log_file_entry(uint entry_no) DBUG_ENTER("read_table_log_file_entry"); if (my_pread(file_id, file_entry, io_size, io_size * entry_no, - MYF(MY_WME))) + MYF(MY_WME)) != IO_SIZE) error= TRUE; DBUG_RETURN(error); } @@ -549,23 +549,24 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) bool frm_action= FALSE; LEX_STRING handler_name; handler *file; - MEMROOT mem_root; - bool= error= TRUE; + MEM_ROOT mem_root; + bool error= TRUE; char path[FN_REFLEN]; char from_path[FN_REFLEN]; - char *par_ext= ".par"; + char *par_ext= (char*)".par"; + handlerton *hton; DBUG_ENTER("execute_table_log_action"); if (table_log_entry->entry_type == TLOG_IGNORE_LOG_ENTRY_CODE) { DBUG_RETURN(FALSE); } - handler_name.str= table_log_entry->handler_type; + handler_name.str= (char*)table_log_entry->handler_type; handler_name.length= strlen(table_log_entry->handler_type); - hton= ha_resolve_by_name(current_thd, handler_name); + hton= ha_resolve_by_name(current_thd, &handler_name); if (!hton) { - my_error(ER_ILLEGAL_HA, table_log_entry->handler_type); + my_error(ER_ILLEGAL_HA, MYF(0), table_log_entry->handler_type); DBUG_RETURN(TRUE); } init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); @@ -573,7 +574,9 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) frm_action= TRUE; else { - file= get_new_handler(table_share, &mem_root, hton); + TABLE_SHARE dummy; + bzero(&dummy, sizeof(TABLE_SHARE)); + file= get_new_handler(&dummy, &mem_root, hton); if (!file) { mem_alloc_error(sizeof(handler)); @@ -581,10 +584,12 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) } } switch (table_log_entry->action_type) - case TLOG_ACTION_DELETE_CODE: - case TLOG_ACTION_REPLACE_CODE: - if (table_log_entry->action_type == TLOG_ACTION_DELETE_CODE || - (table_log_entry->action_type == TLOG_ACTION_REPLACE_CODE && + { + case TLOG_DELETE_ACTION_CODE: + case TLOG_REPLACE_ACTION_CODE: + { + if (table_log_entry->action_type == TLOG_DELETE_ACTION_CODE || + (table_log_entry->action_type == TLOG_REPLACE_ACTION_CODE && table_log_entry->phase == 0UL)) { if (frm_action) @@ -598,7 +603,7 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) } else { - if (file->delete_table(table_name)) + if (file->delete_table(table_log_entry->name)) break; } if ((!inactivate_table_log_entry(table_log_entry->entry_pos))) @@ -610,9 +615,11 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) } break; } - if (table_log_entry->action_type == TLOG_ACTION_DELETE_CODE) + if (table_log_entry->action_type == TLOG_DELETE_ACTION_CODE) break; - case TLOG_ACTION_RENAME_CODE: + } + case TLOG_RENAME_ACTION_CODE: + { error= TRUE; if (frm_action) { @@ -639,6 +646,7 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) } } break; + } default: DBUG_ASSERT(0); break; @@ -978,7 +986,7 @@ execute_table_log_entry(uint first_entry) DBUG_ASSERT(table_log_entry.entry_type == TLOG_LOG_ENTRY_CODE || table_log_entry.entry_type == TLOG_IGNORE_LOG_ENTRY_CODE); - if (execute_table_log_action(file, &table_log_entry)) + if (execute_table_log_action(&table_log_entry)) { DBUG_ASSERT(0); /* Write to error log and continue with next log entry */ @@ -1028,7 +1036,6 @@ execute_table_log_recovery() } } } - release_handler_objects(); VOID(init_table_log()); DBUG_VOID_RETURN; } @@ -1231,6 +1238,9 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) } if (flags & WFRM_INSTALL_SHADOW) { +#ifdef WITH_PARTITION_STORAGE_ENGINE + partition_info *part_info= lpt->part_info; +#endif /* Build frm file name */ @@ -1243,17 +1253,21 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) */ VOID(pthread_mutex_lock(&LOCK_open)); if (my_delete(frm_name, MYF(MY_WME)) || +#ifdef WITH_PARTITION_STORAGE_ENGINE inactivate_table_log_entry(part_info->frm_log_entry->entry_pos) || (sync_table_log(), FALSE) || +#endif my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || lpt->table->file->create_handler_files(path, shadow_path, TRUE)) { error= 1; } VOID(pthread_mutex_unlock(&LOCK_open)); +#ifdef WITH_PARTITION_STORAGE_ENGINE inactivate_table_log_entry(part_info->frm_log_entry->entry_pos); part_info->frm_log_entry= NULL; VOID(sync_table_log()); +#endif } end: From 5b6c6c49b8316d6d8b2f77abafc6743c372385d7 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 20 Feb 2006 16:22:19 -0500 Subject: [PATCH 35/48] WL 2826: Error handling of ALTER TABLE for partitioning Bug fixes sql/ha_partition.cc: Bug fixes sql/sql_partition.cc: Bug fixes sql/sql_table.cc: Bug fixes --- sql/ha_partition.cc | 14 +++++++------- sql/sql_partition.cc | 6 +++--- sql/sql_table.cc | 5 ++++- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index d65203e1b34..4bc0d4e3327 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -714,10 +714,10 @@ int ha_partition::rename_partitions(const char *path) DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); if ((ret_error= file->delete_table((const char *) norm_name_buff))) error= ret_error; - else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + else if (inactivate_table_log_entry(part_elem->log_entry->entry_pos)) error= 1; else - sub_elem->log_entry= NULL; /* Indicate success */ + part_elem->log_entry= NULL; /* Indicate success */ } } while (++i < temp_partitions); VOID(sync_table_log()); @@ -780,8 +780,8 @@ int ha_partition::rename_partitions(const char *path) TEMP_PART_NAME); DBUG_PRINT("info", ("Rename subpartition from %s to %s", part_name_buff, norm_name_buff)); - if ((ret_error= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff))) + if ((ret_error= file->rename_table((const char *) part_name_buff, + (const char *) norm_name_buff))) error= ret_error; else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) error= 1; @@ -797,7 +797,7 @@ int ha_partition::rename_partitions(const char *path) if (part_elem->part_state == PART_IS_CHANGED) { file= m_reorged_file[part_count++]; - DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); + DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); if ((ret_error= file->delete_table((const char *) norm_name_buff))) error= ret_error; else if (inactivate_table_log_entry(part_elem->log_entry->entry_pos)) @@ -810,8 +810,8 @@ int ha_partition::rename_partitions(const char *path) TRUE); DBUG_PRINT("info", ("Rename partition from %s to %s", part_name_buff, norm_name_buff)); - if ((ret_error= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff))) + if ((ret_error= file->rename_table((const char *) part_name_buff, + (const char *) norm_name_buff))) error= ret_error; else if (inactivate_table_log_entry(part_elem->log_entry->entry_pos)) error= 1; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index c7b75c6548c..6756d345cab 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5678,7 +5678,7 @@ write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, bool dont_crash) { partition_info *part_info= lpt->part_info; uint count_loop= 0; - bool success; + bool not_success; TABLE_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry; DBUG_ENTER("write_log_completed"); @@ -5686,11 +5686,11 @@ write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, bool dont_crash) lock_global_table_log(); do { - if (!(success= write_execute_table_log_entry(0UL, TRUE, &log_entry))) + if (!(not_success= write_execute_table_log_entry(0UL, TRUE, &log_entry))) break; my_sleep(1); } while (count_loop++ < 20); - if (!success && !dont_crash) + if (not_success && !dont_crash) { /* Failed to write 20 consecutive attempts to write. Bad... diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 963c8e5171e..4db976c34fa 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -435,7 +435,7 @@ read_table_log_header() { if (read_table_log_file_entry(0UL)) { - /* Write message into error log */ + ; /* Write message into error log */ } else successful_open= TRUE; @@ -446,6 +446,8 @@ read_table_log_header() uint4korr(&file_entry[TLOG_HANDLER_TYPE_POS]); if (successful_open) global_table_log.io_size= uint4korr(&file_entry[TLOG_IO_SIZE_POS]); + else + global_table_log.io_size= IO_SIZE; global_table_log.first_free= NULL; global_table_log.first_used= NULL; global_table_log.no_entries= 0; @@ -513,6 +515,7 @@ init_table_log() char file_name[FN_REFLEN]; DBUG_ENTER("init_table_log"); + global_table_log.io_size= IO_SIZE; create_table_log_file_name(file_name); VOID(my_delete(file_name, MYF(0))); if ((global_table_log.file_id= my_create(file_name, From 0da06937929761146d591097bb21f3c3656836d6 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 20 Feb 2006 21:50:44 -0500 Subject: [PATCH 36/48] WL 2826: Error handling of ALTER TABLE for partitioning Merged error injects with dbug push sql/mysql_priv.h: Merged error injects with dbug push --- sql/mysql_priv.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 0a229d5181b..202c04d0b1c 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -625,9 +625,12 @@ struct Query_cache_query_flags inline bool my_error_inject_name(const char *dbug_str) { - if (_db_on_ && _db_strict_keyword_ (dbug_str)) + const char *extra_str= "-d,"; + char total_str[200]; + if (_db_strict_keyword_ (dbug_str)) { - DBUG_DEL_KEYWORD(dbug_str); + strxmov(total_str, extra_str, dbug_str, NullS); + DBUG_SET(total_str); return 1; } return 0; @@ -647,7 +650,7 @@ my_error_inject(int value) } #define ERROR_INJECT_CRASH(code) \ - DBUG_EXECUTE_COND(code, abort()) + DBUG_EVALUATE_IF(code, (abort(), 0), 0) #define ERROR_INJECT_ACTION(code, action) \ (my_error_inject_name(code) ? ((action), 0) : 0) #define ERROR_INJECT(code) \ From a95646be8d1d56b8ee68ae991ba3c760d9071b94 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Feb 2006 07:49:25 -0500 Subject: [PATCH 37/48] WL 2826: Error handling of ALTER TABLE for partitioning Final fixes dbug/dbug_long.h: Removed patch from dbug_long.h (file not in use anymore) sql/mysql_priv.h: Removed error_inject_code variable --- dbug/dbug_long.h | 13 ------------- sql/mysql_priv.h | 2 +- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/dbug/dbug_long.h b/dbug/dbug_long.h index 4035ca56b66..829df181ef1 100644 --- a/dbug/dbug_long.h +++ b/dbug/dbug_long.h @@ -127,11 +127,6 @@ # define DBUG_SETJMP setjmp # define DBUG_LONGJMP longjmp # define DBUG_DUMP(keyword,a1) -# define DBUG_EXECUTE_IF(keyword, a1) -# define DBUG_EXECUTE_COND(keyword, a1) 0 -# define DBUG_COND(keyword) 0 -# define DBUG_ADD_KEYWORD(key) -# define DBUG_DEL_KEYWORD(key) # else # define DBUG_ENTER(a) \ auto char *_db_func_; auto char *_db_file_; auto int _db_level_; \ @@ -162,12 +157,4 @@ # define DBUG_SETJMP(a1) (_db_setjmp_ (), setjmp (a1)) # define DBUG_LONGJMP(a1,a2) (_db_longjmp_ (), longjmp (a1, a2)) # define DBUG_DUMP(keyword,a1,a2) _db_dump_(__LINE__,keyword,a1,a2) -# define DBUG_EXECUTE_IF(keyword,a1) \ - {if (_db_on_) {if (_db_strict_keyword_ (keyword)) { a1 }}} -# define DBUG_EXECUTE_COND(keyword, a1) \ - (_db_on_ ? ((_db_strict_keyword_ (keyword)) ? ((a1), 0) : 0) : 0) -# define DBUG_COND(keyword) \ - ((_db_on_ && _db_strict_keyword_ (keyword)) ? 1 : 0) -# define DBUG_ADD_KEYWORD(key) _db_add_strict_keyword_(key) -# define DBUG_DEL_KEYWORD(key) _db_del_strict_keyword_(key) # endif diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 202c04d0b1c..96576fd8eea 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1395,7 +1395,7 @@ extern ulong delayed_insert_limit, delayed_queue_size; extern ulong delayed_insert_threads, delayed_insert_writes; extern ulong delayed_rows_in_use,delayed_insert_errors; #ifdef ERROR_INJECT_SUPPORT -extern ulong error_inject_code, error_inject_value; +extern ulong error_inject_value; #endif extern ulong slave_open_temp_tables; extern ulong query_cache_size, query_cache_min_res_unit; From 1c6f84f8284a297c166c1a53ab117df9b9a5239c Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Mar 2006 00:17:22 -0500 Subject: [PATCH 38/48] manual merge --- sql/partition_element.h | 6 +++++- sql/partition_info.h | 9 +++++++-- sql/sql_partition.cc | 4 ++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/sql/partition_element.h b/sql/partition_element.h index d20715d2408..f822f266d4c 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -36,6 +36,8 @@ enum partition_state { PART_IS_ADDED= 8 }; +struct st_table_log_memory_entry; + class partition_element :public Sql_alloc { public: List subpartitions; @@ -44,6 +46,7 @@ public: ulonglong part_min_rows; char *partition_name; char *tablespace_name; + struct st_table_log_memory_entry *log_entry; longlong range_value; char* part_comment; char* data_file_name; @@ -55,7 +58,8 @@ public: partition_element() : part_max_rows(0), part_min_rows(0), partition_name(NULL), - tablespace_name(NULL), range_value(0), part_comment(NULL), + tablespace_name(NULL), log_entry(NULL), + range_value(0), part_comment(NULL), data_file_name(NULL), index_file_name(NULL), engine_type(NULL),part_state(PART_NORMAL), nodegroup_id(UNDEF_NODEGROUP), has_null_value(FALSE) diff --git a/sql/partition_info.h b/sql/partition_info.h index 69aef512a67..eec7db90ad0 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -28,7 +28,7 @@ typedef int (*get_part_id_func)(partition_info *part_info, longlong *func_value); typedef uint32 (*get_subpart_id_func)(partition_info *part_info); - +struct st_table_log_memory_entry; class partition_info : public Sql_alloc { @@ -76,7 +76,11 @@ public: Item *subpart_expr; Item *item_free_list; - + + struct st_table_log_memory_entry *first_log_entry; + struct st_table_log_memory_entry *exec_log_entry; + struct st_table_log_memory_entry *frm_log_entry; + /* A bitmap of partitions used by the current query. Usage pattern: @@ -191,6 +195,7 @@ public: part_field_array(NULL), subpart_field_array(NULL), full_part_field_array(NULL), part_expr(NULL), subpart_expr(NULL), item_free_list(NULL), + first_log_entry(NULL), exec_log_entry(NULL), frm_log_entry(NULL), list_array(NULL), part_info_string(NULL), part_func_string(NULL), subpart_func_string(NULL), diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index a02216a113c..57e6a986987 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5157,7 +5157,7 @@ write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, if (part_elem->part_state == PART_IS_CHANGED || (part_elem->part_state == PART_IS_ADDED && temp_partitions)) { - if (is_sub_partitioned(part_info)) + if (part_info->is_sub_partitioned()) { List_iterator sub_it(part_elem->subpartitions); uint no_subparts= part_info->no_subparts; @@ -5271,7 +5271,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, name_variant= TEMP_PART_NAME; else name_variant= NORMAL_PART_NAME; - if (is_sub_partitioned(part_info)) + if (part_info->is_sub_partitioned()) { List_iterator sub_it(part_elem->subpartitions); uint no_subparts= part_info->no_subparts; From 81a463adeb9c5c3ed1dd6162cc097c93927156cb Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Mar 2006 10:52:12 -0500 Subject: [PATCH 39/48] OPTIMIZE, ANALYZE, CHECK, REPAIR and REBUILD only supported if fast_alter_partition flag set mysql-test/r/ndb_partition_key.result: New test cases for BUG #16819, 16821, and 16822 mysql-test/t/ndb_partition_key.test: New test cases for BUG #16819, 16821, and 16822 sql/handler.h: ensure we don't get hanging after calling change_partition --- mysql-test/r/ndb_partition_key.result | 14 ++++++++++++++ mysql-test/t/ndb_partition_key.test | 19 +++++++++++++++++++ sql/handler.h | 2 +- sql/sql_partition.cc | 5 +++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/ndb_partition_key.result b/mysql-test/r/ndb_partition_key.result index 87b019c83e2..121bbe45ead 100644 --- a/mysql-test/r/ndb_partition_key.result +++ b/mysql-test/r/ndb_partition_key.result @@ -165,3 +165,17 @@ ENGINE=NDB PARTITION BY KEY(c3) PARTITIONS 5; ALTER TABLE t1 COALESCE PARTITION 4; DROP TABLE t1; +CREATE TABLE t1 (a int primary key) +ENGINE=NDB +PARTITION BY KEY(a); +ALTER TABLE t1 OPTIMIZE PARTITION p0; +ERROR HY000: Table storage engine for 't1' doesn't have this option +ALTER TABLE t1 CHECK PARTITION p0; +ERROR HY000: Table storage engine for 't1' doesn't have this option +ALTER TABLE t1 REPAIR PARTITION p0; +ERROR HY000: Table storage engine for 't1' doesn't have this option +ALTER TABLE t1 ANALYZE PARTITION p0; +ERROR HY000: Table storage engine for 't1' doesn't have this option +ALTER TABLE t1 REBUILD PARTITION p0; +ERROR HY000: Table storage engine for 't1' doesn't have this option +DROP TABLE t1; diff --git a/mysql-test/t/ndb_partition_key.test b/mysql-test/t/ndb_partition_key.test index d43dc7e49e4..0fd99f8674e 100644 --- a/mysql-test/t/ndb_partition_key.test +++ b/mysql-test/t/ndb_partition_key.test @@ -153,3 +153,22 @@ b'0', ALTER TABLE t1 COALESCE PARTITION 4; DROP TABLE t1; + +# +# Bug 16822: OPTIMIZE TABLE hangs test +# +CREATE TABLE t1 (a int primary key) +ENGINE=NDB +PARTITION BY KEY(a); +--error 1031 +ALTER TABLE t1 OPTIMIZE PARTITION p0; +--error 1031 +ALTER TABLE t1 CHECK PARTITION p0; +--error 1031 +ALTER TABLE t1 REPAIR PARTITION p0; +--error 1031 +ALTER TABLE t1 ANALYZE PARTITION p0; +--error 1031 +ALTER TABLE t1 REBUILD PARTITION p0; +DROP TABLE t1; + diff --git a/sql/handler.h b/sql/handler.h index a7a12c225d4..50088af1d28 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1387,7 +1387,7 @@ public: ulonglong *deleted, const void *pack_frm_data, uint pack_frm_len) - { return HA_ERR_WRONG_COMMAND; } + { print_error(HA_ERR_WRONG_COMMAND, MYF(0)); return TRUE; } virtual int drop_partitions(const char *path) { return HA_ERR_WRONG_COMMAND; } virtual int rename_partitions(const char *path) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 57e6a986987..552c99518b7 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4499,6 +4499,11 @@ that are reorganised. my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), ptr); DBUG_RETURN(TRUE); } + if (!(*fast_alter_partition)) + { + table->file->print_error(HA_ERR_WRONG_COMMAND, MYF(0)); + DBUG_RETURN(TRUE); + } } else if (alter_info->flags & ALTER_COALESCE_PARTITION) { From 3928d9620fcf96adc94c2d13a7fd216c338eb928 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 24 Mar 2006 18:19:13 -0500 Subject: [PATCH 40/48] WL 2826: Error handling of ALTER TABLE for partitioning Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter Fixed mysqlish method intro's Fixed warning statements 5.1.7 was released still with partition states in clear text Fixed io_size bug Fixed bug in open that TRUNCATED before reading :) file_entry => file_entry_buf Don't open DDL log until first write call to DDL log handler_type => handler_name no => num sql/ha_partition.cc: Loads of review comments fixed inactivate => deactivate table log => ddl log sql/mysql_priv.h: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter sql/mysqld.cc: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter sql/partition_element.h: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter sql/partition_info.h: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter sql/share/errmsg.txt: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter sql/sql_base.cc: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter sql/sql_partition.cc: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter Fixed mysqlish method intro's Fixed warning statements sql/sql_table.cc: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter Fixed mysqlish method intro's Fixed warning statements Fixed io_size bug Fixed bug in open that TRUNCATED before reading :) file_entry => file_entry_buf Don't open DDL log until first write call to DDL log handler_type => handler_name no => num sql/table.cc: Loads of review comments fixed inactivate => deactivate table log => ddl log Commented on Error Inject Module added Put various #defines into enums Fixed abort_and_upgrade_lock, removed unnecessary parameter Fixed mysqlish method intro's Fixed warning statements 5.1.7 was released still with partition states in clear text Fixed io_size bug Fixed bug in open that TRUNCATED before reading :) file_entry => file_entry_buf Don't open DDL log until first write call to DDL log handler_type => handler_name no => num --- sql/ha_partition.cc | 20 +- sql/mysql_priv.h | 133 ++++++--- sql/mysqld.cc | 4 +- sql/partition_element.h | 4 +- sql/partition_info.h | 8 +- sql/share/errmsg.txt | 4 +- sql/sql_base.cc | 11 +- sql/sql_partition.cc | 496 ++++++++++++++----------------- sql/sql_table.cc | 628 ++++++++++++++++++++-------------------- sql/table.cc | 5 +- 10 files changed, 659 insertions(+), 654 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 8351e3e5d01..f3585ff9c5a 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -701,7 +701,7 @@ int ha_partition::rename_partitions(const char *path) DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); if ((ret_error= file->delete_table((const char *) norm_name_buff))) error= ret_error; - else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + else if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos)) error= 1; else sub_elem->log_entry= NULL; /* Indicate success */ @@ -716,13 +716,13 @@ int ha_partition::rename_partitions(const char *path) DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); if ((ret_error= file->delete_table((const char *) norm_name_buff))) error= ret_error; - else if (inactivate_table_log_entry(part_elem->log_entry->entry_pos)) + else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) error= 1; else part_elem->log_entry= NULL; /* Indicate success */ } } while (++i < temp_partitions); - VOID(sync_table_log()); + VOID(sync_ddl_log()); } i= 0; do @@ -771,9 +771,9 @@ int ha_partition::rename_partitions(const char *path) DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); if ((ret_error= file->delete_table((const char *) norm_name_buff))) error= ret_error; - else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + else if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos)) error= 1; - VOID(sync_table_log()); + VOID(sync_ddl_log()); } file= m_new_file[part]; create_subpartition_name(part_name_buff, path, @@ -785,7 +785,7 @@ int ha_partition::rename_partitions(const char *path) if ((ret_error= file->rename_table((const char *) part_name_buff, (const char *) norm_name_buff))) error= ret_error; - else if (inactivate_table_log_entry(sub_elem->log_entry->entry_pos)) + else if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos)) error= 1; else sub_elem->log_entry= NULL; @@ -802,9 +802,9 @@ int ha_partition::rename_partitions(const char *path) DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); if ((ret_error= file->delete_table((const char *) norm_name_buff))) error= ret_error; - else if (inactivate_table_log_entry(part_elem->log_entry->entry_pos)) + else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) error= 1; - VOID(sync_table_log()); + VOID(sync_ddl_log()); } file= m_new_file[i]; create_partition_name(part_name_buff, path, @@ -815,14 +815,14 @@ int ha_partition::rename_partitions(const char *path) if ((ret_error= file->rename_table((const char *) part_name_buff, (const char *) norm_name_buff))) error= ret_error; - else if (inactivate_table_log_entry(part_elem->log_entry->entry_pos)) + else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) error= 1; else part_elem->log_entry= NULL; } } } while (++i < no_parts); - VOID(sync_table_log()); + VOID(sync_ddl_log()); DBUG_RETURN(error); } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index d8bac64faca..265d2840025 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -631,9 +631,6 @@ struct Query_cache_query_flags #else -#define SET_ERROR_INJECT_VALUE(x) \ - current_thd->error_inject_value= (x) - inline bool my_error_inject_name(const char *dbug_str) { @@ -661,6 +658,43 @@ my_error_inject(int value) return 0; } +/* + ERROR INJECT MODULE: + -------------------- + These macros are used to insert macros from the application code. + The event that activates those error injections can be activated + from SQL by using: + SET SESSION dbug=+d,code; + + After the error has been injected, the macros will automatically + remove the debug code, thus similar to using: + SET SESSION dbug=-d,code + from SQL. + + ERROR_INJECT_CRASH will inject a crash of the MySQL Server if code + is set when macro is called. ERROR_INJECT_CRASH can be used in + if-statements, it will always return FALSE unless of course it + crashes in which case it doesn't return at all. + + ERROR_INJECT_ACTION will inject the action specified in the action + parameter of the macro, before performing the action the code will + be removed such that no more events occur. ERROR_INJECT_ACTION + can also be used in if-statements and always returns FALSE. + ERROR_INJECT can be used in a normal if-statement, where the action + part is performed in the if-block. The macro returns TRUE if the + error was activated and otherwise returns FALSE. If activated the + code is removed. + + Sometimes it is necessary to perform error inject actions as a serie + of events. In this case one can use one variable on the THD object. + Thus one sets this value by using e.g. SET_ERROR_INJECT_VALUE(100). + Then one can later test for it by using ERROR_INJECT_CRASH_VALUE, + ERROR_INJECT_ACTION_VALUE and ERROR_INJECT_VALUE. This have the same + behaviour as the above described macros except that they use the + error inject value instead of a code used by DBUG macros. +*/ +#define SET_ERROR_INJECT_VALUE(x) \ + current_thd->error_inject_value= (x) #define ERROR_INJECT_CRASH(code) \ DBUG_EVALUATE_IF(code, (abort(), 0), 0) #define ERROR_INJECT_ACTION(code, action) \ @@ -1186,57 +1220,86 @@ typedef struct st_lock_param_type void mem_alloc_error(size_t size); -typedef struct st_table_log_entry +enum ddl_log_entry_code +{ + /* + DDL_LOG_EXECUTE_CODE: + This is a code that indicates that this is a log entry to + be executed, from this entry a linked list of log entries + can be found and executed. + DDL_LOG_ENTRY_CODE: + An entry to be executed in a linked list from an execute log + entry. + DDL_IGNORE_LOG_ENTRY_CODE: + An entry that is to be ignored + */ + DDL_LOG_EXECUTE_CODE = 'e', + DDL_LOG_ENTRY_CODE = 'l', + DDL_IGNORE_LOG_ENTRY_CODE = 'i' +}; + +enum ddl_log_action_code +{ + /* + The type of action that a DDL_LOG_ENTRY_CODE entry is to + perform. + DDL_LOG_DELETE_ACTION: + Delete an entity + DDL_LOG_RENAME_ACTION: + Rename an entity + DDL_LOG_REPLACE_ACTION: + Rename an entity after removing the previous entry with the + new name, that is replace this entry. + */ + DDL_LOG_DELETE_ACTION = 'd', + DDL_LOG_RENAME_ACTION = 'r', + DDL_LOG_REPLACE_ACTION = 's' +}; + + +typedef struct st_ddl_log_entry { const char *name; const char *from_name; - const char *handler_type; + const char *handler_name; uint next_entry; uint entry_pos; - char action_type; - char entry_type; + enum ddl_log_entry_code entry_type; + enum ddl_log_action_code action_type; char phase; - char not_used; -} TABLE_LOG_ENTRY; +} DDL_LOG_ENTRY; -typedef struct st_table_log_memory_entry +typedef struct st_ddl_log_memory_entry { uint entry_pos; - struct st_table_log_memory_entry *next_log_entry; - struct st_table_log_memory_entry *prev_log_entry; - struct st_table_log_memory_entry *next_active_log_entry; -} TABLE_LOG_MEMORY_ENTRY; + struct st_ddl_log_memory_entry *next_log_entry; + struct st_ddl_log_memory_entry *prev_log_entry; + struct st_ddl_log_memory_entry *next_active_log_entry; +} DDL_LOG_MEMORY_ENTRY; -#define TLOG_EXECUTE_CODE 'e' -#define TLOG_LOG_ENTRY_CODE 'l' -#define TLOG_IGNORE_LOG_ENTRY_CODE 'i' -#define TLOG_DELETE_ACTION_CODE 'd' -#define TLOG_RENAME_ACTION_CODE 'r' -#define TLOG_REPLACE_ACTION_CODE 's' -#define TLOG_HANDLER_TYPE_LEN 32 +#define DDL_LOG_HANDLER_TYPE_LEN 32 -bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, - TABLE_LOG_MEMORY_ENTRY **active_entry); -bool write_execute_table_log_entry(uint first_entry, +bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, + DDL_LOG_MEMORY_ENTRY **active_entry); +bool write_execute_ddl_log_entry(uint first_entry, bool complete, - TABLE_LOG_MEMORY_ENTRY **active_entry); -bool inactivate_table_log_entry(uint entry_no); -void release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry); -bool sync_table_log(); -void release_table_log(); -void execute_table_log_recovery(); -bool execute_table_log_entry(uint first_entry); -void lock_global_table_log(); -void unlock_global_table_log(); + DDL_LOG_MEMORY_ENTRY **active_entry); +bool deactivate_ddl_log_entry(uint entry_no); +void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry); +bool sync_ddl_log(); +void release_ddl_log(); +void execute_ddl_log_recovery(); +bool execute_ddl_log_entry(uint first_entry); +void lock_global_ddl_log(); +void unlock_global_ddl_log(); #define WFRM_WRITE_SHADOW 1 #define WFRM_INSTALL_SHADOW 2 #define WFRM_PACK_FRM 4 bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags); -bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt, - bool can_be_killed); +void abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt); void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt); void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 41233849094..a262b369ae3 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3665,7 +3665,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); unireg_abort(1); } } - execute_table_log_recovery(); + execute_ddl_log_recovery(); create_shutdown_thread(); create_maintenance_thread(); @@ -3696,7 +3696,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); /* (void) pthread_attr_destroy(&connection_attrib); */ DBUG_PRINT("quit",("Exiting main thread")); - release_table_log(); + release_ddl_log(); #ifndef __WIN__ #ifdef EXTRA_DEBUG2 diff --git a/sql/partition_element.h b/sql/partition_element.h index f822f266d4c..13693934c0f 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -36,7 +36,7 @@ enum partition_state { PART_IS_ADDED= 8 }; -struct st_table_log_memory_entry; +struct st_ddl_log_memory_entry; class partition_element :public Sql_alloc { public: @@ -46,7 +46,7 @@ public: ulonglong part_min_rows; char *partition_name; char *tablespace_name; - struct st_table_log_memory_entry *log_entry; + struct st_ddl_log_memory_entry *log_entry; longlong range_value; char* part_comment; char* data_file_name; diff --git a/sql/partition_info.h b/sql/partition_info.h index eec7db90ad0..829f5f9b72c 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -28,7 +28,7 @@ typedef int (*get_part_id_func)(partition_info *part_info, longlong *func_value); typedef uint32 (*get_subpart_id_func)(partition_info *part_info); -struct st_table_log_memory_entry; +struct st_ddl_log_memory_entry; class partition_info : public Sql_alloc { @@ -77,9 +77,9 @@ public: Item *item_free_list; - struct st_table_log_memory_entry *first_log_entry; - struct st_table_log_memory_entry *exec_log_entry; - struct st_table_log_memory_entry *frm_log_entry; + struct st_ddl_log_memory_entry *first_log_entry; + struct st_ddl_log_memory_entry *exec_log_entry; + struct st_ddl_log_memory_entry *frm_log_entry; /* A bitmap of partitions used by the current query. diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index b05a57f714e..9aa4d2f74eb 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5826,5 +5826,5 @@ ER_NDB_CANT_SWITCH_BINLOG_FORMAT eng "The NDB cluster engine does not support changing the binlog format on the fly yet" ER_PARTITION_NO_TEMPORARY eng "Cannot create temporary table with partitions" -ER_TABLE_LOG_ERROR - eng "Error in table log" +ER_DDL_LOG_ERROR + eng "Error in DDL log" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5419416ef3c..ed893f35aec 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6124,24 +6124,17 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b) old_lock_level Old lock level */ -bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt, - bool can_be_killed) +void abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) { uint flags= RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG; - int error= FALSE; DBUG_ENTER("abort_and_upgrade_locks"); lpt->old_lock_type= lpt->table->reginfo.lock_type; VOID(pthread_mutex_lock(&LOCK_open)); mysql_lock_abort(lpt->thd, lpt->table, TRUE); VOID(remove_table_from_cache(lpt->thd, lpt->db, lpt->table_name, flags)); - if (can_be_killed && lpt->thd->killed) - { - lpt->thd->no_warnings_for_error= 0; - error= TRUE; - } VOID(pthread_mutex_unlock(&LOCK_open)); - DBUG_RETURN(error); + DBUG_VOID_RETURN; } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 552c99518b7..682b9f783ba 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5037,10 +5037,8 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) NONE */ -static -void -insert_part_info_log_entry_list(partition_info *part_info, - TABLE_LOG_MEMORY_ENTRY *log_entry) +static void insert_part_info_log_entry_list(partition_info *part_info, + DDL_LOG_MEMORY_ENTRY *log_entry) { log_entry->next_active_log_entry= part_info->first_log_entry; part_info->first_log_entry= log_entry; @@ -5056,15 +5054,13 @@ insert_part_info_log_entry_list(partition_info *part_info, NONE */ -static -void -release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) +static void release_part_info_log_entries(DDL_LOG_MEMORY_ENTRY *log_entry) { DBUG_ENTER("release_part_info_log_entries"); while (log_entry) { - release_table_log_memory_entry(log_entry); + release_ddl_log_memory_entry(log_entry); log_entry= log_entry->next_active_log_entry; } DBUG_VOID_RETURN; @@ -5084,32 +5080,30 @@ release_part_info_log_entries(TABLE_LOG_MEMORY_ENTRY *log_entry) FALSE Success DESCRIPTION Support routine that writes a replace or delete of an frm file into the - table log. It also inserts an entry that keeps track of used space into + ddl log. It also inserts an entry that keeps track of used space into the partition info object */ -static -bool -write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, - uint next_entry, - const char *from_path, - const char *to_path, - bool replace_flag) +static bool write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, + uint next_entry, + const char *from_path, + const char *to_path, + bool replace_flag) { - TABLE_LOG_ENTRY table_log_entry; - TABLE_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_ENTRY ddl_log_entry; + DDL_LOG_MEMORY_ENTRY *log_entry; DBUG_ENTER("write_log_replace_delete_frm"); if (replace_flag) - table_log_entry.action_type= TLOG_REPLACE_ACTION_CODE; + ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION; else - table_log_entry.action_type= TLOG_DELETE_ACTION_CODE; - table_log_entry.next_entry= next_entry; - table_log_entry.handler_type= "frm"; - table_log_entry.name= to_path; + ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION; + ddl_log_entry.next_entry= next_entry; + ddl_log_entry.handler_name= "frm"; + ddl_log_entry.name= to_path; if (replace_flag) - table_log_entry.from_name= from_path; - if (write_table_log_entry(&table_log_entry, &log_entry)) + ddl_log_entry.from_name= from_path; + if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) { DBUG_RETURN(TRUE); } @@ -5140,14 +5134,12 @@ write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, the partition handler. */ -static -bool -write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, - uint *next_entry, const char *path) +static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, + uint *next_entry, const char *path) { - TABLE_LOG_ENTRY table_log_entry; + DDL_LOG_ENTRY ddl_log_entry; partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *log_entry; char tmp_path[FN_LEN]; char normal_path[FN_LEN]; List_iterator part_it(part_info->partitions); @@ -5170,8 +5162,8 @@ write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, do { partition_element *sub_elem= sub_it++; - table_log_entry.next_entry= *next_entry; - table_log_entry.handler_type= + ddl_log_entry.next_entry= *next_entry; + ddl_log_entry.handler_name= ha_resolve_storage_engine_name(sub_elem->engine_type); create_subpartition_name(tmp_path, path, part_elem->partition_name, @@ -5181,13 +5173,13 @@ write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, part_elem->partition_name, sub_elem->partition_name, NORMAL_PART_NAME); - table_log_entry.name= normal_path; - table_log_entry.from_name= tmp_path; + ddl_log_entry.name= normal_path; + ddl_log_entry.from_name= tmp_path; if (part_elem->part_state == PART_IS_CHANGED) - table_log_entry.action_type= TLOG_REPLACE_ACTION_CODE; + ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION; else - table_log_entry.action_type= TLOG_RENAME_ACTION_CODE; - if (write_table_log_entry(&table_log_entry, &log_entry)) + ddl_log_entry.action_type= DDL_LOG_RENAME_ACTION; + if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) { DBUG_RETURN(TRUE); } @@ -5198,8 +5190,8 @@ write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, } else { - table_log_entry.next_entry= *next_entry; - table_log_entry.handler_type= + ddl_log_entry.next_entry= *next_entry; + ddl_log_entry.handler_name= ha_resolve_storage_engine_name(part_elem->engine_type); create_partition_name(tmp_path, path, part_elem->partition_name, @@ -5207,13 +5199,13 @@ write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, create_partition_name(normal_path, path, part_elem->partition_name, NORMAL_PART_NAME, TRUE); - table_log_entry.name= normal_path; - table_log_entry.from_name= tmp_path; + ddl_log_entry.name= normal_path; + ddl_log_entry.from_name= tmp_path; if (part_elem->part_state == PART_IS_CHANGED) - table_log_entry.action_type= TLOG_REPLACE_ACTION_CODE; + ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION; else - table_log_entry.action_type= TLOG_RENAME_ACTION_CODE; - if (write_table_log_entry(&table_log_entry, &log_entry)) + ddl_log_entry.action_type= DDL_LOG_RENAME_ACTION; + if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) { DBUG_RETURN(TRUE); } @@ -5237,16 +5229,14 @@ write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, FALSE Success */ -static -bool -write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, - uint *next_entry, - const char *path, - bool temp_list) +static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, + uint *next_entry, + const char *path, + bool temp_list) { - TABLE_LOG_ENTRY table_log_entry; + DDL_LOG_ENTRY ddl_log_entry; partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *log_entry; char tmp_path[FN_LEN]; List_iterator part_it(part_info->partitions); List_iterator temp_it(part_info->temp_partitions); @@ -5255,7 +5245,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, uint i= 0; DBUG_ENTER("write_log_dropped_partitions"); - table_log_entry.action_type= TLOG_DELETE_ACTION_CODE; + ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION; if (temp_list) no_elements= no_temp_partitions; while (no_elements--) @@ -5284,15 +5274,15 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, do { partition_element *sub_elem= sub_it++; - table_log_entry.next_entry= *next_entry; - table_log_entry.handler_type= + ddl_log_entry.next_entry= *next_entry; + ddl_log_entry.handler_name= ha_resolve_storage_engine_name(sub_elem->engine_type); create_subpartition_name(tmp_path, path, part_elem->partition_name, sub_elem->partition_name, name_variant); - table_log_entry.name= tmp_path; - if (write_table_log_entry(&table_log_entry, &log_entry)) + ddl_log_entry.name= tmp_path; + if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) { DBUG_RETURN(TRUE); } @@ -5304,14 +5294,14 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, } else { - table_log_entry.next_entry= *next_entry; - table_log_entry.handler_type= + ddl_log_entry.next_entry= *next_entry; + ddl_log_entry.handler_name= ha_resolve_storage_engine_name(part_elem->engine_type); create_partition_name(tmp_path, path, part_elem->partition_name, name_variant, TRUE); - table_log_entry.name= tmp_path; - if (write_table_log_entry(&table_log_entry, &log_entry)) + ddl_log_entry.name= tmp_path; + if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) { DBUG_RETURN(TRUE); } @@ -5327,7 +5317,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, /* - Set execute log entry in table log for this partitioned table + Set execute log entry in ddl log for this partitioned table SYNOPSIS set_part_info_exec_log_entry() part_info Partition info object @@ -5336,10 +5326,8 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, NONE */ -static -void -set_part_info_exec_log_entry(partition_info *part_info, - TABLE_LOG_MEMORY_ENTRY *exec_log_entry) +static void set_part_info_exec_log_entry(partition_info *part_info, + DDL_LOG_MEMORY_ENTRY *exec_log_entry) { part_info->exec_log_entry= exec_log_entry; exec_log_entry->next_active_log_entry= NULL; @@ -5358,41 +5346,38 @@ set_part_info_exec_log_entry(partition_info *part_info, TRUE Error FALSE Success DESCRIPTION - Prepare an entry to the table log indicating a drop/install of the shadow frm + Prepare an entry to the ddl log indicating a drop/install of the shadow frm file and its corresponding handler file. */ -static -bool -write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) +static bool write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) { - TABLE_LOG_ENTRY table_log_entry; + DDL_LOG_ENTRY ddl_log_entry; partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry; - TABLE_LOG_MEMORY_ENTRY *exec_log_entry= NULL; + DDL_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *exec_log_entry= NULL; char shadow_path[FN_LEN]; DBUG_ENTER("write_log_drop_shadow_frm"); build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); - lock_global_table_log(); - do - { - if (write_log_replace_delete_frm(lpt, 0UL, NULL, - (const char*)shadow_path, FALSE)) - break; - log_entry= part_info->first_log_entry; - if (write_execute_table_log_entry(log_entry->entry_pos, - FALSE, &exec_log_entry)) - break; - unlock_global_table_log(); - set_part_info_exec_log_entry(part_info, exec_log_entry); - DBUG_RETURN(FALSE); - } while (TRUE); + lock_global_ddl_log(); + if (write_log_replace_delete_frm(lpt, 0UL, NULL, + (const char*)shadow_path, FALSE)) + goto error; + log_entry= part_info->first_log_entry; + if (write_execute_ddl_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + goto error; + unlock_global_ddl_log(); + set_part_info_exec_log_entry(part_info, exec_log_entry); + DBUG_RETURN(FALSE); + +error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_table_log(); + unlock_global_ddl_log(); part_info->first_log_entry= NULL; - my_error(ER_TABLE_LOG_ERROR, MYF(0)); + my_error(ER_DDL_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5410,17 +5395,15 @@ write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) file if failure occurs in the middle of the rename process. */ -static -bool -write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) +static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) { - TABLE_LOG_ENTRY table_log_entry; + DDL_LOG_ENTRY ddl_log_entry; partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry; - TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + DDL_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; char path[FN_LEN]; char shadow_path[FN_LEN]; - TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; + DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; DBUG_ENTER("write_log_rename_frm"); part_info->first_log_entry= NULL; @@ -5428,25 +5411,24 @@ write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table_name, ""); build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); - lock_global_table_log(); - do - { - if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) - break; - log_entry= part_info->first_log_entry; - part_info->frm_log_entry= log_entry; - if (write_execute_table_log_entry(log_entry->entry_pos, - FALSE, &exec_log_entry)) - break; - release_part_info_log_entries(old_first_log_entry); - unlock_global_table_log(); - DBUG_RETURN(FALSE); - } while (TRUE); + lock_global_ddl_log(); + if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) + goto error; + log_entry= part_info->first_log_entry; + part_info->frm_log_entry= log_entry; + if (write_execute_ddl_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + goto error; + release_part_info_log_entries(old_first_log_entry); + unlock_global_ddl_log(); + DBUG_RETURN(FALSE); + +error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_table_log(); + unlock_global_ddl_log(); part_info->first_log_entry= old_first_log_entry; part_info->frm_log_entry= NULL; - my_error(ER_TABLE_LOG_ERROR, MYF(0)); + my_error(ER_DDL_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5462,22 +5444,20 @@ write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) TRUE Error FALSE Success DESCRIPTION - Prepare entries to the table log indicating all partitions to drop and to + Prepare entries to the ddl log indicating all partitions to drop and to install the shadow frm file and remove the old frm file. */ -static -bool -write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { - TABLE_LOG_ENTRY table_log_entry; + DDL_LOG_ENTRY ddl_log_entry; partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry; - TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + DDL_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; char tmp_path[FN_LEN]; char path[FN_LEN]; uint next_entry= 0; - TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; + DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; DBUG_ENTER("write_log_drop_partition"); part_info->first_log_entry= NULL; @@ -5485,29 +5465,28 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table_name, ""); build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, lpt->table_name, "#"); - lock_global_table_log(); - do - { - if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, - FALSE)) - break; - if (write_log_replace_delete_frm(lpt, next_entry, (const char*)path, - (const char*)tmp_path, TRUE)) - break; - log_entry= part_info->first_log_entry; - part_info->frm_log_entry= log_entry; - if (write_execute_table_log_entry(log_entry->entry_pos, - FALSE, &exec_log_entry)) - break; - release_part_info_log_entries(old_first_log_entry); - unlock_global_table_log(); - DBUG_RETURN(FALSE); - } while (TRUE); + lock_global_ddl_log(); + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, + FALSE)) + goto error; + if (write_log_replace_delete_frm(lpt, next_entry, (const char*)path, + (const char*)tmp_path, TRUE)) + goto error; + log_entry= part_info->first_log_entry; + part_info->frm_log_entry= log_entry; + if (write_execute_ddl_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + goto error; + release_part_info_log_entries(old_first_log_entry); + unlock_global_ddl_log(); + DBUG_RETURN(FALSE); + +error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_table_log(); + unlock_global_ddl_log(); part_info->first_log_entry= old_first_log_entry; part_info->frm_log_entry= NULL; - my_error(ER_TABLE_LOG_ERROR, MYF(0)); + my_error(ER_DDL_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5523,19 +5502,17 @@ write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) TRUE Error FALSE Success DESCRIPTION - Prepare entries to the table log indicating all partitions to drop and to + Prepare entries to the ddl log indicating all partitions to drop and to remove the shadow frm file. - We always inject entries backwards in the list in the table log since we + We always inject entries backwards in the list in the ddl log since we don't know the entry position until we have written it. */ -static -bool -write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry; - TABLE_LOG_MEMORY_ENTRY *exec_log_entry= NULL; + DDL_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *exec_log_entry= NULL; char tmp_path[FN_LEN]; char path[FN_LEN]; uint next_entry= 0; @@ -5545,27 +5522,26 @@ write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table_name, ""); build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, lpt->table_name, "#"); - lock_global_table_log(); - do - { - if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, - FALSE)) - break; - if (write_log_replace_delete_frm(lpt, next_entry, NULL, tmp_path, - FALSE)) - break; - log_entry= part_info->first_log_entry; - if (write_execute_table_log_entry(log_entry->entry_pos, - FALSE, &exec_log_entry)) - break; - unlock_global_table_log(); - set_part_info_exec_log_entry(part_info, exec_log_entry); - DBUG_RETURN(FALSE); - } while (TRUE); + lock_global_ddl_log(); + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, + FALSE)) + goto error; + if (write_log_replace_delete_frm(lpt, next_entry, NULL, tmp_path, + FALSE)) + goto error; + log_entry= part_info->first_log_entry; + if (write_execute_ddl_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + goto error; + unlock_global_ddl_log(); + set_part_info_exec_log_entry(part_info, exec_log_entry); + DBUG_RETURN(FALSE); + +error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_table_log(); + unlock_global_ddl_log(); part_info->first_log_entry= NULL; - my_error(ER_TABLE_LOG_ERROR, MYF(0)); + my_error(ER_DDL_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } @@ -5586,17 +5562,15 @@ write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) frm file. */ -static -bool -write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) { - TABLE_LOG_ENTRY table_log_entry; + DDL_LOG_ENTRY ddl_log_entry; partition_info *part_info= lpt->part_info; - TABLE_LOG_MEMORY_ENTRY *log_entry; - TABLE_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + DDL_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; char path[FN_LEN]; char shadow_path[FN_LEN]; - TABLE_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; + DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; uint next_entry= 0; DBUG_ENTER("write_log_final_change_partition"); @@ -5605,36 +5579,35 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table_name, ""); build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); - lock_global_table_log(); - do - { - if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, - TRUE)) - break; - if (write_log_changed_partitions(lpt, &next_entry, (const char*)path)) - break; - if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) - break; - log_entry= part_info->first_log_entry; - part_info->frm_log_entry= log_entry; - if (write_execute_table_log_entry(log_entry->entry_pos, - FALSE, &exec_log_entry)) - break; - release_part_info_log_entries(old_first_log_entry); - unlock_global_table_log(); - DBUG_RETURN(FALSE); - } while (TRUE); + lock_global_ddl_log(); + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, + TRUE)) + goto error; + if (write_log_changed_partitions(lpt, &next_entry, (const char*)path)) + goto error; + if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) + goto error; + log_entry= part_info->first_log_entry; + part_info->frm_log_entry= log_entry; + if (write_execute_ddl_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + goto error; + release_part_info_log_entries(old_first_log_entry); + unlock_global_ddl_log(); + DBUG_RETURN(FALSE); + +error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_table_log(); + unlock_global_ddl_log(); part_info->first_log_entry= old_first_log_entry; part_info->frm_log_entry= NULL; - my_error(ER_TABLE_LOG_ERROR, MYF(0)); + my_error(ER_DDL_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); } /* - Remove entry from table log and release resources for others to use + Remove entry from ddl log and release resources for others to use SYNOPSIS write_log_completed() @@ -5644,37 +5617,30 @@ write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) FALSE Success */ -static -void -write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, bool dont_crash) +static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, + bool dont_crash) { partition_info *part_info= lpt->part_info; uint count_loop= 0; bool not_success; - TABLE_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry; + DDL_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry; DBUG_ENTER("write_log_completed"); DBUG_ASSERT(log_entry); - lock_global_table_log(); - do - { - if (!(not_success= write_execute_table_log_entry(0UL, TRUE, &log_entry))) - break; - my_sleep(1); - } while (count_loop++ < 20); - if (not_success && !dont_crash) + lock_global_ddl_log(); + if (write_execute_ddl_log_entry(0UL, TRUE, &log_entry)) { /* - Failed to write 20 consecutive attempts to write. Bad... + Failed to write, Bad... We have completed the operation but have log records to REMOVE stuff that shouldn't be removed. What clever things could one do here? */ - abort(); + ; } release_part_info_log_entries(part_info->first_log_entry); release_part_info_log_entries(part_info->exec_log_entry); - unlock_global_table_log(); + unlock_global_ddl_log(); part_info->exec_log_entry= NULL; part_info->first_log_entry= NULL; DBUG_VOID_RETURN; @@ -5690,14 +5656,12 @@ write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, bool dont_crash) NONE */ -static -void -release_log_entries(partition_info *part_info) +static void release_log_entries(partition_info *part_info) { - lock_global_table_log(); + lock_global_ddl_log(); release_part_info_log_entries(part_info->first_log_entry); release_part_info_log_entries(part_info->exec_log_entry); - unlock_global_table_log(); + unlock_global_ddl_log(); part_info->first_log_entry= NULL; part_info->exec_log_entry= NULL; } @@ -5713,43 +5677,41 @@ release_log_entries(partition_info *part_info) NONE */ -void -handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, - bool drop_partition, bool frm_install) +void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, + bool not_completed, + bool drop_partition, + bool frm_install) { partition_info *part_info= lpt->part_info; DBUG_ENTER("handle_alter_part_error"); if (!part_info->first_log_entry && - execute_table_log_entry(part_info->first_log_entry->entry_pos)) + execute_ddl_log_entry(part_info->first_log_entry->entry_pos)) { /* - We couldn't recover from error, most likely manual interaction is required. + We couldn't recover from error, most likely manual interaction + is required. */ write_log_completed(lpt, FALSE); release_log_entries(part_info); if (not_completed) { - char *text1= - (char*)"Operation was unsuccessful, table is still intact, "; if (drop_partition) { /* Table is still ok, but we left a shadow frm file behind. */ - char *text2= - (char*)"but it is possible that a shadow frm file was left behind"; push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "%s \n %s", text1, text2); + "%s %s", + "Operation was unsuccessful, table is still intact,", + "but it is possible that a shadow frm file was left behind"); } else { - char *text2= - (char*)"but it is possible that a shadow frm file was left behind."; - char *text3= - (char*)"It is also possible that temporary partitions are left behind, "; - char *text4= - (char*)"these could be empty or more or less filled with records"; push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "%s \n %s \n %s \n %s", text1, text2, text3, text4); + "%s %s %s %s", + "Operation was unsuccessful, table is still intact,", + "but it is possible that a shadow frm file was left behind.", + "It is also possible that temporary partitions are left behind,", + "these could be empty or more or less filled with records"); } } else @@ -5760,48 +5722,39 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, Failed during install of shadow frm file, table isn't intact and dropped partitions are still there */ - char *text1= - (char*)"Failed during alter of partitions, table is no longer intact, "; - char *text2= - (char*)"The frm file is in an unknown state, and a backup"; - char *text3= - (char*)" is required."; push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "%s \n %s%s\n", text1, text2, text3); + "%s %s %s", + "Failed during alter of partitions, table is no longer intact.", + "The frm file is in an unknown state, and a backup", + "is required."); } else if (drop_partition) { /* - Table is ok, we have switched to new table but left dropped partitions - still in their places. We remove the log records and ask the user to - perform the action manually. We remove the log records and ask the user - to perform the action manually. + Table is ok, we have switched to new table but left dropped + partitions still in their places. We remove the log records and + ask the user to perform the action manually. We remove the log + records and ask the user to perform the action manually. */ - char *text1= - (char*)"Failed during drop of partitions, table is intact, "; - char *text2= - (char*)"Manual drop of remaining partitions is required"; push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "%s\n%s", text1, text2); + "%s %s", + "Failed during drop of partitions, table is intact.", + "Manual drop of remaining partitions is required"); } else { /* - We failed during renaming of partitions. The table is most certainly in - a very bad state so we give user warning and disable the table by - writing an ancient frm version into it. + We failed during renaming of partitions. The table is most + certainly in a very bad state so we give user warning and disable + the table by writing an ancient frm version into it. */ - char *text1= - (char*)"Failed during renaming of partitions. We are now in a position"; - char *text2= - (char*)" where table is not reusable"; - char *text3= - (char*)"Table is disabled by writing ancient frm file version into it"; push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "%s%s\n%s", text1, text2, text3); + "%s %s %s", + "Failed during renaming of partitions. We are now in a position", + "where table is not reusable", + "Table is disabled by writing ancient frm file version into it"); } } - } else { @@ -5824,8 +5777,9 @@ handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool not_completed, even though we reported an error the operation was successfully completed. */ - push_warning(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, - "Operation was successfully completed after failure of normal operation"); + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1,"%s %s", + "Operation was successfully completed by failure handling,", + "after failure of normal operation"); } } DBUG_VOID_RETURN; @@ -5999,7 +5953,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 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 + 2) Write the ddl 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 @@ -6010,8 +5964,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 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 + ddl log but before writing the binlog. A solution to this would + require writing the statement first in the ddl 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 @@ -6019,7 +5973,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, reached the abort lock do that before downgrading the lock. 7) Prepare MyISAM handlers for drop of partitions 8) Drop the partitions - 9) Remove entries from table log + 9) Remove entries from ddl log 10) Wait until all accesses using the old frm file has completed 11) Complete query @@ -6033,7 +5987,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, write_log_drop_partition(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_3") || ((not_completed= FALSE), FALSE) || - (abort_and_upgrade_lock(lpt, FALSE), FALSE) || + (abort_and_upgrade_lock(lpt), FALSE) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || @@ -6070,7 +6024,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 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) Log the changes to happen in ddl 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 @@ -6082,7 +6036,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 6) Install the new frm file of the table where the partitions are added to the table. 7) Wait until all accesses using the old frm file has completed - 8) Remove entries from table log + 8) Remove entries from ddl log 9) Complete query */ if (write_log_add_change_partition(lpt) || @@ -6091,7 +6045,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_add_partition_2") || mysql_change_partitions(lpt) || ERROR_INJECT_CRASH("crash_add_partition_3") || - (abort_and_upgrade_lock(lpt, FALSE), FALSE) || + (abort_and_upgrade_lock(lpt), FALSE) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || @@ -6174,7 +6128,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, write_log_final_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_4") || ((not_completed= FALSE), FALSE) || - (abort_and_upgrade_lock(lpt, FALSE), FALSE) || + (abort_and_upgrade_lock(lpt), FALSE) || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7d2dfe6f78c..86a3259484a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -244,7 +244,7 @@ static int mysql_copy_key_list(List *orig_key, /* -------------------------------------------------------------------------- - MODULE: Table log + MODULE: DDL log ----------------- This module is used to ensure that we can recover from crashes that occur @@ -253,12 +253,12 @@ static int mysql_copy_key_list(List *orig_key, also that each table drop is entirely done and not "half-baked". To support this we create log entries for each meta-data statement in the - table log while we are executing. These entries are dropped when the + ddl log while we are executing. These entries are dropped when the operation is completed. At recovery those entries that were not completed will be executed. - There is only one table log in the system and it is protected by a mutex + There is only one ddl log in the system and it is protected by a mutex and there is a global struct that contains information about its current state. @@ -268,82 +268,79 @@ static int mysql_copy_key_list(List *orig_key, */ -typedef struct st_global_table_log +typedef struct st_global_ddl_log { - char file_entry[IO_SIZE]; + char file_entry_buf[4*IO_SIZE]; char file_name_str[FN_REFLEN]; char *file_name; - TABLE_LOG_MEMORY_ENTRY *first_free; - TABLE_LOG_MEMORY_ENTRY *first_used; - uint no_entries; + DDL_LOG_MEMORY_ENTRY *first_free; + DDL_LOG_MEMORY_ENTRY *first_used; + uint num_entries; File file_id; uint name_len; - uint handler_type_len; + uint handler_name_len; uint io_size; -} GLOBAL_TABLE_LOG; + bool inited; +} GLOBAL_DDL_LOG; -GLOBAL_TABLE_LOG global_table_log; +GLOBAL_DDL_LOG global_ddl_log; -pthread_mutex_t LOCK_gtl; +pthread_mutex_t LOCK_gdl; -#define TLOG_ENTRY_TYPE_POS 0 -#define TLOG_ACTION_TYPE_POS 1 -#define TLOG_PHASE_POS 2 -#define TLOG_NEXT_ENTRY_POS 4 -#define TLOG_NAME_POS 8 +#define DDL_LOG_ENTRY_TYPE_POS 0 +#define DDL_LOG_ACTION_TYPE_POS 1 +#define DDL_LOG_PHASE_POS 2 +#define DDL_LOG_NEXT_ENTRY_POS 4 +#define DDL_LOG_NAME_POS 8 -#define TLOG_NO_ENTRY_POS 0 -#define TLOG_NAME_LEN_POS 4 -#define TLOG_HANDLER_TYPE_POS 8 -#define TLOG_IO_SIZE_POS 12 +#define DDL_LOG_NUM_ENTRY_POS 0 +#define DDL_LOG_NAME_LEN_POS 4 +#define DDL_LOG_HANDLER_TYPE_POS 8 +#define DDL_LOG_IO_SIZE_POS 12 /* - Read one entry from table log file + Read one entry from ddl log file SYNOPSIS - read_table_log_file_entry() + read_ddl_log_file_entry() entry_no Entry number to read RETURN VALUES TRUE Error FALSE Success */ -static -bool -read_table_log_file_entry(uint entry_no) +static bool read_ddl_log_file_entry(uint entry_no) { bool error= FALSE; - File file_id= global_table_log.file_id; - char *file_entry= (char*)global_table_log.file_entry; - uint io_size= global_table_log.io_size; - DBUG_ENTER("read_table_log_file_entry"); + File file_id= global_ddl_log.file_id; + char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; + uint io_size= global_ddl_log.io_size; + DBUG_ENTER("read_ddl_log_file_entry"); - if (my_pread(file_id, file_entry, io_size, io_size * entry_no, - MYF(MY_WME)) != IO_SIZE) + if (my_pread(file_id, file_entry_buf, io_size, io_size * entry_no, + MYF(MY_WME)) != io_size) error= TRUE; DBUG_RETURN(error); } /* - Write one entry from table log file + Write one entry from ddl log file SYNOPSIS - write_table_log_file_entry() + write_ddl_log_file_entry() entry_no Entry number to read RETURN VALUES TRUE Error FALSE Success */ -static -bool -write_table_log_file_entry(uint entry_no) +static bool write_ddl_log_file_entry(uint entry_no) { bool error= FALSE; - File file_id= global_table_log.file_id; - char *file_entry= (char*)global_table_log.file_entry; - DBUG_ENTER("write_table_log_file_entry"); + File file_id= global_ddl_log.file_id; + char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; + DBUG_ENTER("write_ddl_log_file_entry"); - if (my_pwrite(file_id, file_entry, + if (my_pwrite(file_id, file_entry_buf, IO_SIZE, IO_SIZE * entry_no, MYF(MY_WME)) != IO_SIZE) error= TRUE; DBUG_RETURN(error); @@ -351,200 +348,197 @@ write_table_log_file_entry(uint entry_no) /* - Write table log header + Write ddl log header SYNOPSIS - write_table_log_header() + write_ddl_log_header() RETURN VALUES TRUE Error FALSE Success */ -static -bool -write_table_log_header() +static bool write_ddl_log_header() { uint16 const_var; bool error= FALSE; - DBUG_ENTER("write_table_log_header"); + DBUG_ENTER("write_ddl_log_header"); - int4store(&global_table_log.file_entry[TLOG_NO_ENTRY_POS], - global_table_log.no_entries); + int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NUM_ENTRY_POS], + global_ddl_log.num_entries); const_var= FN_LEN; - int4store(&global_table_log.file_entry[TLOG_NAME_LEN_POS], + int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_LEN_POS], const_var); - const_var= TLOG_HANDLER_TYPE_LEN; - int4store(&global_table_log.file_entry[TLOG_HANDLER_TYPE_POS], + const_var= DDL_LOG_HANDLER_TYPE_LEN; + int4store(&global_ddl_log.file_entry_buf[DDL_LOG_HANDLER_TYPE_POS], const_var); const_var= IO_SIZE; - int4store(&global_table_log.file_entry[TLOG_IO_SIZE_POS], + int4store(&global_ddl_log.file_entry_buf[DDL_LOG_IO_SIZE_POS], const_var); - if (write_table_log_file_entry(0UL)) + if (write_ddl_log_file_entry(0UL)) error= TRUE; if (!error) - VOID(sync_table_log()); + VOID(sync_ddl_log()); DBUG_RETURN(error); } /* - Create table log file name + Create ddl log file name SYNOPSIS - create_table_log_file_name() + create_ddl_log_file_name() file_name Filename setup RETURN VALUES NONE */ -static -void -create_table_log_file_name(char *file_name) +static inline void create_ddl_log_file_name(char *file_name) { - strxmov(file_name, mysql_data_home, "/", "table_log.log", NullS); + strxmov(file_name, mysql_data_home, "/", "ddl_log.log", NullS); } /* - Read header of table log file + Read header of ddl log file SYNOPSIS - read_table_log_header() + read_ddl_log_header() RETURN VALUES - > 0 Last entry in table log - 0 No entries in table log + > 0 Last entry in ddl log + 0 No entries in ddl log DESCRIPTION - When we read the table log header we get information about maximum sizes - of names in the table log and we also get information about the number - of entries in the table log. + When we read the ddl log header we get information about maximum sizes + of names in the ddl log and we also get information about the number + of entries in the ddl log. */ -static -uint -read_table_log_header() +static uint read_ddl_log_header() { - char *file_entry= (char*)global_table_log.file_entry; + char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; char file_name[FN_REFLEN]; uint entry_no; bool successful_open= FALSE; - DBUG_ENTER("read_table_log_header"); + DBUG_ENTER("read_ddl_log_header"); - bzero(file_entry, sizeof(global_table_log.file_entry)); - create_table_log_file_name(file_name); - if (!(my_open(file_name, O_RDWR | O_TRUNC | O_BINARY, MYF(MY_WME)))) + bzero(file_entry_buf, sizeof(global_ddl_log.file_entry_buf)); + global_ddl_log.inited= FALSE; + create_ddl_log_file_name(file_name); + if (!(my_open(file_name, O_RDONLY | O_BINARY, MYF(MY_WME)))) { - if (read_table_log_file_entry(0UL)) + if (read_ddl_log_file_entry(0UL)) { ; /* Write message into error log */ } else successful_open= TRUE; } - entry_no= uint4korr(&file_entry[TLOG_NO_ENTRY_POS]); - global_table_log.name_len= uint4korr(&file_entry[TLOG_NAME_LEN_POS]); - global_table_log.handler_type_len= - uint4korr(&file_entry[TLOG_HANDLER_TYPE_POS]); + entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]); + global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]); + global_ddl_log.handler_name_len= + uint4korr(&file_entry_buf[DDL_LOG_HANDLER_TYPE_POS]); if (successful_open) - global_table_log.io_size= uint4korr(&file_entry[TLOG_IO_SIZE_POS]); + global_ddl_log.io_size= uint4korr(&file_entry_buf[DDL_LOG_IO_SIZE_POS]); else - global_table_log.io_size= IO_SIZE; - global_table_log.first_free= NULL; - global_table_log.first_used= NULL; - global_table_log.no_entries= 0; - VOID(pthread_mutex_init(&LOCK_gtl, MY_MUTEX_INIT_FAST)); + global_ddl_log.io_size= IO_SIZE; + global_ddl_log.first_free= NULL; + global_ddl_log.first_used= NULL; + global_ddl_log.num_entries= 0; + VOID(pthread_mutex_init(&LOCK_gdl, MY_MUTEX_INIT_FAST)); DBUG_RETURN(entry_no); } /* - Read a table log entry + Read a ddl log entry SYNOPSIS - read_table_log_entry() + read_ddl_log_entry() read_entry Number of entry to read out:entry_info Information from entry RETURN VALUES TRUE Error FALSE Success DESCRIPTION - Read a specified entry in the table log + Read a specified entry in the ddl log */ -bool -read_table_log_entry(uint read_entry, TABLE_LOG_ENTRY *table_log_entry) +bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry) { - char *file_entry= (char*)&global_table_log.file_entry; + char *file_entry_buf= (char*)&global_ddl_log.file_entry_buf; uint inx; - DBUG_ENTER("read_table_log_entry"); + DBUG_ENTER("read_ddl_log_entry"); - if (read_table_log_file_entry(read_entry)) + if (read_ddl_log_file_entry(read_entry)) { /* Error handling */ DBUG_RETURN(TRUE); } - table_log_entry->entry_pos= read_entry; - table_log_entry->entry_type= file_entry[TLOG_ENTRY_TYPE_POS]; - table_log_entry->action_type= file_entry[TLOG_ACTION_TYPE_POS]; - table_log_entry->phase= file_entry[TLOG_PHASE_POS]; - table_log_entry->next_entry= uint4korr(&file_entry[TLOG_NEXT_ENTRY_POS]); - table_log_entry->name= &file_entry[TLOG_NAME_POS]; - inx= TLOG_NAME_POS + global_table_log.name_len; - table_log_entry->from_name= &file_entry[inx]; - inx+= global_table_log.name_len; - table_log_entry->handler_type= &file_entry[inx]; + ddl_log_entry->entry_pos= read_entry; + ddl_log_entry->entry_type= + (enum ddl_log_entry_code)file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]; + ddl_log_entry->action_type= + (enum ddl_log_action_code)file_entry_buf[DDL_LOG_ACTION_TYPE_POS]; + ddl_log_entry->phase= file_entry_buf[DDL_LOG_PHASE_POS]; + ddl_log_entry->next_entry= uint4korr(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS]); + ddl_log_entry->name= &file_entry_buf[DDL_LOG_NAME_POS]; + inx= DDL_LOG_NAME_POS + global_ddl_log.name_len; + ddl_log_entry->from_name= &file_entry_buf[inx]; + inx+= global_ddl_log.name_len; + ddl_log_entry->handler_name= &file_entry_buf[inx]; DBUG_RETURN(FALSE); } /* - Initialise table log + Initialise ddl log SYNOPSIS - init_table_log() + init_ddl_log() RETURN VALUES TRUE Error FALSE Success DESCRIPTION - Write the header of the table log file and length of names. Also set + Write the header of the ddl log file and length of names. Also set number of entries to zero. */ -static -bool -init_table_log() +static bool init_ddl_log() { bool error= FALSE; char file_name[FN_REFLEN]; - DBUG_ENTER("init_table_log"); + DBUG_ENTER("init_ddl_log"); - global_table_log.io_size= IO_SIZE; - create_table_log_file_name(file_name); - VOID(my_delete(file_name, MYF(0))); - if ((global_table_log.file_id= my_create(file_name, - CREATE_MODE, - O_RDWR | O_TRUNC | O_BINARY, - MYF(MY_WME))) < 0) + if (global_ddl_log.inited) { - /* Couldn't create table log file, this is serious error */ + DBUG_RETURN(FALSE); + } + global_ddl_log.io_size= IO_SIZE; + create_ddl_log_file_name(file_name); + VOID(my_delete(file_name, MYF(0))); + if ((global_ddl_log.file_id= my_create(file_name, + CREATE_MODE, + O_RDWR | O_TRUNC | O_BINARY, + MYF(MY_WME))) < 0) + { + /* Couldn't create ddl log file, this is serious error */ abort(); } - if (write_table_log_header()) + if (write_ddl_log_header()) { /* Write to error log */ error= TRUE; } + global_ddl_log.inited= TRUE; DBUG_RETURN(error); } /* - Execute one action in a table log entry + Execute one action in a ddl log entry SYNOPSIS - execute_table_log_action() - table_log_entry Information in action entry to execute + execute_ddl_log_action() + ddl_log_entry Information in action entry to execute RETURN VALUES TRUE Error FALSE Success */ -static -bool -execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) +static bool execute_ddl_log_action(DDL_LOG_ENTRY *ddl_log_entry) { bool frm_action= FALSE; LEX_STRING handler_name; @@ -555,22 +549,22 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) char from_path[FN_REFLEN]; char *par_ext= (char*)".par"; handlerton *hton; - DBUG_ENTER("execute_table_log_action"); + DBUG_ENTER("execute_ddl_log_action"); - if (table_log_entry->entry_type == TLOG_IGNORE_LOG_ENTRY_CODE) + if (ddl_log_entry->entry_type == DDL_IGNORE_LOG_ENTRY_CODE) { DBUG_RETURN(FALSE); } - handler_name.str= (char*)table_log_entry->handler_type; - handler_name.length= strlen(table_log_entry->handler_type); + handler_name.str= (char*)ddl_log_entry->handler_name; + handler_name.length= strlen(ddl_log_entry->handler_name); hton= ha_resolve_by_name(current_thd, &handler_name); if (!hton) { - my_error(ER_ILLEGAL_HA, MYF(0), table_log_entry->handler_type); + my_error(ER_ILLEGAL_HA, MYF(0), ddl_log_entry->handler_name); DBUG_RETURN(TRUE); } init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); - if (strcmp("frm", table_log_entry->handler_type)) + if (strcmp("frm", ddl_log_entry->handler_name)) frm_action= TRUE; else { @@ -583,65 +577,65 @@ execute_table_log_action(TABLE_LOG_ENTRY *table_log_entry) goto error; } } - switch (table_log_entry->action_type) + switch (ddl_log_entry->action_type) { - case TLOG_DELETE_ACTION_CODE: - case TLOG_REPLACE_ACTION_CODE: + case DDL_LOG_DELETE_ACTION: + case DDL_LOG_REPLACE_ACTION: { - if (table_log_entry->action_type == TLOG_DELETE_ACTION_CODE || - (table_log_entry->action_type == TLOG_REPLACE_ACTION_CODE && - table_log_entry->phase == 0UL)) + if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION || + (ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION && + ddl_log_entry->phase == 0UL)) { if (frm_action) { - strxmov(path, table_log_entry->name, reg_ext, NullS); + strxmov(path, ddl_log_entry->name, reg_ext, NullS); if (my_delete(path, MYF(MY_WME))) break; - strxmov(path, table_log_entry->name, par_ext, NullS); + strxmov(path, ddl_log_entry->name, par_ext, NullS); if (my_delete(path, MYF(MY_WME))) break; } else { - if (file->delete_table(table_log_entry->name)) + if (file->delete_table(ddl_log_entry->name)) break; } - if ((!inactivate_table_log_entry(table_log_entry->entry_pos))) + if ((!deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) ; else { - VOID(sync_table_log()); + VOID(sync_ddl_log()); error= FALSE; } break; } - if (table_log_entry->action_type == TLOG_DELETE_ACTION_CODE) + if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION) break; } - case TLOG_RENAME_ACTION_CODE: + case DDL_LOG_RENAME_ACTION: { error= TRUE; if (frm_action) { - strxmov(path, table_log_entry->name, reg_ext, NullS); - strxmov(from_path, table_log_entry->from_name, reg_ext, NullS); + strxmov(path, ddl_log_entry->name, reg_ext, NullS); + strxmov(from_path, ddl_log_entry->from_name, reg_ext, NullS); if (my_rename(path, from_path, MYF(MY_WME))) break; - strxmov(path, table_log_entry->name, par_ext, NullS); - strxmov(from_path, table_log_entry->from_name, par_ext, NullS); + strxmov(path, ddl_log_entry->name, par_ext, NullS); + strxmov(from_path, ddl_log_entry->from_name, par_ext, NullS); if (my_rename(path, from_path, MYF(MY_WME))) break; } else { - if (file->rename_table(table_log_entry->name, - table_log_entry->from_name)) + if (file->rename_table(ddl_log_entry->name, + ddl_log_entry->from_name)) break; - if ((!inactivate_table_log_entry(table_log_entry->entry_pos))) + if ((!deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) ; else { - VOID(sync_table_log()); + VOID(sync_ddl_log()); error= FALSE; } } @@ -659,40 +653,38 @@ error: /* - Get a free entry in the table log + Get a free entry in the ddl log SYNOPSIS - get_free_table_log_entry() - out:active_entry A table log memory entry returned + get_free_ddl_log_entry() + out:active_entry A ddl log memory entry returned RETURN VALUES TRUE Error FALSE Success */ -static -bool -get_free_table_log_entry(TABLE_LOG_MEMORY_ENTRY **active_entry, - bool *write_header) +static bool get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY **active_entry, + bool *write_header) { uint entry_no; - TABLE_LOG_MEMORY_ENTRY *used_entry; - TABLE_LOG_MEMORY_ENTRY *first_used= global_table_log.first_used; - DBUG_ENTER("get_free_table_log_entry"); + DDL_LOG_MEMORY_ENTRY *used_entry; + DDL_LOG_MEMORY_ENTRY *first_used= global_ddl_log.first_used; + DBUG_ENTER("get_free_ddl_log_entry"); - if (global_table_log.first_free == NULL) + if (global_ddl_log.first_free == NULL) { - if (!(used_entry= (TABLE_LOG_MEMORY_ENTRY*)my_malloc( - sizeof(TABLE_LOG_MEMORY_ENTRY), MYF(MY_WME)))) + if (!(used_entry= (DDL_LOG_MEMORY_ENTRY*)my_malloc( + sizeof(DDL_LOG_MEMORY_ENTRY), MYF(MY_WME)))) { DBUG_RETURN(TRUE); } - global_table_log.no_entries++; - used_entry->entry_pos= entry_no= global_table_log.no_entries; + global_ddl_log.num_entries++; + used_entry->entry_pos= entry_no= global_ddl_log.num_entries; *write_header= TRUE; } else { - used_entry= global_table_log.first_free; - global_table_log.first_free= used_entry->next_log_entry; + used_entry= global_ddl_log.first_free; + global_ddl_log.first_free= used_entry->next_log_entry; entry_no= used_entry->entry_pos; *write_header= FALSE; } @@ -701,7 +693,7 @@ get_free_table_log_entry(TABLE_LOG_MEMORY_ENTRY **active_entry, */ used_entry->next_log_entry= first_used; used_entry->prev_log_entry= NULL; - global_table_log.first_used= used_entry; + global_ddl_log.first_used= used_entry; if (first_used) first_used->prev_log_entry= used_entry; @@ -711,76 +703,79 @@ get_free_table_log_entry(TABLE_LOG_MEMORY_ENTRY **active_entry, /* - External interface methods for the Table log Module + External interface methods for the DDL log Module --------------------------------------------------- */ /* SYNOPSIS - write_table_log_entry() - table_log_entry Information about log entry - out:entry_written Entry information written into + write_ddl_log_entry() + ddl_log_entry Information about log entry + out:entry_written Entry information written into RETURN VALUES TRUE Error FALSE Success DESCRIPTION - A careful write of the table log is performed to ensure that we can + A careful write of the ddl log is performed to ensure that we can handle crashes occurring during CREATE and ALTER TABLE processing. */ -bool -write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, - TABLE_LOG_MEMORY_ENTRY **active_entry) +bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, + DDL_LOG_MEMORY_ENTRY **active_entry) { bool error, write_header; - DBUG_ENTER("write_table_log_entry"); + DBUG_ENTER("write_ddl_log_entry"); - global_table_log.file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_LOG_ENTRY_CODE; - global_table_log.file_entry[TLOG_ACTION_TYPE_POS]= - table_log_entry->action_type; - global_table_log.file_entry[TLOG_PHASE_POS]= 0; - int4store(&global_table_log.file_entry[TLOG_NEXT_ENTRY_POS], - table_log_entry->next_entry); - DBUG_ASSERT(strlen(table_log_entry->name) < FN_LEN); - strncpy(&global_table_log.file_entry[TLOG_NAME_POS], - table_log_entry->name, FN_LEN); - if (table_log_entry->action_type == TLOG_RENAME_ACTION_CODE || - table_log_entry->action_type == TLOG_REPLACE_ACTION_CODE) + if (init_ddl_log()) { - DBUG_ASSERT(strlen(table_log_entry->from_name) < FN_LEN); - strncpy(&global_table_log.file_entry[TLOG_NAME_POS + FN_LEN], - table_log_entry->from_name, FN_LEN); + DBUG_RETURN(TRUE); + } + global_ddl_log.file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_LOG_ENTRY_CODE; + global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= + ddl_log_entry->action_type; + global_ddl_log.file_entry_buf[DDL_LOG_PHASE_POS]= 0; + int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], + ddl_log_entry->next_entry); + DBUG_ASSERT(strlen(ddl_log_entry->name) < FN_LEN); + strncpy(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS], + ddl_log_entry->name, FN_LEN); + if (ddl_log_entry->action_type == DDL_LOG_RENAME_ACTION || + ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION) + { + DBUG_ASSERT(strlen(ddl_log_entry->from_name) < FN_LEN); + strncpy(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_LEN], + ddl_log_entry->from_name, FN_LEN); } else - global_table_log.file_entry[TLOG_NAME_POS + FN_LEN]= 0; - DBUG_ASSERT(strlen(table_log_entry->handler_type) < FN_LEN); - strncpy(&global_table_log.file_entry[TLOG_NAME_POS + (2*FN_LEN)], - table_log_entry->handler_type, FN_LEN); - if (get_free_table_log_entry(active_entry, &write_header)) + global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_LEN]= 0; + DBUG_ASSERT(strlen(ddl_log_entry->handler_name) < FN_LEN); + strncpy(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + (2*FN_LEN)], + ddl_log_entry->handler_name, FN_LEN); + if (get_free_ddl_log_entry(active_entry, &write_header)) { DBUG_RETURN(TRUE); } error= FALSE; - if (write_table_log_file_entry((*active_entry)->entry_pos)) + if (write_ddl_log_file_entry((*active_entry)->entry_pos)) error= TRUE; if (write_header && !error) { - VOID(sync_table_log()); - if (write_table_log_header()) + VOID(sync_ddl_log()); + if (write_ddl_log_header()) error= TRUE; } if (error) - release_table_log_memory_entry(*active_entry); + release_ddl_log_memory_entry(*active_entry); DBUG_RETURN(error); } /* - Write final entry in the table log + Write final entry in the ddl log SYNOPSIS - write_execute_table_log_entry() + write_execute_ddl_log_entry() first_entry First entry in linked list of entries to execute, if 0 = NULL it means that the entry is removed and the entries @@ -794,50 +789,53 @@ write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry, FALSE Success DESCRIPTION - This is the last write in the table log. The previous log entries have + This is the last write in the ddl log. The previous log entries have already been written but not yet synched to disk. */ -bool -write_execute_table_log_entry(uint first_entry, - bool complete, - TABLE_LOG_MEMORY_ENTRY **active_entry) +bool write_execute_ddl_log_entry(uint first_entry, + bool complete, + DDL_LOG_MEMORY_ENTRY **active_entry) { bool write_header= FALSE; - char *file_entry= (char*)global_table_log.file_entry; - DBUG_ENTER("write_execute_table_log_entry"); + char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; + DBUG_ENTER("write_execute_ddl_log_entry"); + if (init_ddl_log()) + { + DBUG_RETURN(TRUE); + } if (!complete) { - VOID(sync_table_log()); - file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_EXECUTE_CODE; + VOID(sync_ddl_log()); + file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_LOG_EXECUTE_CODE; } else - file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_IGNORE_LOG_ENTRY_CODE; - file_entry[TLOG_ACTION_TYPE_POS]= 0; /* Ignored for execute entries */ - file_entry[TLOG_PHASE_POS]= 0; - int4store(&file_entry[TLOG_NEXT_ENTRY_POS], first_entry); - file_entry[TLOG_NAME_POS]= 0; - file_entry[TLOG_NAME_POS + FN_LEN]= 0; - file_entry[TLOG_NAME_POS + 2*FN_LEN]= 0; + file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_IGNORE_LOG_ENTRY_CODE; + file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= 0; /* Ignored for execute entries */ + file_entry_buf[DDL_LOG_PHASE_POS]= 0; + int4store(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], first_entry); + file_entry_buf[DDL_LOG_NAME_POS]= 0; + file_entry_buf[DDL_LOG_NAME_POS + FN_LEN]= 0; + file_entry_buf[DDL_LOG_NAME_POS + 2*FN_LEN]= 0; if (!(*active_entry)) { - if (get_free_table_log_entry(active_entry, &write_header)) + if (get_free_ddl_log_entry(active_entry, &write_header)) { DBUG_RETURN(TRUE); } } - if (write_table_log_file_entry((*active_entry)->entry_pos)) + if (write_ddl_log_file_entry((*active_entry)->entry_pos)) { - release_table_log_memory_entry(*active_entry); + release_ddl_log_memory_entry(*active_entry); DBUG_RETURN(TRUE); } - VOID(sync_table_log()); + VOID(sync_ddl_log()); if (write_header) { - if (write_table_log_header()) + if (write_ddl_log_header()) { - release_table_log_memory_entry(*active_entry); + release_ddl_log_memory_entry(*active_entry); DBUG_RETURN(TRUE); } } @@ -846,9 +844,9 @@ write_execute_table_log_entry(uint first_entry, /* - For complex rename operations we need to inactivate individual entries. + For complex rename operations we need to deactivate individual entries. SYNOPSIS - inactivate_table_log_entry() + deactivate_ddl_log_entry() entry_no Entry position of record to change RETURN VALUES TRUE Error @@ -857,7 +855,7 @@ write_execute_table_log_entry(uint first_entry, During replace operations where we start with an existing table called t1 and a replacement table called t1#temp or something else and where we want to delete t1 and rename t1#temp to t1 this is not possible to - do in a safe manner unless the table log is informed of the phases in + do in a safe manner unless the ddl log is informed of the phases in the change. Delete actions are 1-phase actions that can be ignored immediately after @@ -869,32 +867,31 @@ write_execute_table_log_entry(uint first_entry, rename x -> y. */ -bool -inactivate_table_log_entry(uint entry_no) +bool deactivate_ddl_log_entry(uint entry_no) { bool error= TRUE; - char *file_entry= (char*)global_table_log.file_entry; - DBUG_ENTER("inactivate_table_log_entry"); + char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; + DBUG_ENTER("deactivate_ddl_log_entry"); - if (!read_table_log_file_entry(entry_no)) + if (!read_ddl_log_file_entry(entry_no)) { - if (file_entry[TLOG_ENTRY_TYPE_POS] == TLOG_LOG_ENTRY_CODE) + if (file_entry_buf[DDL_LOG_ENTRY_TYPE_POS] == DDL_LOG_ENTRY_CODE) { - if (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_DELETE_ACTION_CODE || - file_entry[TLOG_ACTION_TYPE_POS] == TLOG_RENAME_ACTION_CODE || - (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_REPLACE_ACTION_CODE && - file_entry[TLOG_PHASE_POS] == 1)) - file_entry[TLOG_ENTRY_TYPE_POS]= TLOG_IGNORE_LOG_ENTRY_CODE; - else if (file_entry[TLOG_ACTION_TYPE_POS] == TLOG_REPLACE_ACTION_CODE) + if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_DELETE_ACTION || + file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_RENAME_ACTION || + (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION && + file_entry_buf[DDL_LOG_PHASE_POS] == 1)) + file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_IGNORE_LOG_ENTRY_CODE; + else if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION) { - DBUG_ASSERT(file_entry[TLOG_PHASE_POS] == 0); - file_entry[TLOG_PHASE_POS]= 1; + DBUG_ASSERT(file_entry_buf[DDL_LOG_PHASE_POS] == 0); + file_entry_buf[DDL_LOG_PHASE_POS]= 1; } else { DBUG_ASSERT(0); } - if (!write_table_log_file_entry(entry_no)) + if (!write_ddl_log_file_entry(entry_no)) error= FALSE; } } @@ -903,21 +900,24 @@ inactivate_table_log_entry(uint entry_no) /* - Sync table log file + Sync ddl log file SYNOPSIS - sync_table_log() + sync_ddl_log() RETURN VALUES TRUE Error FALSE Success */ -bool -sync_table_log() +bool sync_ddl_log() { bool error= FALSE; - DBUG_ENTER("sync_table_log"); + DBUG_ENTER("sync_ddl_log"); - if (my_sync(global_table_log.file_id, MYF(0))) + if (init_ddl_log()) + { + DBUG_RETURN(TRUE); + } + if (my_sync(global_ddl_log.file_id, MYF(0))) { /* Write to error log */ error= TRUE; @@ -929,27 +929,26 @@ sync_table_log() /* Release a log memory entry SYNOPSIS - release_table_log_memory_entry() + release_ddl_log_memory_entry() log_memory_entry Log memory entry to release RETURN VALUES NONE */ -void -release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry) +void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry) { - TABLE_LOG_MEMORY_ENTRY *first_free= global_table_log.first_free; - TABLE_LOG_MEMORY_ENTRY *next_log_entry= log_entry->next_log_entry; - TABLE_LOG_MEMORY_ENTRY *prev_log_entry= log_entry->prev_log_entry; - DBUG_ENTER("release_table_log_memory_entry"); + DDL_LOG_MEMORY_ENTRY *first_free= global_ddl_log.first_free; + DDL_LOG_MEMORY_ENTRY *next_log_entry= log_entry->next_log_entry; + DDL_LOG_MEMORY_ENTRY *prev_log_entry= log_entry->prev_log_entry; + DBUG_ENTER("release_ddl_log_memory_entry"); - global_table_log.first_free= log_entry; + global_ddl_log.first_free= log_entry; log_entry->next_log_entry= first_free; if (prev_log_entry) prev_log_entry->next_log_entry= next_log_entry; else - global_table_log.first_used= next_log_entry; + global_ddl_log.first_used= next_log_entry; if (next_log_entry) next_log_entry->prev_log_entry= prev_log_entry; DBUG_VOID_RETURN; @@ -957,75 +956,73 @@ release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry) /* - Execute one entry in the table log. Executing an entry means executing + Execute one entry in the ddl log. Executing an entry means executing a linked list of actions. SYNOPSIS - execute_table_log_entry() + execute_ddl_log_entry() first_entry Reference to first action in entry RETURN VALUES TRUE Error FALSE Success */ -bool -execute_table_log_entry(uint first_entry) +bool execute_ddl_log_entry(uint first_entry) { - TABLE_LOG_ENTRY table_log_entry; + DDL_LOG_ENTRY ddl_log_entry; uint read_entry= first_entry; - DBUG_ENTER("execute_table_log_entry"); + DBUG_ENTER("execute_ddl_log_entry"); - lock_global_table_log(); + lock_global_ddl_log(); do { - if (read_table_log_entry(read_entry, &table_log_entry)) + if (read_ddl_log_entry(read_entry, &ddl_log_entry)) { DBUG_ASSERT(0); /* Write to error log and continue with next log entry */ break; } - DBUG_ASSERT(table_log_entry.entry_type == TLOG_LOG_ENTRY_CODE || - table_log_entry.entry_type == TLOG_IGNORE_LOG_ENTRY_CODE); + DBUG_ASSERT(ddl_log_entry.entry_type == DDL_LOG_ENTRY_CODE || + ddl_log_entry.entry_type == DDL_IGNORE_LOG_ENTRY_CODE); - if (execute_table_log_action(&table_log_entry)) + if (execute_ddl_log_action(&ddl_log_entry)) { DBUG_ASSERT(0); /* Write to error log and continue with next log entry */ break; } - read_entry= table_log_entry.next_entry; + read_entry= ddl_log_entry.next_entry; } while (read_entry); - unlock_global_table_log(); + unlock_global_ddl_log(); DBUG_RETURN(FALSE); } /* - Execute the table log at recovery of MySQL Server + Execute the ddl log at recovery of MySQL Server SYNOPSIS - execute_table_log_recovery() + execute_ddl_log_recovery() RETURN VALUES NONE */ -void -execute_table_log_recovery() +void execute_ddl_log_recovery() { - uint no_entries, i; - TABLE_LOG_ENTRY table_log_entry; - DBUG_ENTER("execute_table_log_recovery"); + uint num_entries, i; + DDL_LOG_ENTRY ddl_log_entry; + DBUG_ENTER("execute_ddl_log_recovery"); - no_entries= read_table_log_header(); - for (i= 0; i < no_entries; i++) + num_entries= read_ddl_log_header(); + for (i= 0; i < num_entries; i++) { - if (read_table_log_entry(i, &table_log_entry)) + if (read_ddl_log_entry(i, &ddl_log_entry)) { DBUG_ASSERT(0); /* Write to error log */ break; } - if (table_log_entry.entry_type == TLOG_EXECUTE_CODE) + if (ddl_log_entry.entry_type == DDL_LOG_EXECUTE_CODE) { - if (execute_table_log_entry(table_log_entry.next_entry)) + if (execute_ddl_log_entry(ddl_log_entry.next_entry)) { /* Currently errors are either crashing or ignored so we should @@ -1036,78 +1033,75 @@ execute_table_log_recovery() } } } - VOID(init_table_log()); + VOID(init_ddl_log()); DBUG_VOID_RETURN; } /* - Release all memory allocated to the table log + Release all memory allocated to the ddl log SYNOPSIS - release_table_log() + release_ddl_log() RETURN VALUES NONE */ -void -release_table_log() +void release_ddl_log() { - TABLE_LOG_MEMORY_ENTRY *free_list= global_table_log.first_free; - TABLE_LOG_MEMORY_ENTRY *used_list= global_table_log.first_used; - DBUG_ENTER("release_table_log"); + DDL_LOG_MEMORY_ENTRY *free_list= global_ddl_log.first_free; + DDL_LOG_MEMORY_ENTRY *used_list= global_ddl_log.first_used; + DBUG_ENTER("release_ddl_log"); - lock_global_table_log(); + lock_global_ddl_log(); while (used_list) { - TABLE_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry; + DDL_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry; my_free((char*)used_list, MYF(0)); used_list= tmp; } while (free_list) { - TABLE_LOG_MEMORY_ENTRY *tmp= free_list->next_log_entry; + DDL_LOG_MEMORY_ENTRY *tmp= free_list->next_log_entry; my_free((char*)free_list, MYF(0)); free_list= tmp; } - VOID(my_close(global_table_log.file_id, MYF(0))); - unlock_global_table_log(); - VOID(pthread_mutex_destroy(&LOCK_gtl)); + VOID(my_close(global_ddl_log.file_id, MYF(0))); + unlock_global_ddl_log(); + VOID(pthread_mutex_destroy(&LOCK_gdl)); DBUG_VOID_RETURN; } /* - Lock mutex for global table log + Lock mutex for global ddl log SYNOPSIS - lock_global_table_log() + lock_global_ddl_log() RETURN VALUES NONE */ -void -lock_global_table_log() +void lock_global_ddl_log() { - DBUG_ENTER("lock_global_table_log"); + DBUG_ENTER("lock_global_ddl_log"); - VOID(pthread_mutex_lock(&LOCK_gtl)); + VOID(pthread_mutex_lock(&LOCK_gdl)); DBUG_VOID_RETURN; } /* - Unlock mutex for global table log + Unlock mutex for global ddl log SYNOPSIS - unlock_global_table_log() + unlock_global_ddl_log() RETURN VALUES NONE */ -void -unlock_global_table_log() +void unlock_global_ddl_log() { - DBUG_ENTER("unlock_global_table_log"); + DBUG_ENTER("unlock_global_ddl_log"); - VOID(pthread_mutex_unlock(&LOCK_gtl)); + VOID(pthread_mutex_unlock(&LOCK_gdl)); DBUG_VOID_RETURN; } @@ -1115,7 +1109,7 @@ unlock_global_table_log() /* --------------------------------------------------------------------------- - END MODULE Table log + END MODULE DDL log -------------------- --------------------------------------------------------------------------- @@ -1254,8 +1248,8 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) VOID(pthread_mutex_lock(&LOCK_open)); if (my_delete(frm_name, MYF(MY_WME)) || #ifdef WITH_PARTITION_STORAGE_ENGINE - inactivate_table_log_entry(part_info->frm_log_entry->entry_pos) || - (sync_table_log(), FALSE) || + deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos) || + (sync_ddl_log(), FALSE) || #endif my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || lpt->table->file->create_handler_files(path, shadow_path, TRUE)) @@ -1264,9 +1258,9 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) } VOID(pthread_mutex_unlock(&LOCK_open)); #ifdef WITH_PARTITION_STORAGE_ENGINE - inactivate_table_log_entry(part_info->frm_log_entry->entry_pos); + deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos); part_info->frm_log_entry= NULL; - VOID(sync_table_log()); + VOID(sync_ddl_log()); #endif } diff --git a/sql/table.cc b/sql/table.cc index f2cde30c14b..20c985040fa 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -667,8 +667,9 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, #endif next_chunk+= 5 + partition_info_len; } -#if 0 - if (share->mysql_version == 50106) +#if 1 + if (share->mysql_version == 50106 || + share->mysql_version == 50107) { /* Partition state array was here in version 5.1.6, this code makes From 79ec84f98abcc94ec267c232207f36a1669b7125 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 1 Apr 2006 16:37:36 +0200 Subject: [PATCH 41/48] WL 2826: Error handling of ALTER TABLE for partitioning More review fixes sql/mysql_priv.h: More review fixes sql/sql_partition.cc: More review fixes sql/sql_table.cc: More review fixes --- sql/mysql_priv.h | 6 ++ sql/sql_partition.cc | 3 +- sql/sql_table.cc | 157 ++++++++++++++++++++++++++++--------------- 3 files changed, 111 insertions(+), 55 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 265d2840025..a39b1209319 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1266,6 +1266,12 @@ typedef struct st_ddl_log_entry uint entry_pos; enum ddl_log_entry_code entry_type; enum ddl_log_action_code action_type; + /* + Most actions have only one phase. REPLACE does however have two + phases. The first phase removes the file with the new name if + there was one there before and the second phase renames the + old name to the new name. + */ char phase; } DDL_LOG_ENTRY; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 682b9f783ba..c093466effa 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5634,7 +5634,8 @@ static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, Failed to write, Bad... We have completed the operation but have log records to REMOVE stuff that shouldn't be removed. What clever things could one do - here? + here? An error output was written to the error output by the + above method so we don't do anything here. */ ; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 86a3259484a..7a4bd2e1608 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -281,6 +281,7 @@ typedef struct st_global_ddl_log uint handler_name_len; uint io_size; bool inited; + bool recovery_phase; } GLOBAL_DDL_LOG; GLOBAL_DDL_LOG global_ddl_log; @@ -374,9 +375,11 @@ static bool write_ddl_log_header() int4store(&global_ddl_log.file_entry_buf[DDL_LOG_IO_SIZE_POS], const_var); if (write_ddl_log_file_entry(0UL)) - error= TRUE; - if (!error) - VOID(sync_ddl_log()); + { + sql_print_error("Error writing ddl log header"); + DBUG_RETURN(TRUE); + } + VOID(sync_ddl_log()); DBUG_RETURN(error); } @@ -419,16 +422,20 @@ static uint read_ddl_log_header() bzero(file_entry_buf, sizeof(global_ddl_log.file_entry_buf)); global_ddl_log.inited= FALSE; + global_ddl_log.recovery_phase= TRUE; create_ddl_log_file_name(file_name); - if (!(my_open(file_name, O_RDONLY | O_BINARY, MYF(MY_WME)))) + if (!(my_open(file_name, O_RDWR | O_BINARY, MYF(MY_WME)))) { if (read_ddl_log_file_entry(0UL)) { - ; /* Write message into error log */ + /* Write message into error log */ + sql_print_error("Failed to read ddl log file in recovery"); } else successful_open= TRUE; } + else + sql_print_error("Failed to open ddl log file in recovery"); entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]); global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]); global_ddl_log.handler_name_len= @@ -436,7 +443,10 @@ static uint read_ddl_log_header() if (successful_open) global_ddl_log.io_size= uint4korr(&file_entry_buf[DDL_LOG_IO_SIZE_POS]); else + { global_ddl_log.io_size= IO_SIZE; + entry_no= 0; + } global_ddl_log.first_free= NULL; global_ddl_log.first_used= NULL; global_ddl_log.num_entries= 0; @@ -466,7 +476,6 @@ bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry) if (read_ddl_log_file_entry(read_entry)) { - /* Error handling */ DBUG_RETURN(TRUE); } ddl_log_entry->entry_pos= read_entry; @@ -508,23 +517,21 @@ static bool init_ddl_log() DBUG_RETURN(FALSE); } global_ddl_log.io_size= IO_SIZE; - create_ddl_log_file_name(file_name); - VOID(my_delete(file_name, MYF(0))); if ((global_ddl_log.file_id= my_create(file_name, CREATE_MODE, O_RDWR | O_TRUNC | O_BINARY, MYF(MY_WME))) < 0) { /* Couldn't create ddl log file, this is serious error */ - abort(); + sql_print_error("Failed to open ddl log file"); + DBUG_RETURN(TRUE); } if (write_ddl_log_header()) { - /* Write to error log */ - error= TRUE; + DBUG_RETURN(TRUE); } global_ddl_log.inited= TRUE; - DBUG_RETURN(error); + DBUG_RETURN(FALSE); } @@ -538,7 +545,7 @@ static bool init_ddl_log() FALSE Success */ -static bool execute_ddl_log_action(DDL_LOG_ENTRY *ddl_log_entry) +static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) { bool frm_action= FALSE; LEX_STRING handler_name; @@ -557,7 +564,7 @@ static bool execute_ddl_log_action(DDL_LOG_ENTRY *ddl_log_entry) } handler_name.str= (char*)ddl_log_entry->handler_name; handler_name.length= strlen(ddl_log_entry->handler_name); - hton= ha_resolve_by_name(current_thd, &handler_name); + hton= ha_resolve_by_name(thd, &handler_name); if (!hton) { my_error(ER_ILLEGAL_HA, MYF(0), ddl_log_entry->handler_name); @@ -579,38 +586,40 @@ static bool execute_ddl_log_action(DDL_LOG_ENTRY *ddl_log_entry) } switch (ddl_log_entry->action_type) { - case DDL_LOG_DELETE_ACTION: case DDL_LOG_REPLACE_ACTION: + case DDL_LOG_DELETE_ACTION: { - if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION || - (ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION && - ddl_log_entry->phase == 0UL)) + if (ddl_log_entry->phase == 0) { if (frm_action) { strxmov(path, ddl_log_entry->name, reg_ext, NullS); if (my_delete(path, MYF(MY_WME))) break; +#ifdef WITH_PARTITION_STORAGE_ENGINE strxmov(path, ddl_log_entry->name, par_ext, NullS); - if (my_delete(path, MYF(MY_WME))) - break; + VOID(my_delete(path, MYF(MY_WME))); +#endif } else { if (file->delete_table(ddl_log_entry->name)) break; } - if ((!deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) - ; - else + if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) { VOID(sync_ddl_log()); error= FALSE; } - break; + if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION) + break; } - if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION) - break; + DBUG_ASSERT(ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION); + /* + Fall through and perform the rename action of the replace + action. We have already indicated the success of the delete + action in the log entry by stepping up the phase. + */ } case DDL_LOG_RENAME_ACTION: { @@ -621,23 +630,22 @@ static bool execute_ddl_log_action(DDL_LOG_ENTRY *ddl_log_entry) strxmov(from_path, ddl_log_entry->from_name, reg_ext, NullS); if (my_rename(path, from_path, MYF(MY_WME))) break; +#ifdef WITH_PARTITION_STORAGE_ENGINE strxmov(path, ddl_log_entry->name, par_ext, NullS); strxmov(from_path, ddl_log_entry->from_name, par_ext, NullS); - if (my_rename(path, from_path, MYF(MY_WME))) - break; + VOID(my_rename(path, from_path, MYF(MY_WME))); +#endif } else { if (file->rename_table(ddl_log_entry->name, ddl_log_entry->from_name)) break; - if ((!deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) - ; - else - { - VOID(sync_ddl_log()); - error= FALSE; - } + } + if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) + { + VOID(sync_ddl_log()); + error= FALSE; } break; } @@ -665,7 +673,6 @@ error: static bool get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY **active_entry, bool *write_header) { - uint entry_no; DDL_LOG_MEMORY_ENTRY *used_entry; DDL_LOG_MEMORY_ENTRY *first_used= global_ddl_log.first_used; DBUG_ENTER("get_free_ddl_log_entry"); @@ -675,17 +682,17 @@ static bool get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY **active_entry, if (!(used_entry= (DDL_LOG_MEMORY_ENTRY*)my_malloc( sizeof(DDL_LOG_MEMORY_ENTRY), MYF(MY_WME)))) { + sql_print_error("Failed to allocate memory for ddl log free list"); DBUG_RETURN(TRUE); } global_ddl_log.num_entries++; - used_entry->entry_pos= entry_no= global_ddl_log.num_entries; + used_entry->entry_pos= global_ddl_log.num_entries; *write_header= TRUE; } else { used_entry= global_ddl_log.first_free; global_ddl_log.first_free= used_entry->next_log_entry; - entry_no= used_entry->entry_pos; *write_header= FALSE; } /* @@ -759,12 +766,17 @@ bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, } error= FALSE; if (write_ddl_log_file_entry((*active_entry)->entry_pos)) + { error= TRUE; + sql_print_error("Failed to write entry_no = %u", + (*active_entry)->entry_pos); + } if (write_header && !error) { VOID(sync_ddl_log()); if (write_ddl_log_header()) error= TRUE; + VOID(sync_ddl_log()); } if (error) release_ddl_log_memory_entry(*active_entry); @@ -791,6 +803,10 @@ bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, DESCRIPTION This is the last write in the ddl log. The previous log entries have already been written but not yet synched to disk. + We write a couple of log entries that describes action to perform. + This entries are set-up in a linked list, however only when a first + execute entry is put as the first entry these will be executed. + This routine writes this first */ bool write_execute_ddl_log_entry(uint first_entry, @@ -807,6 +823,12 @@ bool write_execute_ddl_log_entry(uint first_entry, } if (!complete) { + /* + We haven't synched the log entries yet, we synch them now before + writing the execute entry. If complete is true we haven't written + any log entries before, we are only here to write the execute + entry to indicate it is done. + */ VOID(sync_ddl_log()); file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_LOG_EXECUTE_CODE; } @@ -827,6 +849,7 @@ bool write_execute_ddl_log_entry(uint first_entry, } if (write_ddl_log_file_entry((*active_entry)->entry_pos)) { + sql_print_error("Error writing execute entry in ddl log"); release_ddl_log_memory_entry(*active_entry); DBUG_RETURN(TRUE); } @@ -838,6 +861,7 @@ bool write_execute_ddl_log_entry(uint first_entry, release_ddl_log_memory_entry(*active_entry); DBUG_RETURN(TRUE); } + VOID(sync_ddl_log()); } DBUG_RETURN(FALSE); } @@ -869,7 +893,6 @@ bool write_execute_ddl_log_entry(uint first_entry, bool deactivate_ddl_log_entry(uint entry_no) { - bool error= TRUE; char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; DBUG_ENTER("deactivate_ddl_log_entry"); @@ -891,11 +914,20 @@ bool deactivate_ddl_log_entry(uint entry_no) { DBUG_ASSERT(0); } - if (!write_ddl_log_file_entry(entry_no)) - error= FALSE; + if (write_ddl_log_file_entry(entry_no)) + { + sql_print_error("Error in deactivating log entry. Position = %u", + entry_no); + DBUG_RETURN(TRUE); + } } } - DBUG_RETURN(error); + else + { + sql_print_error("Failed in reading entry before deactivating it"); + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); } @@ -913,13 +945,15 @@ bool sync_ddl_log() bool error= FALSE; DBUG_ENTER("sync_ddl_log"); - if (init_ddl_log()) + if ((!global_ddl_log.recovery_phase) && + init_ddl_log()) { DBUG_RETURN(TRUE); } if (my_sync(global_ddl_log.file_id, MYF(0))) { /* Write to error log */ + sql_print_error("Failed to sync ddl log"); error= TRUE; } DBUG_RETURN(error); @@ -966,7 +1000,7 @@ void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry) FALSE Success */ -bool execute_ddl_log_entry(uint first_entry) +bool execute_ddl_log_entry(THD *thd, uint first_entry) { DDL_LOG_ENTRY ddl_log_entry; uint read_entry= first_entry; @@ -979,15 +1013,19 @@ bool execute_ddl_log_entry(uint first_entry) { DBUG_ASSERT(0); /* Write to error log and continue with next log entry */ + sql_print_error("Failed to read entry = %u from ddl log", + read_entry); break; } DBUG_ASSERT(ddl_log_entry.entry_type == DDL_LOG_ENTRY_CODE || ddl_log_entry.entry_type == DDL_IGNORE_LOG_ENTRY_CODE); - if (execute_ddl_log_action(&ddl_log_entry)) + if (execute_ddl_log_action(thd, &ddl_log_entry)) { DBUG_ASSERT(0); /* Write to error log and continue with next log entry */ + sql_print_error("Failed to execute action for entry = %u from ddl log", + read_entry); break; } read_entry= ddl_log_entry.next_entry; @@ -1011,29 +1049,40 @@ void execute_ddl_log_recovery() DDL_LOG_ENTRY ddl_log_entry; DBUG_ENTER("execute_ddl_log_recovery"); + /* + To be able to run this from boot, we allocate a temporary THD + */ + if (!(thd=new THD)) + DBUG_VOID_RETURN; + thd->thread_stack= (char*) &thd; + thd->store_globals(); + num_entries= read_ddl_log_header(); for (i= 0; i < num_entries; i++) { if (read_ddl_log_entry(i, &ddl_log_entry)) { DBUG_ASSERT(0); - /* Write to error log */ - break; + sql_print_error("Failed to read entry no = %u from ddl log", + i); + continue; } if (ddl_log_entry.entry_type == DDL_LOG_EXECUTE_CODE) { if (execute_ddl_log_entry(ddl_log_entry.next_entry)) { - /* - Currently errors are either crashing or ignored so we should - never end up here - */ - abort(); - DBUG_VOID_RETURN; + /* Real unpleasant scenario but we continue anyways. */ + DBUG_ASSERT(0); + continue; } } } - VOID(init_ddl_log()); + create_ddl_log_file_name(file_name); + VOID(my_delete(file_name, MYF(0))); + global_ddl_log.recovery_phase= FALSE; + delete thd; + /* Remember that we don't have a THD */ + my_pthread_setspecific_ptr(THR_THD, 0); DBUG_VOID_RETURN; } From b7b95ecf2d6bfde1ffda21809f356773f8630cdc Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 3 Apr 2006 12:26:35 -0400 Subject: [PATCH 42/48] Fixes --- sql/mysql_priv.h | 2 +- sql/sql_partition.cc | 3 ++- sql/sql_table.cc | 11 +++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index df7a88ccfbb..dbc1093c01a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1299,7 +1299,7 @@ void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry); bool sync_ddl_log(); void release_ddl_log(); void execute_ddl_log_recovery(); -bool execute_ddl_log_entry(uint first_entry); +bool execute_ddl_log_entry(THD *thd, uint first_entry); void lock_global_ddl_log(); void unlock_global_ddl_log(); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 351ed0dd5a6..f038c2232cf 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5342,7 +5342,8 @@ void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, DBUG_ENTER("handle_alter_part_error"); if (!part_info->first_log_entry && - execute_ddl_log_entry(part_info->first_log_entry->entry_pos)) + execute_ddl_log_entry(current_thd, + part_info->first_log_entry->entry_pos)) { /* We couldn't recover from error, most likely manual interaction diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 90251184120..e8f5fffd88b 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -434,8 +434,6 @@ static uint read_ddl_log_header() else successful_open= TRUE; } - else - sql_print_error("Failed to open ddl log file in recovery"); entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]); global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]); global_ddl_log.handler_name_len= @@ -526,11 +524,12 @@ static bool init_ddl_log() sql_print_error("Failed to open ddl log file"); DBUG_RETURN(TRUE); } + global_ddl_log.inited= TRUE; if (write_ddl_log_header()) { + global_ddl_log.inited= FALSE; DBUG_RETURN(TRUE); } - global_ddl_log.inited= TRUE; DBUG_RETURN(FALSE); } @@ -776,7 +775,6 @@ bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, VOID(sync_ddl_log()); if (write_ddl_log_header()) error= TRUE; - VOID(sync_ddl_log()); } if (error) release_ddl_log_memory_entry(*active_entry); @@ -861,7 +859,6 @@ bool write_execute_ddl_log_entry(uint first_entry, release_ddl_log_memory_entry(*active_entry); DBUG_RETURN(TRUE); } - VOID(sync_ddl_log()); } DBUG_RETURN(FALSE); } @@ -1046,7 +1043,9 @@ bool execute_ddl_log_entry(THD *thd, uint first_entry) void execute_ddl_log_recovery() { uint num_entries, i; + THD *thd; DDL_LOG_ENTRY ddl_log_entry; + char file_name[FN_REFLEN]; DBUG_ENTER("execute_ddl_log_recovery"); /* @@ -1069,7 +1068,7 @@ void execute_ddl_log_recovery() } if (ddl_log_entry.entry_type == DDL_LOG_EXECUTE_CODE) { - if (execute_ddl_log_entry(ddl_log_entry.next_entry)) + if (execute_ddl_log_entry(thd, ddl_log_entry.next_entry)) { /* Real unpleasant scenario but we continue anyways. */ DBUG_ASSERT(0); From 9a40c5bf33b0ae9bec790ed1f8ae44a809285e72 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 15 Apr 2006 21:49:13 -0400 Subject: [PATCH 43/48] WL 2826: Error handling of ALTER TABLE for partitioning After review changes mysql-test/r/ndb_partition_key.result: Fixed result file sql/ha_ndbcluster.cc: Fixed interface to create_handler_files sql/ha_ndbcluster.h: Fixed interface to create_handler_files sql/ha_partition.cc: Fixed interface to create_handler_files and made it two-stage for rename Removed print_error and now it's used by MySQL Server parts instead sql/ha_partition.h: Fixed interface to create_handler_files sql/mysql_priv.h: Fixed error injects Externalised Global DDL log mutex Some interface changes sql/mysqld.cc: Moved close of DDL log until all user threads been closed sql/sql_base.cc: Interface changes sql/sql_partition.cc: Moved print_error to mysql server part sql/sql_table.cc: Lots of after review changes sql/table.cc: Fixed upgrade code --- mysql-test/r/ndb_partition_key.result | 1 + sql/ha_ndbcluster.cc | 4 +- sql/ha_ndbcluster.h | 2 +- sql/ha_partition.cc | 24 ++++---- sql/ha_partition.h | 2 +- sql/mysql_priv.h | 21 ++++--- sql/mysqld.cc | 2 +- sql/sql_base.cc | 9 ++- sql/sql_partition.cc | 81 ++++++++++++++------------- sql/sql_table.cc | 79 +++++++++----------------- sql/table.cc | 15 ++--- 11 files changed, 107 insertions(+), 133 deletions(-) diff --git a/mysql-test/r/ndb_partition_key.result b/mysql-test/r/ndb_partition_key.result index 743453eb912..503283df532 100644 --- a/mysql-test/r/ndb_partition_key.result +++ b/mysql-test/r/ndb_partition_key.result @@ -178,6 +178,7 @@ ALTER TABLE t1 ANALYZE PARTITION p0; ERROR HY000: Table storage engine for 't1' doesn't have this option ALTER TABLE t1 REBUILD PARTITION p0; ERROR HY000: Table storage engine for 't1' doesn't have this option +DROP TABLE t1; CREATE TABLE t1 ( c1 MEDIUMINT NOT NULL AUTO_INCREMENT, c2 TEXT NOT NULL, diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 4310f8d1c12..62c751e1aef 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -4689,7 +4689,7 @@ int ha_ndbcluster::create(const char *name, int ha_ndbcluster::create_handler_files(const char *file, const char *old_name, - bool rename_flag) + int action_flag) { const char *name; Ndb* ndb; @@ -4700,7 +4700,7 @@ int ha_ndbcluster::create_handler_files(const char *file, DBUG_ENTER("create_handler_files"); - if (rename_flag) + if (action_flag) { DBUG_RETURN(FALSE); } diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 70f0c79bd20..3a46f4f702f 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -612,7 +612,7 @@ class ha_ndbcluster: public handler int delete_table(const char *name); int create(const char *name, TABLE *form, HA_CREATE_INFO *info); int create_handler_files(const char *file, const char *old_name, - bool rename_flag); + int action_flag); int get_default_no_partitions(ulonglong max_rows); bool get_no_parts(const char *name, uint *no_parts); void set_auto_partitions(partition_info *part_info); diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 15224a9bc55..e7340f327a9 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -495,7 +495,7 @@ int ha_partition::rename_table(const char *from, const char *to) int ha_partition::create_handler_files(const char *path, const char *old_path, - bool rename_flag) + int action_flag) { DBUG_ENTER("ha_partition::create_handler_files()"); @@ -503,15 +503,17 @@ int ha_partition::create_handler_files(const char *path, We need to update total number of parts since we might write the handler file as part of a partition management command */ - if (rename_flag) + if (action_flag) { char name[FN_REFLEN]; char old_name[FN_REFLEN]; strxmov(name, path, ha_par_ext, NullS); strxmov(old_name, old_path, ha_par_ext, NullS); - if (my_delete(name, MYF(MY_WME)) || - my_rename(old_name, name, MYF(MY_WME))) + if ((action_flag == CHF_DELETE_FLAG && + my_delete(name, MYF(MY_WME))) || + (action_flag == CHF_RENAME_FLAG && + my_rename(old_name, name, MYF(MY_WME)))) { DBUG_RETURN(TRUE); } @@ -1153,7 +1155,6 @@ int ha_partition::prepare_new_partition(TABLE *table, error: if (create_flag) VOID(file->delete_table(part_name)); - print_error(error, MYF(0)); DBUG_RETURN(error); } @@ -1280,7 +1281,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, (m_reorged_parts + 1)))) { mem_alloc_error(sizeof(partition_element*)*(m_reorged_parts+1)); - DBUG_RETURN(TRUE); + DBUG_RETURN(ER_OUTOFMEMORY); } /* @@ -1312,7 +1313,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, (2*(no_remain_partitions + 1))))) { mem_alloc_error(sizeof(handler*)*2*(no_remain_partitions+1)); - DBUG_RETURN(TRUE); + DBUG_RETURN(ER_OUTOFMEMORY); } m_added_file= &new_file_array[no_remain_partitions + 1]; @@ -1384,7 +1385,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, part_elem->engine_type))) { mem_alloc_error(sizeof(handler)); - DBUG_RETURN(TRUE); + DBUG_RETURN(ER_OUTOFMEMORY); } } while (++j < no_subparts); } @@ -1432,7 +1433,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, (const char *)part_name_buff))) { cleanup_new_partition(part_count); - DBUG_RETURN(TRUE); + DBUG_RETURN(error); } m_added_file[part_count++]= new_file_array[part]; } while (++j < no_subparts); @@ -1448,7 +1449,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, (const char *)part_name_buff))) { cleanup_new_partition(part_count); - DBUG_RETURN(TRUE); + DBUG_RETURN(error); } m_added_file[part_count++]= new_file_array[i]; } @@ -1554,8 +1555,7 @@ int ha_partition::copy_partitions(ulonglong *copied, ulonglong *deleted) } DBUG_RETURN(FALSE); error: - print_error(result, MYF(0)); - DBUG_RETURN(TRUE); + DBUG_RETURN(result); } diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 1a592bab340..ba223d5becf 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -180,7 +180,7 @@ public: virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info); virtual int create_handler_files(const char *name, - const char *old_name, bool rename_flag); + const char *old_name, int action_flag); virtual void update_create_info(HA_CREATE_INFO *create_info); virtual char *update_table_comment(const char *comment); virtual int change_partitions(HA_CREATE_INFO *create_info, diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index dbc1093c01a..587069c65cb 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -633,8 +633,7 @@ struct Query_cache_query_flags #else -inline bool -my_error_inject_name(const char *dbug_str) +inline bool check_and_unset_keyword(const char *dbug_str) { const char *extra_str= "-d,"; char total_str[200]; @@ -649,7 +648,7 @@ my_error_inject_name(const char *dbug_str) inline bool -my_error_inject(int value) +check_and_unset_inject_value(int value) { THD *thd= current_thd; if (thd->error_inject_value == (uint)value) @@ -700,15 +699,15 @@ my_error_inject(int value) #define ERROR_INJECT_CRASH(code) \ DBUG_EVALUATE_IF(code, (abort(), 0), 0) #define ERROR_INJECT_ACTION(code, action) \ - (my_error_inject_name(code) ? ((action), 0) : 0) + (check_and_unset_keyword(code) ? ((action), 0) : 0) #define ERROR_INJECT(code) \ - my_error_inject_name(code) + check_and_unset_keyword(code) #define ERROR_INJECT_VALUE(value) \ - my_error_inject(value) + check_and_unset_inject_value(value) #define ERROR_INJECT_VALUE_ACTION(value,action) \ - (my_error_inject(value) ? (action) : 0) + (check_and_unset_inject_value(value) ? (action) : 0) #define ERROR_INJECT_VALUE_CRASH(value) \ - (my_error_inject(value) ? abort() : 0) + ERROR_INJECT_VALUE_ACTION(value, (abort(), 0)) #endif @@ -1300,14 +1299,14 @@ bool sync_ddl_log(); void release_ddl_log(); void execute_ddl_log_recovery(); bool execute_ddl_log_entry(THD *thd, uint first_entry); -void lock_global_ddl_log(); -void unlock_global_ddl_log(); + +extern pthread_mutex_t LOCK_gdl; #define WFRM_WRITE_SHADOW 1 #define WFRM_INSTALL_SHADOW 2 #define WFRM_PACK_FRM 4 bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags); -void abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt); +int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt); void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt); void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 73990a950eb..47df3c43d4b 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3696,7 +3696,6 @@ we force server id to 2, but this MySQL server will not act as a slave."); /* (void) pthread_attr_destroy(&connection_attrib); */ DBUG_PRINT("quit",("Exiting main thread")); - release_ddl_log(); #ifndef __WIN__ #ifdef EXTRA_DEBUG2 @@ -3718,6 +3717,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); pthread_cond_wait(&COND_thread_count,&LOCK_thread_count); (void) pthread_mutex_unlock(&LOCK_thread_count); + release_ddl_log(); #if defined(__WIN__) && !defined(EMBEDDED_LIBRARY) if (Service.IsNT() && start_mode) Service.Stop(); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 4d5eb070d51..5d9b9e70269 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6140,9 +6140,8 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b) abort_and_upgrade_lock() lpt Parameter passing struct All parameters passed through the ALTER_PARTITION_PARAM_TYPE object - RETURN VALUES - TRUE Failure - FALSE Success + RETURN VALUE + 0 DESCRIPTION Remember old lock level (for possible downgrade later on), abort all waiting threads and ensure that all keeping locks currently are @@ -6156,7 +6155,7 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b) old_lock_level Old lock level */ -void abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) +int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) { uint flags= RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG; DBUG_ENTER("abort_and_upgrade_locks"); @@ -6166,7 +6165,7 @@ void abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) mysql_lock_abort(lpt->thd, lpt->table, TRUE); VOID(remove_table_from_cache(lpt->thd, lpt->db, lpt->table_name, flags)); VOID(pthread_mutex_unlock(&LOCK_open)); - DBUG_VOID_RETURN; + DBUG_RETURN(0); } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index f038c2232cf..df404b11240 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4588,12 +4588,17 @@ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) DBUG_ENTER("mysql_change_partitions"); build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); - DBUG_RETURN(file->change_partitions(lpt->create_info, - path, - &lpt->copied, - &lpt->deleted, - lpt->pack_frm_data, - lpt->pack_frm_len)); + if ((error= file->change_partitions(lpt->create_info, path, &lpt->copied, + &lpt->deleted, lpt->pack_frm_data, + lpt->pack_frm_len))) + { + if (error != ER_OUTOFMEMORY) + file->print_error(error, MYF(0)); + else + lpt->thd->fatal_error(); + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); } @@ -5016,7 +5021,7 @@ static bool write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); if (write_log_replace_delete_frm(lpt, 0UL, NULL, (const char*)shadow_path, FALSE)) goto error; @@ -5024,13 +5029,13 @@ static bool write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_execute_ddl_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) goto error; - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); set_part_info_exec_log_entry(part_info, exec_log_entry); DBUG_RETURN(FALSE); error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); part_info->first_log_entry= NULL; my_error(ER_DDL_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); @@ -5066,7 +5071,7 @@ static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table_name, ""); build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) goto error; log_entry= part_info->first_log_entry; @@ -5075,12 +5080,12 @@ static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) FALSE, &exec_log_entry)) goto error; release_part_info_log_entries(old_first_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); DBUG_RETURN(FALSE); error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); part_info->first_log_entry= old_first_log_entry; part_info->frm_log_entry= NULL; my_error(ER_DDL_LOG_ERROR, MYF(0)); @@ -5120,7 +5125,7 @@ static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table_name, ""); build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, lpt->table_name, "#"); - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, FALSE)) goto error; @@ -5133,12 +5138,12 @@ static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) FALSE, &exec_log_entry)) goto error; release_part_info_log_entries(old_first_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); DBUG_RETURN(FALSE); error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); part_info->first_log_entry= old_first_log_entry; part_info->frm_log_entry= NULL; my_error(ER_DDL_LOG_ERROR, MYF(0)); @@ -5177,7 +5182,7 @@ static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table_name, ""); build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, lpt->table_name, "#"); - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, FALSE)) goto error; @@ -5188,13 +5193,13 @@ static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_execute_ddl_log_entry(log_entry->entry_pos, FALSE, &exec_log_entry)) goto error; - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); set_part_info_exec_log_entry(part_info, exec_log_entry); DBUG_RETURN(FALSE); error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); part_info->first_log_entry= NULL; my_error(ER_DDL_LOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); @@ -5234,7 +5239,7 @@ static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table_name, ""); build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, TRUE)) goto error; @@ -5248,12 +5253,12 @@ static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) FALSE, &exec_log_entry)) goto error; release_part_info_log_entries(old_first_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); DBUG_RETURN(FALSE); error: release_part_info_log_entries(part_info->first_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); part_info->first_log_entry= old_first_log_entry; part_info->frm_log_entry= NULL; my_error(ER_DDL_LOG_ERROR, MYF(0)); @@ -5282,7 +5287,7 @@ static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, DBUG_ENTER("write_log_completed"); DBUG_ASSERT(log_entry); - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); if (write_execute_ddl_log_entry(0UL, TRUE, &log_entry)) { /* @@ -5296,7 +5301,7 @@ static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, } release_part_info_log_entries(part_info->first_log_entry); release_part_info_log_entries(part_info->exec_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); part_info->exec_log_entry= NULL; part_info->first_log_entry= NULL; DBUG_VOID_RETURN; @@ -5314,10 +5319,10 @@ static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, static void release_log_entries(partition_info *part_info) { - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); release_part_info_log_entries(part_info->first_log_entry); release_part_info_log_entries(part_info->exec_log_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); part_info->first_log_entry= NULL; part_info->exec_log_entry= NULL; } @@ -5643,8 +5648,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_drop_partition_2") || write_log_drop_partition(lpt) || ERROR_INJECT_CRASH("crash_drop_partition_3") || - ((not_completed= FALSE), FALSE) || - (abort_and_upgrade_lock(lpt), FALSE) || + (not_completed= FALSE) || + abort_and_upgrade_lock(lpt) || /* Always returns 0 */ ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || @@ -5702,13 +5707,13 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_add_partition_2") || mysql_change_partitions(lpt) || ERROR_INJECT_CRASH("crash_add_partition_3") || - (abort_and_upgrade_lock(lpt), FALSE) || + abort_and_upgrade_lock(lpt) || /* Always returns 0 */ ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || ERROR_INJECT_CRASH("crash_add_partition_4") || write_log_rename_frm(lpt) || - ((not_completed= FALSE), FALSE) || + (not_completed= FALSE) || ERROR_INJECT_CRASH("crash_add_partition_5") || ((frm_install= TRUE), FALSE) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || @@ -5784,8 +5789,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_change_partition_3") || write_log_final_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_4") || - ((not_completed= FALSE), FALSE) || - (abort_and_upgrade_lock(lpt), FALSE) || + (not_completed= FALSE) || + abort_and_upgrade_lock(lpt) || /* Always returns 0 */ ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || @@ -6455,10 +6460,9 @@ static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR *part_iter) the del_ren_cre_table method. */ -void -create_partition_name(char *out, const char *in1, - const char *in2, uint name_variant, - bool translate) +void create_partition_name(char *out, const char *in1, + const char *in2, uint name_variant, + bool translate) { char transl_part_name[FN_REFLEN]; const char *transl_part; @@ -6498,10 +6502,9 @@ create_partition_name(char *out, const char *in1, the del_ren_cre_table method. */ -void -create_subpartition_name(char *out, const char *in1, - const char *in2, const char *in3, - uint name_variant) +void create_subpartition_name(char *out, const char *in1, + const char *in2, const char *in3, + uint name_variant) { char transl_part_name[FN_REFLEN], transl_subpart_name[FN_REFLEN]; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e8f5fffd88b..8e8d430f894 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -270,6 +270,12 @@ static int mysql_copy_key_list(List *orig_key, typedef struct st_global_ddl_log { + /* + We need to adjust buffer size to be able to handle downgrades/upgrades + where IO_SIZE has changed. We'll set the buffer size such that we can + handle that the buffer size was upto 4 times bigger in the version + that wrote the DDL log. + */ char file_entry_buf[4*IO_SIZE]; char file_name_str[FN_REFLEN]; char *file_name; @@ -278,7 +284,6 @@ typedef struct st_global_ddl_log uint num_entries; File file_id; uint name_len; - uint handler_name_len; uint io_size; bool inited; bool recovery_phase; @@ -296,8 +301,7 @@ pthread_mutex_t LOCK_gdl; #define DDL_LOG_NUM_ENTRY_POS 0 #define DDL_LOG_NAME_LEN_POS 4 -#define DDL_LOG_HANDLER_TYPE_POS 8 -#define DDL_LOG_IO_SIZE_POS 12 +#define DDL_LOG_IO_SIZE_POS 8 /* Read one entry from ddl log file @@ -368,9 +372,6 @@ static bool write_ddl_log_header() const_var= FN_LEN; int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_LEN_POS], const_var); - const_var= DDL_LOG_HANDLER_TYPE_LEN; - int4store(&global_ddl_log.file_entry_buf[DDL_LOG_HANDLER_TYPE_POS], - const_var); const_var= IO_SIZE; int4store(&global_ddl_log.file_entry_buf[DDL_LOG_IO_SIZE_POS], const_var); @@ -424,7 +425,8 @@ static uint read_ddl_log_header() global_ddl_log.inited= FALSE; global_ddl_log.recovery_phase= TRUE; create_ddl_log_file_name(file_name); - if (!(my_open(file_name, O_RDWR | O_BINARY, MYF(MY_WME)))) + if (!(global_ddl_log.file_id= my_open(file_name, + O_RDWR | O_BINARY, MYF(MY_WME)))) { if (read_ddl_log_file_entry(0UL)) { @@ -436,10 +438,12 @@ static uint read_ddl_log_header() } entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]); global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]); - global_ddl_log.handler_name_len= - uint4korr(&file_entry_buf[DDL_LOG_HANDLER_TYPE_POS]); - if (successful_open) + if (successful_open) + { global_ddl_log.io_size= uint4korr(&file_entry_buf[DDL_LOG_IO_SIZE_POS]); + DBUG_ASSERT(global_ddl_log.io_size <= + sizeof(global_ddl_log.file_entry_buf)); + } else { global_ddl_log.io_size= IO_SIZE; @@ -790,7 +794,9 @@ bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, to execute, if 0 = NULL it means that the entry is removed and the entries are put into the free list. - in:out:exec_entry Entry to execute, 0 = NULL if the entry + complete Flag indicating we are simply writing + info about that entry has been completed + in:out:active_entry Entry to execute, 0 = NULL if the entry is written first time and needs to be returned. In this case the entry written is returned in this parameter @@ -1003,12 +1009,11 @@ bool execute_ddl_log_entry(THD *thd, uint first_entry) uint read_entry= first_entry; DBUG_ENTER("execute_ddl_log_entry"); - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); do { if (read_ddl_log_entry(read_entry, &ddl_log_entry)) { - DBUG_ASSERT(0); /* Write to error log and continue with next log entry */ sql_print_error("Failed to read entry = %u from ddl log", read_entry); @@ -1019,7 +1024,6 @@ bool execute_ddl_log_entry(THD *thd, uint first_entry) if (execute_ddl_log_action(thd, &ddl_log_entry)) { - DBUG_ASSERT(0); /* Write to error log and continue with next log entry */ sql_print_error("Failed to execute action for entry = %u from ddl log", read_entry); @@ -1027,7 +1031,7 @@ bool execute_ddl_log_entry(THD *thd, uint first_entry) } read_entry= ddl_log_entry.next_entry; } while (read_entry); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); DBUG_RETURN(FALSE); } @@ -1061,7 +1065,6 @@ void execute_ddl_log_recovery() { if (read_ddl_log_entry(i, &ddl_log_entry)) { - DBUG_ASSERT(0); sql_print_error("Failed to read entry no = %u from ddl log", i); continue; @@ -1071,7 +1074,6 @@ void execute_ddl_log_recovery() if (execute_ddl_log_entry(thd, ddl_log_entry.next_entry)) { /* Real unpleasant scenario but we continue anyways. */ - DBUG_ASSERT(0); continue; } } @@ -1100,7 +1102,7 @@ void release_ddl_log() DDL_LOG_MEMORY_ENTRY *used_list= global_ddl_log.first_used; DBUG_ENTER("release_ddl_log"); - lock_global_ddl_log(); + pthread_mutex_lock(&LOCK_gdl); while (used_list) { DDL_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry; @@ -1114,46 +1116,12 @@ void release_ddl_log() free_list= tmp; } VOID(my_close(global_ddl_log.file_id, MYF(0))); - unlock_global_ddl_log(); + pthread_mutex_unlock(&LOCK_gdl); VOID(pthread_mutex_destroy(&LOCK_gdl)); DBUG_VOID_RETURN; } -/* - Lock mutex for global ddl log - SYNOPSIS - lock_global_ddl_log() - RETURN VALUES - NONE -*/ - -void lock_global_ddl_log() -{ - DBUG_ENTER("lock_global_ddl_log"); - - VOID(pthread_mutex_lock(&LOCK_gdl)); - DBUG_VOID_RETURN; -} - - -/* - Unlock mutex for global ddl log - SYNOPSIS - unlock_global_ddl_log() - RETURN VALUES - NONE -*/ - -void unlock_global_ddl_log() -{ - DBUG_ENTER("unlock_global_ddl_log"); - - VOID(pthread_mutex_unlock(&LOCK_gdl)); - DBUG_VOID_RETURN; -} - - /* --------------------------------------------------------------------------- @@ -1296,11 +1264,14 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) VOID(pthread_mutex_lock(&LOCK_open)); if (my_delete(frm_name, MYF(MY_WME)) || #ifdef WITH_PARTITION_STORAGE_ENGINE + lpt->table->file->create_handler_files(path, shadow_path, + CHF_DELETE_FLAG) || deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos) || (sync_ddl_log(), FALSE) || #endif my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || - lpt->table->file->create_handler_files(path, shadow_path, TRUE)) + lpt->table->file->create_handler_files(path, shadow_path, + CHF_RENAME_FLAG)) { error= 1; } diff --git a/sql/table.cc b/sql/table.cc index d8d5b841e21..20ab550bf66 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -667,15 +667,16 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, #endif next_chunk+= 5 + partition_info_len; } -#if 1 - if (share->mysql_version == 50106 || - share->mysql_version == 50107) +#if MYSQL_VERSION_ID < 50200 + if (share->mysql_version >= 50106 && share->mysql_version <= 50109) { /* - Partition state array was here in version 5.1.6, this code makes - it possible to load a 5.1.6 table in later versions. Can most - likely be removed at some point in time. - */ + Partition state array was here in version 5.1.6 to 5.1.9, this code + makes it possible to load a 5.1.6 table in later versions. Can most + likely be removed at some point in time. Will only be used for + upgrades within 5.1 series of versions. Upgrade to 5.2 can only be + done from newer 5.1 versions. + */ next_chunk+= 4; } #endif From 4624982ecb152616c88f18e52d4d2896ff4522b0 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 18 Apr 2006 16:58:12 +0200 Subject: [PATCH 44/48] WL 2826: Error handling of ALTER TABLE for partitioning Use \0 to indicate frm-file Add more comments Add more #ifdef code missing previously sql/sql_partition.cc: Use \0 to indicate frm-file sql/sql_table.cc: Use \0 to indicate frm-file Add more comments Add more #ifdef code missing previously --- sql/sql_partition.cc | 2 +- sql/sql_table.cc | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index df404b11240..7bc654c787d 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4759,7 +4759,7 @@ static bool write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, else ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION; ddl_log_entry.next_entry= next_entry; - ddl_log_entry.handler_name= "frm"; + ddl_log_entry.handler_name[0]= 0; ddl_log_entry.name= to_path; if (replace_flag) ddl_log_entry.from_name= from_path; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8e8d430f894..45f25b51f21 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -574,7 +574,7 @@ static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) DBUG_RETURN(TRUE); } init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); - if (strcmp("frm", ddl_log_entry->handler_name)) + if (ddl_log_entry->handler_name[0] == 0) frm_action= TRUE; else { @@ -1260,6 +1260,12 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) /* When we are changing to use new frm file we need to ensure that we don't collide with another thread in process to open the frm file. + We start by deleting the .frm file and possible .par file. Then we + write to the DDL log that we have completed the delete phase by + increasing the phase of the log entry. Next step is to rename the + new .frm file and the new .par file to the real name. After + completing this we write a new phase to the log entry that will + deactivate it. */ VOID(pthread_mutex_lock(&LOCK_open)); if (my_delete(frm_name, MYF(MY_WME)) || @@ -1269,9 +1275,13 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos) || (sync_ddl_log(), FALSE) || #endif +#ifdef WITH_PARTITION_STORAGE_ENGINE my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || lpt->table->file->create_handler_files(path, shadow_path, CHF_RENAME_FLAG)) +#else + my_rename(shadow_frm_name, frm_name, MYF(MY_WME))) +#endif { error= 1; } From c1b8cff03f9826efc168b683797c5646f3a0c014 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Apr 2006 12:05:44 -0400 Subject: [PATCH 45/48] WL 2826: Error handling of ALTER TABLE for partitioning Moved error inject from being flags to compiler to being part of config.h Also error inject only defined if debug is also defined +Small fixes configure.in: Moved error inject from being flags to compiler to being part of config.h Also error inject only defined if debug is also defined sql/handler.h: Small fixes --- configure.in | 27 +++++++++++++++------------ sql/handler.h | 12 +++++++----- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/configure.in b/configure.in index bfd2ec21869..157d2549d62 100644 --- a/configure.in +++ b/configure.in @@ -1588,18 +1588,6 @@ then DEBUG_OPTIMIZE_CXX="" fi -# If we should allow error injection tests -AC_ARG_WITH(error-inject, - [ --with-error-inject Enable error injection in MySQL Server], - [ with_error_inject=$withval ], - [ with_error_inject=no ]) - -if test "$with_error_inject" = "yes" -then - CFLAGS="-DERROR_INJECT_SUPPORT $CFLAGS" - CXXFLAGS="-DERROR_INJECT_SUPPORT $CXXFLAGS" -fi - AC_ARG_WITH(debug, [ --with-debug Add debug code --with-debug=full Add debug code (adds memory checker, very slow)], @@ -1621,6 +1609,21 @@ else CXXFLAGS="$OPTIMIZE_CXXFLAGS -DDBUG_OFF $CXXFLAGS" fi +# If we should allow error injection tests +AC_ARG_WITH(error-inject, + [ --with-error-inject Enable error injection in MySQL Server], + [ with_error_inject=$withval ], + [ with_error_inject=no ]) + +if test $with_debug != "no" +then + if test "$with_error_inject" = "yes" + then + AC_DEFINE([ERROR_INJECT_SUPPORT], [1], + [Enable error injection in MySQL Server]) + fi +fi + AC_ARG_WITH([fast-mutexes], AC_HELP_STRING([--with-fast-mutexes], [Compile with fast mutexes (default is disabled)]), diff --git a/sql/handler.h b/sql/handler.h index 5cc2aa126c4..2e96e74afd4 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1378,11 +1378,13 @@ public: virtual void drop_table(const char *name); virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0; + +#define CHF_DELETE_FLAG 1 +#define CHF_RENAME_FLAG 2 + virtual int create_handler_files(const char *name, const char *old_name, - bool rename_flag) - { - return FALSE; - } + int action_flag) + { return FALSE; } virtual int change_partitions(HA_CREATE_INFO *create_info, const char *path, @@ -1390,7 +1392,7 @@ public: ulonglong *deleted, const void *pack_frm_data, uint pack_frm_len) - { print_error(HA_ERR_WRONG_COMMAND, MYF(0)); return TRUE; } + { return HA_ERR_WRONG_COMMAND; } virtual int drop_partitions(const char *path) { return HA_ERR_WRONG_COMMAND; } virtual int rename_partitions(const char *path) From c0d1c190f8e08ed5ba431447be8b98abbbfec2ff Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Apr 2006 16:08:59 -0400 Subject: [PATCH 46/48] WL 2826: Error handling of ALTER TABLE for partitioning Fixed a number of bugs sql/sql_table.cc: Fixed a number of bugs --- sql/sql_table.cc | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8e8d430f894..850f473a4c6 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -424,9 +424,10 @@ static uint read_ddl_log_header() bzero(file_entry_buf, sizeof(global_ddl_log.file_entry_buf)); global_ddl_log.inited= FALSE; global_ddl_log.recovery_phase= TRUE; + global_ddl_log.io_size= IO_SIZE; create_ddl_log_file_name(file_name); - if (!(global_ddl_log.file_id= my_open(file_name, - O_RDWR | O_BINARY, MYF(MY_WME)))) + if ((global_ddl_log.file_id= my_open(file_name, + O_RDWR | O_BINARY, MYF(MY_WME))) >= 0) { if (read_ddl_log_file_entry(0UL)) { @@ -446,7 +447,6 @@ static uint read_ddl_log_header() } else { - global_ddl_log.io_size= IO_SIZE; entry_no= 0; } global_ddl_log.first_free= NULL; @@ -519,6 +519,7 @@ static bool init_ddl_log() DBUG_RETURN(FALSE); } global_ddl_log.io_size= IO_SIZE; + create_ddl_log_file_name(file_name); if ((global_ddl_log.file_id= my_create(file_name, CREATE_MODE, O_RDWR | O_TRUNC | O_BINARY, @@ -567,18 +568,19 @@ static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) } handler_name.str= (char*)ddl_log_entry->handler_name; handler_name.length= strlen(ddl_log_entry->handler_name); - hton= ha_resolve_by_name(thd, &handler_name); - if (!hton) - { - my_error(ER_ILLEGAL_HA, MYF(0), ddl_log_entry->handler_name); - DBUG_RETURN(TRUE); - } init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); if (strcmp("frm", ddl_log_entry->handler_name)) frm_action= TRUE; else { TABLE_SHARE dummy; + + hton= ha_resolve_by_name(thd, &handler_name); + if (!hton) + { + my_error(ER_ILLEGAL_HA, MYF(0), ddl_log_entry->handler_name); + goto error; + } bzero(&dummy, sizeof(TABLE_SHARE)); file= get_new_handler(&dummy, &mem_root, hton); if (!file) From 319c5da1523a0b1915ed75ec5e4ae7136e81c1eb Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Apr 2006 20:04:00 -0400 Subject: [PATCH 47/48] WL 2826: Error handling of ALTER TABLE for partitioning Various bug fixes (mostly mixed to and from in replace methods) sql/sql_partition.cc: Various bug fixes (mostly mixed to and from in replace methods) sql/sql_table.cc: Various bug fixes (mostly mixed to and from in replace methods) --- sql/sql_partition.cc | 15 ++++----- sql/sql_table.cc | 72 ++++++++++++++++++++++++-------------------- 2 files changed, 47 insertions(+), 40 deletions(-) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 7bc654c787d..792a6d33a87 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4733,8 +4733,9 @@ static void release_part_info_log_entries(DDL_LOG_MEMORY_ENTRY *log_entry) write_log_replace_delete_frm() lpt Struct for parameters next_entry Next reference to use in log record - path Name to rename from - rename_flag TRUE if rename, else delete + from_path Name to rename from + to_path Name to rename to + replace_flag TRUE if replace, else delete RETURN VALUES TRUE Error FALSE Success @@ -4759,7 +4760,7 @@ static bool write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, else ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION; ddl_log_entry.next_entry= next_entry; - ddl_log_entry.handler_name[0]= 0; + ddl_log_entry.handler_name= reg_ext; ddl_log_entry.name= to_path; if (replace_flag) ddl_log_entry.from_name= from_path; @@ -5072,7 +5073,7 @@ static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, lpt->table_name, "#"); pthread_mutex_lock(&LOCK_gdl); - if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) + if (write_log_replace_delete_frm(lpt, 0UL, shadow_path, path, TRUE)) goto error; log_entry= part_info->first_log_entry; part_info->frm_log_entry= log_entry; @@ -5129,8 +5130,8 @@ static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, FALSE)) goto error; - if (write_log_replace_delete_frm(lpt, next_entry, (const char*)path, - (const char*)tmp_path, TRUE)) + if (write_log_replace_delete_frm(lpt, next_entry, (const char*)tmp_path, + (const char*)path, TRUE)) goto error; log_entry= part_info->first_log_entry; part_info->frm_log_entry= log_entry; @@ -5245,7 +5246,7 @@ static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) goto error; if (write_log_changed_partitions(lpt, &next_entry, (const char*)path)) goto error; - if (write_log_replace_delete_frm(lpt, 0UL, path, shadow_path, FALSE)) + if (write_log_replace_delete_frm(lpt, 0UL, shadow_path, path, TRUE)) goto error; log_entry= part_info->first_log_entry; part_info->frm_log_entry= log_entry; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 096e5c54834..09a54a14b91 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -474,6 +474,7 @@ bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry) { char *file_entry_buf= (char*)&global_ddl_log.file_entry_buf; uint inx; + uchar single_char; DBUG_ENTER("read_ddl_log_entry"); if (read_ddl_log_file_entry(read_entry)) @@ -481,10 +482,10 @@ bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry) DBUG_RETURN(TRUE); } ddl_log_entry->entry_pos= read_entry; - ddl_log_entry->entry_type= - (enum ddl_log_entry_code)file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]; - ddl_log_entry->action_type= - (enum ddl_log_action_code)file_entry_buf[DDL_LOG_ACTION_TYPE_POS]; + single_char= file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]; + ddl_log_entry->entry_type= (enum ddl_log_entry_code)single_char; + single_char= file_entry_buf[DDL_LOG_ACTION_TYPE_POS]; + ddl_log_entry->action_type= (enum ddl_log_action_code)single_char; ddl_log_entry->phase= file_entry_buf[DDL_LOG_PHASE_POS]; ddl_log_entry->next_entry= uint4korr(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS]); ddl_log_entry->name= &file_entry_buf[DDL_LOG_NAME_POS]; @@ -553,10 +554,10 @@ static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) { bool frm_action= FALSE; LEX_STRING handler_name; - handler *file; + handler *file= NULL; MEM_ROOT mem_root; bool error= TRUE; - char path[FN_REFLEN]; + char to_path[FN_REFLEN]; char from_path[FN_REFLEN]; char *par_ext= (char*)".par"; handlerton *hton; @@ -569,7 +570,7 @@ static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) handler_name.str= (char*)ddl_log_entry->handler_name; handler_name.length= strlen(ddl_log_entry->handler_name); init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); - if (ddl_log_entry->handler_name[0] == 0) + if (!strcmp(ddl_log_entry->handler_name, reg_ext)) frm_action= TRUE; else { @@ -598,24 +599,29 @@ static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) { if (frm_action) { - strxmov(path, ddl_log_entry->name, reg_ext, NullS); - if (my_delete(path, MYF(MY_WME))) - break; + strxmov(to_path, ddl_log_entry->name, reg_ext, NullS); + if ((error= my_delete(to_path, MYF(MY_WME)))) + { + if (error != ENOENT) + break; + } #ifdef WITH_PARTITION_STORAGE_ENGINE - strxmov(path, ddl_log_entry->name, par_ext, NullS); - VOID(my_delete(path, MYF(MY_WME))); + strxmov(to_path, ddl_log_entry->name, par_ext, NullS); + VOID(my_delete(to_path, MYF(MY_WME))); #endif } else { - if (file->delete_table(ddl_log_entry->name)) - break; + if ((error= file->delete_table(ddl_log_entry->name))) + { + if (error != ENOENT && error != HA_ERR_NO_SUCH_TABLE) + break; + } } if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) - { - VOID(sync_ddl_log()); - error= FALSE; - } + break; + VOID(sync_ddl_log()); + error= FALSE; if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION) break; } @@ -631,27 +637,26 @@ static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) error= TRUE; if (frm_action) { - strxmov(path, ddl_log_entry->name, reg_ext, NullS); + strxmov(to_path, ddl_log_entry->name, reg_ext, NullS); strxmov(from_path, ddl_log_entry->from_name, reg_ext, NullS); - if (my_rename(path, from_path, MYF(MY_WME))) + if (my_rename(from_path, to_path, MYF(MY_WME))) break; #ifdef WITH_PARTITION_STORAGE_ENGINE - strxmov(path, ddl_log_entry->name, par_ext, NullS); + strxmov(to_path, ddl_log_entry->name, par_ext, NullS); strxmov(from_path, ddl_log_entry->from_name, par_ext, NullS); - VOID(my_rename(path, from_path, MYF(MY_WME))); + VOID(my_rename(from_path, to_path, MYF(MY_WME))); #endif } else { - if (file->rename_table(ddl_log_entry->name, - ddl_log_entry->from_name)) + if (file->rename_table(ddl_log_entry->from_name, + ddl_log_entry->name)) break; } if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) - { - VOID(sync_ddl_log()); - error= FALSE; - } + break; + VOID(sync_ddl_log()); + error= FALSE; break; } default: @@ -744,9 +749,10 @@ bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, { DBUG_RETURN(TRUE); } - global_ddl_log.file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_LOG_ENTRY_CODE; + global_ddl_log.file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= + (char)DDL_LOG_ENTRY_CODE; global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= - ddl_log_entry->action_type; + (char)ddl_log_entry->action_type; global_ddl_log.file_entry_buf[DDL_LOG_PHASE_POS]= 0; int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], ddl_log_entry->next_entry); @@ -836,10 +842,10 @@ bool write_execute_ddl_log_entry(uint first_entry, entry to indicate it is done. */ VOID(sync_ddl_log()); - file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_LOG_EXECUTE_CODE; + file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_LOG_EXECUTE_CODE; } else - file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_IGNORE_LOG_ENTRY_CODE; + file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_IGNORE_LOG_ENTRY_CODE; file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= 0; /* Ignored for execute entries */ file_entry_buf[DDL_LOG_PHASE_POS]= 0; int4store(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], first_entry); @@ -1063,7 +1069,7 @@ void execute_ddl_log_recovery() thd->store_globals(); num_entries= read_ddl_log_header(); - for (i= 0; i < num_entries; i++) + for (i= 1; i < num_entries + 1; i++) { if (read_ddl_log_entry(i, &ddl_log_entry)) { From 66e73768cf9d75c47ec6f8cb17226d213724fa7a Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Apr 2006 20:57:42 -0400 Subject: [PATCH 48/48] WL2826: Error handling of ALTER TABLE for partitioning Actual error reported in my_errno from my_delete sql/sql_table.cc: Actual error reported in my_errno from my_delete --- sql/sql_table.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 09a54a14b91..17d3fa909d5 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -550,13 +550,13 @@ static bool init_ddl_log() FALSE Success */ -static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) +static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) { bool frm_action= FALSE; LEX_STRING handler_name; handler *file= NULL; MEM_ROOT mem_root; - bool error= TRUE; + int error= TRUE; char to_path[FN_REFLEN]; char from_path[FN_REFLEN]; char *par_ext= (char*)".par"; @@ -602,7 +602,7 @@ static bool execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) strxmov(to_path, ddl_log_entry->name, reg_ext, NullS); if ((error= my_delete(to_path, MYF(MY_WME)))) { - if (error != ENOENT) + if (my_errno != ENOENT) break; } #ifdef WITH_PARTITION_STORAGE_ENGINE