1 /* Copyright (c) 2008, 2021, Oracle and/or its affiliates.
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, version 2.0,
5   as published by the Free Software Foundation.
6 
7   This program is also distributed with certain software (including
8   but not limited to OpenSSL) that is licensed under separate terms,
9   as designated in a particular file or component or in included license
10   documentation.  The authors of MySQL hereby grant you an additional
11   permission to link the program and your derivative works with the
12   separately licensed software that they have included with MySQL.
13 
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License, version 2.0, for more details.
18 
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software Foundation,
21   51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22 
23 /**
24   @file storage/perfschema/table_events_waits_summary.cc
25   Table EVENTS_WAITS_SUMMARY_BY_xxx (implementation).
26 */
27 
28 #include "my_global.h"
29 #include "my_thread.h"
30 #include "pfs_instr_class.h"
31 #include "pfs_column_types.h"
32 #include "pfs_column_values.h"
33 #include "table_events_waits_summary.h"
34 #include "pfs_global.h"
35 #include "field.h"
36 
37 THR_LOCK table_events_waits_summary_by_instance::m_table_lock;
38 
39 static const TABLE_FIELD_TYPE ews_by_instance_field_types[]=
40 {
41   {
42     { C_STRING_WITH_LEN("EVENT_NAME") },
43     { C_STRING_WITH_LEN("varchar(128)") },
44     { NULL, 0}
45   },
46   {
47     { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") },
48     { C_STRING_WITH_LEN("bigint(20)") },
49     { NULL, 0}
50   },
51   {
52     { C_STRING_WITH_LEN("COUNT_STAR") },
53     { C_STRING_WITH_LEN("bigint(20)") },
54     { NULL, 0}
55   },
56   {
57     { C_STRING_WITH_LEN("SUM_TIMER_WAIT") },
58     { C_STRING_WITH_LEN("bigint(20)") },
59     { NULL, 0}
60   },
61   {
62     { C_STRING_WITH_LEN("MIN_TIMER_WAIT") },
63     { C_STRING_WITH_LEN("bigint(20)") },
64     { NULL, 0}
65   },
66   {
67     { C_STRING_WITH_LEN("AVG_TIMER_WAIT") },
68     { C_STRING_WITH_LEN("bigint(20)") },
69     { NULL, 0}
70   },
71   {
72     { C_STRING_WITH_LEN("MAX_TIMER_WAIT") },
73     { C_STRING_WITH_LEN("bigint(20)") },
74     { NULL, 0}
75   }
76 };
77 
78 TABLE_FIELD_DEF
79 table_events_waits_summary_by_instance::m_field_def=
80 { 7, ews_by_instance_field_types };
81 
82 PFS_engine_table_share
83 table_events_waits_summary_by_instance::m_share=
84 {
85   { C_STRING_WITH_LEN("events_waits_summary_by_instance") },
86   &pfs_truncatable_acl,
87   table_events_waits_summary_by_instance::create,
88   NULL, /* write_row */
89   table_events_waits_summary_by_instance::delete_all_rows,
90   table_all_instr::get_row_count,
91   sizeof(pos_all_instr),
92   &m_table_lock,
93   &m_field_def,
94   false, /* checked */
95   false  /* perpetual */
96 };
97 
create(void)98 PFS_engine_table* table_events_waits_summary_by_instance::create(void)
99 {
100   return new table_events_waits_summary_by_instance();
101 }
102 
delete_all_rows(void)103 int table_events_waits_summary_by_instance::delete_all_rows(void)
104 {
105   reset_events_waits_by_instance();
106   return 0;
107 }
108 
109 table_events_waits_summary_by_instance
table_events_waits_summary_by_instance()110 ::table_events_waits_summary_by_instance()
111   : table_all_instr(&m_share), m_row_exists(false)
112 {}
113 
114 void table_events_waits_summary_by_instance
make_instr_row(PFS_instr * pfs,PFS_instr_class * klass,const void * object_instance_begin,PFS_single_stat * pfs_stat)115 ::make_instr_row(PFS_instr *pfs, PFS_instr_class *klass,
116                  const void *object_instance_begin,
117                  PFS_single_stat *pfs_stat)
118 {
119   pfs_optimistic_state lock;
120   m_row_exists= false;
121 
122   /*
123     Protect this reader against a mutex/rwlock/cond destroy,
124     file delete, table drop.
125   */
126   pfs->m_lock.begin_optimistic_lock(&lock);
127 
128   m_row.m_name= klass->m_name;
129   m_row.m_name_length= klass->m_name_length;
130   m_row.m_object_instance_addr= (intptr) object_instance_begin;
131 
132   get_normalizer(klass);
133   m_row.m_stat.set(m_normalizer, pfs_stat);
134 
135   if (pfs->m_lock.end_optimistic_lock(&lock))
136     m_row_exists= true;
137 }
138 
139 /**
140   Build a row, for mutex statistics in a thread.
141   @param pfs              the mutex this cursor is reading
142 */
make_mutex_row(PFS_mutex * pfs)143 void table_events_waits_summary_by_instance::make_mutex_row(PFS_mutex *pfs)
144 {
145   PFS_mutex_class *safe_class;
146   safe_class= sanitize_mutex_class(pfs->m_class);
147   if (unlikely(safe_class == NULL))
148     return;
149 
150   make_instr_row(pfs, safe_class, pfs->m_identity, &pfs->m_mutex_stat.m_wait_stat);
151 }
152 
153 /**
154   Build a row, for rwlock statistics in a thread.
155   @param pfs              the rwlock this cursor is reading
156 */
make_rwlock_row(PFS_rwlock * pfs)157 void table_events_waits_summary_by_instance::make_rwlock_row(PFS_rwlock *pfs)
158 {
159   PFS_rwlock_class *safe_class;
160   safe_class= sanitize_rwlock_class(pfs->m_class);
161   if (unlikely(safe_class == NULL))
162     return;
163 
164   make_instr_row(pfs, safe_class, pfs->m_identity, &pfs->m_rwlock_stat.m_wait_stat);
165 }
166 
167 /**
168   Build a row, for condition statistics in a thread.
169   @param pfs              the condition this cursor is reading
170 */
make_cond_row(PFS_cond * pfs)171 void table_events_waits_summary_by_instance::make_cond_row(PFS_cond *pfs)
172 {
173   PFS_cond_class *safe_class;
174   safe_class= sanitize_cond_class(pfs->m_class);
175   if (unlikely(safe_class == NULL))
176     return;
177 
178   make_instr_row(pfs, safe_class, pfs->m_identity, &pfs->m_cond_stat.m_wait_stat);
179 }
180 
181 /**
182   Build a row, for file statistics in a thread.
183   @param pfs              the file this cursor is reading
184 */
make_file_row(PFS_file * pfs)185 void table_events_waits_summary_by_instance::make_file_row(PFS_file *pfs)
186 {
187   PFS_file_class *safe_class;
188   safe_class= sanitize_file_class(pfs->m_class);
189   if (unlikely(safe_class == NULL))
190     return;
191 
192   PFS_single_stat sum;
193   pfs->m_file_stat.m_io_stat.sum_waits(& sum);
194   /*
195     Files don't have a in memory structure associated to it,
196     so we use the address of the PFS_file buffer as object_instance_begin
197   */
198   make_instr_row(pfs, safe_class, pfs, & sum);
199 }
200 
201 /**
202   Build a row, for socket statistics in a thread.
203   @param pfs              the socket this cursor is reading
204 */
make_socket_row(PFS_socket * pfs)205 void table_events_waits_summary_by_instance::make_socket_row(PFS_socket *pfs)
206 {
207   PFS_socket_class *safe_class;
208   safe_class= sanitize_socket_class(pfs->m_class);
209   if (unlikely(safe_class == NULL))
210     return;
211 
212   /*
213      Consolidate wait times and byte counts for individual operations. This is
214      done by the consumer in order to reduce overhead on the socket instrument.
215   */
216   PFS_byte_stat pfs_stat;
217   pfs->m_socket_stat.m_io_stat.sum(&pfs_stat);
218 
219   /*
220     Sockets don't have an associated in-memory structure, so use the address of
221     the PFS_socket buffer as object_instance_begin.
222   */
223   make_instr_row(pfs, safe_class, pfs, &pfs_stat);
224 }
225 
226 int table_events_waits_summary_by_instance
read_row_values(TABLE * table,unsigned char *,Field ** fields,bool read_all)227 ::read_row_values(TABLE *table, unsigned char *, Field **fields,
228                   bool read_all)
229 {
230   Field *f;
231 
232   if (unlikely(! m_row_exists))
233     return HA_ERR_RECORD_DELETED;
234 
235   /* Set the null bits */
236   assert(table->s->null_bytes == 0);
237 
238   for (; (f= *fields) ; fields++)
239   {
240     if (read_all || bitmap_is_set(table->read_set, f->field_index))
241     {
242       switch(f->field_index)
243       {
244       case 0: /* NAME */
245         set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
246         break;
247       case 1: /* OBJECT_INSTANCE */
248         set_field_ulonglong(f, m_row.m_object_instance_addr);
249         break;
250       case 2: /* COUNT */
251         set_field_ulonglong(f, m_row.m_stat.m_count);
252         break;
253       case 3: /* SUM */
254         set_field_ulonglong(f, m_row.m_stat.m_sum);
255         break;
256       case 4: /* MIN */
257         set_field_ulonglong(f, m_row.m_stat.m_min);
258         break;
259       case 5: /* AVG */
260         set_field_ulonglong(f, m_row.m_stat.m_avg);
261         break;
262       case 6: /* MAX */
263         set_field_ulonglong(f, m_row.m_stat.m_max);
264         break;
265       default:
266         assert(false);
267       }
268     }
269   }
270 
271   return 0;
272 }
273 
274