Commit 74b06493 authored by Michael Widenius's avatar Michael Widenius

Fixed lp:944422 "mysql_upgrade destroys Maria tables?"

The issue was that check/optimize/anaylze did not zerofill the table before they started to work on it.
Added one more element to not often used function handler::auto_repair() to allow handler to decide when to auto repair.


mysql-test/suite/maria/r/maria-autozerofill.result:
  Test case for lp:944422
mysql-test/suite/maria/t/maria-autozerofill.test:
  Test case for lp:944422
sql/ha_partition.cc:
  Added argument to auto_repair()
sql/ha_partition.h:
  Added argument to auto_repair()
sql/handler.h:
  Added argument to auto_repair()
sql/table.cc:
  Let auto_repair() decide which errors to trigger auto-repair
storage/archive/ha_archive.h:
  Added argument to auto_repair()
storage/csv/ha_tina.h:
  Added argument to auto_repair()
storage/maria/ha_maria.cc:
  Give better error & warning messages for auto-repaired tables.
storage/maria/ha_maria.h:
  Added argument to auto_repair()
  Always auto-repair in case of moved table.
storage/maria/ma_open.c:
  Remove special handling of HA_ERR_OLD_FILE (this is now handled in auto_repair())
storage/myisam/ha_myisam.h:
  Added argument to auto_repair()
