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