mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03: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:
@ -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
|
2010-02-01 The InnoDB Team
|
||||||
|
|
||||||
* handler/ha_innodb.cc, mysql-test/innodb-autoinc.test,
|
* 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);
|
dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
|
||||||
|
|
||||||
dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
|
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
|
/* MySQL changes the active index for a handle also during some
|
||||||
queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
|
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
|
HA_CHECK_OPT* check_opt) /*!< in: check options, currently
|
||||||
ignored */
|
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());
|
DBUG_ASSERT(thd == ha_thd());
|
||||||
ut_a(prebuilt->trx);
|
ut_a(prebuilt->trx);
|
||||||
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
|
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);
|
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"
|
||||||
switch (ret) {
|
"InnoDB: MySQL is trying to use a table handle"
|
||||||
case DB_SUCCESS:
|
" but the .ibd file for\n"
|
||||||
return(HA_ADMIN_OK);
|
"InnoDB: table %s does not exist.\n"
|
||||||
case DB_INTERRUPTED:
|
"InnoDB: Have you deleted the .ibd file"
|
||||||
my_error(ER_QUERY_INTERRUPTED, MYF(0));
|
" from the database directory under\n"
|
||||||
return(-1);
|
"InnoDB: the MySQL datadir, or have you"
|
||||||
default:
|
" used DISCARD TABLESPACE?\n"
|
||||||
return(HA_ADMIN_CORRUPT);
|
"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 */
|
trx_t* trx, /*!< in: transaction handle */
|
||||||
ibool commit); /*!< in: if TRUE then commit trx */
|
ibool commit); /*!< in: if TRUE then commit trx */
|
||||||
/*********************************************************************//**
|
/*********************************************************************//**
|
||||||
Checks a table for corruption.
|
Checks that the index contains entries in an ascending order, unique
|
||||||
@return DB_ERROR or DB_SUCCESS */
|
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
|
UNIV_INTERN
|
||||||
ulint
|
ulint
|
||||||
row_check_table_for_mysql(
|
row_check_index_for_mysql(
|
||||||
/*======================*/
|
/*======================*/
|
||||||
row_prebuilt_t* prebuilt); /*!< in: prebuilt struct in MySQL
|
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct
|
||||||
handle */
|
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.
|
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
|
constraint is not broken, and calculates the number of index entries
|
||||||
in the read view of the current transaction.
|
in the read view of the current transaction.
|
||||||
@return TRUE if ok */
|
@return TRUE if ok */
|
||||||
static
|
UNIV_INTERN
|
||||||
ibool
|
ibool
|
||||||
row_scan_and_check_index(
|
row_check_index_for_mysql(
|
||||||
/*=====================*/
|
/*======================*/
|
||||||
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct in MySQL */
|
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct
|
||||||
dict_index_t* index, /*!< in: index */
|
in MySQL handle */
|
||||||
ulint* n_rows) /*!< out: number of entries seen in the
|
const dict_index_t* index, /*!< in: index */
|
||||||
current consistent read */
|
ulint* n_rows) /*!< out: number of entries
|
||||||
|
seen in the consistent read */
|
||||||
{
|
{
|
||||||
dtuple_t* prev_entry = NULL;
|
dtuple_t* prev_entry = NULL;
|
||||||
ulint matched_fields;
|
ulint matched_fields;
|
||||||
@ -4035,31 +4036,9 @@ row_scan_and_check_index(
|
|||||||
|
|
||||||
*n_rows = 0;
|
*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);
|
buf = mem_alloc(UNIV_PAGE_SIZE);
|
||||||
heap = mem_heap_create(100);
|
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;
|
cnt = 1000;
|
||||||
|
|
||||||
ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
|
ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
|
||||||
@ -4177,119 +4156,6 @@ not_ok:
|
|||||||
goto loop;
|
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.
|
Determines if a table is a magic monitor table.
|
||||||
@return TRUE if monitor table */
|
@return TRUE if monitor table */
|
||||||
|
Reference in New Issue
Block a user