parent d1f31179
...@@ -4,18 +4,43 @@ create database mysqltest; ...@@ -4,18 +4,43 @@ create database mysqltest;
use mysqltest; use mysqltest;
create table t1(a int) engine=maria; create table t1(a int) engine=maria;
insert into t1 values(1); insert into t1 values(1);
flush table t1; create table t2 (a int) engine=maria;
INSERT INTO t2 VALUES (1),(2);
create table t3 (a int) engine=maria;
INSERT INTO t3 VALUES (1),(2);
create table t4 (a int) engine=maria;
INSERT INTO t4 VALUES (1),(2);
flush tables;
create_rename_lsn has non-magic value create_rename_lsn has non-magic value
* shut down mysqld, removed logs, restarted it * shut down mysqld, removed logs, restarted it
select * from t1; select * from t1;
a a
1 1
Warnings: Warnings:
Error 1194 t1' is marked as crashed and should be repaired Note 1194 Zerofilling moved table ./mysqltest/t1
flush table t1; flush table t1;
Status: changed,sorted index pages,zerofilled,movable Status: changed,sorted index pages,zerofilled,movable
create_rename_lsn has magic value create_rename_lsn has magic value
insert into t1 values(2); insert into t1 values(2);
flush table t1; flush table t1;
create_rename_lsn has non-magic value create_rename_lsn has non-magic value
check table t2;
Table Op Msg_type Msg_text
mysqltest.t2 check error Table is from another system and must be zerofilled or repaired to be usable on this system
mysqltest.t2 check error Corrupt
check table t2;
Table Op Msg_type Msg_text
mysqltest.t2 check error Table is from another system and must be zerofilled or repaired to be usable on this system
mysqltest.t2 check error Corrupt
repair table t2;
Table Op Msg_type Msg_text
mysqltest.t2 repair status OK
optimize table t3;
Table Op Msg_type Msg_text
mysqltest.t3 optimize Note Zerofilling moved table ./mysqltest/t3
mysqltest.t3 optimize status OK
analyze table t4;
Table Op Msg_type Msg_text
mysqltest.t4 analyze Note Zerofilling moved table ./mysqltest/t4
mysqltest.t4 analyze status OK
drop database mysqltest; drop database mysqltest;
...@@ -22,9 +22,17 @@ connection default; ...@@ -22,9 +22,17 @@ connection default;
use mysqltest; use mysqltest;
--enable_reconnect --enable_reconnect
# Create some tables for future tests
create table t1(a int) engine=maria; create table t1(a int) engine=maria;
insert into t1 values(1); insert into t1 values(1);
flush table t1; create table t2 (a int) engine=maria;
INSERT INTO t2 VALUES (1),(2);
create table t3 (a int) engine=maria;
INSERT INTO t3 VALUES (1),(2);
create table t4 (a int) engine=maria;
INSERT INTO t4 VALUES (1),(2);
flush tables;
# Check that table is not zerofilled, not movable # Check that table is not zerofilled, not movable
let $MYSQLD_DATADIR= `select @@datadir`; let $MYSQLD_DATADIR= `select @@datadir`;
--exec $MARIA_CHK -dv $MYSQLD_DATADIR/mysqltest/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt --exec $MARIA_CHK -dv $MYSQLD_DATADIR/mysqltest/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
...@@ -80,4 +88,14 @@ perl; ...@@ -80,4 +88,14 @@ perl;
close FILE; close FILE;
EOF EOF
#
# BUG#44422 "mysql_upgrade destroys Maria tables?"
# Check repair and optimize of moved table
#
check table t2;
check table t2;
repair table t2;
optimize table t3;
analyze table t4;
drop database mysqltest; drop database mysqltest;
...@@ -1223,7 +1223,7 @@ bool ha_partition::check_and_repair(THD *thd) ...@@ -1223,7 +1223,7 @@ bool ha_partition::check_and_repair(THD *thd)
@retval FALSE Cannot be auto repaired @retval FALSE Cannot be auto repaired
*/ */
bool ha_partition::auto_repair() const bool ha_partition::auto_repair(int error) const
{ {
DBUG_ENTER("ha_partition::auto_repair"); DBUG_ENTER("ha_partition::auto_repair");
...@@ -1231,7 +1231,7 @@ bool ha_partition::auto_repair() const ...@@ -1231,7 +1231,7 @@ bool ha_partition::auto_repair() const
As long as we only support one storage engine per table, As long as we only support one storage engine per table,
we can use the first partition for this function. we can use the first partition for this function.
*/ */
DBUG_RETURN(m_file[0]->auto_repair()); DBUG_RETURN(m_file[0]->auto_repair(error));
} }
......
...@@ -1105,7 +1105,7 @@ public: ...@@ -1105,7 +1105,7 @@ public:
virtual int check(THD* thd, HA_CHECK_OPT *check_opt); virtual int check(THD* thd, HA_CHECK_OPT *check_opt);
virtual int repair(THD* thd, HA_CHECK_OPT *check_opt); virtual int repair(THD* thd, HA_CHECK_OPT *check_opt);
virtual bool check_and_repair(THD *thd); virtual bool check_and_repair(THD *thd);
virtual bool auto_repair() const; virtual bool auto_repair(int error) const;
virtual bool is_crashed() const; virtual bool is_crashed() const;
private: private:
......
...@@ -1668,7 +1668,7 @@ public: ...@@ -1668,7 +1668,7 @@ public:
virtual bool low_byte_first() const { return 1; } virtual bool low_byte_first() const { return 1; }
virtual uint checksum() const { return 0; } virtual uint checksum() const { return 0; }
virtual bool is_crashed() const { return 0; } virtual bool is_crashed() const { return 0; }
virtual bool auto_repair() const { return 0; } virtual bool auto_repair(int error) const { return 0; }
#define CHF_CREATE_FLAG 0 #define CHF_CREATE_FLAG 0
#define CHF_DELETE_FLAG 1 #define CHF_DELETE_FLAG 1
......
...@@ -1929,8 +1929,7 @@ partititon_err: ...@@ -1929,8 +1929,7 @@ partititon_err:
HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags)))) HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags))))
{ {
/* Set a flag if the table is crashed and it can be auto. repaired */ /* Set a flag if the table is crashed and it can be auto. repaired */
share->crashed= ((ha_err == HA_ERR_CRASHED_ON_USAGE) && share->crashed= (outparam->file->auto_repair(ha_err) &&
outparam->file->auto_repair() &&
!(ha_open_flags & HA_OPEN_FOR_REPAIR)); !(ha_open_flags & HA_OPEN_FOR_REPAIR));
switch (ha_err) switch (ha_err)
......
...@@ -125,7 +125,9 @@ public: ...@@ -125,7 +125,9 @@ public:
int free_share(); int free_share();
int init_archive_writer(); int init_archive_writer();
int init_archive_reader(); int init_archive_reader();
bool auto_repair() const { return 1; } // For the moment we just do this // Always try auto_repair in case of HA_ERR_CRASHED_ON_USAGE
bool auto_repair(int error) const
{ return error == HA_ERR_CRASHED_ON_USAGE; }
int read_data_header(azio_stream *file_to_read); int read_data_header(azio_stream *file_to_read);
void position(const uchar *record); void position(const uchar *record);
int info(uint); int info(uint);
......
...@@ -151,6 +151,8 @@ public: ...@@ -151,6 +151,8 @@ public:
int rnd_end(); int rnd_end();
int repair(THD* thd, HA_CHECK_OPT* check_opt); int repair(THD* thd, HA_CHECK_OPT* check_opt);
/* This is required for SQL layer to know that we support autorepair */ /* This is required for SQL layer to know that we support autorepair */
bool auto_repair(int error) const
{ return error == HA_ERR_CRASHED_ON_USAGE; }
bool auto_repair() const { return 1; } bool auto_repair() const { return 1; }
void position(const uchar *record); void position(const uchar *record);
int info(uint); int info(uint);
......
...@@ -52,6 +52,9 @@ C_MODE_END ...@@ -52,6 +52,9 @@ C_MODE_END
ulong pagecache_division_limit, pagecache_age_threshold; ulong pagecache_division_limit, pagecache_age_threshold;
ulonglong pagecache_buffer_size; ulonglong pagecache_buffer_size;
const char *zerofill_error_msg=
"Table is from another system and must be zerofilled or repaired to be "
"usable on this system";
/** /**
As the auto-repair is initiated when opened from the SQL layer As the auto-repair is initiated when opened from the SQL layer
...@@ -972,7 +975,15 @@ int ha_maria::open(const char *name, int mode, uint test_if_locked) ...@@ -972,7 +975,15 @@ int ha_maria::open(const char *name, int mode, uint test_if_locked)
} }
if (!(file= maria_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER))) if (!(file= maria_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
{
if (my_errno == HA_ERR_OLD_FILE)
{
push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_CRASHED_ON_USAGE,
zerofill_error_msg);
}
return (my_errno ? my_errno : -1); return (my_errno ? my_errno : -1);
}
file->s->chst_invalidator= query_cache_invalidate_by_MyISAM_filename_ref; file->s->chst_invalidator= query_cache_invalidate_by_MyISAM_filename_ref;
...@@ -1074,6 +1085,13 @@ int ha_maria::check(THD * thd, HA_CHECK_OPT * check_opt) ...@@ -1074,6 +1085,13 @@ int ha_maria::check(THD * thd, HA_CHECK_OPT * check_opt)
return HA_ADMIN_ALREADY_DONE; return HA_ADMIN_ALREADY_DONE;
maria_chk_init_for_check(&param, file); maria_chk_init_for_check(&param, file);
if ((file->s->state.changed & (STATE_CRASHED_FLAGS | STATE_MOVED)) ==
STATE_MOVED)
{
_ma_check_print_error(&param, zerofill_error_msg);
return HA_ADMIN_CORRUPT;
}
(void) maria_chk_status(&param, file); // Not fatal (void) maria_chk_status(&param, file); // Not fatal
error= maria_chk_size(&param, file); error= maria_chk_size(&param, file);
if (!error) if (!error)
...@@ -2024,6 +2042,11 @@ bool ha_maria::check_and_repair(THD *thd) ...@@ -2024,6 +2042,11 @@ bool ha_maria::check_and_repair(THD *thd)
if ((file->s->state.changed & (STATE_CRASHED_FLAGS | STATE_MOVED)) == if ((file->s->state.changed & (STATE_CRASHED_FLAGS | STATE_MOVED)) ==
STATE_MOVED) STATE_MOVED)
{ {
/* Remove error about crashed table */
mysql_reset_errors(thd, true);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_CRASHED_ON_USAGE,
"Zerofilling moved table %s", table->s->path.str);
sql_print_information("Zerofilling moved table: '%s'", sql_print_information("Zerofilling moved table: '%s'",
table->s->path.str); table->s->path.str);
if (!(error= zerofill(thd, &check_opt))) if (!(error= zerofill(thd, &check_opt)))
......
...@@ -142,8 +142,14 @@ public: ...@@ -142,8 +142,14 @@ public:
bool check_and_repair(THD * thd); bool check_and_repair(THD * thd);
bool is_crashed() const; bool is_crashed() const;
bool is_changed() const; bool is_changed() const;
bool auto_repair() const bool auto_repair(int error) const
{ return test(maria_recover_options & HA_RECOVER_ANY); } {
/* Always auto-repair moved tables (error == HA_ERR_OLD_FILE) */
return ((test(maria_recover_options & HA_RECOVER_ANY) &&
error == HA_ERR_CRASHED_ON_USAGE) ||
error == HA_ERR_OLD_FILE);
}
int optimize(THD * thd, HA_CHECK_OPT * check_opt); int optimize(THD * thd, HA_CHECK_OPT * check_opt);
int restore(THD * thd, HA_CHECK_OPT * check_opt); int restore(THD * thd, HA_CHECK_OPT * check_opt);
int backup(THD * thd, HA_CHECK_OPT * check_opt); int backup(THD * thd, HA_CHECK_OPT * check_opt);
......
...@@ -968,8 +968,6 @@ err: ...@@ -968,8 +968,6 @@ err:
tmp_name.length= strlen(name); tmp_name.length= strlen(name);
_ma_report_error(save_errno, &tmp_name); _ma_report_error(save_errno, &tmp_name);
} }
if (save_errno == HA_ERR_OLD_FILE) /* uuid is different ? */
save_errno= HA_ERR_CRASHED_ON_USAGE; /* the code to trigger auto-repair */
switch (errpos) { switch (errpos) {
case 5: case 5:
if (data_file >= 0) if (data_file >= 0)
......
...@@ -128,7 +128,11 @@ class ha_myisam: public handler ...@@ -128,7 +128,11 @@ class ha_myisam: public handler
int repair(THD* thd, HA_CHECK_OPT* check_opt); int repair(THD* thd, HA_CHECK_OPT* check_opt);
bool check_and_repair(THD *thd); bool check_and_repair(THD *thd);
bool is_crashed() const; bool is_crashed() const;
bool auto_repair() const { return myisam_recover_options != 0; } bool auto_repair(int error) const
{
return (myisam_recover_options != 0 &&
error == HA_ERR_CRASHED_ON_USAGE);
}
int optimize(THD* thd, HA_CHECK_OPT* check_opt); int optimize(THD* thd, HA_CHECK_OPT* check_opt);
int restore(THD* thd, HA_CHECK_OPT* check_opt); int restore(THD* thd, HA_CHECK_OPT* check_opt);
int backup(THD* thd, HA_CHECK_OPT* check_opt); int backup(THD* thd, HA_CHECK_OPT* check_opt);
......
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