MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
rpl_info_table.cc
1 /* Copyright (c) 2010, 2013, 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
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include "rpl_info_table.h"
17 #include "rpl_utility.h"
18 
19 Rpl_info_table::Rpl_info_table(uint nparam,
20  const char* param_schema,
21  const char *param_table)
22 :Rpl_info_handler(nparam), is_transactional(FALSE)
23 {
24  str_schema.str= str_table.str= NULL;
25  str_schema.length= str_table.length= 0;
26 
27  uint schema_length= strlen(param_schema);
28  if ((str_schema.str= (char *) my_malloc(schema_length + 1, MYF(0))))
29  {
30  str_schema.length= schema_length;
31  strmake(str_schema.str, param_schema, schema_length);
32  }
33 
34  uint table_length= strlen(param_table);
35  if ((str_table.str= (char *) my_malloc(table_length + 1, MYF(0))))
36  {
37  str_table.length= table_length;
38  strmake(str_table.str, param_table, table_length);
39  }
40 
41  if ((description= (char *)
42  my_malloc(str_schema.length + str_table.length + 2, MYF(0))))
43  {
44  char *pos= strmov(description, param_schema);
45  pos= strmov(pos, ".");
46  pos= strmov(pos, param_table);
47  }
48 
49  access= new Rpl_info_table_access();
50 }
51 
52 Rpl_info_table::~Rpl_info_table()
53 {
54  delete access;
55 
56  my_free(description);
57 
58  my_free(str_table.str);
59 
60  my_free(str_schema.str);
61 }
62 
63 int Rpl_info_table::do_init_info()
64 {
65  return do_init_info(FIND_KEY, 0);
66 }
67 
68 int Rpl_info_table::do_init_info(uint instance)
69 {
70  return do_init_info(FIND_SCAN, instance);
71 }
72 
73 int Rpl_info_table::do_init_info(enum_find_method method, uint instance)
74 {
75  int error= 1;
76  enum enum_return_id res= FOUND_ID;
77  TABLE *table= NULL;
78  ulong saved_mode;
79  Open_tables_backup backup;
80 
81  DBUG_ENTER("Rlp_info_table::do_init_info");
82 
83  THD *thd= access->create_thd();
84 
85  saved_mode= thd->variables.sql_mode;
86  tmp_disable_binlog(thd);
87 
88  /*
89  Opens and locks the rpl_info table before accessing it.
90  */
91  if (access->open_table(thd, str_schema, str_table,
92  get_number_info(), TL_WRITE,
93  &table, &backup))
94  goto end;
95 
96  /*
97  Points the cursor at the row to be read according to the
98  keys.
99  */
100  switch (method)
101  {
102  case FIND_KEY:
103  res= access->find_info(field_values, table);
104  break;
105 
106  case FIND_SCAN:
107  res= access->scan_info(table, instance);
108  break;
109 
110  default:
111  DBUG_ASSERT(0);
112  break;
113  }
114 
115  if (res == FOUND_ID)
116  {
117  /*
118  Reads the information stored in the rpl_info table into a
119  set of variables. If there is a failure, an error is returned.
120  */
121  if (access->load_info_values(get_number_info(), table->field,
122  field_values))
123  goto end;
124  }
125  error= (res == ERROR_ID);
126 end:
127  /*
128  Unlocks and closes the rpl_info table.
129  */
130  access->close_table(thd, table, &backup, error);
131  reenable_binlog(thd);
132  thd->variables.sql_mode= saved_mode;
133  access->drop_thd(thd);
134  DBUG_RETURN(error);
135 }
136 
137 int Rpl_info_table::do_flush_info(const bool force)
138 {
139  int error= 1;
140  enum enum_return_id res= FOUND_ID;
141  TABLE *table= NULL;
142  ulong saved_mode;
143  Open_tables_backup backup;
144 
145  DBUG_ENTER("Rpl_info_table::do_flush_info");
146 
147  if (!(force || (sync_period &&
148  ++(sync_counter) >= sync_period)))
149  DBUG_RETURN(0);
150 
151  THD *thd= access->create_thd();
152 
153  sync_counter= 0;
154  saved_mode= thd->variables.sql_mode;
155  tmp_disable_binlog(thd);
156 
157  /*
158  Opens and locks the rpl_info table before accessing it.
159  */
160  if (access->open_table(thd, str_schema, str_table,
161  get_number_info(), TL_WRITE,
162  &table, &backup))
163  goto end;
164 
165  /*
166  Points the cursor at the row to be read according to the
167  keys. If the row is not found an error is reported.
168  */
169  if ((res= access->find_info(field_values, table)) == NOT_FOUND_ID)
170  {
171  /*
172  Prepares the information to be stored before calling ha_write_row.
173  */
174  empty_record(table);
175  if (access->store_info_values(get_number_info(), table->field,
176  field_values))
177  goto end;
178 
179  /*
180  Inserts a new row into rpl_info table.
181  */
182  if ((error= table->file->ha_write_row(table->record[0])))
183  {
184  table->file->print_error(error, MYF(0));
185  /*
186  This makes sure that the error is 1 and not the status returned
187  by the handler.
188  */
189  error= 1;
190  goto end;
191  }
192  error= 0;
193  }
194  else if (res == FOUND_ID)
195  {
196  /*
197  Prepares the information to be stored before calling ha_update_row.
198  */
199  store_record(table, record[1]);
200  if (access->store_info_values(get_number_info(), table->field,
201  field_values))
202  goto end;
203 
204  /*
205  Updates a row in the rpl_info table.
206  */
207  if ((error= table->file->ha_update_row(table->record[1], table->record[0])) &&
208  error != HA_ERR_RECORD_IS_THE_SAME)
209  {
210  table->file->print_error(error, MYF(0));
211  /*
212  This makes sure that the error is 1 and not the status returned
213  by the handler.
214  */
215  error= 1;
216  goto end;
217  }
218  error= 0;
219  }
220 
221 end:
222  DBUG_EXECUTE_IF("mts_debug_concurrent_access",
223  {
224  while (thd->system_thread == SYSTEM_THREAD_SLAVE_WORKER &&
225  mts_debug_concurrent_access < 2 && mts_debug_concurrent_access > 0)
226  {
227  DBUG_PRINT("mts", ("Waiting while locks are acquired to show "
228  "concurrency in mts: %u %lu\n", mts_debug_concurrent_access,
229  (ulong) thd->thread_id));
230  my_sleep(6000000);
231  }
232  };
233  );
234 
235  /*
236  Unlocks and closes the rpl_info table.
237  */
238  access->close_table(thd, table, &backup, error);
239  reenable_binlog(thd);
240  thd->variables.sql_mode= saved_mode;
241  access->drop_thd(thd);
242  DBUG_RETURN(error);
243 }
244 
245 int Rpl_info_table::do_remove_info()
246 {
247  return do_clean_info();
248 }
249 
250 int Rpl_info_table::do_clean_info()
251 {
252  int error= 1;
253  enum enum_return_id res= FOUND_ID;
254  TABLE *table= NULL;
255  ulong saved_mode;
256  Open_tables_backup backup;
257 
258  DBUG_ENTER("Rpl_info_table::do_remove_info");
259 
260  THD *thd= access->create_thd();
261 
262  saved_mode= thd->variables.sql_mode;
263  tmp_disable_binlog(thd);
264 
265  /*
266  Opens and locks the rpl_info table before accessing it.
267  */
268  if (access->open_table(thd, str_schema, str_table,
269  get_number_info(), TL_WRITE,
270  &table, &backup))
271  goto end;
272 
273  /*
274  Points the cursor at the row to be deleted according to the
275  keys. If the row is not found, the execution proceeds normally.
276  */
277  if ((res= access->find_info(field_values, table)) == FOUND_ID)
278  {
279  /*
280  Deletes a row in the rpl_info table.
281  */
282  if ((error= table->file->ha_delete_row(table->record[0])))
283  {
284  table->file->print_error(error, MYF(0));
285  goto end;
286  }
287  }
288  error= (res == ERROR_ID);
289 end:
290  /*
291  Unlocks and closes the rpl_info table.
292  */
293  access->close_table(thd, table, &backup, error);
294  reenable_binlog(thd);
295  thd->variables.sql_mode= saved_mode;
296  access->drop_thd(thd);
297  DBUG_RETURN(error);
298 }
299 
300 int Rpl_info_table::do_reset_info(uint nparam,
301  const char* param_schema,
302  const char *param_table)
303 {
304  int error= 1;
305  TABLE *table= NULL;
306  ulong saved_mode;
307  Open_tables_backup backup;
308  Rpl_info_table *info= NULL;
309  THD *thd= NULL;
310  enum enum_return_id scan_retval= FOUND_ID;
311 
312  DBUG_ENTER("Rpl_info_table::do_reset_info");
313 
314  if (!(info= new Rpl_info_table(nparam, param_schema,
315  param_table)))
316  DBUG_RETURN(error);
317 
318  thd= info->access->create_thd();
319  saved_mode= thd->variables.sql_mode;
320  tmp_disable_binlog(thd);
321 
322  /*
323  Opens and locks the rpl_info table before accessing it.
324  */
325  if (info->access->open_table(thd, info->str_schema, info->str_table,
326  info->get_number_info(), TL_WRITE,
327  &table, &backup))
328  goto end;
329 
330  /*
331  Delete all rows in the rpl_info table. We cannot use truncate() since it
332  is a non-transactional DDL operation.
333  */
334  while ((scan_retval= info->access->scan_info(table, 1)) == FOUND_ID)
335  {
336  if ((error= table->file->ha_delete_row(table->record[0])))
337  {
338  table->file->print_error(error, MYF(0));
339  goto end;
340  }
341  }
342  error= (scan_retval == ERROR_ID);
343 
344 end:
345  /*
346  Unlocks and closes the rpl_info table.
347  */
348  info->access->close_table(thd, table, &backup, error);
349  reenable_binlog(thd);
350  thd->variables.sql_mode= saved_mode;
351  info->access->drop_thd(thd);
352  delete info;
353  DBUG_RETURN(error);
354 }
355 
356 enum_return_check Rpl_info_table::do_check_info()
357 {
358  TABLE *table= NULL;
359  ulong saved_mode;
360  Open_tables_backup backup;
361  enum_return_check return_check= ERROR_CHECKING_REPOSITORY;
362 
363  DBUG_ENTER("Rpl_info_table::do_check_info");
364 
365  THD *thd= access->create_thd();
366  saved_mode= thd->variables.sql_mode;
367 
368  /*
369  Opens and locks the rpl_info table before accessing it.
370  */
371  if (access->open_table(thd, str_schema, str_table,
372  get_number_info(), TL_READ,
373  &table, &backup))
374  {
375  sql_print_warning("Info table is not ready to be used. Table "
376  "'%s.%s' cannot be opened.", str_schema.str,
377  str_table.str);
378 
379  return_check= ERROR_CHECKING_REPOSITORY;
380  goto end;
381  }
382 
383  /*
384  Points the cursor at the row to be read according to the
385  keys.
386  */
387  if (access->find_info(field_values, table) != FOUND_ID)
388  {
389  /*
390  We cannot simply call my_error here because it does not
391  really means that there was a failure but only that the
392  record was not found.
393  */
394  return_check= REPOSITORY_DOES_NOT_EXIST;
395  goto end;
396  }
397  return_check= REPOSITORY_EXISTS;
398 
399 
400 end:
401  /*
402  Unlocks and closes the rpl_info table.
403  */
404  access->close_table(thd, table, &backup,
405  return_check == ERROR_CHECKING_REPOSITORY);
406  thd->variables.sql_mode= saved_mode;
407  access->drop_thd(thd);
408  DBUG_RETURN(return_check);
409 }
410 
411 enum_return_check Rpl_info_table::do_check_info(uint instance)
412 {
413  TABLE *table= NULL;
414  ulong saved_mode;
415  Open_tables_backup backup;
416  enum_return_check return_check= ERROR_CHECKING_REPOSITORY;
417 
418  DBUG_ENTER("Rpl_info_table::do_check_info");
419 
420  THD *thd= access->create_thd();
421  saved_mode= thd->variables.sql_mode;
422 
423  /*
424  Opens and locks the rpl_info table before accessing it.
425  */
426  if (access->open_table(thd, str_schema, str_table,
427  get_number_info(), TL_READ,
428  &table, &backup))
429  {
430  sql_print_warning("Info table is not ready to be used. Table "
431  "'%s.%s' cannot be opened.", str_schema.str,
432  str_table.str);
433 
434  return_check= ERROR_CHECKING_REPOSITORY;
435  goto end;
436  }
437 
438  /*
439  Points the cursor at the row to be read according to the
440  keys.
441  */
442  if (access->scan_info(table, instance) != FOUND_ID)
443  {
444  /*
445  We cannot simply call my_error here because it does not
446  really means that there was a failure but only that the
447  record was not found.
448  */
449  return_check= REPOSITORY_DOES_NOT_EXIST;
450  goto end;
451  }
452  return_check= REPOSITORY_EXISTS;
453 
454 
455 end:
456  /*
457  Unlocks and closes the rpl_info table.
458  */
459  access->close_table(thd, table, &backup,
460  return_check == ERROR_CHECKING_REPOSITORY);
461  thd->variables.sql_mode= saved_mode;
462  access->drop_thd(thd);
463  DBUG_RETURN(return_check);
464 }
465 
466 bool Rpl_info_table::do_count_info(uint nparam,
467  const char* param_schema,
468  const char *param_table,
469  uint* counter)
470 {
471  int error= 1;
472  TABLE *table= NULL;
473  ulong saved_mode;
474  Open_tables_backup backup;
475  Rpl_info_table *info= NULL;
476  THD *thd= NULL;
477 
478  DBUG_ENTER("Rpl_info_table::do_count_info");
479 
480  if (!(info= new Rpl_info_table(nparam, param_schema, param_table)))
481  DBUG_RETURN(true);
482 
483  thd= info->access->create_thd();
484  saved_mode= thd->variables.sql_mode;
485 
486  /*
487  Opens and locks the rpl_info table before accessing it.
488  */
489  if (info->access->open_table(thd, info->str_schema, info->str_table,
490  info->get_number_info(), TL_READ,
491  &table, &backup))
492  {
493  /*
494  We cannot simply print out a warning message at this
495  point because this may represent a bootstrap.
496  */
497  error= 0;
498  goto end;
499  }
500 
501  /*
502  Counts entries in the rpl_info table.
503  */
504  if (info->access->count_info(table, counter))
505  {
506  sql_print_warning("Info table is not ready to be used. Table "
507  "'%s.%s' cannot be scanned.", info->str_schema.str,
508  info->str_table.str);
509  goto end;
510  }
511  error= 0;
512 
513 end:
514  /*
515  Unlocks and closes the rpl_info table.
516  */
517  info->access->close_table(thd, table, &backup, error);
518  thd->variables.sql_mode= saved_mode;
519  info->access->drop_thd(thd);
520  delete info;
521  DBUG_RETURN(error);
522 }
523 
524 void Rpl_info_table::do_end_info()
525 {
526 }
527 
528 int Rpl_info_table::do_prepare_info_for_read()
529 {
530  if (!field_values)
531  return TRUE;
532 
533  cursor= 0;
534  prv_error= FALSE;
535 
536  return FALSE;
537 }
538 
539 int Rpl_info_table::do_prepare_info_for_write()
540 {
541  return(do_prepare_info_for_read());
542 }
543 
544 uint Rpl_info_table::do_get_rpl_info_type()
545 {
546  return INFO_REPOSITORY_TABLE;
547 }
548 
549 bool Rpl_info_table::do_set_info(const int pos, const char *value)
550 {
551  return (field_values->value[pos].copy(value, strlen(value),
552  &my_charset_bin));
553 }
554 
555 bool Rpl_info_table::do_set_info(const int pos, const uchar *value,
556  const size_t size)
557 {
558  return (field_values->value[pos].copy((char *) value, size,
559  &my_charset_bin));
560 }
561 
562 bool Rpl_info_table::do_set_info(const int pos, const ulong value)
563 {
564  return (field_values->value[pos].set_int(value, TRUE,
565  &my_charset_bin));
566 }
567 
568 bool Rpl_info_table::do_set_info(const int pos, const int value)
569 {
570  return (field_values->value[pos].set_int(value, FALSE,
571  &my_charset_bin));
572 }
573 
574 bool Rpl_info_table::do_set_info(const int pos, const float value)
575 {
576  return (field_values->value[pos].set_real(value, NOT_FIXED_DEC,
577  &my_charset_bin));
578 }
579 
580 bool Rpl_info_table::do_set_info(const int pos, const Dynamic_ids *value)
581 {
582  if (const_cast<Dynamic_ids *>(value)->pack_dynamic_ids(&field_values->value[pos]))
583  return TRUE;
584 
585  return FALSE;
586 }
587 
588 bool Rpl_info_table::do_get_info(const int pos, char *value, const size_t size,
589  const char *default_value)
590 {
591  if (field_values->value[pos].length())
592  strmake(value, field_values->value[pos].c_ptr_safe(),
593  field_values->value[pos].length());
594  else if (default_value)
595  strmake(value, default_value, strlen(default_value));
596  else
597  *value= '\0';
598 
599  return FALSE;
600 }
601 
602 bool Rpl_info_table::do_get_info(const int pos, uchar *value, const size_t size,
603  const uchar *default_value __attribute__((unused)))
604 {
605  if (field_values->value[pos].length() == size)
606  return (!memcpy((char *) value, (char *)
607  field_values->value[pos].c_ptr_safe(), size));
608  return TRUE;
609 }
610 
611 bool Rpl_info_table::do_get_info(const int pos, ulong *value,
612  const ulong default_value)
613 {
614  if (field_values->value[pos].length())
615  {
616  *value= strtoul(field_values->value[pos].c_ptr_safe(), 0, 10);
617  return FALSE;
618  }
619  else if (default_value)
620  {
621  *value= default_value;
622  return FALSE;
623  }
624 
625  return TRUE;
626 }
627 
628 bool Rpl_info_table::do_get_info(const int pos, int *value,
629  const int default_value)
630 {
631  if (field_values->value[pos].length())
632  {
633  *value= atoi(field_values->value[pos].c_ptr_safe());
634  return FALSE;
635  }
636  else if (default_value)
637  {
638  *value= default_value;
639  return FALSE;
640  }
641 
642  return TRUE;
643 }
644 
645 bool Rpl_info_table::do_get_info(const int pos, float *value,
646  const float default_value)
647 {
648  if (field_values->value[pos].length())
649  {
650  if (sscanf(field_values->value[pos].c_ptr_safe(), "%f", value) != 1)
651  return TRUE;
652  return FALSE;
653  }
654  else if (default_value != 0.0)
655  {
656  *value= default_value;
657  return FALSE;
658  }
659 
660  return TRUE;
661 }
662 
663 bool Rpl_info_table::do_get_info(const int pos, Dynamic_ids *value,
664  const Dynamic_ids *default_value __attribute__((unused)))
665 {
666  if (value->unpack_dynamic_ids(field_values->value[pos].c_ptr_safe()))
667  return TRUE;
668 
669  return FALSE;
670 }
671 
672 char* Rpl_info_table::do_get_description_info()
673 {
674  return description;
675 }
676 
677 bool Rpl_info_table::do_is_transactional()
678 {
679  return is_transactional;
680 }
681 
682 bool Rpl_info_table::do_update_is_transactional()
683 {
684  bool error= TRUE;
685  ulong saved_mode;
686  TABLE *table= NULL;
687  Open_tables_backup backup;
688 
689  DBUG_ENTER("Rpl_info_table::do_update_is_transactional");
690 
691  THD *thd= access->create_thd();
692  saved_mode= thd->variables.sql_mode;
693  tmp_disable_binlog(thd);
694 
695  /*
696  Opens and locks the rpl_info table before accessing it.
697  */
698  if (access->open_table(thd, str_schema, str_table,
699  get_number_info(), TL_READ,
700  &table, &backup))
701  goto end;
702 
703  is_transactional= table->file->has_transactions();
704  error= FALSE;
705 
706 end:
707  access->close_table(thd, table, &backup, 0);
708  reenable_binlog(thd);
709  thd->variables.sql_mode= saved_mode;
710  access->drop_thd(thd);
711  DBUG_RETURN(error);
712 }