1
/* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software Foundation,
14
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
17
@file storage/perfschema/pfs.cc
18
The performance schema implementation of all instruments.
20
#include "my_global.h"
22
#include "mysql/psi/psi.h"
23
#include "mysql/psi/mysql_thread.h"
24
#include "my_pthread.h"
25
#include "sql_const.h"
27
#include "pfs_instr_class.h"
28
#include "pfs_instr.h"
31
#include "pfs_account.h"
32
#include "pfs_global.h"
33
#include "pfs_column_values.h"
34
#include "pfs_timer.h"
35
#include "pfs_events_waits.h"
36
#include "pfs_events_stages.h"
37
#include "pfs_events_statements.h"
38
#include "pfs_setup_actor.h"
39
#include "pfs_setup_object.h"
40
#include "sql_error.h"
42
#include "pfs_digest.h"
45
@page PAGE_PERFORMANCE_SCHEMA The Performance Schema main page
46
MySQL PERFORMANCE_SCHEMA implementation.
48
@section INTRO Introduction
49
The PERFORMANCE_SCHEMA is a way to introspect the internal execution of
50
the server at runtime.
51
The performance schema focuses primarily on performance data,
52
as opposed to the INFORMATION_SCHEMA whose purpose is to inspect metadata.
54
From a user point of view, the performance schema consists of:
55
- a dedicated database schema, named PERFORMANCE_SCHEMA,
56
- SQL tables, used to query the server internal state or change
57
configuration settings.
59
From an implementation point of view, the performance schema is a dedicated
60
Storage Engine which exposes data collected by 'Instrumentation Points'
61
placed in the server code.
63
@section INTERFACES Multiple interfaces
65
The performance schema exposes many different interfaces,
66
for different components, and for different purposes.
68
@subsection INT_INSTRUMENTING Instrumenting interface
70
All the data representing the server internal state exposed
71
in the performance schema must be first collected:
72
this is the role of the instrumenting interface.
73
The instrumenting interface is a coding interface provided
74
by implementors (of the performance schema) to implementors
75
(of the server or server components).
77
This interface is available to:
80
- the core SQL layer (/sql)
81
- the mysys library (/mysys)
82
- MySQL plugins, including storage engines,
83
- third party plugins, including third party storage engines.
85
For details, see the @ref PAGE_INSTRUMENTATION_INTERFACE
86
"instrumentation interface page".
88
@subsection INT_COMPILING Compiling interface
90
The implementation of the performance schema can be enabled or disabled at
91
build time, when building MySQL from the source code.
93
When building with the performance schema code, some compilation flags
94
are available to change the default values used in the code, if required.
96
For more details, see:
97
@verbatim ./configure --help @endverbatim
99
To compile with the performance schema:
100
@verbatim ./configure --with-perfschema @endverbatim
102
The implementation of all the compiling options is located in
103
@verbatim ./storage/perfschema/plug.in @endverbatim
105
@subsection INT_STARTUP Server startup interface
107
The server startup interface consists of the "./mysqld ..."
108
command line used to start the server.
109
When the performance schema is compiled in the server binary,
110
extra command line options are available.
112
These extra start options allow the DBA to:
113
- enable or disable the performance schema
114
- specify some sizing parameters.
116
To see help for the performance schema startup options, see:
117
@verbatim ./sql/mysqld --verbose --help @endverbatim
119
The implementation of all the startup options is located in
120
@verbatim ./sql/mysqld.cc, my_long_options[] @endverbatim
122
@subsection INT_BOOTSTRAP Server bootstrap interface
124
The bootstrap interface is a private interface exposed by
125
the performance schema, and used by the SQL layer.
126
Its role is to advertise all the SQL tables natively
127
supported by the performance schema to the SQL server.
128
The code consists of creating MySQL tables for the
129
performance schema itself, and is used in './mysql --bootstrap'
130
mode when a server is installed.
132
The implementation of the database creation script is located in
133
@verbatim ./scripts/mysql_system_tables.sql @endverbatim
135
@subsection INT_CONFIG Runtime configuration interface
137
When the performance schema is used at runtime, various configuration
138
parameters can be used to specify what kind of data is collected,
139
what kind of aggregations are computed, what kind of timers are used,
140
what events are timed, etc.
142
For all these capabilities, not a single statement or special syntax
143
was introduced in the parser.
144
Instead of new SQL statements, the interface consists of DML
145
(SELECT, INSERT, UPDATE, DELETE) against special "SETUP" tables.
148
@verbatim mysql> update performance_schema.SETUP_INSTRUMENTS
149
set ENABLED='YES', TIMED='YES';
150
Query OK, 234 rows affected (0.00 sec)
151
Rows matched: 234 Changed: 234 Warnings: 0 @endverbatim
153
@subsection INT_STATUS Internal audit interface
155
The internal audit interface is provided to the DBA to inspect if the
156
performance schema code itself is functioning properly.
157
This interface is necessary because a failure caused while
158
instrumenting code in the server should not cause failures in the
159
MySQL server itself, so that the performance schema implementation
160
never raises errors during runtime execution.
162
This auditing interface consists of:
163
@verbatim SHOW ENGINE PERFORMANCE_SCHEMA STATUS; @endverbatim
164
It displays data related to the memory usage of the performance schema,
165
as well as statistics about lost events, if any.
167
The SHOW STATUS command is implemented in
168
@verbatim ./storage/perfschema/pfs_engine_table.cc @endverbatim
170
@subsection INT_QUERY Query interface
172
The query interface is used to query the internal state of a running server.
173
It is provided as SQL tables.
176
@verbatim mysql> select * from performance_schema.EVENTS_WAITS_CURRENT;
179
@section DESIGN_PRINCIPLES Design principles
181
@subsection PRINCIPLE_BEHAVIOR No behavior changes
183
The primary goal of the performance schema is to measure (instrument) the
184
execution of the server. A good measure should not cause any change
187
To achieve this, the overall design of the performance schema complies
188
with the following very severe design constraints:
190
The parser is unchanged. There are no new keywords, no new statements.
191
This guarantees that existing applications will run the same way with or
192
without the performance schema.
194
All the instrumentation points return "void", there are no error codes.
195
Even if the performance schema internally fails, execution of the server
198
None of the instrumentation points allocate memory.
199
All the memory used by the performance schema is pre-allocated at startup,
200
and is considered "static" during the server life time.
202
None of the instrumentation points use any pthread_mutex, pthread_rwlock,
203
or pthread_cond (or platform equivalents).
204
Executing the instrumentation point should not cause thread scheduling to
205
change in the server.
207
In other words, the implementation of the instrumentation points,
208
including all the code called by the instrumentation points, is:
213
TODO: All the code located in storage/perfschema is malloc free,
214
but unfortunately the usage of LF_HASH introduces some memory allocation.
215
This should be revised if possible, to use a lock-free,
216
malloc-free hash code table.
218
@subsection PRINCIPLE_PERFORMANCE No performance hit
220
The instrumentation of the server should be as fast as possible.
221
In cases when there are choices between:
222
- doing some processing when recording the performance data
223
in the instrumentation,
224
- doing some processing when retrieving the performance data,
226
priority is given in the design to make the instrumentation faster,
227
pushing some complexity to data retrieval.
229
As a result, some parts of the design, related to:
230
- the setup code path,
231
- the query code path,
233
might appear to be sub-optimal.
235
The criterion used here is to optimize primarily the critical path (data
236
collection), possibly at the expense of non-critical code paths.
238
@subsection PRINCIPLE_NOT_INTRUSIVE Unintrusive instrumentation
240
For the performance schema in general to be successful, the barrier
241
of entry for a developer should be low, so it's easy to instrument code.
243
In particular, the instrumentation interface:
244
- is available for C and C++ code (so it's a C interface),
245
- does not require parameters that the calling code can't easily provide,
246
- supports partial instrumentation (for example, instrumenting mutexes does
247
not require that every mutex is instrumented)
249
@subsection PRINCIPLE_EXTENDABLE Extendable instrumentation
251
As the content of the performance schema improves,
252
with more tables exposed and more data collected,
253
the instrumentation interface will also be augmented
254
to support instrumenting new concepts.
255
Existing instrumentations should not be affected when additional
256
instrumentation is made available, and making a new instrumentation
257
available should not require existing instrumented code to support it.
259
@subsection PRINCIPLE_VERSIONED Versioned instrumentation
261
Given that the instrumentation offered by the performance schema will
262
be augmented with time, when more features are implemented,
263
the interface itself should be versioned, to keep compatibility
264
with previous instrumented code.
266
For example, after both plugin-A and plugin-B have been instrumented for
267
mutexes, read write locks and conditions, using the instrumentation
268
interface, we can anticipate that the instrumentation interface
269
is expanded to support file based operations.
271
Plugin-A, a file based storage engine, will most likely use the expanded
272
interface and instrument its file usage, using the version 2
273
interface, while Plugin-B, a network based storage engine, will not change
274
its code and not release a new binary.
276
When later the instrumentation interface is expanded to support network
277
based operations (which will define interface version 3), the Plugin-B code
278
can then be changed to make use of it.
280
Note, this is just an example to illustrate the design concept here.
281
Both mutexes and file instrumentation are already available
282
since version 1 of the instrumentation interface.
284
@subsection PRINCIPLE_DEPLOYMENT Easy deployment
286
Internally, we might want every plugin implementation to upgrade the
287
instrumented code to the latest available, but this will cause additional
288
work and this is not practical if the code change is monolithic.
290
Externally, for third party plugin implementors, asking implementors to
291
always stay aligned to the latest instrumentation and make new releases,
292
even when the change does not provide new functionality for them,
295
For example, requiring a network based engine to re-release because the
296
instrumentation interface changed for file based operations, will create
297
too many deployment issues.
299
So, the performance schema implementation must support concurrently,
300
in the same deployment, multiple versions of the instrumentation
301
interface, and ensure binary compatibility with each version.
303
In addition to this, the performance schema can be included or excluded
304
from the server binary, using build time configuration options.
306
Regardless, the following types of deployment are valid:
307
- a server supporting the performance schema + a storage engine
308
that is not instrumented
309
- a server not supporting the performance schema + a storage engine
314
@page PAGE_INSTRUMENTATION_INTERFACE Performance schema: instrumentation interface page.
315
MySQL performance schema instrumentation interface.
317
@section INTRO Introduction
319
The instrumentation interface consist of two layers:
320
- a raw ABI (Application Binary Interface) layer, that exposes the primitive
321
instrumentation functions exported by the performance schema instrumentation
322
- an API (Application Programing Interface) layer,
323
that provides many helpers for a developer instrumenting some code,
324
to make the instrumentation as easy as possible.
326
The ABI layer consists of:
328
#include "mysql/psi/psi.h"
331
The API layer consists of:
333
#include "mysql/psi/mutex_mutex.h"
334
#include "mysql/psi/mutex_file.h"
337
The first helper is for mutexes, rwlocks and conditions,
338
the second for file io.
340
The API layer exposes C macros and typedefs which will expand:
341
- either to non-instrumented code, when compiled without the performance
342
schema instrumentation
343
- or to instrumented code, that will issue the raw calls to the ABI layer
344
so that the implementation can collect data.
346
Note that all the names introduced (for example, @c mysql_mutex_lock) do not
347
collide with any other namespace.
348
In particular, the macro @c mysql_mutex_lock is on purpose not named
349
@c pthread_mutex_lock.
351
- avoid overloading @c pthread_mutex_lock with yet another macro,
352
which is dangerous as it can affect user code and pollute
353
the end-user namespace.
354
- allow the developer instrumenting code to selectively instrument
355
some code but not all.
357
@section PRINCIPLES Design principles
359
The ABI part is designed as a facade, that exposes basic primitives.
360
The expectation is that each primitive will be very stable over time,
361
but the list will constantly grow when more instruments are supported.
362
To support binary compatibility with plugins compiled with a different
363
version of the instrumentation, the ABI itself is versioned
364
(see @c PSI_v1, @c PSI_v2).
366
For a given instrumentation point in the API, the basic coding pattern
368
- (a) notify the performance schema of the operation
369
about to be performed.
370
- (b) execute the instrumented code.
371
- (c) notify the performance schema that the operation
374
An opaque "locker" pointer is returned by (a), that is given to (c).
375
This pointer helps the implementation to keep context, for performances.
377
The following code fragment is annotated to show how in detail this pattern
378
in implemented, when the instrumentation is compiled in:
381
static inline int mysql_mutex_lock(
382
mysql_mutex_t *that, myf flags, const char *src_file, uint src_line)
385
struct PSI_mutex_locker_state state;
386
struct PSI_mutex_locker *locker= NULL;
389
locker= PSI_server->start_mutex_wait(&state, that->p_psi,
390
PSI_MUTEX_LOCK, locker, src_file, src_line);
393
result= pthread_mutex_lock(&that->m_mutex);
396
PSI_server->end_mutex_wait(locker, result);
402
When the performance schema instrumentation is not compiled in,
403
the code becomes simply a wrapper, expanded in line by the compiler:
406
static inline int mysql_mutex_lock(...)
411
result= pthread_mutex_lock(&that->m_mutex);
419
@page PAGE_AGGREGATES Performance schema: the aggregates page.
420
Performance schema aggregates.
422
@section INTRO Introduction
424
Aggregates tables are tables that can be formally defined as
425
SELECT ... from EVENTS_WAITS_HISTORY_INFINITE ... group by 'group clause'.
427
Each group clause defines a different kind of aggregate, and corresponds to
428
a different table exposed by the performance schema.
430
Aggregates can be either:
431
- computed on the fly,
432
- computed on demand, based on other available data.
434
'EVENTS_WAITS_HISTORY_INFINITE' is a table that does not exist,
435
the best approximation is EVENTS_WAITS_HISTORY_LONG.
436
Aggregates computed on the fly in fact are based on EVENTS_WAITS_CURRENT,
437
while aggregates computed on demand are based on other
438
EVENTS_WAITS_SUMMARY_BY_xxx tables.
440
To better understand the implementation itself, a bit of math is
441
required first, to understand the model behind the code:
442
the code is deceptively simple, the real complexity resides
443
in the flyweight of pointers between various performance schema buffers.
445
@section DIMENSION Concept of dimension
447
An event measured by the instrumentation has many attributes.
448
An event is represented as a data point P(x1, x2, ..., xN),
449
where each x_i coordinate represents a given attribute value.
451
Examples of attributes are:
453
- the object waited on
454
- the instrument waited on
455
- the thread that waited
456
- the operation performed
457
- per object or per operation additional attributes, such as spins,
458
number of bytes, etc.
460
Computing an aggregate per thread is fundamentally different from
461
computing an aggregate by instrument, so the "_BY_THREAD" and
462
"_BY_EVENT_NAME" aggregates are different dimensions,
463
operating on different x_i and x_j coordinates.
464
These aggregates are "orthogonal".
466
@section PROJECTION Concept of projection
468
A given x_i attribute value can convey either just one basic information,
469
such as a number of bytes, or can convey implied information,
470
such as an object fully qualified name.
472
For example, from the value "test.t1", the name of the object schema
473
"test" can be separated from the object name "t1", so that now aggregates
474
by object schema can be implemented.
476
In math terms, that corresponds to defining a function:
478
Applying this function to our point P gives another point P':
481
P(x1, x2, ..., x{i-1}, x_i, x{i+1}, ..., x_N)
482
--> P' (x1, x2, ..., x{i-1}, f_i(x_i), x{i+1}, ..., x_N)
484
That function defines in fact an aggregate !
485
In SQL terms, this aggregate would look like the following table:
488
CREATE VIEW EVENTS_WAITS_SUMMARY_BY_Func_i AS
489
SELECT col_1, col_2, ..., col_{i-1},
492
MIN(col_i), AVG(col_i), MAX(col_i), -- if col_i is a numeric value
493
col_{i+1}, ..., col_N
494
FROM EVENTS_WAITS_HISTORY_INFINITE
495
group by col_1, col_2, ..., col_{i-1}, col{i+1}, ..., col_N.
498
Note that not all columns have to be included,
499
in particular some columns that are dependent on the x_i column should
500
be removed, so that in practice, MySQL's aggregation method tends to
501
remove many attributes at each aggregation steps.
503
For example, when aggregating wait events by object instances,
504
- the wait_time and number_of_bytes can be summed,
505
and sum(wait_time) now becomes an object instance attribute.
506
- the source, timer_start, timer_end columns are not in the
507
_BY_INSTANCE table, because these attributes are only
508
meaningful for a wait.
510
@section COMPOSITION Concept of composition
512
Now, the "test.t1" --> "test" example was purely theory,
513
just to explain the concept, and does not lead very far.
514
Let's look at a more interesting example of data that can be derived
517
An event creates a transient object, PFS_wait_locker, per operation.
518
This object's life cycle is extremely short: it's created just
519
before the start_wait() instrumentation call, and is destroyed in
522
The wait locker itself contains a pointer to the object instance
524
That allows to implement a wait_locker --> object instance projection,
526
The object instance life cycle depends on _init and _destroy calls
527
from the code, such as mysql_mutex_init()
528
and mysql_mutex_destroy() for a mutex.
530
The object instance waited on contains a pointer to the object class,
531
which is represented by the instrument name.
532
That allows to implement an object instance --> object class projection.
533
The object class life cycle is permanent, as instruments are loaded in
534
the server and never removed.
536
The object class is named in such a way
537
(for example, "wait/sync/mutex/sql/LOCK_open",
538
"wait/io/file/maria/data_file) that the component ("sql", "maria")
539
that it belongs to can be inferred.
540
That allows to implement an object class --> server component projection.
542
Back to math again, we have, for example for mutexes:
544
F1 (l) : PFS_wait_locker l --> PFS_mutex m = l->m_target.m_mutex
546
F1_to_2 (m) : PFS_mutex m --> PFS_mutex_class i = m->m_class
548
F2_to_3 (i) : PFS_mutex_class i --> const char *component =
549
substring(i->m_name, ...)
551
Per components aggregates are not implemented, this is just an illustration.
553
F1 alone defines this aggregate:
555
EVENTS_WAITS_HISTORY_INFINITE --> EVENTS_WAITS_SUMMARY_BY_INSTANCE
558
F1_to_2 alone could define this aggregate:
560
EVENTS_WAITS_SUMMARY_BY_INSTANCE --> EVENTS_WAITS_SUMMARY_BY_EVENT_NAME
562
Alternatively, using function composition, with
563
F2 = F1_to_2 o F1, F2 defines:
565
EVENTS_WAITS_HISTORY_INFINITE --> EVENTS_WAITS_SUMMARY_BY_EVENT_NAME
567
Likewise, F_2_to_3 defines:
569
EVENTS_WAITS_SUMMARY_BY_EVENT_NAME --> EVENTS_WAITS_SUMMARY_BY_COMPONENT
571
and F3 = F_2_to_3 o F_1_to_2 o F1 defines:
573
EVENTS_WAITS_HISTORY_INFINITE --> EVENTS_WAITS_SUMMARY_BY_COMPONENT
575
What has all this to do with the code ?
577
Functions (or aggregates) such as F_3 are not implemented as is.
578
Instead, they are decomposed into F_2_to_3 o F_1_to_2 o F1,
579
and each intermediate aggregate is stored into an internal buffer.
580
This allows to support every F1, F2, F3 aggregates from shared
581
internal buffers, where computation already performed to compute F2
582
is reused when computing F3.
584
@section OBJECT_GRAPH Object graph
586
In terms of object instances, or records, pointers between
587
different buffers define an object instance graph.
589
For example, assuming the following scenario:
590
- A mutex class "M" is instrumented, the instrument name
591
is "wait/sync/mutex/sql/M"
592
- This mutex instrument has been instantiated twice,
593
mutex instances are noted M-1 and M-2
594
- Threads T-A and T-B are locking mutex instance M-1
595
- Threads T-C and T-D are locking mutex instance M-2
597
The performance schema will record the following data:
598
- EVENTS_WAITS_CURRENT has 4 rows, one for each mutex locker
599
- EVENTS_WAITS_SUMMARY_BY_INSTANCE shows 2 rows, for M-1 and M-2
600
- EVENTS_WAITS_SUMMARY_BY_EVENT_NAME shows 1 row, for M
602
The graph of structures will look like:
605
PFS_wait_locker (T-A, M-1) ----------
609
- m_wait_stat ------------
612
PFS_wait_locker (T-B, M-1) ---------- |
616
PFS_wait_locker (T-C, M-2) ---------- ^
620
- m_wait_stat ------------
623
PFS_wait_locker (T-D, M-2) ----------
629
EVENTS_WAITS_CURRENT ..._SUMMARY_BY_INSTANCE ..._SUMMARY_BY_EVENT_NAME
632
@section ON_THE_FLY On the fly aggregates
634
'On the fly' aggregates are computed during the code execution.
635
This is necessary because the data the aggregate is based on is volatile,
636
and can not be kept indefinitely.
638
With on the fly aggregates:
639
- the writer thread does all the computation
640
- the reader thread accesses the result directly
642
This model is to be avoided if possible, due to the overhead
643
caused when instrumenting code.
645
@section HIGHER_LEVEL Higher level aggregates
647
'Higher level' aggregates are implemented on demand only.
648
The code executing a SELECT from the aggregate table is
649
collecting data from multiple internal buffers to produce the result.
651
With higher level aggregates:
652
- the reader thread does all the computation
653
- the writer thread has no overhead.
655
@section MIXED Mixed level aggregates
657
The 'Mixed' model is a compromise between 'On the fly' and 'Higher level'
658
aggregates, for internal buffers that are not permanent.
660
While an object is present in a buffer, the higher level model is used.
661
When an object is about to be destroyed, statistics are saved into
662
a 'parent' buffer with a longer life cycle, to follow the on the fly model.
664
With mixed aggregates:
665
- the reader thread does a lot of complex computation,
666
- the writer thread has minimal overhead, on destroy events.
668
@section IMPL_WAIT Implementation for waits aggregates
670
For waits, the tables that contains aggregated wait data are:
671
- EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME
672
- EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME
673
- EVENTS_WAITS_SUMMARY_BY_INSTANCE
674
- EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME
675
- EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME
676
- EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME
677
- FILE_SUMMARY_BY_EVENT_NAME
678
- FILE_SUMMARY_BY_INSTANCE
679
- SOCKET_SUMMARY_BY_INSTANCE
680
- SOCKET_SUMMARY_BY_EVENT_NAME
681
- OBJECTS_SUMMARY_GLOBAL_BY_TYPE
683
The instrumented code that generates waits events consist of:
684
- mutexes (mysql_mutex_t)
685
- rwlocks (mysql_rwlock_t)
686
- conditions (mysql_cond_t)
687
- file io (MYSQL_FILE)
688
- socket io (MYSQL_SOCKET)
693
The flow of data between aggregates tables varies for each instrumentation.
695
@subsection IMPL_WAIT_MUTEX Mutex waits
702
|-> pfs_mutex(M) =====>> [B], [C]
706
| |-> pfs_mutex_class(M.class) =====>> [C]
708
|-> pfs_thread(T).event_name(M) =====>> [A], [D], [E], [F]
712
3a |-> pfs_account(U, H).event_name(M) =====>> [D], [E], [F]
716
3b .....+-> pfs_user(U).event_name(M) =====>> [E]
718
3c .....+-> pfs_host(H).event_name(M) =====>> [F]
721
How to read this diagram:
722
- events that occur during the instrumented code execution are noted with numbers,
723
as in [1]. Code executed by these events has an impact on overhead.
724
- events that occur during TRUNCATE TABLE operations are noted with numbers,
725
followed by "-RESET", as in [4-RESET].
726
Code executed by these events has no impact on overhead,
727
since they are executed by independent monitoring sessions.
728
- events that occur when a reader extracts data from a performance schema table
729
are noted with letters, as in [A]. The name of the table involved,
730
and the method that builds a row are documented. Code executed by these events
731
has no impact on the instrumentation overhead. Note that the table
732
implementation may pull data from different buffers.
733
- nominal code paths are in plain lines. A "nominal" code path corresponds to
734
cases where the performance schema buffers are sized so that no records are lost.
735
- degenerated code paths are in dotted lines. A "degenerated" code path corresponds
736
to edge cases where parent buffers are full, which forces the code to aggregate to
737
grand parents directly.
740
- [1] @c start_mutex_wait_v1(), @c end_mutex_wait_v1()
741
- [2] @c destroy_mutex_v1()
742
- [3] @c aggregate_thread_waits()
743
- [4] @c PFS_account::aggregate_waits()
744
- [A] EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME,
745
@c table_ews_by_thread_by_event_name::make_row()
746
- [B] EVENTS_WAITS_SUMMARY_BY_INSTANCE,
747
@c table_events_waits_summary_by_instance::make_mutex_row()
748
- [C] EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME,
749
@c table_ews_global_by_event_name::make_mutex_row()
750
- [D] EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME,
751
@c table_ews_by_account_by_event_name::make_row()
752
- [E] EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME,
753
@c table_ews_by_user_by_event_name::make_row()
754
- [F] EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME,
755
@c table_ews_by_host_by_event_name::make_row()
757
Table EVENTS_WAITS_SUMMARY_BY_INSTANCE is a 'on the fly' aggregate,
758
because the data is collected on the fly by (1) and stored into a buffer,
759
pfs_mutex. The table implementation [B] simply reads the results directly
762
Table EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME is a 'mixed' aggregate,
763
because some data is collected on the fly (1),
764
some data is preserved with (2) at a later time in the life cycle,
765
and two different buffers pfs_mutex and pfs_mutex_class are used to store the
766
statistics collected. The table implementation [C] is more complex, since
767
it reads from two buffers pfs_mutex and pfs_mutex_class.
769
@subsection IMPL_WAIT_RWLOCK Rwlock waits
776
|-> pfs_rwlock(R) =====>> [B], [C]
780
| |-> pfs_rwlock_class(R.class) =====>> [C]
782
|-> pfs_thread(T).event_name(R) =====>> [A]
788
- [1] @c start_rwlock_rdwait_v1(), @c end_rwlock_rdwait_v1(), ...
789
- [2] @c destroy_rwlock_v1()
790
- [A] EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME,
791
@c table_ews_by_thread_by_event_name::make_row()
792
- [B] EVENTS_WAITS_SUMMARY_BY_INSTANCE,
793
@c table_events_waits_summary_by_instance::make_rwlock_row()
794
- [C] EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME,
795
@c table_ews_global_by_event_name::make_rwlock_row()
797
@subsection IMPL_WAIT_COND Cond waits
804
|-> pfs_cond(C) =====>> [B], [C]
808
| |-> pfs_cond_class(C.class) =====>> [C]
810
|-> pfs_thread(T).event_name(C) =====>> [A]
816
- [1] @c start_cond_wait_v1(), @c end_cond_wait_v1()
817
- [2] @c destroy_cond_v1()
818
- [A] EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME,
819
@c table_ews_by_thread_by_event_name::make_row()
820
- [B] EVENTS_WAITS_SUMMARY_BY_INSTANCE,
821
@c table_events_waits_summary_by_instance::make_cond_row()
822
- [C] EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME,
823
@c table_ews_global_by_event_name::make_cond_row()
825
@subsection IMPL_WAIT_FILE File waits
832
|-> pfs_file(F) =====>> [B], [C], [D], [E]
836
| |-> pfs_file_class(F.class) =====>> [C], [D]
838
|-> pfs_thread(T).event_name(F) =====>> [A]
844
- [1] @c get_thread_file_name_locker_v1(), @c start_file_wait_v1(),
845
@c end_file_wait_v1(), ...
846
- [2] @c close_file_v1()
847
- [A] EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME,
848
@c table_ews_by_thread_by_event_name::make_row()
849
- [B] EVENTS_WAITS_SUMMARY_BY_INSTANCE,
850
@c table_events_waits_summary_by_instance::make_file_row()
851
- [C] EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME,
852
@c table_ews_global_by_event_name::make_file_row()
853
- [D] FILE_SUMMARY_BY_EVENT_NAME,
854
@c table_file_summary_by_event_name::make_row()
855
- [E] FILE_SUMMARY_BY_INSTANCE,
856
@c table_file_summary_by_instance::make_row()
858
@subsection IMPL_WAIT_SOCKET Socket waits
865
|-> pfs_socket(S) =====>> [A], [B], [C], [D], [E]
869
|-> pfs_socket_class(S.class) =====>> [C], [D]
871
|-> pfs_thread(T).event_name(S) =====>> [A]
875
3a |-> pfs_account(U, H).event_name(S) =====>> [F], [G], [H]
879
3b .....+-> pfs_user(U).event_name(S) =====>> [G]
881
3c .....+-> pfs_host(H).event_name(S) =====>> [H]
885
- [1] @c start_socket_wait_v1(), @c end_socket_wait_v1().
886
- [2] @c close_socket_v1()
887
- [3] @c aggregate_thread_waits()
888
- [4] @c PFS_account::aggregate_waits()
889
- [5] @c PFS_host::aggregate_waits()
890
- [A] EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME,
891
@c table_ews_by_thread_by_event_name::make_row()
892
- [B] EVENTS_WAITS_SUMMARY_BY_INSTANCE,
893
@c table_events_waits_summary_by_instance::make_socket_row()
894
- [C] EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME,
895
@c table_ews_global_by_event_name::make_socket_row()
896
- [D] SOCKET_SUMMARY_BY_EVENT_NAME,
897
@c table_socket_summary_by_event_name::make_row()
898
- [E] SOCKET_SUMMARY_BY_INSTANCE,
899
@c table_socket_summary_by_instance::make_row()
900
- [F] EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME,
901
@c table_ews_by_account_by_event_name::make_row()
902
- [G] EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME,
903
@c table_ews_by_user_by_event_name::make_row()
904
- [H] EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME,
905
@c table_ews_by_host_by_event_name::make_row()
907
@subsection IMPL_WAIT_TABLE Table waits
910
table_locker(Thread Th, Table Tb, Event = io or lock)
914
1a |-> pfs_table(Tb) =====>> [A], [B], [C]
918
| |-> pfs_table_share(Tb.share) =====>> [B], [C]
922
| |-> global_table_io_stat =====>> [C]
924
| |-> global_table_lock_stat =====>> [C]
926
1b |-> pfs_thread(Th).event_name(E) =====>> [D], [E], [F], [G]
930
| |-> pfs_account(U, H).event_name(E) =====>> [E], [F], [G]
934
| .....+-> pfs_user(U).event_name(E) =====>> [F]
936
| .....+-> pfs_host(H).event_name(E) =====>> [G]
938
1c |-> pfs_thread(Th).waits_current(W) =====>> [H]
940
1d |-> pfs_thread(Th).waits_history(W) =====>> [I]
942
1e |-> waits_history_long(W) =====>> [J]
946
- [1] @c start_table_io_wait_v1(), @c end_table_io_wait_v1()
947
- [2] @c close_table_v1()
948
- [3] @c drop_table_share_v1()
949
- [4] @c TRUNCATE TABLE EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME
950
- [5] @c TRUNCATE TABLE EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME
951
- [A] EVENTS_WAITS_SUMMARY_BY_INSTANCE,
952
@c table_events_waits_summary_by_instance::make_table_row()
953
- [B] OBJECTS_SUMMARY_GLOBAL_BY_TYPE,
954
@c table_os_global_by_type::make_row()
955
- [C] EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME,
956
@c table_ews_global_by_event_name::make_table_io_row(),
957
@c table_ews_global_by_event_name::make_table_lock_row()
958
- [D] EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME,
959
@c table_ews_by_thread_by_event_name::make_row()
960
- [E] EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME,
961
@c table_ews_by_user_by_account_name::make_row()
962
- [F] EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME,
963
@c table_ews_by_user_by_event_name::make_row()
964
- [G] EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME,
965
@c table_ews_by_host_by_event_name::make_row()
966
- [H] EVENTS_WAITS_CURRENT,
967
@c table_events_waits_common::make_row()
968
- [I] EVENTS_WAITS_HISTORY,
969
@c table_events_waits_common::make_row()
970
- [J] EVENTS_WAITS_HISTORY_LONG,
971
@c table_events_waits_common::make_row()
973
@section IMPL_STAGE Implementation for stages aggregates
975
For stages, the tables that contains aggregated data are:
976
- EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME
977
- EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME
978
- EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME
979
- EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME
980
- EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME
987
1a |-> pfs_thread(T).event_name(S) =====>> [A], [B], [C], [D], [E]
991
| 2a |-> pfs_account(U, H).event_name(S) =====>> [B], [C], [D], [E]
995
| 2b .....+-> pfs_user(U).event_name(S) =====>> [C]
997
| 2c .....+-> pfs_host(H).event_name(S) =====>> [D], [E]
1001
1b |----+----+----+-> pfs_stage_class(S) =====>> [E]
1006
- [1] @c start_stage_v1()
1007
- [2] @c delete_thread_v1(), @c aggregate_thread_stages()
1008
- [3] @c PFS_account::aggregate_stages()
1009
- [4] @c PFS_host::aggregate_stages()
1010
- [A] EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME,
1011
@c table_esgs_by_thread_by_event_name::make_row()
1012
- [B] EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME,
1013
@c table_esgs_by_account_by_event_name::make_row()
1014
- [C] EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME,
1015
@c table_esgs_by_user_by_event_name::make_row()
1016
- [D] EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME,
1017
@c table_esgs_by_host_by_event_name::make_row()
1018
- [E] EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME,
1019
@c table_esgs_global_by_event_name::make_row()
1021
@section IMPL_STATEMENT Implementation for statements consumers
1023
For statements, the tables that contains individual event data are:
1024
- EVENTS_STATEMENTS_CURRENT
1025
- EVENTS_STATEMENTS_HISTORY
1026
- EVENTS_STATEMENTS_HISTORY_LONG
1028
For statements, the tables that contains aggregated data are:
1029
- EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME
1030
- EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME
1031
- EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME
1032
- EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME
1033
- EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME
1034
- EVENTS_STATEMENTS_SUMMARY_BY_DIGEST
1037
statement_locker(T, S)
1041
1a |-> pfs_thread(T).event_name(S) =====>> [A], [B], [C], [D], [E]
1045
| 2a |-> pfs_account(U, H).event_name(S) =====>> [B], [C], [D], [E]
1049
| 2b .....+-> pfs_user(U).event_name(S) =====>> [C]
1051
| 2c .....+-> pfs_host(H).event_name(S) =====>> [D], [E]
1055
1b |----+----+----+-> pfs_statement_class(S) =====>> [E]
1057
1c |-> pfs_thread(T).statement_current(S) =====>> [F]
1059
1d |-> pfs_thread(T).statement_history(S) =====>> [G]
1061
1e |-> statement_history_long(S) =====>> [H]
1063
1f |-> statement_digest(S) =====>> [I]
1068
- [1] @c start_statement_v1(), end_statement_v1()
1069
(1a, 1b) is an aggregation by EVENT_NAME,
1070
(1c, 1d, 1e) is an aggregation by TIME,
1071
(1f) is an aggregation by DIGEST
1072
all of these are orthogonal,
1073
and implemented in end_statement_v1().
1074
- [2] @c delete_thread_v1(), @c aggregate_thread_statements()
1075
- [3] @c PFS_account::aggregate_statements()
1076
- [4] @c PFS_host::aggregate_statements()
1077
- [A] EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME,
1078
@c table_esms_by_thread_by_event_name::make_row()
1079
- [B] EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME,
1080
@c table_esms_by_account_by_event_name::make_row()
1081
- [C] EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME,
1082
@c table_esms_by_user_by_event_name::make_row()
1083
- [D] EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME,
1084
@c table_esms_by_host_by_event_name::make_row()
1085
- [E] EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME,
1086
@c table_esms_global_by_event_name::make_row()
1087
- [F] EVENTS_STATEMENTS_CURRENT,
1088
@c table_events_statements_current::rnd_next(),
1089
@c table_events_statements_common::make_row()
1090
- [G] EVENTS_STATEMENTS_HISTORY,
1091
@c table_events_statements_history::rnd_next(),
1092
@c table_events_statements_common::make_row()
1093
- [H] EVENTS_STATEMENTS_HISTORY_LONG,
1094
@c table_events_statements_history_long::rnd_next(),
1095
@c table_events_statements_common::make_row()
1096
- [I] EVENTS_STATEMENTS_SUMMARY_BY_DIGEST
1097
@c table_esms_by_digest::make_row()
1101
@defgroup Performance_schema Performance Schema
1102
The performance schema component.
1103
For details, see the
1104
@ref PAGE_PERFORMANCE_SCHEMA "performance schema main page".
1106
@defgroup Performance_schema_implementation Performance Schema Implementation
1107
@ingroup Performance_schema
1109
@defgroup Performance_schema_tables Performance Schema Tables
1110
@ingroup Performance_schema_implementation
1113
pthread_key(PFS_thread*, THR_PFS);
1114
bool THR_PFS_initialized= false;
1117
Conversion map from PSI_mutex_operation to enum_operation_type.
1118
Indexed by enum PSI_mutex_operation.
1120
static enum_operation_type mutex_operation_map[]=
1122
OPERATION_TYPE_LOCK,
1123
OPERATION_TYPE_TRYLOCK
1127
Conversion map from PSI_rwlock_operation to enum_operation_type.
1128
Indexed by enum PSI_rwlock_operation.
1130
static enum_operation_type rwlock_operation_map[]=
1132
OPERATION_TYPE_READLOCK,
1133
OPERATION_TYPE_WRITELOCK,
1134
OPERATION_TYPE_TRYREADLOCK,
1135
OPERATION_TYPE_TRYWRITELOCK
1139
Conversion map from PSI_cond_operation to enum_operation_type.
1140
Indexed by enum PSI_cond_operation.
1142
static enum_operation_type cond_operation_map[]=
1144
OPERATION_TYPE_WAIT,
1145
OPERATION_TYPE_TIMEDWAIT
1149
Conversion map from PSI_file_operation to enum_operation_type.
1150
Indexed by enum PSI_file_operation.
1152
static enum_operation_type file_operation_map[]=
1154
OPERATION_TYPE_FILECREATE,
1155
OPERATION_TYPE_FILECREATETMP,
1156
OPERATION_TYPE_FILEOPEN,
1157
OPERATION_TYPE_FILESTREAMOPEN,
1158
OPERATION_TYPE_FILECLOSE,
1159
OPERATION_TYPE_FILESTREAMCLOSE,
1160
OPERATION_TYPE_FILEREAD,
1161
OPERATION_TYPE_FILEWRITE,
1162
OPERATION_TYPE_FILESEEK,
1163
OPERATION_TYPE_FILETELL,
1164
OPERATION_TYPE_FILEFLUSH,
1165
OPERATION_TYPE_FILESTAT,
1166
OPERATION_TYPE_FILEFSTAT,
1167
OPERATION_TYPE_FILECHSIZE,
1168
OPERATION_TYPE_FILEDELETE,
1169
OPERATION_TYPE_FILERENAME,
1170
OPERATION_TYPE_FILESYNC
1174
Conversion map from PSI_table_operation to enum_operation_type.
1175
Indexed by enum PSI_table_io_operation.
1177
static enum_operation_type table_io_operation_map[]=
1179
OPERATION_TYPE_TABLE_FETCH,
1180
OPERATION_TYPE_TABLE_WRITE_ROW,
1181
OPERATION_TYPE_TABLE_UPDATE_ROW,
1182
OPERATION_TYPE_TABLE_DELETE_ROW
1186
Conversion map from enum PFS_TL_LOCK_TYPE to enum_operation_type.
1187
Indexed by enum PFS_TL_LOCK_TYPE.
1189
static enum_operation_type table_lock_operation_map[]=
1191
OPERATION_TYPE_TL_READ_NORMAL, /* PFS_TL_READ */
1192
OPERATION_TYPE_TL_READ_WITH_SHARED_LOCKS, /* PFS_TL_READ_WITH_SHARED_LOCKS */
1193
OPERATION_TYPE_TL_READ_HIGH_PRIORITY, /* PFS_TL_READ_HIGH_PRIORITY */
1194
OPERATION_TYPE_TL_READ_NO_INSERTS, /* PFS_TL_READ_NO_INSERT */
1195
OPERATION_TYPE_TL_WRITE_ALLOW_WRITE, /* PFS_TL_WRITE_ALLOW_WRITE */
1196
OPERATION_TYPE_TL_WRITE_CONCURRENT_INSERT, /* PFS_TL_WRITE_CONCURRENT_INSERT */
1197
OPERATION_TYPE_TL_WRITE_DELAYED, /* PFS_TL_WRITE_DELAYED */
1198
OPERATION_TYPE_TL_WRITE_LOW_PRIORITY, /* PFS_TL_WRITE_LOW_PRIORITY */
1199
OPERATION_TYPE_TL_WRITE_NORMAL, /* PFS_TL_WRITE */
1200
OPERATION_TYPE_TL_READ_EXTERNAL, /* PFS_TL_READ_EXTERNAL */
1201
OPERATION_TYPE_TL_WRITE_EXTERNAL /* PFS_TL_WRITE_EXTERNAL */
1205
Conversion map from PSI_socket_operation to enum_operation_type.
1206
Indexed by enum PSI_socket_operation.
1208
static enum_operation_type socket_operation_map[]=
1210
OPERATION_TYPE_SOCKETCREATE,
1211
OPERATION_TYPE_SOCKETCONNECT,
1212
OPERATION_TYPE_SOCKETBIND,
1213
OPERATION_TYPE_SOCKETCLOSE,
1214
OPERATION_TYPE_SOCKETSEND,
1215
OPERATION_TYPE_SOCKETRECV,
1216
OPERATION_TYPE_SOCKETSENDTO,
1217
OPERATION_TYPE_SOCKETRECVFROM,
1218
OPERATION_TYPE_SOCKETSENDMSG,
1219
OPERATION_TYPE_SOCKETRECVMSG,
1220
OPERATION_TYPE_SOCKETSEEK,
1221
OPERATION_TYPE_SOCKETOPT,
1222
OPERATION_TYPE_SOCKETSTAT,
1223
OPERATION_TYPE_SOCKETSHUTDOWN,
1224
OPERATION_TYPE_SOCKETSELECT
1228
Build the prefix name of a class of instruments in a category.
1229
For example, this function builds the string 'wait/sync/mutex/sql/' from
1230
a prefix 'wait/sync/mutex' and a category 'sql'.
1231
This prefix is used later to build each instrument name, such as
1232
'wait/sync/mutex/sql/LOCK_open'.
1233
@param prefix Prefix for this class of instruments
1234
@param category Category name
1235
@param [out] output Buffer of length PFS_MAX_INFO_NAME_LENGTH.
1236
@param [out] output_length Length of the resulting output string.
1237
@return 0 for success, non zero for errors
1239
static int build_prefix(const LEX_STRING *prefix, const char *category,
1240
char *output, int *output_length)
1242
int len= strlen(category);
1243
char *out_ptr= output;
1244
int prefix_length= prefix->length;
1246
if (unlikely((prefix_length + len + 1) >=
1247
PFS_MAX_FULL_PREFIX_NAME_LENGTH))
1249
pfs_print_error("build_prefix: prefix+category is too long <%s> <%s>\n",
1250
prefix->str, category);
1254
if (unlikely(strchr(category, '/') != NULL))
1256
pfs_print_error("build_prefix: invalid category <%s>\n",
1261
/* output = prefix + category + '/' */
1262
memcpy(out_ptr, prefix->str, prefix_length);
1263
out_ptr+= prefix_length;
1264
memcpy(out_ptr, category, len);
1268
*output_length= out_ptr - output;
1273
#define REGISTER_BODY_V1(KEY_T, PREFIX, REGISTER_FUNC) \
1275
char formatted_name[PFS_MAX_INFO_NAME_LENGTH]; \
1276
int prefix_length; \
1280
DBUG_ASSERT(category != NULL); \
1281
DBUG_ASSERT(info != NULL); \
1282
if (unlikely(build_prefix(&PREFIX, category, \
1283
formatted_name, &prefix_length))) \
1285
for (; count>0; count--, info++) \
1286
*(info->m_key)= 0; \
1290
for (; count>0; count--, info++) \
1292
DBUG_ASSERT(info->m_key != NULL); \
1293
DBUG_ASSERT(info->m_name != NULL); \
1294
len= strlen(info->m_name); \
1295
full_length= prefix_length + len; \
1296
if (likely(full_length <= PFS_MAX_INFO_NAME_LENGTH)) \
1298
memcpy(formatted_name + prefix_length, info->m_name, len); \
1299
key= REGISTER_FUNC(formatted_name, full_length, info->m_flags); \
1303
pfs_print_error("REGISTER_BODY_V1: name too long <%s> <%s>\n", \
1304
category, info->m_name); \
1308
*(info->m_key)= key; \
1312
/* Use C linkage for the interface functions. */
1317
Implementation of the mutex instrumentation interface.
1318
@sa PSI_v1::register_mutex.
1320
static void register_mutex_v1(const char *category,
1321
PSI_mutex_info_v1 *info,
1324
REGISTER_BODY_V1(PSI_mutex_key,
1325
mutex_instrument_prefix,
1326
register_mutex_class)
1330
Implementation of the rwlock instrumentation interface.
1331
@sa PSI_v1::register_rwlock.
1333
static void register_rwlock_v1(const char *category,
1334
PSI_rwlock_info_v1 *info,
1337
REGISTER_BODY_V1(PSI_rwlock_key,
1338
rwlock_instrument_prefix,
1339
register_rwlock_class)
1343
Implementation of the cond instrumentation interface.
1344
@sa PSI_v1::register_cond.
1346
static void register_cond_v1(const char *category,
1347
PSI_cond_info_v1 *info,
1350
REGISTER_BODY_V1(PSI_cond_key,
1351
cond_instrument_prefix,
1352
register_cond_class)
1356
Implementation of the thread instrumentation interface.
1357
@sa PSI_v1::register_thread.
1359
static void register_thread_v1(const char *category,
1360
PSI_thread_info_v1 *info,
1363
REGISTER_BODY_V1(PSI_thread_key,
1364
thread_instrument_prefix,
1365
register_thread_class)
1369
Implementation of the file instrumentation interface.
1370
@sa PSI_v1::register_file.
1372
static void register_file_v1(const char *category,
1373
PSI_file_info_v1 *info,
1376
REGISTER_BODY_V1(PSI_file_key,
1377
file_instrument_prefix,
1378
register_file_class)
1381
static void register_stage_v1(const char *category,
1382
PSI_stage_info_v1 **info_array,
1385
char formatted_name[PFS_MAX_INFO_NAME_LENGTH];
1389
PSI_stage_info_v1 *info;
1391
DBUG_ASSERT(category != NULL);
1392
DBUG_ASSERT(info_array != NULL);
1393
if (unlikely(build_prefix(&stage_instrument_prefix, category,
1394
formatted_name, &prefix_length)))
1396
for (; count>0; count--, info_array++)
1397
(*info_array)->m_key= 0;
1401
for (; count>0; count--, info_array++)
1404
DBUG_ASSERT(info != NULL);
1405
DBUG_ASSERT(info->m_name != NULL);
1406
len= strlen(info->m_name);
1407
full_length= prefix_length + len;
1408
if (likely(full_length <= PFS_MAX_INFO_NAME_LENGTH))
1410
memcpy(formatted_name + prefix_length, info->m_name, len);
1411
info->m_key= register_stage_class(formatted_name,
1418
pfs_print_error("register_stage_v1: name too long <%s> <%s>\n",
1419
category, info->m_name);
1426
static void register_statement_v1(const char *category,
1427
PSI_statement_info_v1 *info,
1430
char formatted_name[PFS_MAX_INFO_NAME_LENGTH];
1435
DBUG_ASSERT(category != NULL);
1436
DBUG_ASSERT(info != NULL);
1437
if (unlikely(build_prefix(&statement_instrument_prefix,
1438
category, formatted_name, &prefix_length)))
1440
for (; count>0; count--, info++)
1445
for (; count>0; count--, info++)
1447
DBUG_ASSERT(info->m_name != NULL);
1448
len= strlen(info->m_name);
1449
full_length= prefix_length + len;
1450
if (likely(full_length <= PFS_MAX_INFO_NAME_LENGTH))
1452
memcpy(formatted_name + prefix_length, info->m_name, len);
1453
info->m_key= register_statement_class(formatted_name, full_length, info->m_flags);
1457
pfs_print_error("register_statement_v1: name too long <%s>\n",
1465
static void register_socket_v1(const char *category,
1466
PSI_socket_info_v1 *info,
1469
REGISTER_BODY_V1(PSI_socket_key,
1470
socket_instrument_prefix,
1471
register_socket_class)
1474
#define INIT_BODY_V1(T, KEY, ID) \
1475
PFS_##T##_class *klass; \
1477
klass= find_##T##_class(KEY); \
1478
if (unlikely(klass == NULL)) \
1480
if (! klass->m_enabled) \
1482
pfs= create_##T(klass, ID); \
1483
return reinterpret_cast<PSI_##T *> (pfs)
1486
Implementation of the mutex instrumentation interface.
1487
@sa PSI_v1::init_mutex.
1490
init_mutex_v1(PSI_mutex_key key, const void *identity)
1492
INIT_BODY_V1(mutex, key, identity);
1496
Implementation of the mutex instrumentation interface.
1497
@sa PSI_v1::destroy_mutex.
1499
static void destroy_mutex_v1(PSI_mutex* mutex)
1501
PFS_mutex *pfs= reinterpret_cast<PFS_mutex*> (mutex);
1503
DBUG_ASSERT(pfs != NULL);
1509
Implementation of the rwlock instrumentation interface.
1510
@sa PSI_v1::init_rwlock.
1513
init_rwlock_v1(PSI_rwlock_key key, const void *identity)
1515
INIT_BODY_V1(rwlock, key, identity);
1519
Implementation of the rwlock instrumentation interface.
1520
@sa PSI_v1::destroy_rwlock.
1522
static void destroy_rwlock_v1(PSI_rwlock* rwlock)
1524
PFS_rwlock *pfs= reinterpret_cast<PFS_rwlock*> (rwlock);
1526
DBUG_ASSERT(pfs != NULL);
1528
destroy_rwlock(pfs);
1532
Implementation of the cond instrumentation interface.
1533
@sa PSI_v1::init_cond.
1536
init_cond_v1(PSI_cond_key key, const void *identity)
1538
INIT_BODY_V1(cond, key, identity);
1542
Implementation of the cond instrumentation interface.
1543
@sa PSI_v1::destroy_cond.
1545
static void destroy_cond_v1(PSI_cond* cond)
1547
PFS_cond *pfs= reinterpret_cast<PFS_cond*> (cond);
1549
DBUG_ASSERT(pfs != NULL);
1555
Implementation of the table instrumentation interface.
1556
@sa PSI_v1::get_table_share.
1558
static PSI_table_share*
1559
get_table_share_v1(my_bool temporary, TABLE_SHARE *share)
1561
/* Ignore temporary tables and views. */
1562
if (temporary || share->is_view)
1564
/* An instrumented thread is required, for LF_PINS. */
1565
PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1566
if (unlikely(pfs_thread == NULL))
1568
PFS_table_share* pfs_share;
1569
pfs_share= find_or_create_table_share(pfs_thread, temporary, share);
1570
return reinterpret_cast<PSI_table_share*> (pfs_share);
1574
Implementation of the table instrumentation interface.
1575
@sa PSI_v1::release_table_share.
1577
static void release_table_share_v1(PSI_table_share* share)
1579
PFS_table_share* pfs= reinterpret_cast<PFS_table_share*> (share);
1581
if (unlikely(pfs == NULL))
1584
release_table_share(pfs);
1588
Implementation of the table instrumentation interface.
1589
@sa PSI_v1::drop_table_share.
1592
drop_table_share_v1(my_bool temporary,
1593
const char *schema_name, int schema_name_length,
1594
const char *table_name, int table_name_length)
1596
/* Ignore temporary tables. */
1599
PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1600
if (unlikely(pfs_thread == NULL))
1602
/* TODO: temporary tables */
1603
drop_table_share(pfs_thread, temporary, schema_name, schema_name_length,
1604
table_name, table_name_length);
1608
Implementation of the table instrumentation interface.
1609
@sa PSI_v1::open_table.
1612
open_table_v1(PSI_table_share *share, const void *identity)
1614
PFS_table_share *pfs_table_share= reinterpret_cast<PFS_table_share*> (share);
1616
if (unlikely(pfs_table_share == NULL))
1619
/* This object is not to be instrumented. */
1620
if (! pfs_table_share->m_enabled)
1623
/* This object is instrumented, but all table instruments are disabled. */
1624
if (! global_table_io_class.m_enabled && ! global_table_lock_class.m_enabled)
1628
When the performance schema is off, do not instrument anything.
1629
Table handles have short life cycle, instrumentation will happen
1630
again if needed during the next open().
1632
if (! flag_global_instrumentation)
1635
PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1636
if (unlikely(thread == NULL))
1639
PFS_table *pfs_table= create_table(pfs_table_share, thread, identity);
1640
return reinterpret_cast<PSI_table *> (pfs_table);
1644
Implementation of the table instrumentation interface.
1645
@sa PSI_v1::unbind_table.
1647
static void unbind_table_v1(PSI_table *table)
1649
PFS_table *pfs= reinterpret_cast<PFS_table*> (table);
1650
if (likely(pfs != NULL))
1652
pfs->m_thread_owner= NULL;
1657
Implementation of the table instrumentation interface.
1658
@sa PSI_v1::rebind_table.
1661
rebind_table_v1(PSI_table_share *share, const void *identity, PSI_table *table)
1663
PFS_table *pfs= reinterpret_cast<PFS_table*> (table);
1664
if (likely(pfs != NULL))
1667
DBUG_ASSERT(pfs->m_thread_owner == NULL);
1669
/* The table handle was already instrumented, reuse it for this thread. */
1670
thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1672
if (unlikely(! pfs->m_share->m_enabled))
1678
if (unlikely(! global_table_io_class.m_enabled && ! global_table_lock_class.m_enabled))
1684
if (unlikely(! flag_global_instrumentation))
1690
pfs->m_thread_owner= thread;
1694
/* See open_table_v1() */
1696
PFS_table_share *pfs_table_share= reinterpret_cast<PFS_table_share*> (share);
1698
if (unlikely(pfs_table_share == NULL))
1701
if (! pfs_table_share->m_enabled)
1704
if (! global_table_io_class.m_enabled && ! global_table_lock_class.m_enabled)
1707
if (! flag_global_instrumentation)
1710
PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1712
PFS_table *pfs_table= create_table(pfs_table_share, thread, identity);
1713
return reinterpret_cast<PSI_table *> (pfs_table);
1717
Implementation of the table instrumentation interface.
1718
@sa PSI_v1::close_table.
1720
static void close_table_v1(PSI_table *table)
1722
PFS_table *pfs= reinterpret_cast<PFS_table*> (table);
1723
if (unlikely(pfs == NULL))
1730
init_socket_v1(PSI_socket_key key, const my_socket *fd,
1731
const struct sockaddr *addr, socklen_t addr_len)
1733
PFS_socket_class *klass;
1735
klass= find_socket_class(key);
1736
if (unlikely(klass == NULL))
1738
if (! klass->m_enabled)
1740
pfs= create_socket(klass, fd, addr, addr_len);
1741
return reinterpret_cast<PSI_socket *> (pfs);
1744
static void destroy_socket_v1(PSI_socket *socket)
1746
PFS_socket *pfs= reinterpret_cast<PFS_socket*> (socket);
1748
DBUG_ASSERT(pfs != NULL);
1750
destroy_socket(pfs);
1754
Implementation of the file instrumentation interface.
1755
@sa PSI_v1::create_file.
1757
static void create_file_v1(PSI_file_key key, const char *name, File file)
1759
if (! flag_global_instrumentation)
1761
int index= (int) file;
1762
if (unlikely(index < 0))
1764
PFS_file_class *klass= find_file_class(key);
1765
if (unlikely(klass == NULL))
1767
if (! klass->m_enabled)
1770
/* A thread is needed for LF_PINS */
1771
PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1772
if (unlikely(pfs_thread == NULL))
1775
if (flag_thread_instrumentation && ! pfs_thread->m_enabled)
1779
We want this check after pfs_thread->m_enabled,
1780
to avoid reporting false loss.
1782
if (unlikely(index >= file_handle_max))
1788
uint len= strlen(name);
1789
PFS_file *pfs_file= find_or_create_file(pfs_thread, klass, name, len, true);
1791
file_handle_array[index]= pfs_file;
1795
Arguments given from a parent to a child thread, packaged in one structure.
1796
This data is used when spawning a new instrumented thread.
1797
@sa pfs_spawn_thread.
1799
struct PFS_spawn_thread_arg
1801
ulonglong m_thread_internal_id;
1802
char m_username[USERNAME_LENGTH];
1803
uint m_username_length;
1804
char m_hostname[HOSTNAME_LENGTH];
1805
uint m_hostname_length;
1807
PSI_thread_key m_child_key;
1808
const void *m_child_identity;
1809
void *(*m_user_start_routine)(void*);
1813
void* pfs_spawn_thread(void *arg)
1815
PFS_spawn_thread_arg *typed_arg= (PFS_spawn_thread_arg*) arg;
1817
void *(*user_start_routine)(void*);
1821
/* First, attach instrumentation to this newly created pthread. */
1822
PFS_thread_class *klass= find_thread_class(typed_arg->m_child_key);
1823
if (likely(klass != NULL))
1825
pfs= create_thread(klass, typed_arg->m_child_identity, 0);
1826
if (likely(pfs != NULL))
1828
clear_thread_account(pfs);
1830
pfs->m_parent_thread_internal_id= typed_arg->m_thread_internal_id;
1832
memcpy(pfs->m_username, typed_arg->m_username, sizeof(pfs->m_username));
1833
pfs->m_username_length= typed_arg->m_username_length;
1835
memcpy(pfs->m_hostname, typed_arg->m_hostname, sizeof(pfs->m_hostname));
1836
pfs->m_hostname_length= typed_arg->m_hostname_length;
1838
set_thread_account(pfs);
1845
my_pthread_setspecific_ptr(THR_PFS, pfs);
1848
Secondly, free the memory allocated in spawn_thread_v1().
1849
It is preferable to do this before invoking the user
1850
routine, to avoid memory leaks at shutdown, in case
1851
the server exits without waiting for this thread.
1853
user_start_routine= typed_arg->m_user_start_routine;
1854
user_arg= typed_arg->m_user_arg;
1857
/* Then, execute the user code for this thread. */
1858
(*user_start_routine)(user_arg);
1864
Implementation of the thread instrumentation interface.
1865
@sa PSI_v1::spawn_thread.
1867
static int spawn_thread_v1(PSI_thread_key key,
1868
pthread_t *thread, const pthread_attr_t *attr,
1869
void *(*start_routine)(void*), void *arg)
1871
PFS_spawn_thread_arg *psi_arg;
1874
/* psi_arg can not be global, and can not be a local variable. */
1875
psi_arg= (PFS_spawn_thread_arg*) my_malloc(sizeof(PFS_spawn_thread_arg),
1877
if (unlikely(psi_arg == NULL))
1880
psi_arg->m_child_key= key;
1881
psi_arg->m_child_identity= (arg ? arg : thread);
1882
psi_arg->m_user_start_routine= start_routine;
1883
psi_arg->m_user_arg= arg;
1885
parent= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1889
Make a copy of the parent attributes.
1890
This is required, because instrumentation for this thread (the parent)
1891
may be destroyed before the child thread instrumentation is created.
1893
psi_arg->m_thread_internal_id= parent->m_thread_internal_id;
1895
memcpy(psi_arg->m_username, parent->m_username, sizeof(psi_arg->m_username));
1896
psi_arg->m_username_length= parent->m_username_length;
1898
memcpy(psi_arg->m_hostname, parent->m_hostname, sizeof(psi_arg->m_hostname));
1899
psi_arg->m_hostname_length= parent->m_hostname_length;
1903
psi_arg->m_thread_internal_id= 0;
1904
psi_arg->m_username_length= 0;
1905
psi_arg->m_hostname_length= 0;
1908
int result= pthread_create(thread, attr, pfs_spawn_thread, psi_arg);
1909
if (unlikely(result != 0))
1915
Implementation of the thread instrumentation interface.
1916
@sa PSI_v1::new_thread.
1919
new_thread_v1(PSI_thread_key key, const void *identity, ulonglong processlist_id)
1923
PFS_thread_class *klass= find_thread_class(key);
1924
if (likely(klass != NULL))
1925
pfs= create_thread(klass, identity, processlist_id);
1929
return reinterpret_cast<PSI_thread*> (pfs);
1933
Implementation of the thread instrumentation interface.
1934
@sa PSI_v1::set_thread_id.
1936
static void set_thread_id_v1(PSI_thread *thread, ulonglong processlist_id)
1938
PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread);
1939
if (unlikely(pfs == NULL))
1941
pfs->m_processlist_id= processlist_id;
1945
Implementation of the thread instrumentation interface.
1946
@sa PSI_v1::get_thread_id.
1951
PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1952
return reinterpret_cast<PSI_thread*> (pfs);
1956
Implementation of the thread instrumentation interface.
1957
@sa PSI_v1::set_thread_user.
1959
static void set_thread_user_v1(const char *user, int user_len)
1961
PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1963
DBUG_ASSERT((user != NULL) || (user_len == 0));
1964
DBUG_ASSERT(user_len >= 0);
1965
DBUG_ASSERT((uint) user_len <= sizeof(pfs->m_username));
1967
if (unlikely(pfs == NULL))
1970
aggregate_thread(pfs, pfs->m_account, pfs->m_user, pfs->m_host);
1972
pfs->m_session_lock.allocated_to_dirty();
1974
clear_thread_account(pfs);
1977
memcpy(pfs->m_username, user, user_len);
1978
pfs->m_username_length= user_len;
1980
set_thread_account(pfs);
1983
if (flag_thread_instrumentation)
1985
if ((pfs->m_username_length > 0) && (pfs->m_hostname_length > 0))
1988
TODO: performance improvement.
1989
Once performance_schema.USERS is exposed,
1990
we can use PFS_user::m_enabled instead of looking up
1991
SETUP_ACTORS every time.
1993
lookup_setup_actor(pfs,
1994
pfs->m_username, pfs->m_username_length,
1995
pfs->m_hostname, pfs->m_hostname_length,
2000
pfs->m_enabled= enabled;
2002
pfs->m_session_lock.dirty_to_allocated();
2006
Implementation of the thread instrumentation interface.
2007
@sa PSI_v1::set_thread_account.
2009
static void set_thread_account_v1(const char *user, int user_len,
2010
const char *host, int host_len)
2012
PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2014
DBUG_ASSERT((user != NULL) || (user_len == 0));
2015
DBUG_ASSERT(user_len >= 0);
2016
DBUG_ASSERT((uint) user_len <= sizeof(pfs->m_username));
2017
DBUG_ASSERT((host != NULL) || (host_len == 0));
2018
DBUG_ASSERT(host_len >= 0);
2019
DBUG_ASSERT((uint) host_len <= sizeof(pfs->m_hostname));
2021
if (unlikely(pfs == NULL))
2024
pfs->m_session_lock.allocated_to_dirty();
2026
clear_thread_account(pfs);
2029
memcpy(pfs->m_hostname, host, host_len);
2030
pfs->m_hostname_length= host_len;
2033
memcpy(pfs->m_username, user, user_len);
2034
pfs->m_username_length= user_len;
2036
set_thread_account(pfs);
2039
if (flag_thread_instrumentation)
2041
if ((pfs->m_username_length > 0) && (pfs->m_hostname_length > 0))
2044
TODO: performance improvement.
2045
Once performance_schema.USERS is exposed,
2046
we can use PFS_user::m_enabled instead of looking up
2047
SETUP_ACTORS every time.
2049
lookup_setup_actor(pfs,
2050
pfs->m_username, pfs->m_username_length,
2051
pfs->m_hostname, pfs->m_hostname_length,
2055
pfs->m_enabled= enabled;
2057
pfs->m_session_lock.dirty_to_allocated();
2061
Implementation of the thread instrumentation interface.
2062
@sa PSI_v1::set_thread_db.
2064
static void set_thread_db_v1(const char* db, int db_len)
2066
PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2068
DBUG_ASSERT((db != NULL) || (db_len == 0));
2069
DBUG_ASSERT(db_len >= 0);
2070
DBUG_ASSERT((uint) db_len <= sizeof(pfs->m_dbname));
2072
if (likely(pfs != NULL))
2074
pfs->m_stmt_lock.allocated_to_dirty();
2076
memcpy(pfs->m_dbname, db, db_len);
2077
pfs->m_dbname_length= db_len;
2078
pfs->m_stmt_lock.dirty_to_allocated();
2083
Implementation of the thread instrumentation interface.
2084
@sa PSI_v1::set_thread_command.
2086
static void set_thread_command_v1(int command)
2088
PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2090
DBUG_ASSERT(command >= 0);
2091
DBUG_ASSERT(command <= (int) COM_END);
2093
if (likely(pfs != NULL))
2095
pfs->m_command= command;
2100
Implementation of the thread instrumentation interface.
2101
@sa PSI_v1::set_thread_start_time.
2103
static void set_thread_start_time_v1(time_t start_time)
2105
PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2107
if (likely(pfs != NULL))
2109
pfs->m_start_time= start_time;
2114
Implementation of the thread instrumentation interface.
2115
@sa PSI_v1::set_thread_state.
2117
static void set_thread_state_v1(const char* state)
2123
Implementation of the thread instrumentation interface.
2124
@sa PSI_v1::set_thread_info.
2126
static void set_thread_info_v1(const char* info, uint info_len)
2128
PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2130
DBUG_ASSERT((info != NULL) || (info_len == 0));
2132
if (likely(pfs != NULL))
2134
if ((info != NULL) && (info_len > 0))
2136
if (info_len > sizeof(pfs->m_processlist_info))
2137
info_len= sizeof(pfs->m_processlist_info);
2139
pfs->m_stmt_lock.allocated_to_dirty();
2140
memcpy(pfs->m_processlist_info, info, info_len);
2141
pfs->m_processlist_info_length= info_len;
2142
pfs->m_stmt_lock.dirty_to_allocated();
2146
pfs->m_stmt_lock.allocated_to_dirty();
2147
pfs->m_processlist_info_length= 0;
2148
pfs->m_stmt_lock.dirty_to_allocated();
2154
Implementation of the thread instrumentation interface.
2155
@sa PSI_v1::set_thread.
2157
static void set_thread_v1(PSI_thread* thread)
2159
PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread);
2160
my_pthread_setspecific_ptr(THR_PFS, pfs);
2164
Implementation of the thread instrumentation interface.
2165
@sa PSI_v1::delete_current_thread.
2167
static void delete_current_thread_v1(void)
2169
PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2172
aggregate_thread(thread, thread->m_account, thread->m_user, thread->m_host);
2173
my_pthread_setspecific_ptr(THR_PFS, NULL);
2174
destroy_thread(thread);
2179
Implementation of the thread instrumentation interface.
2180
@sa PSI_v1::delete_thread.
2182
static void delete_thread_v1(PSI_thread *thread)
2184
PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread);
2188
aggregate_thread(pfs, pfs->m_account, pfs->m_user, pfs->m_host);
2189
destroy_thread(pfs);
2194
Implementation of the mutex instrumentation interface.
2195
@sa PSI_v1::start_mutex_wait.
2197
static PSI_mutex_locker*
2198
start_mutex_wait_v1(PSI_mutex_locker_state *state,
2199
PSI_mutex *mutex, PSI_mutex_operation op,
2200
const char *src_file, uint src_line)
2202
PFS_mutex *pfs_mutex= reinterpret_cast<PFS_mutex*> (mutex);
2203
DBUG_ASSERT((int) op >= 0);
2204
DBUG_ASSERT((uint) op < array_elements(mutex_operation_map));
2205
DBUG_ASSERT(state != NULL);
2207
DBUG_ASSERT(pfs_mutex != NULL);
2208
DBUG_ASSERT(pfs_mutex->m_class != NULL);
2210
if (! pfs_mutex->m_enabled)
2213
register uint flags;
2214
ulonglong timer_start= 0;
2216
if (flag_thread_instrumentation)
2218
PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2219
if (unlikely(pfs_thread == NULL))
2221
if (! pfs_thread->m_enabled)
2223
state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
2224
flags= STATE_FLAG_THREAD;
2226
if (pfs_mutex->m_timed)
2228
timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2229
state->m_timer_start= timer_start;
2230
flags|= STATE_FLAG_TIMED;
2233
if (flag_events_waits_current)
2235
if (unlikely(pfs_thread->m_events_waits_current >=
2236
& pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
2241
PFS_events_waits *wait= pfs_thread->m_events_waits_current;
2242
state->m_wait= wait;
2243
flags|= STATE_FLAG_EVENT;
2245
PFS_events_waits *parent_event= wait - 1;
2246
wait->m_event_type= EVENT_TYPE_WAIT;
2247
wait->m_nesting_event_id= parent_event->m_event_id;
2248
wait->m_nesting_event_type= parent_event->m_event_type;
2250
wait->m_thread= pfs_thread;
2251
wait->m_class= pfs_mutex->m_class;
2252
wait->m_timer_start= timer_start;
2253
wait->m_timer_end= 0;
2254
wait->m_object_instance_addr= pfs_mutex->m_identity;
2255
wait->m_event_id= pfs_thread->m_event_id++;
2256
wait->m_end_event_id= 0;
2257
wait->m_operation= mutex_operation_map[(int) op];
2258
wait->m_source_file= src_file;
2259
wait->m_source_line= src_line;
2260
wait->m_wait_class= WAIT_CLASS_MUTEX;
2262
pfs_thread->m_events_waits_current++;
2267
if (pfs_mutex->m_timed)
2269
timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2270
state->m_timer_start= timer_start;
2271
flags= STATE_FLAG_TIMED;
2272
state->m_thread= NULL;
2279
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
2280
pfs_mutex->m_mutex_stat.m_wait_stat.aggregate_counted();
2285
state->m_flags= flags;
2286
state->m_mutex= mutex;
2287
return reinterpret_cast<PSI_mutex_locker*> (state);
2291
Implementation of the rwlock instrumentation interface.
2292
@sa PSI_v1::start_rwlock_rdwait
2293
@sa PSI_v1::start_rwlock_wrwait
2295
static PSI_rwlock_locker*
2296
start_rwlock_wait_v1(PSI_rwlock_locker_state *state,
2298
PSI_rwlock_operation op,
2299
const char *src_file, uint src_line)
2301
PFS_rwlock *pfs_rwlock= reinterpret_cast<PFS_rwlock*> (rwlock);
2302
DBUG_ASSERT(static_cast<int> (op) >= 0);
2303
DBUG_ASSERT(static_cast<uint> (op) < array_elements(rwlock_operation_map));
2304
DBUG_ASSERT(state != NULL);
2305
DBUG_ASSERT(pfs_rwlock != NULL);
2306
DBUG_ASSERT(pfs_rwlock->m_class != NULL);
2308
if (! pfs_rwlock->m_enabled)
2311
register uint flags;
2312
ulonglong timer_start= 0;
2314
if (flag_thread_instrumentation)
2316
PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2317
if (unlikely(pfs_thread == NULL))
2319
if (! pfs_thread->m_enabled)
2321
state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
2322
flags= STATE_FLAG_THREAD;
2324
if (pfs_rwlock->m_timed)
2326
timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2327
state->m_timer_start= timer_start;
2328
flags|= STATE_FLAG_TIMED;
2331
if (flag_events_waits_current)
2333
if (unlikely(pfs_thread->m_events_waits_current >=
2334
& pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
2339
PFS_events_waits *wait= pfs_thread->m_events_waits_current;
2340
state->m_wait= wait;
2341
flags|= STATE_FLAG_EVENT;
2343
PFS_events_waits *parent_event= wait - 1;
2344
wait->m_event_type= EVENT_TYPE_WAIT;
2345
wait->m_nesting_event_id= parent_event->m_event_id;
2346
wait->m_nesting_event_type= parent_event->m_event_type;
2348
wait->m_thread= pfs_thread;
2349
wait->m_class= pfs_rwlock->m_class;
2350
wait->m_timer_start= timer_start;
2351
wait->m_timer_end= 0;
2352
wait->m_object_instance_addr= pfs_rwlock->m_identity;
2353
wait->m_event_id= pfs_thread->m_event_id++;
2354
wait->m_end_event_id= 0;
2355
wait->m_operation= rwlock_operation_map[static_cast<int> (op)];
2356
wait->m_source_file= src_file;
2357
wait->m_source_line= src_line;
2358
wait->m_wait_class= WAIT_CLASS_RWLOCK;
2360
pfs_thread->m_events_waits_current++;
2365
if (pfs_rwlock->m_timed)
2367
timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2368
state->m_timer_start= timer_start;
2369
flags= STATE_FLAG_TIMED;
2370
state->m_thread= NULL;
2377
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
2378
pfs_rwlock->m_rwlock_stat.m_wait_stat.aggregate_counted();
2383
state->m_flags= flags;
2384
state->m_rwlock= rwlock;
2385
return reinterpret_cast<PSI_rwlock_locker*> (state);
2389
Implementation of the cond instrumentation interface.
2390
@sa PSI_v1::start_cond_wait.
2392
static PSI_cond_locker*
2393
start_cond_wait_v1(PSI_cond_locker_state *state,
2394
PSI_cond *cond, PSI_mutex *mutex,
2395
PSI_cond_operation op,
2396
const char *src_file, uint src_line)
2399
Note about the unused PSI_mutex *mutex parameter:
2400
In the pthread library, a call to pthread_cond_wait()
2401
causes an unlock() + lock() on the mutex associated with the condition.
2402
This mutex operation is not instrumented, so the mutex will still
2403
appear as locked when a thread is waiting on a condition.
2404
This has no impact now, as unlock_mutex() is not recording events.
2405
When unlock_mutex() is implemented by later work logs,
2406
this parameter here will be used to adjust the mutex state,
2407
in start_cond_wait_v1() and end_cond_wait_v1().
2409
PFS_cond *pfs_cond= reinterpret_cast<PFS_cond*> (cond);
2410
DBUG_ASSERT(static_cast<int> (op) >= 0);
2411
DBUG_ASSERT(static_cast<uint> (op) < array_elements(cond_operation_map));
2412
DBUG_ASSERT(state != NULL);
2413
DBUG_ASSERT(pfs_cond != NULL);
2414
DBUG_ASSERT(pfs_cond->m_class != NULL);
2416
if (! pfs_cond->m_enabled)
2419
register uint flags;
2420
ulonglong timer_start= 0;
2422
if (flag_thread_instrumentation)
2424
PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2425
if (unlikely(pfs_thread == NULL))
2427
if (! pfs_thread->m_enabled)
2429
state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
2430
flags= STATE_FLAG_THREAD;
2432
if (pfs_cond->m_timed)
2434
timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2435
state->m_timer_start= timer_start;
2436
flags|= STATE_FLAG_TIMED;
2439
if (flag_events_waits_current)
2441
if (unlikely(pfs_thread->m_events_waits_current >=
2442
& pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
2447
PFS_events_waits *wait= pfs_thread->m_events_waits_current;
2448
state->m_wait= wait;
2449
flags|= STATE_FLAG_EVENT;
2451
PFS_events_waits *parent_event= wait - 1;
2452
wait->m_event_type= EVENT_TYPE_WAIT;
2453
wait->m_nesting_event_id= parent_event->m_event_id;
2454
wait->m_nesting_event_type= parent_event->m_event_type;
2456
wait->m_thread= pfs_thread;
2457
wait->m_class= pfs_cond->m_class;
2458
wait->m_timer_start= timer_start;
2459
wait->m_timer_end= 0;
2460
wait->m_object_instance_addr= pfs_cond->m_identity;
2461
wait->m_event_id= pfs_thread->m_event_id++;
2462
wait->m_end_event_id= 0;
2463
wait->m_operation= cond_operation_map[static_cast<int> (op)];
2464
wait->m_source_file= src_file;
2465
wait->m_source_line= src_line;
2466
wait->m_wait_class= WAIT_CLASS_COND;
2468
pfs_thread->m_events_waits_current++;
2473
if (pfs_cond->m_timed)
2475
timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2476
state->m_timer_start= timer_start;
2477
flags= STATE_FLAG_TIMED;
2484
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
2485
pfs_cond->m_cond_stat.m_wait_stat.aggregate_counted();
2490
state->m_flags= flags;
2491
state->m_cond= cond;
2492
state->m_mutex= mutex;
2493
return reinterpret_cast<PSI_cond_locker*> (state);
2496
static inline PFS_TL_LOCK_TYPE lock_flags_to_lock_type(uint flags)
2498
enum thr_lock_type value= static_cast<enum thr_lock_type> (flags);
2504
case TL_READ_WITH_SHARED_LOCKS:
2505
return PFS_TL_READ_WITH_SHARED_LOCKS;
2506
case TL_READ_HIGH_PRIORITY:
2507
return PFS_TL_READ_HIGH_PRIORITY;
2508
case TL_READ_NO_INSERT:
2509
return PFS_TL_READ_NO_INSERT;
2510
case TL_WRITE_ALLOW_WRITE:
2511
return PFS_TL_WRITE_ALLOW_WRITE;
2512
case TL_WRITE_CONCURRENT_INSERT:
2513
return PFS_TL_WRITE_CONCURRENT_INSERT;
2514
case TL_WRITE_DELAYED:
2515
return PFS_TL_WRITE_DELAYED;
2516
case TL_WRITE_LOW_PRIORITY:
2517
return PFS_TL_WRITE_LOW_PRIORITY;
2519
return PFS_TL_WRITE;
2524
case TL_READ_DEFAULT:
2525
case TL_WRITE_DEFAULT:
2534
static inline PFS_TL_LOCK_TYPE external_lock_flags_to_lock_type(uint flags)
2536
DBUG_ASSERT(flags == F_RDLCK || flags == F_WRLCK);
2537
return (flags == F_RDLCK ? PFS_TL_READ_EXTERNAL : PFS_TL_WRITE_EXTERNAL);
2541
Implementation of the table instrumentation interface.
2542
@sa PSI_v1::start_table_io_wait_v1
2544
static PSI_table_locker*
2545
start_table_io_wait_v1(PSI_table_locker_state *state,
2547
PSI_table_io_operation op,
2549
const char *src_file, uint src_line)
2551
DBUG_ASSERT(static_cast<int> (op) >= 0);
2552
DBUG_ASSERT(static_cast<uint> (op) < array_elements(table_io_operation_map));
2553
DBUG_ASSERT(state != NULL);
2554
PFS_table *pfs_table= reinterpret_cast<PFS_table*> (table);
2555
DBUG_ASSERT(pfs_table != NULL);
2556
DBUG_ASSERT(pfs_table->m_share != NULL);
2558
if (! pfs_table->m_io_enabled)
2561
PFS_thread *pfs_thread= pfs_table->m_thread_owner;
2563
DBUG_ASSERT(pfs_thread ==
2564
my_pthread_getspecific_ptr(PFS_thread*, THR_PFS));
2566
register uint flags;
2567
ulonglong timer_start= 0;
2569
if (flag_thread_instrumentation)
2571
if (pfs_thread == NULL)
2573
if (! pfs_thread->m_enabled)
2575
state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
2576
flags= STATE_FLAG_THREAD;
2578
if (pfs_table->m_io_timed)
2580
timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2581
state->m_timer_start= timer_start;
2582
flags|= STATE_FLAG_TIMED;
2585
if (flag_events_waits_current)
2587
if (unlikely(pfs_thread->m_events_waits_current >=
2588
& pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
2593
PFS_events_waits *wait= pfs_thread->m_events_waits_current;
2594
state->m_wait= wait;
2595
flags|= STATE_FLAG_EVENT;
2597
PFS_events_waits *parent_event= wait - 1;
2598
wait->m_event_type= EVENT_TYPE_WAIT;
2599
wait->m_nesting_event_id= parent_event->m_event_id;
2600
wait->m_nesting_event_type= parent_event->m_event_type;
2602
PFS_table_share *share= pfs_table->m_share;
2603
wait->m_thread= pfs_thread;
2604
wait->m_class= &global_table_io_class;
2605
wait->m_timer_start= timer_start;
2606
wait->m_timer_end= 0;
2607
wait->m_object_instance_addr= pfs_table->m_identity;
2608
wait->m_event_id= pfs_thread->m_event_id++;
2609
wait->m_end_event_id= 0;
2610
wait->m_operation= table_io_operation_map[static_cast<int> (op)];
2612
wait->m_object_type= share->get_object_type();
2613
wait->m_weak_table_share= share;
2614
wait->m_weak_version= share->get_version();
2615
wait->m_index= index;
2616
wait->m_source_file= src_file;
2617
wait->m_source_line= src_line;
2618
wait->m_wait_class= WAIT_CLASS_TABLE;
2620
pfs_thread->m_events_waits_current++;
2625
if (pfs_table->m_io_timed)
2627
timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2628
state->m_timer_start= timer_start;
2629
flags= STATE_FLAG_TIMED;
2633
/* TODO: consider a shortcut here */
2638
state->m_flags= flags;
2639
state->m_table= table;
2640
state->m_io_operation= op;
2641
state->m_index= index;
2642
return reinterpret_cast<PSI_table_locker*> (state);
2646
Implementation of the table instrumentation interface.
2647
@sa PSI_v1::start_table_lock_wait.
2649
static PSI_table_locker*
2650
start_table_lock_wait_v1(PSI_table_locker_state *state,
2652
PSI_table_lock_operation op,
2654
const char *src_file, uint src_line)
2656
DBUG_ASSERT(state != NULL);
2657
DBUG_ASSERT((op == PSI_TABLE_LOCK) || (op == PSI_TABLE_EXTERNAL_LOCK));
2659
PFS_table *pfs_table= reinterpret_cast<PFS_table*> (table);
2661
DBUG_ASSERT(pfs_table != NULL);
2662
DBUG_ASSERT(pfs_table->m_share != NULL);
2664
if (! pfs_table->m_lock_enabled)
2667
PFS_thread *pfs_thread= pfs_table->m_thread_owner;
2669
PFS_TL_LOCK_TYPE lock_type;
2673
case PSI_TABLE_LOCK:
2674
lock_type= lock_flags_to_lock_type(op_flags);
2676
case PSI_TABLE_EXTERNAL_LOCK:
2678
See the handler::external_lock() API design,
2679
there is no handler::external_unlock().
2681
if (op_flags == F_UNLCK)
2683
lock_type= external_lock_flags_to_lock_type(op_flags);
2686
lock_type= PFS_TL_READ;
2690
DBUG_ASSERT((uint) lock_type < array_elements(table_lock_operation_map));
2692
register uint flags;
2693
ulonglong timer_start= 0;
2695
if (flag_thread_instrumentation)
2697
if (pfs_thread == NULL)
2699
if (! pfs_thread->m_enabled)
2701
state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
2702
flags= STATE_FLAG_THREAD;
2704
if (pfs_table->m_lock_timed)
2706
timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2707
state->m_timer_start= timer_start;
2708
flags|= STATE_FLAG_TIMED;
2711
if (flag_events_waits_current)
2713
if (unlikely(pfs_thread->m_events_waits_current >=
2714
& pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
2719
PFS_events_waits *wait= pfs_thread->m_events_waits_current;
2720
state->m_wait= wait;
2721
flags|= STATE_FLAG_EVENT;
2723
PFS_events_waits *parent_event= wait - 1;
2724
wait->m_event_type= EVENT_TYPE_WAIT;
2725
wait->m_nesting_event_id= parent_event->m_event_id;
2726
wait->m_nesting_event_type= parent_event->m_event_type;
2728
PFS_table_share *share= pfs_table->m_share;
2729
wait->m_thread= pfs_thread;
2730
wait->m_class= &global_table_lock_class;
2731
wait->m_timer_start= timer_start;
2732
wait->m_timer_end= 0;
2733
wait->m_object_instance_addr= pfs_table->m_identity;
2734
wait->m_event_id= pfs_thread->m_event_id++;
2735
wait->m_end_event_id= 0;
2736
wait->m_operation= table_lock_operation_map[lock_type];
2738
wait->m_object_type= share->get_object_type();
2739
wait->m_weak_table_share= share;
2740
wait->m_weak_version= share->get_version();
2742
wait->m_source_file= src_file;
2743
wait->m_source_line= src_line;
2744
wait->m_wait_class= WAIT_CLASS_TABLE;
2746
pfs_thread->m_events_waits_current++;
2751
if (pfs_table->m_lock_timed)
2753
timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2754
state->m_timer_start= timer_start;
2755
flags= STATE_FLAG_TIMED;
2759
/* TODO: consider a shortcut here */
2764
state->m_flags= flags;
2765
state->m_table= table;
2766
state->m_index= lock_type;
2767
return reinterpret_cast<PSI_table_locker*> (state);
2771
Implementation of the file instrumentation interface.
2772
@sa PSI_v1::get_thread_file_name_locker.
2774
static PSI_file_locker*
2775
get_thread_file_name_locker_v1(PSI_file_locker_state *state,
2777
PSI_file_operation op,
2778
const char *name, const void *identity)
2780
DBUG_ASSERT(static_cast<int> (op) >= 0);
2781
DBUG_ASSERT(static_cast<uint> (op) < array_elements(file_operation_map));
2782
DBUG_ASSERT(state != NULL);
2784
if (! flag_global_instrumentation)
2786
PFS_file_class *klass= find_file_class(key);
2787
if (unlikely(klass == NULL))
2789
if (! klass->m_enabled)
2792
/* Needed for the LF_HASH */
2793
PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2794
if (unlikely(pfs_thread == NULL))
2797
if (flag_thread_instrumentation && ! pfs_thread->m_enabled)
2800
register uint flags;
2802
state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
2803
flags= STATE_FLAG_THREAD;
2806
flags|= STATE_FLAG_TIMED;
2808
if (flag_events_waits_current)
2810
if (unlikely(pfs_thread->m_events_waits_current >=
2811
& pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
2816
PFS_events_waits *wait= pfs_thread->m_events_waits_current;
2817
state->m_wait= wait;
2818
flags|= STATE_FLAG_EVENT;
2820
PFS_events_waits *parent_event= wait - 1;
2821
wait->m_event_type= EVENT_TYPE_WAIT;
2822
wait->m_nesting_event_id= parent_event->m_event_id;
2823
wait->m_nesting_event_type= parent_event->m_event_type;
2825
wait->m_thread= pfs_thread;
2826
wait->m_class= klass;
2827
wait->m_timer_start= 0;
2828
wait->m_timer_end= 0;
2829
wait->m_object_instance_addr= NULL;
2830
wait->m_weak_file= NULL;
2831
wait->m_weak_version= 0;
2832
wait->m_event_id= pfs_thread->m_event_id++;
2833
wait->m_end_event_id= 0;
2834
wait->m_operation= file_operation_map[static_cast<int> (op)];
2835
wait->m_wait_class= WAIT_CLASS_FILE;
2837
pfs_thread->m_events_waits_current++;
2840
state->m_flags= flags;
2841
state->m_file= NULL;
2842
state->m_name= name;
2843
state->m_class= klass;
2844
state->m_operation= op;
2845
return reinterpret_cast<PSI_file_locker*> (state);
2849
Implementation of the file instrumentation interface.
2850
@sa PSI_v1::get_thread_file_stream_locker.
2852
static PSI_file_locker*
2853
get_thread_file_stream_locker_v1(PSI_file_locker_state *state,
2854
PSI_file *file, PSI_file_operation op)
2856
PFS_file *pfs_file= reinterpret_cast<PFS_file*> (file);
2857
DBUG_ASSERT(static_cast<int> (op) >= 0);
2858
DBUG_ASSERT(static_cast<uint> (op) < array_elements(file_operation_map));
2859
DBUG_ASSERT(state != NULL);
2861
if (unlikely(pfs_file == NULL))
2863
DBUG_ASSERT(pfs_file->m_class != NULL);
2864
PFS_file_class *klass= pfs_file->m_class;
2866
if (! pfs_file->m_enabled)
2869
register uint flags;
2871
if (flag_thread_instrumentation)
2873
PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2874
if (unlikely(pfs_thread == NULL))
2876
if (! pfs_thread->m_enabled)
2878
state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
2879
flags= STATE_FLAG_THREAD;
2881
if (pfs_file->m_timed)
2882
flags|= STATE_FLAG_TIMED;
2884
if (flag_events_waits_current)
2886
if (unlikely(pfs_thread->m_events_waits_current >=
2887
& pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
2892
PFS_events_waits *wait= pfs_thread->m_events_waits_current;
2893
state->m_wait= wait;
2894
flags|= STATE_FLAG_EVENT;
2896
PFS_events_waits *parent_event= wait - 1;
2897
wait->m_event_type= EVENT_TYPE_WAIT;
2898
wait->m_nesting_event_id= parent_event->m_event_id;
2899
wait->m_nesting_event_type= parent_event->m_event_type;
2901
wait->m_thread= pfs_thread;
2902
wait->m_class= klass;
2903
wait->m_timer_start= 0;
2904
wait->m_timer_end= 0;
2905
wait->m_object_instance_addr= pfs_file;
2906
wait->m_weak_file= pfs_file;
2907
wait->m_weak_version= pfs_file->get_version();
2908
wait->m_event_id= pfs_thread->m_event_id++;
2909
wait->m_end_event_id= 0;
2910
wait->m_operation= file_operation_map[static_cast<int> (op)];
2911
wait->m_wait_class= WAIT_CLASS_FILE;
2913
pfs_thread->m_events_waits_current++;
2918
state->m_thread= NULL;
2919
if (pfs_file->m_timed)
2921
flags= STATE_FLAG_TIMED;
2925
/* TODO: consider a shortcut. */
2930
state->m_flags= flags;
2931
state->m_file= reinterpret_cast<PSI_file*> (pfs_file);
2932
state->m_operation= op;
2933
state->m_name= NULL;
2934
state->m_class= klass;
2935
return reinterpret_cast<PSI_file_locker*> (state);
2939
Implementation of the file instrumentation interface.
2940
@sa PSI_v1::get_thread_file_descriptor_locker.
2942
static PSI_file_locker*
2943
get_thread_file_descriptor_locker_v1(PSI_file_locker_state *state,
2944
File file, PSI_file_operation op)
2946
int index= static_cast<int> (file);
2947
DBUG_ASSERT(static_cast<int> (op) >= 0);
2948
DBUG_ASSERT(static_cast<uint> (op) < array_elements(file_operation_map));
2949
DBUG_ASSERT(state != NULL);
2951
if (unlikely((index < 0) || (index >= file_handle_max)))
2954
PFS_file *pfs_file= file_handle_array[index];
2955
if (unlikely(pfs_file == NULL))
2959
We are about to close a file by descriptor number,
2960
and the calling code still holds the descriptor.
2961
Cleanup the file descriptor <--> file instrument association.
2962
Remove the instrumentation *before* the close to avoid race
2963
conditions with another thread opening a file
2964
(that could be given the same descriptor).
2966
if (op == PSI_FILE_CLOSE)
2967
file_handle_array[index]= NULL;
2969
if (! pfs_file->m_enabled)
2972
DBUG_ASSERT(pfs_file->m_class != NULL);
2973
PFS_file_class *klass= pfs_file->m_class;
2975
register uint flags;
2977
if (flag_thread_instrumentation)
2979
PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2980
if (unlikely(pfs_thread == NULL))
2982
if (! pfs_thread->m_enabled)
2984
state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
2985
flags= STATE_FLAG_THREAD;
2987
if (pfs_file->m_timed)
2988
flags|= STATE_FLAG_TIMED;
2990
if (flag_events_waits_current)
2992
if (unlikely(pfs_thread->m_events_waits_current >=
2993
& pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
2998
PFS_events_waits *wait= pfs_thread->m_events_waits_current;
2999
state->m_wait= wait;
3000
flags|= STATE_FLAG_EVENT;
3002
PFS_events_waits *parent_event= wait - 1;
3003
wait->m_event_type= EVENT_TYPE_WAIT;
3004
wait->m_nesting_event_id= parent_event->m_event_id;
3005
wait->m_nesting_event_type= parent_event->m_event_type;
3007
wait->m_thread= pfs_thread;
3008
wait->m_class= klass;
3009
wait->m_timer_start= 0;
3010
wait->m_timer_end= 0;
3011
wait->m_object_instance_addr= pfs_file;
3012
wait->m_weak_file= pfs_file;
3013
wait->m_weak_version= pfs_file->get_version();
3014
wait->m_event_id= pfs_thread->m_event_id++;
3015
wait->m_end_event_id= 0;
3016
wait->m_operation= file_operation_map[static_cast<int> (op)];
3017
wait->m_wait_class= WAIT_CLASS_FILE;
3019
pfs_thread->m_events_waits_current++;
3024
state->m_thread= NULL;
3025
if (pfs_file->m_timed)
3027
flags= STATE_FLAG_TIMED;
3031
/* TODO: consider a shortcut. */
3036
state->m_flags= flags;
3037
state->m_file= reinterpret_cast<PSI_file*> (pfs_file);
3038
state->m_operation= op;
3039
state->m_name= NULL;
3040
state->m_class= klass;
3041
return reinterpret_cast<PSI_file_locker*> (state);
3044
/** Socket locker */
3046
static PSI_socket_locker*
3047
start_socket_wait_v1(PSI_socket_locker_state *state,
3049
PSI_socket_operation op,
3051
const char *src_file, uint src_line)
3053
DBUG_ASSERT(static_cast<int> (op) >= 0);
3054
DBUG_ASSERT(static_cast<uint> (op) < array_elements(socket_operation_map));
3055
DBUG_ASSERT(state != NULL);
3056
PFS_socket *pfs_socket= reinterpret_cast<PFS_socket*> (socket);
3058
DBUG_ASSERT(pfs_socket != NULL);
3059
DBUG_ASSERT(pfs_socket->m_class != NULL);
3061
if (!pfs_socket->m_enabled || pfs_socket->m_idle)
3064
register uint flags= 0;
3065
ulonglong timer_start= 0;
3067
if (flag_thread_instrumentation)
3069
PFS_thread *pfs_thread= pfs_socket->m_thread_owner;
3071
if (unlikely(pfs_thread == NULL))
3074
if (!pfs_thread->m_enabled)
3077
state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
3078
flags= STATE_FLAG_THREAD;
3080
if (pfs_socket->m_timed)
3082
timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
3083
state->m_timer_start= timer_start;
3084
flags|= STATE_FLAG_TIMED;
3087
if (flag_events_waits_current)
3089
if (unlikely(pfs_thread->m_events_waits_current >=
3090
& pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
3095
PFS_events_waits *wait= pfs_thread->m_events_waits_current;
3096
state->m_wait= wait;
3097
flags|= STATE_FLAG_EVENT;
3099
PFS_events_waits *parent_event= wait - 1;
3100
wait->m_event_type= EVENT_TYPE_WAIT;
3101
wait->m_nesting_event_id= parent_event->m_event_id;
3102
wait->m_nesting_event_type= parent_event->m_event_type;
3103
wait->m_thread= pfs_thread;
3104
wait->m_class= pfs_socket->m_class;
3105
wait->m_timer_start= timer_start;
3106
wait->m_timer_end= 0;
3107
wait->m_object_instance_addr= pfs_socket->m_identity;
3108
wait->m_weak_socket= pfs_socket;
3109
wait->m_weak_version= pfs_socket->get_version();
3110
wait->m_event_id= pfs_thread->m_event_id++;
3111
wait->m_end_event_id= 0;
3112
wait->m_operation= socket_operation_map[static_cast<int>(op)];
3113
wait->m_source_file= src_file;
3114
wait->m_source_line= src_line;
3115
wait->m_number_of_bytes= count;
3116
wait->m_wait_class= WAIT_CLASS_SOCKET;
3118
pfs_thread->m_events_waits_current++;
3123
if (pfs_socket->m_timed)
3125
timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
3126
state->m_timer_start= timer_start;
3127
flags= STATE_FLAG_TIMED;
3132
Even if timing is disabled, end_socket_wait() still needs a locker to
3133
capture the number of bytes sent or received by the socket operation.
3134
For operations that do not have a byte count, then just increment the
3135
event counter and return a NULL locker.
3139
case PSI_SOCKET_CONNECT:
3140
case PSI_SOCKET_CREATE:
3141
case PSI_SOCKET_BIND:
3142
case PSI_SOCKET_SEEK:
3143
case PSI_SOCKET_OPT:
3144
case PSI_SOCKET_STAT:
3145
case PSI_SOCKET_SHUTDOWN:
3146
case PSI_SOCKET_CLOSE:
3147
case PSI_SOCKET_SELECT:
3148
pfs_socket->m_socket_stat.m_io_stat.m_misc.aggregate_counted();
3156
state->m_flags= flags;
3157
state->m_socket= socket;
3158
state->m_operation= op;
3159
return reinterpret_cast<PSI_socket_locker*> (state);
3163
Implementation of the mutex instrumentation interface.
3164
@sa PSI_v1::unlock_mutex.
3166
static void unlock_mutex_v1(PSI_mutex *mutex)
3168
PFS_mutex *pfs_mutex= reinterpret_cast<PFS_mutex*> (mutex);
3170
DBUG_ASSERT(pfs_mutex != NULL);
3173
Note that this code is still protected by the instrumented mutex,
3174
and therefore is thread safe. See inline_mysql_mutex_unlock().
3177
/* Always update the instrumented state */
3178
pfs_mutex->m_owner= NULL;
3179
pfs_mutex->m_last_locked= 0;
3183
See WL#2333: SHOW ENGINE ... LOCK STATUS.
3184
PFS_mutex::m_lock_stat is not exposed in user visible tables
3185
currently, so there is no point spending time computing it.
3187
if (! pfs_mutex->m_enabled)
3190
if (! pfs_mutex->m_timed)
3193
ulonglong locked_time;
3194
locked_time= get_timer_pico_value(wait_timer) - pfs_mutex->m_last_locked;
3195
pfs_mutex->m_mutex_stat.m_lock_stat.aggregate_value(locked_time);
3200
Implementation of the rwlock instrumentation interface.
3201
@sa PSI_v1::unlock_rwlock.
3203
static void unlock_rwlock_v1(PSI_rwlock *rwlock)
3205
PFS_rwlock *pfs_rwlock= reinterpret_cast<PFS_rwlock*> (rwlock);
3206
DBUG_ASSERT(pfs_rwlock != NULL);
3207
DBUG_ASSERT(pfs_rwlock == sanitize_rwlock(pfs_rwlock));
3208
DBUG_ASSERT(pfs_rwlock->m_class != NULL);
3209
DBUG_ASSERT(pfs_rwlock->m_lock.is_populated());
3211
bool last_writer= false;
3212
bool last_reader= false;
3215
Note that this code is still protected by the instrumented rwlock,
3217
- thread safe for write locks
3218
- almost thread safe for read locks (pfs_rwlock->m_readers is unsafe).
3219
See inline_mysql_rwlock_unlock()
3222
/* Always update the instrumented state */
3223
if (pfs_rwlock->m_writer != NULL)
3225
/* Nominal case, a writer is unlocking. */
3227
pfs_rwlock->m_writer= NULL;
3228
/* Reset the readers stats, they could be off */
3229
pfs_rwlock->m_readers= 0;
3231
else if (likely(pfs_rwlock->m_readers > 0))
3233
/* Nominal case, a reader is unlocking. */
3234
if (--(pfs_rwlock->m_readers) == 0)
3240
Edge case, we have no writer and no readers,
3242
This is possible for:
3243
- partial instrumentation
3244
- instrumentation disabled at runtime,
3245
see when get_thread_rwlock_locker_v1() returns NULL
3246
No further action is taken here, the next
3247
write lock will put the statistics is a valid state.
3252
/* See WL#2333: SHOW ENGINE ... LOCK STATUS. */
3254
if (! pfs_rwlock->m_enabled)
3257
if (! pfs_rwlock->m_timed)
3260
ulonglong locked_time;
3263
locked_time= get_timer_pico_value(wait_timer) - pfs_rwlock->m_last_written;
3264
pfs_rwlock->m_rwlock_stat.m_write_lock_stat.aggregate_value(locked_time);
3266
else if (last_reader)
3268
locked_time= get_timer_pico_value(wait_timer) - pfs_rwlock->m_last_read;
3269
pfs_rwlock->m_rwlock_stat.m_read_lock_stat.aggregate_value(locked_time);
3278
Implementation of the cond instrumentation interface.
3279
@sa PSI_v1::signal_cond.
3281
static void signal_cond_v1(PSI_cond* cond)
3283
PFS_cond *pfs_cond= reinterpret_cast<PFS_cond*> (cond);
3285
DBUG_ASSERT(pfs_cond != NULL);
3287
pfs_cond->m_cond_stat.m_signal_count++;
3291
Implementation of the cond instrumentation interface.
3292
@sa PSI_v1::broadcast_cond.
3294
static void broadcast_cond_v1(PSI_cond* cond)
3296
PFS_cond *pfs_cond= reinterpret_cast<PFS_cond*> (cond);
3298
DBUG_ASSERT(pfs_cond != NULL);
3300
pfs_cond->m_cond_stat.m_broadcast_count++;
3304
Implementation of the idle instrumentation interface.
3305
@sa PSI_v1::start_idle_wait.
3307
static PSI_idle_locker*
3308
start_idle_wait_v1(PSI_idle_locker_state* state, const char *src_file, uint src_line)
3310
DBUG_ASSERT(state != NULL);
3312
if (!flag_global_instrumentation)
3315
if (!global_idle_class.m_enabled)
3318
register uint flags= 0;
3319
ulonglong timer_start= 0;
3321
if (flag_thread_instrumentation)
3323
PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
3324
if (unlikely(pfs_thread == NULL))
3326
if (!pfs_thread->m_enabled)
3328
state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
3329
flags= STATE_FLAG_THREAD;
3331
DBUG_ASSERT(pfs_thread->m_events_statements_count == 0);
3333
if (global_idle_class.m_timed)
3335
timer_start= get_timer_raw_value_and_function(idle_timer, &state->m_timer);
3336
state->m_timer_start= timer_start;
3337
flags|= STATE_FLAG_TIMED;
3340
if (flag_events_waits_current)
3342
if (unlikely(pfs_thread->m_events_waits_current >=
3343
& pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
3348
PFS_events_waits *wait= pfs_thread->m_events_waits_current;
3349
state->m_wait= wait;
3350
flags|= STATE_FLAG_EVENT;
3352
wait->m_event_type= EVENT_TYPE_WAIT;
3354
IDLE events are waits, but by definition we know that
3355
such waits happen outside of any STAGE and STATEMENT,
3356
so they have no parents.
3358
wait->m_nesting_event_id= 0;
3359
/* no need to set wait->m_nesting_event_type */
3361
wait->m_thread= pfs_thread;
3362
wait->m_class= &global_idle_class;
3363
wait->m_timer_start= timer_start;
3364
wait->m_timer_end= 0;
3365
wait->m_event_id= pfs_thread->m_event_id++;
3366
wait->m_end_event_id= 0;
3367
wait->m_operation= OPERATION_TYPE_IDLE;
3368
wait->m_source_file= src_file;
3369
wait->m_source_line= src_line;
3370
wait->m_wait_class= WAIT_CLASS_IDLE;
3372
pfs_thread->m_events_waits_current++;
3377
if (global_idle_class.m_timed)
3379
timer_start= get_timer_raw_value_and_function(idle_timer, &state->m_timer);
3380
state->m_timer_start= timer_start;
3381
flags= STATE_FLAG_TIMED;
3385
state->m_flags= flags;
3386
return reinterpret_cast<PSI_idle_locker*> (state);
3390
Implementation of the mutex instrumentation interface.
3391
@sa PSI_v1::end_idle_wait.
3393
static void end_idle_wait_v1(PSI_idle_locker* locker)
3395
PSI_idle_locker_state *state= reinterpret_cast<PSI_idle_locker_state*> (locker);
3396
DBUG_ASSERT(state != NULL);
3397
ulonglong timer_end= 0;
3398
ulonglong wait_time= 0;
3400
register uint flags= state->m_flags;
3402
if (flags & STATE_FLAG_TIMED)
3404
timer_end= state->m_timer();
3405
wait_time= timer_end - state->m_timer_start;
3408
if (flags & STATE_FLAG_THREAD)
3410
PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
3411
PFS_single_stat *event_name_array;
3412
event_name_array= thread->m_instr_class_waits_stats;
3414
if (flags & STATE_FLAG_TIMED)
3416
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
3417
event_name_array[GLOBAL_IDLE_EVENT_INDEX].aggregate_value(wait_time);
3421
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
3422
event_name_array[GLOBAL_IDLE_EVENT_INDEX].aggregate_counted();
3425
if (flags & STATE_FLAG_EVENT)
3427
PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
3428
DBUG_ASSERT(wait != NULL);
3430
wait->m_timer_end= timer_end;
3431
wait->m_end_event_id= thread->m_event_id;
3432
if (flag_events_waits_history)
3433
insert_events_waits_history(thread, wait);
3434
if (flag_events_waits_history_long)
3435
insert_events_waits_history_long(wait);
3436
thread->m_events_waits_current--;
3440
if (flags & STATE_FLAG_TIMED)
3442
/* Aggregate to EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME (timed) */
3443
global_idle_stat.aggregate_value(wait_time);
3447
/* Aggregate to EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME (counted) */
3448
global_idle_stat.aggregate_counted();
3453
Implementation of the mutex instrumentation interface.
3454
@sa PSI_v1::end_mutex_wait.
3456
static void end_mutex_wait_v1(PSI_mutex_locker* locker, int rc)
3458
PSI_mutex_locker_state *state= reinterpret_cast<PSI_mutex_locker_state*> (locker);
3459
DBUG_ASSERT(state != NULL);
3461
ulonglong timer_end= 0;
3462
ulonglong wait_time= 0;
3464
PFS_mutex *mutex= reinterpret_cast<PFS_mutex *> (state->m_mutex);
3465
DBUG_ASSERT(mutex != NULL);
3466
PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
3468
register uint flags= state->m_flags;
3470
if (flags & STATE_FLAG_TIMED)
3472
timer_end= state->m_timer();
3473
wait_time= timer_end - state->m_timer_start;
3474
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */
3475
mutex->m_mutex_stat.m_wait_stat.aggregate_value(wait_time);
3479
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
3480
mutex->m_mutex_stat.m_wait_stat.aggregate_counted();
3483
if (likely(rc == 0))
3485
mutex->m_owner= thread;
3486
mutex->m_last_locked= timer_end;
3489
if (flags & STATE_FLAG_THREAD)
3491
PFS_single_stat *event_name_array;
3492
event_name_array= thread->m_instr_class_waits_stats;
3493
uint index= mutex->m_class->m_event_name_index;
3495
if (flags & STATE_FLAG_TIMED)
3497
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
3498
event_name_array[index].aggregate_value(wait_time);
3502
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
3503
event_name_array[index].aggregate_counted();
3506
if (flags & STATE_FLAG_EVENT)
3508
PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
3509
DBUG_ASSERT(wait != NULL);
3511
wait->m_timer_end= timer_end;
3512
wait->m_end_event_id= thread->m_event_id;
3513
if (flag_events_waits_history)
3514
insert_events_waits_history(thread, wait);
3515
if (flag_events_waits_history_long)
3516
insert_events_waits_history_long(wait);
3517
thread->m_events_waits_current--;
3523
Implementation of the rwlock instrumentation interface.
3524
@sa PSI_v1::end_rwlock_rdwait.
3526
static void end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc)
3528
PSI_rwlock_locker_state *state= reinterpret_cast<PSI_rwlock_locker_state*> (locker);
3529
DBUG_ASSERT(state != NULL);
3531
ulonglong timer_end= 0;
3532
ulonglong wait_time= 0;
3534
PFS_rwlock *rwlock= reinterpret_cast<PFS_rwlock *> (state->m_rwlock);
3535
DBUG_ASSERT(rwlock != NULL);
3537
if (state->m_flags & STATE_FLAG_TIMED)
3539
timer_end= state->m_timer();
3540
wait_time= timer_end - state->m_timer_start;
3541
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */
3542
rwlock->m_rwlock_stat.m_wait_stat.aggregate_value(wait_time);
3546
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
3547
rwlock->m_rwlock_stat.m_wait_stat.aggregate_counted();
3554
Multiple threads can execute this section concurrently
3555
(since multiple readers can execute in parallel).
3556
The statistics generated are not safe, which is why they are
3557
just statistics, not facts.
3559
if (rwlock->m_readers == 0)
3560
rwlock->m_last_read= timer_end;
3561
rwlock->m_writer= NULL;
3562
rwlock->m_readers++;
3565
if (state->m_flags & STATE_FLAG_THREAD)
3567
PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
3568
DBUG_ASSERT(thread != NULL);
3570
PFS_single_stat *event_name_array;
3571
event_name_array= thread->m_instr_class_waits_stats;
3572
uint index= rwlock->m_class->m_event_name_index;
3574
if (state->m_flags & STATE_FLAG_TIMED)
3576
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
3577
event_name_array[index].aggregate_value(wait_time);
3581
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
3582
event_name_array[index].aggregate_counted();
3585
if (state->m_flags & STATE_FLAG_EVENT)
3587
PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
3588
DBUG_ASSERT(wait != NULL);
3590
wait->m_timer_end= timer_end;
3591
wait->m_end_event_id= thread->m_event_id;
3592
if (flag_events_waits_history)
3593
insert_events_waits_history(thread, wait);
3594
if (flag_events_waits_history_long)
3595
insert_events_waits_history_long(wait);
3596
thread->m_events_waits_current--;
3602
Implementation of the rwlock instrumentation interface.
3603
@sa PSI_v1::end_rwlock_wrwait.
3605
static void end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc)
3607
PSI_rwlock_locker_state *state= reinterpret_cast<PSI_rwlock_locker_state*> (locker);
3608
DBUG_ASSERT(state != NULL);
3610
ulonglong timer_end= 0;
3611
ulonglong wait_time= 0;
3613
PFS_rwlock *rwlock= reinterpret_cast<PFS_rwlock *> (state->m_rwlock);
3614
DBUG_ASSERT(rwlock != NULL);
3615
PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
3617
if (state->m_flags & STATE_FLAG_TIMED)
3619
timer_end= state->m_timer();
3620
wait_time= timer_end - state->m_timer_start;
3621
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */
3622
rwlock->m_rwlock_stat.m_wait_stat.aggregate_value(wait_time);
3626
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
3627
rwlock->m_rwlock_stat.m_wait_stat.aggregate_counted();
3630
if (likely(rc == 0))
3632
/* Thread safe : we are protected by the instrumented rwlock */
3633
rwlock->m_writer= thread;
3634
rwlock->m_last_written= timer_end;
3635
/* Reset the readers stats, they could be off */
3636
rwlock->m_readers= 0;
3637
rwlock->m_last_read= 0;
3640
if (state->m_flags & STATE_FLAG_THREAD)
3642
PFS_single_stat *event_name_array;
3643
event_name_array= thread->m_instr_class_waits_stats;
3644
uint index= rwlock->m_class->m_event_name_index;
3646
if (state->m_flags & STATE_FLAG_TIMED)
3648
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
3649
event_name_array[index].aggregate_value(wait_time);
3653
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
3654
event_name_array[index].aggregate_counted();
3657
if (state->m_flags & STATE_FLAG_EVENT)
3659
PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
3660
DBUG_ASSERT(wait != NULL);
3662
wait->m_timer_end= timer_end;
3663
wait->m_end_event_id= thread->m_event_id;
3664
if (flag_events_waits_history)
3665
insert_events_waits_history(thread, wait);
3666
if (flag_events_waits_history_long)
3667
insert_events_waits_history_long(wait);
3668
thread->m_events_waits_current--;
3674
Implementation of the cond instrumentation interface.
3675
@sa PSI_v1::end_cond_wait.
3677
static void end_cond_wait_v1(PSI_cond_locker* locker, int rc)
3679
PSI_cond_locker_state *state= reinterpret_cast<PSI_cond_locker_state*> (locker);
3680
DBUG_ASSERT(state != NULL);
3682
ulonglong timer_end= 0;
3683
ulonglong wait_time= 0;
3685
PFS_cond *cond= reinterpret_cast<PFS_cond *> (state->m_cond);
3686
/* PFS_mutex *mutex= reinterpret_cast<PFS_mutex *> (state->m_mutex); */
3688
if (state->m_flags & STATE_FLAG_TIMED)
3690
timer_end= state->m_timer();
3691
wait_time= timer_end - state->m_timer_start;
3692
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */
3693
cond->m_cond_stat.m_wait_stat.aggregate_value(wait_time);
3697
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
3698
cond->m_cond_stat.m_wait_stat.aggregate_counted();
3701
if (state->m_flags & STATE_FLAG_THREAD)
3703
PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
3704
DBUG_ASSERT(thread != NULL);
3706
PFS_single_stat *event_name_array;
3707
event_name_array= thread->m_instr_class_waits_stats;
3708
uint index= cond->m_class->m_event_name_index;
3710
if (state->m_flags & STATE_FLAG_TIMED)
3712
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
3713
event_name_array[index].aggregate_value(wait_time);
3717
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
3718
event_name_array[index].aggregate_counted();
3721
if (state->m_flags & STATE_FLAG_EVENT)
3723
PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
3724
DBUG_ASSERT(wait != NULL);
3726
wait->m_timer_end= timer_end;
3727
wait->m_end_event_id= thread->m_event_id;
3728
if (flag_events_waits_history)
3729
insert_events_waits_history(thread, wait);
3730
if (flag_events_waits_history_long)
3731
insert_events_waits_history_long(wait);
3732
thread->m_events_waits_current--;
3738
Implementation of the table instrumentation interface.
3739
@sa PSI_v1::end_table_io_wait.
3741
static void end_table_io_wait_v1(PSI_table_locker* locker)
3743
PSI_table_locker_state *state= reinterpret_cast<PSI_table_locker_state*> (locker);
3744
DBUG_ASSERT(state != NULL);
3746
ulonglong timer_end= 0;
3747
ulonglong wait_time= 0;
3749
PFS_table *table= reinterpret_cast<PFS_table *> (state->m_table);
3750
DBUG_ASSERT(table != NULL);
3752
PFS_single_stat *stat;
3753
PFS_table_io_stat *table_io_stat;
3755
DBUG_ASSERT((state->m_index < table->m_share->m_key_count) ||
3756
(state->m_index == MAX_INDEXES));
3758
table_io_stat= & table->m_table_stat.m_index_stat[state->m_index];
3759
table_io_stat->m_has_data= true;
3761
switch (state->m_io_operation)
3763
case PSI_TABLE_FETCH_ROW:
3764
stat= & table_io_stat->m_fetch;
3766
case PSI_TABLE_WRITE_ROW:
3767
stat= & table_io_stat->m_insert;
3769
case PSI_TABLE_UPDATE_ROW:
3770
stat= & table_io_stat->m_update;
3772
case PSI_TABLE_DELETE_ROW:
3773
stat= & table_io_stat->m_delete;
3781
register uint flags= state->m_flags;
3783
if (flags & STATE_FLAG_TIMED)
3785
timer_end= state->m_timer();
3786
wait_time= timer_end - state->m_timer_start;
3787
stat->aggregate_value(wait_time);
3791
stat->aggregate_counted();
3794
if (flags & STATE_FLAG_THREAD)
3796
PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
3797
DBUG_ASSERT(thread != NULL);
3799
PFS_single_stat *event_name_array;
3800
event_name_array= thread->m_instr_class_waits_stats;
3803
Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME
3804
(for wait/io/table/sql/handler)
3806
if (flags & STATE_FLAG_TIMED)
3808
event_name_array[GLOBAL_TABLE_IO_EVENT_INDEX].aggregate_value(wait_time);
3812
event_name_array[GLOBAL_TABLE_IO_EVENT_INDEX].aggregate_counted();
3815
if (flags & STATE_FLAG_EVENT)
3817
PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
3818
DBUG_ASSERT(wait != NULL);
3820
wait->m_timer_end= timer_end;
3821
wait->m_end_event_id= thread->m_event_id;
3822
if (flag_events_waits_history)
3823
insert_events_waits_history(thread, wait);
3824
if (flag_events_waits_history_long)
3825
insert_events_waits_history_long(wait);
3826
thread->m_events_waits_current--;
3830
table->m_has_io_stats= true;
3834
Implementation of the table instrumentation interface.
3835
@sa PSI_v1::end_table_lock_wait.
3837
static void end_table_lock_wait_v1(PSI_table_locker* locker)
3839
PSI_table_locker_state *state= reinterpret_cast<PSI_table_locker_state*> (locker);
3840
DBUG_ASSERT(state != NULL);
3842
ulonglong timer_end= 0;
3843
ulonglong wait_time= 0;
3845
PFS_table *table= reinterpret_cast<PFS_table *> (state->m_table);
3846
DBUG_ASSERT(table != NULL);
3848
PFS_single_stat *stat= & table->m_table_stat.m_lock_stat.m_stat[state->m_index];
3850
register uint flags= state->m_flags;
3852
if (flags & STATE_FLAG_TIMED)
3854
timer_end= state->m_timer();
3855
wait_time= timer_end - state->m_timer_start;
3856
stat->aggregate_value(wait_time);
3860
stat->aggregate_counted();
3863
if (flags & STATE_FLAG_THREAD)
3865
PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
3866
DBUG_ASSERT(thread != NULL);
3868
PFS_single_stat *event_name_array;
3869
event_name_array= thread->m_instr_class_waits_stats;
3872
Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME
3873
(for wait/lock/table/sql/handler)
3875
if (flags & STATE_FLAG_TIMED)
3877
event_name_array[GLOBAL_TABLE_LOCK_EVENT_INDEX].aggregate_value(wait_time);
3881
event_name_array[GLOBAL_TABLE_LOCK_EVENT_INDEX].aggregate_counted();
3884
if (flags & STATE_FLAG_EVENT)
3886
PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
3887
DBUG_ASSERT(wait != NULL);
3889
wait->m_timer_end= timer_end;
3890
wait->m_end_event_id= thread->m_event_id;
3891
if (flag_events_waits_history)
3892
insert_events_waits_history(thread, wait);
3893
if (flag_events_waits_history_long)
3894
insert_events_waits_history_long(wait);
3895
thread->m_events_waits_current--;
3899
table->m_has_lock_stats= true;
3902
static void start_file_wait_v1(PSI_file_locker *locker,
3904
const char *src_file,
3907
static void end_file_wait_v1(PSI_file_locker *locker,
3911
Implementation of the file instrumentation interface.
3912
@sa PSI_v1::start_file_open_wait.
3914
static void start_file_open_wait_v1(PSI_file_locker *locker,
3915
const char *src_file,
3918
start_file_wait_v1(locker, 0, src_file, src_line);
3924
Implementation of the file instrumentation interface.
3925
@sa PSI_v1::end_file_open_wait.
3927
static PSI_file* end_file_open_wait_v1(PSI_file_locker *locker,
3930
PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
3931
DBUG_ASSERT(state != NULL);
3933
switch (state->m_operation)
3937
case PSI_FILE_STREAM_OPEN:
3938
case PSI_FILE_CREATE:
3941
PFS_file_class *klass= reinterpret_cast<PFS_file_class*> (state->m_class);
3942
PFS_thread *thread= reinterpret_cast<PFS_thread*> (state->m_thread);
3943
const char *name= state->m_name;
3944
uint len= strlen(name);
3945
PFS_file *pfs_file= find_or_create_file(thread, klass, name, len, true);
3946
state->m_file= reinterpret_cast<PSI_file*> (pfs_file);
3955
end_file_wait_v1(locker, 0);
3957
return state->m_file;
3961
Implementation of the file instrumentation interface.
3962
@sa PSI_v1::end_file_open_wait_and_bind_to_descriptor.
3964
static void end_file_open_wait_and_bind_to_descriptor_v1
3965
(PSI_file_locker *locker, File file)
3967
PFS_file *pfs_file= NULL;
3968
int index= (int) file;
3969
PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
3970
DBUG_ASSERT(state != NULL);
3974
PFS_file_class *klass= reinterpret_cast<PFS_file_class*> (state->m_class);
3975
PFS_thread *thread= reinterpret_cast<PFS_thread*> (state->m_thread);
3976
const char *name= state->m_name;
3977
uint len= strlen(name);
3978
pfs_file= find_or_create_file(thread, klass, name, len, true);
3979
state->m_file= reinterpret_cast<PSI_file*> (pfs_file);
3982
end_file_wait_v1(locker, 0);
3984
if (likely(index >= 0))
3986
if (likely(index < file_handle_max))
3987
file_handle_array[index]= pfs_file;
3990
if (pfs_file != NULL)
3991
release_file(pfs_file);
3998
Implementation of the file instrumentation interface.
3999
@sa PSI_v1::start_file_wait.
4001
static void start_file_wait_v1(PSI_file_locker *locker,
4003
const char *src_file,
4006
ulonglong timer_start= 0;
4007
PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
4008
DBUG_ASSERT(state != NULL);
4010
register uint flags= state->m_flags;
4012
if (flags & STATE_FLAG_TIMED)
4014
timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
4015
state->m_timer_start= timer_start;
4018
if (flags & STATE_FLAG_EVENT)
4020
PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
4021
DBUG_ASSERT(wait != NULL);
4023
wait->m_timer_start= timer_start;
4024
wait->m_source_file= src_file;
4025
wait->m_source_line= src_line;
4026
wait->m_number_of_bytes= count;
4031
Implementation of the file instrumentation interface.
4032
@sa PSI_v1::end_file_wait.
4034
static void end_file_wait_v1(PSI_file_locker *locker,
4037
PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
4038
DBUG_ASSERT(state != NULL);
4039
PFS_file *file= reinterpret_cast<PFS_file *> (state->m_file);
4040
PFS_file_class *klass= reinterpret_cast<PFS_file_class *> (state->m_class);
4041
PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
4043
ulonglong timer_end= 0;
4044
ulonglong wait_time= 0;
4045
PFS_byte_stat *byte_stat;
4046
register uint flags= state->m_flags;
4047
size_t bytes= ((int)byte_count > -1 ? byte_count : 0);
4049
PFS_file_stat *file_stat;
4053
file_stat= & file->m_file_stat;
4057
file_stat= & klass->m_file_stat;
4060
switch (state->m_operation)
4062
/* Group read operations */
4064
byte_stat= &file_stat->m_io_stat.m_read;
4066
/* Group write operations */
4067
case PSI_FILE_WRITE:
4068
byte_stat= &file_stat->m_io_stat.m_write;
4070
/* Group remaining operations as miscellaneous */
4071
case PSI_FILE_CREATE:
4072
case PSI_FILE_CREATE_TMP:
4074
case PSI_FILE_STREAM_OPEN:
4075
case PSI_FILE_STREAM_CLOSE:
4078
case PSI_FILE_FLUSH:
4079
case PSI_FILE_FSTAT:
4080
case PSI_FILE_CHSIZE:
4081
case PSI_FILE_DELETE:
4082
case PSI_FILE_RENAME:
4085
case PSI_FILE_CLOSE:
4086
byte_stat= &file_stat->m_io_stat.m_misc;
4094
/* Aggregation for EVENTS_WAITS_SUMMARY_BY_INSTANCE */
4095
if (flags & STATE_FLAG_TIMED)
4097
timer_end= state->m_timer();
4098
wait_time= timer_end - state->m_timer_start;
4099
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */
4100
byte_stat->aggregate(wait_time, bytes);
4104
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
4105
byte_stat->aggregate_counted(bytes);
4108
if (flags & STATE_FLAG_THREAD)
4110
DBUG_ASSERT(thread != NULL);
4112
PFS_single_stat *event_name_array;
4113
event_name_array= thread->m_instr_class_waits_stats;
4114
uint index= klass->m_event_name_index;
4116
if (flags & STATE_FLAG_TIMED)
4118
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
4119
event_name_array[index].aggregate_value(wait_time);
4123
/* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
4124
event_name_array[index].aggregate_counted();
4127
if (state->m_flags & STATE_FLAG_EVENT)
4129
PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
4130
DBUG_ASSERT(wait != NULL);
4132
wait->m_timer_end= timer_end;
4133
wait->m_number_of_bytes= bytes;
4134
wait->m_end_event_id= thread->m_event_id;
4135
wait->m_object_instance_addr= file;
4136
wait->m_weak_file= file;
4137
wait->m_weak_version= (file ? file->get_version() : 0);
4139
if (flag_events_waits_history)
4140
insert_events_waits_history(thread, wait);
4141
if (flag_events_waits_history_long)
4142
insert_events_waits_history_long(wait);
4143
thread->m_events_waits_current--;
4149
Implementation of the file instrumentation interface.
4150
@sa PSI_v1::start_file_close_wait.
4152
static void start_file_close_wait_v1(PSI_file_locker *locker,
4153
const char *src_file,
4160
PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
4161
DBUG_ASSERT(state != NULL);
4163
switch (state->m_operation)
4165
case PSI_FILE_DELETE:
4166
thread= reinterpret_cast<PFS_thread*> (state->m_thread);
4167
name= state->m_name;
4169
pfs_file= find_or_create_file(thread, NULL, name, len, false);
4170
state->m_file= reinterpret_cast<PSI_file*> (pfs_file);
4172
case PSI_FILE_STREAM_CLOSE:
4173
case PSI_FILE_CLOSE:
4180
start_file_wait_v1(locker, 0, src_file, src_line);
4186
Implementation of the file instrumentation interface.
4187
@sa PSI_v1::end_file_close_wait.
4189
static void end_file_close_wait_v1(PSI_file_locker *locker, int rc)
4191
PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
4192
DBUG_ASSERT(state != NULL);
4194
end_file_wait_v1(locker, 0);
4198
PFS_thread *thread= reinterpret_cast<PFS_thread*> (state->m_thread);
4199
PFS_file *file= reinterpret_cast<PFS_file*> (state->m_file);
4201
/* Release or destroy the file if necessary */
4202
switch(state->m_operation)
4204
case PSI_FILE_CLOSE:
4205
case PSI_FILE_STREAM_CLOSE:
4209
case PSI_FILE_DELETE:
4211
destroy_file(thread, file);
4221
static void start_stage_v1(PSI_stage_key key, const char *src_file, int src_line)
4223
ulonglong timer_value= 0;
4225
PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
4226
if (unlikely(pfs_thread == NULL))
4229
/* Always update column threads.processlist_state. */
4230
pfs_thread->m_stage= key;
4232
if (! flag_global_instrumentation)
4235
if (flag_thread_instrumentation && ! pfs_thread->m_enabled)
4238
PFS_events_stages *pfs= & pfs_thread->m_stage_current;
4239
PFS_events_waits *child_wait= & pfs_thread->m_events_waits_stack[0];
4240
PFS_events_statements *parent_statement= & pfs_thread->m_statement_stack[0];
4242
PFS_instr_class *old_class= pfs->m_class;
4243
if (old_class != NULL)
4245
PFS_stage_stat *event_name_array;
4246
event_name_array= pfs_thread->m_instr_class_stages_stats;
4247
uint index= old_class->m_event_name_index;
4249
/* Finish old event */
4250
if (old_class->m_timed)
4252
timer_value= get_timer_raw_value(stage_timer);;
4253
pfs->m_timer_end= timer_value;
4255
/* Aggregate to EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
4256
ulonglong stage_time= timer_value - pfs->m_timer_start;
4257
event_name_array[index].aggregate_value(stage_time);
4261
/* Aggregate to EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
4262
event_name_array[index].aggregate_counted();
4265
if (flag_events_stages_current)
4267
pfs->m_end_event_id= pfs_thread->m_event_id;
4268
if (flag_events_stages_history)
4269
insert_events_stages_history(pfs_thread, pfs);
4270
if (flag_events_stages_history_long)
4271
insert_events_stages_history_long(pfs);
4274
/* This stage event is now complete. */
4277
/* New waits will now be attached directly to the parent statement. */
4278
child_wait->m_event_id= parent_statement->m_event_id;
4279
child_wait->m_event_type= parent_statement->m_event_type;
4280
/* See below for new stages, that may overwrite this. */
4283
/* Start new event */
4285
PFS_stage_class *new_klass= find_stage_class(key);
4286
if (unlikely(new_klass == NULL))
4289
if (! new_klass->m_enabled)
4292
pfs->m_class= new_klass;
4293
if (new_klass->m_timed)
4296
Do not call the timer again if we have a
4297
TIMER_END for the previous stage already.
4299
if (timer_value == 0)
4300
timer_value= get_timer_raw_value(stage_timer);
4301
pfs->m_timer_start= timer_value;
4304
pfs->m_timer_start= 0;
4305
pfs->m_timer_end= 0;
4307
if (flag_events_stages_current)
4309
/* m_thread_internal_id is immutable and already set */
4310
DBUG_ASSERT(pfs->m_thread_internal_id == pfs_thread->m_thread_internal_id);
4311
pfs->m_event_id= pfs_thread->m_event_id++;
4312
pfs->m_end_event_id= 0;
4313
pfs->m_source_file= src_file;
4314
pfs->m_source_line= src_line;
4316
/* New wait events will have this new stage as parent. */
4317
child_wait->m_event_id= pfs->m_event_id;
4318
child_wait->m_event_type= EVENT_TYPE_STAGE;
4322
static void end_stage_v1()
4324
ulonglong timer_value= 0;
4326
PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
4327
if (unlikely(pfs_thread == NULL))
4330
pfs_thread->m_stage= 0;
4332
if (! flag_global_instrumentation)
4335
if (flag_thread_instrumentation && ! pfs_thread->m_enabled)
4338
PFS_events_stages *pfs= & pfs_thread->m_stage_current;
4340
PFS_instr_class *old_class= pfs->m_class;
4341
if (old_class != NULL)
4343
PFS_stage_stat *event_name_array;
4344
event_name_array= pfs_thread->m_instr_class_stages_stats;
4345
uint index= old_class->m_event_name_index;
4347
/* Finish old event */
4348
if (old_class->m_timed)
4350
timer_value= get_timer_raw_value(stage_timer);;
4351
pfs->m_timer_end= timer_value;
4353
/* Aggregate to EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
4354
ulonglong stage_time= timer_value - pfs->m_timer_start;
4355
event_name_array[index].aggregate_value(stage_time);
4359
/* Aggregate to EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
4360
event_name_array[index].aggregate_counted();
4363
if (flag_events_stages_current)
4365
pfs->m_end_event_id= pfs_thread->m_event_id;
4366
if (flag_events_stages_history)
4367
insert_events_stages_history(pfs_thread, pfs);
4368
if (flag_events_stages_history_long)
4369
insert_events_stages_history_long(pfs);
4372
/* New waits will now be attached directly to the parent statement. */
4373
PFS_events_waits *child_wait= & pfs_thread->m_events_waits_stack[0];
4374
PFS_events_statements *parent_statement= & pfs_thread->m_statement_stack[0];
4375
child_wait->m_event_id= parent_statement->m_event_id;
4376
child_wait->m_event_type= parent_statement->m_event_type;
4378
/* This stage is completed */
4383
static PSI_statement_locker*
4384
get_thread_statement_locker_v1(PSI_statement_locker_state *state,
4385
PSI_statement_key key,
4386
const void *charset)
4388
DBUG_ASSERT(state != NULL);
4389
if (! flag_global_instrumentation)
4391
PFS_statement_class *klass= find_statement_class(key);
4392
if (unlikely(klass == NULL))
4394
if (! klass->m_enabled)
4397
register uint flags;
4399
if (flag_thread_instrumentation)
4401
PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
4402
if (unlikely(pfs_thread == NULL))
4404
if (! pfs_thread->m_enabled)
4406
state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
4407
flags= STATE_FLAG_THREAD;
4410
flags|= STATE_FLAG_TIMED;
4412
if (flag_events_statements_current)
4414
ulonglong event_id= pfs_thread->m_event_id++;
4416
if (pfs_thread->m_events_statements_count >= statement_stack_max)
4421
PFS_events_statements *pfs= & pfs_thread->m_statement_stack[pfs_thread->m_events_statements_count];
4422
/* m_thread_internal_id is immutable and already set */
4423
DBUG_ASSERT(pfs->m_thread_internal_id == pfs_thread->m_thread_internal_id);
4424
pfs->m_event_id= event_id;
4425
pfs->m_end_event_id= 0;
4426
pfs->m_class= klass;
4427
pfs->m_timer_start= 0;
4428
pfs->m_timer_end= 0;
4429
pfs->m_lock_time= 0;
4430
pfs->m_current_schema_name_length= 0;
4431
pfs->m_sqltext_length= 0;
4433
pfs->m_message_text[0]= '\0';
4434
pfs->m_sql_errno= 0;
4435
pfs->m_sqlstate[0]= '\0';
4436
pfs->m_error_count= 0;
4437
pfs->m_warning_count= 0;
4438
pfs->m_rows_affected= 0;
4440
pfs->m_rows_sent= 0;
4441
pfs->m_rows_examined= 0;
4442
pfs->m_created_tmp_disk_tables= 0;
4443
pfs->m_created_tmp_tables= 0;
4444
pfs->m_select_full_join= 0;
4445
pfs->m_select_full_range_join= 0;
4446
pfs->m_select_range= 0;
4447
pfs->m_select_range_check= 0;
4448
pfs->m_select_scan= 0;
4449
pfs->m_sort_merge_passes= 0;
4450
pfs->m_sort_range= 0;
4451
pfs->m_sort_rows= 0;
4452
pfs->m_sort_scan= 0;
4453
pfs->m_no_index_used= 0;
4454
pfs->m_no_good_index_used= 0;
4455
digest_reset(& pfs->m_digest_storage);
4457
/* New stages will have this statement as parent */
4458
PFS_events_stages *child_stage= & pfs_thread->m_stage_current;
4459
child_stage->m_nesting_event_id= event_id;
4460
child_stage->m_nesting_event_type= EVENT_TYPE_STATEMENT;
4462
/* New waits will have this statement as parent, if no stage is instrumented */
4463
PFS_events_waits *child_wait= & pfs_thread->m_events_waits_stack[0];
4464
child_wait->m_nesting_event_id= event_id;
4465
child_wait->m_nesting_event_type= EVENT_TYPE_STATEMENT;
4467
state->m_statement= pfs;
4468
flags|= STATE_FLAG_EVENT;
4470
pfs_thread->m_events_statements_count++;
4476
flags= STATE_FLAG_TIMED;
4481
if (flag_statements_digest)
4483
const CHARSET_INFO *cs= static_cast <const CHARSET_INFO*> (charset);
4484
flags|= STATE_FLAG_DIGEST;
4485
state->m_digest_state.m_last_id_index= 0;
4486
digest_reset(& state->m_digest_state.m_digest_storage);
4487
state->m_digest_state.m_digest_storage.m_charset_number= cs->number;
4490
state->m_discarded= false;
4491
state->m_class= klass;
4492
state->m_flags= flags;
4494
state->m_lock_time= 0;
4495
state->m_rows_sent= 0;
4496
state->m_rows_examined= 0;
4497
state->m_created_tmp_disk_tables= 0;
4498
state->m_created_tmp_tables= 0;
4499
state->m_select_full_join= 0;
4500
state->m_select_full_range_join= 0;
4501
state->m_select_range= 0;
4502
state->m_select_range_check= 0;
4503
state->m_select_scan= 0;
4504
state->m_sort_merge_passes= 0;
4505
state->m_sort_range= 0;
4506
state->m_sort_rows= 0;
4507
state->m_sort_scan= 0;
4508
state->m_no_index_used= 0;
4509
state->m_no_good_index_used= 0;
4511
state->m_schema_name_length= 0;
4513
return reinterpret_cast<PSI_statement_locker*> (state);
4516
static PSI_statement_locker*
4517
refine_statement_v1(PSI_statement_locker *locker,
4518
PSI_statement_key key)
4520
PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker);
4523
DBUG_ASSERT(state->m_class != NULL);
4524
PFS_statement_class *klass;
4525
/* Only refine statements for mutable instrumentation */
4526
klass= reinterpret_cast<PFS_statement_class*> (state->m_class);
4527
DBUG_ASSERT(klass->is_mutable());
4528
klass= find_statement_class(key);
4530
uint flags= state->m_flags;
4532
if (unlikely(klass == NULL) || !klass->m_enabled)
4534
/* pop statement stack */
4535
if (flags & STATE_FLAG_THREAD)
4537
PFS_thread *pfs_thread= reinterpret_cast<PFS_thread *> (state->m_thread);
4538
DBUG_ASSERT(pfs_thread != NULL);
4539
if (pfs_thread->m_events_statements_count > 0)
4540
pfs_thread->m_events_statements_count--;
4543
state->m_discarded= true;
4547
if ((flags & STATE_FLAG_TIMED) && ! klass->m_timed)
4548
flags= flags & ~STATE_FLAG_TIMED;
4550
if (flags & STATE_FLAG_EVENT)
4552
PFS_events_statements *pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement);
4553
DBUG_ASSERT(pfs != NULL);
4555
/* mutate EVENTS_STATEMENTS_CURRENT.EVENT_NAME */
4556
pfs->m_class= klass;
4559
state->m_class= klass;
4560
state->m_flags= flags;
4561
return reinterpret_cast<PSI_statement_locker*> (state);
4564
static void start_statement_v1(PSI_statement_locker *locker,
4565
const char *db, uint db_len,
4566
const char *src_file, uint src_line)
4568
PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker);
4569
DBUG_ASSERT(state != NULL);
4571
register uint flags= state->m_flags;
4572
ulonglong timer_start= 0;
4574
if (flags & STATE_FLAG_TIMED)
4576
timer_start= get_timer_raw_value_and_function(statement_timer, & state->m_timer);
4577
state->m_timer_start= timer_start;
4580
compile_time_assert(PSI_SCHEMA_NAME_LEN == NAME_LEN);
4581
DBUG_ASSERT(db_len <= sizeof(state->m_schema_name));
4584
memcpy(state->m_schema_name, db, db_len);
4585
state->m_schema_name_length= db_len;
4587
if (flags & STATE_FLAG_EVENT)
4589
PFS_events_statements *pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement);
4590
DBUG_ASSERT(pfs != NULL);
4592
pfs->m_timer_start= timer_start;
4593
pfs->m_source_file= src_file;
4594
pfs->m_source_line= src_line;
4596
DBUG_ASSERT(db_len <= sizeof(pfs->m_current_schema_name));
4598
memcpy(pfs->m_current_schema_name, db, db_len);
4599
pfs->m_current_schema_name_length= db_len;
4603
static void set_statement_text_v1(PSI_statement_locker *locker,
4604
const char *text, uint text_len)
4606
PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker);
4607
DBUG_ASSERT(state != NULL);
4609
if (state->m_discarded)
4612
if (state->m_flags & STATE_FLAG_EVENT)
4614
PFS_events_statements *pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement);
4615
DBUG_ASSERT(pfs != NULL);
4616
if (text_len > sizeof (pfs->m_sqltext))
4617
text_len= sizeof(pfs->m_sqltext);
4619
memcpy(pfs->m_sqltext, text, text_len);
4620
pfs->m_sqltext_length= text_len;
4626
#define SET_STATEMENT_ATTR_BODY(LOCKER, ATTR, VALUE) \
4627
PSI_statement_locker_state *state; \
4628
state= reinterpret_cast<PSI_statement_locker_state*> (LOCKER); \
4629
if (unlikely(state == NULL)) \
4631
if (state->m_discarded) \
4633
state->ATTR= VALUE; \
4634
if (state->m_flags & STATE_FLAG_EVENT) \
4636
PFS_events_statements *pfs; \
4637
pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement); \
4638
DBUG_ASSERT(pfs != NULL); \
4643
#define INC_STATEMENT_ATTR_BODY(LOCKER, ATTR, VALUE) \
4644
PSI_statement_locker_state *state; \
4645
state= reinterpret_cast<PSI_statement_locker_state*> (LOCKER); \
4646
if (unlikely(state == NULL)) \
4648
if (state->m_discarded) \
4650
state->ATTR+= VALUE; \
4651
if (state->m_flags & STATE_FLAG_EVENT) \
4653
PFS_events_statements *pfs; \
4654
pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement); \
4655
DBUG_ASSERT(pfs != NULL); \
4656
pfs->ATTR+= VALUE; \
4660
static void set_statement_lock_time_v1(PSI_statement_locker *locker,
4663
SET_STATEMENT_ATTR_BODY(locker, m_lock_time, count);
4666
static void set_statement_rows_sent_v1(PSI_statement_locker *locker,
4669
SET_STATEMENT_ATTR_BODY(locker, m_rows_sent, count);
4672
static void set_statement_rows_examined_v1(PSI_statement_locker *locker,
4675
SET_STATEMENT_ATTR_BODY(locker, m_rows_examined, count);
4678
static void inc_statement_created_tmp_disk_tables_v1(PSI_statement_locker *locker,
4681
INC_STATEMENT_ATTR_BODY(locker, m_created_tmp_disk_tables, count);
4684
static void inc_statement_created_tmp_tables_v1(PSI_statement_locker *locker,
4687
INC_STATEMENT_ATTR_BODY(locker, m_created_tmp_tables, count);
4690
static void inc_statement_select_full_join_v1(PSI_statement_locker *locker,
4693
INC_STATEMENT_ATTR_BODY(locker, m_select_full_join, count);
4696
static void inc_statement_select_full_range_join_v1(PSI_statement_locker *locker,
4699
INC_STATEMENT_ATTR_BODY(locker, m_select_full_range_join, count);
4702
static void inc_statement_select_range_v1(PSI_statement_locker *locker,
4705
INC_STATEMENT_ATTR_BODY(locker, m_select_range, count);
4708
static void inc_statement_select_range_check_v1(PSI_statement_locker *locker,
4711
INC_STATEMENT_ATTR_BODY(locker, m_select_range_check, count);
4714
static void inc_statement_select_scan_v1(PSI_statement_locker *locker,
4717
INC_STATEMENT_ATTR_BODY(locker, m_select_scan, count);
4720
static void inc_statement_sort_merge_passes_v1(PSI_statement_locker *locker,
4723
INC_STATEMENT_ATTR_BODY(locker, m_sort_merge_passes, count);
4726
static void inc_statement_sort_range_v1(PSI_statement_locker *locker,
4729
INC_STATEMENT_ATTR_BODY(locker, m_sort_range, count);
4732
static void inc_statement_sort_rows_v1(PSI_statement_locker *locker,
4735
INC_STATEMENT_ATTR_BODY(locker, m_sort_rows, count);
4738
static void inc_statement_sort_scan_v1(PSI_statement_locker *locker,
4741
INC_STATEMENT_ATTR_BODY(locker, m_sort_scan, count);
4744
static void set_statement_no_index_used_v1(PSI_statement_locker *locker)
4746
SET_STATEMENT_ATTR_BODY(locker, m_no_index_used, 1);
4749
static void set_statement_no_good_index_used_v1(PSI_statement_locker *locker)
4751
SET_STATEMENT_ATTR_BODY(locker, m_no_good_index_used, 1);
4754
static void end_statement_v1(PSI_statement_locker *locker, void *stmt_da)
4756
PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker);
4757
Diagnostics_area *da= reinterpret_cast<Diagnostics_area*> (stmt_da);
4758
DBUG_ASSERT(state != NULL);
4759
DBUG_ASSERT(da != NULL);
4761
if (state->m_discarded)
4764
PFS_statement_class *klass= reinterpret_cast<PFS_statement_class *> (state->m_class);
4765
DBUG_ASSERT(klass != NULL);
4767
ulonglong timer_end= 0;
4768
ulonglong wait_time= 0;
4769
register uint flags= state->m_flags;
4771
if (flags & STATE_FLAG_TIMED)
4773
timer_end= state->m_timer();
4774
wait_time= timer_end - state->m_timer_start;
4777
PFS_statement_stat *event_name_array;
4778
uint index= klass->m_event_name_index;
4779
PFS_statement_stat *stat;
4782
Capture statement stats by digest.
4784
PSI_digest_storage *digest_storage= NULL;
4785
PFS_statement_stat *digest_stat= NULL;
4787
if (flags & STATE_FLAG_THREAD)
4789
PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
4790
DBUG_ASSERT(thread != NULL);
4791
event_name_array= thread->m_instr_class_statements_stats;
4792
/* Aggregate to EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME */
4793
stat= & event_name_array[index];
4795
if (flags & STATE_FLAG_DIGEST)
4797
digest_storage= &state->m_digest_state.m_digest_storage;
4798
/* Populate PFS_statements_digest_stat with computed digest information.*/
4799
digest_stat= find_or_create_digest(thread, digest_storage,
4800
state->m_schema_name,
4801
state->m_schema_name_length);
4804
if (flags & STATE_FLAG_EVENT)
4806
PFS_events_statements *pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement);
4807
DBUG_ASSERT(pfs != NULL);
4809
switch(da->status())
4811
case Diagnostics_area::DA_EMPTY:
4813
case Diagnostics_area::DA_OK:
4814
memcpy(pfs->m_message_text, da->message(), MYSQL_ERRMSG_SIZE);
4815
pfs->m_message_text[MYSQL_ERRMSG_SIZE]= 0;
4816
pfs->m_rows_affected= da->affected_rows();
4817
pfs->m_warning_count= da->statement_warn_count();
4818
memcpy(pfs->m_sqlstate, "00000", SQLSTATE_LENGTH);
4820
case Diagnostics_area::DA_EOF:
4821
pfs->m_warning_count= da->statement_warn_count();
4823
case Diagnostics_area::DA_ERROR:
4824
memcpy(pfs->m_message_text, da->message(), MYSQL_ERRMSG_SIZE);
4825
pfs->m_message_text[MYSQL_ERRMSG_SIZE]= 0;
4826
pfs->m_sql_errno= da->sql_errno();
4827
memcpy(pfs->m_sqlstate, da->get_sqlstate(), SQLSTATE_LENGTH);
4829
case Diagnostics_area::DA_DISABLED:
4833
pfs->m_timer_end= timer_end;
4834
pfs->m_end_event_id= thread->m_event_id;
4836
if (flags & STATE_FLAG_DIGEST)
4839
The following columns in events_statement_current:
4842
are computed from the digest storage.
4844
digest_copy(& pfs->m_digest_storage, digest_storage);
4847
if (flag_events_statements_history)
4848
insert_events_statements_history(thread, pfs);
4849
if (flag_events_statements_history_long)
4850
insert_events_statements_history_long(pfs);
4852
DBUG_ASSERT(thread->m_events_statements_count > 0);
4853
thread->m_events_statements_count--;
4858
if (flags & STATE_FLAG_DIGEST)
4860
PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
4862
/* An instrumented thread is required, for LF_PINS. */
4865
/* Set digest stat. */
4866
digest_storage= &state->m_digest_state.m_digest_storage;
4867
/* Populate statements_digest_stat with computed digest information. */
4868
digest_stat= find_or_create_digest(thread, digest_storage,
4869
state->m_schema_name,
4870
state->m_schema_name_length);
4874
event_name_array= global_instr_class_statements_array;
4875
/* Aggregate to EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME */
4876
stat= & event_name_array[index];
4879
if (flags & STATE_FLAG_TIMED)
4881
/* Aggregate to EVENTS_STATEMENTS_SUMMARY_..._BY_EVENT_NAME (timed) */
4882
stat->aggregate_value(wait_time);
4886
/* Aggregate to EVENTS_STATEMENTS_SUMMARY_..._BY_EVENT_NAME (counted) */
4887
stat->aggregate_counted();
4890
stat->m_lock_time+= state->m_lock_time;
4891
stat->m_rows_sent+= state->m_rows_sent;
4892
stat->m_rows_examined+= state->m_rows_examined;
4893
stat->m_created_tmp_disk_tables+= state->m_created_tmp_disk_tables;
4894
stat->m_created_tmp_tables+= state->m_created_tmp_tables;
4895
stat->m_select_full_join+= state->m_select_full_join;
4896
stat->m_select_full_range_join+= state->m_select_full_range_join;
4897
stat->m_select_range+= state->m_select_range;
4898
stat->m_select_range_check+= state->m_select_range_check;
4899
stat->m_select_scan+= state->m_select_scan;
4900
stat->m_sort_merge_passes+= state->m_sort_merge_passes;
4901
stat->m_sort_range+= state->m_sort_range;
4902
stat->m_sort_rows+= state->m_sort_rows;
4903
stat->m_sort_scan+= state->m_sort_scan;
4904
stat->m_no_index_used+= state->m_no_index_used;
4905
stat->m_no_good_index_used+= state->m_no_good_index_used;
4907
if (digest_stat != NULL)
4909
if (flags & STATE_FLAG_TIMED)
4911
digest_stat->aggregate_value(wait_time);
4915
digest_stat->aggregate_counted();
4918
digest_stat->m_lock_time+= state->m_lock_time;
4919
digest_stat->m_rows_sent+= state->m_rows_sent;
4920
digest_stat->m_rows_examined+= state->m_rows_examined;
4921
digest_stat->m_created_tmp_disk_tables+= state->m_created_tmp_disk_tables;
4922
digest_stat->m_created_tmp_tables+= state->m_created_tmp_tables;
4923
digest_stat->m_select_full_join+= state->m_select_full_join;
4924
digest_stat->m_select_full_range_join+= state->m_select_full_range_join;
4925
digest_stat->m_select_range+= state->m_select_range;
4926
digest_stat->m_select_range_check+= state->m_select_range_check;
4927
digest_stat->m_select_scan+= state->m_select_scan;
4928
digest_stat->m_sort_merge_passes+= state->m_sort_merge_passes;
4929
digest_stat->m_sort_range+= state->m_sort_range;
4930
digest_stat->m_sort_rows+= state->m_sort_rows;
4931
digest_stat->m_sort_scan+= state->m_sort_scan;
4932
digest_stat->m_no_index_used+= state->m_no_index_used;
4933
digest_stat->m_no_good_index_used+= state->m_no_good_index_used;
4936
switch (da->status())
4938
case Diagnostics_area::DA_EMPTY:
4940
case Diagnostics_area::DA_OK:
4941
stat->m_rows_affected+= da->affected_rows();
4942
stat->m_warning_count+= da->statement_warn_count();
4943
if (digest_stat != NULL)
4945
digest_stat->m_rows_affected+= da->affected_rows();
4946
digest_stat->m_warning_count+= da->statement_warn_count();
4949
case Diagnostics_area::DA_EOF:
4950
stat->m_warning_count+= da->statement_warn_count();
4951
if (digest_stat != NULL)
4953
digest_stat->m_warning_count+= da->statement_warn_count();
4956
case Diagnostics_area::DA_ERROR:
4957
stat->m_error_count++;
4958
if (digest_stat != NULL)
4960
digest_stat->m_error_count++;
4963
case Diagnostics_area::DA_DISABLED:
4969
Implementation of the socket instrumentation interface.
4970
@sa PSI_v1::end_socket_wait.
4972
static void end_socket_wait_v1(PSI_socket_locker *locker, size_t byte_count)
4974
PSI_socket_locker_state *state= reinterpret_cast<PSI_socket_locker_state*> (locker);
4975
DBUG_ASSERT(state != NULL);
4977
PFS_socket *socket= reinterpret_cast<PFS_socket *>(state->m_socket);
4978
DBUG_ASSERT(socket != NULL);
4980
ulonglong timer_end= 0;
4981
ulonglong wait_time= 0;
4982
PFS_byte_stat *byte_stat;
4983
register uint flags= state->m_flags;
4984
size_t bytes= ((int)byte_count > -1 ? byte_count : 0);
4986
switch (state->m_operation)
4988
/* Group read operations */
4989
case PSI_SOCKET_RECV:
4990
case PSI_SOCKET_RECVFROM:
4991
case PSI_SOCKET_RECVMSG:
4992
byte_stat= &socket->m_socket_stat.m_io_stat.m_read;
4994
/* Group write operations */
4995
case PSI_SOCKET_SEND:
4996
case PSI_SOCKET_SENDTO:
4997
case PSI_SOCKET_SENDMSG:
4998
byte_stat= &socket->m_socket_stat.m_io_stat.m_write;
5000
/* Group remaining operations as miscellaneous */
5001
case PSI_SOCKET_CONNECT:
5002
case PSI_SOCKET_CREATE:
5003
case PSI_SOCKET_BIND:
5004
case PSI_SOCKET_SEEK:
5005
case PSI_SOCKET_OPT:
5006
case PSI_SOCKET_STAT:
5007
case PSI_SOCKET_SHUTDOWN:
5008
case PSI_SOCKET_SELECT:
5009
case PSI_SOCKET_CLOSE:
5010
byte_stat= &socket->m_socket_stat.m_io_stat.m_misc;
5018
/* Aggregation for EVENTS_WAITS_SUMMARY_BY_INSTANCE */
5019
if (flags & STATE_FLAG_TIMED)
5021
timer_end= state->m_timer();
5022
wait_time= timer_end - state->m_timer_start;
5024
/* Aggregate to the socket instrument for now (timed) */
5025
byte_stat->aggregate(wait_time, bytes);
5029
/* Aggregate to the socket instrument (event count and byte count) */
5030
byte_stat->aggregate_counted(bytes);
5033
/* Aggregate to EVENTS_WAITS_HISTORY and EVENTS_WAITS_HISTORY_LONG */
5034
if (flags & STATE_FLAG_EVENT)
5036
PFS_thread *thread= reinterpret_cast<PFS_thread *>(state->m_thread);
5037
DBUG_ASSERT(thread != NULL);
5038
PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
5039
DBUG_ASSERT(wait != NULL);
5041
wait->m_timer_end= timer_end;
5042
wait->m_end_event_id= thread->m_event_id;
5043
wait->m_number_of_bytes= bytes;
5045
if (flag_events_waits_history)
5046
insert_events_waits_history(thread, wait);
5047
if (flag_events_waits_history_long)
5048
insert_events_waits_history_long(wait);
5049
thread->m_events_waits_current--;
5053
static void set_socket_state_v1(PSI_socket *socket, PSI_socket_state state)
5055
DBUG_ASSERT((state == PSI_SOCKET_STATE_IDLE) || (state == PSI_SOCKET_STATE_ACTIVE));
5056
PFS_socket *pfs= reinterpret_cast<PFS_socket*>(socket);
5057
DBUG_ASSERT(pfs != NULL);
5058
DBUG_ASSERT(pfs->m_idle || (state == PSI_SOCKET_STATE_IDLE));
5059
DBUG_ASSERT(!pfs->m_idle || (state == PSI_SOCKET_STATE_ACTIVE));
5060
pfs->m_idle= (state == PSI_SOCKET_STATE_IDLE);
5064
Set socket descriptor and address info.
5066
static void set_socket_info_v1(PSI_socket *socket,
5067
const my_socket *fd,
5068
const struct sockaddr *addr,
5071
PFS_socket *pfs= reinterpret_cast<PFS_socket*>(socket);
5072
DBUG_ASSERT(pfs != NULL);
5074
/** Set socket descriptor */
5078
/** Set raw socket address and length */
5079
if (likely(addr != NULL && addr_len > 0))
5081
pfs->m_addr_len= addr_len;
5083
/** Restrict address length to size of struct */
5084
if (unlikely(pfs->m_addr_len > sizeof(sockaddr_storage)))
5085
pfs->m_addr_len= sizeof(struct sockaddr_storage);
5087
memcpy(&pfs->m_sock_addr, addr, pfs->m_addr_len);
5092
Implementation of the socket instrumentation interface.
5093
@sa PSI_v1::set_socket_info.
5095
static void set_socket_thread_owner_v1(PSI_socket *socket)
5097
PFS_socket *pfs_socket= reinterpret_cast<PFS_socket*>(socket);
5098
DBUG_ASSERT(pfs_socket != NULL);
5099
pfs_socket->m_thread_owner= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
5104
Implementation of the thread attribute connection interface
5105
@sa PSI_v1::set_thread_connect_attr.
5107
static int set_thread_connect_attrs_v1(const char *buffer, uint length,
5108
const void *from_cs)
5111
PFS_thread *thd= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
5113
DBUG_ASSERT(buffer != NULL);
5115
if (likely(thd != NULL) && session_connect_attrs_size_per_thread > 0)
5117
const CHARSET_INFO *cs = static_cast<const CHARSET_INFO *> (from_cs);
5119
/* copy from the input buffer as much as we can fit */
5120
uint copy_size= (uint)(length < session_connect_attrs_size_per_thread ?
5121
length : session_connect_attrs_size_per_thread);
5122
thd->m_session_lock.allocated_to_dirty();
5123
memcpy(thd->m_session_connect_attrs, buffer, copy_size);
5124
thd->m_session_connect_attrs_length= copy_size;
5125
thd->m_session_connect_attrs_cs_number= cs->number;
5126
thd->m_session_lock.dirty_to_allocated();
5128
if (copy_size == length)
5131
session_connect_attrs_lost++;
5139
Implementation of the instrumentation interface.
5150
register_statement_v1,
5161
release_table_share_v1,
5162
drop_table_share_v1,
5173
set_thread_account_v1,
5175
set_thread_command_v1,
5176
set_thread_start_time_v1,
5177
set_thread_state_v1,
5180
delete_current_thread_v1,
5182
get_thread_file_name_locker_v1,
5183
get_thread_file_stream_locker_v1,
5184
get_thread_file_descriptor_locker_v1,
5191
start_mutex_wait_v1,
5193
start_rwlock_wait_v1, /* read */
5194
end_rwlock_rdwait_v1,
5195
start_rwlock_wait_v1, /* write */
5196
end_rwlock_wrwait_v1,
5199
start_table_io_wait_v1,
5200
end_table_io_wait_v1,
5201
start_table_lock_wait_v1,
5202
end_table_lock_wait_v1,
5203
start_file_open_wait_v1,
5204
end_file_open_wait_v1,
5205
end_file_open_wait_and_bind_to_descriptor_v1,
5208
start_file_close_wait_v1,
5209
end_file_close_wait_v1,
5212
get_thread_statement_locker_v1,
5213
refine_statement_v1,
5215
set_statement_text_v1,
5216
set_statement_lock_time_v1,
5217
set_statement_rows_sent_v1,
5218
set_statement_rows_examined_v1,
5219
inc_statement_created_tmp_disk_tables_v1,
5220
inc_statement_created_tmp_tables_v1,
5221
inc_statement_select_full_join_v1,
5222
inc_statement_select_full_range_join_v1,
5223
inc_statement_select_range_v1,
5224
inc_statement_select_range_check_v1,
5225
inc_statement_select_scan_v1,
5226
inc_statement_sort_merge_passes_v1,
5227
inc_statement_sort_range_v1,
5228
inc_statement_sort_rows_v1,
5229
inc_statement_sort_scan_v1,
5230
set_statement_no_index_used_v1,
5231
set_statement_no_good_index_used_v1,
5233
start_socket_wait_v1,
5235
set_socket_state_v1,
5237
set_socket_thread_owner_v1,
5238
pfs_digest_start_v1,
5239
pfs_digest_add_token_v1,
5240
set_thread_connect_attrs_v1,
5243
static void* get_interface(int version)
5256
struct PSI_bootstrap PFS_bootstrap=