Skip to content

Commit 70bb617

Browse files
AliSQLAliSQL
authored andcommitted
[Perf] Issue#21 SPLIT LOCK_GRANT LOCK
Description: ------------ LOCK_grant is a rwlock: wrlock when modify privileges rdlock when check privileges The fact is that we usually check priv at most scenarios, but has serious conflict. Solution: --------- So we split the LOCK_grant into an array of rwlock: Require one rdlock when checking priv through thread_id % array_size. Require all wrlock when modify priv. It will decrease the rdlock conflict substantially.
1 parent 83d64d9 commit 70bb617

4 files changed

Lines changed: 257 additions & 54 deletions

File tree

sql/mysqld.cc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ mysql_mutex_t LOCK_log_throttle_qni;
742742
#ifdef HAVE_OPENSSL
743743
mysql_mutex_t LOCK_des_key_file;
744744
#endif
745-
mysql_rwlock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
745+
mysql_rwlock_t LOCK_sys_init_connect, LOCK_sys_init_slave;
746746
mysql_rwlock_t LOCK_system_variables_hash;
747747
mysql_cond_t COND_thread_count;
748748
pthread_t signal_thread;
@@ -1993,7 +1993,6 @@ static void wait_for_signal_thread_to_end()
19931993

19941994
static void clean_up_mutexes()
19951995
{
1996-
mysql_rwlock_destroy(&LOCK_grant);
19971996
mysql_mutex_destroy(&LOCK_thread_created);
19981997
mysql_mutex_destroy(&LOCK_thread_count);
19991998
mysql_mutex_destroy(&LOCK_log_throttle_qni);
@@ -4304,7 +4303,6 @@ static int init_thread_environment()
43044303
#endif
43054304
mysql_rwlock_init(key_rwlock_LOCK_sys_init_connect, &LOCK_sys_init_connect);
43064305
mysql_rwlock_init(key_rwlock_LOCK_sys_init_slave, &LOCK_sys_init_slave);
4307-
mysql_rwlock_init(key_rwlock_LOCK_grant, &LOCK_grant);
43084306
mysql_cond_init(key_COND_thread_count, &COND_thread_count, NULL);
43094307
mysql_cond_init(key_COND_connection_count, &COND_connection_count, NULL);
43104308
mysql_cond_init(key_COND_thread_cache, &COND_thread_cache, NULL);

sql/mysqld.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ extern mysql_mutex_t LOCK_des_key_file;
734734
#endif
735735
extern mysql_mutex_t LOCK_server_started;
736736
extern mysql_cond_t COND_server_started;
737-
extern mysql_rwlock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
737+
extern mysql_rwlock_t LOCK_sys_init_connect, LOCK_sys_init_slave;
738738
extern mysql_rwlock_t LOCK_system_variables_hash;
739739
extern mysql_cond_t COND_manager;
740740
extern int32 thread_running;

sql/partitioned_rwlock.h

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
#ifndef PARTITIONED_RWLOCK_INCLUDED
2+
#define PARTITIONED_RWLOCK_INCLUDED
3+
4+
/* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
5+
6+
This program is free software; you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation; version 2 of the License.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
18+
19+
#include "mysql/psi/mysql_thread.h"
20+
/**
21+
Implementation of read-write lock partitioned by thread id.
22+
23+
This rwlock provides better scalability in read-heavy environments by
24+
employing the following simple trick:
25+
*) Read lock is acquired only on one of its partitions. The specific
26+
partition is chosen according to thread id.
27+
*) Write lock is acquired on all partitions.
28+
29+
This way concurrent request for read lock made by different threads have
30+
a good chance not to disturb each other by doing cache invalidattion and
31+
atomic operations. As result scalability in this scenario improves. OTOH
32+
acquisition of write lock becomes more expensive. So this rwlock is not
33+
supposed to be used in cases when number of write requests is significant.
34+
*/
35+
36+
class Partitioned_rwlock
37+
{
38+
public:
39+
Partitioned_rwlock(){}
40+
41+
/**
42+
@param parts Number of partitions.
43+
@param psi_key P_S instrumentation key to use for rwlock instances
44+
for partitions.
45+
*/
46+
bool init(uint parts, PSI_rwlock_key psi_key)
47+
{
48+
m_parts= parts;
49+
if (!(m_locks_array= new (std::nothrow) mysql_rwlock_t[m_parts]))
50+
return true;
51+
52+
for (uint i= 0; i < m_parts; i++)
53+
mysql_rwlock_init(psi_key, &m_locks_array[i]);
54+
55+
return false;
56+
}
57+
58+
void destroy()
59+
{
60+
for (uint i= 0; i < m_parts; i++)
61+
mysql_rwlock_destroy(&m_locks_array[i]);
62+
63+
delete [] m_locks_array;
64+
}
65+
66+
void wrlock()
67+
{
68+
for (uint i= 0; i < m_parts; i++)
69+
mysql_rwlock_wrlock(&m_locks_array[i]);
70+
}
71+
void wrunlock()
72+
{
73+
for (uint i= 0; i < m_parts; i++)
74+
mysql_rwlock_unlock(&m_locks_array[i]);
75+
}
76+
void rdlock(uint thread_id)
77+
{
78+
mysql_rwlock_rdlock(&m_locks_array[thread_id%m_parts]);
79+
}
80+
void rdunlock(uint thread_id)
81+
{
82+
mysql_rwlock_unlock(&m_locks_array[thread_id%m_parts]);
83+
}
84+
85+
private:
86+
mysql_rwlock_t* m_locks_array;
87+
uint m_parts;
88+
89+
Partitioned_rwlock(const Partitioned_rwlock&);
90+
91+
Partitioned_rwlock& operator=(const Partitioned_rwlock&);
92+
93+
};
94+
95+
/**
96+
Read lock guard class for Partitioned_rwlock, Supports early unlocking.
97+
*/
98+
99+
class Partitioned_rwlock_read_guard
100+
{
101+
public:
102+
/**
103+
Acquires read lock on partitoned rwlock on behalf of thread.
104+
Automatically release lock in destructor.
105+
*/
106+
Partitioned_rwlock_read_guard(Partitioned_rwlock *rwlock, uint thread_id)
107+
: m_rwlock(rwlock), m_thread_id(thread_id)
108+
{
109+
m_rwlock->rdlock(m_thread_id);
110+
}
111+
112+
~Partitioned_rwlock_read_guard()
113+
{
114+
if (m_rwlock)
115+
m_rwlock->rdunlock(m_thread_id);
116+
}
117+
118+
/** Release read lock. Optional method for early unlocking. */
119+
void unlock()
120+
{
121+
m_rwlock->rdunlock(m_thread_id);
122+
m_rwlock= NULL;
123+
}
124+
125+
private:
126+
/**
127+
Pointer to the Partitioned rwlock which was acquired. NULL if lock was
128+
released early so destructor should not do anything.
129+
*/
130+
Partitioned_rwlock *m_rwlock;
131+
132+
/**
133+
Id of thread on which behalf lock was acquired and which is to be used for
134+
unlocking.
135+
*/
136+
uint m_thread_id;
137+
138+
// Non-copyable
139+
Partitioned_rwlock_read_guard(const Partitioned_rwlock_read_guard&);
140+
Partitioned_rwlock_read_guard& operator=(const
141+
Partitioned_rwlock_read_guard&);
142+
};
143+
144+
/**
145+
Write lock guard class for Partitioned_rwlock. Supports early unlocking.
146+
*/
147+
148+
class Partitioned_rwlock_write_guard
149+
{
150+
public:
151+
/**
152+
Acquires write lock on partitioned rwlock.
153+
Automatically release it in destructor.
154+
*/
155+
explicit Partitioned_rwlock_write_guard(Partitioned_rwlock *rwlock)
156+
: m_rwlock(rwlock)
157+
{
158+
m_rwlock->wrlock();
159+
}
160+
161+
~Partitioned_rwlock_write_guard()
162+
{
163+
if (m_rwlock)
164+
m_rwlock->wrunlock();
165+
}
166+
167+
/** Release write lock. Optional method for early unlocking. */
168+
void unlock()
169+
{
170+
m_rwlock->wrunlock();
171+
m_rwlock= NULL;
172+
}
173+
174+
private:
175+
/**
176+
Pointer to Partitioned_rwlock which was acquired. NULL if lock was
177+
released early so destructor should not do anything.
178+
*/
179+
Partitioned_rwlock *m_rwlock;
180+
181+
// Non-copyable
182+
Partitioned_rwlock_write_guard(const Partitioned_rwlock_write_guard&);
183+
Partitioned_rwlock_write_guard& operator=(const
184+
Partitioned_rwlock_write_guard&);
185+
};
186+
187+
#endif /* PARTITIONED_RWLOCK_INCLUDED */

0 commit comments

Comments
 (0)