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_sync_instances.cc
25   Table MUTEX_INSTANCES, RWLOCK_INSTANCES
26   and COND_INSTANCES (implementation).
27 */
28 
29 #include "my_global.h"
30 #include "my_thread.h"
31 #include "pfs_instr.h"
32 #include "pfs_column_types.h"
33 #include "pfs_column_values.h"
34 #include "table_sync_instances.h"
35 #include "pfs_global.h"
36 #include "pfs_buffer_container.h"
37 #include "field.h"
38 
39 THR_LOCK table_mutex_instances::m_table_lock;
40 
41 static const TABLE_FIELD_TYPE mutex_field_types[]=
42 {
43   {
44     { C_STRING_WITH_LEN("NAME") },
45     { C_STRING_WITH_LEN("varchar(128)") },
46     { NULL, 0}
47   },
48   {
49     { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") },
50     { C_STRING_WITH_LEN("bigint(20)") },
51     { NULL, 0}
52   },
53   {
54     { C_STRING_WITH_LEN("LOCKED_BY_THREAD_ID") },
55     { C_STRING_WITH_LEN("bigint(20)") },
56     { NULL, 0}
57   }
58 };
59 
60 TABLE_FIELD_DEF
61 table_mutex_instances::m_field_def=
62 { 3, mutex_field_types };
63 
64 PFS_engine_table_share
65 table_mutex_instances::m_share=
66 {
67   { C_STRING_WITH_LEN("mutex_instances") },
68   &pfs_readonly_acl,
69   table_mutex_instances::create,
70   NULL, /* write_row */
71   NULL, /* delete_all_rows */
72   table_mutex_instances::get_row_count,
73   sizeof(PFS_simple_index),
74   &m_table_lock,
75   &m_field_def,
76   false, /* checked */
77   false  /* perpetual */
78 };
79 
create(void)80 PFS_engine_table* table_mutex_instances::create(void)
81 {
82   return new table_mutex_instances();
83 }
84 
85 ha_rows
get_row_count(void)86 table_mutex_instances::get_row_count(void)
87 {
88   return global_mutex_container.get_row_count();
89 }
90 
table_mutex_instances()91 table_mutex_instances::table_mutex_instances()
92   : PFS_engine_table(&m_share, &m_pos),
93   m_row_exists(false), m_pos(0), m_next_pos(0)
94 {}
95 
reset_position(void)96 void table_mutex_instances::reset_position(void)
97 {
98   m_pos.m_index= 0;
99   m_next_pos.m_index= 0;
100 }
101 
rnd_next(void)102 int table_mutex_instances::rnd_next(void)
103 {
104   PFS_mutex *pfs;
105 
106   m_pos.set_at(&m_next_pos);
107   PFS_mutex_iterator it= global_mutex_container.iterate(m_pos.m_index);
108   pfs= it.scan_next(& m_pos.m_index);
109   if (pfs != NULL)
110   {
111     make_row(pfs);
112     m_next_pos.set_after(&m_pos);
113     return 0;
114   }
115 
116   return HA_ERR_END_OF_FILE;
117 }
118 
rnd_pos(const void * pos)119 int table_mutex_instances::rnd_pos(const void *pos)
120 {
121   PFS_mutex *pfs;
122 
123   set_position(pos);
124 
125   pfs= global_mutex_container.get(m_pos.m_index);
126   if (pfs != NULL)
127   {
128     make_row(pfs);
129     return 0;
130   }
131 
132   return HA_ERR_RECORD_DELETED;
133 }
134 
make_row(PFS_mutex * pfs)135 void table_mutex_instances::make_row(PFS_mutex *pfs)
136 {
137   pfs_optimistic_state lock;
138   PFS_mutex_class *safe_class;
139 
140   m_row_exists= false;
141 
142   /* Protect this reader against a mutex destroy */
143   pfs->m_lock.begin_optimistic_lock(&lock);
144 
145   safe_class= sanitize_mutex_class(pfs->m_class);
146   if (unlikely(safe_class == NULL))
147     return;
148 
149   m_row.m_name= safe_class->m_name;
150   m_row.m_name_length= safe_class->m_name_length;
151   m_row.m_identity= pfs->m_identity;
152 
153   /* Protect this reader against a mutex unlock */
154   PFS_thread *safe_owner= sanitize_thread(pfs->m_owner);
155   if (safe_owner)
156   {
157     m_row.m_locked_by_thread_id= safe_owner->m_thread_internal_id;
158     m_row.m_locked= true;
159   }
160   else
161     m_row.m_locked= false;
162 
163   if (pfs->m_lock.end_optimistic_lock(&lock))
164     m_row_exists= true;
165 }
166 
read_row_values(TABLE * table,unsigned char * buf,Field ** fields,bool read_all)167 int table_mutex_instances::read_row_values(TABLE *table,
168                                            unsigned char *buf,
169                                            Field **fields,
170                                            bool read_all)
171 {
172   Field *f;
173 
174   if (unlikely(! m_row_exists))
175     return HA_ERR_RECORD_DELETED;
176 
177   /* Set the null bits */
178   assert(table->s->null_bytes == 1);
179   buf[0]= 0;
180 
181   for (; (f= *fields) ; fields++)
182   {
183     if (read_all || bitmap_is_set(table->read_set, f->field_index))
184     {
185       switch(f->field_index)
186       {
187       case 0: /* NAME */
188         set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
189         break;
190       case 1: /* OBJECT_INSTANCE */
191         set_field_ulonglong(f, (intptr) m_row.m_identity);
192         break;
193       case 2: /* LOCKED_BY_THREAD_ID */
194         if (m_row.m_locked)
195           set_field_ulonglong(f, m_row.m_locked_by_thread_id);
196         else
197           f->set_null();
198         break;
199       default:
200         assert(false);
201       }
202     }
203   }
204 
205   return 0;
206 }
207 
208 THR_LOCK table_rwlock_instances::m_table_lock;
209 
210 static const TABLE_FIELD_TYPE rwlock_field_types[]=
211 {
212   {
213     { C_STRING_WITH_LEN("NAME") },
214     { C_STRING_WITH_LEN("varchar(128)") },
215     { NULL, 0}
216   },
217   {
218     { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") },
219     { C_STRING_WITH_LEN("bigint(20)") },
220     { NULL, 0}
221   },
222   {
223     { C_STRING_WITH_LEN("WRITE_LOCKED_BY_THREAD_ID") },
224     { C_STRING_WITH_LEN("bigint(20)") },
225     { NULL, 0}
226   },
227   {
228     { C_STRING_WITH_LEN("READ_LOCKED_BY_COUNT") },
229     { C_STRING_WITH_LEN("int(10)") },
230     { NULL, 0}
231   }
232 };
233 
234 TABLE_FIELD_DEF
235 table_rwlock_instances::m_field_def=
236 { 4, rwlock_field_types };
237 
238 PFS_engine_table_share
239 table_rwlock_instances::m_share=
240 {
241   { C_STRING_WITH_LEN("rwlock_instances") },
242   &pfs_readonly_acl,
243   table_rwlock_instances::create,
244   NULL, /* write_row */
245   NULL, /* delete_all_rows */
246   table_rwlock_instances::get_row_count,
247   sizeof(PFS_simple_index),
248   &m_table_lock,
249   &m_field_def,
250   false, /* checked */
251   false  /* perpetual */
252 };
253 
create(void)254 PFS_engine_table* table_rwlock_instances::create(void)
255 {
256   return new table_rwlock_instances();
257 }
258 
259 ha_rows
get_row_count(void)260 table_rwlock_instances::get_row_count(void)
261 {
262   return global_rwlock_container.get_row_count();
263 }
264 
table_rwlock_instances()265 table_rwlock_instances::table_rwlock_instances()
266   : PFS_engine_table(&m_share, &m_pos),
267   m_row_exists(false), m_pos(0), m_next_pos(0)
268 {}
269 
reset_position(void)270 void table_rwlock_instances::reset_position(void)
271 {
272   m_pos.m_index= 0;
273   m_next_pos.m_index= 0;
274 }
275 
rnd_next(void)276 int table_rwlock_instances::rnd_next(void)
277 {
278   PFS_rwlock *pfs;
279 
280   m_pos.set_at(&m_next_pos);
281   PFS_rwlock_iterator it= global_rwlock_container.iterate(m_pos.m_index);
282   pfs= it.scan_next(& m_pos.m_index);
283   if (pfs != NULL)
284   {
285     make_row(pfs);
286     m_next_pos.set_after(&m_pos);
287     return 0;
288   }
289 
290   return HA_ERR_END_OF_FILE;
291 }
292 
rnd_pos(const void * pos)293 int table_rwlock_instances::rnd_pos(const void *pos)
294 {
295   PFS_rwlock *pfs;
296 
297   set_position(pos);
298 
299   pfs= global_rwlock_container.get(m_pos.m_index);
300   if (pfs != NULL)
301   {
302     make_row(pfs);
303     return 0;
304   }
305 
306   return HA_ERR_RECORD_DELETED;
307 }
308 
make_row(PFS_rwlock * pfs)309 void table_rwlock_instances::make_row(PFS_rwlock *pfs)
310 {
311   pfs_optimistic_state lock;
312   PFS_rwlock_class *safe_class;
313 
314   m_row_exists= false;
315 
316   /* Protect this reader against a rwlock destroy */
317   pfs->m_lock.begin_optimistic_lock(&lock);
318 
319   safe_class= sanitize_rwlock_class(pfs->m_class);
320   if (unlikely(safe_class == NULL))
321     return;
322 
323   m_row.m_name= safe_class->m_name;
324   m_row.m_name_length= safe_class->m_name_length;
325   m_row.m_identity= pfs->m_identity;
326 
327   /* Protect this reader against a rwlock unlock in the writer */
328   PFS_thread *safe_writer= sanitize_thread(pfs->m_writer);
329   if (safe_writer)
330   {
331     m_row.m_write_locked_by_thread_id= safe_writer->m_thread_internal_id;
332     m_row.m_readers= 0;
333     m_row.m_write_locked= true;
334   }
335   else
336   {
337     m_row.m_readers= pfs->m_readers;
338     m_row.m_write_locked= false;
339   }
340 
341   if (pfs->m_lock.end_optimistic_lock(&lock))
342     m_row_exists= true;
343 }
344 
read_row_values(TABLE * table,unsigned char * buf,Field ** fields,bool read_all)345 int table_rwlock_instances::read_row_values(TABLE *table,
346                                              unsigned char *buf,
347                                              Field **fields,
348                                              bool read_all)
349 {
350   Field *f;
351 
352   if (unlikely(! m_row_exists))
353     return HA_ERR_RECORD_DELETED;
354 
355   /* Set the null bits */
356   assert(table->s->null_bytes == 1);
357   buf[0]= 0;
358 
359   for (; (f= *fields) ; fields++)
360   {
361     if (read_all || bitmap_is_set(table->read_set, f->field_index))
362     {
363       switch(f->field_index)
364       {
365       case 0: /* NAME */
366         set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
367         break;
368       case 1: /* OBJECT_INSTANCE */
369         set_field_ulonglong(f, (intptr) m_row.m_identity);
370         break;
371       case 2: /* WRITE_LOCKED_BY_THREAD_ID */
372         if (m_row.m_write_locked)
373           set_field_ulonglong(f, m_row.m_write_locked_by_thread_id);
374         else
375           f->set_null();
376         break;
377       case 3: /* READ_LOCKED_BY_COUNT */
378         set_field_ulong(f, m_row.m_readers);
379         break;
380       default:
381         assert(false);
382       }
383     }
384   }
385 
386   return 0;
387 }
388 
389 THR_LOCK table_cond_instances::m_table_lock;
390 
391 static const TABLE_FIELD_TYPE cond_field_types[]=
392 {
393   {
394     { C_STRING_WITH_LEN("NAME") },
395     { C_STRING_WITH_LEN("varchar(128)") },
396     { NULL, 0}
397   },
398   {
399     { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") },
400     { C_STRING_WITH_LEN("bigint(20)") },
401     { NULL, 0}
402   }
403 };
404 
405 TABLE_FIELD_DEF
406 table_cond_instances::m_field_def=
407 { 2, cond_field_types };
408 
409 PFS_engine_table_share
410 table_cond_instances::m_share=
411 {
412   { C_STRING_WITH_LEN("cond_instances") },
413   &pfs_readonly_acl,
414   table_cond_instances::create,
415   NULL, /* write_row */
416   NULL, /* delete_all_rows */
417   table_cond_instances::get_row_count,
418   sizeof(PFS_simple_index),
419   &m_table_lock,
420   &m_field_def,
421   false, /* checked */
422   false  /* perpetual */
423 };
424 
create(void)425 PFS_engine_table* table_cond_instances::create(void)
426 {
427   return new table_cond_instances();
428 }
429 
430 ha_rows
get_row_count(void)431 table_cond_instances::get_row_count(void)
432 {
433   return global_cond_container.get_row_count();
434 }
435 
table_cond_instances()436 table_cond_instances::table_cond_instances()
437   : PFS_engine_table(&m_share, &m_pos),
438   m_row_exists(false), m_pos(0), m_next_pos(0)
439 {}
440 
reset_position(void)441 void table_cond_instances::reset_position(void)
442 {
443   m_pos.m_index= 0;
444   m_next_pos.m_index= 0;
445 }
446 
rnd_next(void)447 int table_cond_instances::rnd_next(void)
448 {
449   PFS_cond *pfs;
450 
451   m_pos.set_at(&m_next_pos);
452   PFS_cond_iterator it= global_cond_container.iterate(m_pos.m_index);
453   pfs= it.scan_next(& m_pos.m_index);
454   if (pfs != NULL)
455   {
456     make_row(pfs);
457     m_next_pos.set_after(&m_pos);
458     return 0;
459   }
460 
461   return HA_ERR_END_OF_FILE;
462 }
463 
rnd_pos(const void * pos)464 int table_cond_instances::rnd_pos(const void *pos)
465 {
466   PFS_cond *pfs;
467 
468   set_position(pos);
469 
470   pfs= global_cond_container.get(m_pos.m_index);
471   if (pfs != NULL)
472   {
473     make_row(pfs);
474     return 0;
475   }
476 
477   return HA_ERR_RECORD_DELETED;
478 }
479 
make_row(PFS_cond * pfs)480 void table_cond_instances::make_row(PFS_cond *pfs)
481 {
482   pfs_optimistic_state lock;
483   PFS_cond_class *safe_class;
484 
485   m_row_exists= false;
486 
487   /* Protect this reader against a cond destroy */
488   pfs->m_lock.begin_optimistic_lock(&lock);
489 
490   safe_class= sanitize_cond_class(pfs->m_class);
491   if (unlikely(safe_class == NULL))
492     return;
493 
494   m_row.m_name= safe_class->m_name;
495   m_row.m_name_length= safe_class->m_name_length;
496   m_row.m_identity= pfs->m_identity;
497 
498   if (pfs->m_lock.end_optimistic_lock(&lock))
499     m_row_exists= true;
500 }
501 
read_row_values(TABLE * table,unsigned char *,Field ** fields,bool read_all)502 int table_cond_instances::read_row_values(TABLE *table,
503                                           unsigned char *,
504                                           Field **fields,
505                                           bool read_all)
506 {
507   Field *f;
508 
509   if (unlikely(! m_row_exists))
510     return HA_ERR_RECORD_DELETED;
511 
512   /* Set the null bits */
513   assert(table->s->null_bytes == 0);
514 
515   for (; (f= *fields) ; fields++)
516   {
517     if (read_all || bitmap_is_set(table->read_set, f->field_index))
518     {
519       switch(f->field_index)
520       {
521       case 0: /* NAME */
522         set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
523         break;
524       case 1: /* OBJECT_INSTANCE */
525         set_field_ulonglong(f, (intptr) m_row.m_identity);
526         break;
527       default:
528         assert(false);
529       }
530     }
531   }
532 
533   return 0;
534 }
535 
536