Merge lp:~sergei.glushchenko/percona-server/5.5-ps-blueprint-scalability-metrics into lp:percona-server/5.5

Proposed by Sergei Glushchenko
Status: Merged
Approved by: Alexey Kopytov
Approved revision: 461
Merged at revision: 638
Proposed branch: lp:~sergei.glushchenko/percona-server/5.5-ps-blueprint-scalability-metrics
Merge into: lp:percona-server/5.5
Diff against target: 688 lines (+639/-0)
8 files modified
mysql-test/include/have_scalability_metrics_plugin.inc (+21/-0)
mysql-test/include/plugin.defs (+1/-0)
mysql-test/r/scalability_metrics.result (+65/-0)
mysql-test/t/scalability_metrics-master.opt (+1/-0)
mysql-test/t/scalability_metrics.test (+81/-0)
plugin/scalability_metrics/CMakeLists.txt (+17/-0)
plugin/scalability_metrics/scalability_metrics.c (+451/-0)
sql/item_func.cc (+2/-0)
To merge this branch: bzr merge lp:~sergei.glushchenko/percona-server/5.5-ps-blueprint-scalability-metrics
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Approve
Review via email: mp+198219@code.launchpad.net

Description of the change

    Plugin for scalability metrics.
    This is an audit plugin which provides following status variables
    once loaded and enabled:
    - scalability_metrics_elapsedtime - total time elapsed since starting point
    - scalability_metrics_queries - number of completed queries since starting point
    - scalability_metrics_concurrency - number of queries currently executed
    - scalability_metrics_totaltime - total execution time of all queries
    - scalability_metrics_busytime - server's total busy time
    time is counted in microseconds.
    There is also the global control variable named scalability_metrics_ctl
    with possible values ON, OFF, RESET.
    Setting the value to ON enables counting of metrics. Setting it to OFF disables
    counting. By setting the value to RESET one can reset counters (status
    variables) while continuing to count metrics.

    Notes on implementation.
    Three types of notifications are used to count these metrics (all three are of
    MYSQL_AUDIT_GENERAL_CLASS class).
    MYSQL_AUDIT_GENERAL_LOG with command 'Query' and 'Execute' is considered a
    query start event
    MYSQL_AUDIT_GENERAL_RESULT and MYSQL_AUDIT_GENERAL_ERROR are considered a
    query end event

    Statistics calculated for each THD and stored in data structure
    associated with THD. The only synchronization point is the atomic
    variable used to track number of currently running queries. It is
    used for the purpose of calculating server busy time. Once
    variable becomes non-zero we start tracking busy time, once it
    becomes zero, we stop doing it.

To post a comment you must log in.
Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :
Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :

Stable test case should be constructed, current test case has issues.

Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :
Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :

http://jenkins.percona.com/view/PS%205.5/job/percona-server-5.5-param/918/

it is finally stable, however I didn't find a way to avoid sleep after kill. I need to wait until killed thread invokes audit_notify, but I don't have any good sign that query was killed. the->killed doesn't work at the place needed because killed SELECT SLEEP() doesn't actually treated like a killed of terminated with error, but rather as successfully executed query.

Revision history for this message
Alexey Kopytov (akopytov) wrote :
Download full text (3.9 KiB)

Sergei,

This looks good in general. I suspect that implementing per-thread
accounting via TLS / my_pthread_getspecific() would be more elegant and
a bit more efficient. But the current approach looks acceptable.

Some comments on the patch:

  - could you also document scalability_metrics_ctl and the status vars
    in the blueprint?

  - let’s use CLOCK_MONOTONIC_RAW when available?

  - you can use HAVE_CLOCK_GETTIME instead of “(defined _POSIX_TIMERS) &&
    (_POSIX_TIMERS > 0)”

  - the copyright notice should be “Percona LLC and/or its affiliates”
    rather than “Percona Ireland Ltd”. Same for the author field in
    mysql_declare_plugin

  - string.h / time.h / unistd.h – all should be included by
    my_global.h. You can either wrap them into HAVE_... macros, or just
    rely on my_global.h to include them

  - do you really need to include CoreServices/CoreServices.h and libkern/OSAtomic.h?

  - stdint.h is incompatible with Windows. And the server code expects
    my_global.h types anyway (i.e. longlong, etc.). I understand that
    stdint.h types are more explicit, but since we have to use server
    types anyway, and longlong types are guaranteed to be 64-bit on all
    platforms, let’s use them instead?

  - the __attribute__ portability code is redundant (taken care of in
    my_global.h)

  - use my_micro_time() if clock_gettime() is not available? That gives
    us less OSX-specific code and more supported platforms at the cost
    of slightly less efficient code on OSX. Which is not a priority
    anyway.

  - thd_list_mutex is supposed to protect thd_list, but in sm_reset() it
    is used to reset other global variables? What was the intention?

  - would scalability_metrics_control be a better name for scalability_metrics_ctl?

  - it looks like sm_thd_data_t::end is not really needed (can be an
    auto variable in sm_query_finished)

  - the timestamp global variable is also not really needed

  - there is a race condition in sm_query_finished() around the
    concurrency check:

    suppose that multiple threads first execute
    __sync_bool_compare_and_swap(&concurrency, 1, 0) (which would return
    false), and then all proceed to decrement concurrency. If it becomes
    0 as the result, busytime will not be updated.

  - memory leak in sm_thd_data_release(): list_delete() does not free
    LIST structure allocated by list_push()

  - sequential ‘if’ statements in sm_notify() in case event_class ==
    MYSQL_AUDIT_GENERAL_CLASS should be “else if”. Otherwise we will be
    checking all conditions even in the common case (i.e. Query events)

  - shouldn’t the check for (sm_ctl == CTL_ON) be done regardless of
    event_class? Otherwise we will be doing unnecessary bookkeeping for
    MYSQL_AUDIT_CONNECTION_CLASS events even if the plugin functionality
    is turned off

  - shouldn’t setting sm_ctl to CTL_OFF also release all previously
    allocated memory and destroy thd_list?

  - I don’t quite understand the current logic wrt sm_reset() and
    query_series. So if we reset the stats, setting starttime to the
    current time looks correct. Setting concurrency to 0 does not (there
    may still be running queries)....

