1 /* Copyright (c) 2010, 2018, 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, 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
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #include <my_global.h>
24 #include "sql_priv.h"
25 #include "rpl_slave.h"
26 #include "rpl_info_factory.h"
27
28 /*
29 Defines meta information on diferent repositories.
30 */
31 Rpl_info_factory::struct_table_data Rpl_info_factory::rli_table_data;
32 Rpl_info_factory::struct_file_data Rpl_info_factory::rli_file_data;
33 Rpl_info_factory::struct_table_data Rpl_info_factory::mi_table_data;
34 Rpl_info_factory::struct_file_data Rpl_info_factory::mi_file_data;
35 Rpl_info_factory::struct_file_data Rpl_info_factory::worker_file_data;
36 Rpl_info_factory::struct_table_data Rpl_info_factory::worker_table_data;
37
38 /**
39 Creates both a Master info and a Relay log info repository whose types are
40 defined as parameters. Nothing is done for Workers here.
41
42 @todo Make the repository a pluggable component.
43 @todo Use generic programming to make it easier and clearer to
44 add a new repositories' types and Rpl_info objects.
45
46 @param[in] mi_option Type of the Master info repository.
47 @param[out] mi Reference to the Master_info.
48 @param[in] rli_option Type of the Relay log info repository.
49 @param[out] rli Reference to the Relay_log_info.
50
51 @retval FALSE No error
52 @retval TRUE Failure
53 */
create_coordinators(uint mi_option,Master_info ** mi,uint rli_option,Relay_log_info ** rli)54 bool Rpl_info_factory::create_coordinators(uint mi_option, Master_info **mi,
55 uint rli_option, Relay_log_info **rli)
56 {
57 DBUG_ENTER("Rpl_info_factory::create_coordinators");
58
59 Rpl_info_factory::init_repository_metadata();
60
61 if (!((*mi)= Rpl_info_factory::create_mi(mi_option)))
62 DBUG_RETURN(TRUE);
63
64 if (!((*rli)= Rpl_info_factory::create_rli(rli_option, relay_log_recovery)))
65 {
66 delete *mi;
67 *mi= NULL;
68 DBUG_RETURN(TRUE);
69 }
70
71 /*
72 Setting the cross dependency used all over the code.
73 */
74 (*mi)->set_relay_log_info(*rli);
75 (*rli)->set_master_info(*mi);
76
77 DBUG_RETURN(FALSE);
78 }
79
80 /**
81 Creates a Master info repository whose type is defined as a parameter.
82
83 @param[in] mi_option Type of the repository, e.g. FILE TABLE.
84
85 The execution fails if a user requests a type but a different type
86 already exists in the system. This is done to avoid that a user
87 accidentally accesses the wrong repository and makes the slave go out
88 of sync.
89
90 @retval Pointer to Master_info Success
91 @retval NULL Failure
92 */
create_mi(uint mi_option)93 Master_info *Rpl_info_factory::create_mi(uint mi_option)
94 {
95 Master_info* mi= NULL;
96 Rpl_info_handler* handler_src= NULL;
97 Rpl_info_handler* handler_dest= NULL;
98 uint instances= 1;
99 const char *msg= "Failed to allocate memory for the master info "
100 "structure";
101
102 DBUG_ENTER("Rpl_info_factory::create_mi");
103
104 if (!(mi= new Master_info(
105 #ifdef HAVE_PSI_INTERFACE
106 &key_master_info_run_lock,
107 &key_master_info_data_lock,
108 &key_master_info_sleep_lock,
109 &key_master_info_data_cond,
110 &key_master_info_start_cond,
111 &key_master_info_stop_cond,
112 &key_master_info_sleep_cond,
113 #endif
114 instances
115 )))
116 goto err;
117
118 if(init_repositories(mi_table_data, mi_file_data, mi_option, instances,
119 &handler_src, &handler_dest, &msg))
120 goto err;
121
122 if (decide_repository(mi, mi_option, &handler_src, &handler_dest, &msg))
123 goto err;
124
125 DBUG_RETURN(mi);
126
127 err:
128 delete handler_src;
129 delete handler_dest;
130 if (mi)
131 {
132 /*
133 The handler was previously deleted so we need to remove
134 any reference to it.
135 */
136 mi->set_rpl_info_handler(NULL);
137 delete mi;
138 }
139 sql_print_error("Error creating master info: %s.", msg);
140 DBUG_RETURN(NULL);
141 }
142
143 /**
144 Allows to change the master info repository after startup.
145
146 @param[in] mi Reference to Master_info.
147 @param[in] mi_option Type of the repository, e.g. FILE TABLE.
148 @param[out] msg Error message if something goes wrong.
149
150 @retval FALSE No error
151 @retval TRUE Failure
152 */
change_mi_repository(Master_info * mi,uint mi_option,const char ** msg)153 bool Rpl_info_factory::change_mi_repository(Master_info *mi,
154 uint mi_option,
155 const char **msg)
156 {
157 Rpl_info_handler* handler_src= mi->get_rpl_info_handler();
158 Rpl_info_handler* handler_dest= NULL;
159 uint instances= 1;
160 DBUG_ENTER("Rpl_info_factory::change_mi_repository");
161
162 DBUG_ASSERT(handler_src);
163 if (handler_src->get_rpl_info_type() == mi_option)
164 DBUG_RETURN(false);
165
166 if (init_repositories(mi_table_data, mi_file_data, mi_option, instances,
167 NULL, &handler_dest, msg))
168 goto err;
169
170 if (decide_repository(mi, mi_option, &handler_src, &handler_dest, msg))
171 goto err;
172
173 DBUG_RETURN(FALSE);
174
175 err:
176 delete handler_dest;
177 handler_dest= NULL;
178
179 sql_print_error("Error changing the type of master info's repository: %s.", *msg);
180 DBUG_RETURN(TRUE);
181 }
182
183 /**
184 Creates a Relay log info repository whose type is defined as a parameter.
185
186 @param[in] rli_option Type of the Relay log info repository
187 @param[in] is_slave_recovery If the slave should try to start a recovery
188 process to get consistent relay log files
189
190 The execution fails if a user requests a type but a different type
191 already exists in the system. This is done to avoid that a user
192 accidentally accesses the wrong repository and make the slave go out
193 of sync.
194
195 @retval Pointer to Relay_log_info Success
196 @retval NULL Failure
197 */
create_rli(uint rli_option,bool is_slave_recovery)198 Relay_log_info *Rpl_info_factory::create_rli(uint rli_option, bool is_slave_recovery)
199 {
200 Relay_log_info *rli= NULL;
201 Rpl_info_handler* handler_src= NULL;
202 Rpl_info_handler* handler_dest= NULL;
203 uint instances= 1;
204 uint worker_repository= INVALID_INFO_REPOSITORY;
205 uint worker_instances= 1;
206 const char *msg= NULL;
207 const char *msg_alloc= "Failed to allocate memory for the relay log info "
208 "structure";
209
210 DBUG_ENTER("Rpl_info_factory::create_rli");
211
212 /*
213 Returns how many occurrences of rli's repositories exist. For example,
214 if the repository is a table, this retrieves the number of rows in it.
215 Besides, it also returns the type of the repository where entries were
216 found.
217 */
218 if (rli_option != INFO_REPOSITORY_DUMMY &&
219 scan_repositories(&worker_instances, &worker_repository,
220 worker_table_data, worker_file_data, &msg))
221 goto err;
222
223 try
224 {
225 rli= new Relay_log_info(is_slave_recovery
226 #ifdef HAVE_PSI_INTERFACE
227 ,&key_relay_log_info_run_lock,
228 &key_relay_log_info_data_lock,
229 &key_relay_log_info_sleep_lock,
230 &key_relay_log_info_data_cond,
231 &key_relay_log_info_start_cond,
232 &key_relay_log_info_stop_cond,
233 &key_relay_log_info_sleep_cond
234 #endif
235 , instances
236 );
237 } catch (std::bad_alloc&)
238 {
239 msg= msg_alloc;
240 goto err;
241 }
242
243 if(init_repositories(rli_table_data, rli_file_data, rli_option, instances,
244 &handler_src, &handler_dest, &msg))
245 goto err;
246
247 if (rli_option != INFO_REPOSITORY_DUMMY &&
248 worker_repository != INVALID_INFO_REPOSITORY &&
249 worker_repository != rli_option)
250 {
251 opt_rli_repository_id= rli_option= worker_repository;
252 sql_print_warning("It is not possible to change the type of the relay log "
253 "repository because there are workers repositories with "
254 "possible execution gaps. "
255 "The value of --relay_log_info_repository is altered to "
256 "one of the found Worker repositories. "
257 "The gaps have to be sorted out before resuming with "
258 "the type change.");
259 std::swap(handler_src, handler_dest);
260 }
261 if (decide_repository(rli, rli_option, &handler_src, &handler_dest, &msg))
262 goto err;
263
264 DBUG_RETURN(rli);
265
266 err:
267 delete handler_src;
268 delete handler_dest;
269 if (rli)
270 {
271 /*
272 The handler was previously deleted so we need to remove
273 any reference to it.
274 */
275 rli->set_rpl_info_handler(NULL);
276 delete rli;
277 }
278 sql_print_error("Error creating relay log info: %s.", msg);
279 DBUG_RETURN(NULL);
280 }
281
282 /**
283 Allows to change the relay log info repository after startup.
284
285 @param[in] mi Pointer to Relay_log_info.
286 @param[in] mi_option Type of the repository, e.g. FILE TABLE.
287 @param[out] msg Error message if something goes wrong.
288
289 @retval FALSE No error
290 @retval TRUE Failure
291 */
change_rli_repository(Relay_log_info * rli,uint rli_option,const char ** msg)292 bool Rpl_info_factory::change_rli_repository(Relay_log_info *rli,
293 uint rli_option,
294 const char **msg)
295 {
296 Rpl_info_handler* handler_src= rli->get_rpl_info_handler();
297 Rpl_info_handler* handler_dest= NULL;
298 uint instances= 1;
299 DBUG_ENTER("Rpl_info_factory::change_rli_repository");
300
301 DBUG_ASSERT(handler_src != NULL);
302
303 if (handler_src->get_rpl_info_type() == rli_option)
304 DBUG_RETURN(false);
305
306 if (init_repositories(rli_table_data, rli_file_data, rli_option,
307 instances, NULL, &handler_dest, msg))
308 goto err;
309
310 if (decide_repository(rli, rli_option, &handler_src, &handler_dest,
311 msg))
312 goto err;
313
314 DBUG_RETURN(FALSE);
315
316 err:
317 delete handler_dest;
318 handler_dest= NULL;
319
320 sql_print_error("Error changing the type of relay log info's repository: %s.", *msg);
321 DBUG_RETURN(TRUE);
322 }
323
324 /**
325 Delete all info from Worker info tables to render them useless in
326 future MTS recovery, and indicate that in Coordinator info table.
327
328 @return false on success, true when a failure in deletion or writing
329 to Coordinator table fails.
330 */
reset_workers(Relay_log_info * rli)331 bool Rpl_info_factory::reset_workers(Relay_log_info *rli)
332 {
333 bool error= true;
334
335 DBUG_ENTER("Rpl_info_factory::reset_workers");
336
337 if (rli->recovery_parallel_workers == 0)
338 DBUG_RETURN(0);
339
340 if (Rpl_info_file::do_reset_info(Slave_worker::get_number_worker_fields(),
341 worker_file_data.pattern,
342 worker_file_data.name_indexed))
343 goto err;
344
345 if (Rpl_info_table::do_reset_info(Slave_worker::get_number_worker_fields(),
346 MYSQL_SCHEMA_NAME.str, WORKER_INFO_NAME.str))
347 goto err;
348
349 error= false;
350
351 DBUG_EXECUTE_IF("mts_debug_reset_workers_fails", error= true;);
352
353 err:
354 if (error)
355 sql_print_error("Could not delete from Slave Workers info repository.");
356 rli->recovery_parallel_workers= 0;
357 rli->clear_mts_recovery_groups();
358 if (rli->flush_info(true))
359 {
360 error= true;
361 sql_print_error("Could not store the reset Slave Worker state into "
362 "the slave info repository.");
363 }
364 DBUG_RETURN(error);
365 }
366
367 /**
368 Creates a Slave worker repository whose type is defined as a parameter.
369
370 @param[in] rli_option Type of the repository, e.g. FILE TABLE.
371 @param[in] rli Pointer to Relay_log_info.
372
373 The execution fails if a user requests a type but a different type
374 already exists in the system. This is done to avoid that a user
375 accidentally accesses the wrong repository and make the slave go out
376 of sync.
377
378 @retval Pointer to Slave_worker Success
379 @retval NULL Failure
380 */
create_worker(uint rli_option,uint worker_id,Relay_log_info * rli,bool is_gaps_collecting_phase)381 Slave_worker *Rpl_info_factory::create_worker(uint rli_option, uint worker_id,
382 Relay_log_info *rli,
383 bool is_gaps_collecting_phase)
384 {
385 Rpl_info_handler* handler_src= NULL;
386 Rpl_info_handler* handler_dest= NULL;
387 Slave_worker* worker= NULL;
388 const char *msg= "Failed to allocate memory for the worker info "
389 "structure";
390
391 DBUG_ENTER("Rpl_info_factory::create_worker");
392
393 /*
394 Define the name of the worker and its repository.
395 */
396 char *pos= strmov(worker_file_data.name, worker_file_data.pattern);
397 sprintf(pos, "%u", worker_id + 1);
398
399 try
400 {
401 worker= new Slave_worker(rli
402 #ifdef HAVE_PSI_INTERFACE
403 ,&key_relay_log_info_run_lock,
404 &key_relay_log_info_data_lock,
405 &key_relay_log_info_sleep_lock,
406 &key_relay_log_info_data_cond,
407 &key_relay_log_info_start_cond,
408 &key_relay_log_info_stop_cond,
409 &key_relay_log_info_sleep_cond
410 #endif
411 , worker_id
412 );
413 } catch (std::bad_alloc&)
414 {
415 goto err;
416 }
417
418 if(init_repositories(worker_table_data, worker_file_data, rli_option,
419 worker_id + 1, &handler_src, &handler_dest, &msg))
420 goto err;
421
422 if (decide_repository(worker, rli_option, &handler_src, &handler_dest, &msg))
423 goto err;
424
425 if (DBUG_EVALUATE_IF("mts_worker_thread_init_fails", 1, 0) ||
426 worker->rli_init_info(is_gaps_collecting_phase))
427 {
428 DBUG_EXECUTE_IF("enable_mts_worker_failure_init",
429 {
430 DBUG_SET("-d,mts_worker_thread_init_fails");
431 DBUG_SET("-d,enable_mts_worker_failure_init");
432 });
433 DBUG_EXECUTE_IF("enable_mts_wokrer_failure_in_recovery_finalize",
434 {
435 DBUG_SET("-d,mts_worker_thread_init_fails");
436 DBUG_SET("-d,enable_mts_wokrer_failure_in_recovery_finalize");
437 });
438 msg= "Failed to initialize the worker info structure";
439 goto err;
440 }
441
442 if (rli->info_thd && rli->info_thd->is_error())
443 {
444 msg= "Failed to initialize worker info table";
445 goto err;
446 }
447
448 DBUG_RETURN(worker);
449
450 err:
451 delete handler_src;
452 delete handler_dest;
453 if (worker)
454 {
455 /*
456 The handler was previously deleted so we need to remove
457 any reference to it.
458 */
459 worker->set_rpl_info_handler(NULL);
460 delete worker;
461 }
462 sql_print_error("Error creating relay log info: %s.", msg);
463 DBUG_RETURN(NULL);
464 }
465
build_worker_info_name(char * to,const char * path,const char * fname)466 static void build_worker_info_name(char* to,
467 const char* path,
468 const char* fname)
469 {
470 DBUG_ASSERT(to);
471 char* pos= to;
472 if (path[0])
473 pos= strmov(pos, path);
474 pos= strmov(pos, "worker-");
475 pos= strmov(pos, fname);
476 strmov(pos, ".");
477 }
478
479 /**
480 Initializes startup information on diferent repositories.
481 */
init_repository_metadata()482 void Rpl_info_factory::init_repository_metadata()
483 {
484 /* Needed for the file names and paths for worker info files. */
485 size_t len;
486 char* relay_log_info_file_name;
487 char relay_log_info_file_dirpart[FN_REFLEN];
488
489 /* Extract the directory name from relay_log_info_file */
490 dirname_part(relay_log_info_file_dirpart, relay_log_info_file, &len);
491 relay_log_info_file_name= relay_log_info_file + len;
492
493 rli_table_data.n_fields= Relay_log_info::get_number_info_rli_fields();
494 rli_table_data.schema= MYSQL_SCHEMA_NAME.str;
495 rli_table_data.name= RLI_INFO_NAME.str;
496 rli_file_data.n_fields= Relay_log_info::get_number_info_rli_fields();
497 strmov(rli_file_data.name, relay_log_info_file);
498 strmov(rli_file_data.pattern, relay_log_info_file);
499 rli_file_data.name_indexed= false;
500
501 mi_table_data.n_fields= Master_info::get_number_info_mi_fields();
502 mi_table_data.schema= MYSQL_SCHEMA_NAME.str;
503 mi_table_data.name= MI_INFO_NAME.str;
504 mi_file_data.n_fields= Master_info::get_number_info_mi_fields();
505 strmov(mi_file_data.name, master_info_file);
506 strmov(mi_file_data.pattern, master_info_file);
507 rli_file_data.name_indexed= false;
508
509 worker_table_data.n_fields= Slave_worker::get_number_worker_fields();
510 worker_table_data.schema= MYSQL_SCHEMA_NAME.str;
511 worker_table_data.name= WORKER_INFO_NAME.str;
512 worker_file_data.n_fields= Slave_worker::get_number_worker_fields();
513 build_worker_info_name(worker_file_data.name,
514 relay_log_info_file_dirpart,
515 relay_log_info_file_name);
516 build_worker_info_name(worker_file_data.pattern,
517 relay_log_info_file_dirpart,
518 relay_log_info_file_name);
519 worker_file_data.name_indexed= true;
520 }
521
522
523 /**
524 Decides during startup what repository will be used based on the following
525 decision table:
526
527 \code
528 |--------------+-----------------------+-----------------------|
529 | Exists \ Opt | SOURCE | DESTINATION |
530 |--------------+-----------------------+-----------------------|
531 | ~is_s, ~is_d | - | Create/Update D |
532 | ~is_s, is_d | - | Continue with D |
533 | is_s, ~is_d | Copy S into D | Create/Update D |
534 | is_s, is_d | Error | Error |
535 |--------------+-----------------------+-----------------------|
536 \endcode
537
538 @param[in] info Either master info or relay log info.
539 @param[in] option Identifies the type of the repository that will
540 be used, i.e., destination repository.
541 @param[out] handler_src Source repository from where information is
542 copied into the destination repository.
543 @param[out] handler_dest Destination repository to where informaiton is
544 copied.
545 @param[out] msg Error message if something goes wrong.
546
547 @retval FALSE No error
548 @retval TRUE Failure
549 */
decide_repository(Rpl_info * info,uint option,Rpl_info_handler ** handler_src,Rpl_info_handler ** handler_dest,const char ** msg)550 bool Rpl_info_factory::decide_repository(Rpl_info *info, uint option,
551 Rpl_info_handler **handler_src,
552 Rpl_info_handler **handler_dest,
553 const char **msg)
554 {
555 bool error= true;
556 enum_return_check return_check_src= ERROR_CHECKING_REPOSITORY;
557 enum_return_check return_check_dst= ERROR_CHECKING_REPOSITORY;
558 bool binlog_prot_acquired= false;
559 THD * const thd= current_thd;
560 DBUG_ENTER("Rpl_info_factory::decide_repository");
561
562 if (option == INFO_REPOSITORY_DUMMY)
563 {
564 delete (*handler_src);
565 *handler_src= NULL;
566 info->set_rpl_info_handler(*handler_dest);
567 error = false;
568 goto err;
569 }
570
571 DBUG_ASSERT((*handler_src) != NULL && (*handler_dest) != NULL &&
572 (*handler_src) != (*handler_dest));
573
574 return_check_src= check_src_repository(info, option, handler_src);
575 return_check_dst= (*handler_dest)->do_check_info(info->get_internal_id());
576
577 if (return_check_src == ERROR_CHECKING_REPOSITORY ||
578 return_check_dst == ERROR_CHECKING_REPOSITORY)
579 {
580 /*
581 If there is a problem with one of the repositories we print out
582 more information and exit.
583 */
584 DBUG_RETURN(check_error_repository(info, *handler_src, *handler_dest,
585 return_check_src,
586 return_check_dst, msg));
587 }
588 else
589 {
590 if ((return_check_src == REPOSITORY_EXISTS &&
591 return_check_dst == REPOSITORY_DOES_NOT_EXIST) ||
592 (return_check_src == REPOSITORY_EXISTS &&
593 return_check_dst == REPOSITORY_EXISTS))
594 {
595 /*
596 If there is no error, we can proceed with the normal operation.
597 However, if both repositories are set an error will be printed
598 out.
599 */
600 if (return_check_src == REPOSITORY_EXISTS &&
601 return_check_dst == REPOSITORY_EXISTS)
602 {
603 *msg= "Multiple replication metadata repository instances "
604 "found with data in them. Unable to decide which is "
605 "the correct one to choose";
606 goto err;
607 }
608
609 /*
610 Do a low-level initialization to be able to do a state transfer.
611 */
612 if (init_repositories(info, handler_src, handler_dest, msg))
613 goto err;
614
615 /*
616 Acquire a backup binlog protection lock, because Rpl_info::copy_info()
617 will modify master binary log coordinates.
618 */
619 if (thd && !thd->backup_binlog_lock.is_acquired())
620 {
621 const ulong timeout= thd->variables.lock_wait_timeout;
622
623 DBUG_PRINT("debug", ("Acquiring binlog protection lock"));
624
625 if (thd->backup_binlog_lock.acquire_protection(thd, MDL_EXPLICIT,
626 timeout))
627 goto err;
628
629 binlog_prot_acquired= true;
630 }
631
632 /*
633 Transfer information from source to destination and delete the
634 source. Note this is not fault-tolerant and a crash before removing
635 source may cause the next restart to fail as is_src and is_dest may
636 be true. Moreover, any failure in removing the source may lead to
637 the same.
638 /Alfranio
639 */
640 if (info->copy_info(*handler_src, *handler_dest) ||
641 (*handler_dest)->flush_info(true))
642 {
643 *msg= "Error transfering information";
644 goto err;
645 }
646 (*handler_src)->end_info();
647 if ((*handler_src)->remove_info())
648 {
649 *msg= "Error removing old repository";
650 goto err;
651 }
652 }
653 else if (return_check_src == REPOSITORY_DOES_NOT_EXIST &&
654 return_check_dst == REPOSITORY_EXISTS)
655 {
656 DBUG_ASSERT(info->get_rpl_info_handler() == NULL);
657 if ((*handler_dest)->do_init_info(info->get_internal_id()))
658 {
659 *msg= "Error reading repository";
660 goto err;
661 }
662 }
663 else
664 {
665 DBUG_ASSERT(return_check_src == REPOSITORY_DOES_NOT_EXIST &&
666 return_check_dst == REPOSITORY_DOES_NOT_EXIST);
667 info->inited= false;
668 }
669
670 delete (*handler_src);
671 *handler_src= NULL;
672 info->set_rpl_info_handler(*handler_dest);
673 error= false;
674 }
675
676 err:
677 if (binlog_prot_acquired)
678 {
679 DBUG_PRINT("debug", ("Releasing binlog protection lock"));
680 thd->backup_binlog_lock.release_protection(thd);
681 }
682 DBUG_RETURN(error);
683 }
684
685
686 /**
687 This method is called by the decide_repository() and is used to check if
688 the source repository exits.
689
690 @param[in] info Either master info or relay log info.
691 @param[in] option Identifies the type of the repository that will
692 be used, i.e., destination repository.
693 @param[out] handler_src Source repository from where information is
694
695 @return enum_return_check The repository's status.
696 */
697 enum_return_check
check_src_repository(Rpl_info * info,uint option,Rpl_info_handler ** handler_src)698 Rpl_info_factory::check_src_repository(Rpl_info *info,
699 uint option,
700 Rpl_info_handler **handler_src)
701 {
702 enum_return_check return_check_src= ERROR_CHECKING_REPOSITORY;
703 bool live_migration = info->get_rpl_info_handler() != NULL;
704
705 if (!live_migration)
706 {
707 /*
708 This is not a live migration and we don't know whether the repository
709 exists or not.
710 */
711 return_check_src= (*handler_src)->do_check_info(info->get_internal_id());
712
713 /*
714 Since this is not a live migration, if we are using file repository
715 and there is some error on table repository (for instance, engine
716 disabled) we can ignore it instead of stopping replication.
717 A warning saying that table is not ready to be used was logged.
718 */
719 if (ERROR_CHECKING_REPOSITORY == return_check_src &&
720 INFO_REPOSITORY_FILE == option &&
721 INFO_REPOSITORY_TABLE == (*handler_src)->do_get_rpl_info_type())
722 {
723 return_check_src= REPOSITORY_DOES_NOT_EXIST;
724 /*
725 If a already existent thread was used to access info tables,
726 current_thd will point to it and we must clear access error on
727 it. If a temporary thread was used, then there is nothing to
728 clean because the thread was already deleted.
729 See Rpl_info_table_access::create_thd().
730 */
731 if (current_thd)
732 current_thd->clear_error();
733 }
734 }
735 else
736 {
737 /*
738 This is a live migration as the repository is already associated to.
739 However, we cannot assume that it really exists, for instance, if a
740 file was really created.
741
742 This situation may happen when we start a slave for the first time
743 but skips its initialization and tries to migrate it.
744 */
745 return_check_src= (*handler_src)->do_check_info();
746 }
747
748 return return_check_src;
749 }
750
751
752 /**
753 This method is called by the decide_repository() and is used print out
754 information on errors.
755
756 @param info Either master info or relay log info.
757 @param handler_src Source repository from where information is
758 copied into the destination repository.
759 @param handler_dest Destination repository to where informaiton is
760 copied.
761 @param err_src Possible error status of the source repo check
762 @param err_dst Possible error status of the destination repo check
763 @param[out] msg Error message if something goes wrong.
764
765 @retval TRUE Failure
766 */
check_error_repository(Rpl_info * info,Rpl_info_handler * handler_src,Rpl_info_handler * handler_dest,enum_return_check err_src,enum_return_check err_dst,const char ** msg)767 bool Rpl_info_factory::check_error_repository(Rpl_info *info,
768 Rpl_info_handler *handler_src,
769 Rpl_info_handler *handler_dest,
770 enum_return_check err_src,
771 enum_return_check err_dst,
772 const char **msg)
773 {
774 bool error = true;
775
776 /*
777 If there is an error in any of the source or destination
778 repository checks, the normal operation can't be proceeded.
779 The runtime repository won't be initialized.
780 */
781 if (err_src == ERROR_CHECKING_REPOSITORY)
782 sql_print_error("Error in checking %s repository info type of %s.",
783 handler_src->get_description_info(),
784 handler_src->get_rpl_info_type_str());
785 if (err_dst == ERROR_CHECKING_REPOSITORY)
786 sql_print_error("Error in checking %s repository info type of %s.",
787 handler_dest->get_description_info(),
788 handler_dest->get_rpl_info_type_str());
789 *msg= "Error checking repositories";
790 return error;
791 }
792
793
794 /**
795 This method is called by the decide_repository() and is used to initialize
796 the repositories through a low-level interfacei, which means that if they
797 do not exist nothing will be created.
798
799 @param[in] info Either master info or relay log info.
800 @param[out] handler_src Source repository from where information is
801 copied into the destination repository.
802 @param[out] handler_dest Destination repository to where informaiton is
803 copied.
804 @param[out] msg Error message if something goes wrong.
805
806 @retval FALSE No error
807 @retval TRUE Failure
808 */
init_repositories(Rpl_info * info,Rpl_info_handler ** handler_src,Rpl_info_handler ** handler_dest,const char ** msg)809 bool Rpl_info_factory::init_repositories(Rpl_info *info,
810 Rpl_info_handler **handler_src,
811 Rpl_info_handler **handler_dest,
812 const char **msg)
813 {
814 bool live_migration = info->get_rpl_info_handler() != NULL;
815
816 if (!live_migration)
817 {
818 if ((*handler_src)->do_init_info(info->get_internal_id()) ||
819 (*handler_dest)->do_init_info(info->get_internal_id()))
820 {
821 *msg= "Error transfering information";
822 return true;
823 }
824 }
825 else
826 {
827 if ((*handler_dest)->do_init_info(info->get_internal_id()))
828 {
829 *msg= "Error transfering information";
830 return true;
831 }
832 }
833 return false;
834 }
835
836
837 /**
838 Creates repositories that will be associated to either the Master_info
839 or Relay_log_info.
840
841 @param[in] table_data Defines information to create a table repository.
842 @param[in] file_data Defines information to create a file repository.
843 @param[in] rep_option Identifies the type of the repository that will
844 be used, i.e., destination repository.
845 @param[in] instance Identifies the instance of the repository that
846 will be used.
847 @param[out] handler_src Source repository from where information is
848 copied into the destination repository.
849 @param[out] handler_dest Destination repository to where informaiton is
850 copied.
851 @param[out] msg Error message if something goes wrong.
852
853 @retval FALSE No error
854 @retval TRUE Failure
855 */
init_repositories(const struct_table_data table_data,const struct_file_data file_data,uint rep_option,uint instance,Rpl_info_handler ** handler_src,Rpl_info_handler ** handler_dest,const char ** msg)856 bool Rpl_info_factory::init_repositories(const struct_table_data table_data,
857 const struct_file_data file_data,
858 uint rep_option,
859 uint instance,
860 Rpl_info_handler **handler_src,
861 Rpl_info_handler **handler_dest,
862 const char **msg)
863 {
864 bool error= TRUE;
865 *msg= "Failed to allocate memory for master info repositories";
866
867 DBUG_ENTER("Rpl_info_factory::init_mi_repositories");
868
869 DBUG_ASSERT(handler_dest != NULL);
870 switch (rep_option)
871 {
872 case INFO_REPOSITORY_FILE:
873 if (!(*handler_dest= new Rpl_info_file(file_data.n_fields,
874 file_data.pattern,
875 file_data.name,
876 file_data.name_indexed)))
877 goto err;
878 if (handler_src &&
879 !(*handler_src= new Rpl_info_table(table_data.n_fields,
880 table_data.schema,
881 table_data.name)))
882 goto err;
883 break;
884
885 case INFO_REPOSITORY_TABLE:
886 if (!(*handler_dest= new Rpl_info_table(table_data.n_fields,
887 table_data.schema,
888 table_data.name)))
889 goto err;
890 if (handler_src &&
891 !(*handler_src= new Rpl_info_file(file_data.n_fields,
892 file_data.pattern,
893 file_data.name,
894 file_data.name_indexed)))
895 goto err;
896 break;
897
898 case INFO_REPOSITORY_DUMMY:
899 if (!(*handler_dest= new Rpl_info_dummy(Master_info::get_number_info_mi_fields())))
900 goto err;
901 break;
902
903 default:
904 DBUG_ASSERT(0);
905 }
906 error= FALSE;
907
908 err:
909 DBUG_RETURN(error);
910 }
911
scan_repositories(uint * found_instances,uint * found_rep_option,const struct_table_data table_data,const struct_file_data file_data,const char ** msg)912 bool Rpl_info_factory::scan_repositories(uint* found_instances,
913 uint* found_rep_option,
914 const struct_table_data table_data,
915 const struct_file_data file_data,
916 const char **msg)
917 {
918 bool error= false;
919 uint file_instances= 0;
920 uint table_instances= 0;
921 DBUG_ASSERT(found_rep_option != NULL);
922
923 DBUG_ENTER("Rpl_info_factory::scan_repositories");
924
925 if (Rpl_info_table::do_count_info(table_data.n_fields, table_data.schema,
926 table_data.name, &table_instances))
927 {
928 error= true;
929 goto err;
930 }
931
932 if (Rpl_info_file::do_count_info(file_data.n_fields, file_data.pattern,
933 file_data.name_indexed, &file_instances))
934 {
935 error= true;
936 goto err;
937 }
938
939 if (file_instances != 0 && table_instances != 0)
940 {
941 error= true;
942 *msg= "Multiple repository instances found with data in "
943 "them. Unable to decide which is the correct one to "
944 "choose";
945 goto err;
946 }
947
948 if (table_instances != 0)
949 {
950 *found_instances= table_instances;
951 *found_rep_option= INFO_REPOSITORY_TABLE;
952 }
953 else if (file_instances != 0)
954 {
955 *found_instances= file_instances;
956 *found_rep_option= INFO_REPOSITORY_FILE;
957 }
958 else
959 {
960 *found_instances= 0;
961 *found_rep_option= INVALID_INFO_REPOSITORY;
962 }
963
964 err:
965 DBUG_RETURN(error);
966 }
967