Commit d2f8b7d0 authored by Michael Widenius's avatar Michael Widenius

Fix for LP#602604: RQG: ma_blockrec.c:6187:...

Fix for LP#602604: RQG: ma_blockrec.c:6187: _ma_apply_redo_insert_row_head_or_tail: Assertion `0' failed on Maria engine recovery
More DBUG_PRINT (to simplify future debugging)
Aria: Added STATE_IN_REPAIR, which is set on start of repair. This allows us to see if 'crashed' flag was set intentionally.
Aria: Some trivial speedup optimization
Aria: Better warning if table was marked crashed by unfinnished repair


mysql-test/lib/v1/mysql-test-run.pl:
  Fix so one can run RQG
mysql-test/suite/maria/r/maria-recovery2.result:
  Update for new error message.
mysys/stacktrace.c:
  Fixed compiler warning
storage/maria/ha_maria.cc:
  More DBUG_PRINT
  Added STATE_IN_REPAIR flag, which is set on start of repair. This allows us to see if 'crashed' flag was set intentionally.
  Don't log query for dropping temporary table.
storage/maria/ha_maria.h:
  Added prototype for drop_table()
storage/maria/ma_blockrec.c:
  More DBUG_PRINT
  Make read_long_data() inline for most cases. (Trivial speedup optimization)
storage/maria/ma_check.c:
  Better warning if table was marked crashed by unfinnished repair
storage/maria/ma_open.c:
  More DBUG_PRINT
storage/maria/ma_recovery.c:
  Give warning if found crashed table.
  Changed warning for tables that can't be opened.
storage/maria/ma_recovery_util.c:
  Write warnings to DBUG file
storage/maria/maria_chk.c:
  Added STATE_IN_REPAIR flag, which is set on start of repair. This allows us to see if 'crashed' flag was set intentionally.
storage/maria/maria_def.h:
  Added maria_mark_in_repair(x)
storage/maria/maria_read_log.c:
  Added option: --character-sets-dir
storage/maria/trnman.c:
  By default set min_read_from to max value.
  This allows us to remove TRN:s from rows during recovery to get more space.
  This fixes bug LP#602604: RQG: ma_blockrec.c:6187: _ma_apply_redo_insert_row_head_or_tail: Assertion `0' failed on Maria engine recovery
