List:Maria Storage Engine« Previous MessageNext Message »
From:Michael Widenius Date:June 28 2008 8:27am
Subject:bzr commit into MySQL/Maria:mysql-maria branch (monty:2646) Bug#36578
View as plain text  
#At bzr+ssh://bk-internal.mysql.com/bzrroot/server/mysql-maria/

 2646 Michael Widenius	2008-06-28
      Fix for Bug #36578 Maria: maria-recover may fail to autorepair a table
      Fixed also some similar issues in MyISAM. This was not noticed before as MyISAM did a second retry without key cache (which just made the second repair attempty slower)
modified:
  storage/maria/ha_maria.cc
  storage/maria/ha_maria.h
  storage/maria/ma_check.c
  storage/myisam/ha_myisam.cc

per-file messages:
  storage/maria/ha_maria.cc
    Print information if we retry without quick in case of CHECK TABLE table_name QUICK
    Remove T_QUICK flag when retrying repair, but set T_SAFE_REPAIR to ensure we don't loose any rows
    Remember T_RETRY_WITH_QUICK flag when restoring repair flags
    Don't print 'checking table' if we are not checking table in auto-repair
    Don't use T_QUICK in auto repair (safer)
    Changed parameter of type HA_PARAM &param to HA_PARAM *param
  storage/maria/ha_maria.h
    Changed parameter of type HA_PARAM &param to HA_PARAM *param
  storage/maria/ma_check.c
    Added retry without T_QUICK if there is a problem reading a row in BLOCK_RECORD
  storage/myisam/ha_myisam.cc
    Remove T_QUICK flag when retrying repair, but set T_SAFE_REPAIR to ensure we don't loose any rows
    Remember T_RETRY_WITH_QUICK flag when restoring repair flags
