Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
5c6aa4de
Commit
5c6aa4de
authored
Feb 27, 2015
by
Sergey Vojtovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MDEV-6089 - MySQL WL#7305 "Improve MDL scalability by using lock-free hash"
Replaced hash with lock-free hash.
parent
d9e3a9f2
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
137 additions
and
171 deletions
+137
-171
mysql-test/r/create_or_replace.result
mysql-test/r/create_or_replace.result
+6
-6
sql/mdl.cc
sql/mdl.cc
+128
-164
sql/mdl.h
sql/mdl.h
+3
-1
No files found.
mysql-test/r/create_or_replace.result
View file @
5c6aa4de
...
@@ -264,8 +264,8 @@ select * from information_schema.metadata_lock_info;
...
@@ -264,8 +264,8 @@ select * from information_schema.metadata_lock_info;
THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME
THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock mysqltest2
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock mysqltest2
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock mysqltest2 t2
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock mysqltest2 t2
create or replace table test.t1;
create or replace table test.t1;
ERROR 42000: A table must have at least 1 column
ERROR 42000: A table must have at least 1 column
...
@@ -291,8 +291,8 @@ select * from information_schema.metadata_lock_info;
...
@@ -291,8 +291,8 @@ select * from information_schema.metadata_lock_info;
THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME
THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock mysqltest2
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock mysqltest2
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock mysqltest2 t2
# 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';
create or replace table test.t1 (a int) select 1 as 'a', 2 as 'a';
ERROR 42S21: Duplicate column name 'a'
ERROR 42S21: Duplicate column name 'a'
...
@@ -400,29 +400,29 @@ select * from information_schema.metadata_lock_info;
...
@@ -400,29 +400,29 @@ select * from information_schema.metadata_lock_info;
THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME
THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test
# MDL_SHARED_READ MDL_EXPLICIT Table metadata lock test t2
# MDL_SHARED_READ MDL_EXPLICIT Table metadata lock test t2
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test
create or replace table t1 (i int);
create or replace table t1 (i int);
select * from information_schema.metadata_lock_info;
select * from information_schema.metadata_lock_info;
THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME
THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test
# MDL_SHARED_READ MDL_EXPLICIT Table metadata lock test t2
# MDL_SHARED_READ MDL_EXPLICIT Table metadata lock test t2
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test
create or replace table t1 like t2;
create or replace table t1 like t2;
select * from information_schema.metadata_lock_info;
select * from information_schema.metadata_lock_info;
THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME
THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test
# MDL_SHARED_READ MDL_EXPLICIT Table metadata lock test t2
# MDL_SHARED_READ MDL_EXPLICIT Table metadata lock test t2
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test
create or replace table t1 select 1 as f1;
create or replace table t1 select 1 as f1;
select * from information_schema.metadata_lock_info;
select * from information_schema.metadata_lock_info;
THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME
THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Global read lock
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1
# MDL_SHARED_NO_READ_WRITE MDL_EXPLICIT Table metadata lock test t1
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test
# MDL_SHARED_READ MDL_EXPLICIT Table metadata lock test t2
# MDL_SHARED_READ MDL_EXPLICIT Table metadata lock test t2
# MDL_INTENTION_EXCLUSIVE MDL_EXPLICIT Schema metadata lock test
drop table t1;
drop table t1;
unlock tables;
unlock tables;
#
#
...
...
sql/mdl.cc
View file @
5c6aa4de
...
@@ -17,7 +17,7 @@
...
@@ -17,7 +17,7 @@
#include "sql_class.h"
#include "sql_class.h"
#include "debug_sync.h"
#include "debug_sync.h"
#include "sql_array.h"
#include "sql_array.h"
#include <
hash
.h>
#include <
lf
.h>
#include <mysqld_error.h>
#include <mysqld_error.h>
#include <mysql/plugin.h>
#include <mysql/plugin.h>
#include <mysql/service_thd_wait.h>
#include <mysql/service_thd_wait.h>
...
@@ -26,12 +26,10 @@
...
@@ -26,12 +26,10 @@
#include "wsrep_thd.h"
#include "wsrep_thd.h"
#ifdef HAVE_PSI_INTERFACE
#ifdef HAVE_PSI_INTERFACE
static
PSI_mutex_key
key_MDL_map_mutex
;
static
PSI_mutex_key
key_MDL_wait_LOCK_wait_status
;
static
PSI_mutex_key
key_MDL_wait_LOCK_wait_status
;
static
PSI_mutex_info
all_mdl_mutexes
[]
=
static
PSI_mutex_info
all_mdl_mutexes
[]
=
{
{
{
&
key_MDL_map_mutex
,
"MDL_map::mutex"
,
0
},
{
&
key_MDL_wait_LOCK_wait_status
,
"MDL_wait::LOCK_wait_status"
,
0
}
{
&
key_MDL_wait_LOCK_wait_status
,
"MDL_wait::LOCK_wait_status"
,
0
}
};
};
...
@@ -121,15 +119,12 @@ class MDL_map
...
@@ -121,15 +119,12 @@ class MDL_map
public:
public:
void
init
();
void
init
();
void
destroy
();
void
destroy
();
MDL_lock
*
find_or_insert
(
const
MDL_key
*
key
);
MDL_lock
*
find_or_insert
(
LF_PINS
*
pins
,
const
MDL_key
*
key
);
unsigned
long
get_lock_owner
(
const
MDL_key
*
key
);
unsigned
long
get_lock_owner
(
LF_PINS
*
pins
,
const
MDL_key
*
key
);
void
remove
(
MDL_lock
*
lock
);
void
remove
(
LF_PINS
*
pins
,
MDL_lock
*
lock
);
LF_PINS
*
get_pins
()
{
return
lf_hash_get_pins
(
&
m_locks
);
}
private:
private:
bool
move_from_hash_to_lock_mutex
(
MDL_lock
*
lock
);
LF_HASH
m_locks
;
/**< All acquired locks in the server. */
/** 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. */
/** Pre-allocated MDL_lock object for GLOBAL namespace. */
MDL_lock
*
m_global_lock
;
MDL_lock
*
m_global_lock
;
/** Pre-allocated MDL_lock object for COMMIT namespace. */
/** Pre-allocated MDL_lock object for COMMIT namespace. */
...
@@ -479,7 +474,8 @@ public:
...
@@ -479,7 +474,8 @@ public:
void
reschedule_waiters
();
void
reschedule_waiters
();
void
remove_ticket
(
Ticket_list
MDL_lock
::*
queue
,
MDL_ticket
*
ticket
);
void
remove_ticket
(
LF_PINS
*
pins
,
Ticket_list
MDL_lock
::*
queue
,
MDL_ticket
*
ticket
);
bool
visit_subgraph
(
MDL_ticket
*
waiting_ticket
,
bool
visit_subgraph
(
MDL_ticket
*
waiting_ticket
,
MDL_wait_for_graph_visitor
*
gvisitor
);
MDL_wait_for_graph_visitor
*
gvisitor
);
...
@@ -520,36 +516,44 @@ public:
...
@@ -520,36 +516,44 @@ public:
public:
public:
MDL_lock
()
:
m_hog_lock_count
(
0
),
m_strategy
(
0
)
{
mysql_prlock_init
(
key_MDL_lock_rwlock
,
&
m_rwlock
);
}
MDL_lock
(
const
MDL_key
*
key_arg
)
MDL_lock
(
const
MDL_key
*
key_arg
)
:
key
(
key_arg
),
:
key
(
key_arg
),
m_hog_lock_count
(
0
),
m_hog_lock_count
(
0
),
m_st
ate
(
0
)
m_st
rategy
(
&
m_scoped_lock_strategy
)
{
{
DBUG_ASSERT
(
key_arg
->
mdl_namespace
()
==
MDL_key
::
GLOBAL
||
key_arg
->
mdl_namespace
()
==
MDL_key
::
COMMIT
);
mysql_prlock_init
(
key_MDL_lock_rwlock
,
&
m_rwlock
);
mysql_prlock_init
(
key_MDL_lock_rwlock
,
&
m_rwlock
);
switch
(
key_arg
->
mdl_namespace
())
{
case
MDL_key
:
:
GLOBAL
:
case
MDL_key
:
:
SCHEMA
:
case
MDL_key
:
:
COMMIT
:
m_strategy
=
&
m_scoped_lock_strategy
;
break
;
default:
m_strategy
=
&
m_object_lock_strategy
;
}
}
}
virtual
~
MDL_lock
()
~
MDL_lock
()
{
mysql_prlock_destroy
(
&
m_rwlock
);
}
static
void
lf_alloc_constructor
(
uchar
*
arg
)
{
new
(
arg
+
LF_HASH_OVERHEAD
)
MDL_lock
();
}
static
void
lf_alloc_destructor
(
uchar
*
arg
)
{
((
MDL_lock
*
)(
arg
+
LF_HASH_OVERHEAD
))
->~
MDL_lock
();
}
static
void
lf_hash_initializer
(
LF_HASH
*
hash
__attribute__
((
unused
)),
MDL_lock
*
lock
,
MDL_key
*
key_arg
)
{
{
mysql_prlock_destroy
(
&
m_rwlock
);
DBUG_ASSERT
(
key_arg
->
mdl_namespace
()
!=
MDL_key
::
GLOBAL
&&
key_arg
->
mdl_namespace
()
!=
MDL_key
::
COMMIT
);
new
(
&
lock
->
key
)
MDL_key
(
key_arg
);
if
(
key_arg
->
mdl_namespace
()
==
MDL_key
::
SCHEMA
)
lock
->
m_strategy
=
&
m_scoped_lock_strategy
;
else
lock
->
m_strategy
=
&
m_object_lock_strategy
;
}
}
/**
Lock state: first 31 bits are reference counter, 32-nd bit is deleted flag.
*/
static
const
int32
DELETED
=
1
<<
31
;
int32
m_state
;
private:
const
MDL_lock_strategy
*
m_strategy
;
const
MDL_lock_strategy
*
m_strategy
;
private:
static
const
MDL_scoped_lock
m_scoped_lock_strategy
;
static
const
MDL_scoped_lock
m_scoped_lock_strategy
;
static
const
MDL_object_lock
m_object_lock_strategy
;
static
const
MDL_object_lock
m_object_lock_strategy
;
};
};
...
@@ -616,65 +620,45 @@ void mdl_destroy()
...
@@ -616,65 +620,45 @@ void mdl_destroy()
}
}
static
inline
int
mdl_iterate_lock
(
MDL_lock
*
lock
,
struct
mdl_iterate_arg
int
(
*
callback
)(
MDL_ticket
*
ticket
,
void
*
arg
),
{
void
*
arg
)
int
(
*
callback
)(
MDL_ticket
*
ticket
,
void
*
arg
);
void
*
argument
;
};
static
my_bool
mdl_iterate_lock
(
MDL_lock
*
lock
,
mdl_iterate_arg
*
arg
)
{
{
int
res
=
FALSE
;
/*
We can skip check for m_strategy here, becase m_granted
must be empty for such locks anyway.
*/
mysql_prlock_rdlock
(
&
lock
->
m_rwlock
);
MDL_lock
::
Ticket_iterator
ticket_it
(
lock
->
m_granted
);
MDL_lock
::
Ticket_iterator
ticket_it
(
lock
->
m_granted
);
MDL_ticket
*
ticket
;
MDL_ticket
*
ticket
;
int
res
=
0
;
while
((
ticket
=
ticket_it
++
)
&&
!
(
res
=
arg
->
callback
(
ticket
,
arg
->
argument
)))
mysql_prlock_rdlock
(
&
lock
->
m_rwlock
);
/* no-op */
;
while
((
ticket
=
ticket_it
++
)
&&
!
(
res
=
callback
(
ticket
,
arg
)))
/* no-op */
;
mysql_prlock_unlock
(
&
lock
->
m_rwlock
);
mysql_prlock_unlock
(
&
lock
->
m_rwlock
);
return
res
;
return
MY_TEST
(
res
)
;
}
}
int
mdl_iterate
(
int
(
*
callback
)(
MDL_ticket
*
ticket
,
void
*
arg
),
void
*
arg
)
int
mdl_iterate
(
int
(
*
callback
)(
MDL_ticket
*
ticket
,
void
*
arg
),
void
*
arg
)
{
{
DYNAMIC_ARRAY
locks
;
uint
i
;
int
res
;
DBUG_ENTER
(
"mdl_iterate"
);
DBUG_ENTER
(
"mdl_iterate"
);
mdl_iterate_arg
argument
=
{
callback
,
arg
};
LF_PINS
*
pins
=
mdl_locks
.
get_pins
();
int
res
=
1
;
if
((
res
=
mdl_iterate_lock
(
mdl_locks
.
m_global_lock
,
callback
,
arg
))
||
if
(
pins
)
(
res
=
mdl_iterate_lock
(
mdl_locks
.
m_commit_lock
,
callback
,
arg
)))
DBUG_RETURN
(
res
);
my_init_dynamic_array
(
&
locks
,
sizeof
(
MDL_lock
*
),
512
,
1
,
MYF
(
0
));
/* Collect all locks first */
mysql_mutex_lock
(
&
mdl_locks
.
m_mutex
);
if
(
allocate_dynamic
(
&
locks
,
mdl_locks
.
m_locks
.
records
))
{
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
);
my_atomic_add32_explicit
(
&
lock
->
m_state
,
1
,
MY_MEMORY_ORDER_RELAXED
);
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
(
mdl_locks
.
m_global_lock
,
&
argument
)
||
res
|=
mdl_iterate_lock
(
lock
,
callback
,
arg
);
mdl_iterate_lock
(
mdl_locks
.
m_commit_lock
,
&
argument
)
||
lf_hash_iterate
(
&
mdl_locks
.
m_locks
,
pins
,
mysql_prlock_wrlock
(
&
lock
->
m_rwlock
);
(
my_hash_walk_action
)
mdl_iterate_lock
,
&
argument
);
int32
old_state
=
my_atomic_add32_explicit
(
&
lock
->
m_state
,
-
1
,
lf_hash_put_pins
(
pins
);
MY_MEMORY_ORDER_RELAXED
);
mysql_prlock_unlock
(
&
lock
->
m_rwlock
);
if
(
unlikely
(
old_state
==
MDL_lock
::
DELETED
+
1
))
delete
lock
;
}
}
end:
delete_dynamic
(
&
locks
);
DBUG_RETURN
(
res
);
DBUG_RETURN
(
res
);
}
}
...
@@ -697,9 +681,12 @@ void MDL_map::init()
...
@@ -697,9 +681,12 @@ void MDL_map::init()
m_global_lock
=
new
(
std
::
nothrow
)
MDL_lock
(
&
global_lock_key
);
m_global_lock
=
new
(
std
::
nothrow
)
MDL_lock
(
&
global_lock_key
);
m_commit_lock
=
new
(
std
::
nothrow
)
MDL_lock
(
&
commit_lock_key
);
m_commit_lock
=
new
(
std
::
nothrow
)
MDL_lock
(
&
commit_lock_key
);
mysql_mutex_init
(
key_MDL_map_mutex
,
&
m_mutex
,
NULL
);
lf_hash_init
(
&
m_locks
,
sizeof
(
MDL_lock
),
LF_HASH_UNIQUE
,
0
,
0
,
my_hash_init2
(
&
m_locks
,
0
,
&
my_charset_bin
,
16
/* FIXME */
,
0
,
0
,
mdl_locks_key
,
&
my_charset_bin
);
mdl_locks_key
,
mdl_hash_function
,
0
,
0
);
m_locks
.
alloc
.
constructor
=
MDL_lock
::
lf_alloc_constructor
;
m_locks
.
alloc
.
destructor
=
MDL_lock
::
lf_alloc_destructor
;
m_locks
.
initializer
=
(
lf_hash_initializer
)
MDL_lock
::
lf_hash_initializer
;
m_locks
.
hash_function
=
mdl_hash_function
;
}
}
...
@@ -713,9 +700,8 @@ void MDL_map::destroy()
...
@@ -713,9 +700,8 @@ void MDL_map::destroy()
delete
m_global_lock
;
delete
m_global_lock
;
delete
m_commit_lock
;
delete
m_commit_lock
;
DBUG_ASSERT
(
!
m_locks
.
records
);
DBUG_ASSERT
(
!
my_atomic_load32
(
&
m_locks
.
count
));
mysql_mutex_destroy
(
&
m_mutex
);
lf_hash_destroy
(
&
m_locks
);
my_hash_free
(
&
m_locks
);
}
}
...
@@ -728,7 +714,7 @@ void MDL_map::destroy()
...
@@ -728,7 +714,7 @@ void MDL_map::destroy()
@retval NULL - Failure (OOM).
@retval NULL - Failure (OOM).
*/
*/
MDL_lock
*
MDL_map
::
find_or_insert
(
const
MDL_key
*
mdl_key
)
MDL_lock
*
MDL_map
::
find_or_insert
(
LF_PINS
*
pins
,
const
MDL_key
*
mdl_key
)
{
{
MDL_lock
*
lock
;
MDL_lock
*
lock
;
...
@@ -755,64 +741,21 @@ MDL_lock* MDL_map::find_or_insert(const MDL_key *mdl_key)
...
@@ -755,64 +741,21 @@ MDL_lock* MDL_map::find_or_insert(const MDL_key *mdl_key)
}
}
retry:
retry:
mysql_mutex_lock
(
&
m_mutex
);
while
(
!
(
lock
=
(
MDL_lock
*
)
lf_hash_search_using_hash_value
(
&
m_locks
,
pins
,
if
(
!
(
lock
=
(
MDL_lock
*
)
my_hash_search_using_hash_value
(
&
m_locks
,
mdl_key
->
hash_value
(),
mdl_key
->
ptr
(),
mdl_key
->
length
())))
mdl_key
->
hash_value
(),
if
(
lf_hash_insert
(
&
m_locks
,
pins
,
(
uchar
*
)
mdl_key
)
==
-
1
)
mdl_key
->
ptr
(),
mdl_key
->
length
())))
{
/* No lock object found so we need to create a new one. */
lock
=
new
(
std
::
nothrow
)
MDL_lock
(
mdl_key
);
if
(
!
lock
||
my_hash_insert
(
&
m_locks
,
(
uchar
*
)
lock
))
{
delete
lock
;
mysql_mutex_unlock
(
&
m_mutex
);
return
NULL
;
return
NULL
;
}
}
if
(
move_from_hash_to_lock_mutex
(
lock
))
goto
retry
;
return
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.
@retval FALSE - Success.
@retval TRUE - Object was released while we held no mutex, caller
should re-try looking up MDL_lock object in the hash.
*/
bool
MDL_map
::
move_from_hash_to_lock_mutex
(
MDL_lock
*
lock
)
{
DBUG_ASSERT
(
!
(
my_atomic_load32
(
&
lock
->
m_state
)
&
MDL_lock
::
DELETED
));
mysql_mutex_assert_owner
(
&
m_mutex
);
my_atomic_add32_explicit
(
&
lock
->
m_state
,
1
,
MY_MEMORY_ORDER_RELAXED
);
mysql_mutex_unlock
(
&
m_mutex
);
mysql_prlock_wrlock
(
&
lock
->
m_rwlock
);
mysql_prlock_wrlock
(
&
lock
->
m_rwlock
);
int32
old_state
=
my_atomic_add32_explicit
(
&
lock
->
m_state
,
-
1
,
if
(
unlikely
(
!
lock
->
m_strategy
))
MY_MEMORY_ORDER_RELAXED
);
if
(
unlikely
(
old_state
&
MDL_lock
::
DELETED
))
{
{
/*
Object was released while we held no locks, we need to
release it if no others hold references to it, while our own
reference count ensured that the object as such haven't got
its memory released yet.
*/
mysql_prlock_unlock
(
&
lock
->
m_rwlock
);
mysql_prlock_unlock
(
&
lock
->
m_rwlock
);
if
(
old_state
==
MDL_lock
::
DELETED
+
1
)
lf_hash_search_unpin
(
pins
);
delete
lock
;
goto
retry
;
return
TRUE
;
}
}
return
FALSE
;
lf_hash_search_unpin
(
pins
);
return
lock
;
}
}
...
@@ -821,7 +764,7 @@ bool MDL_map::move_from_hash_to_lock_mutex(MDL_lock *lock)
...
@@ -821,7 +764,7 @@ bool MDL_map::move_from_hash_to_lock_mutex(MDL_lock *lock)
*/
*/
unsigned
long
unsigned
long
MDL_map
::
get_lock_owner
(
const
MDL_key
*
mdl_key
)
MDL_map
::
get_lock_owner
(
LF_PINS
*
pins
,
const
MDL_key
*
mdl_key
)
{
{
MDL_lock
*
lock
;
MDL_lock
*
lock
;
unsigned
long
res
=
0
;
unsigned
long
res
=
0
;
...
@@ -837,14 +780,21 @@ MDL_map::get_lock_owner(const MDL_key *mdl_key)
...
@@ -837,14 +780,21 @@ MDL_map::get_lock_owner(const MDL_key *mdl_key)
}
}
else
else
{
{
mysql_mutex_lock
(
&
m_mutex
);
lock
=
(
MDL_lock
*
)
lf_hash_search_using_hash_value
(
&
m_locks
,
pins
,
lock
=
(
MDL_lock
*
)
my_hash_search_using_hash_value
(
&
m_locks
,
mdl_key
->
hash_value
(),
mdl_key
->
hash_value
(),
mdl_key
->
ptr
(),
mdl_key
->
ptr
(),
mdl_key
->
length
());
mdl_key
->
length
());
if
(
lock
)
if
(
lock
)
{
/*
We can skip check for m_strategy here, becase m_granted
must be empty for such locks anyway.
*/
mysql_prlock_rdlock
(
&
lock
->
m_rwlock
);
res
=
lock
->
get_lock_owner
();
res
=
lock
->
get_lock_owner
();
mysql_mutex_unlock
(
&
m_mutex
);
mysql_prlock_unlock
(
&
lock
->
m_rwlock
);
lf_hash_search_unpin
(
pins
);
}
}
}
return
res
;
return
res
;
}
}
...
@@ -856,7 +806,7 @@ MDL_map::get_lock_owner(const MDL_key *mdl_key)
...
@@ -856,7 +806,7 @@ MDL_map::get_lock_owner(const MDL_key *mdl_key)
it.
it.
*/
*/
void
MDL_map
::
remove
(
MDL_lock
*
lock
)
void
MDL_map
::
remove
(
LF_PINS
*
pins
,
MDL_lock
*
lock
)
{
{
if
(
lock
->
key
.
mdl_namespace
()
==
MDL_key
::
GLOBAL
||
if
(
lock
->
key
.
mdl_namespace
()
==
MDL_key
::
GLOBAL
||
lock
->
key
.
mdl_namespace
()
==
MDL_key
::
COMMIT
)
lock
->
key
.
mdl_namespace
()
==
MDL_key
::
COMMIT
)
...
@@ -869,20 +819,9 @@ void MDL_map::remove(MDL_lock *lock)
...
@@ -869,20 +819,9 @@ void MDL_map::remove(MDL_lock *lock)
return
;
return
;
}
}
mysql_mutex_lock
(
&
m_mutex
);
lock
->
m_strategy
=
0
;
my_hash_delete
(
&
m_locks
,
(
uchar
*
)
lock
);
/*
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.
*/
int32
old_state
=
my_atomic_add32_explicit
(
&
lock
->
m_state
,
MDL_lock
::
DELETED
,
MY_MEMORY_ORDER_RELAXED
);
mysql_mutex_unlock
(
&
m_mutex
);
mysql_prlock_unlock
(
&
lock
->
m_rwlock
);
mysql_prlock_unlock
(
&
lock
->
m_rwlock
);
if
(
!
old_state
)
lf_hash_delete
(
&
m_locks
,
pins
,
lock
->
key
.
ptr
(),
lock
->
key
.
length
());
delete
lock
;
}
}
...
@@ -896,7 +835,8 @@ MDL_context::MDL_context()
...
@@ -896,7 +835,8 @@ MDL_context::MDL_context()
:
:
m_owner
(
NULL
),
m_owner
(
NULL
),
m_needs_thr_lock_abort
(
FALSE
),
m_needs_thr_lock_abort
(
FALSE
),
m_waiting_for
(
NULL
)
m_waiting_for
(
NULL
),
m_pins
(
NULL
)
{
{
mysql_prlock_init
(
key_MDL_context_LOCK_waiting_for
,
&
m_LOCK_waiting_for
);
mysql_prlock_init
(
key_MDL_context_LOCK_waiting_for
,
&
m_LOCK_waiting_for
);
}
}
...
@@ -921,6 +861,14 @@ void MDL_context::destroy()
...
@@ -921,6 +861,14 @@ void MDL_context::destroy()
DBUG_ASSERT
(
m_tickets
[
MDL_EXPLICIT
].
is_empty
());
DBUG_ASSERT
(
m_tickets
[
MDL_EXPLICIT
].
is_empty
());
mysql_prlock_destroy
(
&
m_LOCK_waiting_for
);
mysql_prlock_destroy
(
&
m_LOCK_waiting_for
);
if
(
m_pins
)
lf_hash_put_pins
(
m_pins
);
}
bool
MDL_context
::
fix_pins
()
{
return
m_pins
?
false
:
(
m_pins
=
mdl_locks
.
get_pins
())
==
0
;
}
}
...
@@ -1660,12 +1608,13 @@ MDL_lock::get_lock_owner() const
...
@@ -1660,12 +1608,13 @@ MDL_lock::get_lock_owner() const
/** Remove a ticket from waiting or pending queue and wakeup up waiters. */
/** Remove a ticket from waiting or pending queue and wakeup up waiters. */
void
MDL_lock
::
remove_ticket
(
Ticket_list
MDL_lock
::*
list
,
MDL_ticket
*
ticket
)
void
MDL_lock
::
remove_ticket
(
LF_PINS
*
pins
,
Ticket_list
MDL_lock
::*
list
,
MDL_ticket
*
ticket
)
{
{
mysql_prlock_wrlock
(
&
m_rwlock
);
mysql_prlock_wrlock
(
&
m_rwlock
);
(
this
->*
list
).
remove_ticket
(
ticket
);
(
this
->*
list
).
remove_ticket
(
ticket
);
if
(
is_empty
())
if
(
is_empty
())
mdl_locks
.
remove
(
this
);
mdl_locks
.
remove
(
pins
,
this
);
else
else
{
{
/*
/*
...
@@ -1913,6 +1862,9 @@ MDL_context::try_acquire_lock_impl(MDL_request *mdl_request,
...
@@ -1913,6 +1862,9 @@ MDL_context::try_acquire_lock_impl(MDL_request *mdl_request,
return
FALSE
;
return
FALSE
;
}
}
if
(
fix_pins
())
return
TRUE
;
if
(
!
(
ticket
=
MDL_ticket
::
create
(
this
,
mdl_request
->
type
if
(
!
(
ticket
=
MDL_ticket
::
create
(
this
,
mdl_request
->
type
#ifndef DBUG_OFF
#ifndef DBUG_OFF
,
mdl_request
->
duration
,
mdl_request
->
duration
...
@@ -1921,7 +1873,7 @@ MDL_context::try_acquire_lock_impl(MDL_request *mdl_request,
...
@@ -1921,7 +1873,7 @@ MDL_context::try_acquire_lock_impl(MDL_request *mdl_request,
return
TRUE
;
return
TRUE
;
/* The below call implicitly locks MDL_lock::m_rwlock on success. */
/* The below call implicitly locks MDL_lock::m_rwlock on success. */
if
(
!
(
lock
=
mdl_locks
.
find_or_insert
(
key
)))
if
(
!
(
lock
=
mdl_locks
.
find_or_insert
(
m_pins
,
key
)))
{
{
MDL_ticket
::
destroy
(
ticket
);
MDL_ticket
::
destroy
(
ticket
);
return
TRUE
;
return
TRUE
;
...
@@ -1964,6 +1916,17 @@ MDL_context::clone_ticket(MDL_request *mdl_request)
...
@@ -1964,6 +1916,17 @@ MDL_context::clone_ticket(MDL_request *mdl_request)
{
{
MDL_ticket
*
ticket
;
MDL_ticket
*
ticket
;
/*
Since in theory we can clone ticket belonging to a different context
we need to prepare target context for possible attempts to release
lock and thus possible removal of MDL_lock from MDL_map container.
So we allocate pins to be able to work with this container if they
are not allocated already.
*/
if
(
fix_pins
())
return
TRUE
;
/*
/*
By submitting mdl_request->type to MDL_ticket::create()
By submitting mdl_request->type to MDL_ticket::create()
we effectively downgrade the cloned lock to the level of
we effectively downgrade the cloned lock to the level of
...
@@ -2103,7 +2066,7 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout)
...
@@ -2103,7 +2066,7 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout)
if
(
wait_status
!=
MDL_wait
::
GRANTED
)
if
(
wait_status
!=
MDL_wait
::
GRANTED
)
{
{
lock
->
remove_ticket
(
&
MDL_lock
::
m_waiting
,
ticket
);
lock
->
remove_ticket
(
m_pins
,
&
MDL_lock
::
m_waiting
,
ticket
);
MDL_ticket
::
destroy
(
ticket
);
MDL_ticket
::
destroy
(
ticket
);
switch
(
wait_status
)
switch
(
wait_status
)
{
{
...
@@ -2560,7 +2523,7 @@ void MDL_context::release_lock(enum_mdl_duration duration, MDL_ticket *ticket)
...
@@ -2560,7 +2523,7 @@ void MDL_context::release_lock(enum_mdl_duration duration, MDL_ticket *ticket)
DBUG_ASSERT
(
this
==
ticket
->
get_ctx
());
DBUG_ASSERT
(
this
==
ticket
->
get_ctx
());
lock
->
remove_ticket
(
&
MDL_lock
::
m_granted
,
ticket
);
lock
->
remove_ticket
(
m_pins
,
&
MDL_lock
::
m_granted
,
ticket
);
m_tickets
[
duration
].
remove
(
ticket
);
m_tickets
[
duration
].
remove
(
ticket
);
MDL_ticket
::
destroy
(
ticket
);
MDL_ticket
::
destroy
(
ticket
);
...
@@ -2721,7 +2684,8 @@ MDL_context::is_lock_owner(MDL_key::enum_mdl_namespace mdl_namespace,
...
@@ -2721,7 +2684,8 @@ MDL_context::is_lock_owner(MDL_key::enum_mdl_namespace mdl_namespace,
unsigned
long
unsigned
long
MDL_context
::
get_lock_owner
(
MDL_key
*
key
)
MDL_context
::
get_lock_owner
(
MDL_key
*
key
)
{
{
return
mdl_locks
.
get_lock_owner
(
key
);
fix_pins
();
return
mdl_locks
.
get_lock_owner
(
m_pins
,
key
);
}
}
...
...
sql/mdl.h
View file @
5c6aa4de
...
@@ -28,7 +28,7 @@
...
@@ -28,7 +28,7 @@
#include <my_sys.h>
#include <my_sys.h>
#include <m_string.h>
#include <m_string.h>
#include <mysql_com.h>
#include <mysql_com.h>
#include <
hash
.h>
#include <
lf
.h>
#include <algorithm>
#include <algorithm>
...
@@ -917,6 +917,7 @@ private:
...
@@ -917,6 +917,7 @@ private:
readily available to the wait-for graph iterator.
readily available to the wait-for graph iterator.
*/
*/
MDL_wait_for_subgraph
*
m_waiting_for
;
MDL_wait_for_subgraph
*
m_waiting_for
;
LF_PINS
*
m_pins
;
private:
private:
MDL_ticket
*
find_ticket
(
MDL_request
*
mdl_req
,
MDL_ticket
*
find_ticket
(
MDL_request
*
mdl_req
,
enum_mdl_duration
*
duration
);
enum_mdl_duration
*
duration
);
...
@@ -924,6 +925,7 @@ private:
...
@@ -924,6 +925,7 @@ private:
void
release_lock
(
enum_mdl_duration
duration
,
MDL_ticket
*
ticket
);
void
release_lock
(
enum_mdl_duration
duration
,
MDL_ticket
*
ticket
);
bool
try_acquire_lock_impl
(
MDL_request
*
mdl_request
,
bool
try_acquire_lock_impl
(
MDL_request
*
mdl_request
,
MDL_ticket
**
out_ticket
);
MDL_ticket
**
out_ticket
);
bool
fix_pins
();
public:
public:
THD
*
get_thd
()
const
{
return
m_owner
->
get_thd
();
}
THD
*
get_thd
()
const
{
return
m_owner
->
get_thd
();
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment