mirror of
https://github.com/MariaDB/server.git
synced 2026-04-18 06:15:32 +02:00
MDEV-6089 - MySQL WL#7305 "Improve MDL scalability by using lock-free hash"
Removed MDL map partitions. Won't be needed when this MDEV is implemented.
This commit is contained in:
parent
903160ef59
commit
ecd3ff9f24
9 changed files with 87 additions and 206 deletions
|
|
@ -264,8 +264,8 @@ select * from information_schema.metadata_lock_info;
|
|||
THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME
|
||||
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock
|
||||
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1
|
||||
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock mysqltest2
|
||||
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test
|
||||
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock mysqltest2
|
||||
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock mysqltest2 t2
|
||||
create or replace table test.t1;
|
||||
ERROR 42000: A table must have at least 1 column
|
||||
|
|
@ -291,8 +291,8 @@ select * from information_schema.metadata_lock_info;
|
|||
THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME
|
||||
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock
|
||||
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1
|
||||
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock mysqltest2
|
||||
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test
|
||||
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock mysqltest2
|
||||
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock mysqltest2 t2
|
||||
create or replace table test.t1 (a int) select 1 as 'a', 2 as 'a';
|
||||
ERROR 42S21: Duplicate column name 'a'
|
||||
|
|
|
|||
|
|
@ -454,7 +454,7 @@ The following options may be given as the first argument:
|
|||
--metadata-locks-cache-size=#
|
||||
Unused
|
||||
--metadata-locks-hash-instances=#
|
||||
Number of metadata locks hash instances
|
||||
Unused
|
||||
--min-examined-row-limit=#
|
||||
Don't write queries to slow log that examine fewer rows
|
||||
than that
|
||||
|
|
|
|||
|
|
@ -500,7 +500,7 @@
|
|||
VARIABLE_SCOPE GLOBAL
|
||||
-VARIABLE_TYPE BIGINT UNSIGNED
|
||||
+VARIABLE_TYPE INT UNSIGNED
|
||||
VARIABLE_COMMENT Number of metadata locks hash instances
|
||||
VARIABLE_COMMENT Unused
|
||||
NUMERIC_MIN_VALUE 1
|
||||
NUMERIC_MAX_VALUE 1024
|
||||
@@ -1987,7 +1987,7 @@
|
||||
|
|
|
|||
|
|
@ -2002,7 +2002,7 @@ GLOBAL_VALUE_ORIGIN COMPILE-TIME
|
|||
DEFAULT_VALUE 8
|
||||
VARIABLE_SCOPE GLOBAL
|
||||
VARIABLE_TYPE BIGINT UNSIGNED
|
||||
VARIABLE_COMMENT Number of metadata locks hash instances
|
||||
VARIABLE_COMMENT Unused
|
||||
NUMERIC_MIN_VALUE 1
|
||||
NUMERIC_MAX_VALUE 1024
|
||||
NUMERIC_BLOCK_SIZE 1
|
||||
|
|
|
|||
|
|
@ -500,7 +500,7 @@
|
|||
VARIABLE_SCOPE GLOBAL
|
||||
-VARIABLE_TYPE BIGINT UNSIGNED
|
||||
+VARIABLE_TYPE INT UNSIGNED
|
||||
VARIABLE_COMMENT Number of metadata locks hash instances
|
||||
VARIABLE_COMMENT Unused
|
||||
NUMERIC_MIN_VALUE 1
|
||||
NUMERIC_MAX_VALUE 1024
|
||||
@@ -2183,7 +2183,7 @@
|
||||
|
|
|
|||
|
|
@ -2170,7 +2170,7 @@ GLOBAL_VALUE_ORIGIN COMPILE-TIME
|
|||
DEFAULT_VALUE 8
|
||||
VARIABLE_SCOPE GLOBAL
|
||||
VARIABLE_TYPE BIGINT UNSIGNED
|
||||
VARIABLE_COMMENT Number of metadata locks hash instances
|
||||
VARIABLE_COMMENT Unused
|
||||
NUMERIC_MIN_VALUE 1
|
||||
NUMERIC_MAX_VALUE 1024
|
||||
NUMERIC_BLOCK_SIZE 1
|
||||
|
|
|
|||
274
sql/mdl.cc
274
sql/mdl.cc
|
|
@ -111,39 +111,9 @@ void MDL_key::init_psi_keys()
|
|||
static bool mdl_initialized= 0;
|
||||
|
||||
|
||||
/**
|
||||
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_partition
|
||||
{
|
||||
public:
|
||||
MDL_map_partition();
|
||||
~MDL_map_partition();
|
||||
inline MDL_lock *find_or_insert(const MDL_key *mdl_key);
|
||||
unsigned long get_lock_owner(const MDL_key *key);
|
||||
inline void remove(MDL_lock *lock);
|
||||
private:
|
||||
bool move_from_hash_to_lock_mutex(MDL_lock *lock);
|
||||
/** A partition of all acquired locks in the server. */
|
||||
HASH m_locks;
|
||||
/* Protects access to m_locks hash. */
|
||||
mysql_mutex_t m_mutex;
|
||||
friend int mdl_iterate(int (*)(MDL_ticket *, void *), void *);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
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
|
||||
|
|
@ -155,8 +125,11 @@ public:
|
|||
unsigned long get_lock_owner(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;
|
||||
bool move_from_hash_to_lock_mutex(MDL_lock *lock);
|
||||
/** All acquired locks in the server. */
|
||||
HASH m_locks;
|
||||
/* Protects access to m_locks hash. */
|
||||
mysql_mutex_t m_mutex;
|
||||
/** Pre-allocated MDL_lock object for GLOBAL namespace. */
|
||||
MDL_lock *m_global_lock;
|
||||
/** Pre-allocated MDL_lock object for COMMIT namespace. */
|
||||
|
|
@ -405,8 +378,7 @@ 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,
|
||||
MDL_map_partition *map_part);
|
||||
inline static MDL_lock *create(const MDL_key *key);
|
||||
|
||||
inline unsigned long get_lock_owner() const;
|
||||
|
||||
|
|
@ -435,14 +407,13 @@ public:
|
|||
|
||||
public:
|
||||
|
||||
MDL_lock(const MDL_key *key_arg, MDL_map_partition *map_part)
|
||||
MDL_lock(const MDL_key *key_arg)
|
||||
: key(key_arg),
|
||||
m_hog_lock_count(0),
|
||||
m_ref_usage(0),
|
||||
m_ref_release(0),
|
||||
m_is_destroyed(FALSE),
|
||||
m_version(0),
|
||||
m_map_part(map_part)
|
||||
m_version(0)
|
||||
{
|
||||
mysql_prlock_init(key_MDL_lock_rwlock, &m_rwlock);
|
||||
}
|
||||
|
|
@ -455,17 +426,17 @@ public:
|
|||
public:
|
||||
/**
|
||||
These three members are used to make it possible to separate
|
||||
the MDL_map_partition::m_mutex mutex and MDL_lock::m_rwlock in
|
||||
the MDL_map::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_map_partition::m_mutex and MDL_lock::m_rwlock, thus
|
||||
have both the MDL_map::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_map_partition::m_mutex, but when 'm_is_destroyed' is set to TRUE, this
|
||||
MDL_map::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_map_partition::m_mutex again and if equal
|
||||
without acquiring MDL_map::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.
|
||||
|
|
@ -480,23 +451,19 @@ 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_partition::m_mutex
|
||||
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 partitioned hash to the paritioned unused objects list (or destroyed).
|
||||
the hash to the 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_partition::m_mutex before acquiring the
|
||||
and then released the MDL_map::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_partition::m_mutex
|
||||
the version value which it read while holding the MDL_map::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;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -509,8 +476,8 @@ public:
|
|||
class MDL_scoped_lock : public MDL_lock
|
||||
{
|
||||
public:
|
||||
MDL_scoped_lock(const MDL_key *key_arg, MDL_map_partition *map_part)
|
||||
: MDL_lock(key_arg, map_part)
|
||||
MDL_scoped_lock(const MDL_key *key_arg)
|
||||
: MDL_lock(key_arg)
|
||||
{ }
|
||||
|
||||
virtual const bitmap_t *incompatible_granted_types_bitmap() const
|
||||
|
|
@ -550,8 +517,8 @@ private:
|
|||
class MDL_object_lock : public MDL_lock
|
||||
{
|
||||
public:
|
||||
MDL_object_lock(const MDL_key *key_arg, MDL_map_partition *map_part)
|
||||
: MDL_lock(key_arg, map_part)
|
||||
MDL_object_lock(const MDL_key *key_arg)
|
||||
: MDL_lock(key_arg)
|
||||
{ }
|
||||
|
||||
virtual const bitmap_t *incompatible_granted_types_bitmap() const
|
||||
|
|
@ -660,7 +627,7 @@ static inline int mdl_iterate_lock(MDL_lock *lock,
|
|||
int mdl_iterate(int (*callback)(MDL_ticket *ticket, void *arg), void *arg)
|
||||
{
|
||||
DYNAMIC_ARRAY locks;
|
||||
uint i, j;
|
||||
uint i;
|
||||
int res;
|
||||
DBUG_ENTER("mdl_iterate");
|
||||
|
||||
|
|
@ -670,68 +637,46 @@ int mdl_iterate(int (*callback)(MDL_ticket *ticket, void *arg), void *arg)
|
|||
|
||||
my_init_dynamic_array(&locks, sizeof(MDL_lock*), 512, 1, MYF(0));
|
||||
|
||||
for (i= 0; i < mdl_locks.m_partitions.elements(); i++)
|
||||
/* Collect all locks first */
|
||||
mysql_mutex_lock(&mdl_locks.m_mutex);
|
||||
if (allocate_dynamic(&locks, mdl_locks.m_locks.records))
|
||||
{
|
||||
MDL_map_partition *part= mdl_locks.m_partitions.at(i);
|
||||
/* Collect all locks first */
|
||||
mysql_mutex_lock(&part->m_mutex);
|
||||
if (allocate_dynamic(&locks, part->m_locks.records))
|
||||
{
|
||||
res= 1;
|
||||
mysql_mutex_unlock(&part->m_mutex);
|
||||
break;
|
||||
}
|
||||
reset_dynamic(&locks);
|
||||
for (j= 0; j < part->m_locks.records; j++)
|
||||
{
|
||||
MDL_lock *lock= (MDL_lock*) my_hash_element(&part->m_locks, j);
|
||||
lock->m_ref_usage++;
|
||||
insert_dynamic(&locks, &lock);
|
||||
}
|
||||
mysql_mutex_unlock(&part->m_mutex);
|
||||
|
||||
/* Now show them */
|
||||
for (j= 0; j < locks.elements; j++)
|
||||
{
|
||||
MDL_lock *lock= (MDL_lock*) *dynamic_element(&locks, j, MDL_lock**);
|
||||
res= mdl_iterate_lock(lock, callback, arg);
|
||||
|
||||
mysql_prlock_wrlock(&lock->m_rwlock);
|
||||
uint ref_usage= lock->m_ref_usage;
|
||||
uint ref_release= ++lock->m_ref_release;
|
||||
bool is_destroyed= lock->m_is_destroyed;
|
||||
mysql_prlock_unlock(&lock->m_rwlock);
|
||||
|
||||
if (unlikely(is_destroyed && ref_usage == ref_release))
|
||||
MDL_lock::destroy(lock);
|
||||
|
||||
if (res)
|
||||
break;
|
||||
}
|
||||
res= 1;
|
||||
mysql_mutex_unlock(&mdl_locks.m_mutex);
|
||||
goto end;
|
||||
}
|
||||
for (i= 0; i < mdl_locks.m_locks.records; i++)
|
||||
{
|
||||
MDL_lock *lock= (MDL_lock*) my_hash_element(&mdl_locks.m_locks, i);
|
||||
lock->m_ref_usage++;
|
||||
insert_dynamic(&locks, &lock);
|
||||
}
|
||||
mysql_mutex_unlock(&mdl_locks.m_mutex);
|
||||
|
||||
/* Now show them */
|
||||
for (i= 0; i < locks.elements; i++)
|
||||
{
|
||||
MDL_lock *lock= (MDL_lock*) *dynamic_element(&locks, i, MDL_lock**);
|
||||
res= mdl_iterate_lock(lock, callback, arg);
|
||||
|
||||
mysql_prlock_wrlock(&lock->m_rwlock);
|
||||
uint ref_usage= lock->m_ref_usage;
|
||||
uint ref_release= ++lock->m_ref_release;
|
||||
bool is_destroyed= lock->m_is_destroyed;
|
||||
mysql_prlock_unlock(&lock->m_rwlock);
|
||||
|
||||
if (unlikely(is_destroyed && ref_usage == ref_release))
|
||||
MDL_lock::destroy(lock);
|
||||
|
||||
if (res)
|
||||
break;
|
||||
}
|
||||
end:
|
||||
delete_dynamic(&locks);
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
|
||||
/** 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
my_hash_value_type mdl_hash_function(CHARSET_INFO *cs,
|
||||
const uchar *key, size_t length)
|
||||
{
|
||||
|
|
@ -740,14 +685,20 @@ my_hash_value_type mdl_hash_function(CHARSET_INFO *cs,
|
|||
}
|
||||
|
||||
|
||||
/** Initialize the partition in the container with all MDL locks. */
|
||||
/** Initialize the container for all MDL locks. */
|
||||
|
||||
MDL_map_partition::MDL_map_partition()
|
||||
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);
|
||||
m_commit_lock= MDL_lock::create(&commit_lock_key);
|
||||
|
||||
mysql_mutex_init(key_MDL_map_mutex, &m_mutex, NULL);
|
||||
my_hash_init2(&m_locks, 0, &my_charset_bin, 16 /* FIXME */, 0, 0,
|
||||
mdl_locks_key, mdl_hash_function, 0, 0);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -760,21 +711,6 @@ 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);
|
||||
|
|
@ -816,26 +752,6 @@ MDL_lock* MDL_map::find_or_insert(const MDL_key *mdl_key)
|
|||
return lock;
|
||||
}
|
||||
|
||||
uint part_id= mdl_key->hash_value() % mdl_locks_hash_partitions;
|
||||
MDL_map_partition *part= m_partitions.at(part_id);
|
||||
|
||||
return part->find_or_insert(mdl_key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
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)
|
||||
{
|
||||
MDL_lock *lock;
|
||||
|
||||
retry:
|
||||
mysql_mutex_lock(&m_mutex);
|
||||
if (!(lock= (MDL_lock*) my_hash_search_using_hash_value(&m_locks,
|
||||
|
|
@ -847,7 +763,7 @@ retry:
|
|||
No lock object found so we need to create a new one
|
||||
or reuse an existing unused object.
|
||||
*/
|
||||
lock= MDL_lock::create(mdl_key, this);
|
||||
lock= MDL_lock::create(mdl_key);
|
||||
if (!lock || my_hash_insert(&m_locks, (uchar*)lock))
|
||||
{
|
||||
MDL_lock::destroy(lock);
|
||||
|
|
@ -864,7 +780,7 @@ retry:
|
|||
|
||||
|
||||
/**
|
||||
Release MDL_map_partition::m_mutex mutex and lock MDL_lock::m_rwlock for lock
|
||||
Release MDL_map::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.
|
||||
|
||||
|
|
@ -873,7 +789,7 @@ retry:
|
|||
should re-try looking up MDL_lock object in the hash.
|
||||
*/
|
||||
|
||||
bool MDL_map_partition::move_from_hash_to_lock_mutex(MDL_lock *lock)
|
||||
bool MDL_map::move_from_hash_to_lock_mutex(MDL_lock *lock)
|
||||
{
|
||||
ulonglong version;
|
||||
|
||||
|
|
@ -882,7 +798,7 @@ bool MDL_map_partition::move_from_hash_to_lock_mutex(MDL_lock *lock)
|
|||
|
||||
/*
|
||||
We increment m_ref_usage which is a reference counter protected by
|
||||
MDL_map_partition::m_mutex under the condition it is present in the hash
|
||||
MDL_map::m_mutex under the condition it is present in the hash
|
||||
and m_is_destroyed is FALSE.
|
||||
*/
|
||||
lock->m_ref_usage++;
|
||||
|
|
@ -957,34 +873,19 @@ MDL_map::get_lock_owner(const MDL_key *mdl_key)
|
|||
}
|
||||
else
|
||||
{
|
||||
uint part_id= mdl_key->hash_value() % mdl_locks_hash_partitions;
|
||||
MDL_map_partition *part= m_partitions.at(part_id);
|
||||
res= part->get_lock_owner(mdl_key);
|
||||
mysql_mutex_lock(&m_mutex);
|
||||
lock= (MDL_lock*) my_hash_search_using_hash_value(&m_locks,
|
||||
mdl_key->hash_value(),
|
||||
mdl_key->ptr(),
|
||||
mdl_key->length());
|
||||
if (lock)
|
||||
res= lock->get_lock_owner();
|
||||
mysql_mutex_unlock(&m_mutex);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned long
|
||||
MDL_map_partition::get_lock_owner(const MDL_key *mdl_key)
|
||||
{
|
||||
MDL_lock *lock;
|
||||
unsigned long res= 0;
|
||||
|
||||
mysql_mutex_lock(&m_mutex);
|
||||
lock= (MDL_lock*) my_hash_search_using_hash_value(&m_locks,
|
||||
mdl_key->hash_value(),
|
||||
mdl_key->ptr(),
|
||||
mdl_key->length());
|
||||
if (lock)
|
||||
res= lock->get_lock_owner();
|
||||
mysql_mutex_unlock(&m_mutex);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Destroy MDL_lock object or delegate this responsibility to
|
||||
whatever thread that holds the last outstanding reference to
|
||||
|
|
@ -1004,24 +905,12 @@ 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_partition::m_mutex and
|
||||
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.
|
||||
*/
|
||||
|
|
@ -1033,8 +922,8 @@ void MDL_map_partition::remove(MDL_lock *lock)
|
|||
has the responsibility to release it.
|
||||
|
||||
Setting of m_is_destroyed to TRUE while holding _both_
|
||||
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_map::m_mutex and MDL_lock::m_rwlock mutexes transfers
|
||||
the protection of m_ref_usage from MDL_map::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
|
||||
|
|
@ -1153,17 +1042,16 @@ void MDL_request::init(const MDL_key *key_arg,
|
|||
@note Also chooses an MDL_lock descendant appropriate for object namespace.
|
||||
*/
|
||||
|
||||
inline MDL_lock *MDL_lock::create(const MDL_key *mdl_key,
|
||||
MDL_map_partition *map_part)
|
||||
inline MDL_lock *MDL_lock::create(const MDL_key *mdl_key)
|
||||
{
|
||||
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, map_part);
|
||||
return new (std::nothrow) MDL_scoped_lock(mdl_key);
|
||||
default:
|
||||
return new (std::nothrow) MDL_object_lock(mdl_key, map_part);
|
||||
return new (std::nothrow) MDL_object_lock(mdl_key);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -981,14 +981,6 @@ extern "C" unsigned long thd_get_thread_id(const MYSQL_THD thd);
|
|||
extern "C" int thd_is_connected(MYSQL_THD thd);
|
||||
|
||||
|
||||
/*
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -1410,10 +1410,11 @@ static Sys_var_ulong Sys_metadata_locks_cache_size(
|
|||
VALID_RANGE(1, 1024*1024), DEFAULT(1024),
|
||||
BLOCK_SIZE(1));
|
||||
|
||||
static ulong mdl_locks_hash_partitions;
|
||||
static Sys_var_ulong Sys_metadata_locks_hash_instances(
|
||||
"metadata_locks_hash_instances", "Number of metadata locks hash instances",
|
||||
"metadata_locks_hash_instances", "Unused",
|
||||
READ_ONLY GLOBAL_VAR(mdl_locks_hash_partitions), CMD_LINE(REQUIRED_ARG),
|
||||
VALID_RANGE(1, 1024), DEFAULT(MDL_LOCKS_HASH_PARTITIONS_DEFAULT),
|
||||
VALID_RANGE(1, 1024), DEFAULT(8),
|
||||
BLOCK_SIZE(1));
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue