From 6b98e786e61cb60ba591a42f77475def25e51e21 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 12 Mar 2005 20:09:54 +0100 Subject: [PATCH] if no xa recovery (or after it): warning on startup if prepared foreign xids error on startup if prepared our xids temporarily: always rollback prepared our xids instead of an error sql/mysql_priv.h: opt_tc_log_file made extern sql/mysqld.cc: opt_tc_log_file made extern always call ha_recover() even if no previous crash was detected --- sql/handler.cc | 64 ++++++++++++++++++++++++++++++++++++++++++++---- sql/mysql_priv.h | 2 +- sql/mysqld.cc | 9 +++++-- 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index 7cb0ba3bee2..e185ae0f0a0 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -744,16 +744,48 @@ int ha_commit_or_rollback_by_xid(LEX_STRING *ident, bool commit) /* recover() step of xa + + NOTE + there are three modes of operation: + + - automatic recover after a crash + in this case commit_list != 0, tc_heuristic_recover==0 + all xids from commit_list are committed, others are rolled back + + - manual (heuristic) recover + in this case commit_list==0, tc_heuristic_recover != 0 + DBA has explicitly specified that all prepared transactions should + be committed (or rolled back). + + - no recovery (MySQL did not detect a crash) + in this case commit_list==0, tc_heuristic_recover == 0 + there should be no prepared transactions in this case. */ int ha_recover(HASH *commit_list) { - int len, got; + int len, got, found_foreign_xids=0, found_my_xids=0; handlerton **ht= handlertons, **end_ht=ht+total_ha; XID *list=0; + bool dry_run=(commit_list==0 && tc_heuristic_recover==0); DBUG_ENTER("ha_recover"); - DBUG_ASSERT(total_ha_2pc); - DBUG_ASSERT(commit_list || tc_heuristic_recover); + /* commit_list and tc_heuristic_recover cannot be set both */ + DBUG_ASSERT(commit_list==0 || tc_heuristic_recover==0); + /* if either is set, total_ha_2pc must be set too */ + DBUG_ASSERT((commit_list==0 && tc_heuristic_recover==0) || total_ha_2pc>0); + + if (total_ha_2pc == 0) + DBUG_RETURN(0); + +#ifndef WILL_BE_DELETED_LATER + /* + for now, only InnoDB supports 2pc. It means we can always safely + rollback all pending transactions, without risking inconsistent data + */ + DBUG_ASSERT(total_ha_2pc == opt_bin_log+1); // only InnoDB and binlog + tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK + dry_run=FALSE; +#endif for (len= MAX_XID_LIST_SIZE ; list==0 && len > MIN_XID_LIST_SIZE; len/=2) { @@ -761,7 +793,7 @@ int ha_recover(HASH *commit_list) } if (!list) { - my_error(ER_OUTOFMEMORY, MYF(0), len); + sql_print_error(ER(ER_OUTOFMEMORY), len*sizeof(XID)); DBUG_RETURN(1); } @@ -775,7 +807,16 @@ int ha_recover(HASH *commit_list) { my_xid x=list[i].get_my_xid(); if (!x) // not "mine" - that is generated by external TM + { + found_foreign_xids++; continue; + } + if (dry_run) + { + found_my_xids++; + continue; + } + // recovery mode if (commit_list ? hash_search(commit_list, (byte *)&x, sizeof(x)) != 0 : tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT) @@ -788,6 +829,19 @@ int ha_recover(HASH *commit_list) } } my_free((gptr)list, MYF(0)); + if (found_foreign_xids) + sql_print_warning("Found %d prepared XA transactions", found_foreign_xids); + if (dry_run && found_my_xids) + { + sql_print_error("Found %d prepared transactions! It means that mysqld was " + "not shut down properly last time and critical recovery " + "information (last binlog or %s file) was manually deleted " + "after a crash. You have to start mysqld with " + "--tc-heuristic-recover switch to commit or rollback " + "pending transactions.", + found_my_xids, opt_tc_log_file); + DBUG_RETURN(1); + } DBUG_RETURN(0); } @@ -1385,7 +1439,7 @@ ulonglong handler::get_auto_increment() /* Print error that we got from handler function - NOTE: + NOTE In case of delete table it's only safe to use the following parts of the 'table' structure: table->s->path diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 7e58f7bf728..e43ec502da0 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1033,7 +1033,7 @@ extern Le_creator le_creator; extern char language[FN_REFLEN], reg_ext[FN_EXTLEN]; extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN]; extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file; -extern char log_error_file[FN_REFLEN]; +extern char log_error_file[FN_REFLEN], *opt_tc_log_file; extern double last_query_cost; extern double log_10[32]; extern ulonglong log_10_int[20]; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8271f8fa473..5c96de1d73a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -366,7 +366,7 @@ char* log_error_file_ptr= log_error_file; char mysql_real_data_home[FN_REFLEN], language[FN_REFLEN], reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN], *mysqld_user,*mysqld_chroot, *opt_init_file, - *opt_init_connect, *opt_init_slave, + *opt_init_connect, *opt_init_slave, *opt_tc_log_file, def_ft_boolean_syntax[sizeof(ft_boolean_syntax)]; const char *opt_date_time_formats[3]; @@ -457,7 +457,7 @@ static my_bool opt_do_pstack, opt_noacl, opt_bootstrap, opt_myisam_log; static int cleanup_done; static ulong opt_specialflag, opt_myisam_block_size; static char *opt_logname, *opt_update_logname, *opt_binlog_index_name; -static char *opt_slow_logname, *opt_tc_log_file, *opt_tc_heuristic_recover; +static char *opt_slow_logname, *opt_tc_heuristic_recover; static char *mysql_home_ptr, *pidfile_name_ptr; static char **defaults_argv; static char *opt_bin_logname; @@ -2800,6 +2800,11 @@ server."); unireg_abort(1); } + if (ha_recover(0)) + { + unireg_abort(1); + } + if (opt_bin_log && mysql_bin_log.open(opt_bin_logname, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0)) unireg_abort(1);