mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Many files:
Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1 innobase/buf/buf0rea.c: Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1 innobase/include/dict0load.h: Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1 innobase/include/fil0fil.h: Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1 innobase/include/row0mysql.h: Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1 innobase/include/trx0trx.h: Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1 innobase/dict/dict0load.c: Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1 innobase/fil/fil0fil.c: Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1 innobase/row/row0ins.c: Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1 innobase/row/row0mysql.c: Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1 innobase/row/row0sel.c: Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1 innobase/srv/srv0start.c: Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1 innobase/trx/trx0trx.c: Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1 sql/ha_innodb.cc: Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1
This commit is contained in:
@ -326,7 +326,7 @@ buf_read_page(
|
||||
if (err == DB_TABLESPACE_DELETED) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: error: trying to access tablespace %lu page no. %lu,\n"
|
||||
" InnoDB: Error: trying to access tablespace %lu page no. %lu,\n"
|
||||
"InnoDB: but the tablespace does not exist or is just being dropped.\n",
|
||||
(ulong) space, (ulong) offset);
|
||||
}
|
||||
|
@ -205,12 +205,14 @@ loop:
|
||||
In a crash recovery we already have all the tablespace objects created.
|
||||
This function compares the space id information in the InnoDB data dictionary
|
||||
to what we already read with fil_load_single_table_tablespaces().
|
||||
In a normal startup we just scan the biggest space id, and store it to
|
||||
fil_system. */
|
||||
|
||||
In a normal startup, we create the tablespace objects for every table in
|
||||
InnoDB's data dictionary, if the corresponding .ibd file exists.
|
||||
We also scan the biggest space id, and store it to fil_system. */
|
||||
|
||||
void
|
||||
dict_check_tablespaces_or_store_max_id(
|
||||
/*===================================*/
|
||||
dict_check_tablespaces_and_store_max_id(
|
||||
/*====================================*/
|
||||
ibool in_crash_recovery) /* in: are we doing a crash recovery */
|
||||
{
|
||||
dict_table_t* sys_tables;
|
||||
@ -280,6 +282,14 @@ loop:
|
||||
FALSE, TRUE, TRUE);
|
||||
}
|
||||
|
||||
if (space_id != 0 && !in_crash_recovery) {
|
||||
/* It is a normal database startup: create the space
|
||||
object and check that the .ibd file exists. */
|
||||
|
||||
fil_open_single_table_tablespace(FALSE, space_id,
|
||||
name);
|
||||
}
|
||||
|
||||
mem_free(name);
|
||||
|
||||
if (space_id > max_space_id) {
|
||||
@ -796,8 +806,18 @@ dict_load_table(
|
||||
/* Ok; (if we did a crash recovery then the tablespace
|
||||
can already be in the memory cache) */
|
||||
} else {
|
||||
/* In >= 4.1.9, InnoDB scans the data dictionary also
|
||||
at a normal mysqld startup. It is an error if the
|
||||
space object does not exist in memory. */
|
||||
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: error: space object of table %s,\n"
|
||||
"InnoDB: space id %lu did not exist in memory. Retrying an open.\n",
|
||||
name, (ulong)space);
|
||||
/* Try to open the tablespace */
|
||||
if (!fil_open_single_table_tablespace(space, name)) {
|
||||
if (!fil_open_single_table_tablespace(TRUE,
|
||||
space, name)) {
|
||||
/* We failed to find a sensible tablespace
|
||||
file */
|
||||
|
||||
|
@ -466,6 +466,10 @@ fil_node_open_file(
|
||||
ulint size_low;
|
||||
ulint size_high;
|
||||
ibool ret;
|
||||
byte* buf2;
|
||||
byte* page;
|
||||
ibool success;
|
||||
ulint space_id;
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
ut_ad(mutex_own(&(system->mutex)));
|
||||
@ -494,6 +498,8 @@ fil_node_open_file(
|
||||
system->n_open++;
|
||||
|
||||
if (node->size == 0) {
|
||||
ut_a(space->purpose != FIL_LOG);
|
||||
|
||||
os_file_get_size(node->handle, &size_low, &size_high);
|
||||
|
||||
size_bytes = (((ib_longlong)size_high) << 32)
|
||||
@ -507,6 +513,46 @@ fil_node_open_file(
|
||||
|
||||
ut_a(space->id != 0);
|
||||
|
||||
if (size_bytes < FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: the size of single-table tablespace file %s\n"
|
||||
"InnoDB: is only %lu %lu, should be at least %lu!", node->name,
|
||||
(ulong) size_high,
|
||||
(ulong) size_low, (ulong) (4 * UNIV_PAGE_SIZE));
|
||||
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
/* Read the first page of the tablespace */
|
||||
|
||||
buf2 = ut_malloc(2 * UNIV_PAGE_SIZE);
|
||||
/* Align the memory for file i/o if we might have O_DIRECT
|
||||
set */
|
||||
page = ut_align(buf2, UNIV_PAGE_SIZE);
|
||||
|
||||
success = os_file_read(node->handle, page, 0, 0,
|
||||
UNIV_PAGE_SIZE);
|
||||
space_id = fsp_header_get_space_id(page);
|
||||
|
||||
ut_free(buf2);
|
||||
|
||||
if (space_id == ULINT_UNDEFINED || space_id == 0) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: tablespace id %lu in file %s is not sensible\n",
|
||||
(ulong) space_id,
|
||||
node->name);
|
||||
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
if (space_id != space->id) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: tablespace id is %lu in the data dictionary\n"
|
||||
"InnoDB: but in file %s it is %lu!\n", space->id, node->name, space_id);
|
||||
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
if (size_bytes >= FSP_EXTENT_SIZE * UNIV_PAGE_SIZE) {
|
||||
node->size = (ulint) ((size_bytes / (1024 * 1024))
|
||||
* ((1024 * 1024) / UNIV_PAGE_SIZE));
|
||||
@ -2487,18 +2533,26 @@ func_exit:
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Tries to open a single-table tablespace and checks the space id is right in
|
||||
it. If does not succeed, prints an error message to the .err log. This
|
||||
function is used to open the tablespace when we load a table definition
|
||||
to the dictionary cache. NOTE that we assume this operation is used under the
|
||||
protection of the dictionary mutex, so that two users cannot race here. This
|
||||
operation does not leave the file associated with the tablespace open, but
|
||||
closes it after we have looked at the space id in it. */
|
||||
Tries to open a single-table tablespace and optionally checks the space id is
|
||||
right in it. If does not succeed, prints an error message to the .err log. This
|
||||
function is used to open a tablespace when we start up mysqld, and also in
|
||||
IMPORT TABLESPACE.
|
||||
NOTE that we assume this operation is used either at the database startup
|
||||
or under the protection of the dictionary mutex, so that two users cannot
|
||||
race here. This operation does not leave the file associated with the
|
||||
tablespace open, but closes it after we have looked at the space id in it. */
|
||||
|
||||
ibool
|
||||
fil_open_single_table_tablespace(
|
||||
/*=============================*/
|
||||
/* out: TRUE if success */
|
||||
ibool check_space_id, /* in: should we check that the space
|
||||
id in the file is right; we assume
|
||||
that this function runs much faster
|
||||
if no check is made, since accessing
|
||||
the file inode probably is much
|
||||
faster (the OS caches them) than
|
||||
accessing the first page of the file */
|
||||
ulint id, /* in: space id */
|
||||
const char* name) /* in: table name in the
|
||||
databasename/tablename format */
|
||||
@ -2540,6 +2594,12 @@ fil_open_single_table_tablespace(
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
if (!check_space_id) {
|
||||
space_id = id;
|
||||
|
||||
goto skip_check;
|
||||
}
|
||||
|
||||
/* Read the first page of the tablespace */
|
||||
|
||||
buf2 = ut_malloc(2 * UNIV_PAGE_SIZE);
|
||||
@ -2552,6 +2612,8 @@ fil_open_single_table_tablespace(
|
||||
|
||||
space_id = fsp_header_get_space_id(page);
|
||||
|
||||
ut_free(buf2);
|
||||
|
||||
if (space_id != id) {
|
||||
ut_print_timestamp(stderr);
|
||||
|
||||
@ -2572,6 +2634,7 @@ fil_open_single_table_tablespace(
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
skip_check:
|
||||
success = fil_space_create(filepath, space_id, FIL_TABLESPACE);
|
||||
|
||||
if (!success) {
|
||||
@ -2584,7 +2647,6 @@ fil_open_single_table_tablespace(
|
||||
fil_node_create(filepath, 0, space_id, FALSE);
|
||||
func_exit:
|
||||
os_file_close(file);
|
||||
ut_free(buf2);
|
||||
mem_free(filepath);
|
||||
|
||||
return(ret);
|
||||
@ -2651,7 +2713,7 @@ fil_load_single_table_tablespace(
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: could not open single-table tablespace file\n"
|
||||
"InnoDB: %s!\n"
|
||||
"InnoDB: We do not continue crash recovery, because the table will become\n"
|
||||
"InnoDB: We do not continue the crash recovery, because the table may become\n"
|
||||
"InnoDB: corrupt if we cannot apply the log records in the InnoDB log to it.\n"
|
||||
"InnoDB: To fix the problem and start mysqld:\n"
|
||||
"InnoDB: 1) If there is a permission problem in the file and mysqld cannot\n"
|
||||
@ -2822,8 +2884,9 @@ fil_load_single_table_tablespace(
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
/* We do not measure the size of the file, that is why we pass the 0
|
||||
below */
|
||||
/* We do not use the size information we have about the file, because
|
||||
the rounding formulat for extents and pages is somewhat complex; we
|
||||
let fil_node_open() do that task. */
|
||||
|
||||
fil_node_create(filepath, 0, space_id, FALSE);
|
||||
func_exit:
|
||||
|
@ -18,12 +18,14 @@ Created 4/24/1996 Heikki Tuuri
|
||||
In a crash recovery we already have all the tablespace objects created.
|
||||
This function compares the space id information in the InnoDB data dictionary
|
||||
to what we already read with fil_load_single_table_tablespaces().
|
||||
In a normal startup we just scan the biggest space id, and store it to
|
||||
fil_system. */
|
||||
|
||||
In a normal startup, we create the tablespace objects for every table in
|
||||
InnoDB's data dictionary, if the corresponding .ibd file exists.
|
||||
We also scan the biggest space id, and store it to fil_system. */
|
||||
|
||||
void
|
||||
dict_check_tablespaces_or_store_max_id(
|
||||
/*===================================*/
|
||||
dict_check_tablespaces_and_store_max_id(
|
||||
/*====================================*/
|
||||
ibool in_crash_recovery); /* in: are we doing a crash recovery */
|
||||
/************************************************************************
|
||||
Finds the first table name in the given database. */
|
||||
|
@ -364,16 +364,26 @@ fil_create_new_single_table_tablespace(
|
||||
tablespace file in pages,
|
||||
must be >= FIL_IBD_FILE_INITIAL_SIZE */
|
||||
/************************************************************************
|
||||
Tries to open a single-table tablespace and checks the space id is right in
|
||||
it. If does not succeed, prints an error message to the .err log. This
|
||||
function is used to open the tablespace when we load a table definition
|
||||
to the dictionary cache. NOTE that we assume this operation is used under the
|
||||
protection of the dictionary mutex, so that two users cannot race here. */
|
||||
Tries to open a single-table tablespace and optionally checks the space id is
|
||||
right in it. If does not succeed, prints an error message to the .err log. This
|
||||
function is used to open a tablespace when we start up mysqld, and also in
|
||||
IMPORT TABLESPACE.
|
||||
NOTE that we assume this operation is used either at the database startup
|
||||
or under the protection of the dictionary mutex, so that two users cannot
|
||||
race here. This operation does not leave the file associated with the
|
||||
tablespace open, but closes it after we have looked at the space id in it. */
|
||||
|
||||
ibool
|
||||
fil_open_single_table_tablespace(
|
||||
/*=============================*/
|
||||
/* out: TRUE if success */
|
||||
ibool check_space_id, /* in: should we check that the space
|
||||
id in the file is right; we assume
|
||||
that this function runs much faster
|
||||
if no check is made, since accessing
|
||||
the file inode probably is much
|
||||
faster (the OS caches them) than
|
||||
accessing the first page of the file */
|
||||
ulint id, /* in: space id */
|
||||
const char* name); /* in: table name in the
|
||||
databasename/tablename format */
|
||||
|
@ -367,25 +367,7 @@ row_drop_table_for_mysql(
|
||||
/*************************************************************************
|
||||
Discards the tablespace of a table which stored in an .ibd file. Discarding
|
||||
means that this function deletes the .ibd file and assigns a new table id for
|
||||
the table. Also the flag table->ibd_file_missing is set TRUE.
|
||||
|
||||
How do we prevent crashes caused by ongoing operations on the table? Old
|
||||
operations could try to access non-existent pages.
|
||||
|
||||
1) SQL queries, INSERT, SELECT, ...: we must get an exclusive MySQL table lock
|
||||
on the table before we can do DISCARD TABLESPACE. Then there are no running
|
||||
queries on the table.
|
||||
2) Purge and rollback: we assign a new table id for the table. Since purge and
|
||||
rollback look for the table based on the table id, they see the table as
|
||||
'dropped' and discard their operations.
|
||||
3) Insert buffer: we remove all entries for the tablespace in the insert
|
||||
buffer tree; as long as the tablespace mem object does not exist, ongoing
|
||||
insert buffer page merges are discarded in buf0rea.c. If we recreate the
|
||||
tablespace mem object with IMPORT TABLESPACE later, then the tablespace will
|
||||
have the same id, but the tablespace_version field in the mem object is
|
||||
different, and ongoing old insert buffer page merges get discarded.
|
||||
4) Linear readahead and random readahead: we use the same method as in 3) to
|
||||
discard ongoing operations. */
|
||||
the table. Also the flag table->ibd_file_missing is set TRUE. */
|
||||
|
||||
int
|
||||
row_discard_tablespace_for_mysql(
|
||||
|
@ -378,6 +378,19 @@ struct trx_struct{
|
||||
replication slave, this is the
|
||||
position in the log file up to which
|
||||
replication has processed */
|
||||
/* A MySQL variable mysql_thd->synchronous_repl tells if we have
|
||||
to use synchronous replication. See ha_innodb.cc. */
|
||||
char* repl_wait_binlog_name;/* NULL, or if synchronous MySQL
|
||||
replication is used, the binlog name
|
||||
up to which we must communicate the
|
||||
binlog to the slave, before returning
|
||||
from a commit; this is the same as
|
||||
mysql_log_file_name, but we allocate
|
||||
and copy the name to a separate buffer
|
||||
here */
|
||||
ib_longlong repl_wait_binlog_pos;/* see above at
|
||||
repl_wait_binlog_name */
|
||||
|
||||
os_thread_id_t mysql_thread_id;/* id of the MySQL thread associated
|
||||
with this transaction object */
|
||||
ulint mysql_process_no;/* since in Linux, 'top' reports
|
||||
|
@ -1173,7 +1173,7 @@ run_again:
|
||||
check_index = foreign->foreign_index;
|
||||
}
|
||||
|
||||
if (check_table == NULL) {
|
||||
if (check_table == NULL || check_table->ibd_file_missing) {
|
||||
if (check_ref) {
|
||||
FILE* ef = dict_foreign_err_file;
|
||||
mutex_enter(&dict_foreign_err_mutex);
|
||||
@ -1192,7 +1192,7 @@ run_again:
|
||||
dtuple_print(ef, entry);
|
||||
fputs("\nBut the parent table ", ef);
|
||||
ut_print_name(ef, trx, foreign->referenced_table_name);
|
||||
fputs(" does not currently exist!\n", ef);
|
||||
fputs("\nor its .ind file does not currently exist!\n", ef);
|
||||
mutex_exit(&dict_foreign_err_mutex);
|
||||
|
||||
return(DB_NO_REFERENCED_ROW);
|
||||
|
@ -870,6 +870,20 @@ row_insert_for_mysql(
|
||||
ut_ad(trx);
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
|
||||
if (prebuilt->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"
|
||||
"http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n"
|
||||
"InnoDB: how you can resolve the problem.\n",
|
||||
prebuilt->table->name);
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to free a corrupt\n"
|
||||
@ -1087,6 +1101,20 @@ row_update_for_mysql(
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
UT_NOT_USED(mysql_rec);
|
||||
|
||||
if (prebuilt->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"
|
||||
"http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n"
|
||||
"InnoDB: how you can resolve the problem.\n",
|
||||
prebuilt->table->name);
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to free a corrupt\n"
|
||||
@ -1966,9 +1994,25 @@ row_add_table_to_background_drop_list(
|
||||
/*************************************************************************
|
||||
Discards the tablespace of a table which stored in an .ibd file. Discarding
|
||||
means that this function deletes the .ibd file and assigns a new table id for
|
||||
the table. Also the flag table->ibd_file_missing is set TRUE.
|
||||
the table. Also the flag table->ibd_file_missing is set TRUE. */
|
||||
|
||||
How do we prevent crashes caused by ongoing operations on the table? Old
|
||||
int
|
||||
row_discard_tablespace_for_mysql(
|
||||
/*=============================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
const char* name, /* in: table name */
|
||||
trx_t* trx) /* in: transaction handle */
|
||||
{
|
||||
dict_foreign_t* foreign;
|
||||
dulint new_id;
|
||||
dict_table_t* table;
|
||||
que_thr_t* thr;
|
||||
que_t* graph = NULL;
|
||||
ibool success;
|
||||
ulint err;
|
||||
char* buf;
|
||||
|
||||
/* How do we prevent crashes caused by ongoing operations on the table? Old
|
||||
operations could try to access non-existent pages.
|
||||
|
||||
1) SQL queries, INSERT, SELECT, ...: we must get an exclusive MySQL table lock
|
||||
@ -1984,22 +2028,9 @@ tablespace mem object with IMPORT TABLESPACE later, then the tablespace will
|
||||
have the same id, but the tablespace_version field in the mem object is
|
||||
different, and ongoing old insert buffer page merges get discarded.
|
||||
4) Linear readahead and random readahead: we use the same method as in 3) to
|
||||
discard ongoing operations. */
|
||||
|
||||
int
|
||||
row_discard_tablespace_for_mysql(
|
||||
/*=============================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
const char* name, /* in: table name */
|
||||
trx_t* trx) /* in: transaction handle */
|
||||
{
|
||||
dulint new_id;
|
||||
dict_table_t* table;
|
||||
que_thr_t* thr;
|
||||
que_t* graph = NULL;
|
||||
ibool success;
|
||||
ulint err;
|
||||
char* buf;
|
||||
discard ongoing operations.
|
||||
5) FOREIGN KEY operations: if table->n_foreign_key_checks_running > 0, we
|
||||
do not allow the discard. We also reserve the data dictionary latch. */
|
||||
|
||||
static const char discard_tablespace_proc1[] =
|
||||
"PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
|
||||
@ -2060,6 +2091,54 @@ row_discard_tablespace_for_mysql(
|
||||
goto funct_exit;
|
||||
}
|
||||
|
||||
if (table->n_foreign_key_checks_running > 0) {
|
||||
|
||||
ut_print_timestamp(stderr);
|
||||
fputs(" InnoDB: You are trying to DISCARD table ", stderr);
|
||||
ut_print_name(stderr, trx, table->name);
|
||||
fputs("\n"
|
||||
"InnoDB: though there is a foreign key check running on it.\n"
|
||||
"InnoDB: Cannot discard the table.\n",
|
||||
stderr);
|
||||
|
||||
err = DB_ERROR;
|
||||
|
||||
goto funct_exit;
|
||||
}
|
||||
|
||||
/* Check if the table is referenced by foreign key constraints from
|
||||
some other table (not the table itself) */
|
||||
|
||||
foreign = UT_LIST_GET_FIRST(table->referenced_list);
|
||||
|
||||
while (foreign && foreign->foreign_table == table) {
|
||||
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
|
||||
}
|
||||
|
||||
if (foreign && trx->check_foreigns) {
|
||||
|
||||
FILE* ef = dict_foreign_err_file;
|
||||
|
||||
/* We only allow discarding a referenced table if
|
||||
FOREIGN_KEY_CHECKS is set to 0 */
|
||||
|
||||
err = DB_CANNOT_DROP_CONSTRAINT;
|
||||
|
||||
mutex_enter(&dict_foreign_err_mutex);
|
||||
rewind(ef);
|
||||
ut_print_timestamp(ef);
|
||||
|
||||
fputs(" Cannot drop table ", ef);
|
||||
ut_print_name(ef, trx, name);
|
||||
fputs("\n"
|
||||
"because it is referenced by ", ef);
|
||||
ut_print_name(ef, trx, foreign->foreign_table_name);
|
||||
putc('\n', ef);
|
||||
mutex_exit(&dict_foreign_err_mutex);
|
||||
|
||||
goto funct_exit;
|
||||
}
|
||||
|
||||
new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
|
||||
|
||||
buf = mem_alloc((sizeof discard_tablespace_proc1) +
|
||||
@ -2077,6 +2156,10 @@ row_discard_tablespace_for_mysql(
|
||||
|
||||
ut_a(graph);
|
||||
|
||||
/* Remove any locks there are on the table or its records */
|
||||
|
||||
lock_reset_all_on_table(table);
|
||||
|
||||
graph->trx = trx;
|
||||
trx->graph = NULL;
|
||||
|
||||
@ -2227,8 +2310,8 @@ row_import_tablespace_for_mysql(
|
||||
|
||||
ibuf_delete_for_discarded_space(table->space);
|
||||
|
||||
success = fil_open_single_table_tablespace(table->space, table->name);
|
||||
|
||||
success = fil_open_single_table_tablespace(TRUE, table->space,
|
||||
table->name);
|
||||
if (success) {
|
||||
table->ibd_file_missing = FALSE;
|
||||
table->tablespace_discarded = FALSE;
|
||||
@ -2236,7 +2319,7 @@ row_import_tablespace_for_mysql(
|
||||
if (table->ibd_file_missing) {
|
||||
ut_print_timestamp(stderr);
|
||||
fputs(
|
||||
" InnoDB: cannot find of open in the database directory the .ibd file of\n"
|
||||
" InnoDB: cannot find or open in the database directory the .ibd file of\n"
|
||||
"InnoDB: table ", stderr);
|
||||
ut_print_name(stderr, trx, name);
|
||||
fputs("\n"
|
||||
@ -3284,6 +3367,20 @@ row_check_table_for_mysql(
|
||||
ulint ret = DB_SUCCESS;
|
||||
ulint old_isolation_level;
|
||||
|
||||
if (prebuilt->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"
|
||||
"http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n"
|
||||
"InnoDB: how you can resolve the problem.\n",
|
||||
prebuilt->table->name);
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
prebuilt->trx->op_info = "checking table";
|
||||
|
||||
old_isolation_level = prebuilt->trx->isolation_level;
|
||||
|
@ -2776,7 +2776,7 @@ row_search_for_mysql(
|
||||
/* out: DB_SUCCESS,
|
||||
DB_RECORD_NOT_FOUND,
|
||||
DB_END_OF_INDEX, DB_DEADLOCK,
|
||||
DB_LOCK_TABLE_FULL,
|
||||
DB_LOCK_TABLE_FULL, DB_CORRUPTION,
|
||||
or DB_TOO_BIG_RECORD */
|
||||
byte* buf, /* in/out: buffer for the fetched
|
||||
row in the MySQL format */
|
||||
@ -2829,6 +2829,20 @@ row_search_for_mysql(
|
||||
ut_ad(index && pcur && search_tuple);
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
|
||||
if (prebuilt->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"
|
||||
"http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n"
|
||||
"InnoDB: how you can resolve the problem.\n",
|
||||
prebuilt->table->name);
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to free a corrupt\n"
|
||||
|
@ -1378,14 +1378,39 @@ NetWare. */
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
/* Since ibuf init is in dict_boot, and ibuf is needed
|
||||
in any disk i/o, first call dict_boot */
|
||||
/* Since the insert buffer init is in dict_boot, and the
|
||||
insert buffer is needed in any disk i/o, first we call
|
||||
dict_boot(). Note that trx_sys_init_at_db_start() only needs
|
||||
to access space 0, and the insert buffer at this stage already
|
||||
works for space 0. */
|
||||
|
||||
dict_boot();
|
||||
trx_sys_init_at_db_start();
|
||||
|
||||
/* The following needs trx lists which are initialized in
|
||||
trx_sys_init_at_db_start */
|
||||
if (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) {
|
||||
/* The following call is necessary for the insert
|
||||
buffer to work with multiple tablespaces. We must
|
||||
know the mapping between space id's and .ibd file
|
||||
names.
|
||||
|
||||
In a crash recovery, we check that the info in data
|
||||
dictionary is consistent with what we already know
|
||||
about space id's from the call of
|
||||
fil_load_single_table_tablespaces().
|
||||
|
||||
In a normal startup, we create the space objects for
|
||||
every table in the InnoDB data dictionary that has
|
||||
an .ibd file.
|
||||
|
||||
We also determine the maximum tablespace id used.
|
||||
|
||||
TODO: We may have incomplete transactions in the
|
||||
data dictionary tables. Does that harm the scanning of
|
||||
the data dictionary below? */
|
||||
|
||||
dict_check_tablespaces_and_store_max_id(
|
||||
recv_needed_recovery);
|
||||
}
|
||||
|
||||
srv_startup_is_before_trx_rollback_phase = FALSE;
|
||||
|
||||
@ -1393,6 +1418,9 @@ NetWare. */
|
||||
system */
|
||||
fsp_header_get_free_limit(0);
|
||||
|
||||
/* recv_recovery_from_checkpoint_finish needs trx lists which
|
||||
are initialized in trx_sys_init_at_db_start(). */
|
||||
|
||||
recv_recovery_from_checkpoint_finish();
|
||||
}
|
||||
|
||||
@ -1433,13 +1461,6 @@ NetWare. */
|
||||
}
|
||||
}
|
||||
#endif /* UNIV_LOG_ARCHIVE */
|
||||
if (!create_new_db && srv_force_recovery == 0) {
|
||||
/* After a crash recovery we only check that the info in data
|
||||
dictionary is consistent with what we already know about space
|
||||
id's from the call of fil_load_single_table_tablespaces(). */
|
||||
|
||||
dict_check_tablespaces_or_store_max_id(recv_needed_recovery);
|
||||
}
|
||||
|
||||
if (srv_measure_contention) {
|
||||
/* os_thread_create(&test_measure_cont, NULL, thread_ids +
|
||||
|
@ -110,6 +110,9 @@ trx_create(
|
||||
trx->mysql_master_log_file_name = "";
|
||||
trx->mysql_master_log_pos = 0;
|
||||
|
||||
trx->repl_wait_binlog_name = NULL;
|
||||
trx->repl_wait_binlog_pos = 0;
|
||||
|
||||
mutex_create(&(trx->undo_mutex));
|
||||
mutex_set_level(&(trx->undo_mutex), SYNC_TRX_UNDO);
|
||||
|
||||
@ -271,6 +274,11 @@ trx_free(
|
||||
trx_undo_arr_free(trx->undo_no_arr);
|
||||
}
|
||||
|
||||
if (trx->repl_wait_binlog_name != NULL) {
|
||||
|
||||
mem_free(trx->repl_wait_binlog_name);
|
||||
}
|
||||
|
||||
ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
|
||||
ut_a(UT_LIST_GET_LEN(trx->reply_signals) == 0);
|
||||
|
||||
|
@ -4977,7 +4977,7 @@ the SQL statement in case of an error. */
|
||||
int
|
||||
ha_innobase::external_lock(
|
||||
/*=======================*/
|
||||
/* out: 0 */
|
||||
/* out: 0 or HA_ERR_CRASHED */
|
||||
THD* thd, /* in: handle to the user thread */
|
||||
int lock_type) /* in: lock type */
|
||||
{
|
||||
@ -4989,19 +4989,6 @@ ha_innobase::external_lock(
|
||||
|
||||
update_thd(thd);
|
||||
|
||||
if (prebuilt->table->ibd_file_missing && !current_thd->tablespace_op) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr, " InnoDB error:\n"
|
||||
"MySQL is trying to use a table handle but the .ibd file for\n"
|
||||
"table %s does not exist.\n"
|
||||
"Have you deleted the .ibd file from the database directory under\n"
|
||||
"the MySQL datadir, or have you used DISCARD TABLESPACE?\n"
|
||||
"Look from section 15.1 of http://www.innodb.com/ibman.html\n"
|
||||
"how you can resolve the problem.\n",
|
||||
prebuilt->table->name);
|
||||
DBUG_RETURN(HA_ERR_CRASHED);
|
||||
}
|
||||
|
||||
trx = prebuilt->trx;
|
||||
|
||||
prebuilt->sql_stat_start = TRUE;
|
||||
|
Reference in New Issue
Block a user