Read more...

review: Needs Fixing
Revision history for this message
Alexey Kopytov (akopytov) wrote :

Forgot to add this:

- any reasons to use GCC atomics directly instead of the my_atomic.h ones?

Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :
Download full text (5.3 KiB)

Alexey,

>
> This looks good in general. I suspect that implementing per-thread
> accounting via TLS / my_pthread_getspecific() would be more elegant and
> a bit more efficient. But the current approach looks acceptable.
>

the very first issue with TLS is that THD will float between OS threads in
case of threadpool

> Some comments on the patch:
>
> - could you also document scalability_metrics_ctl and the status vars
> in the blueprint?
>

done.

> - let’s use CLOCK_MONOTONIC_RAW when available?
>

done.

> - you can use HAVE_CLOCK_GETTIME instead of “(defined _POSIX_TIMERS) &&
> (_POSIX_TIMERS > 0)”
>

yup, that is look better.

> - the copyright notice should be “Percona LLC and/or its affiliates”
> rather than “Percona Ireland Ltd”. Same for the author field in
> mysql_declare_plugin
>

fixed

> - string.h / time.h / unistd.h – all should be included by
> my_global.h. You can either wrap them into HAVE_... macros, or just
> rely on my_global.h to include them
>

string.h is not included by my_global.h, but it is included by m_string.h

> - do you really need to include CoreServices/CoreServices.h and libkern/OSAtomic.h?
>

they were left after earlier experiments, it's a garbage

> - stdint.h is incompatible with Windows. And the server code expects
> my_global.h types anyway (i.e. longlong, etc.). I understand that
> stdint.h types are more explicit, but since we have to use server
> types anyway, and longlong types are guaranteed to be 64-bit on all
> platforms, let’s use them instead?
>

changed all to ulonglong

> - the __attribute__ portability code is redundant (taken care of in
> my_global.h)
>

yes, it is

> - use my_micro_time() if clock_gettime() is not available? That gives
> us less OSX-specific code and more supported platforms at the cost
> of slightly less efficient code on OSX. Which is not a priority
> anyway.
>

done

> - thd_list_mutex is supposed to protect thd_list, but in sm_reset() it
> is used to reset other global variables? What was the intention?
>

there is no special need. removed.

> - would scalability_metrics_control be a better name for scalability_metrics_ctl?
>

sounds good. renamed.

> - it looks like sm_thd_data_t::end is not really needed (can be an
> auto variable in sm_query_finished)
>

indeed, it is

> - the timestamp global variable is also not really needed
>

yes

> - there is a race condition in sm_query_finished() around the
> concurrency check:
>
> suppose that multiple threads first execute
> __sync_bool_compare_and_swap(&concurrency, 1, 0) (which would return
> false), and then all proceed to decrement concurrency. If it becomes
> 0 as the result, busytime will not be updated.
>

agree. Changed to decrement and test for zero.

> - memory leak in sm_thd_data_release(): list_delete() does not free
> LIST structure allocated by list_push()
>

thanks for pointing this. I messed up list_pop adn list_delete

> - sequential ‘if’ statements in sm_notify() in case event_class ==
> MYSQL_AUDIT_GENERAL_CLASS should be “else if”. Otherwise we will be
> ch...

Read more...

Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :
Revision history for this message
Alexey Kopytov (akopytov) wrote :
Download full text (6.4 KiB)

Hi Sergei,

On Mon, Jan 06 2014 17:10:58 +0400, Sergei Glushchenko wrote:

> Alexey,
>
>>
>> This looks good in general. I suspect that implementing per-thread
>> accounting via TLS / my_pthread_getspecific() would be more elegant and
>> a bit more efficient. But the current approach looks acceptable.
>>
>
> the very first issue with TLS is that THD will float between OS threads in
> case of threadpool
>

