1 /* Copyright (c) 2008, 2014, 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/ha_perfschema.cc
18 Performance schema storage engine (implementation).
19 */
20
21 #include "my_global.h"
22 #include "my_pthread.h"
23 #include "my_atomic.h"
24 #include "sql_plugin.h"
25 #include "mysql/plugin.h"
26 #include "ha_perfschema.h"
27 #include "pfs_engine_table.h"
28 #include "pfs_column_values.h"
29 #include "pfs_instr_class.h"
30 #include "pfs_instr.h"
31
32 #ifdef MY_ATOMIC_MODE_DUMMY
33 /*
34 The performance schema can can not function with MY_ATOMIC_MODE_DUMMY,
35 a fully functional implementation of MY_ATOMIC should be used instead.
36 If the build fails with this error message:
37 - either use a different ./configure --with-atomic-ops option
38 - or do not build with the performance schema.
39 */
40 #error "The performance schema needs a functional MY_ATOMIC implementation."
41 #endif
42
43 handlerton *pfs_hton= NULL;
44
pfs_create_handler(handlerton * hton,TABLE_SHARE * table,MEM_ROOT * mem_root)45 static handler* pfs_create_handler(handlerton *hton,
46 TABLE_SHARE *table,
47 MEM_ROOT *mem_root)
48 {
49 return new (mem_root) ha_perfschema(hton, table);
50 }
51
compare_database_names(const char * name1,const char * name2)52 static int compare_database_names(const char *name1, const char *name2)
53 {
54 if (lower_case_table_names)
55 return strcasecmp(name1, name2);
56 return strcmp(name1, name2);
57 }
58
59 static const PFS_engine_table_share*
find_table_share(const char * db,const char * name)60 find_table_share(const char *db, const char *name)
61 {
62 DBUG_ENTER("find_table_share");
63
64 if (compare_database_names(db, PERFORMANCE_SCHEMA_str.str) != 0)
65 DBUG_RETURN(NULL);
66
67 const PFS_engine_table_share* result;
68 result= PFS_engine_table::find_engine_table_share(name);
69 DBUG_RETURN(result);
70 }
71
pfs_init_func(void * p)72 static int pfs_init_func(void *p)
73 {
74 DBUG_ENTER("pfs_init_func");
75
76 pfs_hton= reinterpret_cast<handlerton *> (p);
77
78 pfs_hton->state= SHOW_OPTION_YES;
79 pfs_hton->create= pfs_create_handler;
80 pfs_hton->show_status= pfs_show_status;
81 pfs_hton->flags= HTON_ALTER_NOT_SUPPORTED |
82 HTON_TEMPORARY_NOT_SUPPORTED |
83 HTON_NO_PARTITION;
84
85 /*
86 As long as the server implementation keeps using legacy_db_type,
87 as for example in mysql_truncate(),
88 we can not rely on the fact that different mysqld process will assign
89 consistently the same legacy_db_type for a given storage engine name.
90 In particular, using different --loose-skip-xxx options between
91 ./mysqld --bootstrap
92 ./mysqld
93 creates bogus .frm forms when bootstrapping the performance schema,
94 if we rely on ha_initialize_handlerton to assign a really dynamic value.
95 To fix this, a dedicated DB_TYPE is officially assigned to
96 the performance schema. See Bug#43039.
97 */
98 pfs_hton->db_type= DB_TYPE_PERFORMANCE_SCHEMA;
99
100 PFS_engine_table_share::init_all_locks();
101
102 DBUG_RETURN(0);
103 }
104
pfs_done_func(void * p)105 static int pfs_done_func(void *p)
106 {
107 DBUG_ENTER("pfs_done_func");
108
109 pfs_hton= NULL;
110
111 PFS_engine_table_share::delete_all_locks();
112
113 DBUG_RETURN(0);
114 }
115
116 static struct st_mysql_show_var pfs_status_vars[]=
117 {
118 {"Performance_schema_mutex_classes_lost",
119 (char*) &mutex_class_lost, SHOW_LONG_NOFLUSH},
120 {"Performance_schema_rwlock_classes_lost",
121 (char*) &rwlock_class_lost, SHOW_LONG_NOFLUSH},
122 {"Performance_schema_cond_classes_lost",
123 (char*) &cond_class_lost, SHOW_LONG_NOFLUSH},
124 {"Performance_schema_thread_classes_lost",
125 (char*) &thread_class_lost, SHOW_LONG_NOFLUSH},
126 {"Performance_schema_file_classes_lost",
127 (char*) &file_class_lost, SHOW_LONG_NOFLUSH},
128 {"Performance_schema_mutex_instances_lost",
129 (char*) &mutex_lost, SHOW_LONG},
130 {"Performance_schema_rwlock_instances_lost",
131 (char*) &rwlock_lost, SHOW_LONG},
132 {"Performance_schema_cond_instances_lost",
133 (char*) &cond_lost, SHOW_LONG},
134 {"Performance_schema_thread_instances_lost",
135 (char*) &thread_lost, SHOW_LONG},
136 {"Performance_schema_file_instances_lost",
137 (char*) &file_lost, SHOW_LONG},
138 {"Performance_schema_file_handles_lost",
139 (char*) &file_handle_lost, SHOW_LONG},
140 {"Performance_schema_locker_lost",
141 (char*) &locker_lost, SHOW_LONG},
142 /* table shares, can be flushed */
143 {"Performance_schema_table_instances_lost",
144 (char*) &table_share_lost, SHOW_LONG},
145 /* table handles, can be flushed */
146 {"Performance_schema_table_handles_lost",
147 (char*) &table_lost, SHOW_LONG},
148 {NullS, NullS, SHOW_LONG}
149 };
150
151 struct st_mysql_storage_engine pfs_storage_engine=
152 { MYSQL_HANDLERTON_INTERFACE_VERSION };
153
154 const char* pfs_engine_name= "PERFORMANCE_SCHEMA";
155
mysql_declare_plugin(perfschema)156 mysql_declare_plugin(perfschema)
157 {
158 MYSQL_STORAGE_ENGINE_PLUGIN,
159 &pfs_storage_engine,
160 pfs_engine_name,
161 "Marc Alff, Oracle", /* Formerly Sun Microsystems, formerly MySQL */
162 "Performance Schema",
163 PLUGIN_LICENSE_GPL,
164 pfs_init_func, /* Plugin Init */
165 pfs_done_func, /* Plugin Deinit */
166 0x0001 /* 0.1 */,
167 pfs_status_vars, /* status variables */
168 NULL, /* system variables */
169 NULL, /* config options */
170 0, /* flags */
171 }
172 mysql_declare_plugin_end;
173
ha_perfschema(handlerton * hton,TABLE_SHARE * share)174 ha_perfschema::ha_perfschema(handlerton *hton, TABLE_SHARE *share)
175 : handler(hton, share), m_table_share(NULL), m_table(NULL)
176 {}
177
~ha_perfschema()178 ha_perfschema::~ha_perfschema()
179 {}
180
181 static const char *ha_pfs_exts[]= {
182 NullS
183 };
184
bas_ext() const185 const char **ha_perfschema::bas_ext() const
186 {
187 return ha_pfs_exts;
188 }
189
open(const char * name,int mode,uint test_if_locked)190 int ha_perfschema::open(const char *name, int mode, uint test_if_locked)
191 {
192 DBUG_ENTER("ha_perfschema::open");
193
194 m_table_share= find_table_share(table_share->db.str,
195 table_share->table_name.str);
196 if (! m_table_share)
197 DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
198
199 thr_lock_data_init(m_table_share->m_thr_lock_ptr, &m_thr_lock, NULL);
200 ref_length= m_table_share->m_ref_length;
201
202 psi_open();
203
204 DBUG_RETURN(0);
205 }
206
close(void)207 int ha_perfschema::close(void)
208 {
209 DBUG_ENTER("ha_perfschema::close");
210 m_table_share= NULL;
211 delete m_table;
212 m_table= NULL;
213
214 psi_close();
215
216 DBUG_RETURN(0);
217 }
218
write_row(uchar * buf)219 int ha_perfschema::write_row(uchar *buf)
220 {
221 int result;
222
223 DBUG_ENTER("ha_perfschema::write_row");
224
225 ha_statistic_increment(&SSV::ha_write_count);
226 DBUG_ASSERT(m_table_share);
227
228 if (m_table_share->m_write_row)
229 result= m_table_share->m_write_row(table, buf, table->field);
230 else
231 {
232 result= HA_ERR_WRONG_COMMAND;
233 }
234
235 DBUG_RETURN(result);
236 }
237
use_hidden_primary_key(void)238 void ha_perfschema::use_hidden_primary_key(void)
239 {
240 /*
241 This is also called in case of row based replication,
242 see TABLE::mark_columns_needed_for_update().
243 Add all columns to the read set, but do not touch the write set,
244 as some columns in the SETUP_ tables are not writable.
245 */
246 table->column_bitmaps_set_no_signal(&table->s->all_set, table->write_set);
247 }
248
update_row(const uchar * old_data,uchar * new_data)249 int ha_perfschema::update_row(const uchar *old_data, uchar *new_data)
250 {
251 DBUG_ENTER("ha_perfschema::update_row");
252
253 if (is_executed_by_slave())
254 DBUG_RETURN(0);
255
256 DBUG_ASSERT(m_table);
257 int result= m_table->update_row(table, old_data, new_data, table->field);
258 DBUG_RETURN(result);
259 }
260
rnd_init(bool scan)261 int ha_perfschema::rnd_init(bool scan)
262 {
263 int result;
264 DBUG_ENTER("ha_perfschema::rnd_init");
265
266 DBUG_ASSERT(m_table_share);
267 DBUG_ASSERT(m_table_share->m_open_table != NULL);
268
269 stats.records= 0;
270 if (m_table == NULL)
271 m_table= m_table_share->m_open_table();
272 else
273 m_table->reset_position();
274
275 result= m_table ? 0 : HA_ERR_OUT_OF_MEM;
276 DBUG_RETURN(result);
277 }
278
rnd_end(void)279 int ha_perfschema::rnd_end(void)
280 {
281 DBUG_ENTER("ha_perfschema::rnd_end");
282 DBUG_ASSERT(m_table);
283 delete m_table;
284 m_table= NULL;
285 DBUG_RETURN(0);
286 }
287
rnd_next(uchar * buf)288 int ha_perfschema::rnd_next(uchar *buf)
289 {
290 DBUG_ENTER("ha_perfschema::rnd_next");
291
292 DBUG_ASSERT(m_table);
293 int result= m_table->rnd_next();
294 if (result == 0)
295 {
296 result= m_table->read_row(table, buf, table->field);
297 if (result == 0)
298 stats.records++;
299 }
300 DBUG_RETURN(result);
301 }
302
position(const uchar * record)303 void ha_perfschema::position(const uchar *record)
304 {
305 DBUG_ENTER("ha_perfschema::position");
306
307 DBUG_ASSERT(m_table);
308 m_table->get_position(ref);
309 DBUG_VOID_RETURN;
310 }
311
rnd_pos(uchar * buf,uchar * pos)312 int ha_perfschema::rnd_pos(uchar *buf, uchar *pos)
313 {
314 DBUG_ENTER("ha_perfschema::rnd_pos");
315
316 DBUG_ASSERT(m_table);
317 int result= m_table->rnd_pos(pos);
318 if (result == 0)
319 result= m_table->read_row(table, buf, table->field);
320 DBUG_RETURN(result);
321 }
322
info(uint flag)323 int ha_perfschema::info(uint flag)
324 {
325 DBUG_ENTER("ha_perfschema::info");
326 DBUG_ASSERT(m_table_share);
327 if (flag & HA_STATUS_VARIABLE)
328 stats.records= m_table_share->m_records;
329 if (flag & HA_STATUS_CONST)
330 ref_length= m_table_share->m_ref_length;
331 DBUG_RETURN(0);
332 }
333
delete_all_rows(void)334 int ha_perfschema::delete_all_rows(void)
335 {
336 int result;
337
338 DBUG_ENTER("ha_perfschema::delete_all_rows");
339
340 if (is_executed_by_slave())
341 DBUG_RETURN(0);
342
343 DBUG_ASSERT(m_table_share);
344 if (m_table_share->m_delete_all_rows)
345 result= m_table_share->m_delete_all_rows();
346 else
347 {
348 result= HA_ERR_WRONG_COMMAND;
349 }
350 DBUG_RETURN(result);
351 }
352
truncate()353 int ha_perfschema::truncate()
354 {
355 return delete_all_rows();
356 }
357
store_lock(THD * thd,THR_LOCK_DATA ** to,enum thr_lock_type lock_type)358 THR_LOCK_DATA **ha_perfschema::store_lock(THD *thd,
359 THR_LOCK_DATA **to,
360 enum thr_lock_type lock_type)
361 {
362 if (lock_type != TL_IGNORE && m_thr_lock.type == TL_UNLOCK)
363 m_thr_lock.type= lock_type;
364 *to++= &m_thr_lock;
365 m_thr_lock.m_psi= m_psi;
366 return to;
367 }
368
delete_table(const char * name)369 int ha_perfschema::delete_table(const char *name)
370 {
371 DBUG_ENTER("ha_perfschema::delete_table");
372 DBUG_RETURN(0);
373 }
374
rename_table(const char * from,const char * to)375 int ha_perfschema::rename_table(const char * from, const char * to)
376 {
377 DBUG_ENTER("ha_perfschema::rename_table ");
378 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
379 }
380
create(const char * name,TABLE * table_arg,HA_CREATE_INFO * create_info)381 int ha_perfschema::create(const char *name, TABLE *table_arg,
382 HA_CREATE_INFO *create_info)
383 {
384 DBUG_ENTER("ha_perfschema::create");
385 DBUG_ASSERT(table_arg);
386 DBUG_ASSERT(table_arg->s);
387 if (find_table_share(table_arg->s->db.str,
388 table_arg->s->table_name.str))
389 {
390 /*
391 Attempting to create a known performance schema table.
392 Allowing the create, to create .FRM files,
393 for the initial database install, and mysql_upgrade.
394 This should fail once .FRM are removed.
395 */
396 DBUG_RETURN(0);
397 }
398 /*
399 This is not a general purpose engine.
400 Failure to CREATE TABLE is the expected result.
401 */
402 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
403 }
404
print_error(int error,myf errflag)405 void ha_perfschema::print_error(int error, myf errflag)
406 {
407 switch (error)
408 {
409 case HA_ERR_TABLE_NEEDS_UPGRADE:
410 /*
411 The error message for ER_TABLE_NEEDS_UPGRADE refers to REPAIR table,
412 which does not apply to performance schema tables.
413 */
414 my_error(ER_WRONG_NATIVE_TABLE_STRUCTURE, MYF(0),
415 table_share->db.str, table_share->table_name.str);
416 break;
417 case HA_ERR_WRONG_COMMAND:
418 /*
419 The performance schema is not a general purpose storage engine,
420 some operations are not supported, by design.
421 We do not want to print "Command not supported",
422 which gives the impression that a command implementation is missing,
423 and that the failure should be considered a bug.
424 We print "Invalid performance_schema usage." instead,
425 to emphasise that the operation attempted is not meant to be legal,
426 and that the failure returned is indeed the expected result.
427 */
428 my_error(ER_WRONG_PERFSCHEMA_USAGE, MYF(0));
429 break;
430 default:
431 handler::print_error(error, errflag);
432 break;
433 }
434 }
435
436