Commit 903160ef authored by Sergey Vojtovich's avatar Sergey Vojtovich

MDEV-6089 - MySQL WL#7305 "Improve MDL scalability by using lock-free hash"

Removed MDL objects cache. Won't be needed when this MDEV is implemented.
parent 87b0cc99
......@@ -452,7 +452,7 @@ The following options may be given as the first argument:
in between
--memlock Lock mysqld in memory.
--metadata-locks-cache-size=#
Size of unused metadata locks cache
Unused
--metadata-locks-hash-instances=#
Number of metadata locks hash instances
--min-examined-row-limit=#
......
......@@ -491,7 +491,7 @@
VARIABLE_SCOPE GLOBAL
-VARIABLE_TYPE BIGINT UNSIGNED
+VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT Size of unused metadata locks cache
VARIABLE_COMMENT Unused
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 1048576
@@ -1973,7 +1973,7 @@
......
......@@ -1988,7 +1988,7 @@ GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1024
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Size of unused metadata locks cache
VARIABLE_COMMENT Unused
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 1048576
NUMERIC_BLOCK_SIZE 1
......
......@@ -491,7 +491,7 @@
VARIABLE_SCOPE GLOBAL
-VARIABLE_TYPE BIGINT UNSIGNED
+VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT Size of unused metadata locks cache
VARIABLE_COMMENT Unused
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 1048576
@@ -2169,7 +2169,7 @@
......
......@@ -2156,7 +2156,7 @@ GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1024
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Size of unused metadata locks cache
VARIABLE_COMMENT Unused
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 1048576
NUMERIC_BLOCK_SIZE 1
......
......@@ -111,10 +111,6 @@ void MDL_key::init_psi_keys()
static bool mdl_initialized= 0;
class MDL_object_lock;
class MDL_object_lock_cache_adapter;
/**
A partition in a collection of all MDL locks.
MDL_map is partitioned for scalability reasons.
......@@ -135,25 +131,6 @@ private:
HASH m_locks;
/* Protects access to m_locks hash. */
mysql_mutex_t m_mutex;
/**
Cache of (unused) MDL_lock objects available for re-use.
On some systems (e.g. Windows XP) constructing/destructing
MDL_lock objects can be fairly expensive. We use this cache
to avoid these costs in scenarios in which they can have
significant negative effect on performance. For example, when
there is only one thread constantly executing statements in
auto-commit mode and thus constantly causing creation/
destruction of MDL_lock objects for the tables it uses.
Note that this cache contains only MDL_object_lock objects.
Protected by m_mutex mutex.
*/
typedef I_P_List<MDL_object_lock, MDL_object_lock_cache_adapter,
I_P_List_counter>
Lock_cache;
Lock_cache m_unused_locks_cache;
friend int mdl_iterate(int (*)(MDL_ticket *, void *), void *);
};
......@@ -577,26 +554,6 @@ public:
: MDL_lock(key_arg, map_part)
{ }
/**
Reset unused MDL_object_lock object to represent the lock context for a
different object.
*/
void reset(const MDL_key *new_key)
{
/* We need to change only object's key. */
key.mdl_key_init(new_key);
/* m_granted and m_waiting should be already in the empty/initial state. */
DBUG_ASSERT(is_empty());
/* Object should not be marked as destroyed. */
DBUG_ASSERT(! m_is_destroyed);
/*
Values of the rest of the fields should be preserved between old and
new versions of the object. E.g., m_version and m_ref_usage/release
should be kept intact to properly handle possible remaining references
to the old version of the object.
*/
}
virtual const bitmap_t *incompatible_granted_types_bitmap() const
{
return m_granted_incompatible;
......@@ -626,28 +583,10 @@ public:
private:
static const bitmap_t m_granted_incompatible[MDL_TYPE_END];
static const bitmap_t m_waiting_incompatible[MDL_TYPE_END];
public:
/** Members for linking the object into the list of unused objects. */
MDL_object_lock *next_in_cache, **prev_in_cache;
};
/**
Helper class for linking MDL_object_lock objects into the unused objects list.
*/
class MDL_object_lock_cache_adapter :
public I_P_List_adapter<MDL_object_lock, &MDL_object_lock::next_in_cache,
&MDL_object_lock::prev_in_cache>
{
};
static MDL_map mdl_locks;
/**
Start-up parameter for the maximum size of the unused MDL_lock objects cache.
*/
ulong mdl_locks_cache_size;
extern "C"
......@@ -839,10 +778,6 @@ MDL_map_partition::~MDL_map_partition()
DBUG_ASSERT(!m_locks.records);
mysql_mutex_destroy(&m_mutex);
my_hash_free(&m_locks);
MDL_object_lock *lock;
while ((lock= m_unused_locks_cache.pop_front()))
MDL_lock::destroy(lock);
}
......@@ -908,48 +843,14 @@ retry:
mdl_key->ptr(),
mdl_key->length())))
{
MDL_object_lock *unused_lock= NULL;
/*
No lock object found so we need to create a new one
or reuse an existing unused object.
*/
if (mdl_key->mdl_namespace() != MDL_key::SCHEMA &&
m_unused_locks_cache.elements())
{
/*
We need a MDL_object_lock type of object and the unused objects
cache has some. Get the first object from the cache and set a new
key for it.
*/
DBUG_ASSERT(mdl_key->mdl_namespace() != MDL_key::GLOBAL &&
mdl_key->mdl_namespace() != MDL_key::COMMIT);
unused_lock= m_unused_locks_cache.pop_front();
unused_lock->reset(mdl_key);
lock= unused_lock;
}
else
{
lock= MDL_lock::create(mdl_key, this);
}
lock= MDL_lock::create(mdl_key, this);
if (!lock || my_hash_insert(&m_locks, (uchar*)lock))
{
if (unused_lock)
{
/*
Note that we can't easily destroy an object from cache here as it
still might be referenced by other threads. So we simply put it
back into the cache.
*/
m_unused_locks_cache.push_front(unused_lock);
}
else
{
MDL_lock::destroy(lock);
}
MDL_lock::destroy(lock);
mysql_mutex_unlock(&m_mutex);
return NULL;
}
......@@ -1126,55 +1027,32 @@ void MDL_map_partition::remove(MDL_lock *lock)
*/
lock->m_version++;
if ((lock->key.mdl_namespace() != MDL_key::SCHEMA) &&
(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_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);
m_unused_locks_cache.push_front((MDL_object_lock*)lock);
mysql_mutex_unlock(&m_mutex);
mysql_prlock_unlock(&lock->m_rwlock);
}
else
{
/*
Destroy the MDL_lock object, but ensure that anyone that is
holding a reference to the object is not remaining, if so he
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_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
to date version of m_ref_usage.
This means that when m_is_destroyed is TRUE and we hold the
MDL_lock::m_rwlock we can safely read the m_ref_usage
member.
*/
uint ref_usage, ref_release;
/*
Destroy the MDL_lock object, but ensure that anyone that is
holding a reference to the object is not remaining, if so he
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_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
to date version of m_ref_usage.
This means that when m_is_destroyed is TRUE and we hold the
MDL_lock::m_rwlock we can safely read the m_ref_usage
member.
*/
uint ref_usage, ref_release;
lock->m_is_destroyed= TRUE;
ref_usage= lock->m_ref_usage;
ref_release= lock->m_ref_release;
mysql_mutex_unlock(&m_mutex);
mysql_prlock_unlock(&lock->m_rwlock);
if (ref_usage == ref_release)
MDL_lock::destroy(lock);
}
lock->m_is_destroyed= TRUE;
ref_usage= lock->m_ref_usage;
ref_release= lock->m_ref_release;
mysql_mutex_unlock(&m_mutex);
mysql_prlock_unlock(&lock->m_rwlock);
if (ref_usage == ref_release)
MDL_lock::destroy(lock);
}
......
......@@ -981,13 +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 maximum size of the unused MDL_lock objects cache
and a constant for its default value.
*/
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
......
......@@ -1403,10 +1403,11 @@ static Sys_var_ulonglong Sys_max_heap_table_size(
VALID_RANGE(16384, (ulonglong)~(intptr)0), DEFAULT(16*1024*1024),
BLOCK_SIZE(1024));
static ulong mdl_locks_cache_size;
static Sys_var_ulong Sys_metadata_locks_cache_size(
"metadata_locks_cache_size", "Size of unused metadata locks cache",
"metadata_locks_cache_size", "Unused",
READ_ONLY GLOBAL_VAR(mdl_locks_cache_size), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(1, 1024*1024), DEFAULT(MDL_LOCKS_CACHE_SIZE_DEFAULT),
VALID_RANGE(1, 1024*1024), DEFAULT(1024),
BLOCK_SIZE(1));
static Sys_var_ulong Sys_metadata_locks_hash_instances(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment