Merge lp:~laurynas-biveinis/percona-server/xtradb-thread-priority-flag into lp:percona-server/5.6

Proposed by Laurynas Biveinis
Status: Merged
Approved by: Alexey Kopytov
Approved revision: no longer in the source branch.
Merged at revision: 435
Proposed branch: lp:~laurynas-biveinis/percona-server/xtradb-thread-priority-flag
Merge into: lp:percona-server/5.6
Diff against target: 4053 lines (+2141/-303)
48 files modified
Percona-Server/mysql-test/suite/sys_vars/r/innodb_priority_cleaner_basic.result (+31/-0)
Percona-Server/mysql-test/suite/sys_vars/r/innodb_priority_io_basic.result (+31/-0)
Percona-Server/mysql-test/suite/sys_vars/r/innodb_priority_master_basic.result (+31/-0)
Percona-Server/mysql-test/suite/sys_vars/r/innodb_priority_purge_basic.result (+31/-0)
Percona-Server/mysql-test/suite/sys_vars/t/innodb_priority_cleaner_basic.test (+40/-0)
Percona-Server/mysql-test/suite/sys_vars/t/innodb_priority_io_basic.test (+40/-0)
Percona-Server/mysql-test/suite/sys_vars/t/innodb_priority_master_basic.test (+40/-0)
Percona-Server/mysql-test/suite/sys_vars/t/innodb_priority_purge_basic.test (+40/-0)
Percona-Server/storage/innobase/btr/btr0sea.cc (+3/-3)
Percona-Server/storage/innobase/buf/buf0buddy.cc (+1/-1)
Percona-Server/storage/innobase/buf/buf0buf.cc (+12/-12)
Percona-Server/storage/innobase/buf/buf0flu.cc (+4/-2)
Percona-Server/storage/innobase/buf/buf0lru.cc (+6/-6)
Percona-Server/storage/innobase/buf/buf0rea.cc (+3/-3)
Percona-Server/storage/innobase/fil/fil0fil.cc (+2/-2)
Percona-Server/storage/innobase/fsp/fsp0fsp.cc (+11/-11)
Percona-Server/storage/innobase/ha/hash0hash.cc (+15/-15)
Percona-Server/storage/innobase/handler/ha_innodb.cc (+31/-0)
Percona-Server/storage/innobase/include/btr0sea.h (+1/-1)
Percona-Server/storage/innobase/include/btr0sea.ic (+1/-1)
Percona-Server/storage/innobase/include/btr0types.h (+1/-1)
Percona-Server/storage/innobase/include/buf0buf.h (+4/-4)
Percona-Server/storage/innobase/include/buf0buf.ic (+4/-4)
Percona-Server/storage/innobase/include/dict0dict.h (+2/-2)
Percona-Server/storage/innobase/include/dict0dict.ic (+1/-1)
Percona-Server/storage/innobase/include/dict0mem.h (+2/-2)
Percona-Server/storage/innobase/include/fil0fil.h (+1/-1)
Percona-Server/storage/innobase/include/ha0ha.ic (+2/-2)
Percona-Server/storage/innobase/include/hash0hash.h (+10/-9)
Percona-Server/storage/innobase/include/hash0hash.ic (+4/-4)
Percona-Server/storage/innobase/include/log0log.h (+1/-1)
Percona-Server/storage/innobase/include/mtr0mtr.h (+3/-3)
Percona-Server/storage/innobase/include/mtr0mtr.ic (+3/-3)
Percona-Server/storage/innobase/include/srv0srv.h (+12/-0)
Percona-Server/storage/innobase/include/sync0rw.h (+350/-70)
Percona-Server/storage/innobase/include/sync0rw.ic (+527/-61)
Percona-Server/storage/innobase/include/sync0sync.h (+187/-0)
Percona-Server/storage/innobase/include/sync0sync.ic (+235/-6)
Percona-Server/storage/innobase/include/sync0types.h (+13/-0)
Percona-Server/storage/innobase/include/trx0purge.h (+1/-1)
Percona-Server/storage/innobase/include/trx0trx.h (+1/-1)
Percona-Server/storage/innobase/include/univ.i (+7/-0)
Percona-Server/storage/innobase/mtr/mtr0mtr.cc (+2/-2)
Percona-Server/storage/innobase/srv/srv0srv.cc (+22/-0)
Percona-Server/storage/innobase/srv/srv0start.cc (+1/-0)
Percona-Server/storage/innobase/sync/sync0arr.cc (+92/-21)
Percona-Server/storage/innobase/sync/sync0rw.cc (+197/-41)
Percona-Server/storage/innobase/sync/sync0sync.cc (+82/-6)
To merge this branch: bzr merge lp:~laurynas-biveinis/percona-server/xtradb-thread-priority-flag
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Approve
Review via email: mp+187773@code.launchpad.net

This proposal supersedes a proposal from 2013-09-20.

Description of the change

2nd MP:

Thread priority flag, priority mutex, priority free list refill, priority rw latch.

Jenkins http://jenkins.percona.com/job/percona-server-5.6-param/313/. All the yellow dots due to an unfortunate forgotten fprintf(stderr), which fails innodb-log-file-size-1. Will of course remove in the next push.

Additionally tested by making sync_arr_wake_threads_if_sema_free() a no-op, in order to catch any missed wake up events.

Thread priority flag changes from the original MP:

    - UNIV_THREAD_LOCAL defined to __thread under UNIV_LINUX instead
      of __GNUC__, and as no-op elsewhere. The original suggestion to define it as
      0 on other platforms was not used because lvalue is needed.
    - The thread-priority setting system variables are exposed only
      under UNIV_LINUX too.

1st MP:

Implement thread priority flag
(https://blueprints.launchpad.net/percona-server/+spec/xtradb-thread-priority-flag)
that would be available for InnoDB threads to check whether they
should acquire some shared resource with priority or no. The actual
uses of this flag will be in follow-up.

This flag srv_current_thread_priority is implemented through
thread-local storage. There were two other alternatives considered
for its implementation.
1. Passing the flag value from the DECLARE_THREAD functions to its use
   sites through the callstacks. But such callstacks would be very
   deep and would require patching dozens of InnoDB functions to
   include this new arg.
2. pthread_setspecific()/pthread_getspecific(). This would have the
   advantage of being slightly more portable than TLS, but it's more
   complicated to use: 1) the flag would have to be allocated in
   heap. 2) pthread_key_create() calls through pthread_once() would
   be necessary, moreover they'd have to be placed in mysys instead of
   InnoDB and any affected non-mysys-initializing threads in InnoDB
   would have to be converted to initialize mysys. 3)
   pthread_getspecific() calls would have to happen in very hot code
   paths, such as mutex locking/unlocking code.

Thus TLS appears to be the best option.

Means to change the flag value for individual InnoDB utility threads
are provided for UNIV_PERF_DEBUG or UNIV_DEBUG builds through the new
global dynamic variables innodb_priority_purge, innodb_priority_io,
innodb_priority_cleaner, innodb_priority_master. Added sys_vars tests
for them.

http://jenkins.percona.com/job/percona-server-5.6-param/281/

To post a comment you must log in.
Revision history for this message
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal

Just make it Linux-specific for now, i.e. so that the system variables only appear in UNIV_LINUX builds, and srv_current_thread_priority is #define'd to 0 otherwise.

Making it truly portable is more complex than just #ifdef __GNUC__, and I will address it later.

But I also don't like reviewing this change in isolation. Please resubmit with the code that actually makes use of srv_current_thread_priority.

review: Needs Resubmitting
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal

Yes, UNIV_LINUX makes more sense than __GNUC__.

Re. isolation. The whole set of changes would be as follows, in the smallest parts:
- This MP.
- Priority mutex implementation.
- Specific buffer pool free list mutex conversion to priority.
- Non-specific mutex conversion to priority: dict_sys, LRU list, rseg, log.
- Priority rwlatch implementation.
- Non-specific rwlatch conversion to priority: fsp, page_hash, AHI, index, purge.

How this should be distributed among MPs? One big one with everything? Are separate commits OK or one big commit too?

Thanks.

Revision history for this message
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal

1 MP, multiple commits should be fine.

Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote :

Repushed. Removed fprintf, and fixed a typo in the last rw_lock_higher_prio_waiters_exist() call in rw_lock_s_lock_spin(), where true was incorrectly passed instead of priority_lock.

Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote :
Revision history for this message
Alexey Kopytov (akopytov) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'Percona-Server/mysql-test/suite/sys_vars/r/innodb_priority_cleaner_basic.result'
2--- Percona-Server/mysql-test/suite/sys_vars/r/innodb_priority_cleaner_basic.result 1970-01-01 00:00:00 +0000
3+++ Percona-Server/mysql-test/suite/sys_vars/r/innodb_priority_cleaner_basic.result 2013-09-26 14:59:13 +0000
4@@ -0,0 +1,31 @@
5+SET @start_value = @@GLOBAL.innodb_priority_cleaner;
6+SELECT @@GLOBAL.innodb_priority_cleaner;
7+@@GLOBAL.innodb_priority_cleaner
8+0
9+SELECT @@SESSION.innodb_priority_cleaner;
10+ERROR HY000: Variable 'innodb_priority_cleaner' is a GLOBAL variable
11+SET GLOBAL innodb_priority_cleaner='OFF';
12+SELECT @@GLOBAL.innodb_priority_cleaner;
13+@@GLOBAL.innodb_priority_cleaner
14+0
15+SET GLOBAL innodb_priority_cleaner='ON';
16+SELECT @@GLOBAL.innodb_priority_cleaner;
17+@@GLOBAL.innodb_priority_cleaner
18+1
19+SET GLOBAL innodb_priority_cleaner=0;
20+SELECT @@GLOBAL.innodb_priority_cleaner;
21+@@GLOBAL.innodb_priority_cleaner
22+0
23+SET GLOBAL innodb_priority_cleaner=1;
24+SELECT @@GLOBAL.innodb_priority_cleaner;
25+@@GLOBAL.innodb_priority_cleaner
26+1
27+SET GLOBAL innodb_priority_cleaner=1.1;
28+ERROR 42000: Incorrect argument type to variable 'innodb_priority_cleaner'
29+SET GLOBAL innodb_priority_cleaner=1e1;
30+ERROR 42000: Incorrect argument type to variable 'innodb_priority_cleaner'
31+SET GLOBAL innodb_priority_cleaner=2;
32+ERROR 42000: Variable 'innodb_priority_cleaner' can't be set to the value of '2'
33+SET GLOBAL innodb_priority_cleaner='foo';
34+ERROR 42000: Variable 'innodb_priority_cleaner' can't be set to the value of 'foo'
35+SET GLOBAL innodb_priority_cleaner = @start_value;
36
37=== added file 'Percona-Server/mysql-test/suite/sys_vars/r/innodb_priority_io_basic.result'
38--- Percona-Server/mysql-test/suite/sys_vars/r/innodb_priority_io_basic.result 1970-01-01 00:00:00 +0000
39+++ Percona-Server/mysql-test/suite/sys_vars/r/innodb_priority_io_basic.result 2013-09-26 14:59:13 +0000
40@@ -0,0 +1,31 @@
41+SET @start_value = @@GLOBAL.innodb_priority_io;
42+SELECT @@GLOBAL.innodb_priority_io;
43+@@GLOBAL.innodb_priority_io
44+0
45+SELECT @@SESSION.innodb_priority_io;
46+ERROR HY000: Variable 'innodb_priority_io' is a GLOBAL variable
47+SET GLOBAL innodb_priority_io='OFF';
48+SELECT @@GLOBAL.innodb_priority_io;
49+@@GLOBAL.innodb_priority_io
50+0
51+SET GLOBAL innodb_priority_io='ON';
52+SELECT @@GLOBAL.innodb_priority_io;
53+@@GLOBAL.innodb_priority_io
54+1
55+SET GLOBAL innodb_priority_io=0;
56+SELECT @@GLOBAL.innodb_priority_io;
57+@@GLOBAL.innodb_priority_io
58+0
59+SET GLOBAL innodb_priority_io=1;
60+SELECT @@GLOBAL.innodb_priority_io;
61+@@GLOBAL.innodb_priority_io
62+1
63+SET GLOBAL innodb_priority_io=1.1;
64+ERROR 42000: Incorrect argument type to variable 'innodb_priority_io'
65+SET GLOBAL innodb_priority_io=1e1;
66+ERROR 42000: Incorrect argument type to variable 'innodb_priority_io'
67+SET GLOBAL innodb_priority_io=2;
68+ERROR 42000: Variable 'innodb_priority_io' can't be set to the value of '2'
69+SET GLOBAL innodb_priority_io='foo';
70+ERROR 42000: Variable 'innodb_priority_io' can't be set to the value of 'foo'
71+SET GLOBAL innodb_priority_io = @start_value;
72
73=== added file 'Percona-Server/mysql-test/suite/sys_vars/r/innodb_priority_master_basic.result'
74--- Percona-Server/mysql-test/suite/sys_vars/r/innodb_priority_master_basic.result 1970-01-01 00:00:00 +0000
75+++ Percona-Server/mysql-test/suite/sys_vars/r/innodb_priority_master_basic.result 2013-09-26 14:59:13 +0000
76@@ -0,0 +1,31 @@
77+SET @start_value = @@GLOBAL.innodb_priority_master;
78+SELECT @@GLOBAL.innodb_priority_master;
79+@@GLOBAL.innodb_priority_master
80+0
81+SELECT @@SESSION.innodb_priority_master;
82+ERROR HY000: Variable 'innodb_priority_master' is a GLOBAL variable
83+SET GLOBAL innodb_priority_master='OFF';
84+SELECT @@GLOBAL.innodb_priority_master;
85+@@GLOBAL.innodb_priority_master
86+0
87+SET GLOBAL innodb_priority_master='ON';
88+SELECT @@GLOBAL.innodb_priority_master;
89+@@GLOBAL.innodb_priority_master
90+1
91+SET GLOBAL innodb_priority_master=0;
92+SELECT @@GLOBAL.innodb_priority_master;
93+@@GLOBAL.innodb_priority_master
94+0
95+SET GLOBAL innodb_priority_master=1;
96+SELECT @@GLOBAL.innodb_priority_master;
97+@@GLOBAL.innodb_priority_master
98+1
99+SET GLOBAL innodb_priority_master=1.1;
100+ERROR 42000: Incorrect argument type to variable 'innodb_priority_master'
101+SET GLOBAL innodb_priority_master=1e1;
102+ERROR 42000: Incorrect argument type to variable 'innodb_priority_master'
103+SET GLOBAL innodb_priority_master=2;
104+ERROR 42000: Variable 'innodb_priority_master' can't be set to the value of '2'
105+SET GLOBAL innodb_priority_master='foo';
106+ERROR 42000: Variable 'innodb_priority_master' can't be set to the value of 'foo'
107+SET GLOBAL innodb_priority_master = @start_value;
108
109=== added file 'Percona-Server/mysql-test/suite/sys_vars/r/innodb_priority_purge_basic.result'
110--- Percona-Server/mysql-test/suite/sys_vars/r/innodb_priority_purge_basic.result 1970-01-01 00:00:00 +0000
111+++ Percona-Server/mysql-test/suite/sys_vars/r/innodb_priority_purge_basic.result 2013-09-26 14:59:13 +0000
112@@ -0,0 +1,31 @@
113+SET @start_value = @@GLOBAL.innodb_priority_purge;
114+SELECT @@GLOBAL.innodb_priority_purge;
115+@@GLOBAL.innodb_priority_purge
116+0
117+SELECT @@SESSION.innodb_priority_purge;
118+ERROR HY000: Variable 'innodb_priority_purge' is a GLOBAL variable
119+SET GLOBAL innodb_priority_purge='OFF';
120+SELECT @@GLOBAL.innodb_priority_purge;
121+@@GLOBAL.innodb_priority_purge
122+0
123+SET GLOBAL innodb_priority_purge='ON';
124+SELECT @@GLOBAL.innodb_priority_purge;
125+@@GLOBAL.innodb_priority_purge
126+1
127+SET GLOBAL innodb_priority_purge=0;
128+SELECT @@GLOBAL.innodb_priority_purge;
129+@@GLOBAL.innodb_priority_purge
130+0
131+SET GLOBAL innodb_priority_purge=1;
132+SELECT @@GLOBAL.innodb_priority_purge;
133+@@GLOBAL.innodb_priority_purge
134+1
135+SET GLOBAL innodb_priority_purge=1.1;
136+ERROR 42000: Incorrect argument type to variable 'innodb_priority_purge'
137+SET GLOBAL innodb_priority_purge=1e1;
138+ERROR 42000: Incorrect argument type to variable 'innodb_priority_purge'
139+SET GLOBAL innodb_priority_purge=2;
140+ERROR 42000: Variable 'innodb_priority_purge' can't be set to the value of '2'
141+SET GLOBAL innodb_priority_purge='foo';
142+ERROR 42000: Variable 'innodb_priority_purge' can't be set to the value of 'foo'
143+SET GLOBAL innodb_priority_purge = @start_value;
144
145=== added file 'Percona-Server/mysql-test/suite/sys_vars/t/innodb_priority_cleaner_basic.test'
146--- Percona-Server/mysql-test/suite/sys_vars/t/innodb_priority_cleaner_basic.test 1970-01-01 00:00:00 +0000
147+++ Percona-Server/mysql-test/suite/sys_vars/t/innodb_priority_cleaner_basic.test 2013-09-26 14:59:13 +0000
148@@ -0,0 +1,40 @@
149+--source include/have_debug.inc
150+--source include/have_innodb.inc
151+
152+if (`SELECT @@version_compile_os LIKE "Linux" = 0`)
153+{
154+ skip Needs Linux;
155+}
156+
157+# A dynamic, global variable
158+
159+SET @start_value = @@GLOBAL.innodb_priority_cleaner;
160+
161+# Default value
162+SELECT @@GLOBAL.innodb_priority_cleaner;
163+
164+# Global only
165+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
166+SELECT @@SESSION.innodb_priority_cleaner;
167+
168+# Correct values
169+SET GLOBAL innodb_priority_cleaner='OFF';
170+SELECT @@GLOBAL.innodb_priority_cleaner;
171+SET GLOBAL innodb_priority_cleaner='ON';
172+SELECT @@GLOBAL.innodb_priority_cleaner;
173+SET GLOBAL innodb_priority_cleaner=0;
174+SELECT @@GLOBAL.innodb_priority_cleaner;
175+SET GLOBAL innodb_priority_cleaner=1;
176+SELECT @@GLOBAL.innodb_priority_cleaner;
177+
178+# Incorrect values
179+--error ER_WRONG_TYPE_FOR_VAR
180+SET GLOBAL innodb_priority_cleaner=1.1;
181+--error ER_WRONG_TYPE_FOR_VAR
182+SET GLOBAL innodb_priority_cleaner=1e1;
183+--error ER_WRONG_VALUE_FOR_VAR
184+SET GLOBAL innodb_priority_cleaner=2;
185+--error ER_WRONG_VALUE_FOR_VAR
186+SET GLOBAL innodb_priority_cleaner='foo';
187+
188+SET GLOBAL innodb_priority_cleaner = @start_value;
189
190=== added file 'Percona-Server/mysql-test/suite/sys_vars/t/innodb_priority_io_basic.test'
191--- Percona-Server/mysql-test/suite/sys_vars/t/innodb_priority_io_basic.test 1970-01-01 00:00:00 +0000
192+++ Percona-Server/mysql-test/suite/sys_vars/t/innodb_priority_io_basic.test 2013-09-26 14:59:13 +0000
193@@ -0,0 +1,40 @@
194+--source include/have_debug.inc
195+--source include/have_innodb.inc
196+
197+if (`SELECT @@version_compile_os LIKE "Linux" = 0`)
198+{
199+ skip Needs Linux;
200+}
201+
202+# A dynamic, global variable
203+
204+SET @start_value = @@GLOBAL.innodb_priority_io;
205+
206+# Default value
207+SELECT @@GLOBAL.innodb_priority_io;
208+
209+# Global only
210+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
211+SELECT @@SESSION.innodb_priority_io;
212+
213+# Correct values
214+SET GLOBAL innodb_priority_io='OFF';
215+SELECT @@GLOBAL.innodb_priority_io;
216+SET GLOBAL innodb_priority_io='ON';
217+SELECT @@GLOBAL.innodb_priority_io;
218+SET GLOBAL innodb_priority_io=0;
219+SELECT @@GLOBAL.innodb_priority_io;
220+SET GLOBAL innodb_priority_io=1;
221+SELECT @@GLOBAL.innodb_priority_io;
222+
223+# Incorrect values
224+--error ER_WRONG_TYPE_FOR_VAR
225+SET GLOBAL innodb_priority_io=1.1;
226+--error ER_WRONG_TYPE_FOR_VAR
227+SET GLOBAL innodb_priority_io=1e1;
228+--error ER_WRONG_VALUE_FOR_VAR
229+SET GLOBAL innodb_priority_io=2;
230+--error ER_WRONG_VALUE_FOR_VAR
231+SET GLOBAL innodb_priority_io='foo';
232+
233+SET GLOBAL innodb_priority_io = @start_value;
234
235=== added file 'Percona-Server/mysql-test/suite/sys_vars/t/innodb_priority_master_basic.test'
236--- Percona-Server/mysql-test/suite/sys_vars/t/innodb_priority_master_basic.test 1970-01-01 00:00:00 +0000
237+++ Percona-Server/mysql-test/suite/sys_vars/t/innodb_priority_master_basic.test 2013-09-26 14:59:13 +0000
238@@ -0,0 +1,40 @@
239+--source include/have_debug.inc
240+--source include/have_innodb.inc
241+
242+if (`SELECT @@version_compile_os LIKE "Linux" = 0`)
243+{
244+ skip Needs Linux;
245+}
246+
247+# A dynamic, global variable
248+
249+SET @start_value = @@GLOBAL.innodb_priority_master;
250+
251+# Default value
252+SELECT @@GLOBAL.innodb_priority_master;
253+
254+# Global only
255+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
256+SELECT @@SESSION.innodb_priority_master;
257+
258+# Correct values
259+SET GLOBAL innodb_priority_master='OFF';
260+SELECT @@GLOBAL.innodb_priority_master;
261+SET GLOBAL innodb_priority_master='ON';
262+SELECT @@GLOBAL.innodb_priority_master;
263+SET GLOBAL innodb_priority_master=0;
264+SELECT @@GLOBAL.innodb_priority_master;
265+SET GLOBAL innodb_priority_master=1;
266+SELECT @@GLOBAL.innodb_priority_master;
267+
268+# Incorrect values
269+--error ER_WRONG_TYPE_FOR_VAR
270+SET GLOBAL innodb_priority_master=1.1;
271+--error ER_WRONG_TYPE_FOR_VAR
272+SET GLOBAL innodb_priority_master=1e1;
273+--error ER_WRONG_VALUE_FOR_VAR
274+SET GLOBAL innodb_priority_master=2;
275+--error ER_WRONG_VALUE_FOR_VAR
276+SET GLOBAL innodb_priority_master='foo';
277+
278+SET GLOBAL innodb_priority_master = @start_value;
279
280=== added file 'Percona-Server/mysql-test/suite/sys_vars/t/innodb_priority_purge_basic.test'
281--- Percona-Server/mysql-test/suite/sys_vars/t/innodb_priority_purge_basic.test 1970-01-01 00:00:00 +0000
282+++ Percona-Server/mysql-test/suite/sys_vars/t/innodb_priority_purge_basic.test 2013-09-26 14:59:13 +0000
283@@ -0,0 +1,40 @@
284+--source include/have_debug.inc
285+--source include/have_innodb.inc
286+
287+if (`SELECT @@version_compile_os LIKE "Linux" = 0`)
288+{
289+ skip Needs Linux;
290+}
291+
292+# A dynamic, global variable
293+
294+SET @start_value = @@GLOBAL.innodb_priority_purge;
295+
296+# Default value
297+SELECT @@GLOBAL.innodb_priority_purge;
298+
299+# Global only
300+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
301+SELECT @@SESSION.innodb_priority_purge;
302+
303+# Correct values
304+SET GLOBAL innodb_priority_purge='OFF';
305+SELECT @@GLOBAL.innodb_priority_purge;
306+SET GLOBAL innodb_priority_purge='ON';
307+SELECT @@GLOBAL.innodb_priority_purge;
308+SET GLOBAL innodb_priority_purge=0;
309+SELECT @@GLOBAL.innodb_priority_purge;
310+SET GLOBAL innodb_priority_purge=1;
311+SELECT @@GLOBAL.innodb_priority_purge;
312+
313+# Incorrect values
314+--error ER_WRONG_TYPE_FOR_VAR
315+SET GLOBAL innodb_priority_purge=1.1;
316+--error ER_WRONG_TYPE_FOR_VAR
317+SET GLOBAL innodb_priority_purge=1e1;
318+--error ER_WRONG_VALUE_FOR_VAR
319+SET GLOBAL innodb_priority_purge=2;
320+--error ER_WRONG_VALUE_FOR_VAR
321+SET GLOBAL innodb_priority_purge='foo';
322+
323+SET GLOBAL innodb_priority_purge = @start_value;
324
325=== modified file 'Percona-Server/storage/innobase/btr/btr0sea.cc'
326--- Percona-Server/storage/innobase/btr/btr0sea.cc 2013-09-20 05:27:28 +0000
327+++ Percona-Server/storage/innobase/btr/btr0sea.cc 2013-09-26 14:59:13 +0000
328@@ -72,7 +72,7 @@
329 being updated in-place! We can use fact (1) to perform unique searches to
330 indexes. */
331
332-UNIV_INTERN rw_lock_t* btr_search_latch_arr;
333+UNIV_INTERN prio_rw_lock_t* btr_search_latch_arr;
334
335 /** padding to prevent other memory update hotspots from residing on
336 the same memory cache line */
337@@ -184,8 +184,8 @@
338 /* btr_search_index_num is constrained to machine word size for
339 historical reasons. This limitation can be easily removed later. */
340
341- btr_search_latch_arr = (rw_lock_t *)
342- mem_alloc(sizeof(rw_lock_t) * btr_search_index_num);
343+ btr_search_latch_arr = (prio_rw_lock_t *)
344+ mem_alloc(sizeof(prio_rw_lock_t) * btr_search_index_num);
345
346 btr_search_sys = (btr_search_sys_t*)
347 mem_alloc(sizeof(btr_search_sys_t));
348
349=== modified file 'Percona-Server/storage/innobase/buf/buf0buddy.cc'
350--- Percona-Server/storage/innobase/buf/buf0buddy.cc 2013-09-20 05:27:28 +0000
351+++ Percona-Server/storage/innobase/buf/buf0buddy.cc 2013-09-26 14:59:13 +0000
352@@ -548,7 +548,7 @@
353 ib_mutex_t* mutex;
354 ulint space;
355 ulint offset;
356- rw_lock_t* hash_lock;
357+ prio_rw_lock_t* hash_lock;
358
359 ut_ad(mutex_own(&buf_pool->zip_free_mutex));
360 ut_ad(!mutex_own(&buf_pool->zip_mutex));
361
362=== modified file 'Percona-Server/storage/innobase/buf/buf0buf.cc'
363--- Percona-Server/storage/innobase/buf/buf0buf.cc 2013-09-25 05:20:37 +0000
364+++ Percona-Server/storage/innobase/buf/buf0buf.cc 2013-09-26 14:59:13 +0000
365@@ -1640,7 +1640,7 @@
366 buf_page_t* bpage;
367 ulint i;
368 buf_pool_t* buf_pool = buf_pool_get(space, offset);
369- rw_lock_t* hash_lock;
370+ prio_rw_lock_t* hash_lock;
371
372 hash_lock = buf_page_hash_lock_get(buf_pool, fold);
373
374@@ -1756,7 +1756,7 @@
375 {
376 #ifdef UNIV_SYNC_DEBUG
377 /* We must also own the appropriate hash_bucket mutex. */
378- rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold);
379+ prio_rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold);
380 ut_ad(rw_lock_own(hash_lock, RW_LOCK_EX));
381 #endif /* UNIV_SYNC_DEBUG */
382
383@@ -1782,7 +1782,7 @@
384 buf_page_t* bpage;
385 buf_pool_t* buf_pool = buf_pool_get(space, offset);
386 ulint fold = buf_page_address_fold(space, offset);
387- rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool,
388+ prio_rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool,
389 fold);
390
391 rw_lock_x_lock(hash_lock);
392@@ -1828,7 +1828,7 @@
393 buf_page_t* bpage;
394 buf_pool_t* buf_pool = buf_pool_get(space, offset);
395 ulint fold = buf_page_address_fold(space, offset);
396- rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool,
397+ prio_rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool,
398 fold);
399
400 rw_lock_s_lock(hash_lock);
401@@ -1919,7 +1919,7 @@
402 {
403 buf_page_t* bpage;
404 buf_pool_t* buf_pool = buf_pool_get(space, offset);
405- rw_lock_t* hash_lock;
406+ prio_rw_lock_t* hash_lock;
407
408 bpage = buf_page_hash_get_s_locked(buf_pool, space, offset,
409 &hash_lock);
410@@ -1953,7 +1953,7 @@
411 {
412 buf_page_t* bpage;
413 buf_pool_t* buf_pool = buf_pool_get(space, offset);
414- rw_lock_t* hash_lock;
415+ prio_rw_lock_t* hash_lock;
416
417 bpage = buf_page_hash_get_s_locked(buf_pool, space, offset,
418 &hash_lock);
419@@ -2031,7 +2031,7 @@
420 {
421 buf_page_t* bpage;
422 ib_mutex_t* block_mutex;
423- rw_lock_t* hash_lock;
424+ prio_rw_lock_t* hash_lock;
425 ibool discard_attempted = FALSE;
426 ibool must_read;
427 trx_t* trx = NULL;
428@@ -2505,7 +2505,7 @@
429 unsigned access_time;
430 ulint fix_type;
431 ibool must_read;
432- rw_lock_t* hash_lock;
433+ prio_rw_lock_t* hash_lock;
434 ib_mutex_t* block_mutex;
435 buf_page_t* hash_bpage;
436 ulint retries = 0;
437@@ -3286,7 +3286,7 @@
438 ibool success;
439 ulint fix_type;
440 buf_pool_t* buf_pool = buf_pool_get(space_id, page_no);
441- rw_lock_t* hash_lock;
442+ prio_rw_lock_t* hash_lock;
443
444 ut_ad(mtr);
445 ut_ad(mtr->state == MTR_ACTIVE);
446@@ -3498,7 +3498,7 @@
447 buf_block_t* block;
448 buf_page_t* bpage = NULL;
449 buf_page_t* watch_page;
450- rw_lock_t* hash_lock;
451+ prio_rw_lock_t* hash_lock;
452 mtr_t mtr;
453 ulint fold;
454 ibool lru = FALSE;
455@@ -3751,7 +3751,7 @@
456 ulint fold;
457 buf_block_t* free_block = NULL;
458 buf_pool_t* buf_pool = buf_pool_get(space, offset);
459- rw_lock_t* hash_lock;
460+ prio_rw_lock_t* hash_lock;
461
462 ut_ad(mtr);
463 ut_ad(mtr->state == MTR_ACTIVE);
464@@ -4007,7 +4007,7 @@
465 ibool ret = TRUE;
466 const ulint fold = buf_page_address_fold(bpage->space,
467 bpage->offset);
468- rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold);
469+ prio_rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold);
470
471 /* First unfix and release lock on the bpage */
472 mutex_enter(&buf_pool->LRU_list_mutex);
473
474=== modified file 'Percona-Server/storage/innobase/buf/buf0flu.cc'
475--- Percona-Server/storage/innobase/buf/buf0flu.cc 2013-09-25 05:20:37 +0000
476+++ Percona-Server/storage/innobase/buf/buf0flu.cc 2013-09-26 14:59:13 +0000
477@@ -1141,7 +1141,7 @@
478 buf_page_t* bpage;
479 buf_pool_t* buf_pool = buf_pool_get(space, offset);
480 bool ret;
481- rw_lock_t* hash_lock;
482+ prio_rw_lock_t* hash_lock;
483 ib_mutex_t* block_mutex;
484
485 ut_ad(flush_type == BUF_FLUSH_LRU
486@@ -1260,7 +1260,7 @@
487 for (i = low; i < high; i++) {
488
489 buf_page_t* bpage;
490- rw_lock_t* hash_lock;
491+ prio_rw_lock_t* hash_lock;
492 ib_mutex_t* block_mutex;
493
494 if ((count + n_flushed) >= n_to_flush) {
495@@ -2452,6 +2452,8 @@
496
497 while (srv_shutdown_state == SRV_SHUTDOWN_NONE) {
498
499+ srv_current_thread_priority = srv_cleaner_thread_priority;
500+
501 /* The page_cleaner skips sleep if the server is
502 idle and there are no pending IOs in the buffer pool
503 and there is work to do. */
504
505=== modified file 'Percona-Server/storage/innobase/buf/buf0lru.cc'
506--- Percona-Server/storage/innobase/buf/buf0lru.cc 2013-09-20 05:27:28 +0000
507+++ Percona-Server/storage/innobase/buf/buf0lru.cc 2013-09-26 14:59:13 +0000
508@@ -751,7 +751,7 @@
509 bpage != NULL;
510 /* No op */) {
511
512- rw_lock_t* hash_lock;
513+ prio_rw_lock_t* hash_lock;
514 buf_page_t* prev_bpage;
515 ib_mutex_t* block_mutex = NULL;
516
517@@ -1187,7 +1187,7 @@
518 {
519 buf_block_t* block;
520
521- mutex_enter(&buf_pool->free_list_mutex);
522+ mutex_enter_last(&buf_pool->free_list_mutex);
523
524 block = (buf_block_t*) UT_LIST_GET_LAST(buf_pool->free);
525
526@@ -1900,7 +1900,7 @@
527 buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
528 const ulint fold = buf_page_address_fold(bpage->space,
529 bpage->offset);
530- rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold);
531+ prio_rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold);
532
533 ib_mutex_t* block_mutex = buf_page_get_mutex(bpage);
534
535@@ -2228,7 +2228,7 @@
536 page_zip_set_size(&block->page.zip, 0);
537 }
538
539- mutex_enter(&buf_pool->free_list_mutex);
540+ mutex_enter_first(&buf_pool->free_list_mutex);
541 buf_block_set_state(block, BUF_BLOCK_NOT_USED);
542 UT_LIST_ADD_FIRST(list, buf_pool->free, (&block->page));
543 ut_d(block->page.in_free_list = TRUE);
544@@ -2264,7 +2264,7 @@
545 ulint fold;
546 const buf_page_t* hashed_bpage;
547 buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
548- rw_lock_t* hash_lock;
549+ prio_rw_lock_t* hash_lock;
550
551 ut_ad(bpage);
552 ut_ad(mutex_own(&buf_pool->LRU_list_mutex));
553@@ -2513,7 +2513,7 @@
554 #ifdef UNIV_SYNC_DEBUG
555 const ulint fold = buf_page_address_fold(bpage->space,
556 bpage->offset);
557- rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold);
558+ prio_rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold);
559 #endif
560 ib_mutex_t* block_mutex = buf_page_get_mutex(bpage);
561
562
563=== modified file 'Percona-Server/storage/innobase/buf/buf0rea.cc'
564--- Percona-Server/storage/innobase/buf/buf0rea.cc 2013-09-20 05:27:28 +0000
565+++ Percona-Server/storage/innobase/buf/buf0rea.cc 2013-09-26 14:59:13 +0000
566@@ -65,7 +65,7 @@
567 == BUF_BLOCK_FILE_PAGE);
568 const ulint fold = buf_page_address_fold(bpage->space,
569 bpage->offset);
570- rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold);
571+ prio_rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold);
572
573 mutex_enter(&buf_pool->LRU_list_mutex);
574 rw_lock_x_lock(hash_lock);
575@@ -347,7 +347,7 @@
576
577 for (i = low; i < high; i++) {
578
579- rw_lock_t* hash_lock;
580+ prio_rw_lock_t* hash_lock;
581
582 const buf_page_t* bpage =
583 buf_page_hash_get_s_locked(buf_pool, space, i,
584@@ -642,7 +642,7 @@
585
586 for (i = low; i < high; i++) {
587
588- rw_lock_t* hash_lock;
589+ prio_rw_lock_t* hash_lock;
590
591 bpage = buf_page_hash_get_s_locked(buf_pool, space, i,
592 &hash_lock);
593
594=== modified file 'Percona-Server/storage/innobase/fil/fil0fil.cc'
595--- Percona-Server/storage/innobase/fil/fil0fil.cc 2013-09-09 14:20:25 +0000
596+++ Percona-Server/storage/innobase/fil/fil0fil.cc 2013-09-26 14:59:13 +0000
597@@ -238,7 +238,7 @@
598 hash_node_t hash; /*!< hash chain node */
599 hash_node_t name_hash;/*!< hash chain the name_hash table */
600 #ifndef UNIV_HOTBACKUP
601- rw_lock_t latch; /*!< latch protecting the file space storage
602+ prio_rw_lock_t latch; /*!< latch protecting the file space storage
603 allocation */
604 #endif /* !UNIV_HOTBACKUP */
605 UT_LIST_NODE_T(fil_space_t) unflushed_spaces;
606@@ -545,7 +545,7 @@
607 Returns the latch of a file space.
608 @return latch protecting storage allocation */
609 UNIV_INTERN
610-rw_lock_t*
611+prio_rw_lock_t*
612 fil_space_get_latch(
613 /*================*/
614 ulint id, /*!< in: space id */
615
616=== modified file 'Percona-Server/storage/innobase/fsp/fsp0fsp.cc'
617--- Percona-Server/storage/innobase/fsp/fsp0fsp.cc 2013-09-20 05:27:28 +0000
618+++ Percona-Server/storage/innobase/fsp/fsp0fsp.cc 2013-09-26 14:59:13 +0000
619@@ -2044,7 +2044,7 @@
620 ib_id_t seg_id;
621 buf_block_t* block = 0; /* remove warning */
622 fseg_header_t* header = 0; /* remove warning */
623- rw_lock_t* latch;
624+ prio_rw_lock_t* latch;
625 ibool success;
626 ulint n_reserved;
627 ulint i;
628@@ -2212,7 +2212,7 @@
629 ulint space;
630 ulint flags;
631 ulint zip_size;
632- rw_lock_t* latch;
633+ prio_rw_lock_t* latch;
634
635 space = page_get_space_id(page_align(header));
636 latch = fil_space_get_latch(space, &flags);
637@@ -2632,7 +2632,7 @@
638 ulint space;
639 ulint flags;
640 ulint zip_size;
641- rw_lock_t* latch;
642+ prio_rw_lock_t* latch;
643 buf_block_t* block;
644 ulint n_reserved;
645
646@@ -2749,7 +2749,7 @@
647 mtr_t* mtr) /*!< in/out: mini-transaction */
648 {
649 fsp_header_t* space_header;
650- rw_lock_t* latch;
651+ prio_rw_lock_t* latch;
652 ulint n_free_list_ext;
653 ulint free_limit;
654 ulint size;
655@@ -2865,7 +2865,7 @@
656 ulint n_free;
657 ulint n_free_up;
658 ulint reserve;
659- rw_lock_t* latch;
660+ prio_rw_lock_t* latch;
661 mtr_t mtr;
662
663 /* The convoluted mutex acquire is to overcome latching order
664@@ -3195,7 +3195,7 @@
665 ulint flags;
666 ulint zip_size;
667 fseg_inode_t* seg_inode;
668- rw_lock_t* latch;
669+ prio_rw_lock_t* latch;
670
671 latch = fil_space_get_latch(space, &flags);
672 zip_size = fsp_flags_get_zip_size(flags);
673@@ -3225,7 +3225,7 @@
674 mtr_t mtr;
675 ibool is_free;
676 ulint flags;
677- rw_lock_t* latch;
678+ prio_rw_lock_t* latch;
679 xdes_t* descr;
680 ulint zip_size;
681 fseg_inode_t* seg_inode;
682@@ -3350,7 +3350,7 @@
683 ulint flags;
684 ulint zip_size;
685 ulint header_page;
686- rw_lock_t* latch;
687+ prio_rw_lock_t* latch;
688
689 space = page_get_space_id(page_align(header));
690 header_page = page_get_page_no(page_align(header));
691@@ -3438,7 +3438,7 @@
692 ulint flags;
693 ulint zip_size;
694 ulint page_no;
695- rw_lock_t* latch;
696+ prio_rw_lock_t* latch;
697
698 space = page_get_space_id(page_align(header));
699
700@@ -3755,7 +3755,7 @@
701 fsp_header_t* header;
702 fseg_inode_t* seg_inode;
703 page_t* seg_inode_page;
704- rw_lock_t* latch;
705+ prio_rw_lock_t* latch;
706 ulint size;
707 ulint flags;
708 ulint zip_size;
709@@ -4007,7 +4007,7 @@
710 fsp_header_t* header;
711 fseg_inode_t* seg_inode;
712 page_t* seg_inode_page;
713- rw_lock_t* latch;
714+ prio_rw_lock_t* latch;
715 ulint flags;
716 ulint zip_size;
717 ulint size;
718
719=== modified file 'Percona-Server/storage/innobase/ha/hash0hash.cc'
720--- Percona-Server/storage/innobase/ha/hash0hash.cc 2013-08-06 15:16:34 +0000
721+++ Percona-Server/storage/innobase/ha/hash0hash.cc 2013-09-26 14:59:13 +0000
722@@ -105,15 +105,15 @@
723 void
724 hash_mutex_exit_all_but(
725 /*====================*/
726- hash_table_t* table, /*!< in: hash table */
727- ib_mutex_t* keep_mutex) /*!< in: mutex to keep */
728+ hash_table_t* table, /*!< in: hash table */
729+ ib_prio_mutex_t* keep_mutex) /*!< in: mutex to keep */
730 {
731 ulint i;
732
733 ut_ad(table->type == HASH_TABLE_SYNC_MUTEX);
734 for (i = 0; i < table->n_sync_obj; i++) {
735
736- ib_mutex_t* mutex = table->sync_obj.mutexes + i;
737+ ib_prio_mutex_t* mutex = table->sync_obj.mutexes + i;
738 if (UNIV_LIKELY(keep_mutex != mutex)) {
739 mutex_exit(mutex);
740 }
741@@ -132,7 +132,7 @@
742 ulint fold) /*!< in: fold */
743 {
744
745- rw_lock_t* lock = hash_get_lock(table, fold);
746+ prio_rw_lock_t* lock = hash_get_lock(table, fold);
747
748 ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
749 ut_ad(lock);
750@@ -155,7 +155,7 @@
751 ulint fold) /*!< in: fold */
752 {
753
754- rw_lock_t* lock = hash_get_lock(table, fold);
755+ prio_rw_lock_t* lock = hash_get_lock(table, fold);
756
757 ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
758 ut_ad(lock);
759@@ -179,7 +179,7 @@
760 ulint fold) /*!< in: fold */
761 {
762
763- rw_lock_t* lock = hash_get_lock(table, fold);
764+ prio_rw_lock_t* lock = hash_get_lock(table, fold);
765
766 ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
767 ut_ad(lock);
768@@ -200,7 +200,7 @@
769 hash_table_t* table, /*!< in: hash table */
770 ulint fold) /*!< in: fold */
771 {
772- rw_lock_t* lock = hash_get_lock(table, fold);
773+ prio_rw_lock_t* lock = hash_get_lock(table, fold);
774
775 ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
776 ut_ad(lock);
777@@ -225,7 +225,7 @@
778 ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
779 for (i = 0; i < table->n_sync_obj; i++) {
780
781- rw_lock_t* lock = table->sync_obj.rw_locks + i;
782+ prio_rw_lock_t* lock = table->sync_obj.rw_locks + i;
783 #ifdef UNIV_SYNC_DEBUG
784 ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED));
785 ut_ad(!rw_lock_own(lock, RW_LOCK_EX));
786@@ -248,7 +248,7 @@
787 ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
788 for (i = 0; i < table->n_sync_obj; i++) {
789
790- rw_lock_t* lock = table->sync_obj.rw_locks + i;
791+ prio_rw_lock_t* lock = table->sync_obj.rw_locks + i;
792 #ifdef UNIV_SYNC_DEBUG
793 ut_ad(rw_lock_own(lock, RW_LOCK_EX));
794 #endif /* UNIV_SYNC_DEBUG */
795@@ -264,14 +264,14 @@
796 hash_unlock_x_all_but(
797 /*==================*/
798 hash_table_t* table, /*!< in: hash table */
799- rw_lock_t* keep_lock) /*!< in: lock to keep */
800+ prio_rw_lock_t* keep_lock) /*!< in: lock to keep */
801 {
802 ulint i;
803
804 ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
805 for (i = 0; i < table->n_sync_obj; i++) {
806
807- rw_lock_t* lock = table->sync_obj.rw_locks + i;
808+ prio_rw_lock_t* lock = table->sync_obj.rw_locks + i;
809 #ifdef UNIV_SYNC_DEBUG
810 ut_ad(rw_lock_own(lock, RW_LOCK_EX));
811 #endif /* UNIV_SYNC_DEBUG */
812@@ -373,8 +373,8 @@
813
814 switch (type) {
815 case HASH_TABLE_SYNC_MUTEX:
816- table->sync_obj.mutexes = static_cast<ib_mutex_t*>(
817- mem_alloc(n_sync_obj * sizeof(ib_mutex_t)));
818+ table->sync_obj.mutexes = static_cast<ib_prio_mutex_t*>(
819+ mem_alloc(n_sync_obj * sizeof(ib_prio_mutex_t)));
820
821 for (i = 0; i < n_sync_obj; i++) {
822 mutex_create(hash_table_mutex_key,
823@@ -384,8 +384,8 @@
824 break;
825
826 case HASH_TABLE_SYNC_RW_LOCK:
827- table->sync_obj.rw_locks = static_cast<rw_lock_t*>(
828- mem_alloc(n_sync_obj * sizeof(rw_lock_t)));
829+ table->sync_obj.rw_locks = static_cast<prio_rw_lock_t*>(
830+ mem_alloc(n_sync_obj * sizeof(prio_rw_lock_t)));
831
832 for (i = 0; i < n_sync_obj; i++) {
833 rw_lock_create(hash_table_rw_lock_key,
834
835=== modified file 'Percona-Server/storage/innobase/handler/ha_innodb.cc'
836--- Percona-Server/storage/innobase/handler/ha_innodb.cc 2013-09-24 13:11:08 +0000
837+++ Percona-Server/storage/innobase/handler/ha_innodb.cc 2013-09-26 14:59:13 +0000
838@@ -16549,6 +16549,31 @@
839 PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
840 "Number of pages reserved in doublewrite buffer for batch flushing",
841 NULL, NULL, 120, 1, 127, 0);
842+
843+#ifdef UNIV_LINUX
844+
845+static MYSQL_SYSVAR_BOOL(priority_purge, srv_purge_thread_priority,
846+ PLUGIN_VAR_OPCMDARG,
847+ "Make purge coordinator and worker threads acquire shared resources with "
848+ "priority", NULL, NULL, FALSE);
849+
850+static MYSQL_SYSVAR_BOOL(priority_io, srv_io_thread_priority,
851+ PLUGIN_VAR_OPCMDARG,
852+ "Make I/O threads acquire shared resources with priority",
853+ NULL, NULL, FALSE);
854+
855+static MYSQL_SYSVAR_BOOL(priority_cleaner, srv_cleaner_thread_priority,
856+ PLUGIN_VAR_OPCMDARG,
857+ "Make buffer pool cleaner thread acquire shared resources with priority",
858+ NULL, NULL, FALSE);
859+
860+static MYSQL_SYSVAR_BOOL(priority_master, srv_master_thread_priority,
861+ PLUGIN_VAR_OPCMDARG,
862+ "Make buffer pool cleaner thread acquire shared resources with priority",
863+ NULL, NULL, FALSE);
864+
865+#endif /* UNIV_LINUX */
866+
867 #endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */
868
869 static MYSQL_SYSVAR_LONG(buffer_pool_instances, innobase_buffer_pool_instances,
870@@ -17210,6 +17235,12 @@
871 #if defined UNIV_DEBUG || defined UNIV_PERF_DEBUG
872 MYSQL_SYSVAR(page_hash_locks),
873 MYSQL_SYSVAR(doublewrite_batch_size),
874+#ifdef UNIV_LINUX
875+ MYSQL_SYSVAR(priority_purge),
876+ MYSQL_SYSVAR(priority_io),
877+ MYSQL_SYSVAR(priority_cleaner),
878+ MYSQL_SYSVAR(priority_master),
879+#endif /* UNIV_LINUX */
880 #endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */
881 MYSQL_SYSVAR(print_all_deadlocks),
882 MYSQL_SYSVAR(cmp_per_index_enabled),
883
884=== modified file 'Percona-Server/storage/innobase/include/btr0sea.h'
885--- Percona-Server/storage/innobase/include/btr0sea.h 2013-09-06 13:40:39 +0000
886+++ Percona-Server/storage/innobase/include/btr0sea.h 2013-09-26 14:59:13 +0000
887@@ -208,7 +208,7 @@
888 Returns the adaptive hash index latch for a given index key.
889 @return the adaptive hash index latch for a given index key */
890 UNIV_INLINE
891-rw_lock_t*
892+prio_rw_lock_t*
893 btr_search_get_latch(
894 /*=================*/
895 const dict_index_t* index) /*!< in: index */
896
897=== modified file 'Percona-Server/storage/innobase/include/btr0sea.ic'
898--- Percona-Server/storage/innobase/include/btr0sea.ic 2013-09-06 13:40:39 +0000
899+++ Percona-Server/storage/innobase/include/btr0sea.ic 2013-09-26 14:59:13 +0000
900@@ -100,7 +100,7 @@
901 Returns the adaptive hash index latch for a given index key.
902 @return the adaptive hash index latch for a given index key */
903 UNIV_INLINE
904-rw_lock_t*
905+prio_rw_lock_t*
906 btr_search_get_latch(
907 /*=================*/
908 const dict_index_t* index) /*!< in: index */
909
910=== modified file 'Percona-Server/storage/innobase/include/btr0types.h'
911--- Percona-Server/storage/innobase/include/btr0types.h 2013-09-06 13:40:39 +0000
912+++ Percona-Server/storage/innobase/include/btr0types.h 2013-09-26 14:59:13 +0000
913@@ -55,7 +55,7 @@
914 Bear in mind (3) and (4) when using the hash indexes.
915 */
916
917-extern rw_lock_t* btr_search_latch_arr;
918+extern prio_rw_lock_t* btr_search_latch_arr;
919
920 #endif /* UNIV_HOTBACKUP */
921
922
923=== modified file 'Percona-Server/storage/innobase/include/buf0buf.h'
924--- Percona-Server/storage/innobase/include/buf0buf.h 2013-09-20 05:27:28 +0000
925+++ Percona-Server/storage/innobase/include/buf0buf.h 2013-09-26 14:59:13 +0000
926@@ -1256,7 +1256,7 @@
927 buf_pool_t* buf_pool, /*!< buffer pool instance */
928 ulint space, /*!< in: space id */
929 ulint offset, /*!< in: page number */
930- rw_lock_t** lock, /*!< in/out: lock of the page
931+ prio_rw_lock_t** lock, /*!< in/out: lock of the page
932 hash acquired if bpage is
933 found. NULL otherwise. If NULL
934 is passed then the hash_lock
935@@ -1282,7 +1282,7 @@
936 buf_pool_t* buf_pool, /*!< buffer pool instance */
937 ulint space, /*!< in: space id */
938 ulint offset, /*!< in: page number */
939- rw_lock_t** lock, /*!< in/out: lock of the page
940+ prio_rw_lock_t** lock, /*!< in/out: lock of the page
941 hash acquired if bpage is
942 found. NULL otherwise. If NULL
943 is passed then the hash_lock
944@@ -1818,8 +1818,8 @@
945 pool instance, protects compressed
946 only pages (of type buf_page_t, not
947 buf_block_t */
948- ib_mutex_t LRU_list_mutex;
949- ib_mutex_t free_list_mutex;
950+ ib_prio_mutex_t LRU_list_mutex;
951+ ib_prio_mutex_t free_list_mutex;
952 ib_mutex_t zip_free_mutex;
953 ib_mutex_t zip_hash_mutex;
954 ib_mutex_t flush_state_mutex; /*!< Flush state protection
955
956=== modified file 'Percona-Server/storage/innobase/include/buf0buf.ic'
957--- Percona-Server/storage/innobase/include/buf0buf.ic 2013-09-20 05:27:28 +0000
958+++ Percona-Server/storage/innobase/include/buf0buf.ic 2013-09-26 14:59:13 +0000
959@@ -1100,7 +1100,7 @@
960
961 #ifdef UNIV_SYNC_DEBUG
962 ulint hash_fold;
963- rw_lock_t* hash_lock;
964+ prio_rw_lock_t* hash_lock;
965
966 hash_fold = buf_page_address_fold(space, offset);
967 ut_ad(hash_fold == fold);
968@@ -1149,7 +1149,7 @@
969 buf_pool_t* buf_pool, /*!< buffer pool instance */
970 ulint space, /*!< in: space id */
971 ulint offset, /*!< in: page number */
972- rw_lock_t** lock, /*!< in/out: lock of the page
973+ prio_rw_lock_t** lock, /*!< in/out: lock of the page
974 hash acquired if bpage is
975 found. NULL otherwise. If NULL
976 is passed then the hash_lock
977@@ -1160,7 +1160,7 @@
978 {
979 buf_page_t* bpage = NULL;
980 ulint fold;
981- rw_lock_t* hash_lock;
982+ prio_rw_lock_t* hash_lock;
983 ulint mode = RW_LOCK_SHARED;
984
985 if (lock != NULL) {
986@@ -1232,7 +1232,7 @@
987 buf_pool_t* buf_pool, /*!< buffer pool instance */
988 ulint space, /*!< in: space id */
989 ulint offset, /*!< in: page number */
990- rw_lock_t** lock, /*!< in/out: lock of the page
991+ prio_rw_lock_t** lock, /*!< in/out: lock of the page
992 hash acquired if bpage is
993 found. NULL otherwise. If NULL
994 is passed then the hash_lock
995
996=== modified file 'Percona-Server/storage/innobase/include/dict0dict.h'
997--- Percona-Server/storage/innobase/include/dict0dict.h 2013-08-14 03:57:21 +0000
998+++ Percona-Server/storage/innobase/include/dict0dict.h 2013-09-26 14:59:13 +0000
999@@ -1367,7 +1367,7 @@
1000 Gets the read-write lock of the index tree.
1001 @return read-write lock */
1002 UNIV_INLINE
1003-rw_lock_t*
1004+prio_rw_lock_t*
1005 dict_index_get_lock(
1006 /*================*/
1007 dict_index_t* index) /*!< in: index */
1008@@ -1552,7 +1552,7 @@
1009
1010 /* Dictionary system struct */
1011 struct dict_sys_t{
1012- ib_mutex_t mutex; /*!< mutex protecting the data
1013+ ib_prio_mutex_t mutex; /*!< mutex protecting the data
1014 dictionary; protects also the
1015 disk-based dictionary system tables;
1016 this mutex serializes CREATE TABLE
1017
1018=== modified file 'Percona-Server/storage/innobase/include/dict0dict.ic'
1019--- Percona-Server/storage/innobase/include/dict0dict.ic 2013-08-06 15:16:34 +0000
1020+++ Percona-Server/storage/innobase/include/dict0dict.ic 2013-09-26 14:59:13 +0000
1021@@ -1175,7 +1175,7 @@
1022 Gets the read-write lock of the index tree.
1023 @return read-write lock */
1024 UNIV_INLINE
1025-rw_lock_t*
1026+prio_rw_lock_t*
1027 dict_index_get_lock(
1028 /*================*/
1029 dict_index_t* index) /*!< in: index */
1030
1031=== modified file 'Percona-Server/storage/innobase/include/dict0mem.h'
1032--- Percona-Server/storage/innobase/include/dict0mem.h 2013-09-02 10:01:38 +0000
1033+++ Percona-Server/storage/innobase/include/dict0mem.h 2013-09-26 14:59:13 +0000
1034@@ -544,7 +544,7 @@
1035 initialized to 0, NULL or FALSE in dict_mem_index_create(). */
1036 struct dict_index_t{
1037 index_id_t id; /*!< id of the index */
1038- rw_lock_t* search_latch; /*!< latch protecting the AHI partition
1039+ prio_rw_lock_t* search_latch; /*!< latch protecting the AHI partition
1040 corresponding to this index */
1041 hash_table_t* search_table; /*!< hash table protected by
1042 search_latch */
1043@@ -632,7 +632,7 @@
1044 /*!< approximate number of leaf pages in the
1045 index tree */
1046 /* @} */
1047- rw_lock_t lock; /*!< read-write lock protecting the
1048+ prio_rw_lock_t lock; /*!< read-write lock protecting the
1049 upper levels of the index tree */
1050 trx_id_t trx_id; /*!< id of the transaction that created this
1051 index, or 0 if the index existed
1052
1053=== modified file 'Percona-Server/storage/innobase/include/fil0fil.h'
1054--- Percona-Server/storage/innobase/include/fil0fil.h 2013-08-14 03:57:21 +0000
1055+++ Percona-Server/storage/innobase/include/fil0fil.h 2013-09-26 14:59:13 +0000
1056@@ -189,7 +189,7 @@
1057 Returns the latch of a file space.
1058 @return latch protecting storage allocation */
1059 UNIV_INTERN
1060-rw_lock_t*
1061+prio_rw_lock_t*
1062 fil_space_get_latch(
1063 /*================*/
1064 ulint id, /*!< in: space id */
1065
1066=== modified file 'Percona-Server/storage/innobase/include/ha0ha.ic'
1067--- Percona-Server/storage/innobase/include/ha0ha.ic 2013-08-06 15:16:34 +0000
1068+++ Percona-Server/storage/innobase/include/ha0ha.ic 2013-09-26 14:59:13 +0000
1069@@ -123,7 +123,7 @@
1070 ut_ad(mutex_own(hash_get_mutex(table, fold)));
1071 } else if (table->type == HASH_TABLE_SYNC_RW_LOCK) {
1072 # ifdef UNIV_SYNC_DEBUG
1073- rw_lock_t* lock = hash_get_lock(table, fold);
1074+ prio_rw_lock_t* lock = hash_get_lock(table, fold);
1075 ut_ad(rw_lock_own(lock, RW_LOCK_EX));
1076 # endif
1077 } else {
1078@@ -146,7 +146,7 @@
1079 ut_ad(mutex_own(hash_get_mutex(table, fold)));
1080 } else if (table->type == HASH_TABLE_SYNC_RW_LOCK) {
1081 # ifdef UNIV_SYNC_DEBUG
1082- rw_lock_t* lock = hash_get_lock(table, fold);
1083+ prio_rw_lock_t* lock = hash_get_lock(table, fold);
1084 ut_ad(rw_lock_own(lock, RW_LOCK_EX)
1085 || rw_lock_own(lock, RW_LOCK_SHARED));
1086 # endif
1087
1088=== modified file 'Percona-Server/storage/innobase/include/hash0hash.h'
1089--- Percona-Server/storage/innobase/include/hash0hash.h 2013-08-06 15:16:34 +0000
1090+++ Percona-Server/storage/innobase/include/hash0hash.h 2013-09-26 14:59:13 +0000
1091@@ -382,7 +382,7 @@
1092 Gets the nth mutex in a hash table.
1093 @return mutex */
1094 UNIV_INLINE
1095-ib_mutex_t*
1096+ib_prio_mutex_t*
1097 hash_get_nth_mutex(
1098 /*===============*/
1099 hash_table_t* table, /*!< in: hash table */
1100@@ -391,7 +391,7 @@
1101 Gets the nth rw_lock in a hash table.
1102 @return rw_lock */
1103 UNIV_INLINE
1104-rw_lock_t*
1105+prio_rw_lock_t*
1106 hash_get_nth_lock(
1107 /*==============*/
1108 hash_table_t* table, /*!< in: hash table */
1109@@ -400,7 +400,7 @@
1110 Gets the mutex for a fold value in a hash table.
1111 @return mutex */
1112 UNIV_INLINE
1113-ib_mutex_t*
1114+ib_prio_mutex_t*
1115 hash_get_mutex(
1116 /*===========*/
1117 hash_table_t* table, /*!< in: hash table */
1118@@ -409,7 +409,7 @@
1119 Gets the rw_lock for a fold value in a hash table.
1120 @return rw_lock */
1121 UNIV_INLINE
1122-rw_lock_t*
1123+prio_rw_lock_t*
1124 hash_get_lock(
1125 /*==========*/
1126 hash_table_t* table, /*!< in: hash table */
1127@@ -450,8 +450,8 @@
1128 void
1129 hash_mutex_exit_all_but(
1130 /*====================*/
1131- hash_table_t* table, /*!< in: hash table */
1132- ib_mutex_t* keep_mutex); /*!< in: mutex to keep */
1133+ hash_table_t* table, /*!< in: hash table */
1134+ ib_prio_mutex_t* keep_mutex); /*!< in: mutex to keep */
1135 /************************************************************//**
1136 s-lock a lock for a fold value in a hash table. */
1137 UNIV_INTERN
1138@@ -506,7 +506,7 @@
1139 hash_unlock_x_all_but(
1140 /*==================*/
1141 hash_table_t* table, /*!< in: hash table */
1142- rw_lock_t* keep_lock); /*!< in: lock to keep */
1143+ prio_rw_lock_t* keep_lock); /*!< in: lock to keep */
1144
1145 #else /* !UNIV_HOTBACKUP */
1146 # define hash_get_heap(table, fold) ((table)->heap)
1147@@ -547,10 +547,11 @@
1148 rw_locks depending on the type.
1149 Must be a power of 2 */
1150 union {
1151- ib_mutex_t* mutexes;/* NULL, or an array of mutexes
1152+ ib_prio_mutex_t* mutexes;
1153+ /* NULL, or an array of mutexes
1154 used to protect segments of the
1155 hash table */
1156- rw_lock_t* rw_locks;/* NULL, or an array of rw_lcoks
1157+ prio_rw_lock_t* rw_locks;/* NULL, or an array of rw_lcoks
1158 used to protect segments of the
1159 hash table */
1160 } sync_obj;
1161
1162=== modified file 'Percona-Server/storage/innobase/include/hash0hash.ic'
1163--- Percona-Server/storage/innobase/include/hash0hash.ic 2013-08-06 15:16:34 +0000
1164+++ Percona-Server/storage/innobase/include/hash0hash.ic 2013-09-26 14:59:13 +0000
1165@@ -150,7 +150,7 @@
1166 Gets the nth mutex in a hash table.
1167 @return mutex */
1168 UNIV_INLINE
1169-ib_mutex_t*
1170+ib_prio_mutex_t*
1171 hash_get_nth_mutex(
1172 /*===============*/
1173 hash_table_t* table, /*!< in: hash table */
1174@@ -168,7 +168,7 @@
1175 Gets the mutex for a fold value in a hash table.
1176 @return mutex */
1177 UNIV_INLINE
1178-ib_mutex_t*
1179+ib_prio_mutex_t*
1180 hash_get_mutex(
1181 /*===========*/
1182 hash_table_t* table, /*!< in: hash table */
1183@@ -188,7 +188,7 @@
1184 Gets the nth rw_lock in a hash table.
1185 @return rw_lock */
1186 UNIV_INLINE
1187-rw_lock_t*
1188+prio_rw_lock_t*
1189 hash_get_nth_lock(
1190 /*==============*/
1191 hash_table_t* table, /*!< in: hash table */
1192@@ -206,7 +206,7 @@
1193 Gets the rw_lock for a fold value in a hash table.
1194 @return rw_lock */
1195 UNIV_INLINE
1196-rw_lock_t*
1197+prio_rw_lock_t*
1198 hash_get_lock(
1199 /*==========*/
1200 hash_table_t* table, /*!< in: hash table */
1201
1202=== modified file 'Percona-Server/storage/innobase/include/log0log.h'
1203--- Percona-Server/storage/innobase/include/log0log.h 2013-06-25 13:13:06 +0000
1204+++ Percona-Server/storage/innobase/include/log0log.h 2013-09-26 14:59:13 +0000
1205@@ -796,7 +796,7 @@
1206 ulint buf_free; /*!< first free offset within the log
1207 buffer */
1208 #ifndef UNIV_HOTBACKUP
1209- ib_mutex_t mutex; /*!< mutex protecting the log */
1210+ ib_prio_mutex_t mutex; /*!< mutex protecting the log */
1211
1212 ib_mutex_t log_flush_order_mutex;/*!< mutex to serialize access to
1213 the flush list when we are putting
1214
1215=== modified file 'Percona-Server/storage/innobase/include/mtr0mtr.h'
1216--- Percona-Server/storage/innobase/include/mtr0mtr.h 2013-06-25 13:13:06 +0000
1217+++ Percona-Server/storage/innobase/include/mtr0mtr.h 2013-09-26 14:59:13 +0000
1218@@ -234,7 +234,7 @@
1219 /*=============================*/
1220 mtr_t* mtr, /*!< in: mtr */
1221 ulint savepoint, /*!< in: savepoint */
1222- rw_lock_t* lock); /*!< in: latch to release */
1223+ prio_rw_lock_t* lock); /*!< in: latch to release */
1224 #else /* !UNIV_HOTBACKUP */
1225 # define mtr_release_s_latch_at_savepoint(mtr,savepoint,lock) ((void) 0)
1226 #endif /* !UNIV_HOTBACKUP */
1227@@ -281,7 +281,7 @@
1228 void
1229 mtr_s_lock_func(
1230 /*============*/
1231- rw_lock_t* lock, /*!< in: rw-lock */
1232+ prio_rw_lock_t* lock, /*!< in: rw-lock */
1233 const char* file, /*!< in: file name */
1234 ulint line, /*!< in: line number */
1235 mtr_t* mtr); /*!< in: mtr */
1236@@ -292,7 +292,7 @@
1237 void
1238 mtr_x_lock_func(
1239 /*============*/
1240- rw_lock_t* lock, /*!< in: rw-lock */
1241+ prio_rw_lock_t* lock, /*!< in: rw-lock */
1242 const char* file, /*!< in: file name */
1243 ulint line, /*!< in: line number */
1244 mtr_t* mtr); /*!< in: mtr */
1245
1246=== modified file 'Percona-Server/storage/innobase/include/mtr0mtr.ic'
1247--- Percona-Server/storage/innobase/include/mtr0mtr.ic 2013-05-26 14:20:00 +0000
1248+++ Percona-Server/storage/innobase/include/mtr0mtr.ic 2013-09-26 14:59:13 +0000
1249@@ -130,7 +130,7 @@
1250 /*=============================*/
1251 mtr_t* mtr, /*!< in: mtr */
1252 ulint savepoint, /*!< in: savepoint */
1253- rw_lock_t* lock) /*!< in: latch to release */
1254+ prio_rw_lock_t* lock) /*!< in: latch to release */
1255 {
1256 mtr_memo_slot_t* slot;
1257 dyn_array_t* memo;
1258@@ -261,7 +261,7 @@
1259 void
1260 mtr_s_lock_func(
1261 /*============*/
1262- rw_lock_t* lock, /*!< in: rw-lock */
1263+ prio_rw_lock_t* lock, /*!< in: rw-lock */
1264 const char* file, /*!< in: file name */
1265 ulint line, /*!< in: line number */
1266 mtr_t* mtr) /*!< in: mtr */
1267@@ -280,7 +280,7 @@
1268 void
1269 mtr_x_lock_func(
1270 /*============*/
1271- rw_lock_t* lock, /*!< in: rw-lock */
1272+ prio_rw_lock_t* lock, /*!< in: rw-lock */
1273 const char* file, /*!< in: file name */
1274 ulint line, /*!< in: line number */
1275 mtr_t* mtr) /*!< in: mtr */
1276
1277=== modified file 'Percona-Server/storage/innobase/include/srv0srv.h'
1278--- Percona-Server/storage/innobase/include/srv0srv.h 2013-08-06 15:16:34 +0000
1279+++ Percona-Server/storage/innobase/include/srv0srv.h 2013-09-26 14:59:13 +0000
1280@@ -479,6 +479,18 @@
1281 extern const char* srv_io_thread_op_info[];
1282 extern const char* srv_io_thread_function[];
1283
1284+/* The relative priority of the purge coordinator and worker threads. */
1285+extern my_bool srv_purge_thread_priority;
1286+
1287+/* The relative priority of the I/O threads. */
1288+extern my_bool srv_io_thread_priority;
1289+
1290+/* The relative priority of the cleaner thread. */
1291+extern my_bool srv_cleaner_thread_priority;
1292+
1293+/* The relative priority of the master thread. */
1294+extern my_bool srv_master_thread_priority;
1295+
1296 /* the number of purge threads to use from the worker pool (currently 0 or 1) */
1297 extern ulong srv_n_purge_threads;
1298
1299
1300=== modified file 'Percona-Server/storage/innobase/include/sync0rw.h'
1301--- Percona-Server/storage/innobase/include/sync0rw.h 2013-08-06 15:16:34 +0000
1302+++ Percona-Server/storage/innobase/include/sync0rw.h 2013-09-26 14:59:13 +0000
1303@@ -96,6 +96,7 @@
1304 #define X_LOCK_DECR 0x00100000
1305
1306 struct rw_lock_t;
1307+struct prio_rw_lock_t;
1308 #ifdef UNIV_SYNC_DEBUG
1309 struct rw_lock_debug_t;
1310 #endif /* UNIV_SYNC_DEBUG */
1311@@ -299,6 +300,24 @@
1312 #endif /* UNIV_DEBUG */
1313 const char* cmutex_name); /*!< in: mutex name */
1314 /******************************************************************//**
1315+Creates, or rather, initializes a priority rw-lock object in a specified memory
1316+location (which must be appropriately aligned). The rw-lock is initialized
1317+to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free
1318+is necessary only if the memory block containing it is freed. */
1319+UNIV_INTERN
1320+void
1321+rw_lock_create_func(
1322+/*================*/
1323+ prio_rw_lock_t* lock, /*!< in: pointer to memory */
1324+#ifdef UNIV_DEBUG
1325+# ifdef UNIV_SYNC_DEBUG
1326+ ulint level, /*!< in: level */
1327+# endif /* UNIV_SYNC_DEBUG */
1328+ const char* cfile_name, /*!< in: file name where created */
1329+ ulint cline, /*!< in: file line where created */
1330+#endif /* UNIV_DEBUG */
1331+ const char* cmutex_name); /*!< in: mutex name */
1332+/******************************************************************//**
1333 Calling this function is obligatory only if the memory buffer containing
1334 the rw-lock is freed. Removes an rw-lock object from the global list. The
1335 rw-lock is checked to be in the non-locked state. */
1336@@ -307,6 +326,15 @@
1337 rw_lock_free_func(
1338 /*==============*/
1339 rw_lock_t* lock); /*!< in: rw-lock */
1340+/******************************************************************//**
1341+Calling this function is obligatory only if the memory buffer containing
1342+the priority rw-lock is freed. Removes an rw-lock object from the global list.
1343+The rw-lock is checked to be in the non-locked state. */
1344+UNIV_INTERN
1345+void
1346+rw_lock_free_func(
1347+/*==============*/
1348+ prio_rw_lock_t* lock); /*!< in: rw-lock */
1349 #ifdef UNIV_DEBUG
1350 /******************************************************************//**
1351 Checks that the rw-lock has been initialized and that there are no
1352@@ -317,6 +345,15 @@
1353 rw_lock_validate(
1354 /*=============*/
1355 rw_lock_t* lock); /*!< in: rw-lock */
1356+/******************************************************************//**
1357+Checks that the priority rw-lock has been initialized and that there are no
1358+simultaneous shared and exclusive locks.
1359+@return TRUE */
1360+UNIV_INTERN
1361+ibool
1362+rw_lock_validate(
1363+/*=============*/
1364+ prio_rw_lock_t* lock); /*!< in: rw-lock */
1365 #endif /* UNIV_DEBUG */
1366 /******************************************************************//**
1367 Low-level function which tries to lock an rw-lock in s-mode. Performs no
1368@@ -349,6 +386,22 @@
1369 const char* file_name,/*!< in: file name where lock requested */
1370 ulint line); /*!< in: line where requested */
1371 /******************************************************************//**
1372+NOTE! Use the corresponding macro, not directly this function, except if
1373+you supply the file name and line number. Lock a priority rw-lock in shared
1374+mode for the current thread, using the relative thread priority. If the
1375+rw-lock is locked in exclusive mode, or there is an exclusive lock request
1376+waiting, the function spins a preset time (controlled by SYNC_SPIN_ROUNDS),
1377+waiting for the lock, before suspending the thread. */
1378+UNIV_INLINE
1379+void
1380+rw_lock_s_lock_func(
1381+/*================*/
1382+ prio_rw_lock_t* lock, /*!< in: pointer to rw-lock */
1383+ ulint pass, /*!< in: pass value; != 0, if the lock will
1384+ be passed to another thread to unlock */
1385+ const char* file_name,/*!< in: file name where lock requested */
1386+ ulint line); /*!< in: line where requested */
1387+/******************************************************************//**
1388 NOTE! Use the corresponding macro, not directly this function! Lock an
1389 rw-lock in exclusive mode for the current thread if the lock can be
1390 obtained immediately.
1391@@ -373,6 +426,17 @@
1392 rw_lock_t* lock); /*!< in/out: rw-lock */
1393
1394 /******************************************************************//**
1395+Releases a shared mode priority lock. */
1396+UNIV_INLINE
1397+void
1398+rw_lock_s_unlock_func(
1399+/*==================*/
1400+#ifdef UNIV_SYNC_DEBUG
1401+ ulint pass, /*!< in: pass value; != 0, if the lock may have
1402+ been passed to another thread to unlock */
1403+#endif
1404+ prio_rw_lock_t* lock); /*!< in/out: rw-lock */
1405+/******************************************************************//**
1406 NOTE! Use the corresponding macro, not directly this function! Lock an
1407 rw-lock in exclusive mode for the current thread. If the rw-lock is locked
1408 in shared or exclusive mode, or there is an exclusive lock request waiting,
1409@@ -385,7 +449,30 @@
1410 void
1411 rw_lock_x_lock_func(
1412 /*================*/
1413- rw_lock_t* lock, /*!< in: pointer to rw-lock */
1414+ rw_lock_t* lock, /*!< in: pointer to rw-lock */
1415+ ulint pass, /*!< in: pass value; != 0, if the lock will
1416+ be passed to another thread to unlock */
1417+ const char* file_name,/*!< in: file name where lock requested */
1418+ ulint line, /*!< in: line where requested */
1419+ bool priority_lock = false,
1420+ /*!< in: whether the lock is a priority lock */
1421+ bool high_priority = false);
1422+ /*!< in: whether we are acquiring a priority
1423+ lock with high priority */
1424+/******************************************************************//**
1425+NOTE! Use the corresponding macro, not directly this function! Lock a priority
1426+rw-lock in exclusive mode for the current thread. If the rw-lock is locked
1427+in shared or exclusive mode, or there is an exclusive lock request waiting,
1428+the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting
1429+for the lock, before suspending the thread. If the same thread has an x-lock
1430+on the rw-lock, locking succeed, with the following exception: if pass != 0,
1431+only a single x-lock may be taken on the lock. NOTE: If the same thread has
1432+an s-lock, locking does not succeed! */
1433+UNIV_INTERN
1434+void
1435+rw_lock_x_lock_func(
1436+/*================*/
1437+ prio_rw_lock_t* lock, /*!< in: pointer to rw-lock */
1438 ulint pass, /*!< in: pass value; != 0, if the lock will
1439 be passed to another thread to unlock */
1440 const char* file_name,/*!< in: file name where lock requested */
1441@@ -402,6 +489,17 @@
1442 #endif
1443 rw_lock_t* lock); /*!< in/out: rw-lock */
1444 /******************************************************************//**
1445+Releases an exclusive mode priority lock. */
1446+UNIV_INLINE
1447+void
1448+rw_lock_x_unlock_func(
1449+/*==================*/
1450+#ifdef UNIV_SYNC_DEBUG
1451+ ulint pass, /*!< in: pass value; != 0, if the lock may have
1452+ been passed to another thread to unlock */
1453+#endif
1454+ prio_rw_lock_t* lock); /*!< in/out: rw-lock */
1455+/******************************************************************//**
1456 This function is used in the insert buffer to move the ownership of an
1457 x-latch on a buffer frame to the current thread. The x-latch was set by
1458 the buffer read operation and it protected the buffer frame while the
1459@@ -424,6 +522,15 @@
1460 rw_lock_get_x_lock_count(
1461 /*=====================*/
1462 const rw_lock_t* lock); /*!< in: rw-lock */
1463+/******************************************************************//**
1464+Returns the value of writer_count for the priority lock. Does not reserve the
1465+lock mutex, so the caller must be sure it is not changed during the call.
1466+@return value of writer_count */
1467+UNIV_INLINE
1468+ulint
1469+rw_lock_get_x_lock_count(
1470+/*=====================*/
1471+ const prio_rw_lock_t* lock); /*!< in: rw-lock */
1472 /********************************************************************//**
1473 Check if there are threads waiting for the rw-lock.
1474 @return 1 if waiters, 0 otherwise */
1475@@ -432,6 +539,14 @@
1476 rw_lock_get_waiters(
1477 /*================*/
1478 const rw_lock_t* lock); /*!< in: rw-lock */
1479+/********************************************************************//**
1480+Check if there are threads waiting for the priority rw-lock.
1481+@return 1 if waiters, 0 otherwise */
1482+UNIV_INLINE
1483+ulint
1484+rw_lock_get_waiters(
1485+/*================*/
1486+ const prio_rw_lock_t* lock); /*!< in: rw-lock */
1487 /******************************************************************//**
1488 Returns the write-status of the lock - this function made more sense
1489 with the old rw_lock implementation.
1490@@ -442,6 +557,15 @@
1491 /*===============*/
1492 const rw_lock_t* lock); /*!< in: rw-lock */
1493 /******************************************************************//**
1494+Returns the write-status of the priority lock - this function made more sense
1495+with the old rw_lock implementation.
1496+@return RW_LOCK_NOT_LOCKED, RW_LOCK_EX, RW_LOCK_WAIT_EX */
1497+UNIV_INLINE
1498+ulint
1499+rw_lock_get_writer(
1500+/*===============*/
1501+ const prio_rw_lock_t* lock); /*!< in: rw-lock */
1502+/******************************************************************//**
1503 Returns the number of readers.
1504 @return number of readers */
1505 UNIV_INLINE
1506@@ -450,6 +574,14 @@
1507 /*=====================*/
1508 const rw_lock_t* lock); /*!< in: rw-lock */
1509 /******************************************************************//**
1510+Returns the number of readers.
1511+@return number of readers */
1512+UNIV_INLINE
1513+ulint
1514+rw_lock_get_reader_count(
1515+/*=====================*/
1516+ const prio_rw_lock_t* lock); /*!< in: rw-lock */
1517+/******************************************************************//**
1518 Decrements lock_word the specified amount if it is greater than 0.
1519 This is used by both s_lock and x_lock operations.
1520 @return TRUE if decr occurs */
1521@@ -496,6 +628,17 @@
1522 ulint lock_type) /*!< in: lock type: RW_LOCK_SHARED,
1523 RW_LOCK_EX */
1524 __attribute__((warn_unused_result));
1525+/******************************************************************//**
1526+Checks if the thread has locked the priority rw-lock in the specified mode,
1527+with the pass value == 0. */
1528+UNIV_INTERN
1529+ibool
1530+rw_lock_own(
1531+/*========*/
1532+ prio_rw_lock_t* lock, /*!< in: rw-lock */
1533+ ulint lock_type) /*!< in: lock type: RW_LOCK_SHARED,
1534+ RW_LOCK_EX */
1535+ __attribute__((warn_unused_result));
1536 #endif /* UNIV_SYNC_DEBUG */
1537 /******************************************************************//**
1538 Checks if somebody has locked the rw-lock in the specified mode. */
1539@@ -631,6 +774,27 @@
1540 #endif /* UNIV_DEBUG */
1541 };
1542
1543+/** The structure implementing a priority rw lock. */
1544+struct prio_rw_lock_t {
1545+ struct rw_lock_t base_lock; /* The regular rw latch
1546+ provides the lock word etc. for
1547+ the priority rw lock */
1548+ volatile ulint high_priority_s_waiters;
1549+ /* If 1, high priority S
1550+ waiters exist */
1551+ os_event_t high_priority_s_event; /* High priority wait
1552+ array event for S waiters */
1553+ volatile ulint high_priority_x_waiters;
1554+ /* If 1, high priority X
1555+ waiters exist */
1556+ os_event_t high_priority_x_event;
1557+ /* High priority wait arraay
1558+ event for X waiters */
1559+ volatile ulint high_priority_wait_ex_waiter;
1560+ /* If 1, a waiting next-writer
1561+ exists and is high-priority */
1562+};
1563+
1564 #ifdef UNIV_SYNC_DEBUG
1565 /** The structure for storing debug info of an rw-lock. All access to this
1566 structure must be protected by rw_lock_debug_mutex_enter(). */
1567@@ -695,6 +859,26 @@
1568 const char* cmutex_name); /*!< in: mutex name */
1569
1570 /******************************************************************//**
1571+Performance schema instrumented wrap function for rw_lock_create_func()
1572+NOTE! Please use the corresponding macro rw_lock_create(), not
1573+directly this function! */
1574+UNIV_INLINE
1575+void
1576+pfs_rw_lock_create_func(
1577+/*====================*/
1578+ PSI_rwlock_key key, /*!< in: key registered with
1579+ performance schema */
1580+ prio_rw_lock_t* lock, /*!< in: rw lock */
1581+#ifdef UNIV_DEBUG
1582+# ifdef UNIV_SYNC_DEBUG
1583+ ulint level, /*!< in: level */
1584+# endif /* UNIV_SYNC_DEBUG */
1585+ const char* cfile_name, /*!< in: file name where created */
1586+ ulint cline, /*!< in: file line where created */
1587+#endif /* UNIV_DEBUG */
1588+ const char* cmutex_name); /*!< in: mutex name */
1589+
1590+/******************************************************************//**
1591 Performance schema instrumented wrap function for rw_lock_x_lock_func()
1592 NOTE! Please use the corresponding macro rw_lock_x_lock(), not
1593 directly this function! */
1594@@ -707,6 +891,21 @@
1595 be passed to another thread to unlock */
1596 const char* file_name,/*!< in: file name where lock requested */
1597 ulint line); /*!< in: line where requested */
1598+
1599+/******************************************************************//**
1600+Performance schema instrumented wrap function for rw_lock_x_lock_func()
1601+NOTE! Please use the corresponding macro rw_lock_x_lock(), not
1602+directly this function! */
1603+UNIV_INLINE
1604+void
1605+pfs_rw_lock_x_lock_func(
1606+/*====================*/
1607+ prio_rw_lock_t* lock, /*!< in: pointer to rw-lock */
1608+ ulint pass, /*!< in: pass value; != 0, if the lock will
1609+ be passed to another thread to unlock */
1610+ const char* file_name,/*!< in: file name where lock requested */
1611+ ulint line); /*!< in: line where requested */
1612+
1613 /******************************************************************//**
1614 Performance schema instrumented wrap function for
1615 rw_lock_x_lock_func_nowait()
1616@@ -719,75 +918,147 @@
1617 rw_lock_t* lock, /*!< in: pointer to rw-lock */
1618 const char* file_name,/*!< in: file name where lock requested */
1619 ulint line); /*!< in: line where requested */
1620-/******************************************************************//**
1621-Performance schema instrumented wrap function for rw_lock_s_lock_func()
1622-NOTE! Please use the corresponding macro rw_lock_s_lock(), not directly
1623-this function! */
1624-UNIV_INLINE
1625-void
1626-pfs_rw_lock_s_lock_func(
1627-/*====================*/
1628- rw_lock_t* lock, /*!< in: pointer to rw-lock */
1629- ulint pass, /*!< in: pass value; != 0, if the lock will
1630- be passed to another thread to unlock */
1631- const char* file_name,/*!< in: file name where lock requested */
1632- ulint line); /*!< in: line where requested */
1633-/******************************************************************//**
1634-Performance schema instrumented wrap function for rw_lock_s_lock_func()
1635-NOTE! Please use the corresponding macro rw_lock_s_lock(), not directly
1636-this function!
1637-@return TRUE if success */
1638-UNIV_INLINE
1639-ibool
1640-pfs_rw_lock_s_lock_low(
1641-/*===================*/
1642- rw_lock_t* lock, /*!< in: pointer to rw-lock */
1643- ulint pass, /*!< in: pass value; != 0, if the
1644- lock will be passed to another
1645- thread to unlock */
1646- const char* file_name, /*!< in: file name where lock requested */
1647- ulint line); /*!< in: line where requested */
1648-/******************************************************************//**
1649-Performance schema instrumented wrap function for rw_lock_x_lock_func()
1650-NOTE! Please use the corresponding macro rw_lock_x_lock(), not directly
1651-this function! */
1652-UNIV_INLINE
1653-void
1654-pfs_rw_lock_x_lock_func(
1655-/*====================*/
1656- rw_lock_t* lock, /*!< in: pointer to rw-lock */
1657- ulint pass, /*!< in: pass value; != 0, if the lock will
1658- be passed to another thread to unlock */
1659- const char* file_name,/*!< in: file name where lock requested */
1660- ulint line); /*!< in: line where requested */
1661-/******************************************************************//**
1662-Performance schema instrumented wrap function for rw_lock_s_unlock_func()
1663-NOTE! Please use the corresponding macro rw_lock_s_unlock(), not directly
1664-this function! */
1665-UNIV_INLINE
1666-void
1667-pfs_rw_lock_s_unlock_func(
1668-/*======================*/
1669-#ifdef UNIV_SYNC_DEBUG
1670- ulint pass, /*!< in: pass value; != 0, if the
1671- lock may have been passed to another
1672- thread to unlock */
1673-#endif
1674- rw_lock_t* lock); /*!< in/out: rw-lock */
1675-/******************************************************************//**
1676-Performance schema instrumented wrap function for rw_lock_s_unlock_func()
1677-NOTE! Please use the corresponding macro rw_lock_x_unlock(), not directly
1678-this function! */
1679-UNIV_INLINE
1680-void
1681-pfs_rw_lock_x_unlock_func(
1682-/*======================*/
1683-#ifdef UNIV_SYNC_DEBUG
1684- ulint pass, /*!< in: pass value; != 0, if the
1685- lock may have been passed to another
1686- thread to unlock */
1687-#endif
1688- rw_lock_t* lock); /*!< in/out: rw-lock */
1689+
1690+/******************************************************************//**
1691+Performance schema instrumented wrap function for rw_lock_s_lock_func()
1692+NOTE! Please use the corresponding macro rw_lock_s_lock(), not directly
1693+this function! */
1694+UNIV_INLINE
1695+void
1696+pfs_rw_lock_s_lock_func(
1697+/*====================*/
1698+ rw_lock_t* lock, /*!< in: pointer to rw-lock */
1699+ ulint pass, /*!< in: pass value; != 0, if the lock will
1700+ be passed to another thread to unlock */
1701+ const char* file_name,/*!< in: file name where lock requested */
1702+ ulint line); /*!< in: line where requested */
1703+
1704+/******************************************************************//**
1705+Performance schema instrumented wrap function for rw_lock_s_lock_func()
1706+NOTE! Please use the corresponding macro rw_lock_s_lock(), not directly
1707+this function! */
1708+UNIV_INLINE
1709+void
1710+pfs_rw_lock_s_lock_func(
1711+/*====================*/
1712+ prio_rw_lock_t* lock, /*!< in: pointer to rw-lock */
1713+ ulint pass, /*!< in: pass value; != 0, if the lock will
1714+ be passed to another thread to unlock */
1715+ const char* file_name,/*!< in: file name where lock requested */
1716+ ulint line); /*!< in: line where requested */
1717+
1718+/******************************************************************//**
1719+Performance schema instrumented wrap function for rw_lock_s_lock_func()
1720+NOTE! Please use the corresponding macro rw_lock_s_lock(), not directly
1721+this function!
1722+@return TRUE if success */
1723+UNIV_INLINE
1724+ibool
1725+pfs_rw_lock_s_lock_low(
1726+/*===================*/
1727+ rw_lock_t* lock, /*!< in: pointer to rw-lock */
1728+ ulint pass, /*!< in: pass value; != 0, if the
1729+ lock will be passed to another
1730+ thread to unlock */
1731+ const char* file_name, /*!< in: file name where lock requested */
1732+ ulint line); /*!< in: line where requested */
1733+/******************************************************************//**
1734+Performance schema instrumented wrap function for rw_lock_s_lock_func()
1735+NOTE! Please use the corresponding macro rw_lock_s_lock(), not directly
1736+this function!
1737+@return TRUE if success */
1738+UNIV_INLINE
1739+ibool
1740+pfs_rw_lock_s_lock_low(
1741+/*===================*/
1742+ prio_rw_lock_t* lock, /*!< in: pointer to rw-lock */
1743+ ulint pass, /*!< in: pass value; != 0, if the
1744+ lock will be passed to another
1745+ thread to unlock */
1746+ const char* file_name, /*!< in: file name where lock requested */
1747+ ulint line); /*!< in: line where requested */
1748+/******************************************************************//**
1749+Performance schema instrumented wrap function for rw_lock_x_lock_func()
1750+NOTE! Please use the corresponding macro rw_lock_x_lock(), not directly
1751+this function! */
1752+UNIV_INLINE
1753+void
1754+pfs_rw_lock_x_lock_func(
1755+/*====================*/
1756+ rw_lock_t* lock, /*!< in: pointer to rw-lock */
1757+ ulint pass, /*!< in: pass value; != 0, if the lock will
1758+ be passed to another thread to unlock */
1759+ const char* file_name,/*!< in: file name where lock requested */
1760+ ulint line); /*!< in: line where requested */
1761+/******************************************************************//**
1762+Performance schema instrumented wrap function for rw_lock_x_lock_func()
1763+NOTE! Please use the corresponding macro rw_lock_x_lock(), not directly
1764+this function! */
1765+UNIV_INLINE
1766+void
1767+pfs_rw_lock_x_lock_func(
1768+/*====================*/
1769+ prio_rw_lock_t* lock, /*!< in: pointer to rw-lock */
1770+ ulint pass, /*!< in: pass value; != 0, if the lock will
1771+ be passed to another thread to unlock */
1772+ const char* file_name,/*!< in: file name where lock requested */
1773+ ulint line); /*!< in: line where requested */
1774+/******************************************************************//**
1775+Performance schema instrumented wrap function for rw_lock_s_unlock_func()
1776+NOTE! Please use the corresponding macro rw_lock_s_unlock(), not directly
1777+this function! */
1778+UNIV_INLINE
1779+void
1780+pfs_rw_lock_s_unlock_func(
1781+/*======================*/
1782+#ifdef UNIV_SYNC_DEBUG
1783+ ulint pass, /*!< in: pass value; != 0, if the
1784+ lock may have been passed to another
1785+ thread to unlock */
1786+#endif
1787+ rw_lock_t* lock); /*!< in/out: rw-lock */
1788+/******************************************************************//**
1789+Performance schema instrumented wrap function for rw_lock_s_unlock_func()
1790+NOTE! Please use the corresponding macro rw_lock_s_unlock(), not directly
1791+this function! */
1792+UNIV_INLINE
1793+void
1794+pfs_rw_lock_s_unlock_func(
1795+/*======================*/
1796+#ifdef UNIV_SYNC_DEBUG
1797+ ulint pass, /*!< in: pass value; != 0, if the
1798+ lock may have been passed to another
1799+ thread to unlock */
1800+#endif
1801+ prio_rw_lock_t* lock); /*!< in/out: rw-lock */
1802+/******************************************************************//**
1803+Performance schema instrumented wrap function for rw_lock_s_unlock_func()
1804+NOTE! Please use the corresponding macro rw_lock_x_unlock(), not directly
1805+this function! */
1806+UNIV_INLINE
1807+void
1808+pfs_rw_lock_x_unlock_func(
1809+/*======================*/
1810+#ifdef UNIV_SYNC_DEBUG
1811+ ulint pass, /*!< in: pass value; != 0, if the
1812+ lock may have been passed to another
1813+ thread to unlock */
1814+#endif
1815+ rw_lock_t* lock); /*!< in/out: rw-lock */
1816+/******************************************************************//**
1817+Performance schema instrumented wrap function for rw_lock_s_unlock_func()
1818+NOTE! Please use the corresponding macro rw_lock_x_unlock(), not directly
1819+this function! */
1820+UNIV_INLINE
1821+void
1822+pfs_rw_lock_x_unlock_func(
1823+/*======================*/
1824+#ifdef UNIV_SYNC_DEBUG
1825+ ulint pass, /*!< in: pass value; != 0, if the
1826+ lock may have been passed to another
1827+ thread to unlock */
1828+#endif
1829+ prio_rw_lock_t* lock); /*!< in/out: rw-lock */
1830 /******************************************************************//**
1831 Performance schema instrumented wrap function for rw_lock_free_func()
1832 NOTE! Please use the corresponding macro rw_lock_free(), not directly
1833@@ -797,6 +1068,15 @@
1834 pfs_rw_lock_free_func(
1835 /*==================*/
1836 rw_lock_t* lock); /*!< in: rw-lock */
1837+/******************************************************************//**
1838+Performance schema instrumented wrap function for rw_lock_free_func()
1839+NOTE! Please use the corresponding macro rw_lock_free(), not directly
1840+this function! */
1841+UNIV_INLINE
1842+void
1843+pfs_rw_lock_free_func(
1844+/*==================*/
1845+ prio_rw_lock_t* lock); /*!< in: rw-lock */
1846 #endif /* UNIV_PFS_RWLOCK */
1847
1848
1849
1850=== modified file 'Percona-Server/storage/innobase/include/sync0rw.ic'
1851--- Percona-Server/storage/innobase/include/sync0rw.ic 2013-08-06 15:16:34 +0000
1852+++ Percona-Server/storage/innobase/include/sync0rw.ic 2013-09-26 14:59:13 +0000
1853@@ -31,17 +31,22 @@
1854 *******************************************************/
1855
1856 /******************************************************************//**
1857-Lock an rw-lock in shared mode for the current thread. If the rw-lock is
1858-locked in exclusive mode, or there is an exclusive lock request waiting,
1859-the function spins a preset time (controlled by SYNC_SPIN_ROUNDS),
1860+Lock a regular or priority rw-lock in shared mode for the current thread. If
1861+the rw-lock is locked in exclusive mode, or there is an exclusive lock request
1862+waiting, the function spins a preset time (controlled by SYNC_SPIN_ROUNDS),
1863 waiting for the lock before suspending the thread. */
1864 UNIV_INTERN
1865 void
1866 rw_lock_s_lock_spin(
1867 /*================*/
1868- rw_lock_t* lock, /*!< in: pointer to rw-lock */
1869+ void* _lock, /*!< in: pointer to rw-lock */
1870 ulint pass, /*!< in: pass value; != 0, if the lock will
1871 be passed to another thread to unlock */
1872+ bool priority_lock,
1873+ /*!< in: whether the lock is a priority lock */
1874+ bool high_priority,
1875+ /*!< in: whether we are acquiring a priority
1876+ lock with high priority */
1877 const char* file_name,/*!< in: file name where lock requested */
1878 ulint line); /*!< in: line where requested */
1879 #ifdef UNIV_SYNC_DEBUG
1880@@ -80,6 +85,20 @@
1881 }
1882
1883 /********************************************************************//**
1884+Check if there are threads waiting for the priority rw-lock.
1885+@return 1 if waiters, 0 otherwise */
1886+UNIV_INLINE
1887+ulint
1888+rw_lock_get_waiters(
1889+/*================*/
1890+ const prio_rw_lock_t* lock) /*!< in: rw-lock */
1891+{
1892+ return rw_lock_get_waiters(&lock->base_lock)
1893+ | lock->high_priority_s_waiters
1894+ | lock->high_priority_x_waiters;
1895+}
1896+
1897+/********************************************************************//**
1898 Sets lock->waiters to 1. It is not an error if lock->waiters is already
1899 1. On platforms where ATOMIC builtins are used this function enforces a
1900 memory barrier. */
1901@@ -137,6 +156,19 @@
1902 }
1903
1904 /******************************************************************//**
1905+Returns the write-status of the priority lock - this function made more sense
1906+with the old rw_lock implementation.
1907+@return RW_LOCK_NOT_LOCKED, RW_LOCK_EX, RW_LOCK_WAIT_EX */
1908+UNIV_INLINE
1909+ulint
1910+rw_lock_get_writer(
1911+/*===============*/
1912+ const prio_rw_lock_t* lock) /*!< in: rw-lock */
1913+{
1914+ return(rw_lock_get_writer(&lock->base_lock));
1915+}
1916+
1917+/******************************************************************//**
1918 Returns the number of readers.
1919 @return number of readers */
1920 UNIV_INLINE
1921@@ -156,6 +188,18 @@
1922 return(0);
1923 }
1924
1925+/******************************************************************//**
1926+Returns the number of readers.
1927+@return number of readers */
1928+UNIV_INLINE
1929+ulint
1930+rw_lock_get_reader_count(
1931+/*=====================*/
1932+ const prio_rw_lock_t* lock) /*!< in: rw-lock */
1933+{
1934+ return(rw_lock_get_reader_count(&lock->base_lock));
1935+}
1936+
1937 #ifndef INNODB_RW_LOCKS_USE_ATOMICS
1938 UNIV_INLINE
1939 ib_mutex_t*
1940@@ -185,6 +229,19 @@
1941 }
1942
1943 /******************************************************************//**
1944+Returns the value of writer_count for the priority lock. Does not reserve the
1945+lock mutex, so the caller must be sure it is not changed during the call.
1946+@return value of writer_count */
1947+UNIV_INLINE
1948+ulint
1949+rw_lock_get_x_lock_count(
1950+/*=====================*/
1951+ const prio_rw_lock_t* lock) /*!< in: rw-lock */
1952+{
1953+ return(rw_lock_get_x_lock_count(&lock->base_lock));
1954+}
1955+
1956+/******************************************************************//**
1957 Two different implementations for decrementing the lock_word of a rw_lock:
1958 one for systems supporting atomic operations, one for others. This does
1959 does not support recusive x-locks: they should be handled by the caller and
1960@@ -361,7 +418,75 @@
1961 } else {
1962 /* Did not succeed, try spin wait */
1963
1964- rw_lock_s_lock_spin(lock, pass, file_name, line);
1965+ rw_lock_s_lock_spin(lock, pass, false, false, file_name, line);
1966+
1967+ return;
1968+ }
1969+}
1970+
1971+/******************************************************************//**
1972+Return true if waiters of higher priority than the current thread
1973+exist.
1974+@true if waiterss of higher priority exist */
1975+UNIV_INLINE
1976+bool
1977+rw_lock_higher_prio_waiters_exist(
1978+/*==============================*/
1979+ bool priority_lock, /*!< in: whether the lock is a priority lock */
1980+ bool high_priority, /*!< in: whether we are acquiring a priority
1981+ lock with high priority */
1982+ void* lock) /*!< in: rw lock */
1983+{
1984+ if (high_priority || !priority_lock) {
1985+ ut_ad(!(!priority_lock && high_priority));
1986+ return(false);
1987+ }
1988+
1989+ ut_ad(priority_lock && !high_priority);
1990+
1991+ prio_rw_lock_t *prio_rw_lock = (prio_rw_lock_t *) lock;
1992+ return prio_rw_lock->high_priority_wait_ex_waiter > 0
1993+ || prio_rw_lock->high_priority_s_waiters > 0
1994+ || prio_rw_lock->high_priority_x_waiters > 0;
1995+}
1996+
1997+/******************************************************************//**
1998+NOTE! Use the corresponding macro, not directly this function, except if
1999+you supply the file name and line number. Lock a priority rw-lock in shared
2000+mode for the current thread, using the relative thread priority. If the
2001+rw-lock is locked in exclusive mode, or there is an exclusive lock request
2002+waiting, the function spins a preset time (controlled by SYNC_SPIN_ROUNDS),
2003+waiting for the lock, before suspending the thread. */
2004+UNIV_INLINE
2005+void
2006+rw_lock_s_lock_func(
2007+/*================*/
2008+ prio_rw_lock_t* lock, /*!< in: pointer to rw-lock */
2009+ ulint pass, /*!< in: pass value; != 0, if the lock will
2010+ be passed to another thread to unlock */
2011+ const char* file_name,/*!< in: file name where lock requested */
2012+ ulint line) /*!< in: line where requested */
2013+{
2014+#ifdef UNIV_SYNC_DEBUG
2015+ ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */
2016+ ut_ad(!rw_lock_own(lock, RW_LOCK_EX));
2017+#endif /* UNIV_SYNC_DEBUG */
2018+
2019+ bool high_priority = srv_current_thread_priority > 0;
2020+
2021+ /* Do not attempt to acquire a low-priority S latch if there are
2022+ high-priority waiters even if such attempt would be successful. This
2023+ is to prevent a high priority X request from being starved by a
2024+ sequence of overlapping regular priority S requests. */
2025+
2026+ if (!rw_lock_higher_prio_waiters_exist(true, high_priority, lock)
2027+ && rw_lock_s_lock_low(&lock->base_lock, pass, file_name, line)) {
2028+
2029+ return; /* Success */
2030+ } else {
2031+ /* Did not succeed, try spin wait */
2032+ rw_lock_s_lock_spin(lock, pass, true, high_priority, file_name,
2033+ line);
2034
2035 return;
2036 }
2037@@ -380,8 +505,6 @@
2038 const char* file_name,/*!< in: file name where lock requested */
2039 ulint line) /*!< in: line where requested */
2040 {
2041- os_thread_id_t curr_thread = os_thread_get_curr_id();
2042-
2043 ibool success;
2044
2045 #ifdef INNODB_RW_LOCKS_USE_ATOMICS
2046@@ -401,7 +524,8 @@
2047 rw_lock_set_writer_id_and_recursion_flag(lock, TRUE);
2048
2049 } else if (lock->recursive
2050- && os_thread_eq(lock->writer_thread, curr_thread)) {
2051+ && os_thread_eq(lock->writer_thread,
2052+ os_thread_get_curr_id())) {
2053 /* Relock: this lock_word modification is safe since no other
2054 threads can modify (lock, unlock, or reserve) lock_word while
2055 there is an exclusive writer and this is the writer thread. */
2056@@ -469,13 +593,75 @@
2057 }
2058
2059 /******************************************************************//**
2060-Releases an exclusive mode lock. */
2061+Releases a shared mode priority lock. */
2062 UNIV_INLINE
2063 void
2064-rw_lock_x_unlock_func(
2065+rw_lock_s_unlock_func(
2066 /*==================*/
2067 #ifdef UNIV_SYNC_DEBUG
2068 ulint pass, /*!< in: pass value; != 0, if the lock may have
2069+ been passed to another thread to unlock */
2070+#endif
2071+ prio_rw_lock_t* lock) /*!< in/out: rw-lock */
2072+{
2073+ ut_ad(lock->base_lock.lock_word > -X_LOCK_DECR);
2074+ ut_ad(lock->base_lock.lock_word != 0);
2075+ ut_ad(lock->base_lock.lock_word < X_LOCK_DECR);
2076+
2077+#ifdef UNIV_SYNC_DEBUG
2078+ rw_lock_remove_debug_info(&lock->base_lock, pass, RW_LOCK_SHARED);
2079+#endif
2080+
2081+ /* Increment lock_word to indicate 1 less reader */
2082+ if (rw_lock_lock_word_incr(&lock->base_lock, 1) == 0) {
2083+
2084+ /* A waiting next-writer exists, either high priority or
2085+ regular. Wake up the first waiter in this order: 1) high
2086+ priority next-writer; 2) high priority X waiters; 3) high
2087+ priority S waiters; 4) regular priority next-waiter. This
2088+ allows high priority requests to overtake an already-waiting
2089+ regular priority next-waiter. */
2090+ if (lock->high_priority_wait_ex_waiter) {
2091+
2092+ lock->high_priority_wait_ex_waiter = 0;
2093+ /* Note that we do not have a separate high priority
2094+ next-waiter event. There can be only one such waiter,
2095+ here we already know it's high priority, no
2096+ regular-priority wakeup may happen. */
2097+ os_event_set(lock->base_lock.wait_ex_event);
2098+ } else if (lock->high_priority_x_waiters) {
2099+
2100+ lock->high_priority_x_waiters = 0;
2101+ os_event_set(lock->high_priority_x_event);
2102+ } else if (lock->high_priority_s_waiters) {
2103+
2104+ lock->high_priority_s_waiters = 0;
2105+ os_event_set(lock->high_priority_s_event);
2106+ } else {
2107+
2108+ os_event_set(lock->base_lock.wait_ex_event);
2109+ }
2110+ sync_array_object_signalled();
2111+ }
2112+
2113+ ut_ad(rw_lock_validate(lock));
2114+
2115+#ifdef UNIV_SYNC_PERF_STAT
2116+ rw_s_exit_count++;
2117+#endif
2118+}
2119+
2120+/******************************************************************//**
2121+Prepares an exclusive mode lock release: resets the recursion flag and removes
2122+the debug information if needed and returns the required lock word increment
2123+value.
2124+@return lock word increment value to perform the unlock */
2125+UNIV_INLINE
2126+ulint
2127+rw_lock_x_prepare_unlock(
2128+/*=====================*/
2129+#ifdef UNIV_SYNC_DEBUG
2130+ ulint pass, /*!< in: pass value; != 0, if the lock may have
2131 been passed to another thread to unlock */
2132 #endif
2133 rw_lock_t* lock) /*!< in/out: rw-lock */
2134@@ -507,10 +693,32 @@
2135 x_lock_incr = 1;
2136 }
2137
2138+ return(x_lock_incr);
2139+}
2140+
2141+/******************************************************************//**
2142+Releases an exclusive mode lock. */
2143+UNIV_INLINE
2144+void
2145+rw_lock_x_unlock_func(
2146+/*==================*/
2147+#ifdef UNIV_SYNC_DEBUG
2148+ ulint pass, /*!< in: pass value; != 0, if the lock may have
2149+ been passed to another thread to unlock */
2150+#endif
2151+ rw_lock_t* lock) /*!< in/out: rw-lock */
2152+{
2153+ ulint x_lock_incr = rw_lock_x_prepare_unlock(
2154+#ifdef UNIV_SYNC_DEBUG
2155+ pass,
2156+#endif
2157+ lock);
2158+
2159 if (rw_lock_lock_word_incr(lock, x_lock_incr) == X_LOCK_DECR) {
2160 /* Lock is now free. May have to signal read/write waiters.
2161 We do not need to signal wait_ex waiters, since they cannot
2162 exist when there is a writer. */
2163+
2164 if (lock->waiters) {
2165 rw_lock_reset_waiter_flag(lock);
2166 os_event_set(lock->event);
2167@@ -525,6 +733,58 @@
2168 #endif
2169 }
2170
2171+/******************************************************************//**
2172+Releases an exclusive mode priority lock. */
2173+UNIV_INLINE
2174+void
2175+rw_lock_x_unlock_func(
2176+/*==================*/
2177+#ifdef UNIV_SYNC_DEBUG
2178+ ulint pass, /*!< in: pass value; != 0, if the lock may have
2179+ been passed to another thread to unlock */
2180+#endif
2181+ prio_rw_lock_t* lock) /*!< in/out: rw-lock */
2182+{
2183+ ulint x_lock_incr = rw_lock_x_prepare_unlock(
2184+#ifdef UNIV_SYNC_DEBUG
2185+ pass,
2186+#endif
2187+ &lock->base_lock);
2188+
2189+ if (rw_lock_lock_word_incr(&lock->base_lock, x_lock_incr)
2190+ == X_LOCK_DECR) {
2191+
2192+ /* Priority lock is now free. Signal any waiters in this
2193+ order: 1) high priority X waiters; 2) high priority S waiters;
2194+ 3) regular priority waiters.
2195+ We do not need to signal wait_ex waiters, since they cannot
2196+ exist when there is a writer. */
2197+
2198+ if (lock->high_priority_x_waiters) {
2199+
2200+ lock->high_priority_x_waiters = 0;
2201+ os_event_set(lock->high_priority_x_event);
2202+ sync_array_object_signalled();
2203+ } else if (lock->high_priority_s_waiters) {
2204+
2205+ lock->high_priority_s_waiters = 0;
2206+ os_event_set(lock->high_priority_s_event);
2207+ sync_array_object_signalled();
2208+ } else if (lock->base_lock.waiters) {
2209+
2210+ rw_lock_reset_waiter_flag(&lock->base_lock);
2211+ os_event_set(lock->base_lock.event);
2212+ sync_array_object_signalled();
2213+ }
2214+ }
2215+
2216+ ut_ad(rw_lock_validate(lock));
2217+
2218+#ifdef UNIV_SYNC_PERF_STAT
2219+ rw_x_exit_count++;
2220+#endif
2221+}
2222+
2223 #ifdef UNIV_PFS_RWLOCK
2224
2225 /******************************************************************//**
2226@@ -561,6 +821,42 @@
2227 # endif /* UNIV_DEBUG */
2228 cmutex_name);
2229 }
2230+
2231+/******************************************************************//**
2232+Performance schema instrumented wrap function for rw_lock_create_func().
2233+NOTE! Please use the corresponding macro rw_lock_create(), not directly
2234+this function! */
2235+UNIV_INLINE
2236+void
2237+pfs_rw_lock_create_func(
2238+/*====================*/
2239+ mysql_pfs_key_t key, /*!< in: key registered with
2240+ performance schema */
2241+ prio_rw_lock_t* lock, /*!< in: pointer to memory */
2242+# ifdef UNIV_DEBUG
2243+# ifdef UNIV_SYNC_DEBUG
2244+ ulint level, /*!< in: level */
2245+# endif /* UNIV_SYNC_DEBUG */
2246+ const char* cfile_name, /*!< in: file name where created */
2247+ ulint cline, /*!< in: file line where created */
2248+# endif /* UNIV_DEBUG */
2249+ const char* cmutex_name) /*!< in: mutex name */
2250+{
2251+ /* Initialize the rwlock for performance schema */
2252+ lock->base_lock.pfs_psi = PSI_RWLOCK_CALL(init_rwlock)(key, lock);
2253+
2254+ /* The actual function to initialize an rwlock */
2255+ rw_lock_create_func(lock,
2256+# ifdef UNIV_DEBUG
2257+# ifdef UNIV_SYNC_DEBUG
2258+ level,
2259+# endif /* UNIV_SYNC_DEBUG */
2260+ cfile_name,
2261+ cline,
2262+# endif /* UNIV_DEBUG */
2263+ cmutex_name);
2264+}
2265+
2266 /******************************************************************//**
2267 Performance schema instrumented wrap function for rw_lock_x_lock_func()
2268 NOTE! Please use the corresponding macro rw_lock_x_lock(), not directly
2269@@ -594,6 +890,42 @@
2270 rw_lock_x_lock_func(lock, pass, file_name, line);
2271 }
2272 }
2273+
2274+/******************************************************************//**
2275+Performance schema instrumented wrap function for rw_lock_x_lock_func()
2276+NOTE! Please use the corresponding macro rw_lock_x_lock(), not directly
2277+this function! */
2278+UNIV_INLINE
2279+void
2280+pfs_rw_lock_x_lock_func(
2281+/*====================*/
2282+ prio_rw_lock_t* lock, /*!< in: pointer to rw-lock */
2283+ ulint pass, /*!< in: pass value; != 0, if the lock will
2284+ be passed to another thread to unlock */
2285+ const char* file_name,/*!< in: file name where lock requested */
2286+ ulint line) /*!< in: line where requested */
2287+{
2288+ if (lock->base_lock.pfs_psi != NULL)
2289+ {
2290+ PSI_rwlock_locker* locker;
2291+ PSI_rwlock_locker_state state;
2292+
2293+ /* Record the entry of rw x lock request in performance schema */
2294+ locker = PSI_RWLOCK_CALL(start_rwlock_wrwait)(
2295+ &state, lock->base_lock.pfs_psi, PSI_RWLOCK_WRITELOCK,
2296+ file_name, line);
2297+
2298+ rw_lock_x_lock_func(lock, pass, file_name, line);
2299+
2300+ if (locker != NULL)
2301+ PSI_RWLOCK_CALL(end_rwlock_wrwait)(locker, 0);
2302+ }
2303+ else
2304+ {
2305+ rw_lock_x_lock_func(lock, pass, file_name, line);
2306+ }
2307+}
2308+
2309 /******************************************************************//**
2310 Performance schema instrumented wrap function for
2311 rw_lock_x_lock_func_nowait()
2312@@ -650,6 +982,26 @@
2313
2314 rw_lock_free_func(lock);
2315 }
2316+
2317+/******************************************************************//**
2318+Performance schema instrumented wrap function for rw_lock_free_func()
2319+NOTE! Please use the corresponding macro rw_lock_free(), not directly
2320+this function! */
2321+UNIV_INLINE
2322+void
2323+pfs_rw_lock_free_func(
2324+/*==================*/
2325+ prio_rw_lock_t* lock) /*!< in: pointer to rw-lock */
2326+{
2327+ if (lock->base_lock.pfs_psi != NULL)
2328+ {
2329+ PSI_RWLOCK_CALL(destroy_rwlock)(lock->base_lock.pfs_psi);
2330+ lock->base_lock.pfs_psi = NULL;
2331+ }
2332+
2333+ rw_lock_free_func(lock);
2334+}
2335+
2336 /******************************************************************//**
2337 Performance schema instrumented wrap function for rw_lock_s_lock_func()
2338 NOTE! Please use the corresponding macro rw_lock_s_lock(), not
2339@@ -687,6 +1039,46 @@
2340
2341 return;
2342 }
2343+
2344+/******************************************************************//**
2345+Performance schema instrumented wrap function for rw_lock_s_lock_func()
2346+NOTE! Please use the corresponding macro rw_lock_s_lock(), not
2347+directly this function! */
2348+UNIV_INLINE
2349+void
2350+pfs_rw_lock_s_lock_func(
2351+/*====================*/
2352+ prio_rw_lock_t* lock, /*!< in: pointer to rw-lock */
2353+ ulint pass, /*!< in: pass value; != 0, if the
2354+ lock will be passed to another
2355+ thread to unlock */
2356+ const char* file_name,/*!< in: file name where lock
2357+ requested */
2358+ ulint line) /*!< in: line where requested */
2359+{
2360+ if (lock->base_lock.pfs_psi != NULL)
2361+ {
2362+ PSI_rwlock_locker* locker;
2363+ PSI_rwlock_locker_state state;
2364+
2365+ /* Instrumented to inform we are aquiring a shared rwlock */
2366+ locker = PSI_RWLOCK_CALL(start_rwlock_rdwait)(
2367+ &state, lock->base_lock.pfs_psi, PSI_RWLOCK_READLOCK,
2368+ file_name, line);
2369+
2370+ rw_lock_s_lock_func(lock, pass, file_name, line);
2371+
2372+ if (locker != NULL)
2373+ PSI_RWLOCK_CALL(end_rwlock_rdwait)(locker, 0);
2374+ }
2375+ else
2376+ {
2377+ rw_lock_s_lock_func(lock, pass, file_name, line);
2378+ }
2379+
2380+ return;
2381+}
2382+
2383 /******************************************************************//**
2384 Performance schema instrumented wrap function for rw_lock_s_lock_func()
2385 NOTE! Please use the corresponding macro rw_lock_s_lock(), not
2386@@ -728,55 +1120,129 @@
2387 }
2388
2389 /******************************************************************//**
2390-Performance schema instrumented wrap function for rw_lock_x_unlock_func()
2391-NOTE! Please use the corresponding macro rw_lock_x_unlock(), not directly
2392-this function! */
2393-UNIV_INLINE
2394-void
2395-pfs_rw_lock_x_unlock_func(
2396-/*======================*/
2397-#ifdef UNIV_SYNC_DEBUG
2398- ulint pass, /*!< in: pass value; != 0, if the
2399- lock may have been passed to another
2400- thread to unlock */
2401-#endif
2402- rw_lock_t* lock) /*!< in/out: rw-lock */
2403-{
2404- /* Inform performance schema we are unlocking the lock */
2405- if (lock->pfs_psi != NULL)
2406- PSI_RWLOCK_CALL(unlock_rwlock)(lock->pfs_psi);
2407-
2408- rw_lock_x_unlock_func(
2409-#ifdef UNIV_SYNC_DEBUG
2410- pass,
2411-#endif
2412- lock);
2413-}
2414-
2415-/******************************************************************//**
2416-Performance schema instrumented wrap function for rw_lock_s_unlock_func()
2417-NOTE! Please use the corresponding macro pfs_rw_lock_s_unlock(), not
2418-directly this function! */
2419-UNIV_INLINE
2420-void
2421-pfs_rw_lock_s_unlock_func(
2422-/*======================*/
2423-#ifdef UNIV_SYNC_DEBUG
2424- ulint pass, /*!< in: pass value; != 0, if the
2425- lock may have been passed to another
2426- thread to unlock */
2427-#endif
2428- rw_lock_t* lock) /*!< in/out: rw-lock */
2429-{
2430- /* Inform performance schema we are unlocking the lock */
2431- if (lock->pfs_psi != NULL)
2432- PSI_RWLOCK_CALL(unlock_rwlock)(lock->pfs_psi);
2433-
2434- rw_lock_s_unlock_func(
2435-#ifdef UNIV_SYNC_DEBUG
2436- pass,
2437-#endif
2438- lock);
2439-
2440-}
2441+Performance schema instrumented wrap function for rw_lock_s_lock_func()
2442+NOTE! Please use the corresponding macro rw_lock_s_lock(), not
2443+directly this function!
2444+@return TRUE if success */
2445+UNIV_INLINE
2446+ibool
2447+pfs_rw_lock_s_lock_low(
2448+/*===================*/
2449+ prio_rw_lock_t* lock, /*!< in: pointer to rw-lock */
2450+ ulint pass, /*!< in: pass value; != 0, if the
2451+ lock will be passed to another
2452+ thread to unlock */
2453+ const char* file_name, /*!< in: file name where lock requested */
2454+ ulint line) /*!< in: line where requested */
2455+{
2456+ return(pfs_rw_lock_s_lock_low(&lock->base_lock, pass,
2457+ file_name, line));
2458+}
2459+
2460+/******************************************************************//**
2461+Performance schema instrumented wrap function for rw_lock_x_unlock_func()
2462+NOTE! Please use the corresponding macro rw_lock_x_unlock(), not directly
2463+this function! */
2464+UNIV_INLINE
2465+void
2466+pfs_rw_lock_x_unlock_func(
2467+/*======================*/
2468+#ifdef UNIV_SYNC_DEBUG
2469+ ulint pass, /*!< in: pass value; != 0, if the
2470+ lock may have been passed to another
2471+ thread to unlock */
2472+#endif
2473+ rw_lock_t* lock) /*!< in/out: rw-lock */
2474+{
2475+ /* Inform performance schema we are unlocking the lock */
2476+ if (lock->pfs_psi != NULL)
2477+ PSI_RWLOCK_CALL(unlock_rwlock)(lock->pfs_psi);
2478+
2479+ rw_lock_x_unlock_func(
2480+#ifdef UNIV_SYNC_DEBUG
2481+ pass,
2482+#endif
2483+ lock);
2484+}
2485+
2486+/******************************************************************//**
2487+Performance schema instrumented wrap function for rw_lock_x_unlock_func()
2488+NOTE! Please use the corresponding macro rw_lock_x_unlock(), not directly
2489+this function! */
2490+UNIV_INLINE
2491+void
2492+pfs_rw_lock_x_unlock_func(
2493+/*======================*/
2494+#ifdef UNIV_SYNC_DEBUG
2495+ ulint pass, /*!< in: pass value; != 0, if the
2496+ lock may have been passed to another
2497+ thread to unlock */
2498+#endif
2499+ prio_rw_lock_t* lock) /*!< in/out: rw-lock */
2500+{
2501+ /* Inform performance schema we are unlocking the lock */
2502+ if (lock->base_lock.pfs_psi != NULL)
2503+ PSI_RWLOCK_CALL(unlock_rwlock)(lock->base_lock.pfs_psi);
2504+
2505+ rw_lock_x_unlock_func(
2506+#ifdef UNIV_SYNC_DEBUG
2507+ pass,
2508+#endif
2509+ lock);
2510+}
2511+
2512+/******************************************************************//**
2513+Performance schema instrumented wrap function for rw_lock_s_unlock_func()
2514+NOTE! Please use the corresponding macro pfs_rw_lock_s_unlock(), not
2515+directly this function! */
2516+UNIV_INLINE
2517+void
2518+pfs_rw_lock_s_unlock_func(
2519+/*======================*/
2520+#ifdef UNIV_SYNC_DEBUG
2521+ ulint pass, /*!< in: pass value; != 0, if the
2522+ lock may have been passed to another
2523+ thread to unlock */
2524+#endif
2525+ rw_lock_t* lock) /*!< in/out: rw-lock */
2526+{
2527+ /* Inform performance schema we are unlocking the lock */
2528+ if (lock->pfs_psi != NULL)
2529+ PSI_RWLOCK_CALL(unlock_rwlock)(lock->pfs_psi);
2530+
2531+ rw_lock_s_unlock_func(
2532+#ifdef UNIV_SYNC_DEBUG
2533+ pass,
2534+#endif
2535+ lock);
2536+
2537+}
2538+
2539+/******************************************************************//**
2540+Performance schema instrumented wrap function for rw_lock_s_unlock_func()
2541+NOTE! Please use the corresponding macro pfs_rw_lock_s_unlock(), not
2542+directly this function! */
2543+UNIV_INLINE
2544+void
2545+pfs_rw_lock_s_unlock_func(
2546+/*======================*/
2547+#ifdef UNIV_SYNC_DEBUG
2548+ ulint pass, /*!< in: pass value; != 0, if the
2549+ lock may have been passed to another
2550+ thread to unlock */
2551+#endif
2552+ prio_rw_lock_t* lock) /*!< in/out: rw-lock */
2553+{
2554+ /* Inform performance schema we are unlocking the lock */
2555+ if (lock->base_lock.pfs_psi != NULL)
2556+ PSI_RWLOCK_CALL(unlock_rwlock)(lock->base_lock.pfs_psi);
2557+
2558+ rw_lock_s_unlock_func(
2559+#ifdef UNIV_SYNC_DEBUG
2560+ pass,
2561+#endif
2562+ lock);
2563+
2564+}
2565+
2566 #endif /* UNIV_PFS_RWLOCK */
2567
2568=== modified file 'Percona-Server/storage/innobase/include/sync0sync.h'
2569--- Percona-Server/storage/innobase/include/sync0sync.h 2013-09-20 05:27:28 +0000
2570+++ Percona-Server/storage/innobase/include/sync0sync.h 2013-09-26 14:59:13 +0000
2571@@ -160,6 +160,8 @@
2572
2573 mutex_create
2574 mutex_enter
2575+mutex_enter_first
2576+mutex_enter_last
2577 mutex_exit
2578 mutex_enter_nowait
2579 mutex_free
2580@@ -195,6 +197,12 @@
2581 # define mutex_enter_nowait(M) \
2582 pfs_mutex_enter_nowait_func((M), __FILE__, __LINE__)
2583
2584+# define mutex_enter_first(M) \
2585+ pfs_mutex_enter_func((M), __FILE__, __LINE__, HIGH_PRIO)
2586+
2587+# define mutex_enter_last(M) \
2588+ pfs_mutex_enter_func((M), __FILE__, __LINE__, LOW_PRIO)
2589+
2590 # define mutex_exit(M) pfs_mutex_exit_func(M)
2591
2592 # define mutex_free(M) pfs_mutex_free_func(M)
2593@@ -221,6 +229,12 @@
2594 # define mutex_enter_nowait(M) \
2595 mutex_enter_nowait_func((M), __FILE__, __LINE__)
2596
2597+# define mutex_enter_first(M) \
2598+ mutex_enter_func((M), __FILE__, __LINE__, HIGH_PRIO)
2599+
2600+# define mutex_enter_last(M) \
2601+ mutex_enter_func((M), __FILE__, __LINE__, LOW_PRIO)
2602+
2603 # define mutex_exit(M) mutex_exit_func(M)
2604
2605 # define mutex_free(M) mutex_free_func(M)
2606@@ -247,6 +261,26 @@
2607 const char* cmutex_name); /*!< in: mutex name */
2608
2609 /******************************************************************//**
2610+Creates, or rather, initializes a priority mutex object in a specified memory
2611+location (which must be appropriately aligned). The mutex is initialized
2612+in the reset state. Explicit freeing of the mutex with mutex_free is
2613+necessary only if the memory block containing it is freed. */
2614+UNIV_INTERN
2615+void
2616+mutex_create_func(
2617+/*==============*/
2618+ ib_prio_mutex_t* mutex, /*!< in: pointer to memory */
2619+#ifdef UNIV_DEBUG
2620+# ifdef UNIV_SYNC_DEBUG
2621+ ulint level, /*!< in: level */
2622+# endif /* UNIV_SYNC_DEBUG */
2623+ const char* cfile_name, /*!< in: file name where
2624+ created */
2625+ ulint cline, /*!< in: file line where
2626+ created */
2627+#endif /* UNIV_DEBUG */
2628+ const char* cmutex_name); /*!< in: mutex name */
2629+/******************************************************************//**
2630 NOTE! Use the corresponding macro mutex_free(), not directly this function!
2631 Calling this function is obligatory only if the memory buffer containing
2632 the mutex is freed. Removes a mutex object from the mutex list. The mutex
2633@@ -256,6 +290,16 @@
2634 mutex_free_func(
2635 /*============*/
2636 ib_mutex_t* mutex); /*!< in: mutex */
2637+/******************************************************************//**
2638+NOTE! Use the corresponding macro mutex_free(), not directly this function!
2639+Calling this function is obligatory only if the memory buffer containing
2640+the mutex is freed. Removes a priority mutex object from the mutex list. The
2641+mutex is checked to be in the reset state. */
2642+UNIV_INTERN
2643+void
2644+mutex_free_func(
2645+/*============*/
2646+ ib_prio_mutex_t* mutex); /*!< in: mutex */
2647 /**************************************************************//**
2648 NOTE! The following macro should be used in mutex locking, not the
2649 corresponding function. */
2650@@ -275,6 +319,26 @@
2651 ib_mutex_t* mutex, /*!< in: pointer to mutex */
2652 const char* file_name, /*!< in: file name where locked */
2653 ulint line); /*!< in: line where locked */
2654+/******************************************************************//**
2655+NOTE! Use the corresponding macro in the header file, not this function
2656+directly. Locks a priority mutex for the current thread. If the mutex is
2657+reserved the function spins a preset time (controlled by SYNC_SPIN_ROUNDS)
2658+waiting for the mutex before suspending the thread. If the thread is suspended,
2659+the priority argument value determines the relative order for its wake up. Any
2660+HIGH_PRIO waiters will be woken up before any LOW_PRIO waiters. In case of
2661+DEFAULT_PRIO, the relative priority will be set according to
2662+srv_current_thread_priority. */
2663+UNIV_INLINE
2664+void
2665+mutex_enter_func(
2666+/*=============*/
2667+ ib_prio_mutex_t* mutex, /*!< in: pointer to mutex */
2668+ const char* file_name, /*!< in: file name where
2669+ locked */
2670+ ulint line, /*!< in: line where locked */
2671+ enum ib_sync_priority priority = DEFAULT_PRIO);
2672+ /*!<in: mutex acquisition
2673+ priority */
2674 /********************************************************************//**
2675 NOTE! Use the corresponding macro in the header file, not this function
2676 directly. Tries to lock the mutex for the current thread. If the lock is not
2677@@ -288,6 +352,20 @@
2678 const char* file_name, /*!< in: file name where mutex
2679 requested */
2680 ulint line); /*!< in: line where requested */
2681+/********************************************************************//**
2682+NOTE! Use the corresponding macro in the header file, not this function
2683+directly. Tries to lock the mutex for the current thread. If the lock is not
2684+acquired immediately, returns with return value 1.
2685+@return 0 if succeed, 1 if not */
2686+UNIV_INTERN
2687+ulint
2688+mutex_enter_nowait_func(
2689+/*====================*/
2690+ ib_prio_mutex_t* mutex, /*!< in: pointer to mutex */
2691+ const char* file_name, /*!< in: file name where mutex
2692+ requested */
2693+ ulint line); /*!< in: line where
2694+ requested */
2695 /******************************************************************//**
2696 NOTE! Use the corresponding macro mutex_exit(), not directly this function!
2697 Unlocks a mutex owned by the current thread. */
2698@@ -296,6 +374,14 @@
2699 mutex_exit_func(
2700 /*============*/
2701 ib_mutex_t* mutex); /*!< in: pointer to mutex */
2702+/******************************************************************//**
2703+NOTE! Use the corresponding macro mutex_exit(), not directly this function!
2704+Unlocks a priority mutex owned by the current thread. */
2705+UNIV_INLINE
2706+void
2707+mutex_exit_func(
2708+/*============*/
2709+ ib_prio_mutex_t* mutex); /*!< in: pointer to mutex */
2710
2711
2712 #ifdef UNIV_PFS_MUTEX
2713@@ -320,6 +406,29 @@
2714 # endif /* UNIV_DEBUG */
2715 const char* cmutex_name);
2716 /******************************************************************//**
2717+NOTE! Please use the corresponding macro mutex_create(), not directly
2718+this function!
2719+A wrapper function for mutex_create_func(), registers the mutex
2720+with peformance schema if "UNIV_PFS_MUTEX" is defined when
2721+creating the performance mutex */
2722+UNIV_INLINE
2723+void
2724+pfs_mutex_create_func(
2725+/*==================*/
2726+ PSI_mutex_key key, /*!< in: Performance Schema
2727+ key */
2728+ ib_prio_mutex_t* mutex, /*!< in: pointer to memory */
2729+# ifdef UNIV_DEBUG
2730+# ifdef UNIV_SYNC_DEBUG
2731+ ulint level, /*!< in: level */
2732+# endif /* UNIV_SYNC_DEBUG */
2733+ const char* cfile_name, /*!< in: file name where
2734+ created */
2735+ ulint cline, /*!< in: file line where
2736+ created */
2737+# endif /* UNIV_DEBUG */
2738+ const char* cmutex_name);
2739+/******************************************************************//**
2740 NOTE! Please use the corresponding macro mutex_enter(), not directly
2741 this function!
2742 This is a performance schema instrumented wrapper function for
2743@@ -331,6 +440,22 @@
2744 ib_mutex_t* mutex, /*!< in: pointer to mutex */
2745 const char* file_name, /*!< in: file name where locked */
2746 ulint line); /*!< in: line where locked */
2747+/******************************************************************//**
2748+NOTE! Please use the corresponding macro mutex_enter(), not directly
2749+this function!
2750+This is a performance schema instrumented wrapper function for
2751+mutex_enter_func(). */
2752+UNIV_INLINE
2753+void
2754+pfs_mutex_enter_func(
2755+/*=================*/
2756+ ib_prio_mutex_t* mutex, /*!< in: pointer to mutex */
2757+ const char* file_name, /*!< in: file name where
2758+ locked */
2759+ ulint line, /*!< in: line where locked */
2760+ enum ib_sync_priority priority = DEFAULT_PRIO);
2761+ /*!<in: mutex acquisition
2762+ priority */
2763 /********************************************************************//**
2764 NOTE! Please use the corresponding macro mutex_enter_nowait(), not directly
2765 this function!
2766@@ -345,6 +470,21 @@
2767 const char* file_name, /*!< in: file name where mutex
2768 requested */
2769 ulint line); /*!< in: line where requested */
2770+/********************************************************************//**
2771+NOTE! Please use the corresponding macro mutex_enter_nowait(), not directly
2772+this function!
2773+This is a performance schema instrumented wrapper function for
2774+mutex_enter_nowait_func.
2775+@return 0 if succeed, 1 if not */
2776+UNIV_INLINE
2777+ulint
2778+pfs_mutex_enter_nowait_func(
2779+/*========================*/
2780+ ib_prio_mutex_t* mutex, /*!< in: pointer to mutex */
2781+ const char* file_name, /*!< in: file name where mutex
2782+ requested */
2783+ ulint line); /*!< in: line where
2784+ requested */
2785 /******************************************************************//**
2786 NOTE! Please use the corresponding macro mutex_exit(), not directly
2787 this function!
2788@@ -355,6 +495,16 @@
2789 pfs_mutex_exit_func(
2790 /*================*/
2791 ib_mutex_t* mutex); /*!< in: pointer to mutex */
2792+/******************************************************************//**
2793+NOTE! Please use the corresponding macro mutex_exit(), not directly
2794+this function!
2795+A wrap function of mutex_exit_func() with peformance schema instrumentation.
2796+Unlocks a priority mutex owned by the current thread. */
2797+UNIV_INLINE
2798+void
2799+pfs_mutex_exit_func(
2800+/*================*/
2801+ ib_prio_mutex_t* mutex); /*!< in: pointer to mutex */
2802
2803 /******************************************************************//**
2804 NOTE! Please use the corresponding macro mutex_free(), not directly
2805@@ -366,6 +516,16 @@
2806 pfs_mutex_free_func(
2807 /*================*/
2808 ib_mutex_t* mutex); /*!< in: mutex */
2809+/******************************************************************//**
2810+NOTE! Please use the corresponding macro mutex_free(), not directly
2811+this function!
2812+Wrapper function for mutex_free_func(). Also destroys the performance
2813+schema probes when freeing the priority mutex */
2814+UNIV_INLINE
2815+void
2816+pfs_mutex_free_func(
2817+/*================*/
2818+ ib_prio_mutex_t* mutex); /*!< in: mutex */
2819
2820 #endif /* UNIV_PFS_MUTEX */
2821
2822@@ -414,6 +574,16 @@
2823 /*======*/
2824 const ib_mutex_t* mutex) /*!< in: mutex */
2825 __attribute__((warn_unused_result));
2826+/******************************************************************//**
2827+Checks that the current thread owns the priority mutex. Works only
2828+in the debug version.
2829+@return TRUE if owns */
2830+UNIV_INTERN
2831+ibool
2832+mutex_own(
2833+/*======*/
2834+ const ib_prio_mutex_t* mutex) /*!< in: priority mutex */
2835+ __attribute__((warn_unused_result));
2836 #endif /* UNIV_DEBUG */
2837 #ifdef UNIV_SYNC_DEBUG
2838 /******************************************************************//**
2839@@ -748,6 +918,9 @@
2840 #define RW_LOCK_SHARED 352
2841 #define RW_LOCK_WAIT_EX 353
2842 #define SYNC_MUTEX 354
2843+#define SYNC_PRIO_MUTEX 355
2844+#define PRIO_RW_LOCK_EX 356
2845+#define PRIO_RW_LOCK_SHARED 357
2846
2847 /* NOTE! The structure appears here only for the compiler to know its size.
2848 Do not use its fields directly! The structure used in the spin lock
2849@@ -798,6 +971,20 @@
2850 #endif
2851 };
2852
2853+/** XtraDB priority mutex */
2854+struct ib_prio_mutex_t {
2855+ ib_mutex_t base_mutex; /* The regular mutex provides the lock
2856+ word etc. for the priority mutex */
2857+ os_event_t high_priority_event; /* High priority wait array
2858+ event */
2859+ volatile ulint high_priority_waiters; /* Set to 1 if there are (or
2860+ may be) threads that asked for this
2861+ mutex to be acquired with high priority
2862+ in the global wait array for this mutex
2863+ to be released. Otherwise, this is
2864+ 0. */
2865+};
2866+
2867 /** Constant determining how long spin wait is continued before suspending
2868 the thread. A value 600 rounds on a 1995 100 MHz Pentium seems to correspond
2869 to 20 microseconds. */
2870
2871=== modified file 'Percona-Server/storage/innobase/include/sync0sync.ic'
2872--- Percona-Server/storage/innobase/include/sync0sync.ic 2013-08-06 15:16:34 +0000
2873+++ Percona-Server/storage/innobase/include/sync0sync.ic 2013-09-26 14:59:13 +0000
2874@@ -39,14 +39,17 @@
2875 ib_mutex_t* mutex, /*!< in: mutex */
2876 ulint n); /*!< in: value to set */
2877 /******************************************************************//**
2878-Reserves a mutex for the current thread. If the mutex is reserved, the
2879-function spins a preset time (controlled by SYNC_SPIN_ROUNDS) waiting
2880-for the mutex before suspending the thread. */
2881+Reserves a mutex or a priority mutex for the current thread. If the mutex is
2882+reserved, the function spins a preset time (controlled by SYNC_SPIN_ROUNDS)
2883+waiting for the mutex before suspending the thread. */
2884 UNIV_INTERN
2885 void
2886 mutex_spin_wait(
2887 /*============*/
2888- ib_mutex_t* mutex, /*!< in: pointer to mutex */
2889+ void* _mutex, /*!< in: pointer to mutex */
2890+ bool high_priority, /*!< in: whether the mutex is a
2891+ priority mutex with high priority
2892+ specified */
2893 const char* file_name, /*!< in: file name where mutex
2894 requested */
2895 ulint line); /*!< in: line where requested */
2896@@ -192,6 +195,55 @@
2897 }
2898
2899 /******************************************************************//**
2900+NOTE! Use the corresponding macro mutex_exit(), not directly this function!
2901+Unlocks a priority mutex owned by the current thread. */
2902+UNIV_INLINE
2903+void
2904+mutex_exit_func(
2905+/*============*/
2906+ ib_prio_mutex_t* mutex) /*!< in: pointer to mutex */
2907+{
2908+ ut_ad(mutex_own(mutex));
2909+
2910+ ut_d(mutex->base_mutex.thread_id = (os_thread_id_t) ULINT_UNDEFINED);
2911+
2912+#ifdef UNIV_SYNC_DEBUG
2913+ sync_thread_reset_level(&mutex->base_mutex);
2914+#endif
2915+ mutex_reset_lock_word(&mutex->base_mutex);
2916+
2917+ /* A problem: we assume that mutex_reset_lock word
2918+ is a memory barrier, that is when we read the waiters
2919+ field next, the read must be serialized in memory
2920+ after the reset. A speculative processor might
2921+ perform the read first, which could leave a waiting
2922+ thread hanging indefinitely.
2923+
2924+ Our current solution call every second
2925+ sync_arr_wake_threads_if_sema_free()
2926+ to wake up possible hanging threads if
2927+ they are missed in mutex_signal_object. */
2928+
2929+ /* Wake up any high priority waiters first. */
2930+ if (mutex->high_priority_waiters != 0) {
2931+
2932+ mutex->high_priority_waiters = 0;
2933+ os_event_set(mutex->high_priority_event);
2934+ sync_array_object_signalled();
2935+
2936+ } else if (mutex_get_waiters(&mutex->base_mutex) != 0) {
2937+
2938+ mutex_signal_object(&mutex->base_mutex);
2939+ }
2940+
2941+#ifdef UNIV_SYNC_PERF_STAT
2942+ mutex_exit_count++;
2943+#endif
2944+
2945+}
2946+
2947+
2948+/******************************************************************//**
2949 Locks a mutex for the current thread. If the mutex is reserved, the function
2950 spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting for the mutex
2951 before suspending the thread. */
2952@@ -217,8 +269,54 @@
2953 return; /* Succeeded! */
2954 }
2955
2956- mutex_spin_wait(mutex, file_name, line);
2957-}
2958+ mutex_spin_wait(mutex, false, file_name, line);
2959+}
2960+
2961+/******************************************************************//**
2962+NOTE! Use the corresponding macro in the header file, not this function
2963+directly. Locks a priority mutex for the current thread. If the mutex is
2964+reserved the function spins a preset time (controlled by SYNC_SPIN_ROUNDS)
2965+waiting for the mutex before suspending the thread. If the thread is suspended,
2966+the priority argument value determines the relative order for its wake up. Any
2967+HIGH_PRIO waiters will be woken up before any LOW_PRIO waiters. In case of
2968+DEFAULT_PRIO, the relative priority will be set according to
2969+srv_current_thread_priority. */
2970+UNIV_INLINE
2971+void
2972+mutex_enter_func(
2973+/*=============*/
2974+ ib_prio_mutex_t* mutex, /*!< in: pointer to mutex */
2975+ const char* file_name, /*!< in: file name where
2976+ locked */
2977+ ulint line, /*!< in: line where locked */
2978+ enum ib_sync_priority priority)
2979+ /*!<in: mutex acquisition
2980+ priority */
2981+{
2982+ bool high_priority;
2983+
2984+ ut_ad(mutex_validate(&mutex->base_mutex));
2985+ ut_ad(!mutex_own(mutex));
2986+
2987+ /* Note that we do not peek at the value of lock_word before trying
2988+ the atomic test_and_set; we could peek, and possibly save time. */
2989+
2990+ if (!ib_mutex_test_and_set(&mutex->base_mutex)) {
2991+ ut_d(mutex->base_mutex.thread_id = os_thread_get_curr_id());
2992+#ifdef UNIV_SYNC_DEBUG
2993+ mutex_set_debug_info(&mutex->base_mutex, file_name, line);
2994+#endif
2995+ return; /* Succeeded! */
2996+ }
2997+
2998+ if (UNIV_LIKELY(priority == DEFAULT_PRIO)) {
2999+ high_priority = srv_current_thread_priority;
3000+ } else {
3001+ high_priority = (priority == HIGH_PRIO);
3002+ }
3003+ mutex_spin_wait(mutex, high_priority, file_name, line);
3004+}
3005+
3006
3007 #ifdef UNIV_PFS_MUTEX
3008 /******************************************************************//**
3009@@ -252,6 +350,40 @@
3010 }
3011 }
3012
3013+/******************************************************************//**
3014+NOTE! Please use the corresponding macro mutex_enter(), not directly
3015+this function!
3016+This is a performance schema instrumented wrapper function for
3017+mutex_enter_func(). */
3018+UNIV_INLINE
3019+void
3020+pfs_mutex_enter_func(
3021+/*=================*/
3022+ ib_prio_mutex_t* mutex, /*!< in: pointer to mutex */
3023+ const char* file_name, /*!< in: file name where
3024+ locked */
3025+ ulint line, /*!< in: line where locked */
3026+ enum ib_sync_priority priority) /*!<in: mutex acquisition
3027+ priority */
3028+{
3029+ if (mutex->base_mutex.pfs_psi != NULL) {
3030+ PSI_mutex_locker* locker;
3031+ PSI_mutex_locker_state state;
3032+
3033+ locker = PSI_MUTEX_CALL(start_mutex_wait)(
3034+ &state, mutex->base_mutex.pfs_psi,
3035+ PSI_MUTEX_LOCK, file_name, line);
3036+
3037+ mutex_enter_func(mutex, file_name, line, priority);
3038+
3039+ if (locker != NULL) {
3040+ PSI_MUTEX_CALL(end_mutex_wait)(locker, 0);
3041+ }
3042+ } else {
3043+ mutex_enter_func(mutex, file_name, line, priority);
3044+ }
3045+}
3046+
3047 /********************************************************************//**
3048 NOTE! Please use the corresponding macro mutex_enter_nowait(), not directly
3049 this function!
3050@@ -289,6 +421,26 @@
3051 return(ret);
3052 }
3053
3054+/********************************************************************//**
3055+NOTE! Please use the corresponding macro mutex_enter_nowait(), not directly
3056+this function!
3057+This is a performance schema instrumented wrapper function for
3058+mutex_enter_nowait_func.
3059+@return 0 if succeed, 1 if not */
3060+UNIV_INLINE
3061+ulint
3062+pfs_mutex_enter_nowait_func(
3063+/*========================*/
3064+ ib_prio_mutex_t* mutex, /*!< in: pointer to mutex */
3065+ const char* file_name, /*!< in: file name where mutex
3066+ requested */
3067+ ulint line) /*!< in: line where
3068+ requested */
3069+{
3070+ return pfs_mutex_enter_nowait_func(&mutex->base_mutex, file_name,
3071+ line);
3072+}
3073+
3074 /******************************************************************//**
3075 NOTE! Please use the corresponding macro mutex_exit(), not directly
3076 this function!
3077@@ -308,6 +460,25 @@
3078 }
3079
3080 /******************************************************************//**
3081+NOTE! Please use the corresponding macro mutex_exit(), not directly
3082+this function!
3083+A wrap function of mutex_exit_func() with peformance schema instrumentation.
3084+Unlocks a priority mutex owned by the current thread. */
3085+UNIV_INLINE
3086+void
3087+pfs_mutex_exit_func(
3088+/*================*/
3089+ ib_prio_mutex_t* mutex) /*!< in: pointer to mutex */
3090+{
3091+ if (mutex->base_mutex.pfs_psi != NULL) {
3092+ PSI_MUTEX_CALL(unlock_mutex)(mutex->base_mutex.pfs_psi);
3093+ }
3094+
3095+ mutex_exit_func(mutex);
3096+}
3097+
3098+
3099+/******************************************************************//**
3100 NOTE! Please use the corresponding macro mutex_create(), not directly
3101 this function!
3102 A wrapper function for mutex_create_func(), registers the mutex
3103@@ -342,6 +513,44 @@
3104 }
3105
3106 /******************************************************************//**
3107+NOTE! Please use the corresponding macro mutex_create(), not directly
3108+this function!
3109+A wrapper function for mutex_create_func(), registers the mutex
3110+with peformance schema if "UNIV_PFS_MUTEX" is defined when
3111+creating the performance mutex */
3112+UNIV_INLINE
3113+void
3114+pfs_mutex_create_func(
3115+/*==================*/
3116+ PSI_mutex_key key, /*!< in: Performance Schema
3117+ key */
3118+ ib_prio_mutex_t* mutex, /*!< in: pointer to memory */
3119+# ifdef UNIV_DEBUG
3120+# ifdef UNIV_SYNC_DEBUG
3121+ ulint level, /*!< in: level */
3122+# endif /* UNIV_SYNC_DEBUG */
3123+ const char* cfile_name, /*!< in: file name where
3124+ created */
3125+ ulint cline, /*!< in: file line where
3126+ created */
3127+# endif /* UNIV_DEBUG */
3128+ const char* cmutex_name)
3129+{
3130+ mutex->base_mutex.pfs_psi = PSI_MUTEX_CALL(init_mutex)(key, mutex);
3131+
3132+ mutex_create_func(mutex,
3133+# ifdef UNIV_DEBUG
3134+# ifdef UNIV_SYNC_DEBUG
3135+ level,
3136+# endif /* UNIV_SYNC_DEBUG */
3137+ cfile_name,
3138+ cline,
3139+# endif /* UNIV_DEBUG */
3140+ cmutex_name);
3141+}
3142+
3143+
3144+/******************************************************************//**
3145 NOTE! Please use the corresponding macro mutex_free(), not directly
3146 this function!
3147 Wrapper function for mutex_free_func(). Also destroys the performance
3148@@ -360,6 +569,26 @@
3149 mutex_free_func(mutex);
3150 }
3151
3152+/******************************************************************//**
3153+NOTE! Please use the corresponding macro mutex_free(), not directly
3154+this function!
3155+Wrapper function for mutex_free_func(). Also destroys the performance
3156+schema probes when freeing the priority mutex */
3157+UNIV_INLINE
3158+void
3159+pfs_mutex_free_func(
3160+/*================*/
3161+ ib_prio_mutex_t* mutex) /*!< in: mutex */
3162+{
3163+ if (mutex->base_mutex.pfs_psi != NULL) {
3164+ PSI_MUTEX_CALL(destroy_mutex)(mutex->base_mutex.pfs_psi);
3165+ mutex->base_mutex.pfs_psi = NULL;
3166+ }
3167+
3168+ mutex_free_func(mutex);
3169+}
3170+
3171+
3172 #endif /* UNIV_PFS_MUTEX */
3173
3174 #ifndef HAVE_ATOMIC_BUILTINS
3175
3176=== modified file 'Percona-Server/storage/innobase/include/sync0types.h'
3177--- Percona-Server/storage/innobase/include/sync0types.h 2013-08-06 15:16:34 +0000
3178+++ Percona-Server/storage/innobase/include/sync0types.h 2013-09-26 14:59:13 +0000
3179@@ -28,4 +28,17 @@
3180
3181 struct ib_mutex_t;
3182
3183+/* The relative priority of the current thread. If 0, low priority; if 1, high
3184+priority. */
3185+extern UNIV_THREAD_LOCAL ulint srv_current_thread_priority;
3186+
3187+struct ib_prio_mutex_t;
3188+
3189+/** Priority mutex and rwlatch acquisition priorities */
3190+enum ib_sync_priority {
3191+ DEFAULT_PRIO,
3192+ LOW_PRIO,
3193+ HIGH_PRIO
3194+};
3195+
3196 #endif
3197
3198=== modified file 'Percona-Server/storage/innobase/include/trx0purge.h'
3199--- Percona-Server/storage/innobase/include/trx0purge.h 2013-08-06 15:16:34 +0000
3200+++ Percona-Server/storage/innobase/include/trx0purge.h 2013-09-26 14:59:13 +0000
3201@@ -138,7 +138,7 @@
3202 purge query: this trx is not in the
3203 trx list of the trx system and it
3204 never ends */
3205- rw_lock_t latch; /*!< The latch protecting the purge
3206+ prio_rw_lock_t latch; /*!< The latch protecting the purge
3207 view. A purge operation must acquire an
3208 x-latch here for the instant at which
3209 it changes the purge view: an undo
3210
3211=== modified file 'Percona-Server/storage/innobase/include/trx0trx.h'
3212--- Percona-Server/storage/innobase/include/trx0trx.h 2013-09-02 10:01:38 +0000
3213+++ Percona-Server/storage/innobase/include/trx0trx.h 2013-09-26 14:59:13 +0000
3214@@ -1138,7 +1138,7 @@
3215
3216 Bear in mind (3) and (4) when using the hash index.
3217 */
3218-extern rw_lock_t* btr_search_latch_arr;
3219+extern prio_rw_lock_t* btr_search_latch_arr;
3220
3221 #ifndef UNIV_NONINL
3222 #include "trx0trx.ic"
3223
3224=== modified file 'Percona-Server/storage/innobase/include/univ.i'
3225--- Percona-Server/storage/innobase/include/univ.i 2013-08-29 17:05:40 +0000
3226+++ Percona-Server/storage/innobase/include/univ.i 2013-09-26 14:59:13 +0000
3227@@ -277,6 +277,13 @@
3228 # define UNIV_COLD /* empty */
3229 #endif
3230
3231+#ifdef UNIV_LINUX
3232+# define UNIV_THREAD_LOCAL __thread
3233+#else
3234+/* FIXME: the TLS variables are silently broken on other platforms for now */
3235+# define UNIV_THREAD_LOCAL
3236+#endif
3237+
3238 #ifndef UNIV_MUST_NOT_INLINE
3239 /* Definition for inline version */
3240
3241
3242=== modified file 'Percona-Server/storage/innobase/mtr/mtr0mtr.cc'
3243--- Percona-Server/storage/innobase/mtr/mtr0mtr.cc 2013-06-25 13:13:06 +0000
3244+++ Percona-Server/storage/innobase/mtr/mtr0mtr.cc 2013-09-26 14:59:13 +0000
3245@@ -82,10 +82,10 @@
3246 buf_page_release((buf_block_t*) object, slot->type);
3247 break;
3248 case MTR_MEMO_S_LOCK:
3249- rw_lock_s_unlock((rw_lock_t*) object);
3250+ rw_lock_s_unlock((prio_rw_lock_t*) object);
3251 break;
3252 case MTR_MEMO_X_LOCK:
3253- rw_lock_x_unlock((rw_lock_t*) object);
3254+ rw_lock_x_unlock((prio_rw_lock_t*) object);
3255 break;
3256 #ifdef UNIV_DEBUG
3257 default:
3258
3259=== modified file 'Percona-Server/storage/innobase/srv/srv0srv.cc'
3260--- Percona-Server/storage/innobase/srv/srv0srv.cc 2013-09-24 13:11:08 +0000
3261+++ Percona-Server/storage/innobase/srv/srv0srv.cc 2013-09-26 14:59:13 +0000
3262@@ -319,6 +319,22 @@
3263 /* Number of iterations over which adaptive flushing is averaged. */
3264 UNIV_INTERN ulong srv_flushing_avg_loops = 30;
3265
3266+/* The relative priority of the current thread. If 0, low priority; if 1, high
3267+priority. */
3268+UNIV_INTERN UNIV_THREAD_LOCAL ulint srv_current_thread_priority = 0;
3269+
3270+/* The relative priority of the purge coordinator and worker threads. */
3271+UNIV_INTERN my_bool srv_purge_thread_priority = FALSE;
3272+
3273+/* The relative priority of the I/O threads. */
3274+UNIV_INTERN my_bool srv_io_thread_priority = FALSE;
3275+
3276+/* The relative priority of the cleaner thread. */
3277+UNIV_INTERN my_bool srv_cleaner_thread_priority = FALSE;
3278+
3279+/* The relative priority of the master thread. */
3280+UNIV_INTERN my_bool srv_master_thread_priority = FALSE;
3281+
3282 /* The number of purge threads to use.*/
3283 UNIV_INTERN ulong srv_n_purge_threads = 1;
3284
3285@@ -2863,6 +2879,8 @@
3286
3287 MONITOR_INC(MONITOR_MASTER_THREAD_SLEEP);
3288
3289+ srv_current_thread_priority = srv_master_thread_priority;
3290+
3291 if (srv_check_activity(old_activity_count)) {
3292 old_activity_count = srv_get_activity_count();
3293 srv_master_do_active_tasks();
3294@@ -3003,6 +3021,8 @@
3295
3296 os_event_wait(slot->event);
3297
3298+ srv_current_thread_priority = srv_purge_thread_priority;
3299+
3300 if (srv_task_execute()) {
3301
3302 /* If there are tasks in the queue, wakeup
3303@@ -3279,6 +3299,8 @@
3304
3305 n_total_purged = 0;
3306
3307+ srv_current_thread_priority = srv_purge_thread_priority;
3308+
3309 rseg_history_len = srv_do_purge(
3310 srv_n_purge_threads, &n_total_purged);
3311
3312
3313=== modified file 'Percona-Server/storage/innobase/srv/srv0start.cc'
3314--- Percona-Server/storage/innobase/srv/srv0start.cc 2013-08-14 03:57:21 +0000
3315+++ Percona-Server/storage/innobase/srv/srv0start.cc 2013-09-26 14:59:13 +0000
3316@@ -476,6 +476,7 @@
3317 #endif /* UNIV_PFS_THREAD */
3318
3319 while (srv_shutdown_state != SRV_SHUTDOWN_EXIT_THREADS) {
3320+ srv_current_thread_priority = srv_io_thread_priority;
3321 fil_aio_wait(segment);
3322 }
3323
3324
3325=== modified file 'Percona-Server/storage/innobase/sync/sync0arr.cc'
3326--- Percona-Server/storage/innobase/sync/sync0arr.cc 2013-08-14 03:57:21 +0000
3327+++ Percona-Server/storage/innobase/sync/sync0arr.cc 2013-09-26 14:59:13 +0000
3328@@ -83,10 +83,11 @@
3329 void* wait_object; /*!< pointer to the object the
3330 thread is waiting for; if NULL
3331 the cell is free for use */
3332- ib_mutex_t* old_wait_mutex; /*!< the latest wait mutex in cell */
3333- rw_lock_t* old_wait_rw_lock;
3334- /*!< the latest wait rw-lock
3335- in cell */
3336+ void* old_wait_mutex; /*!< the latest regular or priority
3337+ wait mutex in cell */
3338+ void* old_wait_rw_lock;
3339+ /*!< the latest regular or priority
3340+ wait rw-lock in cell */
3341 ulint request_type; /*!< lock type requested on the
3342 object */
3343 const char* file; /*!< in debug version file where
3344@@ -295,9 +296,19 @@
3345
3346 if (type == SYNC_MUTEX) {
3347 return(((ib_mutex_t*) cell->wait_object)->event);
3348+ } else if (type == SYNC_PRIO_MUTEX) {
3349+ return(((ib_prio_mutex_t*) cell->wait_object)
3350+ ->high_priority_event);
3351 } else if (type == RW_LOCK_WAIT_EX) {
3352 return(((rw_lock_t*) cell->wait_object)->wait_ex_event);
3353+ } else if (type == PRIO_RW_LOCK_SHARED) {
3354+ return(((prio_rw_lock_t *) cell->wait_object)
3355+ ->high_priority_s_event);
3356+ } else if (type == PRIO_RW_LOCK_EX) {
3357+ return(((prio_rw_lock_t *) cell->wait_object)
3358+ ->high_priority_x_event);
3359 } else { /* RW_LOCK_SHARED and RW_LOCK_EX wait on the same event */
3360+ ut_ad(type == RW_LOCK_SHARED || type == RW_LOCK_EX);
3361 return(((rw_lock_t*) cell->wait_object)->event);
3362 }
3363 }
3364@@ -336,12 +347,10 @@
3365 cell->waiting = FALSE;
3366 cell->wait_object = object;
3367
3368- if (type == SYNC_MUTEX) {
3369- cell->old_wait_mutex =
3370- static_cast<ib_mutex_t*>(object);
3371+ if (type == SYNC_MUTEX || type == SYNC_PRIO_MUTEX) {
3372+ cell->old_wait_mutex = object;
3373 } else {
3374- cell->old_wait_rw_lock =
3375- static_cast<rw_lock_t*>(object);
3376+ cell->old_wait_rw_lock = object;
3377 }
3378
3379 cell->request_type = type;
3380@@ -436,7 +445,9 @@
3381 sync_cell_t* cell) /*!< in: sync cell */
3382 {
3383 ib_mutex_t* mutex;
3384+ ib_prio_mutex_t* prio_mutex;
3385 rw_lock_t* rwlock;
3386+ prio_rw_lock_t* prio_rwlock = NULL;
3387 ulint type;
3388 ulint writer;
3389
3390@@ -449,10 +460,19 @@
3391 innobase_basename(cell->file), (ulong) cell->line,
3392 difftime(time(NULL), cell->reservation_time));
3393
3394- if (type == SYNC_MUTEX) {
3395+ if (type == SYNC_MUTEX || type == SYNC_PRIO_MUTEX) {
3396 /* We use old_wait_mutex in case the cell has already
3397 been freed meanwhile */
3398- mutex = cell->old_wait_mutex;
3399+ if (type == SYNC_MUTEX) {
3400+
3401+ mutex = static_cast<ib_mutex_t*>(cell->old_wait_mutex);
3402+ } else {
3403+
3404+ prio_mutex = static_cast<ib_prio_mutex_t*>
3405+ (cell->old_wait_mutex);
3406+ mutex = &prio_mutex->base_mutex;
3407+ }
3408+
3409
3410 fprintf(file,
3411 "Mutex at %p '%s', lock var %lu\n"
3412@@ -467,15 +487,38 @@
3413 #endif /* UNIV_SYNC_DEBUG */
3414 (ulong) mutex->waiters);
3415
3416+ if (type == SYNC_PRIO_MUTEX) {
3417+
3418+ fprintf(file,
3419+ "high-priority waiters flag %lu\n",
3420+ (ulong) prio_mutex->high_priority_waiters);
3421+ }
3422+
3423 } else if (type == RW_LOCK_EX
3424 || type == RW_LOCK_WAIT_EX
3425- || type == RW_LOCK_SHARED) {
3426+ || type == RW_LOCK_SHARED
3427+ || type == PRIO_RW_LOCK_SHARED
3428+ || type == PRIO_RW_LOCK_EX) {
3429
3430- fputs(type == RW_LOCK_EX ? "X-lock on"
3431+ fputs((type == RW_LOCK_EX || type == PRIO_RW_LOCK_EX)
3432+ ? "X-lock on"
3433 : type == RW_LOCK_WAIT_EX ? "X-lock (wait_ex) on"
3434 : "S-lock on", file);
3435
3436- rwlock = cell->old_wait_rw_lock;
3437+ /* Currently we are unable to tell high priority
3438+ RW_LOCK_WAIT_EX waiter from a regular priority one. Assume
3439+ it's a regular one. */
3440+ if (type == RW_LOCK_EX || type == RW_LOCK_WAIT_EX
3441+ || type == RW_LOCK_SHARED) {
3442+
3443+ rwlock = static_cast<rw_lock_t *>
3444+ (cell->old_wait_rw_lock);
3445+ } else {
3446+
3447+ prio_rwlock = static_cast<prio_rw_lock_t *>
3448+ (cell->old_wait_rw_lock);
3449+ rwlock = &prio_rwlock->base_lock;
3450+ }
3451
3452 fprintf(file,
3453 " RW-latch at %p '%s'\n",
3454@@ -503,6 +546,15 @@
3455 (ulong) rwlock->last_s_line,
3456 rwlock->last_x_file_name,
3457 (ulong) rwlock->last_x_line);
3458+ if (prio_rwlock) {
3459+ fprintf(stderr, "high priority S waiters flag %lu, "
3460+ "high priority X waiters flag %lu, "
3461+ "wait-exclusive waiter is "
3462+ "high priority if exists: %lu\n",
3463+ prio_rwlock->high_priority_s_waiters,
3464+ prio_rwlock->high_priority_x_waiters,
3465+ prio_rwlock->high_priority_wait_ex_waiter);
3466+ }
3467 } else {
3468 ut_error;
3469 }
3470@@ -615,9 +667,15 @@
3471 return(FALSE); /* No deadlock here */
3472 }
3473
3474- if (cell->request_type == SYNC_MUTEX) {
3475+ if (cell->request_type == SYNC_MUTEX
3476+ || cell->request_type == SYNC_PRIO_MUTEX) {
3477
3478- mutex = static_cast<ib_mutex_t*>(cell->wait_object);
3479+ if (cell->request_type == SYNC_MUTEX) {
3480+ mutex = static_cast<ib_mutex_t*>(cell->wait_object);
3481+ } else {
3482+ mutex = &(static_cast<ib_prio_mutex_t*>(
3483+ cell->wait_object))->base_mutex;
3484+ }
3485
3486 if (mutex_get_lock_word(mutex) != 0) {
3487
3488@@ -647,6 +705,7 @@
3489 return(FALSE); /* No deadlock */
3490
3491 } else if (cell->request_type == RW_LOCK_EX
3492+ || cell->request_type == PRIO_RW_LOCK_EX
3493 || cell->request_type == RW_LOCK_WAIT_EX) {
3494
3495 lock = static_cast<rw_lock_t*>(cell->wait_object);
3496@@ -685,7 +744,8 @@
3497
3498 return(FALSE);
3499
3500- } else if (cell->request_type == RW_LOCK_SHARED) {
3501+ } else if (cell->request_type == RW_LOCK_SHARED
3502+ || cell->request_type == PRIO_RW_LOCK_SHARED) {
3503
3504 lock = static_cast<rw_lock_t*>(cell->wait_object);
3505
3506@@ -734,16 +794,23 @@
3507 ib_mutex_t* mutex;
3508 rw_lock_t* lock;
3509
3510- if (cell->request_type == SYNC_MUTEX) {
3511+ if (cell->request_type == SYNC_MUTEX
3512+ || cell->request_type == SYNC_PRIO_MUTEX) {
3513
3514- mutex = static_cast<ib_mutex_t*>(cell->wait_object);
3515+ if (cell->request_type == SYNC_MUTEX) {
3516+ mutex = static_cast<ib_mutex_t*>(cell->wait_object);
3517+ } else {
3518+ mutex = &(static_cast<ib_prio_mutex_t*>(
3519+ cell->wait_object))->base_mutex;
3520+ }
3521
3522 if (mutex_get_lock_word(mutex) == 0) {
3523
3524 return(TRUE);
3525 }
3526
3527- } else if (cell->request_type == RW_LOCK_EX) {
3528+ } else if (cell->request_type == RW_LOCK_EX
3529+ || cell->request_type == PRIO_RW_LOCK_EX) {
3530
3531 lock = static_cast<rw_lock_t*>(cell->wait_object);
3532
3533@@ -762,7 +829,8 @@
3534
3535 return(TRUE);
3536 }
3537- } else if (cell->request_type == RW_LOCK_SHARED) {
3538+ } else if (cell->request_type == RW_LOCK_SHARED
3539+ || cell->request_type == PRIO_RW_LOCK_SHARED) {
3540 lock = static_cast<rw_lock_t*>(cell->wait_object);
3541
3542 /* lock_word > 0 means no writer or reserved writer */
3543@@ -770,6 +838,9 @@
3544
3545 return(TRUE);
3546 }
3547+ } else {
3548+
3549+ ut_error;
3550 }
3551
3552 return(FALSE);
3553
3554=== modified file 'Percona-Server/storage/innobase/sync/sync0rw.cc'
3555--- Percona-Server/storage/innobase/sync/sync0rw.cc 2013-08-06 15:16:34 +0000
3556+++ Percona-Server/storage/innobase/sync/sync0rw.cc 2013-09-26 14:59:13 +0000
3557@@ -277,6 +277,41 @@
3558 }
3559
3560 /******************************************************************//**
3561+Creates, or rather, initializes a priority rw-lock object in a specified memory
3562+location (which must be appropriately aligned). The rw-lock is initialized
3563+to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free
3564+is necessary only if the memory block containing it is freed. */
3565+UNIV_INTERN
3566+void
3567+rw_lock_create_func(
3568+/*================*/
3569+ prio_rw_lock_t* lock, /*!< in: pointer to memory */
3570+#ifdef UNIV_DEBUG
3571+# ifdef UNIV_SYNC_DEBUG
3572+ ulint level, /*!< in: level */
3573+# endif /* UNIV_SYNC_DEBUG */
3574+ const char* cfile_name, /*!< in: file name where created */
3575+ ulint cline, /*!< in: file line where created */
3576+#endif /* UNIV_DEBUG */
3577+ const char* cmutex_name) /*!< in: mutex name */
3578+{
3579+ rw_lock_create_func(&lock->base_lock,
3580+#ifdef UNIV_DEBUG
3581+# ifdef UNIV_SYNC_DEBUG
3582+ level,
3583+# endif
3584+ cfile_name,
3585+ cline,
3586+#endif
3587+ cmutex_name);
3588+ lock->high_priority_s_waiters = 0;
3589+ lock->high_priority_s_event = os_event_create();
3590+ lock->high_priority_x_waiters = 0;
3591+ lock->high_priority_x_event = os_event_create();
3592+ lock->high_priority_wait_ex_waiter = 0;
3593+}
3594+
3595+/******************************************************************//**
3596 Calling this function is obligatory only if the memory buffer containing
3597 the rw-lock is freed. Removes an rw-lock object from the global list. The
3598 rw-lock is checked to be in the non-locked state. */
3599@@ -321,6 +356,21 @@
3600 #endif /* !INNODB_RW_LOCKS_USE_ATOMICS */
3601 }
3602
3603+/******************************************************************//**
3604+Calling this function is obligatory only if the memory buffer containing
3605+the priority rw-lock is freed. Removes an rw-lock object from the global list.
3606+The rw-lock is checked to be in the non-locked state. */
3607+UNIV_INTERN
3608+void
3609+rw_lock_free_func(
3610+/*==============*/
3611+ prio_rw_lock_t* lock) /*!< in: rw-lock */
3612+{
3613+ os_event_free(lock->high_priority_s_event);
3614+ os_event_free(lock->high_priority_x_event);
3615+ rw_lock_free_func(&lock->base_lock);
3616+}
3617+
3618 #ifdef UNIV_DEBUG
3619 /******************************************************************//**
3620 Checks that the rw-lock has been initialized and that there are no
3621@@ -347,20 +397,41 @@
3622
3623 return(TRUE);
3624 }
3625+
3626+/******************************************************************//**
3627+Checks that the priority rw-lock has been initialized and that there are no
3628+simultaneous shared and exclusive locks.
3629+@return TRUE */
3630+UNIV_INTERN
3631+ibool
3632+rw_lock_validate(
3633+/*=============*/
3634+ prio_rw_lock_t* lock) /*!< in: rw-lock */
3635+{
3636+ ut_ad(lock->high_priority_s_waiters < 2);
3637+ ut_ad(lock->high_priority_x_waiters < 2);
3638+ return(rw_lock_validate(&lock->base_lock));
3639+}
3640+
3641 #endif /* UNIV_DEBUG */
3642
3643 /******************************************************************//**
3644-Lock an rw-lock in shared mode for the current thread. If the rw-lock is
3645-locked in exclusive mode, or there is an exclusive lock request waiting,
3646-the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting
3647-for the lock, before suspending the thread. */
3648+Lock a regular or priority rw-lock in shared mode for the current thread. If
3649+the rw-lock is locked in exclusive mode, or there is an exclusive lock request
3650+waiting, the function spins a preset time (controlled by SYNC_SPIN_ROUNDS),
3651+waiting for the lock, before suspending the thread. */
3652 UNIV_INTERN
3653 void
3654 rw_lock_s_lock_spin(
3655 /*================*/
3656- rw_lock_t* lock, /*!< in: pointer to rw-lock */
3657+ void* _lock, /*!< in: pointer to rw-lock */
3658 ulint pass, /*!< in: pass value; != 0, if the lock
3659 will be passed to another thread to unlock */
3660+ bool priority_lock,
3661+ /*!< in: whether the lock is a priority lock */
3662+ bool high_priority,
3663+ /*!< in: whether we are acquiring a priority
3664+ lock with high priority */
3665 const char* file_name, /*!< in: file name where lock requested */
3666 ulint line) /*!< in: line where requested */
3667 {
3668@@ -368,6 +439,7 @@
3669 ulint i = 0; /* spin round count */
3670 sync_array_t* sync_arr;
3671 size_t counter_index;
3672+ rw_lock_t* lock = (rw_lock_t *) _lock;
3673
3674 /* We reuse the thread id to index into the counter, cache
3675 it here for efficiency. */
3676@@ -379,35 +451,47 @@
3677 rw_lock_stats.rw_s_spin_wait_count.add(counter_index, 1);
3678 lock_loop:
3679
3680- /* Spin waiting for the writer field to become free */
3681- while (i < SYNC_SPIN_ROUNDS && lock->lock_word <= 0) {
3682- if (srv_spin_wait_delay) {
3683- ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
3684- }
3685-
3686- i++;
3687- }
3688-
3689- if (i == SYNC_SPIN_ROUNDS) {
3690+ if (!rw_lock_higher_prio_waiters_exist(priority_lock, high_priority,
3691+ lock)) {
3692+
3693+ /* Spin waiting for the writer field to become free */
3694+ while (i < SYNC_SPIN_ROUNDS && lock->lock_word <= 0) {
3695+ if (srv_spin_wait_delay) {
3696+ ut_delay(ut_rnd_interval(0,
3697+ srv_spin_wait_delay));
3698+ }
3699+
3700+ i++;
3701+ }
3702+
3703+ if (i == SYNC_SPIN_ROUNDS) {
3704+ os_thread_yield();
3705+ }
3706+
3707+ if (srv_print_latch_waits) {
3708+ fprintf(stderr,
3709+ "Thread " ULINTPF " spin wait rw-s-lock at %p"
3710+ " '%s' rnds " ULINTPF "\n",
3711+ os_thread_pf(os_thread_get_curr_id()),
3712+ (void*) lock, lock->lock_name, i);
3713+ }
3714+ } else {
3715+
3716+ /* In case of higher priority waiters already present, perform
3717+ only this part of the spinning code path. */
3718 os_thread_yield();
3719 }
3720
3721- if (srv_print_latch_waits) {
3722- fprintf(stderr,
3723- "Thread " ULINTPF " spin wait rw-s-lock at %p"
3724- " '%s' rnds " ULINTPF "\n",
3725- os_thread_pf(os_thread_get_curr_id()),
3726- (void*) lock, lock->lock_name, i);
3727- }
3728-
3729 /* We try once again to obtain the lock */
3730- if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
3731+ if (!rw_lock_higher_prio_waiters_exist(priority_lock, high_priority,
3732+ lock)
3733+ && (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line))) {
3734 rw_lock_stats.rw_s_spin_round_count.add(counter_index, i);
3735
3736 return; /* Success */
3737 } else {
3738
3739- if (i < SYNC_SPIN_ROUNDS) {
3740+ if (i > 0 && i < SYNC_SPIN_ROUNDS) {
3741 goto lock_loop;
3742 }
3743
3744@@ -416,14 +500,24 @@
3745 sync_arr = sync_array_get();
3746
3747 sync_array_reserve_cell(
3748- sync_arr, lock, RW_LOCK_SHARED,
3749+ sync_arr, lock,
3750+ high_priority ? PRIO_RW_LOCK_SHARED : RW_LOCK_SHARED,
3751 file_name, line, &index);
3752
3753 /* Set waiters before checking lock_word to ensure wake-up
3754 signal is sent. This may lead to some unnecessary signals. */
3755- rw_lock_set_waiter_flag(lock);
3756+ if (high_priority) {
3757+ prio_rw_lock_t* prio_rw_lock
3758+ = (prio_rw_lock_t *) _lock;
3759+ prio_rw_lock->high_priority_s_waiters = 1;
3760+ } else {
3761+ rw_lock_set_waiter_flag(lock);
3762+ }
3763
3764- if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
3765+ if (!rw_lock_higher_prio_waiters_exist(priority_lock,
3766+ high_priority, lock)
3767+ && (TRUE == rw_lock_s_lock_low(lock, pass,
3768+ file_name, line))) {
3769 sync_array_free_cell(sync_arr, index);
3770 return; /* Success */
3771 }
3772@@ -618,7 +712,12 @@
3773 ulint pass, /*!< in: pass value; != 0, if the lock will
3774 be passed to another thread to unlock */
3775 const char* file_name,/*!< in: file name where lock requested */
3776- ulint line) /*!< in: line where requested */
3777+ ulint line, /*!< in: line where requested */
3778+ bool priority_lock,
3779+ /*!< in: whether the lock is a priority lock */
3780+ bool high_priority)
3781+ /*!< in: whether we are acquiring a priority
3782+ lock with high priority */
3783 {
3784 ulint i; /*!< spin round count */
3785 ulint index; /*!< index of the reserved wait cell */
3786@@ -640,12 +739,15 @@
3787
3788 lock_loop:
3789
3790- if (rw_lock_x_lock_low(lock, pass, file_name, line)) {
3791+ if (!rw_lock_higher_prio_waiters_exist(priority_lock, high_priority,
3792+ lock)
3793+ && rw_lock_x_lock_low(lock, pass, file_name, line)) {
3794 rw_lock_stats.rw_x_spin_round_count.add(counter_index, i);
3795
3796 return; /* Locking succeeded */
3797
3798- } else {
3799+ } else if (!rw_lock_higher_prio_waiters_exist(priority_lock,
3800+ high_priority, lock)) {
3801
3802 if (!spinning) {
3803 spinning = TRUE;
3804@@ -669,26 +771,42 @@
3805 } else {
3806 goto lock_loop;
3807 }
3808+ } else {
3809+
3810+ /* In case we skipped spinning because of higher-priority
3811+ waiters already waiting, perform only this bit of the spinning
3812+ code path. */
3813+ os_thread_yield();
3814 }
3815
3816- rw_lock_stats.rw_x_spin_round_count.add(counter_index, i);
3817-
3818- if (srv_print_latch_waits) {
3819- fprintf(stderr,
3820- "Thread " ULINTPF " spin wait rw-x-lock at %p"
3821- " '%s' rnds " ULINTPF "\n",
3822- os_thread_pf(os_thread_get_curr_id()), (void*) lock,
3823- lock->lock_name, i);
3824+ if (spinning) {
3825+
3826+ rw_lock_stats.rw_x_spin_round_count.add(counter_index, i);
3827+
3828+ if (srv_print_latch_waits) {
3829+ fprintf(stderr,
3830+ "Thread " ULINTPF " spin wait rw-x-lock at %p"
3831+ " '%s' rnds " ULINTPF "\n",
3832+ os_thread_pf(os_thread_get_curr_id()),
3833+ (void*) lock,lock->lock_name, i);
3834+ }
3835 }
3836
3837 sync_arr = sync_array_get();
3838
3839 sync_array_reserve_cell(
3840- sync_arr, lock, RW_LOCK_EX, file_name, line, &index);
3841+ sync_arr, lock,
3842+ high_priority ? PRIO_RW_LOCK_EX : RW_LOCK_EX,
3843+ file_name, line, &index);
3844
3845 /* Waiters must be set before checking lock_word, to ensure signal
3846 is sent. This could lead to a few unnecessary wake-up signals. */
3847- rw_lock_set_waiter_flag(lock);
3848+ if (high_priority) {
3849+ prio_rw_lock_t* prio_lock = (prio_rw_lock_t *)lock;
3850+ prio_lock->high_priority_x_waiters = 1;
3851+ } else {
3852+ rw_lock_set_waiter_flag(lock);
3853+ }
3854
3855 if (rw_lock_x_lock_low(lock, pass, file_name, line)) {
3856 sync_array_free_cell(sync_arr, index);
3857@@ -713,6 +831,29 @@
3858 goto lock_loop;
3859 }
3860
3861+/******************************************************************//**
3862+NOTE! Use the corresponding macro, not directly this function! Lock a priority
3863+rw-lock in exclusive mode for the current thread. If the rw-lock is locked
3864+in shared or exclusive mode, or there is an exclusive lock request waiting,
3865+the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting
3866+for the lock, before suspending the thread. If the same thread has an x-lock
3867+on the rw-lock, locking succeed, with the following exception: if pass != 0,
3868+only a single x-lock may be taken on the lock. NOTE: If the same thread has
3869+an s-lock, locking does not succeed! */
3870+UNIV_INTERN
3871+void
3872+rw_lock_x_lock_func(
3873+/*================*/
3874+ prio_rw_lock_t* lock, /*!< in: pointer to rw-lock */
3875+ ulint pass, /*!< in: pass value; != 0, if the lock will
3876+ be passed to another thread to unlock */
3877+ const char* file_name,/*!< in: file name where lock requested */
3878+ ulint line) /*!< in: line where requested */
3879+{
3880+ rw_lock_x_lock_func(&lock->base_lock, pass, file_name, line, true,
3881+ srv_current_thread_priority > 0);
3882+}
3883+
3884 #ifdef UNIV_SYNC_DEBUG
3885 /******************************************************************//**
3886 Acquires the debug mutex. We cannot use the mutex defined in sync0sync,
3887@@ -881,6 +1022,21 @@
3888
3889 return(FALSE);
3890 }
3891+
3892+/******************************************************************//**
3893+Checks if the thread has locked the priority rw-lock in the specified mode,
3894+with the pass value == 0. */
3895+UNIV_INTERN
3896+ibool
3897+rw_lock_own(
3898+/*========*/
3899+ prio_rw_lock_t* lock, /*!< in: rw-lock */
3900+ ulint lock_type) /*!< in: lock type: RW_LOCK_SHARED,
3901+ RW_LOCK_EX */
3902+{
3903+ return(rw_lock_own(&lock->base_lock, lock_type));
3904+}
3905+
3906 #endif /* UNIV_SYNC_DEBUG */
3907
3908 /******************************************************************//**
3909
3910=== modified file 'Percona-Server/storage/innobase/sync/sync0sync.cc'
3911--- Percona-Server/storage/innobase/sync/sync0sync.cc 2013-09-20 05:27:28 +0000
3912+++ Percona-Server/storage/innobase/sync/sync0sync.cc 2013-09-26 14:59:13 +0000
3913@@ -321,6 +321,40 @@
3914 }
3915
3916 /******************************************************************//**
3917+Creates, or rather, initializes a priority mutex object in a specified memory
3918+location (which must be appropriately aligned). The mutex is initialized
3919+in the reset state. Explicit freeing of the mutex with mutex_free is
3920+necessary only if the memory block containing it is freed. */
3921+UNIV_INTERN
3922+void
3923+mutex_create_func(
3924+/*==============*/
3925+ ib_prio_mutex_t* mutex, /*!< in: pointer to memory */
3926+#ifdef UNIV_DEBUG
3927+# ifdef UNIV_SYNC_DEBUG
3928+ ulint level, /*!< in: level */
3929+# endif /* UNIV_SYNC_DEBUG */
3930+ const char* cfile_name, /*!< in: file name where
3931+ created */
3932+ ulint cline, /*!< in: file line where
3933+ created */
3934+#endif /* UNIV_DEBUG */
3935+ const char* cmutex_name) /*!< in: mutex name */
3936+{
3937+ mutex_create_func(&mutex->base_mutex,
3938+#ifdef UNIV_DEBUG
3939+# ifdef UNIV_SYNC_DEBUG
3940+ level,
3941+#endif /* UNIV_SYNC_DEBUG */
3942+ cfile_name,
3943+ cline,
3944+#endif /* UNIV_DEBUG */
3945+ cmutex_name);
3946+ mutex->high_priority_waiters = 0;
3947+ mutex->high_priority_event = os_event_create();
3948+}
3949+
3950+/******************************************************************//**
3951 NOTE! Use the corresponding macro mutex_free(), not directly this function!
3952 Calling this function is obligatory only if the memory buffer containing
3953 the mutex is freed. Removes a mutex object from the mutex list. The mutex
3954@@ -380,6 +414,22 @@
3955 return;
3956 }
3957
3958+/******************************************************************//**
3959+NOTE! Use the corresponding macro mutex_free(), not directly this function!
3960+Calling this function is obligatory only if the memory buffer containing
3961+the mutex is freed. Removes a priority mutex object from the mutex list. The
3962+mutex is checked to be in the reset state. */
3963+UNIV_INTERN
3964+void
3965+mutex_free_func(
3966+/*============*/
3967+ ib_prio_mutex_t* mutex) /*!< in: mutex */
3968+{
3969+ ut_a(mutex->high_priority_waiters == 0);
3970+ os_event_free(mutex->high_priority_event);
3971+ mutex_free_func(&mutex->base_mutex);
3972+}
3973+
3974 /********************************************************************//**
3975 NOTE! Use the corresponding macro in the header file, not this function
3976 directly. Tries to lock the mutex for the current thread. If the lock is not
3977@@ -442,6 +492,20 @@
3978 return(mutex_get_lock_word(mutex) == 1
3979 && os_thread_eq(mutex->thread_id, os_thread_get_curr_id()));
3980 }
3981+
3982+/******************************************************************//**
3983+Checks that the current thread owns the priority mutex. Works only
3984+in the debug version.
3985+@return TRUE if owns */
3986+UNIV_INTERN
3987+ibool
3988+mutex_own(
3989+/*======*/
3990+ const ib_prio_mutex_t* mutex) /*!< in: priority mutex */
3991+{
3992+ return mutex_own(&mutex->base_mutex);
3993+}
3994+
3995 #endif /* UNIV_DEBUG */
3996
3997 /******************************************************************//**
3998@@ -464,14 +528,17 @@
3999 }
4000
4001 /******************************************************************//**
4002-Reserves a mutex for the current thread. If the mutex is reserved, the
4003-function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting
4004-for the mutex before suspending the thread. */
4005+Reserves a mutex or a priority mutex for the current thread. If the mutex is
4006+reserved, the function spins a preset time (controlled by SYNC_SPIN_ROUNDS),
4007+waiting for the mutex before suspending the thread. */
4008 UNIV_INTERN
4009 void
4010 mutex_spin_wait(
4011 /*============*/
4012- ib_mutex_t* mutex, /*!< in: pointer to mutex */
4013+ void* _mutex, /*!< in: pointer to mutex */
4014+ bool high_priority, /*!< in: whether the mutex is a
4015+ priority mutex with high priority
4016+ specified */
4017 const char* file_name, /*!< in: file name where mutex
4018 requested */
4019 ulint line) /*!< in: line where requested */
4020@@ -480,6 +547,10 @@
4021 ulint index; /* index of the reserved wait cell */
4022 sync_array_t* sync_arr;
4023 size_t counter_index;
4024+ /* The typecast below is performed for some of the priority mutexes
4025+ too, when !high_priority. This exploits the fact that regular mutex is
4026+ a prefix of the priority mutex in memory. */
4027+ ib_mutex_t* mutex = (ib_mutex_t *) _mutex;
4028
4029 counter_index = (size_t) os_thread_get_curr_id();
4030
4031@@ -543,7 +614,8 @@
4032 sync_arr = sync_array_get();
4033
4034 sync_array_reserve_cell(
4035- sync_arr, mutex, SYNC_MUTEX, file_name, line, &index);
4036+ sync_arr, mutex, high_priority ? SYNC_PRIO_MUTEX : SYNC_MUTEX,
4037+ file_name, line, &index);
4038
4039 /* The memory order of the array reservation and the change in the
4040 waiters field is important: when we suspend a thread, we first
4041@@ -551,7 +623,11 @@
4042 released in mutex_exit, the waiters field is first set to zero and
4043 then the event is set to the signaled state. */
4044
4045- mutex_set_waiters(mutex, 1);
4046+ if (high_priority) {
4047+ ((ib_prio_mutex_t *)_mutex)->high_priority_waiters = 1;
4048+ } else {
4049+ mutex_set_waiters(mutex, 1);
4050+ }
4051
4052 /* Try to reserve still a few times */
4053 for (i = 0; i < 4; i++) {

Subscribers

People subscribed via source and target branches