Drizzled Public API Documentation

data_dictionary.cc
1 /*****************************************************************************
2 
3 Copyright (C) 2007, 2009, Innobase Oy. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15 St, Fifth Floor, Boston, MA 02110-1301 USA
16 
17 *****************************************************************************/
18 
19 #include <config.h>
20 
21 #include "data_dictionary.h"
22 
23 #include <drizzled/current_session.h>
24 
25 #include "trx0i_s.h"
26 #include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */
27 #include "buf0buddy.h" /* for i_s_cmpmem */
28 #include "buf0buf.h" /* for buf_pool and PAGE_ZIP_MIN_SIZE */
29 #include "ha_prototypes.h" /* for innobase_convert_name() */
30 #include "srv0start.h" /* for srv_was_started */
31 #include "btr0pcur.h" /* for file sys_tables related info. */
32 #include "btr0types.h"
33 #include "dict0load.h" /* for file sys_tables related info. */
34 #include "dict0mem.h"
35 #include "dict0types.h"
36 #include "handler0vars.h"
37 
38 using namespace drizzled;
39 
40 InnodbSysTablesTool::InnodbSysTablesTool() :
41  plugin::TableFunction("DATA_DICTIONARY", "INNODB_SYS_TABLES")
42 {
43  add_field("TABLE_ID", plugin::TableFunction::NUMBER, 0, false);
44  add_field("NAME", plugin::TableFunction::STRING, NAME_LEN + 1, false);
45  add_field("FLAG", plugin::TableFunction::NUMBER, 0, false);
46  add_field("N_COLS", plugin::TableFunction::NUMBER, 0, false);
47  add_field("SPACE", plugin::TableFunction::NUMBER, 0, false);
48 }
49 
50 InnodbSysTablesTool::Generator::Generator(Field **arg) :
51  plugin::TableFunction::Generator(arg)
52 {
53  heap= NULL;
54 }
55 
56 bool InnodbSysTablesTool::Generator::populate()
57 {
58  if (heap == NULL)
59  {
60  heap = mem_heap_create(1000);
61  mutex_enter(&(dict_sys->mutex));
62  mtr_start(&mtr);
63 
64  rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
65  }
66  else
67  {
68  /* Get the next record */
69  mutex_enter(&dict_sys->mutex);
70  mtr_start(&mtr);
71  rec = dict_getnext_system(&pcur, &mtr);
72  }
73 
74  if (! rec)
75  {
76  mtr_commit(&mtr);
77  mutex_exit(&dict_sys->mutex);
78  mem_heap_free(heap);
79  return false;
80  }
81 
82  const char* err_msg;
83  dict_table_t* table_rec;
84 
85  /* Create and populate a dict_table_t structure with
86  information from SYS_TABLES row */
87  err_msg = dict_process_sys_tables_rec(heap, rec, &table_rec,
89 
90  mtr_commit(&mtr);
91  mutex_exit(&dict_sys->mutex);
92 
93  if (!err_msg) {
94  push(table_rec->id);
95  push(table_rec->name);
96  push(static_cast<uint64_t>(table_rec->flags));
97  push(static_cast<uint64_t>(table_rec->n_cols));
98  push(static_cast<uint64_t>(table_rec->space));
99  } else {
100 /* push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
101  ER_CANT_FIND_SYSTEM_REC,
102  err_msg);
103 */ }
104 
105  /* Since dict_process_sys_tables_rec() is called with
106  DICT_TABLE_LOAD_FROM_RECORD, the table_rec is created in
107  dict_process_sys_tables_rec(), we will need to free it */
108  if (table_rec) {
109  dict_mem_table_free(table_rec);
110  }
111 
112  mem_heap_empty(heap);
113 
114  return true;
115 }
116 
117 InnodbSysTableStatsTool::InnodbSysTableStatsTool() :
118  plugin::TableFunction("DATA_DICTIONARY", "INNODB_SYS_TABLESTATS")
119 {
120  add_field("TABLE_ID", plugin::TableFunction::NUMBER, 0, false);
121  add_field("NAME", plugin::TableFunction::STRING, NAME_LEN + 1, false);
122  add_field("STATS_INITIALIZED", plugin::TableFunction::STRING, NAME_LEN + 1, false);
123  add_field("NUM_ROWS", plugin::TableFunction::NUMBER, 0, false);
124  add_field("CLUST_INDEX_SIZE", plugin::TableFunction::NUMBER, 0, false);
125  add_field("OTHER_INDEX_SIZE", plugin::TableFunction::NUMBER, 0, false);
126  add_field("MODIFIED_COUNTER", plugin::TableFunction::NUMBER, 0, false);
127  add_field("AUTOINC", plugin::TableFunction::NUMBER, 0, false);
128  add_field("HANDLES_OPENED", plugin::TableFunction::NUMBER, 0, false);
129 }
130 
131 InnodbSysTableStatsTool::Generator::Generator(Field **arg) :
132  plugin::TableFunction::Generator(arg)
133 {
134  heap= NULL;
135 }
136 
137 bool InnodbSysTableStatsTool::Generator::populate()
138 {
139  if (heap == NULL)
140  {
141  heap = mem_heap_create(1000);
142  mutex_enter(&dict_sys->mutex);
143  mtr_start(&mtr);
144  rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
145  }
146  else
147  {
148  /* Get the next record */
149  mutex_enter(&dict_sys->mutex);
150  mtr_start(&mtr);
151  rec = dict_getnext_system(&pcur, &mtr);
152  }
153 
154  if (!rec)
155  {
156  mtr_commit(&mtr);
157  mutex_exit(&dict_sys->mutex);
158  mem_heap_free(heap);
159  return false;
160  }
161 
162  const char* err_msg;
163  dict_table_t* table_rec;
164 
165  /* Fetch the dict_table_t structure corresponding to
166  this SYS_TABLES record */
167  err_msg = dict_process_sys_tables_rec(heap, rec, &table_rec,
169 
170  mtr_commit(&mtr);
171  mutex_exit(&dict_sys->mutex);
172 
173  if (!err_msg) {
174  push(table_rec->id);
175  push(table_rec->name);
176  if (table_rec->stat_initialized)
177  push("Initialized");
178  else
179  push("Uninitialized");
180  push(table_rec->stat_n_rows);
181  push(static_cast<uint64_t>(table_rec->stat_clustered_index_size));
182  push(static_cast<uint64_t>(table_rec->stat_sum_of_other_index_sizes));
183  push(static_cast<uint64_t>(table_rec->stat_modified_counter));
184  push(table_rec->autoinc);
185  push(static_cast<uint64_t>(table_rec->n_mysql_handles_opened));
186  } else {
187  /* push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
188  ER_CANT_FIND_SYSTEM_REC,
189  err_msg);*/
190  }
191 
192  mem_heap_empty(heap);
193 
194  return true;
195 }
196 
197 InnodbSysIndexesTool::InnodbSysIndexesTool() :
198  plugin::TableFunction("DATA_DICTIONARY", "INNODB_SYS_INDEXES")
199 {
200  add_field("INDEX_ID", plugin::TableFunction::NUMBER, 0, false);
201  add_field("NAME", plugin::TableFunction::STRING, NAME_LEN + 1, false);
202  add_field("TABLE_ID", plugin::TableFunction::NUMBER, 0, false);
203  add_field("TYPE", plugin::TableFunction::NUMBER, 0, false);
204  add_field("N_FIELDS", plugin::TableFunction::NUMBER, 0, false);
205  add_field("PAGE_NO", plugin::TableFunction::NUMBER, 0, false);
206  add_field("SPACE", plugin::TableFunction::NUMBER, 0, false);
207 }
208 
209 InnodbSysIndexesTool::Generator::Generator(Field **arg) :
210  plugin::TableFunction::Generator(arg)
211 {
212  heap= NULL;
213 }
214 
215 bool InnodbSysIndexesTool::Generator::populate()
216 {
217  if (heap == NULL)
218  {
219  heap = mem_heap_create(1000);
220  mutex_enter(&dict_sys->mutex);
221  mtr_start(&mtr);
222 
223  /* Start scan the SYS_INDEXES table */
224  rec = dict_startscan_system(&pcur, &mtr, SYS_INDEXES);
225  }
226  else
227  {
228  /* Get the next record */
229  mutex_enter(&dict_sys->mutex);
230  mtr_start(&mtr);
231  rec = dict_getnext_system(&pcur, &mtr);
232  }
233 
234  if (! rec)
235  {
236  mtr_commit(&mtr);
237  mutex_exit(&dict_sys->mutex);
238  mem_heap_free(heap);
239  return false;
240  }
241 
242  const char* err_msg;;
243  table_id_t table_id;
244  dict_index_t index_rec;
245 
246  /* Populate a dict_index_t structure with information from
247  a SYS_INDEXES row */
248  err_msg = dict_process_sys_indexes_rec(heap, rec, &index_rec,
249  &table_id);
250 
251  mtr_commit(&mtr);
252  mutex_exit(&dict_sys->mutex);
253  if (!err_msg) {
254  push(index_rec.id);
255  push(index_rec.name);
256  push(static_cast<uint64_t>(table_id));
257  push(static_cast<uint64_t>(index_rec.type));
258  push(static_cast<uint64_t>(index_rec.n_fields));
259  push(static_cast<uint64_t>(index_rec.page));
260  push(static_cast<uint64_t>(index_rec.space));
261  } else {
262 /* push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
263  ER_CANT_FIND_SYSTEM_REC,
264  err_msg);*/
265  }
266 
267  mem_heap_empty(heap);
268 
269  if (!rec)
270  {
271  mtr_commit(&mtr);
272  mutex_exit(&dict_sys->mutex);
273  mem_heap_free(heap);
274  return false;
275  }
276 
277  return true;
278 }
279 
280 InnodbSysColumnsTool::InnodbSysColumnsTool() :
281  plugin::TableFunction("DATA_DICTIONARY", "INNODB_SYS_COLUMNS")
282 {
283  add_field("TABLE_ID", plugin::TableFunction::NUMBER, 0, false);
284  add_field("NAME", plugin::TableFunction::STRING, NAME_LEN + 1, false);
285  add_field("POS", plugin::TableFunction::NUMBER, 0, false);
286  add_field("MTYPE", plugin::TableFunction::NUMBER, 0, false);
287  add_field("PRTYPE", plugin::TableFunction::NUMBER, 0, false);
288  add_field("LEN", plugin::TableFunction::NUMBER, 0, false);
289 }
290 
291 InnodbSysColumnsTool::Generator::Generator(Field **arg) :
292  plugin::TableFunction::Generator(arg)
293 {
294  heap= NULL;
295 }
296 
297 bool InnodbSysColumnsTool::Generator::populate()
298 {
299  if (heap == NULL)
300  {
301  heap = mem_heap_create(1000);
302  mutex_enter(&dict_sys->mutex);
303  mtr_start(&mtr);
304  rec = dict_startscan_system(&pcur, &mtr, SYS_COLUMNS);
305  }
306  else
307  {
308  /* Get the next record */
309  mutex_enter(&dict_sys->mutex);
310  mtr_start(&mtr);
311  rec = dict_getnext_system(&pcur, &mtr);
312  }
313 
314  if (! rec)
315  {
316  mtr_commit(&mtr);
317  mutex_exit(&dict_sys->mutex);
318  mem_heap_free(heap);
319  return false;
320  }
321 
322  const char* err_msg;
323  dict_col_t column_rec;
324  table_id_t table_id;
325  const char* col_name;
326 
327  /* populate a dict_col_t structure with information from
328  a SYS_COLUMNS row */
329  err_msg = dict_process_sys_columns_rec(heap, rec, &column_rec,
330  &table_id, &col_name);
331 
332  mtr_commit(&mtr);
333  mutex_exit(&dict_sys->mutex);
334 
335  if (!err_msg) {
336  push(table_id);
337  push(col_name);
338  push(static_cast<uint64_t>(column_rec.ind));
339  push(static_cast<uint64_t>(column_rec.mtype));
340  push(static_cast<uint64_t>(column_rec.prtype));
341  push(static_cast<uint64_t>(column_rec.len));
342  } else {
343 /* push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
344  ER_CANT_FIND_SYSTEM_REC,
345  err_msg);*/
346  }
347 
348  mem_heap_empty(heap);
349 
350  return true;
351 }
352 
353 InnodbSysFieldsTool::InnodbSysFieldsTool() :
354  plugin::TableFunction("DATA_DICTIONARY", "INNODB_SYS_FIELDS")
355 {
356  add_field("INDEX_ID", plugin::TableFunction::NUMBER, 0, false);
357  add_field("NAME", plugin::TableFunction::STRING, NAME_LEN + 1, false);
358  add_field("POS", plugin::TableFunction::NUMBER, 0, false);
359 }
360 
361 InnodbSysFieldsTool::Generator::Generator(Field **arg) :
362  plugin::TableFunction::Generator(arg)
363 {
364  heap= NULL;
365 }
366 
367 bool InnodbSysFieldsTool::Generator::populate()
368 {
369  if (heap == NULL)
370  {
371  heap = mem_heap_create(1000);
372  mutex_enter(&dict_sys->mutex);
373  mtr_start(&mtr);
374 
375  /* will save last index id so that we know whether we move to
376  the next index. This is used to calculate prefix length */
377  last_id = 0;
378 
379  rec = dict_startscan_system(&pcur, &mtr, SYS_FIELDS);
380  }
381  else
382  {
383  /* Get the next record */
384  mutex_enter(&dict_sys->mutex);
385  mtr_start(&mtr);
386  rec = dict_getnext_system(&pcur, &mtr);
387  }
388 
389  if (! rec)
390  {
391  mtr_commit(&mtr);
392  mutex_exit(&dict_sys->mutex);
393  mem_heap_free(heap);
394 
395  return false;
396  }
397 
398  ulint pos;
399  const char* err_msg;
400  index_id_t index_id;
401  dict_field_t field_rec;
402 
403  /* Populate a dict_field_t structure with information from
404  a SYS_FIELDS row */
405  err_msg = dict_process_sys_fields_rec(heap, rec, &field_rec,
406  &pos, &index_id, last_id);
407 
408  mtr_commit(&mtr);
409  mutex_exit(&dict_sys->mutex);
410 
411  if (!err_msg) {
412  push(index_id);
413  push(field_rec.name);
414  push(static_cast<uint64_t>(pos));
415 
416  last_id = index_id;
417  } else {
418 /* push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
419  ER_CANT_FIND_SYSTEM_REC,
420  err_msg);*/
421  }
422 
423  mem_heap_empty(heap);
424 
425  return true;
426 }
427 
428 InnodbSysForeignTool::InnodbSysForeignTool() :
429  plugin::TableFunction("DATA_DICTIONARY", "INNODB_SYS_FOREIGN")
430 {
431  add_field("ID", plugin::TableFunction::STRING, NAME_LEN + 1, false);
432  add_field("FOR_NAME", plugin::TableFunction::STRING, NAME_LEN + 1, false);
433  add_field("REF_NAME", plugin::TableFunction::STRING, NAME_LEN + 1, false);
434  add_field("N_COLS", plugin::TableFunction::NUMBER, 0, false);
435  add_field("TYPE", plugin::TableFunction::NUMBER, 0, false);
436 }
437 
438 InnodbSysForeignTool::Generator::Generator(Field **arg) :
439  plugin::TableFunction::Generator(arg)
440 {
441  heap= NULL;
442 }
443 
444 bool InnodbSysForeignTool::Generator::populate()
445 {
446  if (heap == NULL)
447  {
448  heap = mem_heap_create(1000);
449  mutex_enter(&dict_sys->mutex);
450  mtr_start(&mtr);
451 
452  rec = dict_startscan_system(&pcur, &mtr, SYS_FOREIGN);
453  }
454  else
455  {
456  /* Get the next record */
457  mtr_start(&mtr);
458  mutex_enter(&dict_sys->mutex);
459  rec = dict_getnext_system(&pcur, &mtr);
460  }
461 
462  if (! rec)
463  {
464  mtr_commit(&mtr);
465  mutex_exit(&dict_sys->mutex);
466  mem_heap_free(heap);
467  return false;
468  }
469 
470  const char* err_msg;
471  dict_foreign_t foreign_rec;
472 
473  /* Populate a dict_foreign_t structure with information from
474  a SYS_FOREIGN row */
475  err_msg = dict_process_sys_foreign_rec(heap, rec, &foreign_rec);
476 
477  mtr_commit(&mtr);
478  mutex_exit(&dict_sys->mutex);
479 
480  if (!err_msg) {
481  push(foreign_rec.id);
482  push(foreign_rec.foreign_table_name);
483  push(foreign_rec.referenced_table_name);
484  push(static_cast<uint64_t>(foreign_rec.n_fields));
485  push(static_cast<uint64_t>(foreign_rec.type));
486  } else {
487 /* push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
488  ER_CANT_FIND_SYSTEM_REC,
489  err_msg);
490 */ }
491 
492  mem_heap_empty(heap);
493 
494  return true;
495 }
496 
497 InnodbSysForeignColsTool::InnodbSysForeignColsTool() :
498  plugin::TableFunction("DATA_DICTIONARY", "INNODB_SYS_FOREIGN_COLS")
499 {
500  add_field("ID", plugin::TableFunction::STRING, NAME_LEN + 1, false);
501  add_field("FOR_COL_NAME", plugin::TableFunction::STRING, NAME_LEN + 1, false);
502  add_field("REF_COL_NAME", plugin::TableFunction::STRING, NAME_LEN + 1, false);
503  add_field("POS", plugin::TableFunction::NUMBER, 0, false);
504 }
505 
506 InnodbSysForeignColsTool::Generator::Generator(Field **arg) :
507  plugin::TableFunction::Generator(arg)
508 {
509  heap= NULL;
510 }
511 
512 bool InnodbSysForeignColsTool::Generator::populate()
513 {
514  if (heap == NULL)
515  {
516  heap = mem_heap_create(1000);
517  mutex_enter(&dict_sys->mutex);
518  mtr_start(&mtr);
519 
520  rec = dict_startscan_system(&pcur, &mtr, SYS_FOREIGN_COLS);
521  }
522  else
523  {
524  /* Get the next record */
525  mutex_enter(&dict_sys->mutex);
526  mtr_start(&mtr);
527  rec = dict_getnext_system(&pcur, &mtr);
528  }
529 
530  if (! rec)
531  {
532  mtr_commit(&mtr);
533  mutex_exit(&dict_sys->mutex);
534  mem_heap_free(heap);
535 
536  return false;
537  }
538 
539  const char* err_msg;
540  const char* name;
541  const char* for_col_name;
542  const char* ref_col_name;
543  ulint pos;
544 
545  /* Extract necessary information from a SYS_FOREIGN_COLS row */
546  err_msg = dict_process_sys_foreign_col_rec(heap, rec, &name, &for_col_name,
547  &ref_col_name, &pos);
548 
549  mtr_commit(&mtr);
550  mutex_exit(&dict_sys->mutex);
551 
552  if (!err_msg) {
553  push(name);
554  push(for_col_name);
555  push(ref_col_name);
556  push(static_cast<uint64_t>(pos));
557  } else {
558 /* push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
559  ER_CANT_FIND_SYSTEM_REC,
560  err_msg);
561 */
562  }
563 
564  mem_heap_empty(heap);
565 
566  return true;
567 }
568 
569 /*
570  * Fill the dynamic table data_dictionary.INNODB_CMP and INNODB_CMP_RESET
571  *
572  */
573 CmpTool::CmpTool(bool in_reset) :
574  plugin::TableFunction("DATA_DICTIONARY", in_reset ? "INNODB_CMP_RESET" : "INNODB_CMP"),
575  outer_reset(in_reset)
576 {
577  add_field("PAGE_SIZE", plugin::TableFunction::NUMBER, 0, false);
578  add_field("COMPRESS_OPS", plugin::TableFunction::NUMBER, 0, false);
579  add_field("COMPRESS_OPS_OK", plugin::TableFunction::NUMBER, 0, false);
580  add_field("COMPRESS_TIME", plugin::TableFunction::NUMBER, 0, false);
581  add_field("UNCOMPRESS_OPS", plugin::TableFunction::NUMBER, 0, false);
582  add_field("UNCOMPRESS_TIME", plugin::TableFunction::NUMBER, 0, false);
583 }
584 
585 CmpTool::Generator::Generator(Field **arg, bool in_reset) :
586  plugin::TableFunction::Generator(arg),
587  record_number(0),
588  inner_reset(in_reset)
589 {
590 }
591 
592 bool CmpTool::Generator::populate()
593 {
594  if (record_number == (PAGE_ZIP_NUM_SSIZE - 1))
595  {
596  return false;
597  }
598 
599  page_zip_stat_t* zip_stat = &page_zip_stat[record_number];
600 
601  push(static_cast<uint64_t>(PAGE_ZIP_MIN_SIZE << record_number));
602 
603  /* The cumulated counts are not protected by any
604  mutex. Thus, some operation in page0zip.c could
605  increment a counter between the time we read it and
606  clear it. We could introduce mutex protection, but it
607  could cause a measureable performance hit in
608  page0zip.c. */
609  push(static_cast<uint64_t>(zip_stat->compressed));
610  push(static_cast<uint64_t>(zip_stat->compressed_ok));
611  push(zip_stat->compressed_usec / 1000000);
612  push(static_cast<uint64_t>(zip_stat->decompressed));
613  push(zip_stat->decompressed_usec / 1000000);
614 
615  if (inner_reset)
616  {
617  memset(zip_stat, 0, sizeof *zip_stat);
618  }
619 
620  record_number++;
621 
622  return true;
623 }
624 
625 /*
626  * Fill the dynamic table data_dictionary.INNODB_CMPMEM and INNODB_CMPMEM_RESET
627  *
628  */
629 CmpmemTool::CmpmemTool(bool in_reset) :
630  plugin::TableFunction("DATA_DICTIONARY", in_reset ? "INNODB_CMPMEM_RESET" : "INNODB_CMPMEM"),
631  outer_reset(in_reset)
632 {
633  add_field("BUF_POOL", plugin::TableFunction::NUMBER, 0, false);
634  add_field("PAGE_SIZE", plugin::TableFunction::NUMBER, 0, false);
635  add_field("PAGES_USED", plugin::TableFunction::NUMBER, 0, false);
636  add_field("PAGES_FREE", plugin::TableFunction::NUMBER, 0, false);
637  add_field("RELOCATION_OPS", plugin::TableFunction::NUMBER, 0, false);
638  add_field("RELOCATION_TIME", plugin::TableFunction::NUMBER, 0, false);
639 }
640 
641 CmpmemTool::Generator::Generator(Field **arg, bool in_reset) :
642  plugin::TableFunction::Generator(arg),
643  record_number(0),
644  inner_reset(in_reset)
645 {
646 }
647 
648 CmpmemTool::Generator::~Generator()
649 {
650 }
651 
652 bool CmpmemTool::Generator::populate()
653 {
654  if (record_number >= (BUF_BUDDY_SIZES+1)*srv_buf_pool_instances)
655  {
656  return false;
657  }
658 
659  uint32_t buddy_nr= record_number % (BUF_BUDDY_SIZES+1);
660  uint32_t buf_pool_nr= (record_number/(BUF_BUDDY_SIZES+1));
661 
662  buf_pool_t *buf_pool= buf_pool_from_array(buf_pool_nr);
663 
664  buf_pool_mutex_enter(buf_pool);
665 
666  buf_buddy_stat_t* buddy_stat = &buf_pool->buddy_stat[buddy_nr];
667 
668 
669  push(static_cast<uint64_t>(buf_pool_nr));
670  push(static_cast<uint64_t>(BUF_BUDDY_LOW << buddy_nr));
671  push(static_cast<uint64_t>(buddy_stat->used));
672 
673 
674  uint64_t pages_free= (UNIV_LIKELY(buddy_nr < BUF_BUDDY_SIZES) ? UT_LIST_GET_LEN(buf_pool->zip_free[buddy_nr]) : 0);
675  push(pages_free);
676 
677  push(buddy_stat->relocated);
678  push(buddy_stat->relocated_usec / 1000000);
679 
680 
681  if (inner_reset)
682  {
683  buddy_stat->relocated = 0;
684  buddy_stat->relocated_usec = 0;
685  }
686 
687  buf_pool_mutex_exit(buf_pool);
688  record_number++;
689 
690  return true;
691 }
692 
693 /*
694  * Fill the dynamic table data_dictionary.INNODB_TRX INNODB_LOCKS INNODB_LOCK_WAITS
695  *
696  */
697 InnodbTrxTool::InnodbTrxTool(const char* in_table_name) :
698  plugin::TableFunction("DATA_DICTIONARY", in_table_name),
699  table_name(in_table_name)
700 {
701  if (innobase_strcasecmp(table_name, "INNODB_TRX") == 0)
702  {
703  add_field("TRX_ID");
704  add_field("TRX_STATE");
705  add_field("TRX_STARTED", plugin::TableFunction::NUMBER, 0, false);
706  add_field("TRX_REQUESTED_LOCK_ID");
707  add_field("TRX_WAIT_STARTED", plugin::TableFunction::NUMBER, 0, false);
708  add_field("TRX_WEIGHT", plugin::TableFunction::NUMBER, 0, false);
709  add_field("TRX_DRIZZLE_THREAD_ID", plugin::TableFunction::NUMBER, 0, false);
710  add_field("TRX_QUERY", plugin::TableFunction::STRING, TRX_I_S_TRX_QUERY_MAX_LEN, true);
711  add_field("TRX_OPERATION_STATE", plugin::TableFunction::STRING, TRX_I_S_TRX_OP_STATE_MAX_LEN, true);
712 // add_field("TRX_TABLES_IN_USE", plugin::TableFunction::NUMBER, 0, false);
713  add_field("TRX_TABLES_LOCKED", plugin::TableFunction::NUMBER, 0, false);
714  add_field("TRX_LOCK_STRUCTS", plugin::TableFunction::NUMBER, 0, false);
715  add_field("TRX_LOCK_MEMORY_BYTES", plugin::TableFunction::NUMBER, 0, false);
716  add_field("TRX_ROWS_LOCKED", plugin::TableFunction::NUMBER, 0, false);
717  add_field("TRX_ROWS_MODIFIED", plugin::TableFunction::NUMBER, 0, false);
718  add_field("TRX_CONCURRENCY_TICKETS", plugin::TableFunction::NUMBER, 0, false);
719  add_field("TRX_ISOLATION_LEVEL", plugin::TableFunction::STRING, TRX_I_S_TRX_ISOLATION_LEVEL_MAX_LEN, false);
720  add_field("TRX_UNIQUE_CHECKS", plugin::TableFunction::NUMBER, 0, false);
721  add_field("TRX_FOREIGN_KEY_CHECKS", plugin::TableFunction::NUMBER, 0, false);
722  add_field("TRX_LAST_FOREIGN_KEY_ERROR", plugin::TableFunction::STRING,
724  add_field("TRX_ADAPTIVE_HASH_LATCHED", plugin::TableFunction::NUMBER, 0, false);
725  add_field("TRX_ADAPTIVE_HASH_TIMEOUT", plugin::TableFunction::NUMBER, 0, false);
726  }
727  else if (innobase_strcasecmp(table_name, "INNODB_LOCKS") == 0)
728  {
729  add_field("LOCK_ID");
730  add_field("LOCK_TRX_ID");
731  add_field("LOCK_MODE");
732  add_field("LOCK_TYPE");
733  add_field("LOCK_TABLE");
734  add_field("LOCK_INDEX");
735  add_field("LOCK_SPACE", plugin::TableFunction::NUMBER, 0, false);
736  add_field("LOCK_PAGE", plugin::TableFunction::NUMBER, 0, false);
737  add_field("LOCK_REC", plugin::TableFunction::NUMBER, 0, false);
738  add_field("LOCK_DATA");
739  }
740  else if (innobase_strcasecmp(table_name, "INNODB_LOCK_WAITS") == 0)
741  {
742  add_field("REQUESTING_TRX_ID");
743  add_field("REQUESTED_LOCK_ID");
744  add_field("BLOCKING_TRX_ID");
745  add_field("BLOCKING_LOCK_ID");
746  }
747 }
748 
749 InnodbTrxTool::Generator::Generator(Field **arg, const char* in_table_name) :
750  plugin::TableFunction::Generator(arg),
751  table_name(in_table_name)
752 {
753  /* update the cache */
754  trx_i_s_cache_start_write(trx_i_s_cache);
756  trx_i_s_cache_end_write(trx_i_s_cache);
757 
758  if (trx_i_s_cache_is_truncated(trx_i_s_cache))
759  {
760  errmsg_printf(error::ERROR, _("Warning: data in %s truncated due to memory limit of %d bytes\n"),
761  table_name, TRX_I_S_MEM_LIMIT);
762  }
763 
764  trx_i_s_cache_start_read(trx_i_s_cache);
765 
766  if (innobase_strcasecmp(table_name, "INNODB_TRX") == 0)
767  number_rows= trx_i_s_cache_get_rows_used(trx_i_s_cache, I_S_INNODB_TRX);
768  else if (innobase_strcasecmp(table_name, "INNODB_LOCKS") == 0)
769  number_rows= trx_i_s_cache_get_rows_used(trx_i_s_cache, I_S_INNODB_LOCKS);
770  else if (innobase_strcasecmp(table_name, "INNODB_LOCK_WAITS") == 0)
771  number_rows= trx_i_s_cache_get_rows_used(trx_i_s_cache, I_S_INNODB_LOCK_WAITS);
772 
773  record_number= 0;
774 }
775 
776 InnodbTrxTool::Generator::~Generator()
777 {
778  trx_i_s_cache_end_read(trx_i_s_cache);
779 }
780 
781 bool InnodbTrxTool::Generator::populate()
782 {
783  if (record_number == number_rows)
784  {
785  return false;
786  }
787 
788  if (innobase_strcasecmp(table_name, "INNODB_TRX") == 0)
789  {
790  populate_innodb_trx();
791  }
792  else if (innobase_strcasecmp(table_name, "INNODB_LOCKS") == 0)
793  {
794  populate_innodb_locks();
795  }
796  else if (innobase_strcasecmp(table_name, "INNODB_LOCK_WAITS") == 0)
797  {
798  populate_innodb_lock_waits();
799  }
800  else
801  {
802  return false;
803  }
804  record_number++;
805 
806  return true;
807 }
808 
809 void InnodbTrxTool::Generator::populate_innodb_locks()
810 {
811 
812  char lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
813  i_s_locks_row_t* row;
814 
815  /* note that the decoded database or table name is
816  never expected to be longer than NAME_LEN;
817  NAME_LEN for database name
818  2 for surrounding quotes around database name
819  NAME_LEN for table name
820  2 for surrounding quotes around table name
821  1 for the separating dot (.)
822  9 for the #mysql50# prefix
823  */
824 
825  char buf[2 * NAME_LEN + 14];
826  const char* bufend;
827 
828  char lock_trx_id[TRX_ID_MAX_LEN + 1];
829 
830  row = (i_s_locks_row_t*)
832  trx_i_s_cache, I_S_INNODB_LOCKS, record_number);
833 
834 
835  trx_i_s_create_lock_id(row, lock_id, sizeof(lock_id));
836  push(lock_id);
837 
838  ut_snprintf(lock_trx_id, sizeof(lock_trx_id),
839  TRX_ID_FMT, row->lock_trx_id);
840  push(lock_trx_id);
841 
842  push(row->lock_mode);
843  push(row->lock_type);
844 
845  bufend = innobase_convert_name(buf, sizeof(buf),
846  row->lock_table,
847  strlen(row->lock_table),
848  &getSession(), TRUE);
849  push(bufend);
850 
851  if (row->lock_index != NULL)
852  {
853  bufend = innobase_convert_name(buf, sizeof(buf),
854  row->lock_index,
855  strlen(row->lock_index),
856  &getSession(), FALSE);
857  push(bufend);
858  }
859  else
860  {
861  push("");
862  }
863 
864  push(static_cast<uint64_t>(row->lock_space));
865  push(static_cast<uint64_t>(row->lock_page));
866  push(static_cast<uint64_t>(row->lock_rec));
867  push(row->lock_data);
868 }
869 
870 void InnodbTrxTool::Generator::populate_innodb_trx()
871 {
872  char lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
873  i_s_trx_row_t* row;
874  char trx_id[TRX_ID_MAX_LEN + 1];
875  row = (i_s_trx_row_t*) trx_i_s_cache_get_nth_row(trx_i_s_cache, I_S_INNODB_TRX, record_number);
876 
877  /* trx_id */
878  ut_snprintf(trx_id, sizeof(trx_id), TRX_ID_FMT, row->trx_id);
879 
880  push(trx_id);
881  push(row->trx_state);
882  push(static_cast<uint64_t>(row->trx_started));
883 
884  if (row->trx_wait_started != 0)
885  {
886  push(trx_i_s_create_lock_id(row->requested_lock_row, lock_id, sizeof(lock_id)));
887  push(static_cast<uint64_t>(row->trx_wait_started));
888  }
889  else
890  {
891  push(static_cast<uint64_t>(0));
892  push(static_cast<uint64_t>(0));
893  }
894 
895  push(static_cast<int64_t>(row->trx_weight));
896  push(static_cast<uint64_t>(row->trx_mysql_thread_id));
897  if (row->trx_query)
898  push(row->trx_query);
899  else
900  push();
901 
902  if (row->trx_operation_state)
903  push(row->trx_operation_state);
904  else
905  push();
906 
907 // push(row->trx_tables_in_use);
908  push(static_cast<uint64_t>(row->trx_tables_locked));
909  push(static_cast<uint64_t>(row->trx_lock_structs));
910  push(static_cast<uint64_t>(row->trx_lock_memory_bytes));
911  push(static_cast<uint64_t>(row->trx_rows_locked));
912  push(static_cast<uint64_t>(row->trx_rows_modified));
913  push(static_cast<uint64_t>(row->trx_concurrency_tickets));
914  push(row->trx_isolation_level);
915  push(static_cast<uint64_t>(row->trx_unique_checks));
916  push(static_cast<uint64_t>(row->trx_foreign_key_checks));
917  if (row->trx_foreign_key_error)
918  push(row->trx_foreign_key_error);
919  else
920  push();
921 
922  push(static_cast<uint64_t>(row->trx_has_search_latch));
923  push(static_cast<uint64_t>(row->trx_search_latch_timeout));
924 }
925 
926 void InnodbTrxTool::Generator::populate_innodb_lock_waits()
927 {
928  char requested_lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
929  char blocking_lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1];
930 
932 
933  char requesting_trx_id[TRX_ID_MAX_LEN + 1];
934  char blocking_trx_id[TRX_ID_MAX_LEN + 1];
935 
936  row = (i_s_lock_waits_row_t*)
938  trx_i_s_cache, I_S_INNODB_LOCK_WAITS, record_number);
939 
940  ut_snprintf(requesting_trx_id, sizeof(requesting_trx_id),
942  push(requesting_trx_id);
943 
944  push(trx_i_s_create_lock_id(row->requested_lock_row, requested_lock_id,
945  sizeof(requested_lock_id)));
946 
947  ut_snprintf(blocking_trx_id, sizeof(blocking_trx_id),
949  push(blocking_trx_id);
950 
951  push(trx_i_s_create_lock_id(row->blocking_lock_row, blocking_lock_id,
952  sizeof(blocking_lock_id)));
953 }