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