diff options
-rw-r--r-- | innobase/buf/buf0rea.c | 2 | ||||
-rw-r--r-- | innobase/dict/dict0load.c | 30 | ||||
-rw-r--r-- | innobase/fil/fil0fil.c | 93 | ||||
-rw-r--r-- | innobase/include/dict0load.h | 10 | ||||
-rw-r--r-- | innobase/include/fil0fil.h | 28 | ||||
-rw-r--r-- | innobase/include/row0mysql.h | 20 | ||||
-rw-r--r-- | innobase/include/trx0trx.h | 13 | ||||
-rw-r--r-- | innobase/row/row0ins.c | 4 | ||||
-rw-r--r-- | innobase/row/row0mysql.c | 141 | ||||
-rw-r--r-- | innobase/row/row0sel.c | 18 | ||||
-rw-r--r-- | innobase/srv/srv0start.c | 43 | ||||
-rw-r--r-- | innobase/trx/trx0trx.c | 8 | ||||
-rw-r--r-- | sql/ha_innodb.cc | 15 |
13 files changed, 321 insertions, 104 deletions
diff --git a/innobase/buf/buf0rea.c b/innobase/buf/buf0rea.c index 11107d777c8..58287d37387 100644 --- a/innobase/buf/buf0rea.c +++ b/innobase/buf/buf0rea.c @@ -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); } diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c index 7890ebd2b47..61facc8818d 100644 --- a/innobase/dict/dict0load.c +++ b/innobase/dict/dict0load.c @@ -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 */ diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index de528355182..89648b3feca 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -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,21 +2533,29 @@ 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 */ - ulint id, /* in: space id */ - const char* name) /* in: table name in the - databasename/tablename format */ + /* 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 */ { os_file_t file; char* filepath; @@ -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: diff --git a/innobase/include/dict0load.h b/innobase/include/dict0load.h index d4dccb33373..1f0a5407140 100644 --- a/innobase/include/dict0load.h +++ b/innobase/include/dict0load.h @@ -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. */ diff --git a/innobase/include/fil0fil.h b/innobase/include/fil0fil.h index 43327aab9d2..c1a127aadca 100644 --- a/innobase/include/fil0fil.h +++ b/innobase/include/fil0fil.h @@ -364,19 +364,29 @@ 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 */ - ulint id, /* in: space id */ - const char* name); /* in: table name in the - databasename/tablename format */ + /* 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 */ /************************************************************************ It is possible, though very improbable, that the lsn's in the tablespace to be imported have risen above the current system lsn, if a lengthy purge, ibuf diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h index f47ce74ce37..19007069e28 100644 --- a/innobase/include/row0mysql.h +++ b/innobase/include/row0mysql.h @@ -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( diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index 7eb91048684..8336e05bdb0 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -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 diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index 6d1482b6720..f596bd3d473 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -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); diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index dec2b19559c..3be3d3e6396 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -869,7 +869,21 @@ 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; diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index ce76f48e7a7..8cdcdd569ac 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -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 */ @@ -2828,7 +2828,21 @@ 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" diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 69341a1d7d1..c91db1f0dcc 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -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 + diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index f7497ac4090..af4f1979858 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -109,6 +109,9 @@ trx_create( trx->mysql_log_offset = 0; 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); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 552f2676bdd..b8ac40cee92 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -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; |