1/* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
2
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.
6
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.
11
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 */
15
16/**
17 @file storage/perfschema/pfs.cc
18 The performance schema implementation of all instruments.
19*/
20#include "my_global.h"
21#include "thr_lock.h"
22#include "mysql/psi/psi.h"
23#include "mysql/psi/mysql_thread.h"
24#include "my_pthread.h"
25#include "sql_const.h"
26#include "pfs.h"
27#include "pfs_instr_class.h"
28#include "pfs_instr.h"
29#include "pfs_host.h"
30#include "pfs_user.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"
41#include "sp_head.h"
42#include "pfs_digest.h"
43
44/**
45 @page PAGE_PERFORMANCE_SCHEMA The Performance Schema main page
46 MySQL PERFORMANCE_SCHEMA implementation.
47
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.
53
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.
58
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.
62
63 @section INTERFACES Multiple interfaces
64
65 The performance schema exposes many different interfaces,
66 for different components, and for different purposes.
67
68 @subsection INT_INSTRUMENTING Instrumenting interface
69
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).
76
77 This interface is available to:
78 - C implementations
79 - C++ implementations
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.
84
85 For details, see the @ref PAGE_INSTRUMENTATION_INTERFACE
86 "instrumentation interface page".
87
88 @subsection INT_COMPILING Compiling interface
89
90 The implementation of the performance schema can be enabled or disabled at
91 build time, when building MySQL from the source code.
92
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.
95
96 For more details, see:
97 @verbatim ./configure --help @endverbatim
98
99 To compile with the performance schema:
100 @verbatim ./configure --with-perfschema @endverbatim
101
102 The implementation of all the compiling options is located in
103 @verbatim ./storage/perfschema/plug.in @endverbatim
104
105 @subsection INT_STARTUP Server startup interface
106
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.
111
112 These extra start options allow the DBA to:
113 - enable or disable the performance schema
114 - specify some sizing parameters.
115
116 To see help for the performance schema startup options, see:
117 @verbatim ./sql/mysqld --verbose --help @endverbatim
118
119 The implementation of all the startup options is located in
120 @verbatim ./sql/mysqld.cc, my_long_options[] @endverbatim
121
122 @subsection INT_BOOTSTRAP Server bootstrap interface
123
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.
131
132 The implementation of the database creation script is located in
133 @verbatim ./scripts/mysql_performance_tables.sql @endverbatim
134
135 @subsection INT_CONFIG Runtime configuration interface
136
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.
141
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.
146
147 For example:
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
152
153 @subsection INT_STATUS Internal audit interface
154
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.
161
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.
166
167 The SHOW STATUS command is implemented in
168 @verbatim ./storage/perfschema/pfs_engine_table.cc @endverbatim
169
170 @subsection INT_QUERY Query interface
171
172 The query interface is used to query the internal state of a running server.
173 It is provided as SQL tables.
174
175 For example:
176 @verbatim mysql> select * from performance_schema.EVENTS_WAITS_CURRENT;
177 @endverbatim
178
179 @section DESIGN_PRINCIPLES Design principles
180
181 @subsection PRINCIPLE_BEHAVIOR No behavior changes
182
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
185 in behavior.
186
187 To achieve this, the overall design of the performance schema complies
188 with the following very severe design constraints:
189
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.
193
194 All the instrumentation points return "void", there are no error codes.
195 Even if the performance schema internally fails, execution of the server
196 code will proceed.
197
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.
201
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.
206
207 In other words, the implementation of the instrumentation points,
208 including all the code called by the instrumentation points, is:
209 - malloc free
210 - mutex free
211 - rwlock free
212
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.
217
218 @subsection PRINCIPLE_PERFORMANCE No performance hit
219
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,
225
226 priority is given in the design to make the instrumentation faster,
227 pushing some complexity to data retrieval.
228
229 As a result, some parts of the design, related to:
230 - the setup code path,
231 - the query code path,
232
233 might appear to be sub-optimal.
234
235 The criterion used here is to optimize primarily the critical path (data
236 collection), possibly at the expense of non-critical code paths.
237
238 @subsection PRINCIPLE_NOT_INTRUSIVE Unintrusive instrumentation
239
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.
242
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)
248
249 @subsection PRINCIPLE_EXTENDABLE Extendable instrumentation
250
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.
258
259 @subsection PRINCIPLE_VERSIONED Versioned instrumentation
260
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.
265
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.
270
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.
275
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.
279
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.
283
284 @subsection PRINCIPLE_DEPLOYMENT Easy deployment
285
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.
289
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,
293 is a bad idea.
294
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.
298
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.
302
303 In addition to this, the performance schema can be included or excluded
304 from the server binary, using build time configuration options.
305
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
310 that is instrumented
311*/
312
313/**
314 @page PAGE_INSTRUMENTATION_INTERFACE Performance schema: instrumentation interface page.
315 MySQL performance schema instrumentation interface.
316
317 @section INTRO Introduction
318
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.
325
326 The ABI layer consists of:
327@code
328#include "mysql/psi/psi.h"
329@endcode
330
331 The API layer consists of:
332@code
333#include "mysql/psi/mutex_mutex.h"
334#include "mysql/psi/mutex_file.h"
335@endcode
336
337 The first helper is for mutexes, rwlocks and conditions,
338 the second for file io.
339
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.
345
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.
350 This is to:
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.
356
357 @section PRINCIPLES Design principles
358
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).
365
366 For a given instrumentation point in the API, the basic coding pattern
367 used is:
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
372 is completed.
373
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.
376
377 The following code fragment is annotated to show how in detail this pattern
378 in implemented, when the instrumentation is compiled in:
379
380@verbatim
381static inline int mysql_mutex_lock(
382 mysql_mutex_t *that, myf flags, const char *src_file, uint src_line)
383{
384 int result;
385 struct PSI_mutex_locker_state state;
386 struct PSI_mutex_locker *locker= NULL;
387
388 ............... (a)
389 locker= PSI_server->start_mutex_wait(&state, that->p_psi,
390 PSI_MUTEX_LOCK, locker, src_file, src_line);
391
392 ............... (b)
393 result= pthread_mutex_lock(&that->m_mutex);
394
395 ............... (c)
396 PSI_server->end_mutex_wait(locker, result);
397
398 return result;
399}
400@endverbatim
401
402 When the performance schema instrumentation is not compiled in,
403 the code becomes simply a wrapper, expanded in line by the compiler:
404
405@verbatim
406static inline int mysql_mutex_lock(...)
407{
408 int result;
409
410 ............... (b)
411 result= pthread_mutex_lock(&that->m_mutex);
412
413 return result;
414}
415@endverbatim
416*/
417
418/**
419 @page PAGE_AGGREGATES Performance schema: the aggregates page.
420 Performance schema aggregates.
421
422 @section INTRO Introduction
423
424 Aggregates tables are tables that can be formally defined as
425 SELECT ... from EVENTS_WAITS_HISTORY_INFINITE ... group by 'group clause'.
426
427 Each group clause defines a different kind of aggregate, and corresponds to
428 a different table exposed by the performance schema.
429
430 Aggregates can be either:
431 - computed on the fly,
432 - computed on demand, based on other available data.
433
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.
439
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.
444
445 @section DIMENSION Concept of dimension
446
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.
450
451 Examples of attributes are:
452 - the time waited
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.
459
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".
465
466 @section PROJECTION Concept of projection
467
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.
471
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.
475
476 In math terms, that corresponds to defining a function:
477 F_i (x): x --> y
478 Applying this function to our point P gives another point P':
479
480 F_i (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)
483
484 That function defines in fact an aggregate !
485 In SQL terms, this aggregate would look like the following table:
486
487@verbatim
488 CREATE VIEW EVENTS_WAITS_SUMMARY_BY_Func_i AS
489 SELECT col_1, col_2, ..., col_{i-1},
490 Func_i(col_i),
491 COUNT(col_i),
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.
496@endverbatim
497
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.
502
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.
509
510 @section COMPOSITION Concept of composition
511
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
515 from the row event.
516
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
520 the end_wait() call.
521
522 The wait locker itself contains a pointer to the object instance
523 waited on.
524 That allows to implement a wait_locker --> object instance projection,
525 with m_target.
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.
529
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.
535
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.
541
542 Back to math again, we have, for example for mutexes:
543
544 F1 (l) : PFS_wait_locker l --> PFS_mutex m = l->m_target.m_mutex
545
546 F1_to_2 (m) : PFS_mutex m --> PFS_mutex_class i = m->m_class
547
548 F2_to_3 (i) : PFS_mutex_class i --> const char *component =
549 substring(i->m_name, ...)
550
551 Per components aggregates are not implemented, this is just an illustration.
552
553 F1 alone defines this aggregate:
554
555 EVENTS_WAITS_HISTORY_INFINITE --> EVENTS_WAITS_SUMMARY_BY_INSTANCE
556 (or MUTEX_INSTANCE)
557
558 F1_to_2 alone could define this aggregate:
559
560 EVENTS_WAITS_SUMMARY_BY_INSTANCE --> EVENTS_WAITS_SUMMARY_BY_EVENT_NAME
561
562 Alternatively, using function composition, with
563 F2 = F1_to_2 o F1, F2 defines:
564
565 EVENTS_WAITS_HISTORY_INFINITE --> EVENTS_WAITS_SUMMARY_BY_EVENT_NAME
566
567 Likewise, F_2_to_3 defines:
568
569 EVENTS_WAITS_SUMMARY_BY_EVENT_NAME --> EVENTS_WAITS_SUMMARY_BY_COMPONENT
570
571 and F3 = F_2_to_3 o F_1_to_2 o F1 defines:
572
573 EVENTS_WAITS_HISTORY_INFINITE --> EVENTS_WAITS_SUMMARY_BY_COMPONENT
574
575 What has all this to do with the code ?
576
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.
583
584 @section OBJECT_GRAPH Object graph
585
586 In terms of object instances, or records, pointers between
587 different buffers define an object instance graph.
588
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
596
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
601
602 The graph of structures will look like:
603
604@verbatim
605 PFS_wait_locker (T-A, M-1) ----------
606 |
607 v
608 PFS_mutex (M-1)
609 - m_wait_stat ------------
610 ^ |
611 | |
612 PFS_wait_locker (T-B, M-1) ---------- |
613 v
614 PFS_mutex_class (M)
615 - m_wait_stat
616 PFS_wait_locker (T-C, M-2) ---------- ^
617 | |
618 v |
619 PFS_mutex (M-2) |
620 - m_wait_stat ------------
621 ^
622 |
623 PFS_wait_locker (T-D, M-2) ----------
624
625 || || ||
626 || || ||
627 vv vv vv
628
629 EVENTS_WAITS_CURRENT ..._SUMMARY_BY_INSTANCE ..._SUMMARY_BY_EVENT_NAME
630@endverbatim
631
632 @section ON_THE_FLY On the fly aggregates
633
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.
637
638 With on the fly aggregates:
639 - the writer thread does all the computation
640 - the reader thread accesses the result directly
641
642 This model is to be avoided if possible, due to the overhead
643 caused when instrumenting code.
644
645 @section HIGHER_LEVEL Higher level aggregates
646
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.
650
651 With higher level aggregates:
652 - the reader thread does all the computation
653 - the writer thread has no overhead.
654
655 @section MIXED Mixed level aggregates
656
657 The 'Mixed' model is a compromise between 'On the fly' and 'Higher level'
658 aggregates, for internal buffers that are not permanent.
659
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.
663
664 With mixed aggregates:
665 - the reader thread does a lot of complex computation,
666 - the writer thread has minimal overhead, on destroy events.
667
668 @section IMPL_WAIT Implementation for waits aggregates
669
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
682
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)
689 - table io
690 - table lock
691 - idle
692
693 The flow of data between aggregates tables varies for each instrumentation.
694
695 @subsection IMPL_WAIT_MUTEX Mutex waits
696
697@verbatim
698 mutex_locker(T, M)
699 |
700 | [1]
701 |
702 |-> pfs_mutex(M) =====>> [B], [C]
703 | |
704 | | [2]
705 | |
706 | |-> pfs_mutex_class(M.class) =====>> [C]
707 |
708 |-> pfs_thread(T).event_name(M) =====>> [A], [D], [E], [F]
709 |
710 | [3]
711 |
712 3a |-> pfs_account(U, H).event_name(M) =====>> [D], [E], [F]
713 . |
714 . | [4-RESET]
715 . |
716 3b .....+-> pfs_user(U).event_name(M) =====>> [E]
717 . |
718 3c .....+-> pfs_host(H).event_name(M) =====>> [F]
719@endverbatim
720
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.
738
739 Implemented as:
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()
756
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
760 from this buffer.
761
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.
768
769 @subsection IMPL_WAIT_RWLOCK Rwlock waits
770
771@verbatim
772 rwlock_locker(T, R)
773 |
774 | [1]
775 |
776 |-> pfs_rwlock(R) =====>> [B], [C]
777 | |
778 | | [2]
779 | |
780 | |-> pfs_rwlock_class(R.class) =====>> [C]
781 |
782 |-> pfs_thread(T).event_name(R) =====>> [A]
783 |
784 ...
785@endverbatim
786
787 Implemented as:
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()
796
797 @subsection IMPL_WAIT_COND Cond waits
798
799@verbatim
800 cond_locker(T, C)
801 |
802 | [1]
803 |
804 |-> pfs_cond(C) =====>> [B], [C]
805 | |
806 | | [2]
807 | |
808 | |-> pfs_cond_class(C.class) =====>> [C]
809 |
810 |-> pfs_thread(T).event_name(C) =====>> [A]
811 |
812 ...
813@endverbatim
814
815 Implemented as:
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()
824
825 @subsection IMPL_WAIT_FILE File waits
826
827@verbatim
828 file_locker(T, F)
829 |
830 | [1]
831 |
832 |-> pfs_file(F) =====>> [B], [C], [D], [E]
833 | |
834 | | [2]
835 | |
836 | |-> pfs_file_class(F.class) =====>> [C], [D]
837 |
838 |-> pfs_thread(T).event_name(F) =====>> [A]
839 |
840 ...
841@endverbatim
842
843 Implemented as:
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()
857
858 @subsection IMPL_WAIT_SOCKET Socket waits
859
860@verbatim
861 socket_locker(T, S)
862 |
863 | [1]
864 |
865 |-> pfs_socket(S) =====>> [A], [B], [C], [D], [E]
866 |
867 | [2]
868 |
869 |-> pfs_socket_class(S.class) =====>> [C], [D]
870 |
871 |-> pfs_thread(T).event_name(S) =====>> [A]
872 |
873 | [3]
874 |
875 3a |-> pfs_account(U, H).event_name(S) =====>> [F], [G], [H]
876 . |
877 . | [4-RESET]
878 . |
879 3b .....+-> pfs_user(U).event_name(S) =====>> [G]
880 . |
881 3c .....+-> pfs_host(H).event_name(S) =====>> [H]
882@endverbatim
883
884 Implemented as:
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()
906
907 @subsection IMPL_WAIT_TABLE Table waits
908
909@verbatim
910 table_locker(Thread Th, Table Tb, Event = io or lock)
911 |
912 | [1]
913 |
9141a |-> pfs_table(Tb) =====>> [A], [B], [C]
915 | |
916 | | [2]
917 | |
918 | |-> pfs_table_share(Tb.share) =====>> [B], [C]
919 | |
920 | | [3]
921 | |
922 | |-> global_table_io_stat =====>> [C]
923 | |
924 | |-> global_table_lock_stat =====>> [C]
925 |
9261b |-> pfs_thread(Th).event_name(E) =====>> [D], [E], [F], [G]
927 | |
928 | | [ 4-RESET]
929 | |
930 | |-> pfs_account(U, H).event_name(E) =====>> [E], [F], [G]
931 | . |
932 | . | [5-RESET]
933 | . |
934 | .....+-> pfs_user(U).event_name(E) =====>> [F]
935 | . |
936 | .....+-> pfs_host(H).event_name(E) =====>> [G]
937 |
9381c |-> pfs_thread(Th).waits_current(W) =====>> [H]
939 |
9401d |-> pfs_thread(Th).waits_history(W) =====>> [I]
941 |
9421e |-> waits_history_long(W) =====>> [J]
943@endverbatim
944
945 Implemented as:
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()
972
973 @section IMPL_STAGE Implementation for stages aggregates
974
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
981
982@verbatim
983 start_stage(T, S)
984 |
985 | [1]
986 |
9871a |-> pfs_thread(T).event_name(S) =====>> [A], [B], [C], [D], [E]
988 | |
989 | | [2]
990 | |
991 | 2a |-> pfs_account(U, H).event_name(S) =====>> [B], [C], [D], [E]
992 | . |
993 | . | [3-RESET]
994 | . |
995 | 2b .....+-> pfs_user(U).event_name(S) =====>> [C]
996 | . |
997 | 2c .....+-> pfs_host(H).event_name(S) =====>> [D], [E]
998 | . . |
999 | . . | [4-RESET]
1000 | 2d . . |
10011b |----+----+----+-> pfs_stage_class(S) =====>> [E]
1002
1003@endverbatim
1004
1005 Implemented as:
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()
1020
1021@section IMPL_STATEMENT Implementation for statements consumers
1022
1023 For statements, the tables that contains individual event data are:
1024 - EVENTS_STATEMENTS_CURRENT
1025 - EVENTS_STATEMENTS_HISTORY
1026 - EVENTS_STATEMENTS_HISTORY_LONG
1027
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
1035
1036@verbatim
1037 statement_locker(T, S)
1038 |
1039 | [1]
1040 |
10411a |-> pfs_thread(T).event_name(S) =====>> [A], [B], [C], [D], [E]
1042 | |
1043 | | [2]
1044 | |
1045 | 2a |-> pfs_account(U, H).event_name(S) =====>> [B], [C], [D], [E]
1046 | . |
1047 | . | [3-RESET]
1048 | . |
1049 | 2b .....+-> pfs_user(U).event_name(S) =====>> [C]
1050 | . |
1051 | 2c .....+-> pfs_host(H).event_name(S) =====>> [D], [E]
1052 | . . |
1053 | . . | [4-RESET]
1054 | 2d . . |
10551b |----+----+----+-> pfs_statement_class(S) =====>> [E]
1056 |
10571c |-> pfs_thread(T).statement_current(S) =====>> [F]
1058 |
10591d |-> pfs_thread(T).statement_history(S) =====>> [G]
1060 |
10611e |-> statement_history_long(S) =====>> [H]
1062 |
10631f |-> statement_digest(S) =====>> [I]
1064
1065@endverbatim
1066
1067 Implemented as:
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()
1098*/
1099
1100/**
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".
1105
1106 @defgroup Performance_schema_implementation Performance Schema Implementation
1107 @ingroup Performance_schema
1108
1109 @defgroup Performance_schema_tables Performance Schema Tables
1110 @ingroup Performance_schema_implementation
1111*/
1112
1113pthread_key(PFS_thread*, THR_PFS);
1114bool THR_PFS_initialized= false;
1115
1116/**
1117 Conversion map from PSI_mutex_operation to enum_operation_type.
1118 Indexed by enum PSI_mutex_operation.
1119*/
1120static enum_operation_type mutex_operation_map[]=
1121{
1122 OPERATION_TYPE_LOCK,
1123 OPERATION_TYPE_TRYLOCK
1124};
1125
1126/**
1127 Conversion map from PSI_rwlock_operation to enum_operation_type.
1128 Indexed by enum PSI_rwlock_operation.
1129*/
1130static enum_operation_type rwlock_operation_map[]=
1131{
1132 OPERATION_TYPE_READLOCK,
1133 OPERATION_TYPE_WRITELOCK,
1134 OPERATION_TYPE_TRYREADLOCK,
1135 OPERATION_TYPE_TRYWRITELOCK
1136};
1137
1138/**
1139 Conversion map from PSI_cond_operation to enum_operation_type.
1140 Indexed by enum PSI_cond_operation.
1141*/
1142static enum_operation_type cond_operation_map[]=
1143{
1144 OPERATION_TYPE_WAIT,
1145 OPERATION_TYPE_TIMEDWAIT
1146};
1147
1148/**
1149 Conversion map from PSI_file_operation to enum_operation_type.
1150 Indexed by enum PSI_file_operation.
1151*/
1152static enum_operation_type file_operation_map[]=
1153{
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
1171};
1172
1173/**
1174 Conversion map from PSI_table_operation to enum_operation_type.
1175 Indexed by enum PSI_table_io_operation.
1176*/
1177static enum_operation_type table_io_operation_map[]=
1178{
1179 OPERATION_TYPE_TABLE_FETCH,
1180 OPERATION_TYPE_TABLE_WRITE_ROW,
1181 OPERATION_TYPE_TABLE_UPDATE_ROW,
1182 OPERATION_TYPE_TABLE_DELETE_ROW
1183};
1184
1185/**
1186 Conversion map from enum PFS_TL_LOCK_TYPE to enum_operation_type.
1187 Indexed by enum PFS_TL_LOCK_TYPE.
1188*/
1189static enum_operation_type table_lock_operation_map[]=
1190{
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 */
1202};
1203
1204/**
1205 Conversion map from PSI_socket_operation to enum_operation_type.
1206 Indexed by enum PSI_socket_operation.
1207*/
1208static enum_operation_type socket_operation_map[]=
1209{
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
1225};
1226
1227/**
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
1238*/
1239static int build_prefix(const LEX_CSTRING *prefix, const char *category,
1240 char *output, int *output_length)
1241{
1242 size_t len= strlen(category);
1243 char *out_ptr= output;
1244 size_t prefix_length= prefix->length;
1245
1246 if (unlikely((prefix_length + len + 1) >=
1247 PFS_MAX_FULL_PREFIX_NAME_LENGTH))
1248 {
1249 pfs_print_error("build_prefix: prefix+category is too long <%s> <%s>\n",
1250 prefix->str, category);
1251 return 1;
1252 }
1253
1254 if (unlikely(strchr(category, '/') != NULL))
1255 {
1256 pfs_print_error("build_prefix: invalid category <%s>\n",
1257 category);
1258 return 1;
1259 }
1260
1261 /* output = prefix + category + '/' */
1262 memcpy(out_ptr, prefix->str, prefix_length);
1263 out_ptr+= prefix_length;
1264 memcpy(out_ptr, category, len);
1265 out_ptr+= len;
1266 *out_ptr= '/';
1267 out_ptr++;
1268 *output_length= (int)(out_ptr - output);
1269
1270 return 0;
1271}
1272
1273#define REGISTER_BODY_V1(KEY_T, PREFIX, REGISTER_FUNC) \
1274 KEY_T key; \
1275 char formatted_name[PFS_MAX_INFO_NAME_LENGTH]; \
1276 int prefix_length; \
1277 int len; \
1278 int full_length; \
1279 \
1280 DBUG_ASSERT(category != NULL); \
1281 DBUG_ASSERT(info != NULL); \
1282 if (unlikely(build_prefix(&PREFIX, category, \
1283 formatted_name, &prefix_length))) \
1284 { \
1285 for (; count>0; count--, info++) \
1286 *(info->m_key)= 0; \
1287 return ; \
1288 } \
1289 \
1290 for (; count>0; count--, info++) \
1291 { \
1292 DBUG_ASSERT(info->m_key != NULL); \
1293 DBUG_ASSERT(info->m_name != NULL); \
1294 len= (int)strlen(info->m_name); \
1295 full_length= prefix_length + len; \
1296 if (likely(full_length <= PFS_MAX_INFO_NAME_LENGTH)) \
1297 { \
1298 memcpy(formatted_name + prefix_length, info->m_name, len); \
1299 key= REGISTER_FUNC(formatted_name, full_length, info->m_flags); \
1300 } \
1301 else \
1302 { \
1303 pfs_print_error("REGISTER_BODY_V1: name too long <%s> <%s>\n", \
1304 category, info->m_name); \
1305 key= 0; \
1306 } \
1307 \
1308 *(info->m_key)= key; \
1309 } \
1310 return;
1311
1312/* Use C linkage for the interface functions. */
1313
1314C_MODE_START
1315
1316/**
1317 Implementation of the mutex instrumentation interface.
1318 @sa PSI_v1::register_mutex.
1319*/
1320static void register_mutex_v1(const char *category,
1321 PSI_mutex_info_v1 *info,
1322 int count)
1323{
1324 REGISTER_BODY_V1(PSI_mutex_key,
1325 mutex_instrument_prefix,
1326 register_mutex_class)
1327}
1328
1329/**
1330 Implementation of the rwlock instrumentation interface.
1331 @sa PSI_v1::register_rwlock.
1332*/
1333static void register_rwlock_v1(const char *category,
1334 PSI_rwlock_info_v1 *info,
1335 int count)
1336{
1337 REGISTER_BODY_V1(PSI_rwlock_key,
1338 rwlock_instrument_prefix,
1339 register_rwlock_class)
1340}
1341
1342/**
1343 Implementation of the cond instrumentation interface.
1344 @sa PSI_v1::register_cond.
1345*/
1346static void register_cond_v1(const char *category,
1347 PSI_cond_info_v1 *info,
1348 int count)
1349{
1350 REGISTER_BODY_V1(PSI_cond_key,
1351 cond_instrument_prefix,
1352 register_cond_class)
1353}
1354
1355/**
1356 Implementation of the thread instrumentation interface.
1357 @sa PSI_v1::register_thread.
1358*/
1359static void register_thread_v1(const char *category,
1360 PSI_thread_info_v1 *info,
1361 int count)
1362{
1363 REGISTER_BODY_V1(PSI_thread_key,
1364 thread_instrument_prefix,
1365 register_thread_class)
1366}
1367
1368/**
1369 Implementation of the file instrumentation interface.
1370 @sa PSI_v1::register_file.
1371*/
1372static void register_file_v1(const char *category,
1373 PSI_file_info_v1 *info,
1374 int count)
1375{
1376 REGISTER_BODY_V1(PSI_file_key,
1377 file_instrument_prefix,
1378 register_file_class)
1379}
1380
1381static void register_stage_v1(const char *category,
1382 PSI_stage_info_v1 **info_array,
1383 int count)
1384{
1385 char formatted_name[PFS_MAX_INFO_NAME_LENGTH];
1386 int prefix_length;
1387 int len;
1388 int full_length;
1389 PSI_stage_info_v1 *info;
1390
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)))
1395 {
1396 for (; count>0; count--, info_array++)
1397 (*info_array)->m_key= 0;
1398 return ;
1399 }
1400
1401 for (; count>0; count--, info_array++)
1402 {
1403 info= *info_array;
1404 DBUG_ASSERT(info != NULL);
1405 DBUG_ASSERT(info->m_name != NULL);
1406 len= (int)strlen(info->m_name);
1407 full_length= prefix_length + len;
1408 if (likely(full_length <= PFS_MAX_INFO_NAME_LENGTH))
1409 {
1410 memcpy(formatted_name + prefix_length, info->m_name, len);
1411 info->m_key= register_stage_class(formatted_name,
1412 prefix_length,
1413 full_length,
1414 info->m_flags);
1415 }
1416 else
1417 {
1418 pfs_print_error("register_stage_v1: name too long <%s> <%s>\n",
1419 category, info->m_name);
1420 info->m_key= 0;
1421 }
1422 }
1423 return;
1424}
1425
1426static void register_statement_v1(const char *category,
1427 PSI_statement_info_v1 *info,
1428 int count)
1429{
1430 char formatted_name[PFS_MAX_INFO_NAME_LENGTH];
1431 int prefix_length;
1432 int len;
1433 int full_length;
1434
1435 DBUG_ASSERT(category != NULL);
1436 DBUG_ASSERT(info != NULL);
1437 if (unlikely(build_prefix(&statement_instrument_prefix,
1438 category, formatted_name, &prefix_length)))
1439 {
1440 for (; count>0; count--, info++)
1441 info->m_key= 0;
1442 return ;
1443 }
1444
1445 for (; count>0; count--, info++)
1446 {
1447 if (info->m_name == NULL)
1448 continue;
1449
1450 len= (int)strlen(info->m_name);
1451 full_length= prefix_length + len;
1452 if (likely(full_length <= PFS_MAX_INFO_NAME_LENGTH))
1453 {
1454 memcpy(formatted_name + prefix_length, info->m_name, len);
1455 info->m_key= register_statement_class(formatted_name, full_length, info->m_flags);
1456 }
1457 else
1458 {
1459 pfs_print_error("register_statement_v1: name too long <%s>\n",
1460 info->m_name);
1461 info->m_key= 0;
1462 }
1463 }
1464 return;
1465}
1466
1467static void register_socket_v1(const char *category,
1468 PSI_socket_info_v1 *info,
1469 int count)
1470{
1471 REGISTER_BODY_V1(PSI_socket_key,
1472 socket_instrument_prefix,
1473 register_socket_class)
1474}
1475
1476#define INIT_BODY_V1(T, KEY, ID) \
1477 PFS_##T##_class *klass; \
1478 PFS_##T *pfs; \
1479 klass= find_##T##_class(KEY); \
1480 if (unlikely(klass == NULL)) \
1481 return NULL; \
1482 if (! klass->m_enabled) \
1483 return NULL; \
1484 pfs= create_##T(klass, ID); \
1485 return reinterpret_cast<PSI_##T *> (pfs)
1486
1487/**
1488 Implementation of the mutex instrumentation interface.
1489 @sa PSI_v1::init_mutex.
1490*/
1491static PSI_mutex*
1492init_mutex_v1(PSI_mutex_key key, const void *identity)
1493{
1494 INIT_BODY_V1(mutex, key, identity);
1495}
1496
1497/**
1498 Implementation of the mutex instrumentation interface.
1499 @sa PSI_v1::destroy_mutex.
1500*/
1501static void destroy_mutex_v1(PSI_mutex* mutex)
1502{
1503 PFS_mutex *pfs= reinterpret_cast<PFS_mutex*> (mutex);
1504
1505 DBUG_ASSERT(pfs != NULL);
1506
1507 destroy_mutex(pfs);
1508}
1509
1510/**
1511 Implementation of the rwlock instrumentation interface.
1512 @sa PSI_v1::init_rwlock.
1513*/
1514static PSI_rwlock*
1515init_rwlock_v1(PSI_rwlock_key key, const void *identity)
1516{
1517 INIT_BODY_V1(rwlock, key, identity);
1518}
1519
1520/**
1521 Implementation of the rwlock instrumentation interface.
1522 @sa PSI_v1::destroy_rwlock.
1523*/
1524static void destroy_rwlock_v1(PSI_rwlock* rwlock)
1525{
1526 PFS_rwlock *pfs= reinterpret_cast<PFS_rwlock*> (rwlock);
1527
1528 DBUG_ASSERT(pfs != NULL);
1529
1530 destroy_rwlock(pfs);
1531}
1532
1533/**
1534 Implementation of the cond instrumentation interface.
1535 @sa PSI_v1::init_cond.
1536*/
1537static PSI_cond*
1538init_cond_v1(PSI_cond_key key, const void *identity)
1539{
1540 INIT_BODY_V1(cond, key, identity);
1541}
1542
1543/**
1544 Implementation of the cond instrumentation interface.
1545 @sa PSI_v1::destroy_cond.
1546*/
1547static void destroy_cond_v1(PSI_cond* cond)
1548{
1549 PFS_cond *pfs= reinterpret_cast<PFS_cond*> (cond);
1550
1551 DBUG_ASSERT(pfs != NULL);
1552
1553 destroy_cond(pfs);
1554}
1555
1556/**
1557 Implementation of the table instrumentation interface.
1558 @sa PSI_v1::get_table_share.
1559*/
1560static PSI_table_share*
1561get_table_share_v1(my_bool temporary, TABLE_SHARE *share)
1562{
1563 /* Ignore temporary tables and views. */
1564 if (temporary || share->is_view)
1565 return NULL;
1566 /* An instrumented thread is required, for LF_PINS. */
1567 PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1568 if (unlikely(pfs_thread == NULL))
1569 return NULL;
1570 PFS_table_share* pfs_share;
1571 pfs_share= find_or_create_table_share(pfs_thread, temporary, share);
1572 return reinterpret_cast<PSI_table_share*> (pfs_share);
1573}
1574
1575/**
1576 Implementation of the table instrumentation interface.
1577 @sa PSI_v1::release_table_share.
1578*/
1579static void release_table_share_v1(PSI_table_share* share)
1580{
1581 PFS_table_share* pfs= reinterpret_cast<PFS_table_share*> (share);
1582
1583 if (unlikely(pfs == NULL))
1584 return;
1585
1586 release_table_share(pfs);
1587}
1588
1589/**
1590 Implementation of the table instrumentation interface.
1591 @sa PSI_v1::drop_table_share.
1592*/
1593static void
1594drop_table_share_v1(my_bool temporary,
1595 const char *schema_name, int schema_name_length,
1596 const char *table_name, int table_name_length)
1597{
1598 /* Ignore temporary tables. */
1599 if (temporary)
1600 return;
1601 PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1602 if (unlikely(pfs_thread == NULL))
1603 return;
1604 /* TODO: temporary tables */
1605 drop_table_share(pfs_thread, temporary, schema_name, schema_name_length,
1606 table_name, table_name_length);
1607}
1608
1609/**
1610 Implementation of the table instrumentation interface.
1611 @sa PSI_v1::open_table.
1612*/
1613static PSI_table*
1614open_table_v1(PSI_table_share *share, const void *identity)
1615{
1616 PFS_table_share *pfs_table_share= reinterpret_cast<PFS_table_share*> (share);
1617
1618 /*
1619 When the performance schema is off, do not instrument anything.
1620 Table handles have short life cycle, instrumentation will happen
1621 again if needed during the next open().
1622 */
1623 if (psi_unlikely(! flag_global_instrumentation))
1624 return NULL;
1625
1626 if (unlikely(pfs_table_share == NULL))
1627 return NULL;
1628
1629 /* This object is not to be instrumented. */
1630 if (! pfs_table_share->m_enabled)
1631 return NULL;
1632
1633 /* This object is instrumented, but all table instruments are disabled. */
1634 if (! global_table_io_class.m_enabled && ! global_table_lock_class.m_enabled)
1635 return NULL;
1636
1637 PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1638 if (unlikely(thread == NULL))
1639 return NULL;
1640
1641 PFS_table *pfs_table= create_table(pfs_table_share, thread, identity);
1642 return reinterpret_cast<PSI_table *> (pfs_table);
1643}
1644
1645/**
1646 Implementation of the table instrumentation interface.
1647 @sa PSI_v1::unbind_table.
1648*/
1649static void unbind_table_v1(PSI_table *table)
1650{
1651 PFS_table *pfs= reinterpret_cast<PFS_table*> (table);
1652 if (likely(pfs != NULL))
1653 {
1654 pfs->m_thread_owner= NULL;
1655 }
1656}
1657
1658/**
1659 Implementation of the table instrumentation interface.
1660 @sa PSI_v1::rebind_table.
1661*/
1662static PSI_table *
1663rebind_table_v1(PSI_table_share *share, const void *identity, PSI_table *table)
1664{
1665 PFS_table *pfs= reinterpret_cast<PFS_table*> (table);
1666 if (likely(pfs != NULL))
1667 {
1668 PFS_thread *thread;
1669 DBUG_ASSERT(pfs->m_thread_owner == NULL);
1670
1671 if (psi_unlikely(! flag_global_instrumentation))
1672 {
1673 destroy_table(pfs);
1674 return NULL;
1675 }
1676
1677 /* The table handle was already instrumented, reuse it for this thread. */
1678 thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1679
1680 if (unlikely(! pfs->m_share->m_enabled))
1681 {
1682 destroy_table(pfs);
1683 return NULL;
1684 }
1685
1686 if (unlikely(! global_table_io_class.m_enabled && ! global_table_lock_class.m_enabled))
1687 {
1688 destroy_table(pfs);
1689 return NULL;
1690 }
1691
1692 pfs->m_thread_owner= thread;
1693 return table;
1694 }
1695
1696 if (psi_unlikely(! flag_global_instrumentation))
1697 return NULL;
1698
1699 /* See open_table_v1() */
1700
1701 PFS_table_share *pfs_table_share= reinterpret_cast<PFS_table_share*> (share);
1702
1703 if (unlikely(pfs_table_share == NULL))
1704 return NULL;
1705
1706 if (! pfs_table_share->m_enabled)
1707 return NULL;
1708
1709 if (! global_table_io_class.m_enabled && ! global_table_lock_class.m_enabled)
1710 return NULL;
1711
1712 PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1713 if (unlikely(thread == NULL))
1714 return NULL;
1715
1716 PFS_table *pfs_table= create_table(pfs_table_share, thread, identity);
1717 return reinterpret_cast<PSI_table *> (pfs_table);
1718}
1719
1720/**
1721 Implementation of the table instrumentation interface.
1722 @sa PSI_v1::close_table.
1723*/
1724static void close_table_v1(PSI_table *table)
1725{
1726 PFS_table *pfs= reinterpret_cast<PFS_table*> (table);
1727 if (unlikely(pfs == NULL))
1728 return;
1729 pfs->aggregate();
1730 destroy_table(pfs);
1731}
1732
1733static PSI_socket*
1734init_socket_v1(PSI_socket_key key, const my_socket *fd,
1735 const struct sockaddr *addr, socklen_t addr_len)
1736{
1737 PFS_socket_class *klass;
1738 PFS_socket *pfs;
1739 klass= find_socket_class(key);
1740 if (unlikely(klass == NULL))
1741 return NULL;
1742 if (! klass->m_enabled)
1743 return NULL;
1744 pfs= create_socket(klass, fd, addr, addr_len);
1745 return reinterpret_cast<PSI_socket *> (pfs);
1746}
1747
1748static void destroy_socket_v1(PSI_socket *socket)
1749{
1750 PFS_socket *pfs= reinterpret_cast<PFS_socket*> (socket);
1751
1752 DBUG_ASSERT(pfs != NULL);
1753
1754 destroy_socket(pfs);
1755}
1756
1757/**
1758 Implementation of the file instrumentation interface.
1759 @sa PSI_v1::create_file.
1760*/
1761static void create_file_v1(PSI_file_key key, const char *name, File file)
1762{
1763 if (psi_unlikely(! flag_global_instrumentation))
1764 return;
1765 int index= (int) file;
1766 if (unlikely(index < 0))
1767 return;
1768 PFS_file_class *klass= find_file_class(key);
1769 if (unlikely(klass == NULL))
1770 return;
1771 if (! klass->m_enabled)
1772 return;
1773
1774 /* A thread is needed for LF_PINS */
1775 PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1776 if (unlikely(pfs_thread == NULL))
1777 return;
1778
1779 if (flag_thread_instrumentation && ! pfs_thread->m_enabled)
1780 return;
1781
1782 /*
1783 We want this check after pfs_thread->m_enabled,
1784 to avoid reporting false loss.
1785 */
1786 if (unlikely(index >= file_handle_max))
1787 {
1788 file_handle_lost++;
1789 return;
1790 }
1791
1792 uint len= (uint)strlen(name);
1793 PFS_file *pfs_file= find_or_create_file(pfs_thread, klass, name, len, true);
1794
1795 file_handle_array[index]= pfs_file;
1796}
1797
1798/**
1799 Arguments given from a parent to a child thread, packaged in one structure.
1800 This data is used when spawning a new instrumented thread.
1801 @sa pfs_spawn_thread.
1802*/
1803struct PFS_spawn_thread_arg
1804{
1805 ulonglong m_thread_internal_id;
1806 char m_username[USERNAME_LENGTH];
1807 uint m_username_length;
1808 char m_hostname[HOSTNAME_LENGTH];
1809 uint m_hostname_length;
1810
1811 PSI_thread_key m_child_key;
1812 const void *m_child_identity;
1813 void *(*m_user_start_routine)(void*);
1814 void *m_user_arg;
1815};
1816
1817void* pfs_spawn_thread(void *arg)
1818{
1819 PFS_spawn_thread_arg *typed_arg= (PFS_spawn_thread_arg*) arg;
1820 void *user_arg;
1821 void *(*user_start_routine)(void*);
1822
1823 PFS_thread *pfs;
1824
1825 /* First, attach instrumentation to this newly created pthread. */
1826 PFS_thread_class *klass= find_thread_class(typed_arg->m_child_key);
1827 if (likely(klass != NULL))
1828 {
1829 pfs= create_thread(klass, typed_arg->m_child_identity, 0);
1830 if (likely(pfs != NULL))
1831 {
1832 clear_thread_account(pfs);
1833
1834 pfs->m_parent_thread_internal_id= typed_arg->m_thread_internal_id;
1835
1836 memcpy(pfs->m_username, typed_arg->m_username, sizeof(pfs->m_username));
1837 pfs->m_username_length= typed_arg->m_username_length;
1838
1839 memcpy(pfs->m_hostname, typed_arg->m_hostname, sizeof(pfs->m_hostname));
1840 pfs->m_hostname_length= typed_arg->m_hostname_length;
1841
1842 set_thread_account(pfs);
1843 }
1844 }
1845 else
1846 {
1847 pfs= NULL;
1848 }
1849 my_pthread_setspecific_ptr(THR_PFS, pfs);
1850
1851 /*
1852 Secondly, free the memory allocated in spawn_thread_v1().
1853 It is preferable to do this before invoking the user
1854 routine, to avoid memory leaks at shutdown, in case
1855 the server exits without waiting for this thread.
1856 */
1857 user_start_routine= typed_arg->m_user_start_routine;
1858 user_arg= typed_arg->m_user_arg;
1859 my_free(typed_arg);
1860
1861 /* Then, execute the user code for this thread. */
1862 (*user_start_routine)(user_arg);
1863
1864 return NULL;
1865}
1866
1867/**
1868 Implementation of the thread instrumentation interface.
1869 @sa PSI_v1::spawn_thread.
1870*/
1871static int spawn_thread_v1(PSI_thread_key key,
1872 pthread_t *thread, const pthread_attr_t *attr,
1873 void *(*start_routine)(void*), void *arg)
1874{
1875 PFS_spawn_thread_arg *psi_arg;
1876 PFS_thread *parent;
1877
1878 /* psi_arg can not be global, and can not be a local variable. */
1879 psi_arg= (PFS_spawn_thread_arg*) my_malloc(sizeof(PFS_spawn_thread_arg),
1880 MYF(MY_WME));
1881 if (unlikely(psi_arg == NULL))
1882 return EAGAIN;
1883
1884 psi_arg->m_child_key= key;
1885 psi_arg->m_child_identity= (arg ? arg : thread);
1886 psi_arg->m_user_start_routine= start_routine;
1887 psi_arg->m_user_arg= arg;
1888
1889 parent= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1890 if (parent != NULL)
1891 {
1892 /*
1893 Make a copy of the parent attributes.
1894 This is required, because instrumentation for this thread (the parent)
1895 may be destroyed before the child thread instrumentation is created.
1896 */
1897 psi_arg->m_thread_internal_id= parent->m_thread_internal_id;
1898
1899 memcpy(psi_arg->m_username, parent->m_username, sizeof(psi_arg->m_username));
1900 psi_arg->m_username_length= parent->m_username_length;
1901
1902 memcpy(psi_arg->m_hostname, parent->m_hostname, sizeof(psi_arg->m_hostname));
1903 psi_arg->m_hostname_length= parent->m_hostname_length;
1904 }
1905 else
1906 {
1907 psi_arg->m_thread_internal_id= 0;
1908 psi_arg->m_username_length= 0;
1909 psi_arg->m_hostname_length= 0;
1910 }
1911
1912 int result= pthread_create(thread, attr, pfs_spawn_thread, psi_arg);
1913 if (unlikely(result != 0))
1914 my_free(psi_arg);
1915 return result;
1916}
1917
1918/**
1919 Implementation of the thread instrumentation interface.
1920 @sa PSI_v1::new_thread.
1921*/
1922static PSI_thread*
1923new_thread_v1(PSI_thread_key key, const void *identity, ulonglong processlist_id)
1924{
1925 PFS_thread *pfs;
1926
1927 PFS_thread_class *klass= find_thread_class(key);
1928 if (likely(klass != NULL))
1929 pfs= create_thread(klass, identity, processlist_id);
1930 else
1931 pfs= NULL;
1932
1933 return reinterpret_cast<PSI_thread*> (pfs);
1934}
1935
1936/**
1937 Implementation of the thread instrumentation interface.
1938 @sa PSI_v1::set_thread_id.
1939*/
1940static void set_thread_id_v1(PSI_thread *thread, ulonglong processlist_id)
1941{
1942 PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread);
1943 if (unlikely(pfs == NULL))
1944 return;
1945 pfs->m_processlist_id= (ulong)processlist_id;
1946}
1947
1948/**
1949 Implementation of the thread instrumentation interface.
1950 @sa PSI_v1::get_thread_id.
1951*/
1952static PSI_thread*
1953get_thread_v1(void)
1954{
1955 PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1956 return reinterpret_cast<PSI_thread*> (pfs);
1957}
1958
1959/**
1960 Implementation of the thread instrumentation interface.
1961 @sa PSI_v1::set_thread_user.
1962*/
1963static void set_thread_user_v1(const char *user, int user_len)
1964{
1965 PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
1966
1967 DBUG_ASSERT((user != NULL) || (user_len == 0));
1968 DBUG_ASSERT(user_len >= 0);
1969 DBUG_ASSERT((uint) user_len <= sizeof(pfs->m_username));
1970
1971 if (unlikely(pfs == NULL))
1972 return;
1973
1974 aggregate_thread(pfs, pfs->m_account, pfs->m_user, pfs->m_host);
1975
1976 pfs->m_session_lock.allocated_to_dirty();
1977
1978 clear_thread_account(pfs);
1979
1980 if (user_len > 0)
1981 memcpy(pfs->m_username, user, user_len);
1982 pfs->m_username_length= user_len;
1983
1984 set_thread_account(pfs);
1985
1986 bool enabled= true;
1987 if (flag_thread_instrumentation)
1988 {
1989 if ((pfs->m_username_length > 0) && (pfs->m_hostname_length > 0))
1990 {
1991 /*
1992 TODO: performance improvement.
1993 Once performance_schema.USERS is exposed,
1994 we can use PFS_user::m_enabled instead of looking up
1995 SETUP_ACTORS every time.
1996 */
1997 lookup_setup_actor(pfs,
1998 pfs->m_username, pfs->m_username_length,
1999 pfs->m_hostname, pfs->m_hostname_length,
2000 &enabled);
2001 }
2002 }
2003
2004 pfs->m_enabled= enabled;
2005
2006 pfs->m_session_lock.dirty_to_allocated();
2007}
2008
2009/**
2010 Implementation of the thread instrumentation interface.
2011 @sa PSI_v1::set_thread_account.
2012*/
2013static void set_thread_account_v1(const char *user, int user_len,
2014 const char *host, int host_len)
2015{
2016 PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2017
2018 DBUG_ASSERT((user != NULL) || (user_len == 0));
2019 DBUG_ASSERT(user_len >= 0);
2020 DBUG_ASSERT((uint) user_len <= sizeof(pfs->m_username));
2021 DBUG_ASSERT((host != NULL) || (host_len == 0));
2022 DBUG_ASSERT(host_len >= 0);
2023
2024 host_len= MY_MIN(host_len, static_cast<int>(sizeof(pfs->m_hostname)));
2025
2026 if (unlikely(pfs == NULL))
2027 return;
2028
2029 pfs->m_session_lock.allocated_to_dirty();
2030
2031 clear_thread_account(pfs);
2032
2033 if (host_len > 0)
2034 memcpy(pfs->m_hostname, host, host_len);
2035 pfs->m_hostname_length= host_len;
2036
2037 if (user_len > 0)
2038 memcpy(pfs->m_username, user, user_len);
2039 pfs->m_username_length= user_len;
2040
2041 set_thread_account(pfs);
2042
2043 bool enabled= true;
2044 if (flag_thread_instrumentation)
2045 {
2046 if ((pfs->m_username_length > 0) && (pfs->m_hostname_length > 0))
2047 {
2048 /*
2049 TODO: performance improvement.
2050 Once performance_schema.USERS is exposed,
2051 we can use PFS_user::m_enabled instead of looking up
2052 SETUP_ACTORS every time.
2053 */
2054 lookup_setup_actor(pfs,
2055 pfs->m_username, pfs->m_username_length,
2056 pfs->m_hostname, pfs->m_hostname_length,
2057 &enabled);
2058 }
2059 }
2060 pfs->m_enabled= enabled;
2061
2062 pfs->m_session_lock.dirty_to_allocated();
2063}
2064
2065/**
2066 Implementation of the thread instrumentation interface.
2067 @sa PSI_v1::set_thread_db.
2068*/
2069static void set_thread_db_v1(const char* db, int db_len)
2070{
2071 PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2072
2073 DBUG_ASSERT((db != NULL) || (db_len == 0));
2074 DBUG_ASSERT(db_len >= 0);
2075 DBUG_ASSERT((uint) db_len <= sizeof(pfs->m_dbname));
2076
2077 if (likely(pfs != NULL))
2078 {
2079 pfs->m_stmt_lock.allocated_to_dirty();
2080 if (db_len > 0)
2081 memcpy(pfs->m_dbname, db, db_len);
2082 pfs->m_dbname_length= db_len;
2083 pfs->m_stmt_lock.dirty_to_allocated();
2084 }
2085}
2086
2087/**
2088 Implementation of the thread instrumentation interface.
2089 @sa PSI_v1::set_thread_command.
2090*/
2091static void set_thread_command_v1(int command)
2092{
2093 PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2094
2095 DBUG_ASSERT(command >= 0);
2096 DBUG_ASSERT(command <= (int) COM_END);
2097
2098 if (likely(pfs != NULL))
2099 {
2100 pfs->m_command= command;
2101 }
2102}
2103
2104/**
2105 Implementation of the thread instrumentation interface.
2106 @sa PSI_v1::set_thread_start_time.
2107*/
2108static void set_thread_start_time_v1(time_t start_time)
2109{
2110 PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2111
2112 if (likely(pfs != NULL))
2113 {
2114 pfs->m_start_time= start_time;
2115 }
2116}
2117
2118/**
2119 Implementation of the thread instrumentation interface.
2120 @sa PSI_v1::set_thread_state.
2121*/
2122static void set_thread_state_v1(const char* state)
2123{
2124 /* DEPRECATED. */
2125}
2126
2127/**
2128 Implementation of the thread instrumentation interface.
2129 @sa PSI_v1::set_thread_info.
2130*/
2131static void set_thread_info_v1(const char* info, uint info_len)
2132{
2133 PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2134
2135 DBUG_ASSERT((info != NULL) || (info_len == 0));
2136
2137 if (likely(pfs != NULL))
2138 {
2139 if ((info != NULL) && (info_len > 0))
2140 {
2141 if (info_len > sizeof(pfs->m_processlist_info))
2142 info_len= sizeof(pfs->m_processlist_info);
2143
2144 pfs->m_stmt_lock.allocated_to_dirty();
2145 memcpy(pfs->m_processlist_info, info, info_len);
2146 pfs->m_processlist_info_length= info_len;
2147 pfs->m_stmt_lock.dirty_to_allocated();
2148 }
2149 else
2150 {
2151 pfs->m_stmt_lock.allocated_to_dirty();
2152 pfs->m_processlist_info_length= 0;
2153 pfs->m_stmt_lock.dirty_to_allocated();
2154 }
2155 }
2156}
2157
2158/**
2159 Implementation of the thread instrumentation interface.
2160 @sa PSI_v1::set_thread.
2161*/
2162static void set_thread_v1(PSI_thread* thread)
2163{
2164 PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread);
2165 my_pthread_setspecific_ptr(THR_PFS, pfs);
2166}
2167
2168/**
2169 Implementation of the thread instrumentation interface.
2170 @sa PSI_v1::delete_current_thread.
2171*/
2172static void delete_current_thread_v1(void)
2173{
2174 PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2175 if (thread != NULL)
2176 {
2177 aggregate_thread(thread, thread->m_account, thread->m_user, thread->m_host);
2178 my_pthread_setspecific_ptr(THR_PFS, NULL);
2179 destroy_thread(thread);
2180 }
2181}
2182
2183/**
2184 Implementation of the thread instrumentation interface.
2185 @sa PSI_v1::delete_thread.
2186*/
2187static void delete_thread_v1(PSI_thread *thread)
2188{
2189 PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread);
2190
2191 if (pfs != NULL)
2192 {
2193 aggregate_thread(pfs, pfs->m_account, pfs->m_user, pfs->m_host);
2194 destroy_thread(pfs);
2195 }
2196}
2197
2198/**
2199 Implementation of the mutex instrumentation interface.
2200 @sa PSI_v1::start_mutex_wait.
2201*/
2202static PSI_mutex_locker*
2203start_mutex_wait_v1(PSI_mutex_locker_state *state,
2204 PSI_mutex *mutex, PSI_mutex_operation op,
2205 const char *src_file, uint src_line)
2206{
2207 PFS_mutex *pfs_mutex= reinterpret_cast<PFS_mutex*> (mutex);
2208 DBUG_ASSERT((int) op >= 0);
2209 DBUG_ASSERT((uint) op < array_elements(mutex_operation_map));
2210 DBUG_ASSERT(state != NULL);
2211
2212 DBUG_ASSERT(pfs_mutex != NULL);
2213 DBUG_ASSERT(pfs_mutex->m_class != NULL);
2214
2215 if (! pfs_mutex->m_enabled)
2216 return NULL;
2217
2218 uint flags;
2219 ulonglong timer_start= 0;
2220
2221 if (flag_thread_instrumentation)
2222 {
2223 PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2224 if (unlikely(pfs_thread == NULL))
2225 return NULL;
2226 if (! pfs_thread->m_enabled)
2227 return NULL;
2228 state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
2229 flags= STATE_FLAG_THREAD;
2230
2231 if (pfs_mutex->m_timed)
2232 {
2233 timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2234 state->m_timer_start= timer_start;
2235 flags|= STATE_FLAG_TIMED;
2236 }
2237
2238 if (flag_events_waits_current)
2239 {
2240 if (unlikely(pfs_thread->m_events_waits_current >=
2241 & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
2242 {
2243 locker_lost++;
2244 return NULL;
2245 }
2246 PFS_events_waits *wait= pfs_thread->m_events_waits_current;
2247 state->m_wait= wait;
2248 flags|= STATE_FLAG_EVENT;
2249
2250 PFS_events_waits *parent_event= wait - 1;
2251 wait->m_event_type= EVENT_TYPE_WAIT;
2252 wait->m_nesting_event_id= parent_event->m_event_id;
2253 wait->m_nesting_event_type= parent_event->m_event_type;
2254
2255 wait->m_thread= pfs_thread;
2256 wait->m_class= pfs_mutex->m_class;
2257 wait->m_timer_start= timer_start;
2258 wait->m_timer_end= 0;
2259 wait->m_object_instance_addr= pfs_mutex->m_identity;
2260 wait->m_event_id= pfs_thread->m_event_id++;
2261 wait->m_end_event_id= 0;
2262 wait->m_operation= mutex_operation_map[(int) op];
2263 wait->m_source_file= src_file;
2264 wait->m_source_line= src_line;
2265 wait->m_wait_class= WAIT_CLASS_MUTEX;
2266
2267 pfs_thread->m_events_waits_current++;
2268 }
2269 }
2270 else
2271 {
2272 if (pfs_mutex->m_timed)
2273 {
2274 timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2275 state->m_timer_start= timer_start;
2276 flags= STATE_FLAG_TIMED;
2277 state->m_thread= NULL;
2278 }
2279 else
2280 {
2281 /*
2282 Complete shortcut.
2283 */
2284 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
2285 pfs_mutex->m_mutex_stat.m_wait_stat.aggregate_counted();
2286 return NULL;
2287 }
2288 }
2289
2290 state->m_flags= flags;
2291 state->m_mutex= mutex;
2292 return reinterpret_cast<PSI_mutex_locker*> (state);
2293}
2294
2295/**
2296 Implementation of the rwlock instrumentation interface.
2297 @sa PSI_v1::start_rwlock_rdwait
2298 @sa PSI_v1::start_rwlock_wrwait
2299*/
2300static PSI_rwlock_locker*
2301start_rwlock_wait_v1(PSI_rwlock_locker_state *state,
2302 PSI_rwlock *rwlock,
2303 PSI_rwlock_operation op,
2304 const char *src_file, uint src_line)
2305{
2306 PFS_rwlock *pfs_rwlock= reinterpret_cast<PFS_rwlock*> (rwlock);
2307 DBUG_ASSERT(static_cast<int> (op) >= 0);
2308 DBUG_ASSERT(static_cast<uint> (op) < array_elements(rwlock_operation_map));
2309 DBUG_ASSERT(state != NULL);
2310 DBUG_ASSERT(pfs_rwlock != NULL);
2311 DBUG_ASSERT(pfs_rwlock->m_class != NULL);
2312
2313 if (! pfs_rwlock->m_enabled)
2314 return NULL;
2315
2316 uint flags;
2317 ulonglong timer_start= 0;
2318
2319 if (flag_thread_instrumentation)
2320 {
2321 PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2322 if (unlikely(pfs_thread == NULL))
2323 return NULL;
2324 if (! pfs_thread->m_enabled)
2325 return NULL;
2326 state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
2327 flags= STATE_FLAG_THREAD;
2328
2329 if (pfs_rwlock->m_timed)
2330 {
2331 timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2332 state->m_timer_start= timer_start;
2333 flags|= STATE_FLAG_TIMED;
2334 }
2335
2336 if (flag_events_waits_current)
2337 {
2338 if (unlikely(pfs_thread->m_events_waits_current >=
2339 & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
2340 {
2341 locker_lost++;
2342 return NULL;
2343 }
2344 PFS_events_waits *wait= pfs_thread->m_events_waits_current;
2345 state->m_wait= wait;
2346 flags|= STATE_FLAG_EVENT;
2347
2348 PFS_events_waits *parent_event= wait - 1;
2349 wait->m_event_type= EVENT_TYPE_WAIT;
2350 wait->m_nesting_event_id= parent_event->m_event_id;
2351 wait->m_nesting_event_type= parent_event->m_event_type;
2352
2353 wait->m_thread= pfs_thread;
2354 wait->m_class= pfs_rwlock->m_class;
2355 wait->m_timer_start= timer_start;
2356 wait->m_timer_end= 0;
2357 wait->m_object_instance_addr= pfs_rwlock->m_identity;
2358 wait->m_event_id= pfs_thread->m_event_id++;
2359 wait->m_end_event_id= 0;
2360 wait->m_operation= rwlock_operation_map[static_cast<int> (op)];
2361 wait->m_source_file= src_file;
2362 wait->m_source_line= src_line;
2363 wait->m_wait_class= WAIT_CLASS_RWLOCK;
2364
2365 pfs_thread->m_events_waits_current++;
2366 }
2367 }
2368 else
2369 {
2370 if (pfs_rwlock->m_timed)
2371 {
2372 timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2373 state->m_timer_start= timer_start;
2374 flags= STATE_FLAG_TIMED;
2375 state->m_thread= NULL;
2376 }
2377 else
2378 {
2379 /*
2380 Complete shortcut.
2381 */
2382 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
2383 pfs_rwlock->m_rwlock_stat.m_wait_stat.aggregate_counted();
2384 return NULL;
2385 }
2386 }
2387
2388 state->m_flags= flags;
2389 state->m_rwlock= rwlock;
2390 return reinterpret_cast<PSI_rwlock_locker*> (state);
2391}
2392
2393/**
2394 Implementation of the cond instrumentation interface.
2395 @sa PSI_v1::start_cond_wait.
2396*/
2397static PSI_cond_locker*
2398start_cond_wait_v1(PSI_cond_locker_state *state,
2399 PSI_cond *cond, PSI_mutex *mutex,
2400 PSI_cond_operation op,
2401 const char *src_file, uint src_line)
2402{
2403 /*
2404 Note about the unused PSI_mutex *mutex parameter:
2405 In the pthread library, a call to pthread_cond_wait()
2406 causes an unlock() + lock() on the mutex associated with the condition.
2407 This mutex operation is not instrumented, so the mutex will still
2408 appear as locked when a thread is waiting on a condition.
2409 This has no impact now, as unlock_mutex() is not recording events.
2410 When unlock_mutex() is implemented by later work logs,
2411 this parameter here will be used to adjust the mutex state,
2412 in start_cond_wait_v1() and end_cond_wait_v1().
2413 */
2414 PFS_cond *pfs_cond= reinterpret_cast<PFS_cond*> (cond);
2415 DBUG_ASSERT(static_cast<int> (op) >= 0);
2416 DBUG_ASSERT(static_cast<uint> (op) < array_elements(cond_operation_map));
2417 DBUG_ASSERT(state != NULL);
2418 DBUG_ASSERT(pfs_cond != NULL);
2419 DBUG_ASSERT(pfs_cond->m_class != NULL);
2420
2421 if (! pfs_cond->m_enabled)
2422 return NULL;
2423
2424 uint flags;
2425 ulonglong timer_start= 0;
2426
2427 if (flag_thread_instrumentation)
2428 {
2429 PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2430 if (unlikely(pfs_thread == NULL))
2431 return NULL;
2432 if (! pfs_thread->m_enabled)
2433 return NULL;
2434 state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
2435 flags= STATE_FLAG_THREAD;
2436
2437 if (pfs_cond->m_timed)
2438 {
2439 timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2440 state->m_timer_start= timer_start;
2441 flags|= STATE_FLAG_TIMED;
2442 }
2443
2444 if (flag_events_waits_current)
2445 {
2446 if (unlikely(pfs_thread->m_events_waits_current >=
2447 & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
2448 {
2449 locker_lost++;
2450 return NULL;
2451 }
2452 PFS_events_waits *wait= pfs_thread->m_events_waits_current;
2453 state->m_wait= wait;
2454 flags|= STATE_FLAG_EVENT;
2455
2456 PFS_events_waits *parent_event= wait - 1;
2457 wait->m_event_type= EVENT_TYPE_WAIT;
2458 wait->m_nesting_event_id= parent_event->m_event_id;
2459 wait->m_nesting_event_type= parent_event->m_event_type;
2460
2461 wait->m_thread= pfs_thread;
2462 wait->m_class= pfs_cond->m_class;
2463 wait->m_timer_start= timer_start;
2464 wait->m_timer_end= 0;
2465 wait->m_object_instance_addr= pfs_cond->m_identity;
2466 wait->m_event_id= pfs_thread->m_event_id++;
2467 wait->m_end_event_id= 0;
2468 wait->m_operation= cond_operation_map[static_cast<int> (op)];
2469 wait->m_source_file= src_file;
2470 wait->m_source_line= src_line;
2471 wait->m_wait_class= WAIT_CLASS_COND;
2472
2473 pfs_thread->m_events_waits_current++;
2474 }
2475 }
2476 else
2477 {
2478 if (pfs_cond->m_timed)
2479 {
2480 timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2481 state->m_timer_start= timer_start;
2482 flags= STATE_FLAG_TIMED;
2483 }
2484 else
2485 {
2486 /*
2487 Complete shortcut.
2488 */
2489 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
2490 pfs_cond->m_cond_stat.m_wait_stat.aggregate_counted();
2491 return NULL;
2492 }
2493 }
2494
2495 state->m_flags= flags;
2496 state->m_cond= cond;
2497 state->m_mutex= mutex;
2498 return reinterpret_cast<PSI_cond_locker*> (state);
2499}
2500
2501static inline PFS_TL_LOCK_TYPE lock_flags_to_lock_type(uint flags)
2502{
2503 enum thr_lock_type value= static_cast<enum thr_lock_type> (flags);
2504
2505 switch (value)
2506 {
2507 case TL_READ:
2508 return PFS_TL_READ;
2509 case TL_READ_WITH_SHARED_LOCKS:
2510 return PFS_TL_READ_WITH_SHARED_LOCKS;
2511 case TL_READ_HIGH_PRIORITY:
2512 return PFS_TL_READ_HIGH_PRIORITY;
2513 case TL_READ_NO_INSERT:
2514 return PFS_TL_READ_NO_INSERT;
2515 case TL_WRITE_ALLOW_WRITE:
2516 return PFS_TL_WRITE_ALLOW_WRITE;
2517 case TL_WRITE_CONCURRENT_INSERT:
2518 return PFS_TL_WRITE_CONCURRENT_INSERT;
2519 case TL_WRITE_DELAYED:
2520 return PFS_TL_WRITE_DELAYED;
2521 case TL_WRITE_LOW_PRIORITY:
2522 return PFS_TL_WRITE_LOW_PRIORITY;
2523 case TL_WRITE:
2524 return PFS_TL_WRITE;
2525
2526 case TL_WRITE_ONLY:
2527 case TL_IGNORE:
2528 case TL_UNLOCK:
2529 case TL_READ_DEFAULT:
2530 case TL_WRITE_DEFAULT:
2531 default:
2532 DBUG_ASSERT(false);
2533 }
2534
2535 /* Dead code */
2536 return PFS_TL_READ;
2537}
2538
2539static inline PFS_TL_LOCK_TYPE external_lock_flags_to_lock_type(uint flags)
2540{
2541 DBUG_ASSERT(flags == F_RDLCK || flags == F_WRLCK);
2542 return (flags == F_RDLCK ? PFS_TL_READ_EXTERNAL : PFS_TL_WRITE_EXTERNAL);
2543}
2544
2545/**
2546 Implementation of the table instrumentation interface.
2547 @sa PSI_v1::start_table_io_wait_v1
2548*/
2549static PSI_table_locker*
2550start_table_io_wait_v1(PSI_table_locker_state *state,
2551 PSI_table *table,
2552 PSI_table_io_operation op,
2553 uint index,
2554 const char *src_file, uint src_line)
2555{
2556 DBUG_ASSERT(static_cast<int> (op) >= 0);
2557 DBUG_ASSERT(static_cast<uint> (op) < array_elements(table_io_operation_map));
2558 DBUG_ASSERT(state != NULL);
2559 PFS_table *pfs_table= reinterpret_cast<PFS_table*> (table);
2560 DBUG_ASSERT(pfs_table != NULL);
2561 DBUG_ASSERT(pfs_table->m_share != NULL);
2562
2563 if (! pfs_table->m_io_enabled)
2564 return NULL;
2565
2566 PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2567
2568 uint flags;
2569 ulonglong timer_start= 0;
2570
2571 if (flag_thread_instrumentation)
2572 {
2573 if (pfs_thread == NULL)
2574 return NULL;
2575 if (! pfs_thread->m_enabled)
2576 return NULL;
2577 state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
2578 flags= STATE_FLAG_THREAD;
2579
2580 if (pfs_table->m_io_timed)
2581 {
2582 timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2583 state->m_timer_start= timer_start;
2584 flags|= STATE_FLAG_TIMED;
2585 }
2586
2587 if (flag_events_waits_current)
2588 {
2589 if (unlikely(pfs_thread->m_events_waits_current >=
2590 & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
2591 {
2592 locker_lost++;
2593 return NULL;
2594 }
2595 PFS_events_waits *wait= pfs_thread->m_events_waits_current;
2596 state->m_wait= wait;
2597 flags|= STATE_FLAG_EVENT;
2598
2599 PFS_events_waits *parent_event= wait - 1;
2600 wait->m_event_type= EVENT_TYPE_WAIT;
2601 wait->m_nesting_event_id= parent_event->m_event_id;
2602 wait->m_nesting_event_type= parent_event->m_event_type;
2603
2604 PFS_table_share *share= pfs_table->m_share;
2605 wait->m_thread= pfs_thread;
2606 wait->m_class= &global_table_io_class;
2607 wait->m_timer_start= timer_start;
2608 wait->m_timer_end= 0;
2609 wait->m_object_instance_addr= pfs_table->m_identity;
2610 wait->m_event_id= pfs_thread->m_event_id++;
2611 wait->m_end_event_id= 0;
2612 wait->m_operation= table_io_operation_map[static_cast<int> (op)];
2613 wait->m_flags= 0;
2614 wait->m_object_type= share->get_object_type();
2615 wait->m_weak_table_share= share;
2616 wait->m_weak_version= share->get_version();
2617 wait->m_index= index;
2618 wait->m_source_file= src_file;
2619 wait->m_source_line= src_line;
2620 wait->m_wait_class= WAIT_CLASS_TABLE;
2621
2622 pfs_thread->m_events_waits_current++;
2623 }
2624 }
2625 else
2626 {
2627 if (pfs_table->m_io_timed)
2628 {
2629 timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2630 state->m_timer_start= timer_start;
2631 flags= STATE_FLAG_TIMED;
2632 }
2633 else
2634 {
2635 /* TODO: consider a shortcut here */
2636 flags= 0;
2637 }
2638 }
2639
2640 state->m_flags= flags;
2641 state->m_table= table;
2642 state->m_io_operation= op;
2643 state->m_index= index;
2644 return reinterpret_cast<PSI_table_locker*> (state);
2645}
2646
2647/**
2648 Implementation of the table instrumentation interface.
2649 @sa PSI_v1::start_table_lock_wait.
2650*/
2651static PSI_table_locker*
2652start_table_lock_wait_v1(PSI_table_locker_state *state,
2653 PSI_table *table,
2654 PSI_table_lock_operation op,
2655 ulong op_flags,
2656 const char *src_file, uint src_line)
2657{
2658 DBUG_ASSERT(state != NULL);
2659 DBUG_ASSERT((op == PSI_TABLE_LOCK) || (op == PSI_TABLE_EXTERNAL_LOCK));
2660
2661 PFS_table *pfs_table= reinterpret_cast<PFS_table*> (table);
2662
2663 DBUG_ASSERT(pfs_table != NULL);
2664 DBUG_ASSERT(pfs_table->m_share != NULL);
2665
2666 if (! pfs_table->m_lock_enabled)
2667 return NULL;
2668
2669 PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2670
2671 PFS_TL_LOCK_TYPE lock_type;
2672
2673 switch (op)
2674 {
2675 case PSI_TABLE_LOCK:
2676 lock_type= lock_flags_to_lock_type(op_flags);
2677 break;
2678 case PSI_TABLE_EXTERNAL_LOCK:
2679 /*
2680 See the handler::external_lock() API design,
2681 there is no handler::external_unlock().
2682 */
2683 if (op_flags == F_UNLCK)
2684 return NULL;
2685 lock_type= external_lock_flags_to_lock_type(op_flags);
2686 break;
2687 default:
2688 lock_type= PFS_TL_READ;
2689 DBUG_ASSERT(false);
2690 }
2691
2692 DBUG_ASSERT((uint) lock_type < array_elements(table_lock_operation_map));
2693
2694 uint flags;
2695 ulonglong timer_start= 0;
2696
2697 if (flag_thread_instrumentation)
2698 {
2699 if (pfs_thread == NULL)
2700 return NULL;
2701 if (! pfs_thread->m_enabled)
2702 return NULL;
2703 state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
2704 flags= STATE_FLAG_THREAD;
2705
2706 if (pfs_table->m_lock_timed)
2707 {
2708 timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2709 state->m_timer_start= timer_start;
2710 flags|= STATE_FLAG_TIMED;
2711 }
2712
2713 if (flag_events_waits_current)
2714 {
2715 if (unlikely(pfs_thread->m_events_waits_current >=
2716 & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
2717 {
2718 locker_lost++;
2719 return NULL;
2720 }
2721 PFS_events_waits *wait= pfs_thread->m_events_waits_current;
2722 state->m_wait= wait;
2723 flags|= STATE_FLAG_EVENT;
2724
2725 PFS_events_waits *parent_event= wait - 1;
2726 wait->m_event_type= EVENT_TYPE_WAIT;
2727 wait->m_nesting_event_id= parent_event->m_event_id;
2728 wait->m_nesting_event_type= parent_event->m_event_type;
2729
2730 PFS_table_share *share= pfs_table->m_share;
2731 wait->m_thread= pfs_thread;
2732 wait->m_class= &global_table_lock_class;
2733 wait->m_timer_start= timer_start;
2734 wait->m_timer_end= 0;
2735 wait->m_object_instance_addr= pfs_table->m_identity;
2736 wait->m_event_id= pfs_thread->m_event_id++;
2737 wait->m_end_event_id= 0;
2738 wait->m_operation= table_lock_operation_map[lock_type];
2739 wait->m_flags= 0;
2740 wait->m_object_type= share->get_object_type();
2741 wait->m_weak_table_share= share;
2742 wait->m_weak_version= share->get_version();
2743 wait->m_index= 0;
2744 wait->m_source_file= src_file;
2745 wait->m_source_line= src_line;
2746 wait->m_wait_class= WAIT_CLASS_TABLE;
2747
2748 pfs_thread->m_events_waits_current++;
2749 }
2750 }
2751 else
2752 {
2753 if (pfs_table->m_lock_timed)
2754 {
2755 timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
2756 state->m_timer_start= timer_start;
2757 flags= STATE_FLAG_TIMED;
2758 }
2759 else
2760 {
2761 /* TODO: consider a shortcut here */
2762 flags= 0;
2763 }
2764 }
2765
2766 state->m_flags= flags;
2767 state->m_table= table;
2768 state->m_index= lock_type;
2769 return reinterpret_cast<PSI_table_locker*> (state);
2770}
2771
2772/**
2773 Implementation of the file instrumentation interface.
2774 @sa PSI_v1::get_thread_file_name_locker.
2775*/
2776static PSI_file_locker*
2777get_thread_file_name_locker_v1(PSI_file_locker_state *state,
2778 PSI_file_key key,
2779 PSI_file_operation op,
2780 const char *name, const void *identity)
2781{
2782 DBUG_ASSERT(static_cast<int> (op) >= 0);
2783 DBUG_ASSERT(static_cast<uint> (op) < array_elements(file_operation_map));
2784 DBUG_ASSERT(state != NULL);
2785
2786 if (psi_unlikely(! flag_global_instrumentation))
2787 return NULL;
2788 PFS_file_class *klass= find_file_class(key);
2789 if (unlikely(klass == NULL))
2790 return NULL;
2791 if (! klass->m_enabled)
2792 return NULL;
2793
2794 /* Needed for the LF_HASH */
2795 PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2796 if (unlikely(pfs_thread == NULL))
2797 return NULL;
2798
2799 if (flag_thread_instrumentation && ! pfs_thread->m_enabled)
2800 return NULL;
2801
2802 uint flags;
2803
2804 state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
2805 flags= STATE_FLAG_THREAD;
2806
2807 if (klass->m_timed)
2808 flags|= STATE_FLAG_TIMED;
2809
2810 if (flag_events_waits_current)
2811 {
2812 if (unlikely(pfs_thread->m_events_waits_current >=
2813 & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
2814 {
2815 locker_lost++;
2816 return NULL;
2817 }
2818 PFS_events_waits *wait= pfs_thread->m_events_waits_current;
2819 state->m_wait= wait;
2820 flags|= STATE_FLAG_EVENT;
2821
2822 PFS_events_waits *parent_event= wait - 1;
2823 wait->m_event_type= EVENT_TYPE_WAIT;
2824 wait->m_nesting_event_id= parent_event->m_event_id;
2825 wait->m_nesting_event_type= parent_event->m_event_type;
2826
2827 wait->m_thread= pfs_thread;
2828 wait->m_class= klass;
2829 wait->m_timer_start= 0;
2830 wait->m_timer_end= 0;
2831 wait->m_object_instance_addr= NULL;
2832 wait->m_weak_file= NULL;
2833 wait->m_weak_version= 0;
2834 wait->m_event_id= pfs_thread->m_event_id++;
2835 wait->m_end_event_id= 0;
2836 wait->m_operation= file_operation_map[static_cast<int> (op)];
2837 wait->m_wait_class= WAIT_CLASS_FILE;
2838
2839 pfs_thread->m_events_waits_current++;
2840 }
2841
2842 state->m_flags= flags;
2843 state->m_file= NULL;
2844 state->m_name= name;
2845 state->m_class= klass;
2846 state->m_operation= op;
2847 return reinterpret_cast<PSI_file_locker*> (state);
2848}
2849
2850/**
2851 Implementation of the file instrumentation interface.
2852 @sa PSI_v1::get_thread_file_stream_locker.
2853*/
2854static PSI_file_locker*
2855get_thread_file_stream_locker_v1(PSI_file_locker_state *state,
2856 PSI_file *file, PSI_file_operation op)
2857{
2858 PFS_file *pfs_file= reinterpret_cast<PFS_file*> (file);
2859 DBUG_ASSERT(static_cast<int> (op) >= 0);
2860 DBUG_ASSERT(static_cast<uint> (op) < array_elements(file_operation_map));
2861 DBUG_ASSERT(state != NULL);
2862
2863 if (unlikely(pfs_file == NULL))
2864 return NULL;
2865 DBUG_ASSERT(pfs_file->m_class != NULL);
2866 PFS_file_class *klass= pfs_file->m_class;
2867
2868 if (! pfs_file->m_enabled)
2869 return NULL;
2870
2871 uint flags;
2872
2873 if (flag_thread_instrumentation)
2874 {
2875 PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2876 if (unlikely(pfs_thread == NULL))
2877 return NULL;
2878 if (! pfs_thread->m_enabled)
2879 return NULL;
2880 state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
2881 flags= STATE_FLAG_THREAD;
2882
2883 if (pfs_file->m_timed)
2884 flags|= STATE_FLAG_TIMED;
2885
2886 if (flag_events_waits_current)
2887 {
2888 if (unlikely(pfs_thread->m_events_waits_current >=
2889 & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
2890 {
2891 locker_lost++;
2892 return NULL;
2893 }
2894 PFS_events_waits *wait= pfs_thread->m_events_waits_current;
2895 state->m_wait= wait;
2896 flags|= STATE_FLAG_EVENT;
2897
2898 PFS_events_waits *parent_event= wait - 1;
2899 wait->m_event_type= EVENT_TYPE_WAIT;
2900 wait->m_nesting_event_id= parent_event->m_event_id;
2901 wait->m_nesting_event_type= parent_event->m_event_type;
2902
2903 wait->m_thread= pfs_thread;
2904 wait->m_class= klass;
2905 wait->m_timer_start= 0;
2906 wait->m_timer_end= 0;
2907 wait->m_object_instance_addr= pfs_file;
2908 wait->m_weak_file= pfs_file;
2909 wait->m_weak_version= pfs_file->get_version();
2910 wait->m_event_id= pfs_thread->m_event_id++;
2911 wait->m_end_event_id= 0;
2912 wait->m_operation= file_operation_map[static_cast<int> (op)];
2913 wait->m_wait_class= WAIT_CLASS_FILE;
2914
2915 pfs_thread->m_events_waits_current++;
2916 }
2917 }
2918 else
2919 {
2920 state->m_thread= NULL;
2921 if (pfs_file->m_timed)
2922 {
2923 flags= STATE_FLAG_TIMED;
2924 }
2925 else
2926 {
2927 /* TODO: consider a shortcut. */
2928 flags= 0;
2929 }
2930 }
2931
2932 state->m_flags= flags;
2933 state->m_file= reinterpret_cast<PSI_file*> (pfs_file);
2934 state->m_operation= op;
2935 state->m_name= NULL;
2936 state->m_class= klass;
2937 return reinterpret_cast<PSI_file_locker*> (state);
2938}
2939
2940/**
2941 Implementation of the file instrumentation interface.
2942 @sa PSI_v1::get_thread_file_descriptor_locker.
2943*/
2944static PSI_file_locker*
2945get_thread_file_descriptor_locker_v1(PSI_file_locker_state *state,
2946 File file, PSI_file_operation op)
2947{
2948 int index= static_cast<int> (file);
2949 DBUG_ASSERT(static_cast<int> (op) >= 0);
2950 DBUG_ASSERT(static_cast<uint> (op) < array_elements(file_operation_map));
2951 DBUG_ASSERT(state != NULL);
2952
2953 if (unlikely((index < 0) || (index >= file_handle_max)))
2954 return NULL;
2955
2956 PFS_file *pfs_file= file_handle_array[index];
2957 if (unlikely(pfs_file == NULL))
2958 return NULL;
2959
2960 /*
2961 We are about to close a file by descriptor number,
2962 and the calling code still holds the descriptor.
2963 Cleanup the file descriptor <--> file instrument association.
2964 Remove the instrumentation *before* the close to avoid race
2965 conditions with another thread opening a file
2966 (that could be given the same descriptor).
2967 */
2968 if (op == PSI_FILE_CLOSE)
2969 file_handle_array[index]= NULL;
2970
2971 if (! pfs_file->m_enabled)
2972 return NULL;
2973
2974 DBUG_ASSERT(pfs_file->m_class != NULL);
2975 PFS_file_class *klass= pfs_file->m_class;
2976
2977 uint flags;
2978
2979 if (flag_thread_instrumentation)
2980 {
2981 PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
2982 if (unlikely(pfs_thread == NULL))
2983 return NULL;
2984 if (! pfs_thread->m_enabled)
2985 return NULL;
2986 state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
2987 flags= STATE_FLAG_THREAD;
2988
2989 if (pfs_file->m_timed)
2990 flags|= STATE_FLAG_TIMED;
2991
2992 if (flag_events_waits_current)
2993 {
2994 if (unlikely(pfs_thread->m_events_waits_current >=
2995 & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
2996 {
2997 locker_lost++;
2998 return NULL;
2999 }
3000 PFS_events_waits *wait= pfs_thread->m_events_waits_current;
3001 state->m_wait= wait;
3002 flags|= STATE_FLAG_EVENT;
3003
3004 PFS_events_waits *parent_event= wait - 1;
3005 wait->m_event_type= EVENT_TYPE_WAIT;
3006 wait->m_nesting_event_id= parent_event->m_event_id;
3007 wait->m_nesting_event_type= parent_event->m_event_type;
3008
3009 wait->m_thread= pfs_thread;
3010 wait->m_class= klass;
3011 wait->m_timer_start= 0;
3012 wait->m_timer_end= 0;
3013 wait->m_object_instance_addr= pfs_file;
3014 wait->m_weak_file= pfs_file;
3015 wait->m_weak_version= pfs_file->get_version();
3016 wait->m_event_id= pfs_thread->m_event_id++;
3017 wait->m_end_event_id= 0;
3018 wait->m_operation= file_operation_map[static_cast<int> (op)];
3019 wait->m_wait_class= WAIT_CLASS_FILE;
3020
3021 pfs_thread->m_events_waits_current++;
3022 }
3023 }
3024 else
3025 {
3026 state->m_thread= NULL;
3027 if (pfs_file->m_timed)
3028 {
3029 flags= STATE_FLAG_TIMED;
3030 }
3031 else
3032 {
3033 /* TODO: consider a shortcut. */
3034 flags= 0;
3035 }
3036 }
3037
3038 state->m_flags= flags;
3039 state->m_file= reinterpret_cast<PSI_file*> (pfs_file);
3040 state->m_operation= op;
3041 state->m_name= NULL;
3042 state->m_class= klass;
3043 return reinterpret_cast<PSI_file_locker*> (state);
3044}
3045
3046/** Socket locker */
3047
3048static PSI_socket_locker*
3049start_socket_wait_v1(PSI_socket_locker_state *state,
3050 PSI_socket *socket,
3051 PSI_socket_operation op,
3052 size_t count,
3053 const char *src_file, uint src_line)
3054{
3055 DBUG_ASSERT(static_cast<int> (op) >= 0);
3056 DBUG_ASSERT(static_cast<uint> (op) < array_elements(socket_operation_map));
3057 DBUG_ASSERT(state != NULL);
3058 PFS_socket *pfs_socket= reinterpret_cast<PFS_socket*> (socket);
3059
3060 DBUG_ASSERT(pfs_socket != NULL);
3061 DBUG_ASSERT(pfs_socket->m_class != NULL);
3062
3063 if (!pfs_socket->m_enabled || pfs_socket->m_idle)
3064 return NULL;
3065
3066 uint flags= 0;
3067 ulonglong timer_start= 0;
3068
3069 if (flag_thread_instrumentation)
3070 {
3071 /*
3072 Do not use pfs_socket->m_thread_owner here,
3073 as different threads may use concurrently the same socket,
3074 for example during a KILL.
3075 */
3076 PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
3077
3078 if (unlikely(pfs_thread == NULL))
3079 return NULL;
3080
3081 if (!pfs_thread->m_enabled)
3082 return NULL;
3083
3084 state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
3085 flags= STATE_FLAG_THREAD;
3086
3087 if (pfs_socket->m_timed)
3088 {
3089 timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
3090 state->m_timer_start= timer_start;
3091 flags|= STATE_FLAG_TIMED;
3092 }
3093
3094 if (flag_events_waits_current)
3095 {
3096 if (unlikely(pfs_thread->m_events_waits_current >=
3097 & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
3098 {
3099 locker_lost++;
3100 return NULL;
3101 }
3102 PFS_events_waits *wait= pfs_thread->m_events_waits_current;
3103 state->m_wait= wait;
3104 flags|= STATE_FLAG_EVENT;
3105
3106 PFS_events_waits *parent_event= wait - 1;
3107 wait->m_event_type= EVENT_TYPE_WAIT;
3108 wait->m_nesting_event_id= parent_event->m_event_id;
3109 wait->m_nesting_event_type= parent_event->m_event_type;
3110 wait->m_thread= pfs_thread;
3111 wait->m_class= pfs_socket->m_class;
3112 wait->m_timer_start= timer_start;
3113 wait->m_timer_end= 0;
3114 wait->m_object_instance_addr= pfs_socket->m_identity;
3115 wait->m_weak_socket= pfs_socket;
3116 wait->m_weak_version= pfs_socket->get_version();
3117 wait->m_event_id= pfs_thread->m_event_id++;
3118 wait->m_end_event_id= 0;
3119 wait->m_operation= socket_operation_map[static_cast<int>(op)];
3120 wait->m_source_file= src_file;
3121 wait->m_source_line= src_line;
3122 wait->m_number_of_bytes= count;
3123 wait->m_wait_class= WAIT_CLASS_SOCKET;
3124
3125 pfs_thread->m_events_waits_current++;
3126 }
3127 }
3128 else
3129 {
3130 if (pfs_socket->m_timed)
3131 {
3132 timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
3133 state->m_timer_start= timer_start;
3134 flags= STATE_FLAG_TIMED;
3135 }
3136 else
3137 {
3138 /*
3139 Even if timing is disabled, end_socket_wait() still needs a locker to
3140 capture the number of bytes sent or received by the socket operation.
3141 For operations that do not have a byte count, then just increment the
3142 event counter and return a NULL locker.
3143 */
3144 switch (op)
3145 {
3146 case PSI_SOCKET_CONNECT:
3147 case PSI_SOCKET_CREATE:
3148 case PSI_SOCKET_BIND:
3149 case PSI_SOCKET_SEEK:
3150 case PSI_SOCKET_OPT:
3151 case PSI_SOCKET_STAT:
3152 case PSI_SOCKET_SHUTDOWN:
3153 case PSI_SOCKET_CLOSE:
3154 case PSI_SOCKET_SELECT:
3155 pfs_socket->m_socket_stat.m_io_stat.m_misc.aggregate_counted();
3156 return NULL;
3157 default:
3158 break;
3159 }
3160 }
3161 }
3162
3163 state->m_flags= flags;
3164 state->m_socket= socket;
3165 state->m_operation= op;
3166 return reinterpret_cast<PSI_socket_locker*> (state);
3167}
3168
3169/**
3170 Implementation of the mutex instrumentation interface.
3171 @sa PSI_v1::unlock_mutex.
3172*/
3173static void unlock_mutex_v1(PSI_mutex *mutex)
3174{
3175 PFS_mutex *pfs_mutex= reinterpret_cast<PFS_mutex*> (mutex);
3176
3177 DBUG_ASSERT(pfs_mutex != NULL);
3178
3179 /*
3180 Note that this code is still protected by the instrumented mutex,
3181 and therefore is thread safe. See inline_mysql_mutex_unlock().
3182 */
3183
3184 /* Always update the instrumented state */
3185 pfs_mutex->m_owner= NULL;
3186 pfs_mutex->m_last_locked= 0;
3187
3188#ifdef LATER_WL2333
3189 /*
3190 See WL#2333: SHOW ENGINE ... LOCK STATUS.
3191 PFS_mutex::m_lock_stat is not exposed in user visible tables
3192 currently, so there is no point spending time computing it.
3193 */
3194 if (! pfs_mutex->m_enabled)
3195 return;
3196
3197 if (! pfs_mutex->m_timed)
3198 return;
3199
3200 ulonglong locked_time;
3201 locked_time= get_timer_pico_value(wait_timer) - pfs_mutex->m_last_locked;
3202 pfs_mutex->m_mutex_stat.m_lock_stat.aggregate_value(locked_time);
3203#endif
3204}
3205
3206/**
3207 Implementation of the rwlock instrumentation interface.
3208 @sa PSI_v1::unlock_rwlock.
3209*/
3210static void unlock_rwlock_v1(PSI_rwlock *rwlock)
3211{
3212 PFS_rwlock *pfs_rwlock= reinterpret_cast<PFS_rwlock*> (rwlock);
3213 DBUG_ASSERT(pfs_rwlock != NULL);
3214 DBUG_ASSERT(pfs_rwlock == sanitize_rwlock(pfs_rwlock));
3215 DBUG_ASSERT(pfs_rwlock->m_class != NULL);
3216 DBUG_ASSERT(pfs_rwlock->m_lock.is_populated());
3217
3218 bool last_writer= false;
3219 bool last_reader= false;
3220
3221 /*
3222 Note that this code is still protected by the instrumented rwlock,
3223 and therefore is:
3224 - thread safe for write locks
3225 - almost thread safe for read locks (pfs_rwlock->m_readers is unsafe).
3226 See inline_mysql_rwlock_unlock()
3227 */
3228
3229 /* Always update the instrumented state */
3230 if (pfs_rwlock->m_writer != NULL)
3231 {
3232 /* Nominal case, a writer is unlocking. */
3233 last_writer= true;
3234 pfs_rwlock->m_writer= NULL;
3235 /* Reset the readers stats, they could be off */
3236 pfs_rwlock->m_readers= 0;
3237 }
3238 else if (likely(pfs_rwlock->m_readers > 0))
3239 {
3240 /* Nominal case, a reader is unlocking. */
3241 if (--(pfs_rwlock->m_readers) == 0)
3242 last_reader= true;
3243 }
3244 else
3245 {
3246 /*
3247 Edge case, we have no writer and no readers,
3248 on an unlock event.
3249 This is possible for:
3250 - partial instrumentation
3251 - instrumentation disabled at runtime,
3252 see when get_thread_rwlock_locker_v1() returns NULL
3253 No further action is taken here, the next
3254 write lock will put the statistics is a valid state.
3255 */
3256 }
3257
3258#ifdef LATER_WL2333
3259 /* See WL#2333: SHOW ENGINE ... LOCK STATUS. */
3260
3261 if (! pfs_rwlock->m_enabled)
3262 return;
3263
3264 if (! pfs_rwlock->m_timed)
3265 return;
3266
3267 ulonglong locked_time;
3268 if (last_writer)
3269 {
3270 locked_time= get_timer_pico_value(wait_timer) - pfs_rwlock->m_last_written;
3271 pfs_rwlock->m_rwlock_stat.m_write_lock_stat.aggregate_value(locked_time);
3272 }
3273 else if (last_reader)
3274 {
3275 locked_time= get_timer_pico_value(wait_timer) - pfs_rwlock->m_last_read;
3276 pfs_rwlock->m_rwlock_stat.m_read_lock_stat.aggregate_value(locked_time);
3277 }
3278#else
3279 (void) last_reader;
3280 (void) last_writer;
3281#endif
3282}
3283
3284/**
3285 Implementation of the cond instrumentation interface.
3286 @sa PSI_v1::signal_cond.
3287*/
3288static void signal_cond_v1(PSI_cond* cond)
3289{
3290 PFS_cond *pfs_cond= reinterpret_cast<PFS_cond*> (cond);
3291
3292 DBUG_ASSERT(pfs_cond != NULL);
3293
3294 pfs_cond->m_cond_stat.m_signal_count++;
3295}
3296
3297/**
3298 Implementation of the cond instrumentation interface.
3299 @sa PSI_v1::broadcast_cond.
3300*/
3301static void broadcast_cond_v1(PSI_cond* cond)
3302{
3303 PFS_cond *pfs_cond= reinterpret_cast<PFS_cond*> (cond);
3304
3305 DBUG_ASSERT(pfs_cond != NULL);
3306
3307 pfs_cond->m_cond_stat.m_broadcast_count++;
3308}
3309
3310/**
3311 Implementation of the idle instrumentation interface.
3312 @sa PSI_v1::start_idle_wait.
3313*/
3314static PSI_idle_locker*
3315start_idle_wait_v1(PSI_idle_locker_state* state, const char *src_file, uint src_line)
3316{
3317 DBUG_ASSERT(state != NULL);
3318
3319 if (psi_unlikely(! flag_global_instrumentation))
3320 return NULL;
3321
3322 if (!global_idle_class.m_enabled)
3323 return NULL;
3324
3325 uint flags= 0;
3326 ulonglong timer_start= 0;
3327
3328 if (flag_thread_instrumentation)
3329 {
3330 PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
3331 if (unlikely(pfs_thread == NULL))
3332 return NULL;
3333 if (!pfs_thread->m_enabled)
3334 return NULL;
3335 state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
3336 flags= STATE_FLAG_THREAD;
3337
3338 DBUG_ASSERT(pfs_thread->m_events_statements_count == 0);
3339
3340 if (global_idle_class.m_timed)
3341 {
3342 timer_start= get_timer_raw_value_and_function(idle_timer, &state->m_timer);
3343 state->m_timer_start= timer_start;
3344 flags|= STATE_FLAG_TIMED;
3345 }
3346
3347 if (flag_events_waits_current)
3348 {
3349 if (unlikely(pfs_thread->m_events_waits_current >=
3350 & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
3351 {
3352 locker_lost++;
3353 return NULL;
3354 }
3355 PFS_events_waits *wait= pfs_thread->m_events_waits_current;
3356 state->m_wait= wait;
3357 flags|= STATE_FLAG_EVENT;
3358
3359 wait->m_event_type= EVENT_TYPE_WAIT;
3360 /*
3361 IDLE events are waits, but by definition we know that
3362 such waits happen outside of any STAGE and STATEMENT,
3363 so they have no parents.
3364 */
3365 wait->m_nesting_event_id= 0;
3366 /* no need to set wait->m_nesting_event_type */
3367
3368 wait->m_thread= pfs_thread;
3369 wait->m_class= &global_idle_class;
3370 wait->m_timer_start= timer_start;
3371 wait->m_timer_end= 0;
3372 wait->m_event_id= pfs_thread->m_event_id++;
3373 wait->m_end_event_id= 0;
3374 wait->m_operation= OPERATION_TYPE_IDLE;
3375 wait->m_source_file= src_file;
3376 wait->m_source_line= src_line;
3377 wait->m_wait_class= WAIT_CLASS_IDLE;
3378
3379 pfs_thread->m_events_waits_current++;
3380 }
3381 }
3382 else
3383 {
3384 if (global_idle_class.m_timed)
3385 {
3386 timer_start= get_timer_raw_value_and_function(idle_timer, &state->m_timer);
3387 state->m_timer_start= timer_start;
3388 flags= STATE_FLAG_TIMED;
3389 }
3390 }
3391
3392 state->m_flags= flags;
3393 return reinterpret_cast<PSI_idle_locker*> (state);
3394}
3395
3396/**
3397 Implementation of the mutex instrumentation interface.
3398 @sa PSI_v1::end_idle_wait.
3399*/
3400static void end_idle_wait_v1(PSI_idle_locker* locker)
3401{
3402 PSI_idle_locker_state *state= reinterpret_cast<PSI_idle_locker_state*> (locker);
3403 DBUG_ASSERT(state != NULL);
3404 ulonglong timer_end= 0;
3405 ulonglong wait_time= 0;
3406
3407 uint flags= state->m_flags;
3408
3409 if (flags & STATE_FLAG_TIMED)
3410 {
3411 timer_end= state->m_timer();
3412 wait_time= timer_end - state->m_timer_start;
3413 }
3414
3415 if (flags & STATE_FLAG_THREAD)
3416 {
3417 PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
3418 PFS_single_stat *event_name_array;
3419 event_name_array= thread->m_instr_class_waits_stats;
3420
3421 if (flags & STATE_FLAG_TIMED)
3422 {
3423 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
3424 event_name_array[GLOBAL_IDLE_EVENT_INDEX].aggregate_value(wait_time);
3425 }
3426 else
3427 {
3428 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
3429 event_name_array[GLOBAL_IDLE_EVENT_INDEX].aggregate_counted();
3430 }
3431
3432 if (flags & STATE_FLAG_EVENT)
3433 {
3434 PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
3435 DBUG_ASSERT(wait != NULL);
3436
3437 wait->m_timer_end= timer_end;
3438 wait->m_end_event_id= thread->m_event_id;
3439 if (flag_events_waits_history)
3440 insert_events_waits_history(thread, wait);
3441 if (flag_events_waits_history_long)
3442 insert_events_waits_history_long(wait);
3443 thread->m_events_waits_current--;
3444
3445 DBUG_ASSERT(wait == thread->m_events_waits_current);
3446 }
3447 }
3448
3449 if (flags & STATE_FLAG_TIMED)
3450 {
3451 /* Aggregate to EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME (timed) */
3452 global_idle_stat.aggregate_value(wait_time);
3453 }
3454 else
3455 {
3456 /* Aggregate to EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME (counted) */
3457 global_idle_stat.aggregate_counted();
3458 }
3459}
3460
3461/**
3462 Implementation of the mutex instrumentation interface.
3463 @sa PSI_v1::end_mutex_wait.
3464*/
3465static void end_mutex_wait_v1(PSI_mutex_locker* locker, int rc)
3466{
3467 PSI_mutex_locker_state *state= reinterpret_cast<PSI_mutex_locker_state*> (locker);
3468 DBUG_ASSERT(state != NULL);
3469
3470 ulonglong timer_end= 0;
3471 ulonglong wait_time= 0;
3472
3473 PFS_mutex *mutex= reinterpret_cast<PFS_mutex *> (state->m_mutex);
3474 DBUG_ASSERT(mutex != NULL);
3475 PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
3476
3477 uint flags= state->m_flags;
3478
3479 if (flags & STATE_FLAG_TIMED)
3480 {
3481 timer_end= state->m_timer();
3482 wait_time= timer_end - state->m_timer_start;
3483 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */
3484 mutex->m_mutex_stat.m_wait_stat.aggregate_value(wait_time);
3485 }
3486 else
3487 {
3488 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
3489 mutex->m_mutex_stat.m_wait_stat.aggregate_counted();
3490 }
3491
3492 if (likely(rc == 0))
3493 {
3494 mutex->m_owner= thread;
3495 mutex->m_last_locked= timer_end;
3496 }
3497
3498 if (flags & STATE_FLAG_THREAD)
3499 {
3500 PFS_single_stat *event_name_array;
3501 event_name_array= thread->m_instr_class_waits_stats;
3502 uint index= mutex->m_class->m_event_name_index;
3503
3504 if (flags & STATE_FLAG_TIMED)
3505 {
3506 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
3507 event_name_array[index].aggregate_value(wait_time);
3508 }
3509 else
3510 {
3511 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
3512 event_name_array[index].aggregate_counted();
3513 }
3514
3515 if (flags & STATE_FLAG_EVENT)
3516 {
3517 PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
3518 DBUG_ASSERT(wait != NULL);
3519
3520 wait->m_timer_end= timer_end;
3521 wait->m_end_event_id= thread->m_event_id;
3522 if (flag_events_waits_history)
3523 insert_events_waits_history(thread, wait);
3524 if (flag_events_waits_history_long)
3525 insert_events_waits_history_long(wait);
3526 thread->m_events_waits_current--;
3527
3528 DBUG_ASSERT(wait == thread->m_events_waits_current);
3529 }
3530 }
3531}
3532
3533/**
3534 Implementation of the rwlock instrumentation interface.
3535 @sa PSI_v1::end_rwlock_rdwait.
3536*/
3537static void end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc)
3538{
3539 PSI_rwlock_locker_state *state= reinterpret_cast<PSI_rwlock_locker_state*> (locker);
3540 DBUG_ASSERT(state != NULL);
3541
3542 ulonglong timer_end= 0;
3543 ulonglong wait_time= 0;
3544
3545 PFS_rwlock *rwlock= reinterpret_cast<PFS_rwlock *> (state->m_rwlock);
3546 DBUG_ASSERT(rwlock != NULL);
3547
3548 if (state->m_flags & STATE_FLAG_TIMED)
3549 {
3550 timer_end= state->m_timer();
3551 wait_time= timer_end - state->m_timer_start;
3552 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */
3553 rwlock->m_rwlock_stat.m_wait_stat.aggregate_value(wait_time);
3554 }
3555 else
3556 {
3557 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
3558 rwlock->m_rwlock_stat.m_wait_stat.aggregate_counted();
3559 }
3560
3561 if (rc == 0)
3562 {
3563 /*
3564 Warning:
3565 Multiple threads can execute this section concurrently
3566 (since multiple readers can execute in parallel).
3567 The statistics generated are not safe, which is why they are
3568 just statistics, not facts.
3569 */
3570 if (rwlock->m_readers == 0)
3571 rwlock->m_last_read= timer_end;
3572 rwlock->m_writer= NULL;
3573 rwlock->m_readers++;
3574 }
3575
3576 if (state->m_flags & STATE_FLAG_THREAD)
3577 {
3578 PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
3579 DBUG_ASSERT(thread != NULL);
3580
3581 PFS_single_stat *event_name_array;
3582 event_name_array= thread->m_instr_class_waits_stats;
3583 uint index= rwlock->m_class->m_event_name_index;
3584
3585 if (state->m_flags & STATE_FLAG_TIMED)
3586 {
3587 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
3588 event_name_array[index].aggregate_value(wait_time);
3589 }
3590 else
3591 {
3592 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
3593 event_name_array[index].aggregate_counted();
3594 }
3595
3596 if (state->m_flags & STATE_FLAG_EVENT)
3597 {
3598 PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
3599 DBUG_ASSERT(wait != NULL);
3600
3601 wait->m_timer_end= timer_end;
3602 wait->m_end_event_id= thread->m_event_id;
3603 if (flag_events_waits_history)
3604 insert_events_waits_history(thread, wait);
3605 if (flag_events_waits_history_long)
3606 insert_events_waits_history_long(wait);
3607 thread->m_events_waits_current--;
3608
3609 DBUG_ASSERT(wait == thread->m_events_waits_current);
3610 }
3611 }
3612}
3613
3614/**
3615 Implementation of the rwlock instrumentation interface.
3616 @sa PSI_v1::end_rwlock_wrwait.
3617*/
3618static void end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc)
3619{
3620 PSI_rwlock_locker_state *state= reinterpret_cast<PSI_rwlock_locker_state*> (locker);
3621 DBUG_ASSERT(state != NULL);
3622
3623 ulonglong timer_end= 0;
3624 ulonglong wait_time= 0;
3625
3626 PFS_rwlock *rwlock= reinterpret_cast<PFS_rwlock *> (state->m_rwlock);
3627 DBUG_ASSERT(rwlock != NULL);
3628 PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
3629
3630 if (state->m_flags & STATE_FLAG_TIMED)
3631 {
3632 timer_end= state->m_timer();
3633 wait_time= timer_end - state->m_timer_start;
3634 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */
3635 rwlock->m_rwlock_stat.m_wait_stat.aggregate_value(wait_time);
3636 }
3637 else
3638 {
3639 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
3640 rwlock->m_rwlock_stat.m_wait_stat.aggregate_counted();
3641 }
3642
3643 if (likely(rc == 0))
3644 {
3645 /* Thread safe : we are protected by the instrumented rwlock */
3646 rwlock->m_writer= thread;
3647 rwlock->m_last_written= timer_end;
3648 /* Reset the readers stats, they could be off */
3649 rwlock->m_readers= 0;
3650 rwlock->m_last_read= 0;
3651 }
3652
3653 if (state->m_flags & STATE_FLAG_THREAD)
3654 {
3655 PFS_single_stat *event_name_array;
3656 event_name_array= thread->m_instr_class_waits_stats;
3657 uint index= rwlock->m_class->m_event_name_index;
3658
3659 if (state->m_flags & STATE_FLAG_TIMED)
3660 {
3661 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
3662 event_name_array[index].aggregate_value(wait_time);
3663 }
3664 else
3665 {
3666 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
3667 event_name_array[index].aggregate_counted();
3668 }
3669
3670 if (state->m_flags & STATE_FLAG_EVENT)
3671 {
3672 PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
3673 DBUG_ASSERT(wait != NULL);
3674
3675 wait->m_timer_end= timer_end;
3676 wait->m_end_event_id= thread->m_event_id;
3677 if (flag_events_waits_history)
3678 insert_events_waits_history(thread, wait);
3679 if (flag_events_waits_history_long)
3680 insert_events_waits_history_long(wait);
3681 thread->m_events_waits_current--;
3682
3683 DBUG_ASSERT(wait == thread->m_events_waits_current);
3684 }
3685 }
3686}
3687
3688/**
3689 Implementation of the cond instrumentation interface.
3690 @sa PSI_v1::end_cond_wait.
3691*/
3692static void end_cond_wait_v1(PSI_cond_locker* locker, int rc)
3693{
3694 PSI_cond_locker_state *state= reinterpret_cast<PSI_cond_locker_state*> (locker);
3695 DBUG_ASSERT(state != NULL);
3696
3697 ulonglong timer_end= 0;
3698 ulonglong wait_time= 0;
3699
3700 PFS_cond *cond= reinterpret_cast<PFS_cond *> (state->m_cond);
3701 /* PFS_mutex *mutex= reinterpret_cast<PFS_mutex *> (state->m_mutex); */
3702
3703 if (state->m_flags & STATE_FLAG_TIMED)
3704 {
3705 timer_end= state->m_timer();
3706 wait_time= timer_end - state->m_timer_start;
3707 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */
3708 cond->m_cond_stat.m_wait_stat.aggregate_value(wait_time);
3709 }
3710 else
3711 {
3712 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
3713 cond->m_cond_stat.m_wait_stat.aggregate_counted();
3714 }
3715
3716 if (state->m_flags & STATE_FLAG_THREAD)
3717 {
3718 PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
3719 DBUG_ASSERT(thread != NULL);
3720
3721 PFS_single_stat *event_name_array;
3722 event_name_array= thread->m_instr_class_waits_stats;
3723 uint index= cond->m_class->m_event_name_index;
3724
3725 if (state->m_flags & STATE_FLAG_TIMED)
3726 {
3727 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
3728 event_name_array[index].aggregate_value(wait_time);
3729 }
3730 else
3731 {
3732 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
3733 event_name_array[index].aggregate_counted();
3734 }
3735
3736 if (state->m_flags & STATE_FLAG_EVENT)
3737 {
3738 PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
3739 DBUG_ASSERT(wait != NULL);
3740
3741 wait->m_timer_end= timer_end;
3742 wait->m_end_event_id= thread->m_event_id;
3743 if (flag_events_waits_history)
3744 insert_events_waits_history(thread, wait);
3745 if (flag_events_waits_history_long)
3746 insert_events_waits_history_long(wait);
3747 thread->m_events_waits_current--;
3748
3749 DBUG_ASSERT(wait == thread->m_events_waits_current);
3750 }
3751 }
3752}
3753
3754/**
3755 Implementation of the table instrumentation interface.
3756 @sa PSI_v1::end_table_io_wait.
3757*/
3758static void end_table_io_wait_v1(PSI_table_locker* locker)
3759{
3760 PSI_table_locker_state *state= reinterpret_cast<PSI_table_locker_state*> (locker);
3761 DBUG_ASSERT(state != NULL);
3762
3763 ulonglong timer_end= 0;
3764 ulonglong wait_time= 0;
3765
3766 PFS_table *table= reinterpret_cast<PFS_table *> (state->m_table);
3767 DBUG_ASSERT(table != NULL);
3768
3769 PFS_single_stat *stat;
3770 PFS_table_io_stat *table_io_stat;
3771
3772 DBUG_ASSERT((state->m_index < table->m_share->m_key_count) ||
3773 (state->m_index == MAX_INDEXES));
3774
3775 table_io_stat= & table->m_table_stat.m_index_stat[state->m_index];
3776 table_io_stat->m_has_data= true;
3777
3778 switch (state->m_io_operation)
3779 {
3780 case PSI_TABLE_FETCH_ROW:
3781 stat= & table_io_stat->m_fetch;
3782 break;
3783 case PSI_TABLE_WRITE_ROW:
3784 stat= & table_io_stat->m_insert;
3785 break;
3786 case PSI_TABLE_UPDATE_ROW:
3787 stat= & table_io_stat->m_update;
3788 break;
3789 case PSI_TABLE_DELETE_ROW:
3790 stat= & table_io_stat->m_delete;
3791 break;
3792 default:
3793 DBUG_ASSERT(false);
3794 stat= NULL;
3795 break;
3796 }
3797
3798 uint flags= state->m_flags;
3799
3800 if (flags & STATE_FLAG_TIMED)
3801 {
3802 timer_end= state->m_timer();
3803 wait_time= timer_end - state->m_timer_start;
3804 stat->aggregate_value(wait_time);
3805 }
3806 else
3807 {
3808 stat->aggregate_counted();
3809 }
3810
3811 if (flags & STATE_FLAG_THREAD)
3812 {
3813 PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
3814 DBUG_ASSERT(thread != NULL);
3815
3816 PFS_single_stat *event_name_array;
3817 event_name_array= thread->m_instr_class_waits_stats;
3818
3819 /*
3820 Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME
3821 (for wait/io/table/sql/handler)
3822 */
3823 if (flags & STATE_FLAG_TIMED)
3824 {
3825 event_name_array[GLOBAL_TABLE_IO_EVENT_INDEX].aggregate_value(wait_time);
3826 }
3827 else
3828 {
3829 event_name_array[GLOBAL_TABLE_IO_EVENT_INDEX].aggregate_counted();
3830 }
3831
3832 if (flags & STATE_FLAG_EVENT)
3833 {
3834 PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
3835 DBUG_ASSERT(wait != NULL);
3836
3837 wait->m_timer_end= timer_end;
3838 wait->m_end_event_id= thread->m_event_id;
3839 if (flag_events_waits_history)
3840 insert_events_waits_history(thread, wait);
3841 if (flag_events_waits_history_long)
3842 insert_events_waits_history_long(wait);
3843 thread->m_events_waits_current--;
3844
3845 DBUG_ASSERT(wait == thread->m_events_waits_current);
3846 }
3847 }
3848
3849 table->m_has_io_stats= true;
3850}
3851
3852/**
3853 Implementation of the table instrumentation interface.
3854 @sa PSI_v1::end_table_lock_wait.
3855*/
3856static void end_table_lock_wait_v1(PSI_table_locker* locker)
3857{
3858 PSI_table_locker_state *state= reinterpret_cast<PSI_table_locker_state*> (locker);
3859 DBUG_ASSERT(state != NULL);
3860
3861 ulonglong timer_end= 0;
3862 ulonglong wait_time= 0;
3863
3864 PFS_table *table= reinterpret_cast<PFS_table *> (state->m_table);
3865 DBUG_ASSERT(table != NULL);
3866
3867 PFS_single_stat *stat= & table->m_table_stat.m_lock_stat.m_stat[state->m_index];
3868
3869 uint flags= state->m_flags;
3870
3871 if (flags & STATE_FLAG_TIMED)
3872 {
3873 timer_end= state->m_timer();
3874 wait_time= timer_end - state->m_timer_start;
3875 stat->aggregate_value(wait_time);
3876 }
3877 else
3878 {
3879 stat->aggregate_counted();
3880 }
3881
3882 if (flags & STATE_FLAG_THREAD)
3883 {
3884 PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
3885 DBUG_ASSERT(thread != NULL);
3886
3887 PFS_single_stat *event_name_array;
3888 event_name_array= thread->m_instr_class_waits_stats;
3889
3890 /*
3891 Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME
3892 (for wait/lock/table/sql/handler)
3893 */
3894 if (flags & STATE_FLAG_TIMED)
3895 {
3896 event_name_array[GLOBAL_TABLE_LOCK_EVENT_INDEX].aggregate_value(wait_time);
3897 }
3898 else
3899 {
3900 event_name_array[GLOBAL_TABLE_LOCK_EVENT_INDEX].aggregate_counted();
3901 }
3902
3903 if (flags & STATE_FLAG_EVENT)
3904 {
3905 PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
3906 DBUG_ASSERT(wait != NULL);
3907
3908 wait->m_timer_end= timer_end;
3909 wait->m_end_event_id= thread->m_event_id;
3910 if (flag_events_waits_history)
3911 insert_events_waits_history(thread, wait);
3912 if (flag_events_waits_history_long)
3913 insert_events_waits_history_long(wait);
3914 thread->m_events_waits_current--;
3915
3916 DBUG_ASSERT(wait == thread->m_events_waits_current);
3917 }
3918 }
3919
3920 table->m_has_lock_stats= true;
3921}
3922
3923static void start_file_wait_v1(PSI_file_locker *locker,
3924 size_t count,
3925 const char *src_file,
3926 uint src_line);
3927
3928static void end_file_wait_v1(PSI_file_locker *locker,
3929 size_t count);
3930
3931/**
3932 Implementation of the file instrumentation interface.
3933 @sa PSI_v1::start_file_open_wait.
3934*/
3935static void start_file_open_wait_v1(PSI_file_locker *locker,
3936 const char *src_file,
3937 uint src_line)
3938{
3939 start_file_wait_v1(locker, 0, src_file, src_line);
3940
3941 return;
3942}
3943
3944/**
3945 Implementation of the file instrumentation interface.
3946 @sa PSI_v1::end_file_open_wait.
3947*/
3948static PSI_file* end_file_open_wait_v1(PSI_file_locker *locker,
3949 void *result)
3950{
3951 PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
3952 DBUG_ASSERT(state != NULL);
3953
3954 switch (state->m_operation)
3955 {
3956 case PSI_FILE_STAT:
3957 case PSI_FILE_RENAME:
3958 break;
3959 case PSI_FILE_STREAM_OPEN:
3960 case PSI_FILE_CREATE:
3961 case PSI_FILE_OPEN:
3962 if (result != NULL)
3963 {
3964 PFS_file_class *klass= reinterpret_cast<PFS_file_class*> (state->m_class);
3965 PFS_thread *thread= reinterpret_cast<PFS_thread*> (state->m_thread);
3966 const char *name= state->m_name;
3967 uint len= (uint)strlen(name);
3968 PFS_file *pfs_file= find_or_create_file(thread, klass, name, len, true);
3969 state->m_file= reinterpret_cast<PSI_file*> (pfs_file);
3970 }
3971 break;
3972 default:
3973 DBUG_ASSERT(false);
3974 break;
3975 }
3976
3977 end_file_wait_v1(locker, 0);
3978
3979 return state->m_file;
3980}
3981
3982/**
3983 Implementation of the file instrumentation interface.
3984 @sa PSI_v1::end_file_open_wait_and_bind_to_descriptor.
3985*/
3986static void end_file_open_wait_and_bind_to_descriptor_v1
3987 (PSI_file_locker *locker, File file)
3988{
3989 PFS_file *pfs_file= NULL;
3990 int index= (int) file;
3991 PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
3992 DBUG_ASSERT(state != NULL);
3993
3994 if (index >= 0)
3995 {
3996 PFS_file_class *klass= reinterpret_cast<PFS_file_class*> (state->m_class);
3997 PFS_thread *thread= reinterpret_cast<PFS_thread*> (state->m_thread);
3998 const char *name= state->m_name;
3999 uint len= (uint)strlen(name);
4000 pfs_file= find_or_create_file(thread, klass, name, len, true);
4001 state->m_file= reinterpret_cast<PSI_file*> (pfs_file);
4002 }
4003
4004 end_file_wait_v1(locker, 0);
4005
4006 if (likely(index >= 0))
4007 {
4008 if (likely(index < file_handle_max))
4009 file_handle_array[index]= pfs_file;
4010 else
4011 {
4012 if (pfs_file != NULL)
4013 release_file(pfs_file);
4014 file_handle_lost++;
4015 }
4016 }
4017}
4018
4019/**
4020 Implementation of the file instrumentation interface.
4021 @sa PSI_v1::start_file_wait.
4022*/
4023static void start_file_wait_v1(PSI_file_locker *locker,
4024 size_t count,
4025 const char *src_file,
4026 uint src_line)
4027{
4028 ulonglong timer_start= 0;
4029 PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
4030 DBUG_ASSERT(state != NULL);
4031
4032 uint flags= state->m_flags;
4033
4034 if (flags & STATE_FLAG_TIMED)
4035 {
4036 timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
4037 state->m_timer_start= timer_start;
4038 }
4039
4040 if (flags & STATE_FLAG_EVENT)
4041 {
4042 PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
4043 DBUG_ASSERT(wait != NULL);
4044
4045 wait->m_timer_start= timer_start;
4046 wait->m_source_file= src_file;
4047 wait->m_source_line= src_line;
4048 wait->m_number_of_bytes= count;
4049 }
4050}
4051
4052/**
4053 Implementation of the file instrumentation interface.
4054 @sa PSI_v1::end_file_wait.
4055*/
4056static void end_file_wait_v1(PSI_file_locker *locker,
4057 size_t byte_count)
4058{
4059 PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
4060 DBUG_ASSERT(state != NULL);
4061 PFS_file *file= reinterpret_cast<PFS_file *> (state->m_file);
4062 PFS_file_class *klass= reinterpret_cast<PFS_file_class *> (state->m_class);
4063 PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
4064
4065 ulonglong timer_end= 0;
4066 ulonglong wait_time= 0;
4067 PFS_byte_stat *byte_stat;
4068 uint flags= state->m_flags;
4069 size_t bytes= ((int)byte_count > -1 ? byte_count : 0);
4070
4071 PFS_file_stat *file_stat;
4072
4073 if (file != NULL)
4074 {
4075 file_stat= & file->m_file_stat;
4076 }
4077 else
4078 {
4079 file_stat= & klass->m_file_stat;
4080 }
4081
4082 switch (state->m_operation)
4083 {
4084 /* Group read operations */
4085 case PSI_FILE_READ:
4086 byte_stat= &file_stat->m_io_stat.m_read;
4087 break;
4088 /* Group write operations */
4089 case PSI_FILE_WRITE:
4090 byte_stat= &file_stat->m_io_stat.m_write;
4091 break;
4092 /* Group remaining operations as miscellaneous */
4093 case PSI_FILE_CREATE:
4094 case PSI_FILE_CREATE_TMP:
4095 case PSI_FILE_OPEN:
4096 case PSI_FILE_STREAM_OPEN:
4097 case PSI_FILE_STREAM_CLOSE:
4098 case PSI_FILE_SEEK:
4099 case PSI_FILE_TELL:
4100 case PSI_FILE_FLUSH:
4101 case PSI_FILE_FSTAT:
4102 case PSI_FILE_CHSIZE:
4103 case PSI_FILE_DELETE:
4104 case PSI_FILE_RENAME:
4105 case PSI_FILE_SYNC:
4106 case PSI_FILE_STAT:
4107 case PSI_FILE_CLOSE:
4108 byte_stat= &file_stat->m_io_stat.m_misc;
4109 break;
4110 default:
4111 DBUG_ASSERT(false);
4112 byte_stat= NULL;
4113 break;
4114 }
4115
4116 /* Aggregation for EVENTS_WAITS_SUMMARY_BY_INSTANCE */
4117 if (flags & STATE_FLAG_TIMED)
4118 {
4119 timer_end= state->m_timer();
4120 wait_time= timer_end - state->m_timer_start;
4121 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */
4122 byte_stat->aggregate(wait_time, bytes);
4123 }
4124 else
4125 {
4126 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
4127 byte_stat->aggregate_counted(bytes);
4128 }
4129
4130 if (flags & STATE_FLAG_THREAD)
4131 {
4132 DBUG_ASSERT(thread != NULL);
4133
4134 PFS_single_stat *event_name_array;
4135 event_name_array= thread->m_instr_class_waits_stats;
4136 uint index= klass->m_event_name_index;
4137
4138 if (flags & STATE_FLAG_TIMED)
4139 {
4140 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
4141 event_name_array[index].aggregate_value(wait_time);
4142 }
4143 else
4144 {
4145 /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
4146 event_name_array[index].aggregate_counted();
4147 }
4148
4149 if (state->m_flags & STATE_FLAG_EVENT)
4150 {
4151 PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
4152 DBUG_ASSERT(wait != NULL);
4153
4154 wait->m_timer_end= timer_end;
4155 wait->m_number_of_bytes= bytes;
4156 wait->m_end_event_id= thread->m_event_id;
4157 wait->m_object_instance_addr= file;
4158 wait->m_weak_file= file;
4159 wait->m_weak_version= (file ? file->get_version() : 0);
4160
4161 if (flag_events_waits_history)
4162 insert_events_waits_history(thread, wait);
4163 if (flag_events_waits_history_long)
4164 insert_events_waits_history_long(wait);
4165 thread->m_events_waits_current--;
4166
4167 DBUG_ASSERT(wait == thread->m_events_waits_current);
4168 }
4169 }
4170}
4171
4172/**
4173 Implementation of the file instrumentation interface.
4174 @sa PSI_v1::start_file_close_wait.
4175*/
4176static void start_file_close_wait_v1(PSI_file_locker *locker,
4177 const char *src_file,
4178 uint src_line)
4179{
4180 PFS_thread *thread;
4181 const char *name;
4182 uint len;
4183 PFS_file *pfs_file;
4184 PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
4185 DBUG_ASSERT(state != NULL);
4186
4187 switch (state->m_operation)
4188 {
4189 case PSI_FILE_DELETE:
4190 thread= reinterpret_cast<PFS_thread*> (state->m_thread);
4191 name= state->m_name;
4192 len= (uint)strlen(name);
4193 pfs_file= find_or_create_file(thread, NULL, name, len, false);
4194 state->m_file= reinterpret_cast<PSI_file*> (pfs_file);
4195 break;
4196 case PSI_FILE_STREAM_CLOSE:
4197 case PSI_FILE_CLOSE:
4198 break;
4199 default:
4200 DBUG_ASSERT(false);
4201 break;
4202 }
4203
4204 start_file_wait_v1(locker, 0, src_file, src_line);
4205
4206 return;
4207}
4208
4209/**
4210 Implementation of the file instrumentation interface.
4211 @sa PSI_v1::end_file_close_wait.
4212*/
4213static void end_file_close_wait_v1(PSI_file_locker *locker, int rc)
4214{
4215 PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
4216 DBUG_ASSERT(state != NULL);
4217
4218 end_file_wait_v1(locker, 0);
4219
4220 if (rc == 0)
4221 {
4222 PFS_thread *thread= reinterpret_cast<PFS_thread*> (state->m_thread);
4223 PFS_file *file= reinterpret_cast<PFS_file*> (state->m_file);
4224
4225 /* Release or destroy the file if necessary */
4226 switch(state->m_operation)
4227 {
4228 case PSI_FILE_CLOSE:
4229 case PSI_FILE_STREAM_CLOSE:
4230 if (file != NULL)
4231 release_file(file);
4232 break;
4233 case PSI_FILE_DELETE:
4234 if (file != NULL)
4235 destroy_file(thread, file);
4236 break;
4237 default:
4238 DBUG_ASSERT(false);
4239 break;
4240 }
4241 }
4242 return;
4243}
4244
4245static void start_stage_v1(PSI_stage_key key, const char *src_file, int src_line)
4246{
4247 ulonglong timer_value= 0;
4248
4249 PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
4250 if (unlikely(pfs_thread == NULL))
4251 return;
4252
4253 /* Always update column threads.processlist_state. */
4254 pfs_thread->m_stage= key;
4255
4256 if (psi_unlikely(! flag_global_instrumentation))
4257 return;
4258
4259 if (flag_thread_instrumentation && ! pfs_thread->m_enabled)
4260 return;
4261
4262 PFS_events_stages *pfs= & pfs_thread->m_stage_current;
4263 PFS_events_waits *child_wait= & pfs_thread->m_events_waits_stack[0];
4264 PFS_events_statements *parent_statement= & pfs_thread->m_statement_stack[0];
4265
4266 PFS_instr_class *old_class= pfs->m_class;
4267 if (old_class != NULL)
4268 {
4269 PFS_stage_stat *event_name_array;
4270 event_name_array= pfs_thread->m_instr_class_stages_stats;
4271 uint index= old_class->m_event_name_index;
4272
4273 /* Finish old event */
4274 if (old_class->m_timed)
4275 {
4276 timer_value= get_timer_raw_value(stage_timer);;
4277 pfs->m_timer_end= timer_value;
4278
4279 /* Aggregate to EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
4280 ulonglong stage_time= timer_value - pfs->m_timer_start;
4281 event_name_array[index].aggregate_value(stage_time);
4282 }
4283 else
4284 {
4285 /* Aggregate to EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
4286 event_name_array[index].aggregate_counted();
4287 }
4288
4289 if (flag_events_stages_current)
4290 {
4291 pfs->m_end_event_id= pfs_thread->m_event_id;
4292 if (flag_events_stages_history)
4293 insert_events_stages_history(pfs_thread, pfs);
4294 if (flag_events_stages_history_long)
4295 insert_events_stages_history_long(pfs);
4296 }
4297
4298 /* This stage event is now complete. */
4299 pfs->m_class= NULL;
4300
4301 /* New waits will now be attached directly to the parent statement. */
4302 child_wait->m_event_id= parent_statement->m_event_id;
4303 child_wait->m_event_type= parent_statement->m_event_type;
4304 /* See below for new stages, that may overwrite this. */
4305 }
4306
4307 /* Start new event */
4308
4309 PFS_stage_class *new_klass= find_stage_class(key);
4310 if (unlikely(new_klass == NULL))
4311 return;
4312
4313 if (! new_klass->m_enabled)
4314 return;
4315
4316 pfs->m_class= new_klass;
4317 if (new_klass->m_timed)
4318 {
4319 /*
4320 Do not call the timer again if we have a
4321 TIMER_END for the previous stage already.
4322 */
4323 if (timer_value == 0)
4324 timer_value= get_timer_raw_value(stage_timer);
4325 pfs->m_timer_start= timer_value;
4326 }
4327 else
4328 pfs->m_timer_start= 0;
4329 pfs->m_timer_end= 0;
4330
4331 if (flag_events_stages_current)
4332 {
4333 /* m_thread_internal_id is immutable and already set */
4334 DBUG_ASSERT(pfs->m_thread_internal_id == pfs_thread->m_thread_internal_id);
4335 pfs->m_event_id= pfs_thread->m_event_id++;
4336 pfs->m_end_event_id= 0;
4337 pfs->m_source_file= src_file;
4338 pfs->m_source_line= src_line;
4339
4340 /* New wait events will have this new stage as parent. */
4341 child_wait->m_event_id= pfs->m_event_id;
4342 child_wait->m_event_type= EVENT_TYPE_STAGE;
4343 }
4344}
4345
4346static void end_stage_v1()
4347{
4348 ulonglong timer_value= 0;
4349
4350 PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
4351 if (unlikely(pfs_thread == NULL))
4352 return;
4353
4354 pfs_thread->m_stage= 0;
4355
4356 if (psi_unlikely(! flag_global_instrumentation))
4357 return;
4358
4359 if (flag_thread_instrumentation && ! pfs_thread->m_enabled)
4360 return;
4361
4362 PFS_events_stages *pfs= & pfs_thread->m_stage_current;
4363
4364 PFS_instr_class *old_class= pfs->m_class;
4365 if (old_class != NULL)
4366 {
4367 PFS_stage_stat *event_name_array;
4368 event_name_array= pfs_thread->m_instr_class_stages_stats;
4369 uint index= old_class->m_event_name_index;
4370
4371 /* Finish old event */
4372 if (old_class->m_timed)
4373 {
4374 timer_value= get_timer_raw_value(stage_timer);;
4375 pfs->m_timer_end= timer_value;
4376
4377 /* Aggregate to EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
4378 ulonglong stage_time= timer_value - pfs->m_timer_start;
4379 event_name_array[index].aggregate_value(stage_time);
4380 }
4381 else
4382 {
4383 /* Aggregate to EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
4384 event_name_array[index].aggregate_counted();
4385 }
4386
4387 if (flag_events_stages_current)
4388 {
4389 pfs->m_end_event_id= pfs_thread->m_event_id;
4390 if (flag_events_stages_history)
4391 insert_events_stages_history(pfs_thread, pfs);
4392 if (flag_events_stages_history_long)
4393 insert_events_stages_history_long(pfs);
4394 }
4395
4396 /* New waits will now be attached directly to the parent statement. */
4397 PFS_events_waits *child_wait= & pfs_thread->m_events_waits_stack[0];
4398 PFS_events_statements *parent_statement= & pfs_thread->m_statement_stack[0];
4399 child_wait->m_event_id= parent_statement->m_event_id;
4400 child_wait->m_event_type= parent_statement->m_event_type;
4401
4402 /* This stage is completed */
4403 pfs->m_class= NULL;
4404 }
4405}
4406
4407static PSI_statement_locker*
4408get_thread_statement_locker_v1(PSI_statement_locker_state *state,
4409 PSI_statement_key key,
4410 const void *charset)
4411{
4412 DBUG_ASSERT(state != NULL);
4413 DBUG_ASSERT(charset != NULL);
4414
4415 if (psi_unlikely(! flag_global_instrumentation))
4416 return NULL;
4417 PFS_statement_class *klass= find_statement_class(key);
4418 if (unlikely(klass == NULL))
4419 return NULL;
4420 if (! klass->m_enabled)
4421 return NULL;
4422
4423 uint flags;
4424
4425 if (flag_thread_instrumentation)
4426 {
4427 PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
4428 if (unlikely(pfs_thread == NULL))
4429 return NULL;
4430 if (! pfs_thread->m_enabled)
4431 return NULL;
4432 state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
4433 flags= STATE_FLAG_THREAD;
4434
4435 if (klass->m_timed)
4436 flags|= STATE_FLAG_TIMED;
4437
4438 if (flag_events_statements_current)
4439 {
4440 ulonglong event_id= pfs_thread->m_event_id++;
4441
4442 if (pfs_thread->m_events_statements_count >= statement_stack_max)
4443 {
4444 return NULL;
4445 }
4446
4447 pfs_thread->m_stmt_lock.allocated_to_dirty();
4448 PFS_events_statements *pfs= & pfs_thread->m_statement_stack[pfs_thread->m_events_statements_count];
4449 /* m_thread_internal_id is immutable and already set */
4450 DBUG_ASSERT(pfs->m_thread_internal_id == pfs_thread->m_thread_internal_id);
4451 pfs->m_event_id= event_id;
4452 pfs->m_end_event_id= 0;
4453 pfs->m_class= klass;
4454 pfs->m_timer_start= 0;
4455 pfs->m_timer_end= 0;
4456 pfs->m_lock_time= 0;
4457 pfs->m_current_schema_name_length= 0;
4458 pfs->m_sqltext_length= 0;
4459 pfs->m_sqltext_truncated= false;
4460 pfs->m_sqltext_cs_number= system_charset_info->number; /* default */
4461
4462 pfs->m_message_text[0]= '\0';
4463 pfs->m_sql_errno= 0;
4464 pfs->m_sqlstate[0]= '\0';
4465 pfs->m_error_count= 0;
4466 pfs->m_warning_count= 0;
4467 pfs->m_rows_affected= 0;
4468
4469 pfs->m_rows_sent= 0;
4470 pfs->m_rows_examined= 0;
4471 pfs->m_created_tmp_disk_tables= 0;
4472 pfs->m_created_tmp_tables= 0;
4473 pfs->m_select_full_join= 0;
4474 pfs->m_select_full_range_join= 0;
4475 pfs->m_select_range= 0;
4476 pfs->m_select_range_check= 0;
4477 pfs->m_select_scan= 0;
4478 pfs->m_sort_merge_passes= 0;
4479 pfs->m_sort_range= 0;
4480 pfs->m_sort_rows= 0;
4481 pfs->m_sort_scan= 0;
4482 pfs->m_no_index_used= 0;
4483 pfs->m_no_good_index_used= 0;
4484 pfs->m_digest_storage.reset();
4485
4486 /* New stages will have this statement as parent */
4487 PFS_events_stages *child_stage= & pfs_thread->m_stage_current;
4488 child_stage->m_nesting_event_id= event_id;
4489 child_stage->m_nesting_event_type= EVENT_TYPE_STATEMENT;
4490
4491 /* New waits will have this statement as parent, if no stage is instrumented */
4492 PFS_events_waits *child_wait= & pfs_thread->m_events_waits_stack[0];
4493 child_wait->m_nesting_event_id= event_id;
4494 child_wait->m_nesting_event_type= EVENT_TYPE_STATEMENT;
4495
4496 state->m_statement= pfs;
4497 flags|= STATE_FLAG_EVENT;
4498
4499 pfs_thread->m_events_statements_count++;
4500 pfs_thread->m_stmt_lock.dirty_to_allocated();
4501 }
4502 }
4503 else
4504 {
4505 if (klass->m_timed)
4506 flags= STATE_FLAG_TIMED;
4507 else
4508 flags= 0;
4509 }
4510
4511 if (flag_statements_digest)
4512 {
4513 flags|= STATE_FLAG_DIGEST;
4514 }
4515
4516 state->m_discarded= false;
4517 state->m_class= klass;
4518 state->m_flags= flags;
4519
4520 state->m_lock_time= 0;
4521 state->m_rows_sent= 0;
4522 state->m_rows_examined= 0;
4523 state->m_created_tmp_disk_tables= 0;
4524 state->m_created_tmp_tables= 0;
4525 state->m_select_full_join= 0;
4526 state->m_select_full_range_join= 0;
4527 state->m_select_range= 0;
4528 state->m_select_range_check= 0;
4529 state->m_select_scan= 0;
4530 state->m_sort_merge_passes= 0;
4531 state->m_sort_range= 0;
4532 state->m_sort_rows= 0;
4533 state->m_sort_scan= 0;
4534 state->m_no_index_used= 0;
4535 state->m_no_good_index_used= 0;
4536
4537 state->m_digest= NULL;
4538
4539 state->m_schema_name_length= 0;
4540 state->m_cs_number= ((CHARSET_INFO *)charset)->number;
4541
4542 return reinterpret_cast<PSI_statement_locker*> (state);
4543}
4544
4545static PSI_statement_locker*
4546refine_statement_v1(PSI_statement_locker *locker,
4547 PSI_statement_key key)
4548{
4549 PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker);
4550 if (state == NULL)
4551 return NULL;
4552 DBUG_ASSERT(state->m_class != NULL);
4553 PFS_statement_class *klass;
4554 /* Only refine statements for mutable instrumentation */
4555 klass= reinterpret_cast<PFS_statement_class*> (state->m_class);
4556 DBUG_ASSERT(klass->is_mutable());
4557 klass= find_statement_class(key);
4558
4559 uint flags= state->m_flags;
4560
4561 if (unlikely(klass == NULL) || !klass->m_enabled)
4562 {
4563 /* pop statement stack */
4564 if (flags & STATE_FLAG_THREAD)
4565 {
4566 PFS_thread *pfs_thread= reinterpret_cast<PFS_thread *> (state->m_thread);
4567 DBUG_ASSERT(pfs_thread != NULL);
4568 if (pfs_thread->m_events_statements_count > 0)
4569 pfs_thread->m_events_statements_count--;
4570 }
4571
4572 state->m_discarded= true;
4573 return NULL;
4574 }
4575
4576 if ((flags & STATE_FLAG_TIMED) && ! klass->m_timed)
4577 flags= flags & ~STATE_FLAG_TIMED;
4578
4579 if (flags & STATE_FLAG_EVENT)
4580 {
4581 PFS_events_statements *pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement);
4582 DBUG_ASSERT(pfs != NULL);
4583
4584 /* mutate EVENTS_STATEMENTS_CURRENT.EVENT_NAME */
4585 pfs->m_class= klass;
4586 }
4587
4588 state->m_class= klass;
4589 state->m_flags= flags;
4590 return reinterpret_cast<PSI_statement_locker*> (state);
4591}
4592
4593static void start_statement_v1(PSI_statement_locker *locker,
4594 const char *db, uint db_len,
4595 const char *src_file, uint src_line)
4596{
4597 PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker);
4598 DBUG_ASSERT(state != NULL);
4599
4600 uint flags= state->m_flags;
4601 ulonglong timer_start= 0;
4602
4603 if (flags & STATE_FLAG_TIMED)
4604 {
4605 timer_start= get_timer_raw_value_and_function(statement_timer, & state->m_timer);
4606 state->m_timer_start= timer_start;
4607 }
4608
4609 compile_time_assert(PSI_SCHEMA_NAME_LEN == NAME_LEN);
4610 DBUG_ASSERT(db_len <= sizeof(state->m_schema_name));
4611
4612 if (db_len > 0)
4613 memcpy(state->m_schema_name, db, db_len);
4614 state->m_schema_name_length= db_len;
4615
4616 if (flags & STATE_FLAG_EVENT)
4617 {
4618 PFS_events_statements *pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement);
4619 DBUG_ASSERT(pfs != NULL);
4620
4621 pfs->m_timer_start= timer_start;
4622 pfs->m_source_file= src_file;
4623 pfs->m_source_line= src_line;
4624
4625 DBUG_ASSERT(db_len <= sizeof(pfs->m_current_schema_name));
4626 if (db_len > 0)
4627 memcpy(pfs->m_current_schema_name, db, db_len);
4628 pfs->m_current_schema_name_length= db_len;
4629 }
4630}
4631
4632static void set_statement_text_v1(PSI_statement_locker *locker,
4633 const char *text, uint text_len)
4634{
4635 PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker);
4636 DBUG_ASSERT(state != NULL);
4637
4638 if (state->m_discarded)
4639 return;
4640
4641 if (state->m_flags & STATE_FLAG_EVENT)
4642 {
4643 PFS_events_statements *pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement);
4644 DBUG_ASSERT(pfs != NULL);
4645 if (text_len > sizeof (pfs->m_sqltext))
4646 {
4647 text_len= sizeof(pfs->m_sqltext);
4648 pfs->m_sqltext_truncated= true;
4649 }
4650 if (text_len)
4651 memcpy(pfs->m_sqltext, text, text_len);
4652 pfs->m_sqltext_length= text_len;
4653 pfs->m_sqltext_cs_number= state->m_cs_number;
4654 }
4655
4656 return;
4657}
4658
4659#define SET_STATEMENT_ATTR_BODY(LOCKER, ATTR, VALUE) \
4660 PSI_statement_locker_state *state; \
4661 state= reinterpret_cast<PSI_statement_locker_state*> (LOCKER); \
4662 if (unlikely(state == NULL)) \
4663 return; \
4664 if (state->m_discarded) \
4665 return; \
4666 state->ATTR= VALUE; \
4667 if (state->m_flags & STATE_FLAG_EVENT) \
4668 { \
4669 PFS_events_statements *pfs; \
4670 pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement); \
4671 DBUG_ASSERT(pfs != NULL); \
4672 pfs->ATTR= VALUE; \
4673 } \
4674 return;
4675
4676#define INC_STATEMENT_ATTR_BODY(LOCKER, ATTR, VALUE) \
4677 PSI_statement_locker_state *state; \
4678 state= reinterpret_cast<PSI_statement_locker_state*> (LOCKER); \
4679 if (unlikely(state == NULL)) \
4680 return; \
4681 if (state->m_discarded) \
4682 return; \
4683 state->ATTR+= VALUE; \
4684 if (state->m_flags & STATE_FLAG_EVENT) \
4685 { \
4686 PFS_events_statements *pfs; \
4687 pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement); \
4688 DBUG_ASSERT(pfs != NULL); \
4689 pfs->ATTR+= VALUE; \
4690 } \
4691 return;
4692
4693static void set_statement_lock_time_v1(PSI_statement_locker *locker,
4694 ulonglong count)
4695{
4696 SET_STATEMENT_ATTR_BODY(locker, m_lock_time, count);
4697}
4698
4699static void set_statement_rows_sent_v1(PSI_statement_locker *locker,
4700 ulonglong count)
4701{
4702 SET_STATEMENT_ATTR_BODY(locker, m_rows_sent, count);
4703}
4704
4705static void set_statement_rows_examined_v1(PSI_statement_locker *locker,
4706 ulonglong count)
4707{
4708 SET_STATEMENT_ATTR_BODY(locker, m_rows_examined, count);
4709}
4710
4711static void inc_statement_created_tmp_disk_tables_v1(PSI_statement_locker *locker,
4712 ulong count)
4713{
4714 INC_STATEMENT_ATTR_BODY(locker, m_created_tmp_disk_tables, count);
4715}
4716
4717static void inc_statement_created_tmp_tables_v1(PSI_statement_locker *locker,
4718 ulong count)
4719{
4720 INC_STATEMENT_ATTR_BODY(locker, m_created_tmp_tables, count);
4721}
4722
4723static void inc_statement_select_full_join_v1(PSI_statement_locker *locker,
4724 ulong count)
4725{
4726 INC_STATEMENT_ATTR_BODY(locker, m_select_full_join, count);
4727}
4728
4729static void inc_statement_select_full_range_join_v1(PSI_statement_locker *locker,
4730 ulong count)
4731{
4732 INC_STATEMENT_ATTR_BODY(locker, m_select_full_range_join, count);
4733}
4734
4735static void inc_statement_select_range_v1(PSI_statement_locker *locker,
4736 ulong count)
4737{
4738 INC_STATEMENT_ATTR_BODY(locker, m_select_range, count);
4739}
4740
4741static void inc_statement_select_range_check_v1(PSI_statement_locker *locker,
4742 ulong count)
4743{
4744 INC_STATEMENT_ATTR_BODY(locker, m_select_range_check, count);
4745}
4746
4747static void inc_statement_select_scan_v1(PSI_statement_locker *locker,
4748 ulong count)
4749{
4750 INC_STATEMENT_ATTR_BODY(locker, m_select_scan, count);
4751}
4752
4753static void inc_statement_sort_merge_passes_v1(PSI_statement_locker *locker,
4754 ulong count)
4755{
4756 INC_STATEMENT_ATTR_BODY(locker, m_sort_merge_passes, count);
4757}
4758
4759static void inc_statement_sort_range_v1(PSI_statement_locker *locker,
4760 ulong count)
4761{
4762 INC_STATEMENT_ATTR_BODY(locker, m_sort_range, count);
4763}
4764
4765static void inc_statement_sort_rows_v1(PSI_statement_locker *locker,
4766 ulong count)
4767{
4768 INC_STATEMENT_ATTR_BODY(locker, m_sort_rows, count);
4769}
4770
4771static void inc_statement_sort_scan_v1(PSI_statement_locker *locker,
4772 ulong count)
4773{
4774 INC_STATEMENT_ATTR_BODY(locker, m_sort_scan, count);
4775}
4776
4777static void set_statement_no_index_used_v1(PSI_statement_locker *locker)
4778{
4779 SET_STATEMENT_ATTR_BODY(locker, m_no_index_used, 1);
4780}
4781
4782static void set_statement_no_good_index_used_v1(PSI_statement_locker *locker)
4783{
4784 SET_STATEMENT_ATTR_BODY(locker, m_no_good_index_used, 1);
4785}
4786
4787static void end_statement_v1(PSI_statement_locker *locker, void *stmt_da)
4788{
4789 PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker);
4790 Diagnostics_area *da= reinterpret_cast<Diagnostics_area*> (stmt_da);
4791 DBUG_ASSERT(state != NULL);
4792 DBUG_ASSERT(da != NULL);
4793
4794 if (state->m_discarded)
4795 return;
4796
4797 PFS_statement_class *klass= reinterpret_cast<PFS_statement_class *> (state->m_class);
4798 DBUG_ASSERT(klass != NULL);
4799
4800 ulonglong timer_end= 0;
4801 ulonglong wait_time= 0;
4802 uint flags= state->m_flags;
4803
4804 if (flags & STATE_FLAG_TIMED)
4805 {
4806 timer_end= state->m_timer();
4807 wait_time= timer_end - state->m_timer_start;
4808 }
4809
4810 PFS_statement_stat *event_name_array;
4811 uint index= klass->m_event_name_index;
4812 PFS_statement_stat *stat;
4813
4814 /*
4815 Capture statement stats by digest.
4816 */
4817 const sql_digest_storage *digest_storage= NULL;
4818 PFS_statement_stat *digest_stat= NULL;
4819
4820 if (flags & STATE_FLAG_THREAD)
4821 {
4822 PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
4823 DBUG_ASSERT(thread != NULL);
4824 event_name_array= thread->m_instr_class_statements_stats;
4825 /* Aggregate to EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME */
4826 stat= & event_name_array[index];
4827
4828 if (flags & STATE_FLAG_DIGEST)
4829 {
4830 digest_storage= state->m_digest;
4831
4832 if (digest_storage != NULL)
4833 {
4834 /* Populate PFS_statements_digest_stat with computed digest information.*/
4835 digest_stat= find_or_create_digest(thread, digest_storage,
4836 state->m_schema_name,
4837 state->m_schema_name_length);
4838 }
4839 }
4840
4841 if (flags & STATE_FLAG_EVENT)
4842 {
4843 PFS_events_statements *pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement);
4844 DBUG_ASSERT(pfs != NULL);
4845
4846 thread->m_stmt_lock.allocated_to_dirty();
4847
4848 switch(da->status())
4849 {
4850 case Diagnostics_area::DA_OK_BULK:
4851 case Diagnostics_area::DA_EMPTY:
4852 break;
4853 case Diagnostics_area::DA_OK:
4854 memcpy(pfs->m_message_text, da->message(), MYSQL_ERRMSG_SIZE);
4855 pfs->m_message_text[MYSQL_ERRMSG_SIZE]= 0;
4856 pfs->m_rows_affected= da->affected_rows();
4857 pfs->m_warning_count= da->statement_warn_count();
4858 memcpy(pfs->m_sqlstate, "00000", SQLSTATE_LENGTH);
4859 break;
4860 case Diagnostics_area::DA_EOF:
4861 pfs->m_warning_count= da->statement_warn_count();
4862 break;
4863 case Diagnostics_area::DA_ERROR:
4864 memcpy(pfs->m_message_text, da->message(), MYSQL_ERRMSG_SIZE);
4865 pfs->m_message_text[MYSQL_ERRMSG_SIZE]= 0;
4866 pfs->m_sql_errno= da->sql_errno();
4867 pfs->m_error_count++;
4868 memcpy(pfs->m_sqlstate, da->get_sqlstate(), SQLSTATE_LENGTH);
4869 break;
4870 case Diagnostics_area::DA_DISABLED:
4871 break;
4872 }
4873
4874 pfs->m_timer_end= timer_end;
4875 pfs->m_end_event_id= thread->m_event_id;
4876
4877 if (digest_storage != NULL)
4878 {
4879 /*
4880 The following columns in events_statement_current:
4881 - DIGEST,
4882 - DIGEST_TEXT
4883 are computed from the digest storage.
4884 */
4885 pfs->m_digest_storage.copy(digest_storage);
4886 }
4887
4888 if (flag_events_statements_history)
4889 insert_events_statements_history(thread, pfs);
4890 if (flag_events_statements_history_long)
4891 insert_events_statements_history_long(pfs);
4892
4893 DBUG_ASSERT(thread->m_events_statements_count > 0);
4894 thread->m_events_statements_count--;
4895 thread->m_stmt_lock.dirty_to_allocated();
4896 }
4897 }
4898 else
4899 {
4900 if (flags & STATE_FLAG_DIGEST)
4901 {
4902 PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
4903
4904 /* An instrumented thread is required, for LF_PINS. */
4905 if (thread != NULL)
4906 {
4907 /* Set digest stat. */
4908 digest_storage= state->m_digest;
4909
4910 if (digest_storage != NULL)
4911 {
4912 /* Populate statements_digest_stat with computed digest information. */
4913 digest_stat= find_or_create_digest(thread, digest_storage,
4914 state->m_schema_name,
4915 state->m_schema_name_length);
4916 }
4917 }
4918 }
4919
4920 event_name_array= global_instr_class_statements_array;
4921 /* Aggregate to EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME */
4922 stat= & event_name_array[index];
4923 }
4924
4925 if (flags & STATE_FLAG_TIMED)
4926 {
4927 /* Aggregate to EVENTS_STATEMENTS_SUMMARY_..._BY_EVENT_NAME (timed) */
4928 stat->aggregate_value(wait_time);
4929 }
4930 else
4931 {
4932 /* Aggregate to EVENTS_STATEMENTS_SUMMARY_..._BY_EVENT_NAME (counted) */
4933 stat->aggregate_counted();
4934 }
4935
4936 stat->m_lock_time+= state->m_lock_time;
4937 stat->m_rows_sent+= state->m_rows_sent;
4938 stat->m_rows_examined+= state->m_rows_examined;
4939 stat->m_created_tmp_disk_tables+= state->m_created_tmp_disk_tables;
4940 stat->m_created_tmp_tables+= state->m_created_tmp_tables;
4941 stat->m_select_full_join+= state->m_select_full_join;
4942 stat->m_select_full_range_join+= state->m_select_full_range_join;
4943 stat->m_select_range+= state->m_select_range;
4944 stat->m_select_range_check+= state->m_select_range_check;
4945 stat->m_select_scan+= state->m_select_scan;
4946 stat->m_sort_merge_passes+= state->m_sort_merge_passes;
4947 stat->m_sort_range+= state->m_sort_range;
4948 stat->m_sort_rows+= state->m_sort_rows;
4949 stat->m_sort_scan+= state->m_sort_scan;
4950 stat->m_no_index_used+= state->m_no_index_used;
4951 stat->m_no_good_index_used+= state->m_no_good_index_used;
4952
4953 if (digest_stat != NULL)
4954 {
4955 if (flags & STATE_FLAG_TIMED)
4956 {
4957 digest_stat->aggregate_value(wait_time);
4958 }
4959 else
4960 {
4961 digest_stat->aggregate_counted();
4962 }
4963
4964 digest_stat->m_lock_time+= state->m_lock_time;
4965 digest_stat->m_rows_sent+= state->m_rows_sent;
4966 digest_stat->m_rows_examined+= state->m_rows_examined;
4967 digest_stat->m_created_tmp_disk_tables+= state->m_created_tmp_disk_tables;
4968 digest_stat->m_created_tmp_tables+= state->m_created_tmp_tables;
4969 digest_stat->m_select_full_join+= state->m_select_full_join;
4970 digest_stat->m_select_full_range_join+= state->m_select_full_range_join;
4971 digest_stat->m_select_range+= state->m_select_range;
4972 digest_stat->m_select_range_check+= state->m_select_range_check;
4973 digest_stat->m_select_scan+= state->m_select_scan;
4974 digest_stat->m_sort_merge_passes+= state->m_sort_merge_passes;
4975 digest_stat->m_sort_range+= state->m_sort_range;
4976 digest_stat->m_sort_rows+= state->m_sort_rows;
4977 digest_stat->m_sort_scan+= state->m_sort_scan;
4978 digest_stat->m_no_index_used+= state->m_no_index_used;
4979 digest_stat->m_no_good_index_used+= state->m_no_good_index_used;
4980 }
4981
4982 switch (da->status())
4983 {
4984 case Diagnostics_area::DA_OK_BULK:
4985 case Diagnostics_area::DA_EMPTY:
4986 break;
4987 case Diagnostics_area::DA_OK:
4988 stat->m_rows_affected+= da->affected_rows();
4989 stat->m_warning_count+= da->statement_warn_count();
4990 if (digest_stat != NULL)
4991 {
4992 digest_stat->m_rows_affected+= da->affected_rows();
4993 digest_stat->m_warning_count+= da->statement_warn_count();
4994 }
4995 break;
4996 case Diagnostics_area::DA_EOF:
4997 stat->m_warning_count+= da->statement_warn_count();
4998 if (digest_stat != NULL)
4999 {
5000 digest_stat->m_warning_count+= da->statement_warn_count();
5001 }
5002 break;
5003 case Diagnostics_area::DA_ERROR:
5004 stat->m_error_count++;
5005 if (digest_stat != NULL)
5006 {
5007 digest_stat->m_error_count++;
5008 }
5009 break;
5010 case Diagnostics_area::DA_DISABLED:
5011 break;
5012 }
5013}
5014
5015/**
5016 Implementation of the socket instrumentation interface.
5017 @sa PSI_v1::end_socket_wait.
5018*/
5019static void end_socket_wait_v1(PSI_socket_locker *locker, size_t byte_count)
5020{
5021 PSI_socket_locker_state *state= reinterpret_cast<PSI_socket_locker_state*> (locker);
5022 DBUG_ASSERT(state != NULL);
5023
5024 PFS_socket *socket= reinterpret_cast<PFS_socket *>(state->m_socket);
5025 DBUG_ASSERT(socket != NULL);
5026
5027 ulonglong timer_end= 0;
5028 ulonglong wait_time= 0;
5029 PFS_byte_stat *byte_stat;
5030 uint flags= state->m_flags;
5031 size_t bytes= ((int)byte_count > -1 ? byte_count : 0);
5032
5033 switch (state->m_operation)
5034 {
5035 /* Group read operations */
5036 case PSI_SOCKET_RECV:
5037 case PSI_SOCKET_RECVFROM:
5038 case PSI_SOCKET_RECVMSG:
5039 byte_stat= &socket->m_socket_stat.m_io_stat.m_read;
5040 break;
5041 /* Group write operations */
5042 case PSI_SOCKET_SEND:
5043 case PSI_SOCKET_SENDTO:
5044 case PSI_SOCKET_SENDMSG:
5045 byte_stat= &socket->m_socket_stat.m_io_stat.m_write;
5046 break;
5047 /* Group remaining operations as miscellaneous */
5048 case PSI_SOCKET_CONNECT:
5049 case PSI_SOCKET_CREATE:
5050 case PSI_SOCKET_BIND:
5051 case PSI_SOCKET_SEEK:
5052 case PSI_SOCKET_OPT:
5053 case PSI_SOCKET_STAT:
5054 case PSI_SOCKET_SHUTDOWN:
5055 case PSI_SOCKET_SELECT:
5056 case PSI_SOCKET_CLOSE:
5057 byte_stat= &socket->m_socket_stat.m_io_stat.m_misc;
5058 break;
5059 default:
5060 DBUG_ASSERT(false);
5061 byte_stat= NULL;
5062 break;
5063 }
5064
5065 /* Aggregation for EVENTS_WAITS_SUMMARY_BY_INSTANCE */
5066 if (flags & STATE_FLAG_TIMED)
5067 {
5068 timer_end= state->m_timer();
5069 wait_time= timer_end - state->m_timer_start;
5070
5071 /* Aggregate to the socket instrument for now (timed) */
5072 byte_stat->aggregate(wait_time, bytes);
5073 }
5074 else
5075 {
5076 /* Aggregate to the socket instrument (event count and byte count) */
5077 byte_stat->aggregate_counted(bytes);
5078 }
5079
5080 /* Aggregate to EVENTS_WAITS_HISTORY and EVENTS_WAITS_HISTORY_LONG */
5081 if (flags & STATE_FLAG_EVENT)
5082 {
5083 PFS_thread *thread= reinterpret_cast<PFS_thread *>(state->m_thread);
5084 DBUG_ASSERT(thread != NULL);
5085 PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
5086 DBUG_ASSERT(wait != NULL);
5087
5088 wait->m_timer_end= timer_end;
5089 wait->m_end_event_id= thread->m_event_id;
5090 wait->m_number_of_bytes= bytes;
5091
5092 if (flag_events_waits_history)
5093 insert_events_waits_history(thread, wait);
5094 if (flag_events_waits_history_long)
5095 insert_events_waits_history_long(wait);
5096 thread->m_events_waits_current--;
5097
5098 DBUG_ASSERT(wait == thread->m_events_waits_current);
5099 }
5100}
5101
5102static void set_socket_state_v1(PSI_socket *socket, PSI_socket_state state)
5103{
5104 DBUG_ASSERT((state == PSI_SOCKET_STATE_IDLE) || (state == PSI_SOCKET_STATE_ACTIVE));
5105 PFS_socket *pfs= reinterpret_cast<PFS_socket*>(socket);
5106 DBUG_ASSERT(pfs != NULL);
5107 DBUG_ASSERT(pfs->m_idle || (state == PSI_SOCKET_STATE_IDLE));
5108 DBUG_ASSERT(!pfs->m_idle || (state == PSI_SOCKET_STATE_ACTIVE));
5109 pfs->m_idle= (state == PSI_SOCKET_STATE_IDLE);
5110}
5111
5112/**
5113 Set socket descriptor and address info.
5114*/
5115static void set_socket_info_v1(PSI_socket *socket,
5116 const my_socket *fd,
5117 const struct sockaddr *addr,
5118 socklen_t addr_len)
5119{
5120 PFS_socket *pfs= reinterpret_cast<PFS_socket*>(socket);
5121 DBUG_ASSERT(pfs != NULL);
5122
5123 /** Set socket descriptor */
5124 if (fd != NULL)
5125 pfs->m_fd= (uint)*fd;
5126
5127 /** Set raw socket address and length */
5128 if (likely(addr != NULL && addr_len > 0))
5129 {
5130 pfs->m_addr_len= addr_len;
5131
5132 /** Restrict address length to size of struct */
5133 if (unlikely(pfs->m_addr_len > sizeof(sockaddr_storage)))
5134 pfs->m_addr_len= sizeof(struct sockaddr_storage);
5135
5136 memcpy(&pfs->m_sock_addr, addr, pfs->m_addr_len);
5137 }
5138}
5139
5140/**
5141 Implementation of the socket instrumentation interface.
5142 @sa PSI_v1::set_socket_info.
5143*/
5144static void set_socket_thread_owner_v1(PSI_socket *socket)
5145{
5146 PFS_socket *pfs_socket= reinterpret_cast<PFS_socket*>(socket);
5147 DBUG_ASSERT(pfs_socket != NULL);
5148 pfs_socket->m_thread_owner= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
5149}
5150
5151struct PSI_digest_locker*
5152pfs_digest_start_v1(PSI_statement_locker *locker)
5153{
5154 PSI_statement_locker_state *statement_state;
5155 statement_state= reinterpret_cast<PSI_statement_locker_state*> (locker);
5156 DBUG_ASSERT(statement_state != NULL);
5157
5158 if (statement_state->m_discarded)
5159 return NULL;
5160
5161 if (statement_state->m_flags & STATE_FLAG_DIGEST)
5162 {
5163 return reinterpret_cast<PSI_digest_locker*> (locker);
5164 }
5165
5166 return NULL;
5167}
5168
5169void pfs_digest_end_v1(PSI_digest_locker *locker, const sql_digest_storage *digest)
5170{
5171 PSI_statement_locker_state *statement_state;
5172 statement_state= reinterpret_cast<PSI_statement_locker_state*> (locker);
5173 DBUG_ASSERT(statement_state != NULL);
5174 DBUG_ASSERT(digest != NULL);
5175
5176 if (statement_state->m_discarded)
5177 return;
5178
5179 if (statement_state->m_flags & STATE_FLAG_DIGEST)
5180 {
5181 statement_state->m_digest= digest;
5182 }
5183}
5184
5185/**
5186 Implementation of the thread attribute connection interface
5187 @sa PSI_v1::set_thread_connect_attr.
5188*/
5189static int set_thread_connect_attrs_v1(const char *buffer, uint length,
5190 const void *from_cs)
5191{
5192
5193 PFS_thread *thd= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
5194
5195 DBUG_ASSERT(buffer != NULL);
5196
5197 if (likely(thd != NULL) && session_connect_attrs_size_per_thread > 0)
5198 {
5199 const CHARSET_INFO *cs = static_cast<const CHARSET_INFO *> (from_cs);
5200
5201 /* copy from the input buffer as much as we can fit */
5202 uint copy_size= (uint)(length < session_connect_attrs_size_per_thread ?
5203 length : session_connect_attrs_size_per_thread);
5204 thd->m_session_lock.allocated_to_dirty();
5205 memcpy(thd->m_session_connect_attrs, buffer, copy_size);
5206 thd->m_session_connect_attrs_length= copy_size;
5207 thd->m_session_connect_attrs_cs_number= cs->number;
5208 thd->m_session_lock.dirty_to_allocated();
5209
5210 if (copy_size == length)
5211 return 0;
5212
5213 session_connect_attrs_lost++;
5214 return 1;
5215 }
5216 return 0;
5217}
5218
5219
5220/**
5221 Implementation of the instrumentation interface.
5222 @sa PSI_v1.
5223*/
5224PSI_v1 PFS_v1=
5225{
5226 register_mutex_v1,
5227 register_rwlock_v1,
5228 register_cond_v1,
5229 register_thread_v1,
5230 register_file_v1,
5231 register_stage_v1,
5232 register_statement_v1,
5233 register_socket_v1,
5234 init_mutex_v1,
5235 destroy_mutex_v1,
5236 init_rwlock_v1,
5237 destroy_rwlock_v1,
5238 init_cond_v1,
5239 destroy_cond_v1,
5240 init_socket_v1,
5241 destroy_socket_v1,
5242 get_table_share_v1,
5243 release_table_share_v1,
5244 drop_table_share_v1,
5245 open_table_v1,
5246 unbind_table_v1,
5247 rebind_table_v1,
5248 close_table_v1,
5249 create_file_v1,
5250 spawn_thread_v1,
5251 new_thread_v1,
5252 set_thread_id_v1,
5253 get_thread_v1,
5254 set_thread_user_v1,
5255 set_thread_account_v1,
5256 set_thread_db_v1,
5257 set_thread_command_v1,
5258 set_thread_start_time_v1,
5259 set_thread_state_v1,
5260 set_thread_info_v1,
5261 set_thread_v1,
5262 delete_current_thread_v1,
5263 delete_thread_v1,
5264 get_thread_file_name_locker_v1,
5265 get_thread_file_stream_locker_v1,
5266 get_thread_file_descriptor_locker_v1,
5267 unlock_mutex_v1,
5268 unlock_rwlock_v1,
5269 signal_cond_v1,
5270 broadcast_cond_v1,
5271 start_idle_wait_v1,
5272 end_idle_wait_v1,
5273 start_mutex_wait_v1,
5274 end_mutex_wait_v1,
5275 start_rwlock_wait_v1, /* read */
5276 end_rwlock_rdwait_v1,
5277 start_rwlock_wait_v1, /* write */
5278 end_rwlock_wrwait_v1,
5279 start_cond_wait_v1,
5280 end_cond_wait_v1,
5281 start_table_io_wait_v1,
5282 end_table_io_wait_v1,
5283 start_table_lock_wait_v1,
5284 end_table_lock_wait_v1,
5285 start_file_open_wait_v1,
5286 end_file_open_wait_v1,
5287 end_file_open_wait_and_bind_to_descriptor_v1,
5288 start_file_wait_v1,
5289 end_file_wait_v1,
5290 start_file_close_wait_v1,
5291 end_file_close_wait_v1,
5292 start_stage_v1,
5293 end_stage_v1,
5294 get_thread_statement_locker_v1,
5295 refine_statement_v1,
5296 start_statement_v1,
5297 set_statement_text_v1,
5298 set_statement_lock_time_v1,
5299 set_statement_rows_sent_v1,
5300 set_statement_rows_examined_v1,
5301 inc_statement_created_tmp_disk_tables_v1,
5302 inc_statement_created_tmp_tables_v1,
5303 inc_statement_select_full_join_v1,
5304 inc_statement_select_full_range_join_v1,
5305 inc_statement_select_range_v1,
5306 inc_statement_select_range_check_v1,
5307 inc_statement_select_scan_v1,
5308 inc_statement_sort_merge_passes_v1,
5309 inc_statement_sort_range_v1,
5310 inc_statement_sort_rows_v1,
5311 inc_statement_sort_scan_v1,
5312 set_statement_no_index_used_v1,
5313 set_statement_no_good_index_used_v1,
5314 end_statement_v1,
5315 start_socket_wait_v1,
5316 end_socket_wait_v1,
5317 set_socket_state_v1,
5318 set_socket_info_v1,
5319 set_socket_thread_owner_v1,
5320 pfs_digest_start_v1,
5321 pfs_digest_end_v1,
5322 set_thread_connect_attrs_v1,
5323};
5324
5325static void* get_interface(int version)
5326{
5327 switch (version)
5328 {
5329 case PSI_VERSION_1:
5330 return &PFS_v1;
5331 default:
5332 return NULL;
5333 }
5334}
5335
5336C_MODE_END
5337
5338struct PSI_bootstrap PFS_bootstrap=
5339{
5340 get_interface
5341};
5342