List:Commits« Previous MessageNext Message »
From:Dmitry Lenev Date:September 27 2012 2:56pm
Subject:bzr push into mysql-trunk branch (Dmitry.Lenev:4579 to 4580) Bug#14569140
View as plain text  
 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 <hash.h>
 #include <mysqld_error.h>
 #include <mysql/plugin.h>
@@ -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<MDL_map_partition *> 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).
Thread
bzr push into mysql-trunk branch (Dmitry.Lenev:4579 to 4580) Bug#14569140Dmitry Lenev28 Sep