Right, but that’s precisely what you need in terms of scalability
metrics. I.e. you need to keep track of concurrent queries
(i.e. execution threads), rather than user connections. With the default
scheduler, there’s 1:1 mapping, so there’s no difference
(functionality-wise, not implementation-wise). But in case of
threadpool, if you have, say, thousands of connections with only a few
worker threads executing queries, you can keep stats per connection, but
that would be redundant, as tracking per-thread stats would be
sufficient.

[...]

>
>> - the copyright notice should be “Percona LLC and/or its affiliates”
>> rather than “Percona Ireland Ltd”. Same for the author field in
>> mysql_declare_plugin
>>
>
> fixed

The ‘author’ field in mysql_declare_plugin() stills reads “Percona Ireland Ltd.”

>
>> - string.h / time.h / unistd.h – all should be included by
>> my_global.h. You can either wrap them into HAVE_... macros, or just
>> rely on my_global.h to include them
>>
>
> string.h is not included by my_global.h, but it is included by m_string.h
>

OK, though I don’t think you need to include the entire m_string.h just
to include string.h.

[...]

>> - use my_micro_time() if clock_gettime() is not available? That gives
>> us less OSX-specific code and more supported platforms at the cost
>> of slightly less efficient code on OSX. Which is not a priority
>> anyway.
>>
>
> done

Hm, but now we have wrong values being returned by
sm_clock_time_duration() when my_micro_time() is used. I.e. all
timestamps are already in microseconds, we don’t have to divide them by
1000. Better yet, do division for the clock_gettime() case in
sm_clock_time_get() and then you won’t need sm_clock_time_duration() at all.

[...]

>
>> - it looks like sm_thd_data_t::end is not really needed (can be an
>> auto variable in sm_query_finished)
>>
>
> indeed, it is

Thanks. But I wonder why ‘end’ and ‘save_busystart’ have also become volatile.

[...]

>> - shouldn’t the check for (sm_ctl == CTL_ON) be done regardless of
>> event_class? Otherwise we will be doing unnecessary bookkeeping for
>> MYSQL_AUDIT_CONNECTION_CLASS events even if the plugin functionality
>> is turned off
>>
>
> This is needed because we don't want to miss disconnect events and forget to release memory. (see below)
>
>> - shouldn’t setting sm_ctl to CTL_OFF also release all previously
>> allocated memory and destroy thd_list?
>>
>
> It will not work because we do not protect thd_data from being
> destroyed. We can introduce mutex for each thd_data, but shoul we?

Right, I see. No, mutex will not help us here. What we want to achieve
here is make getting a pointer from THDVAR and dereferencing it to get
its own mutex an atomic opera...

Read more...

Revision history for this message
Alexey Kopytov (akopytov) :
review: Needs Fixing
Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :

Hi Alexey,

I don't see how can thread-local storage be used without maintaining
per-thrad list similar to what I did for per-THD case since we cannot access
other thread's local variables and we cannot enumerate runnung threads.
The issue will remain the same for per-thread accounting.

changed in this MP:

Fixed author field for plugin.
Reverted include of string.h.
Removed volatile for 'end' and ‘save_busystart’.
Used my_getsystime because of better precision and fixed bug inroduced in prev MP.
Changed 'RESET' semantic.
Simplified test case.

http://jenkins.percona.com/view/PS%205.5/job/percona-server-5.5-param/951/

Revision history for this message
Alexey Kopytov (akopytov) wrote :

Sergei,

