Commit 6b98e786 authored by unknown's avatar unknown
Browse files

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
parent f609d604
Loading
Loading
Loading
Loading
+59 −5
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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];
+7 −2
Original line number Diff line number Diff line
@@ -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);