=== modified file 'storage/maria/ha_maria.cc'
--- a/storage/maria/ha_maria.cc	2008-06-26 05:18:28 +0000
+++ b/storage/maria/ha_maria.cc	2008-06-28 08:27:14 +0000
@@ -1226,15 +1226,20 @@ int ha_maria::repair(THD * thd, HA_CHECK
                    (check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
   param.sort_buffer_length= THDVAR(thd, sort_buffer_size);
   start_records= file->state->records;
-  while ((error= repair(thd, param, 0)) && param.retry_repair)
+  while ((error= repair(thd, &param, 0)) && param.retry_repair)
   {
     param.retry_repair= 0;
     if (test_all_bits(param.testflag,
                       (uint) (T_RETRY_WITHOUT_QUICK | T_QUICK)))
     {
-      param.testflag &= ~T_RETRY_WITHOUT_QUICK;
-      sql_print_information("Retrying repair of: '%s' without quick",
-                            table->s->path.str);
+      param.testflag&= ~(T_RETRY_WITHOUT_QUICK | T_QUICK);
+      /* Ensure we don't loose any rows when retrying without quick */
+      param.testflag|= T_SAFE_REPAIR;
+      if (thd->vio_ok())
+        _ma_check_print_info(&param, "Retrying repair without quick");
+      else
+        sql_print_information("Retrying repair of: '%s' without quick",
+                              table->s->path.str);
       continue;
     }
     param.testflag &= ~T_QUICK;
@@ -1280,9 +1285,9 @@ int ha_maria::zerofill(THD * thd, HA_CHE
 int ha_maria::optimize(THD * thd, HA_CHECK_OPT *check_opt)
 {
   int error;
+  HA_CHECK param;
   if (!file)
     return HA_ADMIN_INTERNAL_ERROR;
-  HA_CHECK param;
 
   maria_chk_init(&param);
   param.thd= thd;
@@ -1290,21 +1295,21 @@ int ha_maria::optimize(THD * thd, HA_CHE
   param.testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE |
                    T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
   param.sort_buffer_length= THDVAR(thd, sort_buffer_size);
-  if ((error= repair(thd, param, 1)) && param.retry_repair)
+  if ((error= repair(thd, &param, 1)) && param.retry_repair)
   {
     sql_print_warning("Warning: Optimize table got errno %d on %s.%s, retrying",
                       my_errno, param.db_name, param.table_name);
     param.testflag &= ~T_REP_BY_SORT;
-    error= repair(thd, param, 1);
+    error= repair(thd, &param, 1);
   }
   return error;
 }
 
 
-int ha_maria::repair(THD *thd, HA_CHECK &param, bool do_optimize)
+int ha_maria::repair(THD *thd, HA_CHECK *param, bool do_optimize)
 {
   int error= 0;
-  ulonglong local_testflag= param.testflag;
+  ulonglong local_testflag= param->testflag;
   bool optimize_done= !do_optimize, statistics_done= 0;
   const char *old_proc_info= thd->proc_info;
   char fixed_name[FN_REFLEN];
@@ -1336,20 +1341,20 @@ int ha_maria::repair(THD *thd, HA_CHECK 
   if (share->base.born_transactional && !share->now_transactional)
     _ma_copy_nontrans_state_information(file);
 
-  param.db_name= table->s->db.str;
-  param.table_name= table->alias;
-  param.tmpfile_createflag= O_RDWR | O_TRUNC;
-  param.using_global_keycache= 1;
-  param.thd= thd;
-  param.tmpdir= &mysql_tmpdir_list;
-  param.out_flag= 0;
+  param->db_name= table->s->db.str;
+  param->table_name= table->alias;
+  param->tmpfile_createflag= O_RDWR | O_TRUNC;
+  param->using_global_keycache= 1;
+  param->thd= thd;
+  param->tmpdir= &mysql_tmpdir_list;
+  param->out_flag= 0;
   strmov(fixed_name, share->open_file_name);
 
   // Don't lock tables if we have used LOCK TABLE
   if (!thd->locked_tables &&
       maria_lock_database(file, table->s->tmp_table ? F_EXTRA_LCK : F_WRLCK))
   {
-    _ma_check_print_error(&param, ER(ER_CANT_LOCK), my_errno);
+    _ma_check_print_error(param, ER(ER_CANT_LOCK), my_errno);
     DBUG_RETURN(HA_ADMIN_FAILED);
   }
 
@@ -1357,19 +1362,19 @@ int ha_maria::repair(THD *thd, HA_CHECK 
       ((share->data_file_type == BLOCK_RECORD) ?
        (share->state.changed & STATE_NOT_OPTIMIZED_ROWS) :
        (file->state->del || share->state.split != file->state->records)) &&
-      (!(param.testflag & T_QUICK) ||
+      (!(param->testflag & T_QUICK) ||
        (share->state.changed & (STATE_NOT_OPTIMIZED_KEYS |
                                 STATE_NOT_OPTIMIZED_ROWS))))
   {
     ulonglong key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ?
                         maria_get_mask_all_keys_active(share->base.keys) :
                         share->state.key_map);
-    ulonglong save_testflag= param.testflag;
+    ulonglong save_testflag= param->testflag;
     if (maria_test_if_sort_rep(file, file->state->records, key_map, 0) &&
         (local_testflag & T_REP_BY_SORT))
     {
       local_testflag |= T_STATISTICS;
-      param.testflag |= T_STATISTICS;           // We get this for free
+      param->testflag |= T_STATISTICS;           // We get this for free
       statistics_done= 1;
       /* TODO: Remove BLOCK_RECORD test when parallel works with blocks */
       if (THDVAR(thd,repair_threads) > 1 &&
@@ -1379,28 +1384,28 @@ int ha_maria::repair(THD *thd, HA_CHECK 
         /* TODO: respect maria_repair_threads variable */
         my_snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map));
         thd_proc_info(thd, buf);
-        param.testflag|= T_REP_PARALLEL;
-        error= maria_repair_parallel(&param, file, fixed_name,
-                                     test(param.testflag & T_QUICK));
+        param->testflag|= T_REP_PARALLEL;
+        error= maria_repair_parallel(param, file, fixed_name,
+                                     test(param->testflag & T_QUICK));
         /* to reset proc_info, as it was pointing to local buffer */
         thd_proc_info(thd, "Repair done");
       }
       else
       {
         thd_proc_info(thd, "Repair by sorting");
-        param.testflag|= T_REP_BY_SORT;
-        error= maria_repair_by_sort(&param, file, fixed_name,
-                                    test(param.testflag & T_QUICK));
+        param->testflag|= T_REP_BY_SORT;
+        error= maria_repair_by_sort(param, file, fixed_name,
+                                    test(param->testflag & T_QUICK));
       }
     }
     else
     {
       thd_proc_info(thd, "Repair with keycache");
-      param.testflag &= ~(T_REP_BY_SORT | T_REP_PARALLEL);
-      error= maria_repair(&param, file, fixed_name,
-                          test(param.testflag & T_QUICK));
+      param->testflag &= ~(T_REP_BY_SORT | T_REP_PARALLEL);
+      error= maria_repair(param, file, fixed_name,
+                          test(param->testflag & T_QUICK));
     }
-    param.testflag= save_testflag;
+    param->testflag= save_testflag | (param->testflag & T_RETRY_WITHOUT_QUICK);
     optimize_done= 1;
   }
   if (!error)
@@ -1410,7 +1415,7 @@ int ha_maria::repair(THD *thd, HA_CHECK 
     {
       optimize_done= 1;
       thd_proc_info(thd, "Sorting index");
-      error= maria_sort_index(&param, file, fixed_name);
+      error= maria_sort_index(param, file, fixed_name);
     }
     if (!statistics_done && (local_testflag & T_STATISTICS))
     {
@@ -1418,7 +1423,7 @@ int ha_maria::repair(THD *thd, HA_CHECK 
       {
         optimize_done= 1;
         thd_proc_info(thd, "Analyzing");
-        error= maria_chk_key(&param, file);
+        error= maria_chk_key(param, file);
       }
       else
         local_testflag &= ~T_STATISTICS;        // Don't update statistics
@@ -1440,18 +1445,18 @@ int ha_maria::repair(THD *thd, HA_CHECK 
     if (file->state != &share->state.state)
       *file->state= share->state.state;
     if (share->base.auto_key)
-      _ma_update_auto_increment_key(&param, file, 1);
+      _ma_update_auto_increment_key(param, file, 1);
     if (optimize_done)
-      error= maria_update_state_info(&param, file,
+      error= maria_update_state_info(param, file,
                                      UPDATE_TIME | UPDATE_OPEN_COUNT |
                                      (local_testflag &
                                       T_STATISTICS ? UPDATE_STAT : 0));
     info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
          HA_STATUS_CONST);
-    if (rows != file->state->records && !(param.testflag & T_VERY_SILENT))
+    if (rows != file->state->records && !(param->testflag & T_VERY_SILENT))
     {
       char llbuff[22], llbuff2[22];
-      _ma_check_print_warning(&param, "Number of rows changed from %s to %s",
+      _ma_check_print_warning(param, "Number of rows changed from %s to %s",
                               llstr(rows, llbuff),
                               llstr(file->state->records, llbuff2));
       /* Abort if warning was converted to error */
@@ -1463,7 +1468,7 @@ int ha_maria::repair(THD *thd, HA_CHECK 
   {
     maria_mark_crashed_on_repair(file);
     file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
-    maria_update_state_info(&param, file, 0);
+    maria_update_state_info(param, file, 0);
   }
   pthread_mutex_unlock(&share->intern_lock);
   thd_proc_info(thd, old_proc_info);
@@ -1471,7 +1476,7 @@ int ha_maria::repair(THD *thd, HA_CHECK 
     maria_lock_database(file, F_UNLCK);
   error= error ? HA_ADMIN_FAILED :
     (optimize_done ?
-     (write_log_record_for_repair(&param, file) ? HA_ADMIN_FAILED :
+     (write_log_record_for_repair(param, file) ? HA_ADMIN_FAILED :
       HA_ADMIN_OK) : HA_ADMIN_ALREADY_DONE);
   DBUG_RETURN(error);
 }
@@ -1701,15 +1706,16 @@ int ha_maria::enable_indexes(uint mode)
     param.sort_buffer_length= THDVAR(thd,sort_buffer_size);
     param.stats_method= (enum_handler_stats_method)THDVAR(thd,stats_method);
     param.tmpdir= &mysql_tmpdir_list;
-    if ((error= (repair(thd, param, 0) != HA_ADMIN_OK)) && param.retry_repair)
+    if ((error= (repair(thd, &param, 0) != HA_ADMIN_OK)) && param.retry_repair)
     {
-      sql_print_warning("Warning: Enabling keys got errno %d on %s.%s, retrying",
+      sql_print_warning("Warning: Enabling keys got errno %d on %s.%s, "
+                        "retrying",
                         my_errno, param.db_name, param.table_name);
       /* This should never fail normally */
       DBUG_ASSERT(0);
       /* Repairing by sort failed. Now try standard repair method. */
       param.testflag &= ~(T_REP_BY_SORT | T_QUICK);
-      error= (repair(thd, param, 0) != HA_ADMIN_OK);
+      error= (repair(thd, &param, 0) != HA_ADMIN_OK);
       /*
         If the standard repair succeeded, clear all error messages which
         might have been set by the first repair. They can still be seen
@@ -1875,8 +1881,7 @@ end:
 
 bool ha_maria::check_and_repair(THD *thd)
 {
-  int error;
-  int marked_crashed;
+  int error, crashed;
   char *old_query;
   uint old_query_length;
   HA_CHECK_OPT check_opt;
@@ -1905,7 +1910,6 @@ bool ha_maria::check_and_repair(THD *thd
   // Don't use quick if deleted rows
   if (!file->state->del && (maria_recover_options & HA_RECOVER_QUICK))
     check_opt.flags |= T_QUICK;
-  sql_print_warning("Checking table:   '%s'", table->s->path.str);
 
   old_query= thd->query;
   old_query_length= thd->query_length;
@@ -1914,12 +1918,17 @@ bool ha_maria::check_and_repair(THD *thd
   thd->query_length= table->s->table_name.length;
   pthread_mutex_unlock(&LOCK_thread_count);
 
-  if ((marked_crashed= maria_is_crashed(file)) || check(thd, &check_opt))
+  if (!(crashed= maria_is_crashed(file)))
+  {
+    sql_print_warning("Checking table:   '%s'", table->s->path.str);
+    crashed= check(thd, &check_opt);
+  }
+
+  if (crashed)
   {
     sql_print_warning("Recovering table: '%s'", table->s->path.str);
     check_opt.flags=
       ((maria_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
-       (marked_crashed ? 0 : T_QUICK) |
        (maria_recover_options & HA_RECOVER_FORCE ? 0 : T_SAFE_REPAIR) |
        T_AUTO_REPAIR);
     if (repair(thd, &check_opt))

=== modified file 'storage/maria/ha_maria.h'
--- a/storage/maria/ha_maria.h	2008-05-29 15:33:33 +0000
+++ b/storage/maria/ha_maria.h	2008-06-28 08:27:14 +0000
@@ -45,7 +45,7 @@ class ha_maria :public handler
     UNDO_BULK_INSERT with/without repair. 
   */
   uint8 bulk_insert_single_undo;
-  int repair(THD * thd, HA_CHECK &param, bool optimize);
+  int repair(THD * thd, HA_CHECK *param, bool optimize);
   int zerofill(THD * thd, HA_CHECK_OPT *check_opt);
 
 public:

=== modified file 'storage/maria/ma_check.c'
--- a/storage/maria/ma_check.c	2008-06-26 05:18:28 +0000
+++ b/storage/maria/ma_check.c	2008-06-28 08:27:14 +0000
@@ -99,6 +99,7 @@ static my_bool _ma_flush_table_files_bef
                                                  MARIA_HA *info);
 static TrID max_trid_in_system(void);
 static void _ma_check_print_not_visible_error(HA_CHECK *param, TrID used_trid);
+void retry_if_quick(MARIA_SORT_PARAM *param, int error);
 
 
 /* Initialize check param with default values */
@@ -4632,9 +4633,12 @@ static int sort_get_next_record(MARIA_SO
       }
       /* Retry only if wrong record, not if disk error */
       if (flag != HA_ERR_WRONG_IN_RECORD)
+      {
+        retry_if_quick(sort_param, flag);
         DBUG_RETURN(flag);
+      }
     }
-    break;
+    break;                                      /* Impossible */
   }
   case STATIC_RECORD:
     for (;;)
@@ -4644,8 +4648,7 @@ static int sort_get_next_record(MARIA_SO
       {
 	if (sort_param->read_cache.error)
 	  param->out_flag |= O_DATA_LOST;
-        param->retry_repair=1;
-        param->testflag|=T_RETRY_WITHOUT_QUICK;
+        retry_if_quick(sort_param, my_errno);
 	DBUG_RETURN(-1);
       }
       sort_param->start_recpos=sort_param->pos;
@@ -6634,3 +6637,22 @@ static void _ma_check_print_not_visible_
     }
   }
 }
+
+
+/**
+  Mark that we can retry normal repair if we used quick repair
+
+  We shouldn't do this in case of disk error as in this case we are likely
+  to loose much more than expected.
+*/
+
+void retry_if_quick(MARIA_SORT_PARAM *sort_param, int error)
+{
+  HA_CHECK *param=sort_param->sort_info->param;
+
+  if (!sort_param->fix_datafile && error >= HA_ERR_FIRST)
+  {
+    param->retry_repair=1;
+    param->testflag|=T_RETRY_WITHOUT_QUICK;
+  }
+}

=== modified file 'storage/myisam/ha_myisam.cc'
--- a/storage/myisam/ha_myisam.cc	2008-05-29 18:39:25 +0000
+++ b/storage/myisam/ha_myisam.cc	2008-06-28 08:27:14 +0000
@@ -996,7 +996,9 @@ int ha_myisam::repair(THD* thd, HA_CHECK
     if (test_all_bits(param.testflag,
 		      (uint) (T_RETRY_WITHOUT_QUICK | T_QUICK)))
     {
-      param.testflag&= ~T_RETRY_WITHOUT_QUICK;
+      param.testflag&= ~(T_RETRY_WITHOUT_QUICK | T_QUICK);
+      /* Ensure we don't loose any rows when retrying without quick */
+      param.testflag|= T_SAFE_REPAIR;
       sql_print_information("Retrying repair of: '%s' without quick",
                             table->s->path.str);
       continue;
@@ -1130,7 +1132,7 @@ int ha_myisam::repair(THD *thd, HA_CHECK
       error=  mi_repair(&param, file, fixed_name,
 			test(param.testflag & T_QUICK));
     }
-    param.testflag=testflag;
+    param.testflag= testflag | (param.testflag & T_RETRY_WITHOUT_QUICK);
     optimize_done=1;
   }
   if (!error)

Thread
bzr commit into MySQL/Maria:mysql-maria branch (monty:2646) Bug#36578Michael Widenius28 Jun