mirror of
https://github.com/MariaDB/server.git
synced 2025-01-20 05:52:27 +01:00
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
This commit is contained in:
parent
bce33719cc
commit
101d6a09cb
4 changed files with 163 additions and 159 deletions
|
@ -1,3 +1,8 @@
|
|||
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,
|
||||
|
|
|
@ -5489,7 +5489,7 @@ ha_innobase::change_active_index(
|
|||
dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
|
||||
|
||||
dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
|
||||
prebuilt->index->n_fields);
|
||||
prebuilt->index->n_fields);
|
||||
|
||||
/* MySQL changes the active index for a handle also during some
|
||||
queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
|
||||
|
@ -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);
|
||||
|
||||
switch (ret) {
|
||||
case DB_SUCCESS:
|
||||
return(HA_ADMIN_OK);
|
||||
case DB_INTERRUPTED:
|
||||
my_error(ER_QUERY_INTERRUPTED, MYF(0));
|
||||
return(-1);
|
||||
default:
|
||||
return(HA_ADMIN_CORRUPT);
|
||||
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);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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 @@ not_ok:
|
|||
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 */
|
||||
|
|
Loading…
Reference in a new issue