diff options
author | Jon Olav Hauglid <jon.hauglid@sun.com> | 2010-07-01 15:53:46 +0200 |
---|---|---|
committer | Jon Olav Hauglid <jon.hauglid@sun.com> | 2010-07-01 15:53:46 +0200 |
commit | 41a3dfe49093e41806a0f3b36dbb654ef1b8f29a (patch) | |
tree | c9d08724cb81d3b7ffd2f6515930d6df9e4b5bf1 /sql/sql_truncate.cc | |
parent | 34e409fafa8e5a413f9acbb30ca72a0480e83ed8 (diff) | |
download | mariadb-git-41a3dfe49093e41806a0f3b36dbb654ef1b8f29a.tar.gz |
A 5.5 version of the fix for Bug #54360 "Deadlock DROP/ALTER/CREATE
DATABASE with open HANDLER"
Remove LOCK_create_db, database name locks, and use metadata locks instead.
This exposes CREATE/DROP/ALTER DATABASE statements to the graph-based
deadlock detector in MDL, and paves the way for a safe, deadlock-free
implementation of RENAME DATABASE.
Database DDL statements will now take exclusive metadata locks on
the database name, while table/view/routine DDL statements take
intention exclusive locks on the database name. This prevents race
conditions between database DDL and table/view/routine DDL.
(e.g. DROP DATABASE with concurrent CREATE/ALTER/DROP TABLE)
By adding database name locks, this patch implements
WL#4450 "DDL locking: CREATE/DROP DATABASE must use database locks" and
WL#4985 "DDL locking: namespace/hierarchical locks".
The patch also changes code to use init_one_table() where appropriate.
The new lock_table_names() function requires TABLE_LIST::db_length to
be set correctly, and this is taken care of by init_one_table().
This patch also adds a simple template to help work with
the mysys HASH data structure.
Most of the patch was written by Konstantin Osipov.
Diffstat (limited to 'sql/sql_truncate.cc')
-rw-r--r-- | sql/sql_truncate.cc | 42 |
1 files changed, 18 insertions, 24 deletions
diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index 901ab8e987d..6bbf86cbe55 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -242,9 +242,10 @@ static bool open_and_lock_table_for_truncate(THD *thd, TABLE_LIST *table_ref, MDL_ticket **ticket_downgrade) { TABLE *table= NULL; - MDL_ticket *mdl_ticket= NULL; DBUG_ENTER("open_and_lock_table_for_truncate"); + DBUG_ASSERT(table_ref->lock_type == TL_WRITE); + DBUG_ASSERT(table_ref->mdl_request.type == MDL_SHARED_NO_READ_WRITE); /* Before doing anything else, acquire a metadata lock on the table, or ensure we have one. We don't use open_and_lock_tables() @@ -266,6 +267,7 @@ static bool open_and_lock_table_for_truncate(THD *thd, TABLE_LIST *table_ref, *hton_can_recreate= ha_check_storage_engine_flag(table->s->db_type(), HTON_CAN_RECREATE); + table_ref->mdl_request.ticket= table->mdl_ticket; } else { @@ -273,21 +275,12 @@ static bool open_and_lock_table_for_truncate(THD *thd, TABLE_LIST *table_ref, Even though we could use the previous execution branch here just as well, we must not try to open the table: */ - MDL_request mdl_global_request, mdl_request; - MDL_request_list mdl_requests; - - mdl_global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE); - mdl_request.init(MDL_key::TABLE, table_ref->db, table_ref->table_name, - MDL_SHARED_NO_READ_WRITE); - mdl_requests.push_front(&mdl_request); - mdl_requests.push_front(&mdl_global_request); - - if (thd->mdl_context.acquire_locks(&mdl_requests, - thd->variables.lock_wait_timeout)) + DBUG_ASSERT(table_ref->next_global == NULL); + if (lock_table_names(thd, table_ref, NULL, + thd->variables.lock_wait_timeout, + MYSQL_OPEN_SKIP_TEMPORARY)) DBUG_RETURN(TRUE); - mdl_ticket= mdl_request.ticket; - if (dd_check_storage_engine_flag(thd, table_ref->db, table_ref->table_name, HTON_CAN_RECREATE, hton_can_recreate)) DBUG_RETURN(TRUE); @@ -313,7 +306,9 @@ static bool open_and_lock_table_for_truncate(THD *thd, TABLE_LIST *table_ref, else { ulong timeout= thd->variables.lock_wait_timeout; - if (thd->mdl_context.upgrade_shared_lock_to_exclusive(mdl_ticket, timeout)) + if (thd->mdl_context. + upgrade_shared_lock_to_exclusive(table_ref->mdl_request.ticket, + timeout)) DBUG_RETURN(TRUE); mysql_mutex_lock(&LOCK_open); tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table_ref->db, @@ -335,15 +330,14 @@ static bool open_and_lock_table_for_truncate(THD *thd, TABLE_LIST *table_ref, table_ref->required_type= FRMTYPE_TABLE; /* We don't need to load triggers. */ DBUG_ASSERT(table_ref->trg_event_map == 0); - /* Work around partition parser rules using alter table's. */ - if (thd->lex->alter_info.flags & ALTER_ADMIN_PARTITION) - { - table_ref->lock_type= TL_WRITE; - table_ref->mdl_request.set_type(MDL_SHARED_WRITE); - } - /* Ensure proper lock types (e.g. from the parser). */ - DBUG_ASSERT(table_ref->lock_type == TL_WRITE); - DBUG_ASSERT(table_ref->mdl_request.type == MDL_SHARED_WRITE); + /* + Even though we have an MDL lock on the table here, we don't + pass MYSQL_OPEN_HAS_MDL_LOCK to open_and_lock_tables + since to truncate a MERGE table, we must open and lock + merge children, and on those we don't have an MDL lock. + Thus clear the ticket to satisfy MDL asserts. + */ + table_ref->mdl_request.ticket= NULL; /* Open the table as it will handle some required preparations. |