WL 2826: First step in error handling of ALTER TABLE for partitioning

parent 86a15e5e
...@@ -71,6 +71,7 @@ pentium_cflags="$check_cpu_cflags" ...@@ -71,6 +71,7 @@ pentium_cflags="$check_cpu_cflags"
pentium64_cflags="$check_cpu_cflags -m64" pentium64_cflags="$check_cpu_cflags -m64"
ppc_cflags="$check_cpu_cflags" ppc_cflags="$check_cpu_cflags"
sparc_cflags="" sparc_cflags=""
error_inject_flag="--with-error-inject "
# be as fast as we can be without losing our ability to backtrace # be as fast as we can be without losing our ability to backtrace
fast_cflags="-O3 -fno-omit-frame-pointer" fast_cflags="-O3 -fno-omit-frame-pointer"
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
path=`dirname $0` path=`dirname $0`
. "$path/SETUP.sh" $@ --with-debug=full . "$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" c_warnings="$c_warnings $debug_extra_warnings"
cxx_warnings="$cxx_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"
......
...@@ -654,6 +654,7 @@ else ...@@ -654,6 +654,7 @@ else
AC_MSG_RESULT([no]) AC_MSG_RESULT([no])
fi fi
MYSQL_SYS_LARGEFILE MYSQL_SYS_LARGEFILE
# Types that must be checked AFTER large file support is checked # Types that must be checked AFTER large file support is checked
...@@ -1554,6 +1555,18 @@ then ...@@ -1554,6 +1555,18 @@ then
DEBUG_OPTIMIZE_CXX="" DEBUG_OPTIMIZE_CXX=""
fi 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, AC_ARG_WITH(debug,
[ --without-debug Build a production version without debugging code], [ --without-debug Build a production version without debugging code],
[with_debug=$withval], [with_debug=$withval],
......
...@@ -4399,7 +4399,9 @@ int ha_ndbcluster::create(const char *name, ...@@ -4399,7 +4399,9 @@ int ha_ndbcluster::create(const char *name,
DBUG_RETURN(my_errno); 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; const char *name;
Ndb* ndb; Ndb* ndb;
...@@ -4410,6 +4412,10 @@ int ha_ndbcluster::create_handler_files(const char *file) ...@@ -4410,6 +4412,10 @@ int ha_ndbcluster::create_handler_files(const char *file)
DBUG_ENTER("create_handler_files"); DBUG_ENTER("create_handler_files");
if (rename_flag)
{
DBUG_RETURN(FALSE);
}
if (!(ndb= get_ndb())) if (!(ndb= get_ndb()))
DBUG_RETURN(HA_ERR_NO_CONNECTION); DBUG_RETURN(HA_ERR_NO_CONNECTION);
......
...@@ -588,7 +588,8 @@ class ha_ndbcluster: public handler ...@@ -588,7 +588,8 @@ class ha_ndbcluster: public handler
int rename_table(const char *from, const char *to); int rename_table(const char *from, const char *to);
int delete_table(const char *name); int delete_table(const char *name);
int create(const char *name, TABLE *form, HA_CREATE_INFO *info); 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); int get_default_no_partitions(ulonglong max_rows);
bool get_no_parts(const char *name, uint *no_parts); bool get_no_parts(const char *name, uint *no_parts);
void set_auto_partitions(partition_info *part_info); void set_auto_partitions(partition_info *part_info);
......
...@@ -563,7 +563,9 @@ int ha_partition::rename_table(const char *from, const char *to) ...@@ -563,7 +563,9 @@ int ha_partition::rename_table(const char *from, const char *to)
and types of engines in the partitions. 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()"); DBUG_ENTER("ha_partition::create_handler_files()");
...@@ -571,10 +573,27 @@ int ha_partition::create_handler_files(const char *name) ...@@ -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 We need to update total number of parts since we might write the handler
file as part of a partition management command 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)); char name[FN_REFLEN];
DBUG_RETURN(1); 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); DBUG_RETURN(0);
} }
......
...@@ -179,7 +179,8 @@ class ha_partition :public handler ...@@ -179,7 +179,8 @@ class ha_partition :public handler
virtual int rename_table(const char *from, const char *to); virtual int rename_table(const char *from, const char *to);
virtual int create(const char *name, TABLE *form, virtual int create(const char *name, TABLE *form,
HA_CREATE_INFO *create_info); 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 void update_create_info(HA_CREATE_INFO *create_info);
virtual char *update_table_comment(const char *comment); virtual char *update_table_comment(const char *comment);
virtual int change_partitions(HA_CREATE_INFO *create_info, virtual int change_partitions(HA_CREATE_INFO *create_info,
......
...@@ -1779,7 +1779,11 @@ class handler :public Sql_alloc ...@@ -1779,7 +1779,11 @@ class handler :public Sql_alloc
virtual void drop_table(const char *name); virtual void drop_table(const char *name);
virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0; 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, virtual int change_partitions(HA_CREATE_INFO *create_info,
const char *path, const char *path,
......
...@@ -603,6 +603,29 @@ struct Query_cache_query_flags ...@@ -603,6 +603,29 @@ struct Query_cache_query_flags
#define query_cache_invalidate_by_MyISAM_filename_ref NULL #define query_cache_invalidate_by_MyISAM_filename_ref NULL
#endif /*HAVE_QUERY_CACHE*/ #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, uint build_table_path(char *buff, size_t bufflen, const char *db,
const char *table, const char *ext); const char *table, const char *ext);
void write_bin_log(THD *thd, bool clear_error, void write_bin_log(THD *thd, bool clear_error,
...@@ -1099,9 +1122,10 @@ typedef struct st_lock_param_type ...@@ -1099,9 +1122,10 @@ typedef struct st_lock_param_type
} ALTER_PARTITION_PARAM_TYPE; } ALTER_PARTITION_PARAM_TYPE;
void mem_alloc_error(size_t size); void mem_alloc_error(size_t size);
#define WFRM_INITIAL_WRITE 1 bool write_table_log(ALTER_PARTITION_PARAM_TYPE *lpt);
#define WFRM_CREATE_HANDLER_FILES 2 #define WFRM_WRITE_SHADOW 1
#define WFRM_PACK_FRM 4 #define WFRM_INSTALL_SHADOW 2
#define WFRM_PACK_FRM
bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags); 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);
void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt); void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt);
......
...@@ -7055,6 +7055,12 @@ static void mysql_init_variables(void) ...@@ -7055,6 +7055,12 @@ static void mysql_init_variables(void)
max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR;
global_system_variables.old_passwords= 0; global_system_variables.old_passwords= 0;
global_system_variables.old_alter_table= 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 Default behavior for 4.1 and 5.0 is to treat NULL values as unequal
......
...@@ -215,6 +215,12 @@ sys_var_long_ptr sys_delayed_insert_timeout("delayed_insert_timeout", ...@@ -215,6 +215,12 @@ sys_var_long_ptr sys_delayed_insert_timeout("delayed_insert_timeout",
&delayed_insert_timeout); &delayed_insert_timeout);
sys_var_long_ptr sys_delayed_queue_size("delayed_queue_size", sys_var_long_ptr sys_delayed_queue_size("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", sys_var_event_executor sys_event_executor("event_scheduler",
&event_executor_running_global_var); &event_executor_running_global_var);
sys_var_long_ptr sys_expire_logs_days("expire_logs_days", sys_var_long_ptr sys_expire_logs_days("expire_logs_days",
...@@ -729,6 +735,10 @@ SHOW_VAR init_vars[]= { ...@@ -729,6 +735,10 @@ SHOW_VAR init_vars[]= {
{sys_div_precincrement.name,(char*) &sys_div_precincrement,SHOW_SYS}, {sys_div_precincrement.name,(char*) &sys_div_precincrement,SHOW_SYS},
{sys_engine_condition_pushdown.name, {sys_engine_condition_pushdown.name,
(char*) &sys_engine_condition_pushdown, SHOW_SYS}, (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_event_executor.name, (char*) &sys_event_executor, SHOW_SYS},
{sys_expire_logs_days.name, (char*) &sys_expire_logs_days, SHOW_SYS}, {sys_expire_logs_days.name, (char*) &sys_expire_logs_days, SHOW_SYS},
{sys_flush.name, (char*) &sys_flush, SHOW_SYS}, {sys_flush.name, (char*) &sys_flush, SHOW_SYS},
......
...@@ -186,6 +186,10 @@ struct system_variables ...@@ -186,6 +186,10 @@ struct system_variables
ha_rows max_join_size; ha_rows max_join_size;
ulong auto_increment_increment, auto_increment_offset; ulong auto_increment_increment, auto_increment_offset;
ulong bulk_insert_buff_size; ulong bulk_insert_buff_size;
#ifdef ERROR_INJECT_SUPPORT
ulong error_inject_code;
ulong error_inject_value;
#endif
ulong join_buff_size; ulong join_buff_size;
ulong long_query_time; ulong long_query_time;
ulong max_allowed_packet; ulong max_allowed_packet;
......
...@@ -5244,7 +5244,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ...@@ -5244,7 +5244,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
1) Write the new frm, pack it and then delete it 1) Write the new frm, pack it and then delete it
2) Perform the change within the handler 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))) (mysql_change_partitions(lpt)))
{ {
fast_alter_partition_error_handler(lpt); fast_alter_partition_error_handler(lpt);
...@@ -5275,29 +5275,56 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ...@@ -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 after a DROP PARTITION) if one ensured that failed accesses to the
dropped partitions was aborted for sure (thus only possible for dropped partitions was aborted for sure (thus only possible for
transactional engines). 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 the table have completed
2) Write the new frm file where the partitions have changed but are 4) Write the bin log
still remaining with the state PART_TO_BE_DROPPED Unfortunately the writing of the binlog is not synchronised with
3) Write the bin log other logging activities. So no matter in which order the binlog
4) Prepare MyISAM handlers for drop of partitions is written compared to other activities there will always be cases
5) Ensure that any users that has opened the table but not yet 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. reached the abort lock do that before downgrading the lock.
6) Drop the partitions 7) Prepare MyISAM handlers for drop of partitions
7) Write the frm file that the partition has been dropped 8) Drop the partitions
8) Wait until all accesses using the old frm file has completed 9) Remove entries from table log
9) Complete query 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)) || if (write_log_shadow_frm(lpt) ||
(mysql_write_frm(lpt, WFRM_INITIAL_WRITE)) || 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) && ((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE, write_bin_log(thd, FALSE,
thd->query, thd->query_length), FALSE)) || thd->query, thd->query_length), FALSE) ||
(table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE)) || ERROR_INJECTOR_CRASH(1003) ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
(close_open_tables_and_downgrade(lpt), FALSE) || (close_open_tables_and_downgrade(lpt), FALSE) ||
(mysql_drop_partitions(lpt)) || ERROR_INJECTOR_CRASH(1004) ||
(mysql_write_frm(lpt, WFRM_CREATE_HANDLER_FILES)) || 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)) (mysql_wait_completed_table(lpt, table), FALSE))
{ {
fast_alter_partition_error_handler(lpt); fast_alter_partition_error_handler(lpt);
...@@ -5317,26 +5344,38 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ...@@ -5317,26 +5344,38 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
miss updates made by a transaction serialised before it that are miss updates made by a transaction serialised before it that are
inserted into the new partition. inserted into the new partition.
1) Write the new frm file where state of added partitions is 0) Write an entry that removes the shadow frm file if crash occurs
changed to PART_TO_BE_ADDED 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 2) Add the new partitions
3) Lock all partitions in TL_WRITE_ONLY to ensure that no users 3) Lock all partitions in TL_WRITE_ONLY to ensure that no users
are still using the old partitioning scheme. Wait until all are still using the old partitioning scheme. Wait until all
ongoing users have completed before progressing. ongoing users have completed before progressing.
4) Write a new frm file of the table where the partitions are added 4) Write binlog
to the table. 5) Install the new frm file of the table where the partitions are
5) Write binlog added to the table.
6) Wait until all accesses using the old frm file has completed 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)) || if (write_log_shadow_frm(lpt) ||
(mysql_change_partitions(lpt)) || ERROR_INJECTED_CRASH(1010) ||
(abort_and_upgrade_lock(lpt)) || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
(mysql_write_frm(lpt, WFRM_CREATE_HANDLER_FILES)) || 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) && ((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE, (write_bin_log(thd, FALSE,
thd->query, thd->query_length), 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); fast_alter_partition_error_handler(lpt);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
...@@ -5375,40 +5414,56 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ...@@ -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 use a lower lock level. This can be handled inside store_lock in the
respective handler. respective handler.
1) Write the new frm file where state of added partitions is 0) Write an entry that removes the shadow frm file if crash occurs
changed to PART_TO_BE_ADDED and the reorganised partitions 1) Write the shadow frm file of new partitioning
are set in state PART_TO_BE_REORGED. 2) Log such that temporary partitions added in change phase are
2) Add the new partitions removed in a crash situation
3) Add the new partitions
Copy from the reorganised partitions to 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 are still using the old partitioning scheme. Wait until all
ongoing users have completed before progressing. ongoing users have completed before progressing.
4) Prepare MyISAM handlers for rename and delete of partitions 6) Prepare MyISAM handlers for rename and delete of partitions
5) Write a new frm file of the table where the partitions are 7) Rename the reorged partitions such that they are no longer
reorganised.
6) Rename the reorged partitions such that they are no longer
used and rename those added to their real new names. used and rename those added to their real new names.
7) Write bin log 8) Write bin log
8) Wait until all accesses using the old frm file has completed 9) Install the shadow frm file
9) Drop the reorganised partitions 10) Wait until all accesses using the old frm file has completed
10)Write a new frm file of the table where the partitions are 11) Drop the reorganised partitions
reorganised. 12) Remove log entry
11)Wait until all accesses using the old frm file has completed 13)Wait until all accesses using the old frm file has completed
12)Complete query 14)Complete query
*/ */
if ((mysql_write_frm(lpt, WFRM_INITIAL_WRITE)) || if (write_log_shadow_frm(lpt) ||
(mysql_change_partitions(lpt)) || ERROR_INJECT_CRASH(1020) ||
(abort_and_upgrade_lock(lpt)) || mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
(mysql_write_frm(lpt, WFRM_CREATE_HANDLER_FILES)) || ERROR_INJECT_CRASH(1021) ||
(table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE)) || write_log_ph1_change_partition(lpt) ||
(mysql_rename_partitions(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) && ((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE, (write_bin_log(thd, FALSE,
thd->query, thd->query_length), 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) || (close_open_tables_and_downgrade(lpt), FALSE) ||
(mysql_drop_partitions(lpt)) || ERROR_INJECT_CRASH(1029) ||
(mysql_write_frm(lpt, 0UL)) || mysql_drop_partitions(lpt) ||
ERROR_INJECT_CRASH(1030) ||
write_log_completed(lpt) ||
ERROR_INJECT_CRASH(1031) ||
(mysql_wait_completed_table(lpt, table), FALSE)) (mysql_wait_completed_table(lpt, table), FALSE))
{ {
fast_alter_partition_error_handler(lpt); fast_alter_partition_error_handler(lpt);
......
...@@ -245,6 +245,28 @@ static int mysql_copy_key_list(List<Key> *orig_key, ...@@ -245,6 +245,28 @@ static int mysql_copy_key_list(List<Key> *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 SYNOPSIS
mysql_write_frm() mysql_write_frm()
...@@ -277,83 +299,66 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) ...@@ -277,83 +299,66 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
*/ */
int error= 0; int error= 0;
char path[FN_REFLEN+1]; char path[FN_REFLEN+1];
char shadow_path[FN_REFLEN+1];
char shadow_frm_name[FN_REFLEN+1];
char frm_name[FN_REFLEN+1]; char frm_name[FN_REFLEN+1];
DBUG_ENTER("mysql_write_frm"); 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, if (mysql_copy_create_list(lpt->create_list,
&lpt->new_create_list); &lpt->new_create_list) ||
error+= mysql_copy_key_list(lpt->key_list, mysql_copy_key_list(lpt->key_list,
&lpt->new_key_list); &lpt->new_key_list) ||
if (error) 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); 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 #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 + partition_info *part_info= lpt->table->part_info;
part_info->temp_partitions.elements; char *part_syntax_buf;
if (!(part_info->part_state= (uchar*)sql_alloc(max_part_state_len))) uint syntax_len;
{
DBUG_RETURN(TRUE); if (part_info)
}
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; if (!(part_syntax_buf= generate_partition_syntax(part_info,
part_info->part_state_len= 0; &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_info_string= part_syntax_buf;
part_info->part_info_len= syntax_len;
} }
}
#endif #endif
/* /* Write shadow frm file */
We write the frm file with the LOCK_open mutex since otherwise we could lpt->create_info->table_options= lpt->db_options;
overwrite the frm file as another is reading it in open_table. if ((mysql_create_frm(lpt->thd, shadow_frm_name, lpt->db,
*/ lpt->table_name, lpt->create_info,
lpt->create_info->table_options= lpt->db_options; lpt->new_create_list, lpt->key_count,
VOID(pthread_mutex_lock(&LOCK_open)); lpt->key_info_buffer, lpt->table->file)) ||
if ((mysql_create_frm(lpt->thd, frm_name, lpt->db, lpt->table_name, lpt->table->file->create_handler_files(shadow_path, NULL, FALSE))
lpt->create_info, lpt->new_create_list, lpt->key_count, {
lpt->key_info_buffer, lpt->table->file)) || my_delete(shadow_frm_name, MYF(0));
((flags & WFRM_CREATE_HANDLER_FILES) && error= 1;
lpt->table->file->create_handler_files(path))) goto end;
{ }
error= 1;
goto end;
} }
if (flags & WFRM_PACK_FRM) if (flags & WFRM_PACK_FRM)
{ {
...@@ -365,7 +370,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) ...@@ -365,7 +370,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
*/ */
const void *data= 0; const void *data= 0;
uint length= 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)) packfrm(data, length, &lpt->pack_frm_data, &lpt->pack_frm_len))
{ {
my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
...@@ -374,11 +379,31 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) ...@@ -374,11 +379,31 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
error= 1; error= 1;
goto end; 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: end:
VOID(pthread_mutex_unlock(&LOCK_open));
DBUG_RETURN(error); DBUG_RETURN(error);
} }
...@@ -4631,7 +4656,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -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, error= (mysql_create_frm(thd, reg_path, db, table_name,
create_info, prepared_create_list, key_count, create_info, prepared_create_list, key_count,
key_info_buffer, table->file) || 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)); VOID(pthread_mutex_unlock(&LOCK_open));
if (error) if (error)
goto err; goto err;
...@@ -4677,7 +4702,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -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, error= (mysql_create_frm(thd, reg_path, db, table_name,
create_info, prepared_create_list, key_count, create_info, prepared_create_list, key_count,
key_info_buffer, table->file) || 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)); VOID(pthread_mutex_unlock(&LOCK_open));
if (error) if (error)
goto err; goto err;
...@@ -4900,7 +4925,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -4900,7 +4925,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
VOID(pthread_mutex_lock(&LOCK_open)); VOID(pthread_mutex_lock(&LOCK_open));
} }
/* Tell the handler that a new frm file is in place. */ /* 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)); VOID(pthread_mutex_unlock(&LOCK_open));
goto err; goto err;
......
...@@ -330,7 +330,7 @@ int rea_create_table(THD *thd, const char *path, ...@@ -330,7 +330,7 @@ int rea_create_table(THD *thd, const char *path,
// Make sure mysql_create_frm din't remove extension // Make sure mysql_create_frm din't remove extension
DBUG_ASSERT(*fn_rext(frm_name)); DBUG_ASSERT(*fn_rext(frm_name));
if (file->create_handler_files(path)) if (file->create_handler_files(path, NULL, FALSE))
goto err_handler; goto err_handler;
if (!create_info->frm_only && ha_create_table(thd, path, db, table_name, if (!create_info->frm_only && ha_create_table(thd, path, db, table_name,
create_info,0)) create_info,0))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment