Browse Source
A 5.5 version of the fix for Bug #54360 "Deadlock DROP/ALTER/CREATE
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.pull/73/head
28 changed files with 1300 additions and 652 deletions
-
237mysql-test/r/mdl_sync.result
-
2mysql-test/r/partition_debug_sync.result
-
50mysql-test/r/schema.result
-
8mysql-test/suite/perfschema/r/server_init.result
-
6mysql-test/suite/perfschema/t/server_init.test
-
475mysql-test/t/mdl_sync.test
-
2mysql-test/t/partition_debug_sync.test
-
98mysql-test/t/schema.test
-
67sql/lock.cc
-
3sql/lock.h
-
76sql/mdl.cc
-
10sql/mdl.h
-
21sql/mysqld.cc
-
6sql/mysqld.h
-
97sql/sql_acl.cc
-
167sql/sql_base.cc
-
10sql/sql_base.h
-
320sql/sql_db.cc
-
7sql/sql_db.h
-
23sql/sql_help.cc
-
117sql/sql_hset.h
-
37sql/sql_parse.cc
-
10sql/sql_rename.cc
-
49sql/sql_table.cc
-
1sql/sql_table.h
-
42sql/sql_truncate.cc
-
7sql/sql_view.cc
-
4sql/sql_yacc.yy
@ -0,0 +1,117 @@ |
|||
#ifndef SQL_HSET_INCLUDED |
|||
#define SQL_HSET_INCLUDED |
|||
/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
|||
|
|||
#include "my_global.h" |
|||
#include "hash.h" |
|||
|
|||
|
|||
/** |
|||
A type-safe wrapper around mysys HASH. |
|||
*/ |
|||
|
|||
template <typename T, my_hash_get_key K> |
|||
class Hash_set |
|||
{ |
|||
public: |
|||
typedef T Value_type; |
|||
enum { START_SIZE= 8 }; |
|||
/** |
|||
Constructs an empty hash. Does not allocate memory, it is done upon |
|||
the first insert. Thus does not cause or return errors. |
|||
*/ |
|||
Hash_set(); |
|||
/** |
|||
Destroy the hash by freeing the buckets table. Does |
|||
not call destructors for the elements. |
|||
*/ |
|||
~Hash_set(); |
|||
/** |
|||
Insert a single value into a hash. Does not tell whether |
|||
the value was inserted -- if an identical value existed, |
|||
it is not replaced. |
|||
|
|||
@retval TRUE Out of memory. |
|||
@retval FALSE OK. The value either was inserted or existed |
|||
in the hash. |
|||
*/ |
|||
bool insert(T *value); |
|||
/** Is this hash set empty? */ |
|||
bool is_empty() const { return m_hash.records == 0; } |
|||
/** Returns the number of unique elements. */ |
|||
size_t size() const { return static_cast<size_t>(m_hash.records); } |
|||
/** An iterator over hash elements. Is not insert-stable. */ |
|||
class Iterator |
|||
{ |
|||
public: |
|||
Iterator(Hash_set &hash_set); |
|||
/** |
|||
Return the current element and reposition the iterator to the next |
|||
element. |
|||
*/ |
|||
inline T *operator++(int); |
|||
void rewind() { m_idx= 0; } |
|||
private: |
|||
HASH *m_hash; |
|||
uint m_idx; |
|||
}; |
|||
private: |
|||
HASH m_hash; |
|||
}; |
|||
|
|||
|
|||
template <typename T, my_hash_get_key K> |
|||
Hash_set<T, K>::Hash_set() |
|||
{ |
|||
my_hash_clear(&m_hash); |
|||
} |
|||
|
|||
|
|||
template <typename T, my_hash_get_key K> |
|||
Hash_set<T, K>::~Hash_set() |
|||
{ |
|||
my_hash_free(&m_hash); |
|||
} |
|||
|
|||
|
|||
template <typename T, my_hash_get_key K> |
|||
bool Hash_set<T, K>::insert(T *value) |
|||
{ |
|||
my_hash_init_opt(&m_hash, &my_charset_bin, START_SIZE, 0, 0, K, 0, MYF(0)); |
|||
size_t key_len; |
|||
const uchar *key= K(reinterpret_cast<uchar*>(value), &key_len, FALSE); |
|||
if (my_hash_search(&m_hash, key, key_len) == NULL) |
|||
return my_hash_insert(&m_hash, reinterpret_cast<uchar *>(value)); |
|||
return FALSE; |
|||
} |
|||
|
|||
|
|||
template <typename T, my_hash_get_key K> |
|||
Hash_set<T, K>::Iterator::Iterator(Hash_set<T, K> &set_arg) |
|||
:m_hash(&set_arg.m_hash), |
|||
m_idx(0) |
|||
{} |
|||
|
|||
|
|||
template <typename T, my_hash_get_key K> |
|||
inline T *Hash_set<T, K>::Iterator::operator++(int) |
|||
{ |
|||
if (m_idx < m_hash->records) |
|||
return reinterpret_cast<T*>(my_hash_element(m_hash, m_idx++)); |
|||
return NULL; |
|||
} |
|||
|
|||
#endif // SQL_HSET_INCLUDED |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue