Commit 4c43e9da authored by Sergey Vojtovich's avatar Sergey Vojtovich

Applying InnoDB snapshot

Detailed revision comments:

r6547 | marko | 2010-02-03 14:43:38 +0200 (Wed, 03 Feb 2010) | 14 lines
branches/zip: Clean up CHECK TABLE error handling. (Issue #220)

ha_innobase::change_active_index(): Clean up code formatting.

ha_innobase::check(): Incorporate the code from
row_check_table_for_mysql().  Report errors to the client connection
instead of writing them to the error log.

row_check_table_for_mysql(): Remove.

row_check_index_for_mysql(): Renamed from row_scan_and_check_index().
Let the caller initialize prebuilt, and assume that the index is usable.

rb://178 approved by Sunny Bains
parent 4c62306b
2010-02-03 The InnoDB Team
* handler/ha_innodb.cc, include/row0mysql.h, row/row0mysql.c:
Clean up CHECK TABLE error handling.
2010-02-01 The InnoDB Team
* handler/ha_innodb.cc, mysql-test/innodb-autoinc.test,
......
......@@ -7626,8 +7626,13 @@ ha_innobase::check(
HA_CHECK_OPT* check_opt) /*!< in: check options, currently
ignored */
{
ulint ret;
dict_index_t* index;
ulint n_rows;
ulint n_rows_in_table = ULINT_UNDEFINED;
ibool is_ok = TRUE;
ulint old_isolation_level;
DBUG_ENTER("ha_innobase::check");
DBUG_ASSERT(thd == ha_thd());
ut_a(prebuilt->trx);
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
......@@ -7640,17 +7645,140 @@ ha_innobase::check(
build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW);
}
ret = row_check_table_for_mysql(prebuilt);
if (prebuilt->table->ibd_file_missing) {
sql_print_error("InnoDB: Error:\n"
"InnoDB: MySQL is trying to use a table handle"
" but the .ibd file for\n"
"InnoDB: table %s does not exist.\n"
"InnoDB: Have you deleted the .ibd file"
" from the database directory under\n"
"InnoDB: the MySQL datadir, or have you"
" used DISCARD TABLESPACE?\n"
"InnoDB: Please refer to\n"
"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
"InnoDB: how you can resolve the problem.\n",
prebuilt->table->name);
DBUG_RETURN(HA_ADMIN_CORRUPT);
}
switch (ret) {
case DB_SUCCESS:
return(HA_ADMIN_OK);
case DB_INTERRUPTED:
prebuilt->trx->op_info = "checking table";
old_isolation_level = prebuilt->trx->isolation_level;
/* We must run the index record counts at an isolation level
>= READ COMMITTED, because a dirty read can see a wrong number
of records in some index; to play safe, we use always
REPEATABLE READ here */
prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ;
/* Enlarge the fatal lock wait timeout during CHECK TABLE. */
mutex_enter(&kernel_mutex);
srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
mutex_exit(&kernel_mutex);
for (index = dict_table_get_first_index(prebuilt->table);
index != NULL;
index = dict_table_get_next_index(index)) {
#if 0
fputs("Validating index ", stderr);
ut_print_name(stderr, trx, FALSE, index->name);
putc('\n', stderr);
#endif
if (!btr_validate_index(index, prebuilt->trx)) {
is_ok = FALSE;
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_NOT_KEYFILE,
"InnoDB: The B-tree of"
" index '%-.200s' is corrupted.",
index->name);
continue;
}
/* Instead of invoking change_active_index(), set up
a dummy template for non-locking reads, disabling
access to the clustered index. */
prebuilt->index = index;
prebuilt->index_usable = row_merge_is_index_usable(
prebuilt->trx, prebuilt->index);
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
HA_ERR_TABLE_DEF_CHANGED,
"InnoDB: Insufficient history for"
" index '%-.200s'",
index->name);
continue;
}
prebuilt->sql_stat_start = TRUE;
prebuilt->template_type = ROW_MYSQL_DUMMY_TEMPLATE;
prebuilt->n_template = 0;
prebuilt->need_to_access_clustered = FALSE;
dtuple_set_n_fields(prebuilt->search_tuple, 0);
prebuilt->select_lock_type = LOCK_NONE;
if (!row_check_index_for_mysql(prebuilt, index, &n_rows)) {
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_NOT_KEYFILE,
"InnoDB: The B-tree of"
" index '%-.200s' is corrupted.",
index->name);
is_ok = FALSE;
}
if (thd_killed(user_thd)) {
break;
}
#if 0
fprintf(stderr, "%lu entries in index %s\n", n_rows,
index->name);
#endif
if (index == dict_table_get_first_index(prebuilt->table)) {
n_rows_in_table = n_rows;
} else if (n_rows != n_rows_in_table) {
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_NOT_KEYFILE,
"InnoDB: Index '%-.200s'"
" contains %lu entries,"
" should be %lu.",
index->name,
(ulong) n_rows,
(ulong) n_rows_in_table);
is_ok = FALSE;
}
}
/* Restore the original isolation level */
prebuilt->trx->isolation_level = old_isolation_level;
/* We validate also the whole adaptive hash index for all tables
at every CHECK TABLE */
if (!btr_search_validate()) {
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_NOT_KEYFILE,
"InnoDB: The adaptive hash index is corrupted.");
is_ok = FALSE;
}
/* Restore the fatal lock wait timeout after CHECK TABLE. */
mutex_enter(&kernel_mutex);
srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
mutex_exit(&kernel_mutex);
prebuilt->trx->op_info = "";
if (thd_killed(user_thd)) {
my_error(ER_QUERY_INTERRUPTED, MYF(0));
return(-1);
default:
return(HA_ADMIN_CORRUPT);
}
DBUG_RETURN(is_ok ? HA_ADMIN_OK : HA_ADMIN_CORRUPT);
}
/*************************************************************//**
......
......@@ -500,14 +500,19 @@ row_rename_table_for_mysql(
trx_t* trx, /*!< in: transaction handle */
ibool commit); /*!< in: if TRUE then commit trx */
/*********************************************************************//**
Checks a table for corruption.
@return DB_ERROR or DB_SUCCESS */
Checks that the index contains entries in an ascending order, unique
constraint is not broken, and calculates the number of index entries
in the read view of the current transaction.
@return DB_SUCCESS if ok */
UNIV_INTERN
ulint
row_check_table_for_mysql(
row_check_index_for_mysql(
/*======================*/
row_prebuilt_t* prebuilt); /*!< in: prebuilt struct in MySQL
handle */
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct
in MySQL handle */
const dict_index_t* index, /*!< in: index */
ulint* n_rows); /*!< out: number of entries
seen in the consistent read */
/*********************************************************************//**
Determines if a table is a magic monitor table.
......
......@@ -4007,14 +4007,15 @@ Checks that the index contains entries in an ascending order, unique
constraint is not broken, and calculates the number of index entries
in the read view of the current transaction.
@return TRUE if ok */
static
UNIV_INTERN
ibool
row_scan_and_check_index(
/*=====================*/
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct in MySQL */
dict_index_t* index, /*!< in: index */
ulint* n_rows) /*!< out: number of entries seen in the
current consistent read */
row_check_index_for_mysql(
/*======================*/
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct
in MySQL handle */
const dict_index_t* index, /*!< in: index */
ulint* n_rows) /*!< out: number of entries
seen in the consistent read */
{
dtuple_t* prev_entry = NULL;
ulint matched_fields;
......@@ -4035,31 +4036,9 @@ row_scan_and_check_index(
*n_rows = 0;
if (!row_merge_is_index_usable(prebuilt->trx, index)) {
/* A newly created index may lack some delete-marked
records that may exist in the read view of
prebuilt->trx. Thus, such indexes must not be
accessed by consistent read. */
return(is_ok);
}
buf = mem_alloc(UNIV_PAGE_SIZE);
heap = mem_heap_create(100);
/* Make a dummy template in prebuilt, which we will use
in scanning the index entries */
prebuilt->index = index;
/* row_merge_is_index_usable() was already checked above. */
prebuilt->index_usable = TRUE;
prebuilt->sql_stat_start = TRUE;
prebuilt->template_type = ROW_MYSQL_DUMMY_TEMPLATE;
prebuilt->n_template = 0;
prebuilt->need_to_access_clustered = FALSE;
dtuple_set_n_fields(prebuilt->search_tuple, 0);
prebuilt->select_lock_type = LOCK_NONE;
cnt = 1000;
ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
......@@ -4177,119 +4156,6 @@ row_scan_and_check_index(
goto loop;
}
/*********************************************************************//**
Checks a table for corruption.
@return DB_ERROR or DB_SUCCESS */
UNIV_INTERN
ulint
row_check_table_for_mysql(
/*======================*/
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
handle */
{
dict_table_t* table = prebuilt->table;
dict_index_t* index;
ulint n_rows;
ulint n_rows_in_table = ULINT_UNDEFINED;
ulint ret = DB_SUCCESS;
ulint old_isolation_level;
if (table->ibd_file_missing) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Error:\n"
"InnoDB: MySQL is trying to use a table handle"
" but the .ibd file for\n"
"InnoDB: table %s does not exist.\n"
"InnoDB: Have you deleted the .ibd file"
" from the database directory under\n"
"InnoDB: the MySQL datadir, or have you"
" used DISCARD TABLESPACE?\n"
"InnoDB: Look from\n"
"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
"InnoDB: how you can resolve the problem.\n",
table->name);
return(DB_ERROR);
}
prebuilt->trx->op_info = "checking table";
old_isolation_level = prebuilt->trx->isolation_level;
/* We must run the index record counts at an isolation level
>= READ COMMITTED, because a dirty read can see a wrong number
of records in some index; to play safe, we use always
REPEATABLE READ here */
prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ;
/* Enlarge the fatal lock wait timeout during CHECK TABLE. */
mutex_enter(&kernel_mutex);
srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
mutex_exit(&kernel_mutex);
index = dict_table_get_first_index(table);
while (index != NULL) {
/* fputs("Validating index ", stderr);
ut_print_name(stderr, trx, FALSE, index->name);
putc('\n', stderr); */
if (!btr_validate_index(index, prebuilt->trx)) {
ret = DB_ERROR;
} else {
if (!row_scan_and_check_index(prebuilt,index, &n_rows)){
ret = DB_ERROR;
}
if (trx_is_interrupted(prebuilt->trx)) {
ret = DB_INTERRUPTED;
break;
}
/* fprintf(stderr, "%lu entries in index %s\n", n_rows,
index->name); */
if (index == dict_table_get_first_index(table)) {
n_rows_in_table = n_rows;
} else if (n_rows != n_rows_in_table) {
ret = DB_ERROR;
fputs("Error: ", stderr);
dict_index_name_print(stderr,
prebuilt->trx, index);
fprintf(stderr,
" contains %lu entries,"
" should be %lu\n",
(ulong) n_rows,
(ulong) n_rows_in_table);
}
}
index = dict_table_get_next_index(index);
}
/* Restore the original isolation level */
prebuilt->trx->isolation_level = old_isolation_level;
/* We validate also the whole adaptive hash index for all tables
at every CHECK TABLE */
if (!btr_search_validate()) {
ret = DB_ERROR;
}
/* Restore the fatal lock wait timeout after CHECK TABLE. */
mutex_enter(&kernel_mutex);
srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
mutex_exit(&kernel_mutex);
prebuilt->trx->op_info = "";
return(ret);
}
/*********************************************************************//**
Determines if a table is a magic monitor table.
@return TRUE if monitor table */
......
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