From: Dmitry Lenev Date: September 27 2012 2:56pm Subject: bzr push into mysql-trunk branch (Dmitry.Lenev:4579 to 4580) Bug#14569140 List-Archive: http://lists.mysql.com/commits/144913 X-Bug: 14569140 Message-Id: <20120927145651.26246.70638.4580@jubjub> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 4580 Dmitry Lenev 2012-09-27 [merge] Merged fix for bug #14569140 into mysql-trunk. added: mysql-test/suite/sys_vars/r/metadata_locks_hash_instances_basic.result mysql-test/suite/sys_vars/t/metadata_locks_hash_instances_basic.test modified: mysql-test/r/mysqld--help-notwin.result mysql-test/r/mysqld--help-win.result sql/mdl.cc sql/mdl.h sql/sys_vars.cc unittest/gunit/mdl-t.cc unittest/gunit/mdl_mytap-t.cc 4579 Ramil Kalimullin 2012-09-27 [merge] Null-merge of patches that were previously pushed to the trunk. === modified file 'mysql-test/r/mysqld--help-notwin.result' --- a/mysql-test/r/mysqld--help-notwin.result 2012-09-11 18:07:38 +0000 +++ b/mysql-test/r/mysqld--help-notwin.result 2012-09-27 14:55:47 +0000 @@ -411,6 +411,8 @@ The following options may be given as th --memlock Lock mysqld in memory. --metadata-locks-cache-size=# Size of unused metadata locks cache + --metadata-locks-hash-instances=# + Number of metadata locks hash instances --min-examined-row-limit=# Don't write queries to slow log that examine fewer rows than that @@ -1090,6 +1092,7 @@ max-user-connections 0 max-write-lock-count 18446744073709551615 memlock FALSE metadata-locks-cache-size 1024 +metadata-locks-hash-instances 8 min-examined-row-limit 0 multi-range-count 256 myisam-block-size 1024 === modified file 'mysql-test/r/mysqld--help-win.result' --- a/mysql-test/r/mysqld--help-win.result 2012-09-11 18:07:38 +0000 +++ b/mysql-test/r/mysqld--help-win.result 2012-09-27 14:55:47 +0000 @@ -410,6 +410,8 @@ The following options may be given as th --memlock Lock mysqld in memory. --metadata-locks-cache-size=# Size of unused metadata locks cache + --metadata-locks-hash-instances=# + Number of metadata locks hash instances --min-examined-row-limit=# Don't write queries to slow log that examine fewer rows than that @@ -1097,6 +1099,7 @@ max-user-connections 0 max-write-lock-count 18446744073709551615 memlock FALSE metadata-locks-cache-size 1024 +metadata-locks-hash-instances 8 min-examined-row-limit 0 multi-range-count 256 myisam-block-size 1024 === added file 'mysql-test/suite/sys_vars/r/metadata_locks_hash_instances_basic.result' --- a/mysql-test/suite/sys_vars/r/metadata_locks_hash_instances_basic.result 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/sys_vars/r/metadata_locks_hash_instances_basic.result 2012-09-27 14:54:18 +0000 @@ -0,0 +1,51 @@ +#################################################################### +# Displaying default value # +#################################################################### +SELECT @@GLOBAL.metadata_locks_hash_instances; +@@GLOBAL.metadata_locks_hash_instances +8 +#################################################################### +# Check that value cannot be set (this variable is settable only # +# at start-up). # +#################################################################### +SET @@GLOBAL.metadata_locks_hash_instances=1; +ERROR HY000: Variable 'metadata_locks_hash_instances' is a read only variable +SELECT @@GLOBAL.metadata_locks_hash_instances; +@@GLOBAL.metadata_locks_hash_instances +8 +################################################################# +# Check if the value in GLOBAL Table matches value in variable # +################################################################# +SELECT @@GLOBAL.metadata_locks_hash_instances = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='metadata_locks_hash_instances'; +@@GLOBAL.metadata_locks_hash_instances = VARIABLE_VALUE +1 +SELECT @@GLOBAL.metadata_locks_hash_instances; +@@GLOBAL.metadata_locks_hash_instances +8 +SELECT VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='metadata_locks_hash_instances'; +VARIABLE_VALUE +8 +###################################################################### +# Check if accessing variable with and without GLOBAL point to same # +# variable # +###################################################################### +SELECT @@metadata_locks_hash_instances = @@GLOBAL.metadata_locks_hash_instances; +@@metadata_locks_hash_instances = @@GLOBAL.metadata_locks_hash_instances +1 +###################################################################### +# Check if variable has only the GLOBAL scope # +###################################################################### +SELECT @@metadata_locks_hash_instances; +@@metadata_locks_hash_instances +8 +SELECT @@GLOBAL.metadata_locks_hash_instances; +@@GLOBAL.metadata_locks_hash_instances +8 +SELECT @@local.metadata_locks_hash_instances; +ERROR HY000: Variable 'metadata_locks_hash_instances' is a GLOBAL variable +SELECT @@SESSION.metadata_locks_hash_instances; +ERROR HY000: Variable 'metadata_locks_hash_instances' is a GLOBAL variable === added file 'mysql-test/suite/sys_vars/t/metadata_locks_hash_instances_basic.test' --- a/mysql-test/suite/sys_vars/t/metadata_locks_hash_instances_basic.test 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/sys_vars/t/metadata_locks_hash_instances_basic.test 2012-09-27 14:54:18 +0000 @@ -0,0 +1,60 @@ +########## mysql-test\t\metadata_locks_hash_instances_basic.test ############## +# # +# Variable Name: metadata_locks_hash_instances # +# Scope: Global # +# Access Type: Static # +# Data Type: Integer # +# # +############################################################################### + + +--echo #################################################################### +--echo # Displaying default value # +--echo #################################################################### +SELECT @@GLOBAL.metadata_locks_hash_instances; + + +--echo #################################################################### +--echo # Check that value cannot be set (this variable is settable only # +--echo # at start-up). # +--echo #################################################################### +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@GLOBAL.metadata_locks_hash_instances=1; + +SELECT @@GLOBAL.metadata_locks_hash_instances; + + +--echo ################################################################# +--echo # Check if the value in GLOBAL Table matches value in variable # +--echo ################################################################# +SELECT @@GLOBAL.metadata_locks_hash_instances = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='metadata_locks_hash_instances'; + +SELECT @@GLOBAL.metadata_locks_hash_instances; + +SELECT VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='metadata_locks_hash_instances'; + + +--echo ###################################################################### +--echo # Check if accessing variable with and without GLOBAL point to same # +--echo # variable # +--echo ###################################################################### +SELECT @@metadata_locks_hash_instances = @@GLOBAL.metadata_locks_hash_instances; + + +--echo ###################################################################### +--echo # Check if variable has only the GLOBAL scope # +--echo ###################################################################### + +SELECT @@metadata_locks_hash_instances; + +SELECT @@GLOBAL.metadata_locks_hash_instances; + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@local.metadata_locks_hash_instances; + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@SESSION.metadata_locks_hash_instances; === modified file 'sql/mdl.cc' --- a/sql/mdl.cc 2012-08-07 06:35:32 +0000 +++ b/sql/mdl.cc 2012-09-27 14:55:47 +0000 @@ -16,6 +16,7 @@ #include "mdl.h" #include "debug_sync.h" +#include "sql_array.h" #include #include #include @@ -28,7 +29,7 @@ static PSI_mutex_key key_MDL_wait_LOCK_w static PSI_mutex_info all_mdl_mutexes[]= { - { &key_MDL_map_mutex, "MDL_map::mutex", PSI_FLAG_GLOBAL}, + { &key_MDL_map_mutex, "MDL_map::mutex", 0}, { &key_MDL_wait_LOCK_wait_status, "MDL_wait::LOCK_wait_status", 0} }; @@ -112,22 +113,26 @@ class MDL_object_lock_cache_adapter; /** - A collection of all MDL locks. A singleton, - there is only one instance of the map in the server. + A partition in a collection of all MDL locks. + MDL_map is partitioned for scalability reasons. Maps MDL_key to MDL_lock instances. */ -class MDL_map +class MDL_map_partition { public: - void init(); - void destroy(); - MDL_lock *find_or_insert(const MDL_key *key); - void remove(MDL_lock *lock); + MDL_map_partition(); + ~MDL_map_partition(); + inline MDL_lock *find_or_insert(const MDL_key *mdl_key, + my_hash_value_type hash_value); + inline void remove(MDL_lock *lock); + my_hash_value_type get_key_hash(const MDL_key *mdl_key) const + { + return my_calc_hash(&m_locks, mdl_key->ptr(), mdl_key->length()); + } private: bool move_from_hash_to_lock_mutex(MDL_lock *lock); -private: - /** All acquired locks in the server. */ + /** A partition of all acquired locks in the server. */ HASH m_locks; /* Protects access to m_locks hash. */ mysql_mutex_t m_mutex; @@ -150,6 +155,30 @@ private: I_P_List_counter> Lock_cache; Lock_cache m_unused_locks_cache; +}; + + +/** + Start-up parameter for the number of partitions of the MDL_lock hash. +*/ +ulong mdl_locks_hash_partitions; + +/** + A collection of all MDL locks. A singleton, + there is only one instance of the map in the server. + Contains instances of MDL_map_partition +*/ + +class MDL_map +{ +public: + void init(); + void destroy(); + MDL_lock *find_or_insert(const MDL_key *key); + void remove(MDL_lock *lock); +private: + /** Array of partitions where the locks are actually stored. */ + Dynamic_array m_partitions; /** Pre-allocated MDL_lock object for GLOBAL namespace. */ MDL_lock *m_global_lock; /** Pre-allocated MDL_lock object for COMMIT namespace. */ @@ -397,7 +426,8 @@ public: bool can_grant_lock(enum_mdl_type type, MDL_context *requstor_ctx, bool ignore_lock_priority) const; - inline static MDL_lock *create(const MDL_key *key); + inline static MDL_lock *create(const MDL_key *key, + MDL_map_partition *map_part); void reschedule_waiters(); @@ -424,13 +454,14 @@ public: public: - MDL_lock(const MDL_key *key_arg) + MDL_lock(const MDL_key *key_arg, MDL_map_partition *map_part) : key(key_arg), m_hog_lock_count(0), m_ref_usage(0), m_ref_release(0), m_is_destroyed(FALSE), - m_version(0) + m_version(0), + m_map_part(map_part) { mysql_prlock_init(key_MDL_lock_rwlock, &m_rwlock); } @@ -443,18 +474,18 @@ public: public: /** These three members are used to make it possible to separate - the mdl_locks.m_mutex mutex and MDL_lock::m_rwlock in + the MDL_map_partition::m_mutex mutex and MDL_lock::m_rwlock in MDL_map::find_or_insert() for increased scalability. The 'm_is_destroyed' member is only set by destroyers that - have both the mdl_locks.m_mutex and MDL_lock::m_rwlock, thus + have both the MDL_map_partition::m_mutex and MDL_lock::m_rwlock, thus holding any of the mutexes is sufficient to read it. The 'm_ref_usage; is incremented under protection by - mdl_locks.m_mutex, but when 'm_is_destroyed' is set to TRUE, this + MDL_map_partition::m_mutex, but when 'm_is_destroyed' is set to TRUE, this member is moved to be protected by the MDL_lock::m_rwlock. This means that the MDL_map::find_or_insert() which only holds the MDL_lock::m_rwlock can compare it to 'm_ref_release' - without acquiring mdl_locks.m_mutex again and if equal it can also - destroy the lock object safely. + without acquiring MDL_map_partition::m_mutex again and if equal + it can also destroy the lock object safely. The 'm_ref_release' is incremented under protection by MDL_lock::m_rwlock. Note since we are only interested in equality of these two @@ -468,19 +499,23 @@ public: /** We use the same idea and an additional version counter to support caching of unused MDL_lock object for further re-use. - This counter is incremented while holding both MDL_map::m_mutex and - MDL_lock::m_rwlock locks each time when a MDL_lock is moved from - the hash to the unused objects list (or destroyed). + This counter is incremented while holding both MDL_map_partition::m_mutex + and MDL_lock::m_rwlock locks each time when a MDL_lock is moved from + the partitioned hash to the paritioned unused objects list (or destroyed). A thread, which has found a MDL_lock object for the key in the hash - and then released the MDL_map::m_mutex before acquiring the + and then released the MDL_map_partition::m_mutex before acquiring the MDL_lock::m_rwlock, can determine that this object was moved to the unused objects list (or destroyed) while it held no locks by comparing - the version value which it read while holding the MDL_map::m_mutex + the version value which it read while holding the MDL_map_partition::m_mutex with the value read after acquiring the MDL_lock::m_rwlock. Note that since it takes several years to overflow this counter such theoretically possible overflows should not have any practical effects. */ ulonglong m_version; + /** + Partition of MDL_map where the lock is stored. + */ + MDL_map_partition *m_map_part; }; @@ -493,8 +528,8 @@ public: class MDL_scoped_lock : public MDL_lock { public: - MDL_scoped_lock(const MDL_key *key_arg) - : MDL_lock(key_arg) + MDL_scoped_lock(const MDL_key *key_arg, MDL_map_partition *map_part) + : MDL_lock(key_arg, map_part) { } virtual const bitmap_t *incompatible_granted_types_bitmap() const @@ -534,8 +569,8 @@ private: class MDL_object_lock : public MDL_lock { public: - MDL_object_lock(const MDL_key *key_arg) - : MDL_lock(key_arg) + MDL_object_lock(const MDL_key *key_arg, MDL_map_partition *map_part) + : MDL_lock(key_arg, map_part) { } /** @@ -665,33 +700,62 @@ void mdl_destroy() } -/** Initialize the global hash containing all MDL locks. */ +/** Initialize the container for all MDL locks. */ void MDL_map::init() { MDL_key global_lock_key(MDL_key::GLOBAL, "", ""); MDL_key commit_lock_key(MDL_key::COMMIT, "", ""); + m_global_lock= MDL_lock::create(&global_lock_key, NULL); + m_commit_lock= MDL_lock::create(&commit_lock_key, NULL); + + for (uint i= 0; i < mdl_locks_hash_partitions; i++) + { + MDL_map_partition *part= new (std::nothrow) MDL_map_partition(); + m_partitions.append(part); + } +} + + +/** Initialize the partition in the container with all MDL locks. */ + +MDL_map_partition::MDL_map_partition() +{ mysql_mutex_init(key_MDL_map_mutex, &m_mutex, NULL); my_hash_init(&m_locks, &my_charset_bin, 16 /* FIXME */, 0, 0, mdl_locks_key, 0, 0); - m_global_lock= MDL_lock::create(&global_lock_key); - m_commit_lock= MDL_lock::create(&commit_lock_key); -} +}; /** - Destroy the global hash containing all MDL locks. + Destroy the container for all MDL locks. @pre It must be empty. */ void MDL_map::destroy() { + MDL_lock::destroy(m_global_lock); + MDL_lock::destroy(m_commit_lock); + + while (m_partitions.elements() > 0) + { + MDL_map_partition *part= m_partitions.pop(); + delete part; + } +} + + +/** + Destroy the partition in container for all MDL locks. + @pre It must be empty. +*/ + +MDL_map_partition::~MDL_map_partition() +{ DBUG_ASSERT(!m_locks.records); mysql_mutex_destroy(&m_mutex); my_hash_free(&m_locks); - MDL_lock::destroy(m_global_lock); - MDL_lock::destroy(m_commit_lock); MDL_object_lock *lock; while ((lock= m_unused_locks_cache.pop_front())) @@ -711,13 +775,12 @@ void MDL_map::destroy() MDL_lock* MDL_map::find_or_insert(const MDL_key *mdl_key) { MDL_lock *lock; - my_hash_value_type hash_value; if (mdl_key->mdl_namespace() == MDL_key::GLOBAL || mdl_key->mdl_namespace() == MDL_key::COMMIT) { /* - Avoid locking m_mutex when lock for GLOBAL or COMMIT namespace is + Avoid locking any m_mutex when lock for GLOBAL or COMMIT namespace is requested. Return pointer to pre-allocated MDL_lock instance instead. Such an optimization allows to save one mutex lock/unlock for any statement changing data. @@ -735,8 +798,27 @@ MDL_lock* MDL_map::find_or_insert(const return lock; } + my_hash_value_type hash_value= m_partitions.at(0)->get_key_hash(mdl_key); + uint part_id= hash_value % mdl_locks_hash_partitions; + MDL_map_partition *part= m_partitions.at(part_id); - hash_value= my_calc_hash(&m_locks, mdl_key->ptr(), mdl_key->length()); + return part->find_or_insert(mdl_key, hash_value); +} + + +/** + Find MDL_lock object corresponding to the key and hash value in + MDL_map partition, create it if it does not exist. + + @retval non-NULL - Success. MDL_lock instance for the key with + locked MDL_lock::m_rwlock. + @retval NULL - Failure (OOM). +*/ + +MDL_lock* MDL_map_partition::find_or_insert(const MDL_key *mdl_key, + my_hash_value_type hash_value) +{ + MDL_lock *lock; retry: mysql_mutex_lock(&m_mutex); @@ -769,7 +851,7 @@ retry: } else { - lock= MDL_lock::create(mdl_key); + lock= MDL_lock::create(mdl_key, this); } if (!lock || my_hash_insert(&m_locks, (uchar*)lock)) @@ -800,7 +882,7 @@ retry: /** - Release mdl_locks.m_mutex mutex and lock MDL_lock::m_rwlock for lock + Release MDL_map_partition::m_mutex mutex and lock MDL_lock::m_rwlock for lock object from the hash. Handle situation when object was released while we held no locks. @@ -809,7 +891,7 @@ retry: should re-try looking up MDL_lock object in the hash. */ -bool MDL_map::move_from_hash_to_lock_mutex(MDL_lock *lock) +bool MDL_map_partition::move_from_hash_to_lock_mutex(MDL_lock *lock) { ulonglong version; @@ -818,8 +900,8 @@ bool MDL_map::move_from_hash_to_lock_mut /* We increment m_ref_usage which is a reference counter protected by - mdl_locks.m_mutex under the condition it is present in the hash and - m_is_destroyed is FALSE. + MDL_map_partition::m_mutex under the condition it is present in the hash + and m_is_destroyed is FALSE. */ lock->m_ref_usage++; /* Read value of the version counter under protection of m_mutex lock. */ @@ -891,28 +973,41 @@ void MDL_map::remove(MDL_lock *lock) return; } + lock->m_map_part->remove(lock); +} + + +/** + Destroy MDL_lock object belonging to specific MDL_map + partition or delegate this responsibility to whatever + thread that holds the last outstanding reference to it. +*/ + +void MDL_map_partition::remove(MDL_lock *lock) +{ mysql_mutex_lock(&m_mutex); my_hash_delete(&m_locks, (uchar*) lock); /* To let threads holding references to the MDL_lock object know that it was moved to the list of unused objects or destroyed, we increment the version - counter under protection of both MDL_map::m_mutex and MDL_lock::m_rwlock - locks. This allows us to read the version value while having either one - of those locks. + counter under protection of both MDL_map_partition::m_mutex and + MDL_lock::m_rwlock locks. This allows us to read the version value while + having either one of those locks. */ lock->m_version++; if ((lock->key.mdl_namespace() != MDL_key::SCHEMA) && - (m_unused_locks_cache.elements() < mdl_locks_cache_size)) + (m_unused_locks_cache.elements() < + mdl_locks_cache_size/mdl_locks_hash_partitions)) { /* This is an object of MDL_object_lock type and the cache of unused objects has not reached its maximum size yet. So instead of destroying object we move it to the list of unused objects to allow its later re-use with possibly different key. Any threads holding references to - this object (owning MDL_map::m_mutex or MDL_lock::m_rwlock) will notice - this thanks to the fact that we have changed the MDL_lock::m_version - counter. + this object (owning MDL_map_partition::m_mutex or MDL_lock::m_rwlock) + will notice this thanks to the fact that we have changed the + MDL_lock::m_version counter. */ DBUG_ASSERT(lock->key.mdl_namespace() != MDL_key::GLOBAL && lock->key.mdl_namespace() != MDL_key::COMMIT); @@ -929,8 +1024,8 @@ void MDL_map::remove(MDL_lock *lock) has the responsibility to release it. Setting of m_is_destroyed to TRUE while holding _both_ - mdl_locks.m_mutex and MDL_lock::m_rwlock mutexes transfers the - protection of m_ref_usage from mdl_locks.m_mutex to + MDL_map_partition::m_mutex and MDL_lock::m_rwlock mutexes transfers + the protection of m_ref_usage from MDL_map_partition::m_mutex to MDL_lock::m_rwlock while removal of the object from the hash (and cache of unused objects) makes it read-only. Therefore whoever acquires MDL_lock::m_rwlock next will see the most up @@ -1050,16 +1145,17 @@ void MDL_request::init(const MDL_key *ke @note Also chooses an MDL_lock descendant appropriate for object namespace. */ -inline MDL_lock *MDL_lock::create(const MDL_key *mdl_key) +inline MDL_lock *MDL_lock::create(const MDL_key *mdl_key, + MDL_map_partition *map_part) { switch (mdl_key->mdl_namespace()) { case MDL_key::GLOBAL: case MDL_key::SCHEMA: case MDL_key::COMMIT: - return new (std::nothrow) MDL_scoped_lock(mdl_key); + return new (std::nothrow) MDL_scoped_lock(mdl_key, map_part); default: - return new (std::nothrow) MDL_object_lock(mdl_key); + return new (std::nothrow) MDL_object_lock(mdl_key, map_part); } } === modified file 'sql/mdl.h' --- a/sql/mdl.h 2012-08-07 06:35:32 +0000 +++ b/sql/mdl.h 2012-09-27 14:55:47 +0000 @@ -950,6 +950,14 @@ extern ulong mdl_locks_cache_size; static const ulong MDL_LOCKS_CACHE_SIZE_DEFAULT = 1024; /* + Start-up parameter for the number of partitions of the hash + containing all the MDL_lock objects and a constant for + its default value. +*/ +extern ulong mdl_locks_hash_partitions; +static const ulong MDL_LOCKS_HASH_PARTITIONS_DEFAULT = 8; + +/* Metadata locking subsystem tries not to grant more than max_write_lock_count high-prio, strong locks successively, to avoid starving out weak, low-prio locks. === modified file 'sql/sys_vars.cc' --- a/sql/sys_vars.cc 2012-09-27 10:48:50 +0000 +++ b/sql/sys_vars.cc 2012-09-27 14:55:47 +0000 @@ -1774,6 +1774,12 @@ static Sys_var_ulong Sys_metadata_locks_ VALID_RANGE(1, 1024*1024), DEFAULT(MDL_LOCKS_CACHE_SIZE_DEFAULT), BLOCK_SIZE(1)); +static Sys_var_ulong Sys_metadata_locks_hash_instances( + "metadata_locks_hash_instances", "Number of metadata locks hash instances", + READ_ONLY GLOBAL_VAR(mdl_locks_hash_partitions), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(1, 1024), DEFAULT(MDL_LOCKS_HASH_PARTITIONS_DEFAULT), + BLOCK_SIZE(1)); + static Sys_var_ulong Sys_pseudo_thread_id( "pseudo_thread_id", "This variable is for internal server use", === modified file 'unittest/gunit/mdl-t.cc' --- a/unittest/gunit/mdl-t.cc 2012-08-07 06:35:32 +0000 +++ b/unittest/gunit/mdl-t.cc 2012-09-27 14:55:47 +0000 @@ -108,6 +108,7 @@ protected: static void SetUpTestCase() { error_handler_hook= test_error_handler_hook; + mdl_locks_hash_partitions= MDL_LOCKS_HASH_PARTITIONS_DEFAULT; } void SetUp() === modified file 'unittest/gunit/mdl_mytap-t.cc' --- a/unittest/gunit/mdl_mytap-t.cc 2012-02-02 09:12:43 +0000 +++ b/unittest/gunit/mdl_mytap-t.cc 2012-09-27 14:54:18 +0000 @@ -170,6 +170,7 @@ protected: static void SetUpTestCase() { error_handler_hook= test_error_handler_hook; + mdl_locks_hash_partitions= MDL_LOCKS_HASH_PARTITIONS_DEFAULT; } void SetUp() No bundle (reason: useless for push emails).