The thing is that with thread-local storage you don't need to enumerate running threads. But, as I wrote, the current implementation is still acceptable. Approved.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'mysql-test/include/have_scalability_metrics_plugin.inc'
2--- mysql-test/include/have_scalability_metrics_plugin.inc 1970-01-01 00:00:00 +0000
3+++ mysql-test/include/have_scalability_metrics_plugin.inc 2014-02-09 18:51:30 +0000
4@@ -0,0 +1,21 @@
5+#
6+# Check if server has support for loading plugins
7+#
8+if (`SELECT @@have_dynamic_loading != 'YES'`) {
9+ --skip Example plugin requires dynamic loading
10+}
11+
12+#
13+# Check if the variable SCALABILITY_METRICS is set
14+#
15+if (!$SCALABILITY_METRICS) {
16+ --skip Example plugin requires the environment variable \$SCALABILITY_METRICS to be set (normally done by mtr)
17+}
18+
19+#
20+# Check if --plugin-dir was setup for exampledb
21+#
22+if (`SELECT CONCAT('--plugin-dir=', REPLACE(@@plugin_dir, '\\\\', '/')) != '$SCALABILITY_METRICS_OPT/'`) {
23+ --skip Example plugin requires that --plugin-dir is set to the example plugin dir (either the .opt file does not contain \$SCALABILITY_METRICS_OPT or another plugin is in use)
24+}
25+enable_query_log;
26
27=== modified file 'mysql-test/include/plugin.defs'
28--- mysql-test/include/plugin.defs 2012-10-31 07:10:48 +0000
29+++ mysql-test/include/plugin.defs 2014-02-09 18:51:30 +0000
30@@ -41,3 +41,4 @@
31 mypluglib plugin/fulltext SIMPLE_PARSER
32 libdaemon_example plugin/daemon_example DAEMONEXAMPLE
33 adt_null plugin/audit_null AUDIT_NULL
34+scalability_metrics plugin/scalability_metrics SCALABILITY_METRICS
35
36=== added file 'mysql-test/r/scalability_metrics.result'
37--- mysql-test/r/scalability_metrics.result 1970-01-01 00:00:00 +0000
38+++ mysql-test/r/scalability_metrics.result 2014-02-09 18:51:30 +0000
39@@ -0,0 +1,65 @@
40+set debug_sync= 'RESET';
41+INSTALL PLUGIN scalability_metrics SONAME 'scalability_metrics.so';
42+SHOW STATUS LIKE 'scalability_metrics%';
43+Variable_name Value
44+scalability_metrics_busytime 0
45+scalability_metrics_concurrency 0
46+scalability_metrics_elapsedtime 0
47+scalability_metrics_queries 0
48+scalability_metrics_totaltime 0
49+SET GLOBAL scalability_metrics_control = ON;
50+SHOW STATUS LIKE 'scalability_metrics_concurrency';
51+Variable_name Value
52+scalability_metrics_concurrency 1
53+SHOW STATUS LIKE 'scalability_metrics_queries';
54+Variable_name Value
55+scalability_metrics_queries 1
56+SET DEBUG_SYNC="func_sleep_before_sleep SIGNAL sleep1";
57+SELECT SLEEP(100);
58+SET DEBUG_SYNC= 'now WAIT_FOR sleep1';
59+SHOW STATUS LIKE 'scalability_metrics_concurrency';
60+Variable_name Value
61+scalability_metrics_concurrency 2
62+SHOW STATUS LIKE 'scalability_metrics_queries';
63+Variable_name Value
64+scalability_metrics_queries 7
65+KILL QUERY @id;
66+SLEEP(100)
67+1
68+SHOW STATUS LIKE 'scalability_metrics_concurrency';
69+Variable_name Value
70+scalability_metrics_concurrency 1
71+SHOW STATUS LIKE 'scalability_metrics_queries';
72+Variable_name Value
73+scalability_metrics_queries 11
74+SET DEBUG_SYNC="func_sleep_before_sleep SIGNAL sleep2";
75+SELECT SLEEP(100);
76+SET DEBUG_SYNC= 'now WAIT_FOR sleep2';
77+SET GLOBAL scalability_metrics_control = RESET;
78+SHOW STATUS LIKE 'scalability_metrics_concurrency';
79+Variable_name Value
80+scalability_metrics_concurrency 2
81+SHOW STATUS LIKE 'scalability_metrics_queries';
82+Variable_name Value
83+scalability_metrics_queries 2
84+KILL QUERY @id;
85+SHOW STATUS LIKE 'scalability_metrics_concurrency';
86+Variable_name Value
87+scalability_metrics_concurrency 1
88+SHOW STATUS LIKE 'scalability_metrics_queries';
89+Variable_name Value
90+scalability_metrics_queries 6
91+SLEEP(100)
92+1
93+SET GLOBAL scalability_metrics_control = OFF;
94+SHOW STATUS LIKE 'scalability_metrics%';
95+Variable_name Value
96+scalability_metrics_busytime 0
97+scalability_metrics_concurrency 1
98+scalability_metrics_elapsedtime 0
99+scalability_metrics_queries 0
100+scalability_metrics_totaltime 0
101+UNINSTALL PLUGIN scalability_metrics;
102+Warnings:
103+Warning 1620 Plugin is busy and will be uninstalled on shutdown
104+set debug_sync= 'RESET';
105
106=== added file 'mysql-test/t/scalability_metrics-master.opt'
107--- mysql-test/t/scalability_metrics-master.opt 1970-01-01 00:00:00 +0000
108+++ mysql-test/t/scalability_metrics-master.opt 2014-02-09 18:51:30 +0000
109@@ -0,0 +1,1 @@
110+$SCALABILITY_METRICS_OPT
111
112=== added file 'mysql-test/t/scalability_metrics.test'
113--- mysql-test/t/scalability_metrics.test 1970-01-01 00:00:00 +0000
114+++ mysql-test/t/scalability_metrics.test 2014-02-09 18:51:30 +0000
115@@ -0,0 +1,81 @@
116+################################################################################
117+# Test for plugin scalability_metrics
118+################################################################################
119+
120+--source include/have_scalability_metrics_plugin.inc
121+--source include/have_debug_sync.inc
122+
123+set debug_sync= 'RESET';
124+
125+INSTALL PLUGIN scalability_metrics SONAME 'scalability_metrics.so';
126+
127+SHOW STATUS LIKE 'scalability_metrics%';
128+SET GLOBAL scalability_metrics_control = ON;
129+
130+SHOW STATUS LIKE 'scalability_metrics_concurrency';
131+SHOW STATUS LIKE 'scalability_metrics_queries';
132+
133+connect (con1,localhost,root,,);
134+
135+let $ID= `SELECT @id := CONNECTION_ID()`;
136+
137+SET DEBUG_SYNC="func_sleep_before_sleep SIGNAL sleep1";
138+
139+send SELECT SLEEP(100);
140+
141+connection default;
142+
143+SET DEBUG_SYNC= 'now WAIT_FOR sleep1';
144+
145+let $ignore= `SELECT @id := $ID`;
146+
147+SHOW STATUS LIKE 'scalability_metrics_concurrency';
148+SHOW STATUS LIKE 'scalability_metrics_queries';
149+
150+KILL QUERY @id;
151+
152+connection default;
153+
154+connection con1;
155+reap;
156+
157+sleep 3;
158+
159+SHOW STATUS LIKE 'scalability_metrics_concurrency';
160+SHOW STATUS LIKE 'scalability_metrics_queries';
161+
162+SET DEBUG_SYNC="func_sleep_before_sleep SIGNAL sleep2";
163+
164+send SELECT SLEEP(100);
165+
166+connection default;
167+
168+SET DEBUG_SYNC= 'now WAIT_FOR sleep2';
169+
170+let $ignore= `SELECT @id := $ID`;
171+
172+SET GLOBAL scalability_metrics_control = RESET;
173+
174+SHOW STATUS LIKE 'scalability_metrics_concurrency';
175+SHOW STATUS LIKE 'scalability_metrics_queries';
176+
177+KILL QUERY @id;
178+
179+SHOW STATUS LIKE 'scalability_metrics_concurrency';
180+SHOW STATUS LIKE 'scalability_metrics_queries';
181+
182+connection con1;
183+reap;
184+
185+sleep 3;
186+
187+SET GLOBAL scalability_metrics_control = OFF;
188+SHOW STATUS LIKE 'scalability_metrics%';
189+
190+disconnect con1;
191+
192+connection default;
193+
194+UNINSTALL PLUGIN scalability_metrics;
195+
196+set debug_sync= 'RESET';
197
198=== added directory 'plugin/scalability_metrics'
199=== added file 'plugin/scalability_metrics/CMakeLists.txt'
200--- plugin/scalability_metrics/CMakeLists.txt 1970-01-01 00:00:00 +0000
201+++ plugin/scalability_metrics/CMakeLists.txt 2014-02-09 18:51:30 +0000
202@@ -0,0 +1,17 @@
203+# Copyright (c) 2014 Percona LLC and/or its affiliates. All rights reserved.
204+#
205+# This program is free software; you can redistribute it and/or modify
206+# it under the terms of the GNU General Public License as published by
207+# the Free Software Foundation; version 2 of the License.
208+#
209+# This program is distributed in the hope that it will be useful,
210+# but WITHOUT ANY WARRANTY; without even the implied warranty of
211+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
212+# GNU General Public License for more details.
213+#
214+# You should have received a copy of the GNU General Public License
215+# along with this program; if not, write to the Free Software
216+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
217+
218+MYSQL_ADD_PLUGIN(scalability_metrics scalability_metrics.c
219+ MODULE_ONLY MODULE_OUTPUT_NAME "scalability_metrics")
220
221=== added file 'plugin/scalability_metrics/scalability_metrics.c'
222--- plugin/scalability_metrics/scalability_metrics.c 1970-01-01 00:00:00 +0000
223+++ plugin/scalability_metrics/scalability_metrics.c 2014-02-09 18:51:30 +0000
224@@ -0,0 +1,451 @@
225+/* Copyright (c) 2014 Percona LLC and/or its affiliates. All rights reserved.
226+
227+ This program is free software; you can redistribute it and/or
228+ modify it under the terms of the GNU General Public License
229+ as published by the Free Software Foundation; version 2 of
230+ the License.
231+
232+ This program is distributed in the hope that it will be useful,
233+ but WITHOUT ANY WARRANTY; without even the implied warranty of
234+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
235+ GNU General Public License for more details.
236+
237+ You should have received a copy of the GNU General Public License
238+ along with this program; if not, write to the Free Software
239+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
240+
241+#include <mysql/plugin.h>
242+#include <mysql/plugin_audit.h>
243+#include <my_global.h>
244+#include <my_sys.h>
245+#include <my_list.h>
246+#include <my_pthread.h>
247+#include <typelib.h>
248+#include <limits.h>
249+#include <string.h>
250+
251+static volatile ulonglong starttime= 0;
252+static volatile ulonglong concurrency= 0;
253+static volatile ulonglong busystart= 0;
254+static volatile ulonglong busytime= 0;
255+static volatile ulonglong totaltime= 0;
256+static volatile ulonglong queries= 0;
257+
258+#ifdef HAVE_PSI_INTERFACE
259+PSI_mutex_key key_thd_list_mutex;
260+#endif
261+mysql_mutex_t thd_list_mutex;
262+
263+LIST *thd_list_root= NULL;
264+
265+typedef struct sm_thd_data_struct {
266+ ulonglong start;
267+ ulonglong duration;
268+ ulonglong queries;
269+ LIST *backref;
270+} sm_thd_data_t;
271+
272+typedef enum { CTL_ON= 0, CTL_OFF= 1, CTL_RESET= 2 } sm_ctl_t;
273+static const char* sm_ctl_names[]= { "ON", "OFF", "RESET", NullS };
274+static TYPELIB sm_ctl_typelib= {
275+ array_elements(sm_ctl_names) - 1,
276+ "",
277+ sm_ctl_names,
278+ NULL
279+};
280+
281+static
282+void sm_ctl_update(MYSQL_THD thd, struct st_mysql_sys_var *var,
283+ void *var_ptr, const void *save);
284+
285+static ulong sm_ctl= CTL_OFF;
286+
287+static
288+MYSQL_THDVAR_ULONGLONG(thd_data,
289+ PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR | PLUGIN_VAR_NOCMDOPT,
290+ "scalability metrics data", NULL, NULL, 0, 0, ULONGLONG_MAX, 0);
291+
292+
293+static MYSQL_SYSVAR_ENUM(
294+ control, /* name */
295+ sm_ctl, /* var */
296+ PLUGIN_VAR_RQCMDARG,
297+ "Control the scalability metrics. Use this to turn ON/OFF or RESET metrics.",
298+ NULL, /* check func. */
299+ sm_ctl_update, /* update func. */
300+ CTL_OFF, /* default */
301+ &sm_ctl_typelib /* typelib */
302+);
303+
304+static
305+ulonglong sm_clock_time_get()
306+{
307+#if (defined HAVE_CLOCK_GETTIME)
308+ struct timespec ts;
309+#ifdef CLOCK_MONOTONIC_RAW
310+ clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
311+#else
312+ clock_gettime(CLOCK_MONOTONIC, &ts);
313+#endif
314+ return((ulonglong) ts.tv_sec * 1000000000 + ts.tv_nsec);
315+#else
316+ /* since output values measured in microseconds anyway,
317+ 100 nanoseconds precision should be enough here */
318+ return(my_getsystime() * 100);
319+#endif
320+}
321+
322+
323+/* Get duration in microseconds */
324+static
325+ulonglong sm_clock_time_duration(ulonglong beg, ulonglong end)
326+{
327+ return((end - beg) / 1000);
328+}
329+
330+static
331+sm_thd_data_t *sm_thd_data_get(MYSQL_THD thd)
332+{
333+ sm_thd_data_t *thd_data = (sm_thd_data_t *) (intptr) THDVAR(thd, thd_data);
334+ if (unlikely(thd_data == NULL))
335+ {
336+ thd_data= calloc(sizeof(sm_thd_data_t), 1);
337+ mysql_mutex_lock(&thd_list_mutex);
338+ thd_data->backref= list_push(thd_list_root, thd_data);
339+ mysql_mutex_unlock(&thd_list_mutex);
340+ THDVAR(thd, thd_data)= (ulonglong) (intptr) thd_data;
341+ }
342+ return thd_data;
343+}
344+
345+
346+static
347+void sm_thd_data_release(MYSQL_THD thd)
348+{
349+ sm_thd_data_t *thd_data = (sm_thd_data_t *) (intptr) THDVAR(thd, thd_data);
350+ if (likely(thd_data != NULL && thd_data->backref != NULL))
351+ {
352+ (void) __sync_add_and_fetch(&queries, thd_data->queries);
353+ (void) __sync_add_and_fetch(&totaltime, thd_data->duration);
354+ mysql_mutex_lock(&thd_list_mutex);
355+ thd_list_root= list_delete(thd_list_root, thd_data->backref);
356+ mysql_mutex_unlock(&thd_list_mutex);
357+ free(thd_data->backref);
358+ free(thd_data);
359+ THDVAR(thd, thd_data)= 0;
360+ }
361+}
362+
363+static
364+int sm_reset_one(void *data, void *argument)
365+{
366+ sm_thd_data_t *thd_data= (sm_thd_data_t *) data;
367+ thd_data->queries= 0;
368+ thd_data->duration= 0;
369+ return(0);
370+}
371+
372+static
373+void sm_reset()
374+{
375+ starttime= sm_clock_time_get();
376+ busytime= totaltime= queries= 0;
377+ mysql_mutex_lock(&thd_list_mutex);
378+ list_walk(thd_list_root, sm_reset_one, NULL);
379+ mysql_mutex_unlock(&thd_list_mutex);
380+}
381+
382+
383+static
384+void sm_ctl_update(MYSQL_THD thd __attribute__((unused)),
385+ struct st_mysql_sys_var *var __attribute__((unused)),
386+ void *var_ptr __attribute__((unused)),
387+ const void *save) {
388+ ulong new_val= *((sm_ctl_t*) save);
389+
390+ if (new_val != sm_ctl)
391+ sm_reset();
392+
393+ if (new_val != CTL_RESET)
394+ {
395+ sm_ctl= new_val;
396+
397+ if (new_val == CTL_OFF)
398+ {
399+ mysql_mutex_lock(&thd_list_mutex);
400+ list_free(thd_list_root, FALSE);
401+ thd_list_root= NULL;
402+ mysql_mutex_unlock(&thd_list_mutex);
403+ }
404+ }
405+
406+}
407+
408+
409+static
410+int sm_plugin_init(void *arg __attribute__((unused)))
411+{
412+ mysql_mutex_init(key_thd_list_mutex, &thd_list_mutex, MY_MUTEX_INIT_FAST);
413+
414+ sm_reset();
415+
416+ return(0);
417+}
418+
419+
420+static
421+int sm_plugin_deinit(void *arg __attribute__((unused)))
422+{
423+ list_free(thd_list_root, FALSE);
424+ thd_list_root= NULL;
425+
426+ mysql_mutex_destroy(&thd_list_mutex);
427+
428+ return(0);
429+}
430+
431+static
432+void sm_query_started(MYSQL_THD thd,
433+ const char* query __attribute__((unused))) {
434+
435+ sm_thd_data_t *thd_data= sm_thd_data_get(thd);
436+
437+ if (__sync_bool_compare_and_swap(&concurrency, 0, 1))
438+ {
439+ thd_data->start= sm_clock_time_get();
440+ busystart= thd_data->start;
441+ }
442+ else
443+ {
444+ thd_data->start= sm_clock_time_get();
445+ (void) __sync_add_and_fetch(&concurrency, 1);
446+ }
447+}
448+
449+static
450+void sm_query_finished(MYSQL_THD thd,
451+ const char* query __attribute__((unused))) {
452+
453+ sm_thd_data_t *thd_data= sm_thd_data_get(thd);
454+ ulonglong end, save_busystart;
455+
456+ if (thd_data->start != 0)
457+ {
458+ save_busystart= busystart;
459+ if (__sync_sub_and_fetch(&concurrency, 1) == 0)
460+ {
461+ end= sm_clock_time_get();
462+ (void) __sync_add_and_fetch(&busytime,
463+ sm_clock_time_duration(save_busystart, end));
464+ }
465+ else
466+ {
467+ end= sm_clock_time_get();
468+ }
469+
470+ thd_data->duration+= sm_clock_time_duration(thd_data->start, end);
471+ thd_data->queries++;
472+ }
473+}
474+
475+static
476+void sm_query_failed(MYSQL_THD thd,
477+ const char* query,
478+ int err __attribute__((unused))) {
479+
480+ /* currently there is no difference between success and failure */
481+
482+ sm_query_finished(thd, query);
483+
484+}
485+
486+
487+static
488+int sm_elapsedtime(MYSQL_THD thd __attribute__((unused)),
489+ struct st_mysql_show_var* var,
490+ char *buff)
491+{
492+ *((ulonglong*)buff)= (sm_ctl == CTL_ON) ?
493+ sm_clock_time_duration(starttime, sm_clock_time_get()) :
494+ 0;
495+ var->type= SHOW_LONGLONG;
496+ var->value= buff;
497+ return(0);
498+}
499+
500+
501+static
502+int sm_sum_queries(void *data, void *argument)
503+{
504+ sm_thd_data_t *thd_data= (sm_thd_data_t *) data;
505+ *((ulonglong *) argument)+= thd_data->queries;
506+ return(0);
507+}
508+
509+
510+static
511+int sm_queries(MYSQL_THD thd __attribute__((unused)),
512+ struct st_mysql_show_var* var,
513+ char *buff)
514+{
515+ ulonglong sum_queries= 0;
516+
517+ if (sm_ctl == CTL_ON)
518+ {
519+ mysql_mutex_lock(&thd_list_mutex);
520+ list_walk(thd_list_root, sm_sum_queries, (unsigned char *) &sum_queries);
521+ mysql_mutex_unlock(&thd_list_mutex);
522+ }
523+ *((ulonglong *) buff)= queries + sum_queries;
524+ var->type= SHOW_LONGLONG;
525+ var->value= buff;
526+ return(0);
527+}
528+
529+
530+static
531+int sm_sum_totaltime(void *data, void *argument)
532+{
533+ sm_thd_data_t *thd_data= (sm_thd_data_t *) data;
534+ *((ulonglong *) argument)+= thd_data->duration;
535+ return(0);
536+}
537+
538+
539+static
540+int sm_totaltime(MYSQL_THD thd __attribute__((unused)),
541+ struct st_mysql_show_var* var,
542+ char *buff)
543+{
544+ ulonglong sum_totaltime= 0;
545+
546+ if (sm_ctl == CTL_ON)
547+ {
548+ mysql_mutex_lock(&thd_list_mutex);
549+ list_walk(thd_list_root, sm_sum_totaltime,
550+ (unsigned char *) &sum_totaltime);
551+ mysql_mutex_unlock(&thd_list_mutex);
552+ }
553+ *((ulonglong *) buff)= totaltime + sum_totaltime;
554+ var->type= SHOW_LONGLONG;
555+ var->value= buff;
556+ return(0);
557+}
558+
559+
560+static void sm_notify(MYSQL_THD thd, unsigned int event_class,
561+ const void *event)
562+{
563+
564+ if (event_class == MYSQL_AUDIT_GENERAL_CLASS)
565+ {
566+ const struct mysql_event_general *event_general=
567+ (const struct mysql_event_general *) event;
568+
569+ if (sm_ctl != CTL_ON)
570+ {
571+ return;
572+ }
573+
574+ if (event_general->general_command &&
575+ event_general->event_subclass == MYSQL_AUDIT_GENERAL_LOG &&
576+ strcmp(event_general->general_command, "Query") == 0)
577+ {
578+ sm_query_started(thd, event_general->general_query);
579+ }
580+ else if (event_general->general_command &&
581+ event_general->event_subclass == MYSQL_AUDIT_GENERAL_LOG &&
582+ strcmp(event_general->general_command, "Execute") == 0)
583+ {
584+ sm_query_started(thd, event_general->general_query);
585+ }
586+ else if (event_general->general_query &&
587+ event_general->event_subclass == MYSQL_AUDIT_GENERAL_RESULT)
588+ {
589+ sm_query_finished(thd, event_general->general_query);
590+ }
591+ else if (event_general->general_query &&
592+ event_general->event_subclass == MYSQL_AUDIT_GENERAL_ERROR)
593+ {
594+ sm_query_failed(thd, event_general->general_query,
595+ event_general->general_error_code);
596+ }
597+
598+ }
599+ else if (event_class == MYSQL_AUDIT_CONNECTION_CLASS)
600+ {
601+ const struct mysql_event_connection *event_connection=
602+ (const struct mysql_event_connection *) event;
603+ switch (event_connection->event_subclass)
604+ {
605+ case MYSQL_AUDIT_CONNECTION_CONNECT:
606+ sm_thd_data_get(thd);
607+ break;
608+ case MYSQL_AUDIT_CONNECTION_DISCONNECT:
609+ sm_thd_data_release(thd);
610+ break;
611+ default:
612+ break;
613+ }
614+ }
615+}
616+
617+/*
618+ * Plugin system vars
619+ */
620+static struct st_mysql_sys_var* scalability_metrics_system_variables[] =
621+{
622+ MYSQL_SYSVAR(thd_data),
623+ MYSQL_SYSVAR(control),
624+ NULL
625+};
626+
627+/*
628+ Plugin type-specific descriptor
629+*/
630+static struct st_mysql_audit scalability_metrics_descriptor=
631+{
632+ MYSQL_AUDIT_INTERFACE_VERSION, /* interface version */
633+ NULL, /* release_thd function */
634+ sm_notify, /* notify function */
635+ { MYSQL_AUDIT_GENERAL_CLASSMASK |
636+ MYSQL_AUDIT_CONNECTION_CLASSMASK } /* class mask */
637+};
638+
639+/*
640+ Plugin status variables for SHOW STATUS
641+*/
642+
643+static struct st_mysql_show_var simple_status[]=
644+{
645+ { "scalability_metrics_elapsedtime", (char *) &sm_elapsedtime, SHOW_FUNC },
646+ { "scalability_metrics_queries", (char *) &sm_queries, SHOW_FUNC },
647+ { "scalability_metrics_concurrency", (char *) &concurrency, SHOW_LONGLONG },
648+ { "scalability_metrics_totaltime", (char *) &sm_totaltime, SHOW_FUNC },
649+ { "scalability_metrics_busytime", (char *) &busytime, SHOW_LONGLONG },
650+ { 0, 0, 0}
651+};
652+
653+
654+/*
655+ Plugin library descriptor
656+*/
657+
658+mysql_declare_plugin(scalability_metrics)
659+{
660+ MYSQL_AUDIT_PLUGIN, /* type */
661+ &scalability_metrics_descriptor, /* descriptor */
662+ "scalability_metrics", /* name */
663+ "Percona LLC and/or its affiliates", /* author */
664+ "Scalability metrics", /* description */
665+ PLUGIN_LICENSE_GPL,
666+ sm_plugin_init, /* init function (when loaded) */
667+ sm_plugin_deinit, /* deinit function (when unloaded) */
668+ 0x0001, /* version */
669+ simple_status, /* status variables */
670+ scalability_metrics_system_variables, /* system variables */
671+ NULL,
672+ 0,
673+}
674+mysql_declare_plugin_end;
675+
676
677=== modified file 'sql/item_func.cc'
678--- sql/item_func.cc 2013-06-27 15:35:20 +0000
679+++ sql/item_func.cc 2014-02-09 18:51:30 +0000
680@@ -4135,6 +4135,8 @@
681 thd->mysys_var->current_mutex= &LOCK_user_locks;
682 thd->mysys_var->current_cond= &cond;
683
684+ DEBUG_SYNC(current_thd, "func_sleep_before_sleep");
685+
686 error= 0;
687 thd_wait_begin(thd, THD_WAIT_SLEEP);
688 while (!thd->killed)

Subscribers

People subscribed via source and target branches