Commit a9a21fb9 authored by marko's avatar marko

branches/zip: Do not release the data dictionary latch while holding locks

to the data dictionary records.  This should fix Issue #83.

row_drop_table_for_mysql_no_commit(): Rename back to
row_drop_table_for_mysql().  Commit the transaction if the data
dictionary was not locked when the function was called.  Otherwise,
neither commit the transaction nor unlock the data dictionary.

row_merge_drop_table(): Let row_drop_table_for_mysql() take care of
locking the data dictionary.

dict_create_or_check_foreign_constraint_tables(),
trx_rollback_active(), row_create_table_for_mysql(),
row_create_index_for_mysql(), row_table_add_foreign_constraints():
Explicitly commit the transaction, because row_drop_table_for_mysql()
would no longer commit it, given that the data dictionary will be
locked during the calls.

Approved by Sunny (over IM). rb://23
parent 278a68a0
2008-10-08 The InnoDB Team
* dict/dict0crea.c, trx/trx0roll.c, include/row0mysql.h,
row/row0merge.c, row/row0mysql.c: When dropping a table, hold the
data dictionary latch until the transaction has been committed.
The data dictionary latch is supposed to prevent lock waits and
deadlocks in the data dictionary tables. Due to this bug,
DROP TABLE could cause a deadlock or hang. Note that because of
Bug#33650 and Bug#39833, MySQL may also drop a (temporary) table
when executing CREATE INDEX or ALTER TABLE ... ADD INDEX.
2008-10-04 The InnoDB Team 2008-10-04 The InnoDB Team
* handler/ha_innodb.cc, mysql-test/innodb_bug39438-master.opt, * handler/ha_innodb.cc, mysql-test/innodb_bug39438-master.opt,
......
...@@ -1225,7 +1225,6 @@ dict_create_or_check_foreign_constraint_tables(void) ...@@ -1225,7 +1225,6 @@ dict_create_or_check_foreign_constraint_tables(void)
" FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n" " FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n"
"CREATE UNIQUE CLUSTERED INDEX ID_IND" "CREATE UNIQUE CLUSTERED INDEX ID_IND"
" ON SYS_FOREIGN_COLS (ID, POS);\n" " ON SYS_FOREIGN_COLS (ID, POS);\n"
"COMMIT WORK;\n"
"END;\n" "END;\n"
, FALSE, trx); , FALSE, trx);
...@@ -1248,7 +1247,7 @@ dict_create_or_check_foreign_constraint_tables(void) ...@@ -1248,7 +1247,7 @@ dict_create_or_check_foreign_constraint_tables(void)
error = DB_MUST_GET_MORE_FILE_SPACE; error = DB_MUST_GET_MORE_FILE_SPACE;
} }
trx->op_info = ""; trx_commit_for_mysql(trx);
row_mysql_unlock_data_dictionary(trx); row_mysql_unlock_data_dictionary(trx);
......
...@@ -411,10 +411,12 @@ row_truncate_table_for_mysql( ...@@ -411,10 +411,12 @@ row_truncate_table_for_mysql(
dict_table_t* table, /* in: table handle */ dict_table_t* table, /* in: table handle */
trx_t* trx); /* in: transaction handle */ trx_t* trx); /* in: transaction handle */
/************************************************************************* /*************************************************************************
Drops a table for MySQL. If the name of the dropped table ends in Drops a table for MySQL. If the name of the dropped table ends in
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor", one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
"innodb_table_monitor", then this will also stop the printing of monitor "innodb_table_monitor", then this will also stop the printing of monitor
output by the master thread. */ output by the master thread. If the data dictionary was not already locked
by the transaction, the transaction will be committed. Otherwise, the
data dictionary will remain locked. */
UNIV_INTERN UNIV_INTERN
int int
row_drop_table_for_mysql( row_drop_table_for_mysql(
...@@ -425,20 +427,6 @@ row_drop_table_for_mysql( ...@@ -425,20 +427,6 @@ row_drop_table_for_mysql(
ibool drop_db);/* in: TRUE=dropping whole database */ ibool drop_db);/* in: TRUE=dropping whole database */
/************************************************************************* /*************************************************************************
Drops a table for MySQL but does not commit the transaction. If the
name of the dropped table ends in one of "innodb_monitor",
"innodb_lock_monitor", "innodb_tablespace_monitor",
"innodb_table_monitor", then this will also stop the printing of
monitor output by the master thread. */
UNIV_INTERN
int
row_drop_table_for_mysql_no_commit(
/*===============================*/
/* out: error code or DB_SUCCESS */
const char* name, /* in: table name */
trx_t* trx, /* in: transaction handle */
ibool drop_db);/* in: TRUE=dropping whole database */
/*************************************************************************
Discards the tablespace of a table which stored in an .ibd file. Discarding 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 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. */
......
...@@ -2218,24 +2218,10 @@ row_merge_drop_table( ...@@ -2218,24 +2218,10 @@ row_merge_drop_table(
trx_t* trx, /* in: transaction */ trx_t* trx, /* in: transaction */
dict_table_t* table) /* in: table to drop */ dict_table_t* table) /* in: table to drop */
{ {
ulint err = DB_SUCCESS;
ibool dict_locked = FALSE;
if (trx->dict_operation_lock_mode == 0) {
row_mysql_lock_data_dictionary(trx);
dict_locked = TRUE;
}
/* There must be no open transactions on the table. */ /* There must be no open transactions on the table. */
ut_a(table->n_mysql_handles_opened == 0); ut_a(table->n_mysql_handles_opened == 0);
err = row_drop_table_for_mysql_no_commit(table->name, trx, FALSE); return(row_drop_table_for_mysql(table->name, trx, FALSE));
if (dict_locked) {
row_mysql_unlock_data_dictionary(trx);
}
return(err);
} }
/************************************************************************* /*************************************************************************
......
...@@ -1850,6 +1850,7 @@ err_exit: ...@@ -1850,6 +1850,7 @@ err_exit:
if (dict_table_get_low(table->name)) { if (dict_table_get_low(table->name)) {
row_drop_table_for_mysql(table->name, trx, FALSE); row_drop_table_for_mysql(table->name, trx, FALSE);
trx_commit_for_mysql(trx);
} }
break; break;
...@@ -2007,6 +2008,8 @@ error_handling: ...@@ -2007,6 +2008,8 @@ error_handling:
row_drop_table_for_mysql(table_name, trx, FALSE); row_drop_table_for_mysql(table_name, trx, FALSE);
trx_commit_for_mysql(trx);
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
} }
...@@ -2074,6 +2077,8 @@ row_table_add_foreign_constraints( ...@@ -2074,6 +2077,8 @@ row_table_add_foreign_constraints(
row_drop_table_for_mysql(name, trx, FALSE); row_drop_table_for_mysql(name, trx, FALSE);
trx_commit_for_mysql(trx);
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
} }
...@@ -2933,10 +2938,12 @@ funct_exit: ...@@ -2933,10 +2938,12 @@ funct_exit:
} }
/************************************************************************* /*************************************************************************
Drops a table for MySQL. If the name of the dropped table ends in Drops a table for MySQL. If the name of the dropped table ends in
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor", one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
"innodb_table_monitor", then this will also stop the printing of monitor "innodb_table_monitor", then this will also stop the printing of monitor
output by the master thread. */ output by the master thread. If the data dictionary was not already locked
by the transaction, the transaction will be committed. Otherwise, the
data dictionary will remain locked. */
UNIV_INTERN UNIV_INTERN
int int
row_drop_table_for_mysql( row_drop_table_for_mysql(
...@@ -2945,29 +2952,6 @@ row_drop_table_for_mysql( ...@@ -2945,29 +2952,6 @@ row_drop_table_for_mysql(
const char* name, /* in: table name */ const char* name, /* in: table name */
trx_t* trx, /* in: transaction handle */ trx_t* trx, /* in: transaction handle */
ibool drop_db)/* in: TRUE=dropping whole database */ ibool drop_db)/* in: TRUE=dropping whole database */
{
ulint err;
err = row_drop_table_for_mysql_no_commit(name, trx, drop_db);
trx_commit_for_mysql(trx);
return(err);
}
/*************************************************************************
Drops a table for MySQL but does not commit the transaction. If the
name of the dropped table ends in one of "innodb_monitor",
"innodb_lock_monitor", "innodb_tablespace_monitor",
"innodb_table_monitor", then this will also stop the printing of
monitor output by the master thread. */
UNIV_INTERN
int
row_drop_table_for_mysql_no_commit(
/*===============================*/
/* out: error code or DB_SUCCESS */
const char* name, /* in: table name */
trx_t* trx, /* in: transaction handle */
ibool drop_db)/* in: TRUE=dropping whole database */
{ {
dict_foreign_t* foreign; dict_foreign_t* foreign;
dict_table_t* table; dict_table_t* table;
...@@ -3336,6 +3320,8 @@ check_next_foreign: ...@@ -3336,6 +3320,8 @@ check_next_foreign:
funct_exit: funct_exit:
if (locked_dictionary) { if (locked_dictionary) {
trx_commit_for_mysql(trx);
row_mysql_unlock_data_dictionary(trx); row_mysql_unlock_data_dictionary(trx);
} }
......
...@@ -506,6 +506,7 @@ trx_rollback_active( ...@@ -506,6 +506,7 @@ trx_rollback_active(
fputs(" in recovery\n", stderr); fputs(" in recovery\n", stderr);
err = row_drop_table_for_mysql(table->name, trx, TRUE); err = row_drop_table_for_mysql(table->name, trx, TRUE);
trx_commit_for_mysql(trx);
ut_a(err == (int) DB_SUCCESS); ut_a(err == (int) DB_SUCCESS);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment