diff options
author | dlenev@mockturtle.local <> | 2007-05-11 20:33:13 +0400 |
---|---|---|
committer | dlenev@mockturtle.local <> | 2007-05-11 20:33:13 +0400 |
commit | 8b93e52e92391586edf99f26ba558ab7e6bf9bc9 (patch) | |
tree | 01aa6fe19c21d165b16410f3782f57992de632f1 /sql/lock.cc | |
parent | 4b0d37362b0f70623a34a2e6512c40e12af3338f (diff) | |
download | mariadb-git-8b93e52e92391586edf99f26ba558ab7e6bf9bc9.tar.gz |
Fix for:
Bug #20662 "Infinite loop in CREATE TABLE IF NOT EXISTS ... SELECT
with locked tables"
Bug #20903 "Crash when using CREATE TABLE .. SELECT and triggers"
Bug #24738 "CREATE TABLE ... SELECT is not isolated properly"
Bug #24508 "Inconsistent results of CREATE TABLE ... SELECT when
temporary table exists"
Deadlock occured when one tried to execute CREATE TABLE IF NOT
EXISTS ... SELECT statement under LOCK TABLES which held
read lock on target table.
Attempt to execute the same statement for already existing
target table with triggers caused server crashes.
Also concurrent execution of CREATE TABLE ... SELECT statement
and other statements involving target table suffered from
various races (some of which might've led to deadlocks).
Finally, attempt to execute CREATE TABLE ... SELECT in case
when a temporary table with same name was already present
led to the insertion of data into this temporary table and
creation of empty non-temporary table.
All above problems stemmed from the old implementation of CREATE
TABLE ... SELECT in which we created, opened and locked target
table without any special protection in a separate step and not
with the rest of tables used by this statement.
This underminded deadlock-avoidance approach used in server
and created window for races. It also excluded target table
from prelocking causing problems with trigger execution.
The patch solves these problems by implementing new approach to
handling of CREATE TABLE ... SELECT for base tables.
We try to open and lock table to be created at the same time as
the rest of tables used by this statement. If such table does not
exist at this moment we create and place in the table cache special
placeholder for it which prevents its creation or any other usage
by other threads.
We still use old approach for creation of temporary tables.
Also note that we decided to postpone introduction of some tests
for concurrent behaviour of CREATE TABLE ... SELECT till 5.1.
The main reason for this is absence in 5.0 ability to set @@debug
variable at runtime, which can be circumvented only by using several
test files with individual .opt files. Since the latter is likely
to slowdown test-suite unnecessary we chose not to push this tests
into 5.0, but run them manually for this version and later push
their optimized version into 5.1
Diffstat (limited to 'sql/lock.cc')
-rw-r--r-- | sql/lock.cc | 33 |
1 files changed, 6 insertions, 27 deletions
diff --git a/sql/lock.cc b/sql/lock.cc index 233d12d9cc4..9298b33b4d2 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -853,7 +853,6 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list) TABLE *table; char key[MAX_DBKEY_LENGTH]; char *db= table_list->db; - int table_in_key_offset; uint key_length; HASH_SEARCH_STATE state; DBUG_ENTER("lock_table_name"); @@ -861,10 +860,8 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list) safe_mutex_assert_owner(&LOCK_open); - table_in_key_offset= strmov(key, db) - key + 1; - key_length= (uint)(strmov(key + table_in_key_offset, table_list->table_name) - - key) + 1; - + key_length= (uint)(strmov(strmov(key, db) + 1, table_list->table_name) - + key) + 1; /* Only insert the table if we haven't insert it already */ for (table=(TABLE*) hash_first(&open_cache, (byte*)key, key_length, &state); @@ -873,29 +870,11 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list) if (table->in_use == thd) DBUG_RETURN(0); - /* - Create a table entry with the right key and with an old refresh version - Note that we must use my_malloc() here as this is freed by the table - cache - */ - if (!(table= (TABLE*) my_malloc(sizeof(*table)+key_length, - MYF(MY_WME | MY_ZEROFILL)))) - DBUG_RETURN(-1); - table->s= &table->share_not_to_be_used; - memcpy((table->s->table_cache_key= (char*) (table+1)), key, key_length); - table->s->db= table->s->table_cache_key; - table->s->table_name= table->s->table_cache_key + table_in_key_offset; - table->s->key_length=key_length; - table->in_use=thd; - table->locked_by_name=1; - table_list->table=table; - - if (my_hash_insert(&open_cache, (byte*) table)) - { - my_free((gptr) table,MYF(0)); + if (!(table= table_cache_insert_placeholder(thd, key, key_length))) DBUG_RETURN(-1); - } - + + table_list->table= table; + /* Return 1 if table is in use */ DBUG_RETURN(test(remove_table_from_cache(thd, db, table_list->table_name, RTFC_NO_FLAG))); |