parent cf86a5ae
......@@ -3970,7 +3970,7 @@ sub mysqld_arguments ($$$$) {
}
}
mtr_add_arg($args, "%s--character-set-server-set=latin1", $prefix);
mtr_add_arg($args, "%s--character-set-server=latin1", $prefix);
mtr_add_arg($args, "%s--language=%s", $prefix, $path_language);
mtr_add_arg($args, "%s--tmpdir=$opt_tmpdir", $prefix);
......
......@@ -136,7 +136,7 @@ ERROR HY000: Lost connection to MySQL server during query
* recovery happens
check table t_corrupted1 extended;
Table Op Msg_type Msg_text
mysqltest.t_corrupted1 check warning Table is marked as crashed and last repair failed
mysqltest.t_corrupted1 check warning Last repair was aborted before finishing
mysqltest.t_corrupted1 check status OK
* testing that checksum after recovery is as expected
Checksum-check
......
......@@ -86,7 +86,7 @@ void my_print_stacktrace(uchar* stack_bottom __attribute__((unused)),
#if BACKTRACE_DEMANGLE
char __attribute__ ((weak)) *my_demangle(const char *mangled_name, int *status)
char __attribute__ ((weak)) *my_demangle(const char *mangled_name __attribute__((unused)), int *status __attribute__((unused)))
{
return NULL;
}
......
......@@ -749,6 +749,9 @@ static int maria_create_trn_for_mysql(MARIA_HA *info)
(uchar*) thd->query(),
thd->query_length());
}
else
DBUG_PRINT("info", ("lock_type: %d trnman_flags: %u",
info->lock_type, trnman_get_flags(trn))); /* QQ */
#endif
DBUG_RETURN(0);
}
......@@ -1055,7 +1058,8 @@ int ha_maria::check(THD * thd, HA_CHECK_OPT * check_opt)
if (!maria_is_crashed(file) &&
(((param.testflag & T_CHECK_ONLY_CHANGED) &&
!(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
STATE_CRASHED_ON_REPAIR)) &&
STATE_CRASHED_ON_REPAIR |
STATE_IN_REPAIR)) &&
share->state.open_count == 0) ||
((param.testflag & T_FAST) && (share->state.open_count ==
(uint) (share->global_changed ? 1 :
......@@ -1092,14 +1096,15 @@ int ha_maria::check(THD * thd, HA_CHECK_OPT * check_opt)
if (!error)
{
if ((share->state.changed & (STATE_CHANGED |
STATE_CRASHED_ON_REPAIR |
STATE_CRASHED_ON_REPAIR | STATE_IN_REPAIR |
STATE_CRASHED | STATE_NOT_ANALYZED)) ||
(param.testflag & T_STATISTICS) || maria_is_crashed(file))
{
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
pthread_mutex_lock(&share->intern_lock);
share->state.changed &= ~(STATE_CHANGED | STATE_CRASHED |
STATE_CRASHED_ON_REPAIR);
DBUG_PRINT("info", ("Reseting crashed state"));
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
STATE_CRASHED_ON_REPAIR | STATE_IN_REPAIR);
if (!(table->db_stat & HA_READ_ONLY))
error= maria_update_state_info(&param, file,
UPDATE_TIME | UPDATE_OPEN_COUNT |
......@@ -1513,8 +1518,9 @@ int ha_maria::repair(THD *thd, HA_CHECK *param, bool do_optimize)
{
if ((share->state.changed & STATE_CHANGED) || maria_is_crashed(file))
{
share->state.changed &= ~(STATE_CHANGED | STATE_CRASHED |
STATE_CRASHED_ON_REPAIR);
DBUG_PRINT("info", ("Reseting crashed state"));
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
STATE_CRASHED_ON_REPAIR | STATE_IN_REPAIR);
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
}
/*
......@@ -2360,6 +2366,15 @@ int ha_maria::delete_table(const char *name)
}
/* This is mainly for temporary tables, so no logging necessary */
void ha_maria::drop_table(const char *name)
{
(void) close();
(void) maria_delete_table(name);
}
int ha_maria::external_lock(THD *thd, int lock_type)
{
DBUG_ENTER("ha_maria::external_lock");
......
......@@ -135,6 +135,7 @@ class ha_maria :public handler
ulonglong *nb_reserved_values);
int rename_table(const char *from, const char *to);
int delete_table(const char *name);
void drop_table(const char *name);
int check(THD * thd, HA_CHECK_OPT * check_opt);
int analyze(THD * thd, HA_CHECK_OPT * check_opt);
int repair(THD * thd, HA_CHECK_OPT * check_opt);
......
......@@ -1377,7 +1377,8 @@ void _ma_compact_block_page(uchar *buff, uint block_size, uint rownr,
uint freed_size= 0;
uchar *dir, *end;
DBUG_ENTER("_ma_compact_block_page");
DBUG_PRINT("enter", ("rownr: %u", rownr));
DBUG_PRINT("enter", ("rownr: %u min_read_from: %lu", rownr,
(ulong) min_read_from));
DBUG_ASSERT(max_entry > 0 &&
max_entry < (block_size - PAGE_HEADER_SIZE -
PAGE_SUFFIX_SIZE) / DIR_ENTRY_SIZE);
......@@ -3407,13 +3408,14 @@ static my_bool allocate_and_write_block_record(MARIA_HA *info,
DBUG_ASSERT(row->checksum == (info->s->calc_checksum)(info, record));
}
}
DBUG_PRINT("info", ("rowid: %lu (%lu:%u) length: %u", (ulong) row->lastpos,
(ulong) ma_recordpos_to_page(row->lastpos),
ma_recordpos_to_dir_entry(row->lastpos),
row_pos.length));
if (write_block_record(info, (uchar*) 0, record, row,
blocks, blocks->block->org_bitmap_value != 0,
&row_pos, undo_lsn, 0))
goto err; /* Error reading bitmap */
DBUG_PRINT("exit", ("rowid: %lu (%lu:%u)", (ulong) row->lastpos,
(ulong) ma_recordpos_to_page(row->lastpos),
ma_recordpos_to_dir_entry(row->lastpos)));
goto err;
/* Now let checkpoint happen but don't commit */
DBUG_EXECUTE_IF("maria_over_alloc_bitmap", sleep(1000););
DBUG_RETURN(0);
......@@ -4404,13 +4406,15 @@ static uchar *read_next_extent(MARIA_HA *info, MARIA_EXTENT_CURSOR *extent,
1 error
*/
static my_bool read_long_data(MARIA_HA *info, uchar *to, ulong length,
static my_bool read_long_data2(MARIA_HA *info, uchar *to, ulong length,
MARIA_EXTENT_CURSOR *extent,
uchar **data, uchar **end_of_data)
{
DBUG_ENTER("read_long_data");
uint left_length;
left_length= (uint) (*end_of_data - *data);
DBUG_ENTER("read_long_data2");
DBUG_PRINT("enter", ("length: %lu left_length: %u",
length, (uint) (*end_of_data - *data)));
length, left_length));
DBUG_ASSERT(*data <= *end_of_data);
/*
......@@ -4422,14 +4426,15 @@ static my_bool read_long_data(MARIA_HA *info, uchar *to, ulong length,
This may change in the future, which is why we have the loop written
the way it's written.
*/
if (extent->first_extent && length > (ulong) (*end_of_data - *data))
if (extent->first_extent && length > left_length)
{
*end_of_data= *data;
left_length= 0;
}
for(;;)
{
uint left_length;
left_length= (uint) (*end_of_data - *data);
if (likely(left_length >= length))
if (unlikely(left_length >= length))
{
memcpy(to, *data, length);
(*data)+= length;
......@@ -4441,10 +4446,25 @@ static my_bool read_long_data(MARIA_HA *info, uchar *to, ulong length,
length-= left_length;
if (!(*data= read_next_extent(info, extent, end_of_data)))
break;
left_length= (uint) (*end_of_data - *data);
}
DBUG_RETURN(1);
}
static inline my_bool read_long_data(MARIA_HA *info, uchar *to, ulong length,
MARIA_EXTENT_CURSOR *extent,
uchar **data, uchar **end_of_data)
{
uint left_length= (uint) (*end_of_data - *data);
if (likely(left_length >= length))
{
memcpy(to, *data, length);
(*data)+= length;
return 0;
}
return read_long_data2(info, to, length, extent, data, end_of_data);
}
/*
Read a record from page (helper function for _ma_read_block_record())
......
......@@ -154,6 +154,9 @@ int maria_chk_status(HA_CHECK *param, MARIA_HA *info)
if (maria_is_crashed_on_repair(info))
_ma_check_print_warning(param,
"Table is marked as crashed and last repair failed");
else if (maria_in_repair(info))
_ma_check_print_warning(param,
"Last repair was aborted before finishing");
else if (maria_is_crashed(info))
_ma_check_print_warning(param,
"Table is marked as crashed");
......@@ -2242,7 +2245,7 @@ static my_bool protect_against_repair_crash(MARIA_HA *info,
if ((param->testflag & T_NO_CREATE_RENAME_LSN) == 0)
{
/* this can be true only for a transactional table */
maria_mark_crashed_on_repair(info);
maria_mark_in_repair(info);
if (_ma_state_info_write(share,
MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
MA_STATE_INFO_WRITE_LOCK))
......
......@@ -209,6 +209,7 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share, const char *name,
DBUG_RETURN(m_info);
err:
DBUG_PRINT("error", ("error: %d", my_errno));
save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
if ((save_errno == HA_ERR_CRASHED) ||
(save_errno == HA_ERR_CRASHED_ON_USAGE) ||
......@@ -918,10 +919,15 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
if (!(m_info= maria_clone_internal(share, name, mode, data_file)))
goto err;
if (maria_is_crashed(m_info))
DBUG_PRINT("warning", ("table is crashed: changed: %u",
share->state.changed));
pthread_mutex_unlock(&THR_LOCK_maria);
DBUG_RETURN(m_info);
err:
DBUG_PRINT("error", ("error: %d errpos: %d", my_errno, errpos));
save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
if ((save_errno == HA_ERR_CRASHED) ||
(save_errno == HA_ERR_CRASHED_ON_USAGE) ||
......
/* Copyright (C) 2006, 2007 MySQL AB
Copyright (C) 2010 Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -56,6 +57,7 @@ static ulong skipped_undo_phase;
static ulonglong now; /**< for tracking execution time of phases */
static int (*save_error_handler_hook)(uint, const char *,myf);
static uint recovery_warnings; /**< count of warnings */
static uint recovery_found_crashed_tables;
#define prototype_redo_exec_hook(R) \
static int exec_REDO_LOGREC_ ## R(const TRANSLOG_HEADER_BUFFER *rec)
......@@ -219,7 +221,7 @@ int maria_recovery_from_log(void)
TRUE, TRUE, TRUE, &warnings_count);
if (!res)
{
if (warnings_count == 0)
if (warnings_count == 0 && recovery_found_crashed_tables == 0)
tprint(trace_file, "SUCCESS\n");
else
tprint(trace_file, "DOUBTFUL (%u warnings, check previous output)\n",
......@@ -265,7 +267,7 @@ int maria_apply_log(LSN from_lsn, enum maria_apply_log_way apply,
DBUG_ASSERT(apply == MARIA_LOG_APPLY || !should_run_undo_phase);
DBUG_ASSERT(!maria_multi_threaded);
recovery_warnings= 0;
recovery_warnings= recovery_found_crashed_tables= 0;
maria_recovery_changed_data= 0;
/* checkpoints can happen only if TRNs have been built */
DBUG_ASSERT(should_run_undo_phase || !take_checkpoints);
......@@ -456,7 +458,7 @@ int maria_apply_log(LSN from_lsn, enum maria_apply_log_way apply,
log_record_buffer.str= NULL;
log_record_buffer.length= 0;
ma_checkpoint_end();
*warnings_count= recovery_warnings;
*warnings_count= recovery_warnings + recovery_found_crashed_tables;
if (recovery_message_printed != REC_MSG_NONE)
{
if (procent_printed)
......@@ -726,9 +728,12 @@ prototype_redo_exec_hook(REDO_CREATE_TABLE)
maria_close(info);
info= NULL;
}
else /* one or two files absent, or header corrupted... */
tprint(tracef, "Table '%s' can't be opened, probably does not exist\n",
name);
else
{
/* one or two files absent, or header corrupted... */
tprint(tracef, "Table '%s' can't be opened (Error: %d)\n",
name, my_errno);
}
/* if does not exist, or is older, overwrite it */
ptr= name + strlen(name) + 1;
if ((flags= ptr[0] ? HA_DONT_TOUCH_DATA : 0))
......@@ -1206,6 +1211,7 @@ static int new_table(uint16 sid, const char *name, LSN lsn_of_file_id)
*/
tprint(tracef, ", record is corrupted");
info= NULL;
recovery_warnings++;
goto end;
}
tprint(tracef, "Table '%s', id %u", name, sid);
......@@ -1215,6 +1221,8 @@ static int new_table(uint16 sid, const char *name, LSN lsn_of_file_id)
tprint(tracef, ", is absent (must have been dropped later?)"
" or its header is so corrupted that we cannot open it;"
" we skip it");
if (my_errno != ENOENT)
recovery_found_crashed_tables++;
error= 0;
goto end;
}
......@@ -1238,6 +1246,7 @@ static int new_table(uint16 sid, const char *name, LSN lsn_of_file_id)
*/
tprint(tracef, ", is not transactional. Ignoring open request");
error= -1;
recovery_warnings++;
goto end;
}
if (cmp_translog_addr(lsn_of_file_id, share->state.create_rename_lsn) <= 0)
......@@ -1246,6 +1255,7 @@ static int new_table(uint16 sid, const char *name, LSN lsn_of_file_id)
" LOGREC_FILE_ID's LSN (%lu,0x%lx), ignoring open request",
LSN_IN_PARTS(share->state.create_rename_lsn),
LSN_IN_PARTS(lsn_of_file_id));
recovery_warnings++;
error= -1;
goto end;
/*
......@@ -1257,6 +1267,7 @@ static int new_table(uint16 sid, const char *name, LSN lsn_of_file_id)
{
eprint(tracef, "Table '%s' is crashed, skipping it. Please repair it with"
" maria_chk -r", share->open_file_name.str);
recovery_found_crashed_tables++;
error= -1; /* not fatal, try with other tables */
goto end;
/*
......@@ -1275,6 +1286,7 @@ static int new_table(uint16 sid, const char *name, LSN lsn_of_file_id)
(kfile_len == MY_FILEPOS_ERROR))
{
tprint(tracef, ", length unknown\n");
recovery_warnings++;
goto end;
}
if (share->state.state.data_file_length != dfile_len)
......
......@@ -57,8 +57,16 @@ void tprint(FILE *trace_file __attribute__ ((unused)),
const char *format __attribute__ ((unused)), ...)
{
va_list args;
#ifndef DBUG_OFF
{
char buff[1024];
va_start(args, format);
vsnprintf(buff, sizeof(buff)-1, format, args);
DBUG_PRINT("info", ("%s", buff));
va_end(args);
}
#endif
va_start(args, format);
DBUG_PRINT("info", ("%s", format));
if (trace_file != NULL)
{
if (procent_printed)
......
......@@ -990,7 +990,7 @@ static int maria_chk(HA_CHECK *param, char *filename)
if ((param->testflag & (T_REP_ANY | T_SORT_RECORDS)) &&
((share->state.changed & (STATE_CHANGED | STATE_CRASHED |
STATE_CRASHED_ON_REPAIR) ||
STATE_CRASHED_ON_REPAIR | STATE_IN_REPAIR) ||
!(param->testflag & T_CHECK_ONLY_CHANGED))))
need_to_check=1;
......@@ -1008,7 +1008,7 @@ static int maria_chk(HA_CHECK *param, char *filename)
}
if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
STATE_CRASHED_ON_REPAIR)))
STATE_CRASHED_ON_REPAIR | STATE_IN_REPAIR)))
need_to_check=1;
if (!need_to_check)
{
......@@ -1225,8 +1225,11 @@ static int maria_chk(HA_CHECK *param, char *filename)
if (!error && (param->testflag & T_ZEROFILL))
error= maria_zerofill(param, info, filename);
if (!error)
{
DBUG_PRINT("info", ("Reseting crashed state"));
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
STATE_CRASHED_ON_REPAIR);
STATE_CRASHED_ON_REPAIR | STATE_IN_REPAIR);
}
else
maria_mark_crashed(info);
}
......@@ -1278,8 +1281,9 @@ static int maria_chk(HA_CHECK *param, char *filename)
if ((share->state.changed & STATE_CHANGED) &&
(param->testflag & T_UPDATE_STATE))
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
DBUG_PRINT("info", ("Reseting crashed state"));
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
STATE_CRASHED_ON_REPAIR);
STATE_CRASHED_ON_REPAIR | STATE_IN_REPAIR);
}
else if (!maria_is_crashed(info) &&
(param->testflag & T_UPDATE_STATE))
......
......@@ -611,6 +611,7 @@ struct st_maria_handler
#define STATE_NOT_ZEROFILLED 128
#define STATE_NOT_MOVABLE 256
#define STATE_MOVED 512 /* set if base->uuid != maria_uuid */
#define STATE_IN_REPAIR 1024 /* We are running repair on table */
/* options to maria_read_cache */
......@@ -666,11 +667,17 @@ struct st_maria_handler
#define maria_mark_crashed_on_repair(x) do{(x)->s->state.changed|= \
STATE_CRASHED|STATE_CRASHED_ON_REPAIR; \
(x)->update|= HA_STATE_CHANGED; \
DBUG_PRINT("error", \
("Marked table crashed")); \
DBUG_PRINT("error", ("Marked table crashed on repair")); \
}while(0)
#define maria_mark_in_repair(x) do{(x)->s->state.changed|= \
STATE_CRASHED | STATE_IN_REPAIR; \
(x)->update|= HA_STATE_CHANGED; \
DBUG_PRINT("error", ("Marked table crashed for repair")); \
}while(0)
#define maria_is_crashed(x) ((x)->s->state.changed & STATE_CRASHED)
#define maria_is_crashed_on_repair(x) ((x)->s->state.changed & STATE_CRASHED_ON_REPAIR)
#define maria_in_repair(x) ((x)->s->state.changed & STATE_IN_REPAIR)
#ifdef EXTRA_DEBUG
/**
Brings additional information in certain debug builds and in standalone
......
/* Copyright (C) 2007 MySQL AB
Copyright (C) 2010 Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -150,6 +151,9 @@ int main(int argc, char **argv)
#include "ma_check_standalone.h"
enum options_mc {
OPT_CHARSETS_DIR=256
};
static struct my_option my_long_options[] =
{
......@@ -158,6 +162,9 @@ static struct my_option my_long_options[] =
" Displays a lot of information if not run with --silent",
(uchar **) &opt_apply, (uchar **) &opt_apply, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"character-sets-dir", OPT_CHARSETS_DIR,
"Directory where character sets are.",
(uchar**) &charsets_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"check", 'c',
"if --display-only, check if record is fully readable (for debugging)",
(uchar **) &opt_check, (uchar **) &opt_check, 0,
......@@ -206,7 +213,7 @@ static struct my_option my_long_options[] =
static void print_version(void)
{
VOID(printf("%s Ver 1.2 for %s on %s\n",
VOID(printf("%s Ver 1.3 for %s on %s\n",
my_progname_short, SYSTEM_TYPE, MACHINE_TYPE));
NETWARE_SET_SCREEN_MODE(1);
}
......
......@@ -176,6 +176,7 @@ int trnman_init(TrID initial_trid)
trnman_active_transactions= 0;
trnman_committed_transactions= 0;
trnman_allocated_transactions= 0;
dummy_transaction_object.min_read_from= ~(TrID) 0; /* for recovery */
pool= 0;
global_trid_generator= initial_trid;
......
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