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 "rpl_info_factory.h"
24
25 #include "log.h" // sql_print_error
26 #include "mysqld.h" // key_master_info_run_lock
27 #include "rpl_info_dummy.h" // Rpl_info_dummy
28 #include "rpl_info_file.h" // Rpl_info_file
29 #include "rpl_info_table.h" // Rpl_info_table
30 #include "rpl_info_table_access.h" // Rpl_info_table_access
31 #include "rpl_mi.h" // Master_info
32 #include "rpl_msr.h" // channel_map
33 #include "rpl_rli.h" // Relay_log_info
34 #include "rpl_rli_pdb.h" // Slave_worker
35
36
37 /*
38 Defines meta information on diferent repositories.
39 */
40 Rpl_info_factory::struct_table_data Rpl_info_factory::rli_table_data;
41 Rpl_info_factory::struct_file_data Rpl_info_factory::rli_file_data;
42 Rpl_info_factory::struct_table_data Rpl_info_factory::mi_table_data;
43 Rpl_info_factory::struct_file_data Rpl_info_factory::mi_file_data;
44 Rpl_info_factory::struct_file_data Rpl_info_factory::worker_file_data;
45 Rpl_info_factory::struct_table_data Rpl_info_factory::worker_table_data;
46
47 /**
48 Creates a Master info repository whose type is defined as a parameter.
49
50 @param[in] mi_option Type of the repository, e.g. FILE TABLE.
51 @param[in] channel the channel for which mi is to be created
52 @param[in] to_decide_repo the flag is set to true if mi repositories
53 are allowed to convert. For details,
54 see init_slave()
55
56 The execution fails if a user requests a type but a different type
57 already exists in the system. This is done to avoid that a user
58 accidentally accesses the wrong repository and makes the slave go out
59 of sync.
60
61 @retval Pointer to Master_info Success
62 @retval NULL Failure
63 */
create_mi(uint mi_option,const char * channel,bool to_decide_repo)64 Master_info *Rpl_info_factory::create_mi(uint mi_option, const char* channel,
65 bool to_decide_repo)
66 {
67 Master_info* mi= NULL;
68 Rpl_info_handler* handler_src= NULL;
69 Rpl_info_handler* handler_dest= NULL;
70 uint instances= 1;
71 const char *msg= "Failed to allocate memory for the master info "
72 "structure";
73
74 DBUG_ENTER("Rpl_info_factory::create_mi");
75
76 if (!(mi= new Master_info(
77 #ifdef HAVE_PSI_INTERFACE
78 &key_master_info_run_lock,
79 &key_master_info_data_lock,
80 &key_master_info_sleep_lock,
81 &key_master_info_thd_lock,
82 &key_master_info_data_cond,
83 &key_master_info_start_cond,
84 &key_master_info_stop_cond,
85 &key_master_info_sleep_cond,
86 #endif
87 instances, channel
88 )))
89 goto err;
90
91 if(init_repositories(mi_table_data, mi_file_data, mi_option, instances,
92 &handler_src, &handler_dest, &msg))
93 goto err;
94
95 if(to_decide_repo)
96 {
97 if (decide_repository(mi, mi_option, &handler_src, &handler_dest, &msg))
98 goto err;
99 }
100 else
101 {
102 if (handler_dest->get_rpl_info_type() != INFO_REPOSITORY_TABLE)
103 {
104 sql_print_error("Slave: Wrong repository. Respository should be TABLE");
105 goto err;
106 }
107 mi->set_rpl_info_handler(handler_dest);
108
109 if (mi->set_info_search_keys(handler_dest))
110 goto err;
111
112 delete handler_src;
113
114 }
115
116 DBUG_RETURN(mi);
117
118 err:
119 delete handler_src;
120 delete handler_dest;
121 if (mi)
122 {
123 /*
124 The handler was previously deleted so we need to remove
125 any reference to it.
126 */
127 mi->set_rpl_info_handler(NULL);
128 mi->channel_wrlock();
129 delete mi;
130 }
131 sql_print_error("Error creating master info: %s.", msg);
132 DBUG_RETURN(NULL);
133 }
134
135 /**
136 Allows to change the master info repository after startup.
137
138 @param[in] mi Reference to Master_info.
139 @param[in] mi_option Type of the repository, e.g. FILE TABLE.
140 @param[out] msg Error message if something goes wrong.
141
142 @retval FALSE No error
143 @retval TRUE Failure
144 */
change_mi_repository(Master_info * mi,uint mi_option,const char ** msg)145 bool Rpl_info_factory::change_mi_repository(Master_info *mi,
146 uint mi_option,
147 const char **msg)
148 {
149 Rpl_info_handler* handler_src= mi->get_rpl_info_handler();
150 Rpl_info_handler* handler_dest= NULL;
151 uint instances= 1;
152 DBUG_ENTER("Rpl_info_factory::change_mi_repository");
153
154 DBUG_ASSERT(handler_src);
155
156 if (init_repositories(mi_table_data, mi_file_data, mi_option, instances,
157 NULL, &handler_dest, msg))
158 goto err;
159
160 if (decide_repository(mi, mi_option, &handler_src, &handler_dest, msg))
161 goto err;
162
163 DBUG_RETURN(FALSE);
164
165 err:
166 delete handler_dest;
167 handler_dest= NULL;
168
169 sql_print_error("Error changing the type of master info's repository: %s.", *msg);
170 DBUG_RETURN(TRUE);
171 }
172
173 /**
174 Creates a Relay log info repository whose type is defined as a parameter.
175
176 @param[in] rli_option Type of the Relay log info repository
177 @param[in] is_slave_recovery If the slave should try to start a recovery
178 process to get consistent relay log files
179 @param[in] channel the channel for which mi is to be created
180 @param[in] to_decide_repo If true, rli repositories are allowed
181 to convert from one repo to other
182
183
184 The execution fails if a user requests a type but a different type
185 already exists in the system. This is done to avoid that a user
186 accidentally accesses the wrong repository and make the slave go out
187 of sync.
188
189 @retval Pointer to Relay_log_info Success
190 @retval NULL Failure
191 */
create_rli(uint rli_option,bool is_slave_recovery,const char * channel,bool to_decide_repo)192 Relay_log_info *Rpl_info_factory::create_rli(uint rli_option,
193 bool is_slave_recovery,
194 const char* channel,
195 bool to_decide_repo)
196 {
197 Relay_log_info *rli= NULL;
198 Rpl_info_handler* handler_src= NULL;
199 Rpl_info_handler* handler_dest= NULL;
200 uint instances= 1;
201 uint worker_repository= INVALID_INFO_REPOSITORY;
202 uint worker_instances= 1;
203 const char *msg= NULL;
204 const char *msg_alloc= "Failed to allocate memory for the relay log info "
205 "structure";
206
207 DBUG_ENTER("Rpl_info_factory::create_rli");
208
209 /*
210 Returns how many occurrences of worker's repositories exist. For example,
211 if the repository is a table, this retrieves the number of rows in it.
212 Besides, it also returns the type of the repository where entries were
213 found.
214 */
215 if (rli_option != INFO_REPOSITORY_DUMMY &&
216 scan_repositories(&worker_instances, &worker_repository,
217 worker_table_data, worker_file_data, &msg))
218 goto err;
219
220 if (!(rli= new Relay_log_info(is_slave_recovery
221 #ifdef HAVE_PSI_INTERFACE
222 ,&key_relay_log_info_run_lock,
223 &key_relay_log_info_data_lock,
224 &key_relay_log_info_sleep_lock,
225 &key_relay_log_info_thd_lock,
226 &key_relay_log_info_data_cond,
227 &key_relay_log_info_start_cond,
228 &key_relay_log_info_stop_cond,
229 &key_relay_log_info_sleep_cond
230 #endif
231 , instances, channel,
232 (rli_option != INFO_REPOSITORY_TABLE
233 && rli_option != INFO_REPOSITORY_FILE)
234 )))
235 {
236 msg= msg_alloc;
237 goto err;
238 }
239
240 if(init_repositories(rli_table_data, rli_file_data, rli_option, instances,
241 &handler_src, &handler_dest, &msg))
242 goto err;
243
244 if (rli_option != INFO_REPOSITORY_DUMMY &&
245 worker_repository != INVALID_INFO_REPOSITORY &&
246 worker_repository != rli_option)
247 {
248 opt_rli_repository_id= rli_option= worker_repository;
249 sql_print_warning("It is not possible to change the type of the relay log "
250 "repository because there are workers repositories with "
251 "possible execution gaps. "
252 "The value of --relay_log_info_repository is altered to "
253 "one of the found Worker repositories. "
254 "The gaps have to be sorted out before resuming with "
255 "the type change.");
256 std::swap(handler_src, handler_dest);
257 }
258
259 if (to_decide_repo)
260 {
261 if (decide_repository(rli, rli_option, &handler_src, &handler_dest, &msg))
262 goto err;
263 }
264 else
265 {
266 if(channel != NULL)
267 {
268 /* Here dest code should be TABLE type repo. See, init_slave() */
269 if (handler_dest->get_rpl_info_type() != INFO_REPOSITORY_TABLE)
270 {
271 sql_print_error("Slave: Wrong repository. Repository should be TABLE");
272 goto err;
273 }
274
275 if(rli->set_info_search_keys(handler_dest))
276 goto err;
277 }
278
279 rli->set_rpl_info_handler(handler_dest);
280
281 /*
282 By this time, rli must be loaded with it's primary key,
283 which is channel_name
284 */
285 delete handler_src;
286
287 }
288
289 DBUG_RETURN(rli);
290
291 err:
292 delete handler_src;
293 delete handler_dest;
294 if (rli)
295 {
296 /*
297 The handler was previously deleted so we need to remove
298 any reference to it.
299 */
300 rli->set_rpl_info_handler(NULL);
301 delete rli;
302 }
303 sql_print_error("Error creating relay log info: %s.", msg);
304 DBUG_RETURN(NULL);
305 }
306
307 /**
308 Allows to change the relay log info repository after startup.
309
310 @param[in] mi Pointer to Relay_log_info.
311 @param[in] mi_option Type of the repository, e.g. FILE TABLE.
312 @param[out] msg Error message if something goes wrong.
313
314 @retval FALSE No error
315 @retval TRUE Failure
316 */
change_rli_repository(Relay_log_info * rli,uint rli_option,const char ** msg)317 bool Rpl_info_factory::change_rli_repository(Relay_log_info *rli,
318 uint rli_option,
319 const char **msg)
320 {
321 Rpl_info_handler* handler_src= rli->get_rpl_info_handler();
322 Rpl_info_handler* handler_dest= NULL;
323 uint instances= 1;
324 DBUG_ENTER("Rpl_info_factory::change_rli_repository");
325
326 DBUG_ASSERT(handler_src != NULL);
327
328 if (init_repositories(rli_table_data, rli_file_data, rli_option,
329 instances, NULL, &handler_dest, msg))
330 goto err;
331
332 if (decide_repository(rli, rli_option, &handler_src, &handler_dest,
333 msg))
334 goto err;
335
336 DBUG_RETURN(FALSE);
337
338 err:
339 delete handler_dest;
340 handler_dest= NULL;
341
342 sql_print_error("Error changing the type of relay log info's repository: %s.", *msg);
343 DBUG_RETURN(TRUE);
344 }
345
346 /**
347 Delete all info from Worker info tables to render them useless in
348 future MTS recovery, and indicate that in Coordinator info table.
349
350 @return false on success, true when a failure in deletion or writing
351 to Coordinator table fails.
352 */
reset_workers(Relay_log_info * rli)353 bool Rpl_info_factory::reset_workers(Relay_log_info *rli)
354 {
355 bool error= true;
356
357 DBUG_ENTER("Rpl_info_factory::reset_workers");
358
359 if (rli->recovery_parallel_workers == 0)
360 DBUG_RETURN(0);
361
362 if (Rpl_info_file::do_reset_info(Slave_worker::get_number_worker_fields(),
363 worker_file_data.pattern,
364 worker_file_data.name_indexed))
365 goto err;
366
367 if (Rpl_info_table::do_reset_info(Slave_worker::get_number_worker_fields(),
368 MYSQL_SCHEMA_NAME.str, WORKER_INFO_NAME.str,
369 rli->channel,
370 Slave_worker::get_channel_field_index()))
371 goto err;
372
373 error= false;
374
375 DBUG_EXECUTE_IF("mts_debug_reset_workers_fails", error= true;);
376
377 err:
378 if (error)
379 sql_print_error("Could not delete from Slave Workers info repository.");
380 rli->recovery_parallel_workers= 0;
381 rli->clear_mts_recovery_groups();
382 if (rli->flush_info(true))
383 {
384 error= true;
385 sql_print_error("Could not store the reset Slave Worker state into "
386 "the slave info repository.");
387 }
388 DBUG_RETURN(error);
389 }
390
391 /**
392 Creates a Slave worker repository whose type is defined as a parameter.
393
394 @param[in] rli_option Type of the repository, e.g. FILE TABLE.
395 @param[in] rli Pointer to Relay_log_info.
396
397 The execution fails if a user requests a type but a different type
398 already exists in the system. This is done to avoid that a user
399 accidentally accesses the wrong repository and make the slave go out
400 of sync.
401
402 @retval Pointer to Slave_worker Success
403 @retval NULL Failure
404 */
create_worker(uint rli_option,uint worker_id,Relay_log_info * rli,bool is_gaps_collecting_phase)405 Slave_worker *Rpl_info_factory::create_worker(uint rli_option, uint worker_id,
406 Relay_log_info *rli,
407 bool is_gaps_collecting_phase)
408 {
409 Rpl_info_handler* handler_src= NULL;
410 Rpl_info_handler* handler_dest= NULL;
411 Slave_worker* worker= NULL;
412 const char *msg= "Failed to allocate memory for the worker info "
413 "structure";
414
415 DBUG_ENTER("Rpl_info_factory::create_worker");
416
417 /*
418 Define the name of the worker and its repository.
419 */
420 char *pos= my_stpcpy(worker_file_data.name, worker_file_data.pattern);
421 sprintf(pos, "%u", worker_id + 1);
422
423 if (!(worker= new Slave_worker(rli
424 #ifdef HAVE_PSI_INTERFACE
425 ,&key_relay_log_info_run_lock,
426 &key_relay_log_info_data_lock,
427 &key_relay_log_info_sleep_lock,
428 &key_relay_log_info_thd_lock,
429 &key_relay_log_info_data_cond,
430 &key_relay_log_info_start_cond,
431 &key_relay_log_info_stop_cond,
432 &key_relay_log_info_sleep_cond
433 #endif
434 , worker_id, rli->get_channel()
435 )))
436 goto err;
437
438
439 if(init_repositories(worker_table_data, worker_file_data, rli_option,
440 worker_id + 1, &handler_src, &handler_dest, &msg))
441 goto err;
442 /*
443 Preparing the being set up handler with search keys early.
444 The file repo type handler can't be manupulated this way and it does
445 not have to.
446 */
447 if (handler_dest->get_rpl_info_type() == INFO_REPOSITORY_TABLE)
448 worker->set_info_search_keys(handler_dest);
449
450 /* get_num_instances() requires channel_map lock */
451 /*
452 DBUG_ASSERT(channel_map.get_num_instances() <= 1 ||
453 (rli_option == 1 && handler_dest->get_rpl_info_type() == 1));
454 */
455 if (decide_repository(worker, rli_option, &handler_src, &handler_dest, &msg))
456 goto err;
457
458 if (DBUG_EVALUATE_IF("mts_worker_thread_init_fails", 1, 0) ||
459 worker->rli_init_info(is_gaps_collecting_phase))
460 {
461 DBUG_EXECUTE_IF("enable_mts_worker_failure_init",
462 {
463 DBUG_SET("-d,mts_worker_thread_init_fails");
464 DBUG_SET("-d,enable_mts_worker_failure_init");
465 });
466 DBUG_EXECUTE_IF("enable_mts_wokrer_failure_in_recovery_finalize",
467 {
468 DBUG_SET("-d,mts_worker_thread_init_fails");
469 DBUG_SET("-d,enable_mts_wokrer_failure_in_recovery_finalize");
470 });
471 msg= "Failed to initialize the worker info structure";
472 goto err;
473 }
474
475 if (rli->info_thd && rli->info_thd->is_error())
476 {
477 msg= "Failed to initialize worker info table";
478 goto err;
479 }
480 DBUG_RETURN(worker);
481
482 err:
483 delete handler_src;
484 delete handler_dest;
485 if (worker)
486 {
487 /*
488 The handler was previously deleted so we need to remove
489 any reference to it.
490 */
491 worker->set_rpl_info_handler(NULL);
492 delete worker;
493 }
494 sql_print_error("Error creating relay log info: %s.", msg);
495 DBUG_RETURN(NULL);
496 }
497
build_worker_info_name(char * to,const char * path,const char * fname)498 static void build_worker_info_name(char* to,
499 const char* path,
500 const char* fname)
501 {
502 DBUG_ASSERT(to);
503 char* pos= to;
504 if (path[0])
505 pos= my_stpcpy(pos, path);
506 pos= my_stpcpy(pos, "worker-");
507 pos= my_stpcpy(pos, fname);
508 my_stpcpy(pos, ".");
509 }
510
511 /**
512 Initializes startup information on diferent repositories.
513 */
init_repository_metadata()514 void Rpl_info_factory::init_repository_metadata()
515 {
516 /* Needed for the file names and paths for worker info files. */
517 size_t len;
518 char* relay_log_info_file_name;
519 char relay_log_info_file_dirpart[FN_REFLEN];
520
521 /* Extract the directory name from relay_log_info_file */
522 dirname_part(relay_log_info_file_dirpart, relay_log_info_file, &len);
523 relay_log_info_file_name= relay_log_info_file + len;
524
525 rli_table_data.n_fields= Relay_log_info::get_number_info_rli_fields();
526 rli_table_data.schema= MYSQL_SCHEMA_NAME.str;
527 rli_table_data.name= RLI_INFO_NAME.str;
528 rli_table_data.n_pk_fields= 0;
529 rli_table_data.pk_field_indexes= NULL;
530 rli_file_data.n_fields= Relay_log_info::get_number_info_rli_fields();
531 my_stpcpy(rli_file_data.name, relay_log_info_file);
532 my_stpcpy(rli_file_data.pattern, relay_log_info_file);
533 rli_file_data.name_indexed= false;
534
535 mi_table_data.n_fields= Master_info::get_number_info_mi_fields();
536 mi_table_data.schema= MYSQL_SCHEMA_NAME.str;
537 mi_table_data.name= MI_INFO_NAME.str;
538 mi_table_data.n_pk_fields= 1;
539 mi_table_data.pk_field_indexes= Master_info::get_table_pk_field_indexes();
540 mi_file_data.n_fields= Master_info::get_number_info_mi_fields();
541 my_stpcpy(mi_file_data.name, master_info_file);
542 my_stpcpy(mi_file_data.pattern, master_info_file);
543 rli_file_data.name_indexed= false;
544
545 worker_table_data.n_fields= Slave_worker::get_number_worker_fields();
546 worker_table_data.schema= MYSQL_SCHEMA_NAME.str;
547 worker_table_data.name= WORKER_INFO_NAME.str;
548 worker_table_data.n_pk_fields= 2;
549 worker_table_data.pk_field_indexes=
550 Slave_worker::get_table_pk_field_indexes();
551 worker_file_data.n_fields= Slave_worker::get_number_worker_fields();
552 build_worker_info_name(worker_file_data.name,
553 relay_log_info_file_dirpart,
554 relay_log_info_file_name);
555 build_worker_info_name(worker_file_data.pattern,
556 relay_log_info_file_dirpart,
557 relay_log_info_file_name);
558 worker_file_data.name_indexed= true;
559 }
560
561
562 /**
563 Decides during startup what repository will be used based on the following
564 decision table:
565
566 \code
567 |--------------+-----------------------+-----------------------|
568 | Exists \ Opt | SOURCE | DESTINATION |
569 |--------------+-----------------------+-----------------------|
570 | ~is_s, ~is_d | - | Create/Update D |
571 | ~is_s, is_d | - | Continue with D |
572 | is_s, ~is_d | Copy S into D | Create/Update D |
573 | is_s, is_d | Error | Error |
574 |--------------+-----------------------+-----------------------|
575 \endcode
576
577 @param[in] info Either master info or relay log info.
578 @param[in] option Identifies the type of the repository that will
579 be used, i.e., destination repository.
580 @param[out] handler_src Source repository from where information is
581 copied into the destination repository.
582 @param[out] handler_dest Destination repository to where informaiton is
583 copied.
584 @param[out] msg Error message if something goes wrong.
585
586 @retval FALSE No error
587 @retval TRUE Failure
588 */
decide_repository(Rpl_info * info,uint option,Rpl_info_handler ** handler_src,Rpl_info_handler ** handler_dest,const char ** msg)589 bool Rpl_info_factory::decide_repository(Rpl_info *info, uint option,
590 Rpl_info_handler **handler_src,
591 Rpl_info_handler **handler_dest,
592 const char **msg)
593 {
594 bool error= true;
595 enum_return_check return_check_src= ERROR_CHECKING_REPOSITORY;
596 enum_return_check return_check_dst= ERROR_CHECKING_REPOSITORY;
597 DBUG_ENTER("Rpl_info_factory::decide_repository");
598
599 if (option == INFO_REPOSITORY_DUMMY)
600 {
601 delete (*handler_src);
602 *handler_src= NULL;
603 info->set_rpl_info_handler(*handler_dest);
604 error = false;
605 goto err;
606 }
607
608 DBUG_ASSERT((*handler_src) != NULL && (*handler_dest) != NULL &&
609 (*handler_src) != (*handler_dest));
610
611 return_check_src= check_src_repository(info, option, handler_src);
612 return_check_dst= (*handler_dest)->do_check_info(info->get_internal_id()); // approx via scan, not field_values! Todo: reconsider any need for that at least in the Worker case
613
614 if (return_check_src == ERROR_CHECKING_REPOSITORY ||
615 return_check_dst == ERROR_CHECKING_REPOSITORY)
616 {
617 /*
618 If there is a problem with one of the repositories we print out
619 more information and exit.
620 */
621 DBUG_RETURN(check_error_repository(info, *handler_src, *handler_dest,
622 return_check_src,
623 return_check_dst, msg));
624 }
625 else
626 {
627 if ((return_check_src == REPOSITORY_EXISTS &&
628 return_check_dst == REPOSITORY_DOES_NOT_EXIST) ||
629 (return_check_src == REPOSITORY_EXISTS &&
630 return_check_dst == REPOSITORY_EXISTS))
631 {
632 /*
633 If there is no error, we can proceed with the normal operation.
634 However, if both repositories are set an error will be printed
635 out.
636 */
637 if (return_check_src == REPOSITORY_EXISTS &&
638 return_check_dst == REPOSITORY_EXISTS)
639 {
640 *msg= "Multiple replication metadata repository instances "
641 "found with data in them. Unable to decide which is "
642 "the correct one to choose";
643 goto err;
644 }
645
646 /*
647 Do a low-level initialization to be able to do a state transfer.
648 */
649 if (init_repositories(info, handler_src, handler_dest, msg))
650 goto err;
651
652 /*
653 Transfer information from source to destination and delete the
654 source. Note this is not fault-tolerant and a crash before removing
655 source may cause the next restart to fail as is_src and is_dest may
656 be true. Moreover, any failure in removing the source may lead to
657 the same.
658 /Alfranio
659 */
660 if (info->copy_info(*handler_src, *handler_dest) ||
661 (*handler_dest)->flush_info(true))
662 {
663 *msg= "Error transfering information";
664 goto err;
665 }
666 (*handler_src)->end_info();
667 if ((*handler_src)->remove_info())
668 {
669 *msg= "Error removing old repository";
670 goto err;
671 }
672 }
673 else if (return_check_src == REPOSITORY_DOES_NOT_EXIST &&
674 return_check_dst == REPOSITORY_EXISTS)
675 {
676 DBUG_ASSERT(info->get_rpl_info_handler() == NULL);
677 if ((*handler_dest)->do_init_info(info->get_internal_id()))
678 {
679 *msg= "Error reading repository";
680 goto err;
681 }
682 }
683 else
684 {
685 DBUG_ASSERT(return_check_src == REPOSITORY_DOES_NOT_EXIST &&
686 return_check_dst == REPOSITORY_DOES_NOT_EXIST);
687 info->inited= false;
688 }
689
690 delete (*handler_src);
691 *handler_src= NULL;
692 info->set_rpl_info_handler(*handler_dest);
693 error= false;
694 }
695
696 err:
697 DBUG_RETURN(error);
698 }
699
700
701 /**
702 This method is called by the decide_repository() and is used to check if
703 the source repository exits.
704
705 @param[in] info Either master info or relay log info.
706 @param[in] option Identifies the type of the repository that will
707 be used, i.e., destination repository.
708 @param[out] handler_src Source repository from where information is
709
710 @return enum_return_check The repository's status.
711 */
712 enum_return_check
check_src_repository(Rpl_info * info,uint option,Rpl_info_handler ** handler_src)713 Rpl_info_factory::check_src_repository(Rpl_info *info,
714 uint option,
715 Rpl_info_handler **handler_src)
716 {
717 enum_return_check return_check_src= ERROR_CHECKING_REPOSITORY;
718 bool live_migration = info->get_rpl_info_handler() != NULL;
719
720 if (!live_migration)
721 {
722 /*
723 This is not a live migration and we don't know whether the repository
724 exists or not.
725 */
726 return_check_src= (*handler_src)->do_check_info(info->get_internal_id());
727
728 /*
729 Since this is not a live migration, if we are using file repository
730 and there is some error on table repository (for instance, engine
731 disabled) we can ignore it instead of stopping replication.
732 A warning saying that table is not ready to be used was logged.
733 */
734 if (ERROR_CHECKING_REPOSITORY == return_check_src &&
735 INFO_REPOSITORY_FILE == option &&
736 INFO_REPOSITORY_TABLE == (*handler_src)->do_get_rpl_info_type())
737 {
738 return_check_src= REPOSITORY_DOES_NOT_EXIST;
739 /*
740 If a already existent thread was used to access info tables,
741 current_thd will point to it and we must clear access error on
742 it. If a temporary thread was used, then there is nothing to
743 clean because the thread was already deleted.
744 See Rpl_info_table_access::create_thd().
745 */
746 if (current_thd)
747 current_thd->clear_error();
748 }
749 }
750 else
751 {
752 /*
753 This is a live migration as the repository is already associated to.
754 However, we cannot assume that it really exists, for instance, if a
755 file was really created.
756
757 This situation may happen when we start a slave for the first time
758 but skips its initialization and tries to migrate it.
759 */
760 return_check_src= (*handler_src)->do_check_info();
761 }
762
763 return return_check_src;
764 }
765
766
767 /**
768 This method is called by the decide_repository() and is used print out
769 information on errors.
770
771 @param info Either master info or relay log info.
772 @param handler_src Source repository from where information is
773 copied into the destination repository.
774 @param handler_dest Destination repository to where informaiton is
775 copied.
776 @param err_src Possible error status of the source repo check
777 @param err_dst Possible error status of the destination repo check
778 @param[out] msg Error message if something goes wrong.
779
780 @retval TRUE Failure
781 */
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)782 bool Rpl_info_factory::check_error_repository(Rpl_info *info,
783 Rpl_info_handler *handler_src,
784 Rpl_info_handler *handler_dest,
785 enum_return_check err_src,
786 enum_return_check err_dst,
787 const char **msg)
788 {
789 bool error = true;
790
791 /*
792 If there is an error in any of the source or destination
793 repository checks, the normal operation can't be proceeded.
794 The runtime repository won't be initialized.
795 */
796 if (err_src == ERROR_CHECKING_REPOSITORY)
797 sql_print_error("Error in checking %s repository info type of %s.",
798 handler_src->get_description_info(),
799 handler_src->get_rpl_info_type_str());
800 if (err_dst == ERROR_CHECKING_REPOSITORY)
801 sql_print_error("Error in checking %s repository info type of %s.",
802 handler_dest->get_description_info(),
803 handler_dest->get_rpl_info_type_str());
804 *msg= "Error checking repositories";
805 return error;
806 }
807
808
809 /**
810 This method is called by the decide_repository() and is used to initialize
811 the repositories through a low-level interfacei, which means that if they
812 do not exist nothing will be created.
813
814 @param[in] info Either master info or relay log info.
815 @param[out] handler_src Source repository from where information is
816 copied into the destination repository.
817 @param[out] handler_dest Destination repository to where informaiton is
818 copied.
819 @param[out] msg Error message if something goes wrong.
820
821 @retval FALSE No error
822 @retval TRUE Failure
823 */
init_repositories(Rpl_info * info,Rpl_info_handler ** handler_src,Rpl_info_handler ** handler_dest,const char ** msg)824 bool Rpl_info_factory::init_repositories(Rpl_info *info,
825 Rpl_info_handler **handler_src,
826 Rpl_info_handler **handler_dest,
827 const char **msg)
828 {
829 bool live_migration = info->get_rpl_info_handler() != NULL;
830
831 if (!live_migration)
832 {
833 if ((*handler_src)->do_init_info(info->get_internal_id()) ||
834 (*handler_dest)->do_init_info(info->get_internal_id()))
835 {
836 *msg= "Error transfering information";
837 return true;
838 }
839 }
840 else
841 {
842 if ((*handler_dest)->do_init_info(info->get_internal_id()))
843 {
844 *msg= "Error transfering information";
845 return true;
846 }
847 }
848 return false;
849 }
850
851
852 /**
853 Creates repositories that will be associated to either the Master_info
854 or Relay_log_info.
855
856 @param[in] table_data Defines information to create a table repository.
857 @param[in] file_data Defines information to create a file repository.
858 @param[in] rep_option Identifies the type of the repository that will
859 be used, i.e., destination repository.
860 @param[in] instance Identifies the instance of the repository that
861 will be used.
862 @param[out] handler_src Source repository from where information is
863 copied into the destination repository.
864 @param[out] handler_dest Destination repository to where informaiton is
865 copied.
866 @param[out] msg Error message if something goes wrong.
867
868 @retval FALSE No error
869 @retval TRUE Failure
870 */
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)871 bool Rpl_info_factory::init_repositories(const struct_table_data table_data,
872 const struct_file_data file_data,
873 uint rep_option,
874 uint instance,
875 Rpl_info_handler **handler_src,
876 Rpl_info_handler **handler_dest,
877 const char **msg)
878 {
879 bool error= TRUE;
880 *msg= "Failed to allocate memory for master info repositories";
881
882 DBUG_ENTER("Rpl_info_factory::init_mi_repositories");
883
884 DBUG_ASSERT(handler_dest != NULL);
885 switch (rep_option)
886 {
887 case INFO_REPOSITORY_FILE:
888 if (!(*handler_dest= new Rpl_info_file(file_data.n_fields,
889 file_data.pattern,
890 file_data.name,
891 file_data.name_indexed)))
892 goto err;
893 if (handler_src &&
894 !(*handler_src= new Rpl_info_table(table_data.n_fields,
895 table_data.schema,
896 table_data.name,
897 table_data.n_pk_fields,
898 table_data.pk_field_indexes)))
899 goto err;
900 break;
901
902 case INFO_REPOSITORY_TABLE:
903 if (!(*handler_dest= new Rpl_info_table(table_data.n_fields,
904 table_data.schema,
905 table_data.name,
906 table_data.n_pk_fields,
907 table_data.pk_field_indexes)))
908 goto err;
909 if (handler_src &&
910 !(*handler_src= new Rpl_info_file(file_data.n_fields,
911 file_data.pattern,
912 file_data.name,
913 file_data.name_indexed)))
914 goto err;
915 break;
916
917 case INFO_REPOSITORY_DUMMY:
918 if (!(*handler_dest= new Rpl_info_dummy(Master_info::get_number_info_mi_fields())))
919 goto err;
920 break;
921
922 default:
923 DBUG_ASSERT(0);
924 }
925 error= FALSE;
926
927 err:
928 DBUG_RETURN(error);
929 }
930
scan_repositories(uint * found_instances,uint * found_rep_option,const struct_table_data table_data,const struct_file_data file_data,const char ** msg)931 bool Rpl_info_factory::scan_repositories(uint* found_instances,
932 uint* found_rep_option,
933 const struct_table_data table_data,
934 const struct_file_data file_data,
935 const char **msg)
936 {
937 bool error= false;
938 uint file_instances= 0;
939 uint table_instances= 0;
940 DBUG_ASSERT(found_rep_option != NULL);
941
942 DBUG_ENTER("Rpl_info_factory::scan_repositories");
943
944 if (Rpl_info_table::do_count_info(table_data.n_fields, table_data.schema,
945 table_data.name, &table_instances))
946 {
947 error= true;
948 goto err;
949 }
950
951 if (Rpl_info_file::do_count_info(file_data.n_fields, file_data.pattern,
952 file_data.name_indexed, &file_instances))
953 {
954 error= true;
955 goto err;
956 }
957
958 if (file_instances != 0 && table_instances != 0)
959 {
960 error= true;
961 *msg= "Multiple repository instances found with data in "
962 "them. Unable to decide which is the correct one to "
963 "choose";
964 goto err;
965 }
966
967 if (table_instances != 0)
968 {
969 *found_instances= table_instances;
970 *found_rep_option= INFO_REPOSITORY_TABLE;
971 }
972 else if (file_instances != 0)
973 {
974 *found_instances= file_instances;
975 *found_rep_option= INFO_REPOSITORY_FILE;
976 }
977 else
978 {
979 *found_instances= 0;
980 *found_rep_option= INVALID_INFO_REPOSITORY;
981 }
982
983 err:
984 DBUG_RETURN(error);
985 }
986
987
988 /**
989 This function should be called from init_slave() only.
990
991 During the server start, read all the slave repositories
992 on disk (either in FILE or TABLE form) and create corresponding
993 slave info objects. Each thus created master_info object is
994 added to pchannel_map.
995
996 Multisource replication is supported by only TABLE based
997 repositories. Based on this fact, the following table shows
998 the supported cases considering the repository type and
999 multiple channels of a slave.
1000 Each <---> represents a channel with a name on top of it.
1001 '' is an empty stringed channel (or default channel).
1002 'N' indicates some name for a channel.
1003
1004 +-----------------------------+------------------+-----------+
1005 | channels | Supported? FILE | TABLE |
1006 +-----------------------------+------------------+-----------+
1007 | '' | | |
1008 | A) Master<------->Slave | YES | YES |
1009 | | | |
1010 | | | |
1011 | 'N' | | |
1012 | B) Master<------->Slave | NO | YES |
1013 | | | |
1014 | '' | | |
1015 | Master0<------------+ | | |
1016 | 'N' v | NO | YES |
1017 | C) Master1<----------->Slave| | |
1018 | 'N' ^ | | |
1019 | Mastern<------------+ | | |
1020 | | | |
1021 | | | |
1022 | 'N' | | |
1023 | Master1<------------+ | | |
1024 | 'N' v | NO | YES |
1025 | D) Master2<----------->Slave| | |
1026 | 'N' ^ | | |
1027 | Mastern<------------+ | | |
1028 | | | |
1029 | | | |
1030 +-----------------------------+------------------+-----------+
1031
1032 In a new server, A) shown above is created by default.
1033 If there are multiple 'named' channels, but and if a default_channel
1034 is not created, it is created.
1035
1036 Some points to note from the above table
1037 =========================================
1038
1039 From the table it also follows that conversion of repositories
1040 is possible *ONLY* in the case of A) i.e for ex: if B) type repository
1041 (i.e a named slave channel) was found during server starup but the user
1042 repository option is INFO_REPOSITORY_FILE, then we exit the function.
1043
1044 @note: only for type A) i.e default channel, it is permissable to
1045 have different repo types for Master_info and Relay_log_info
1046 (Ex: FILE for mi and TABLE for rli)
1047
1048 @note: The above restrictions break factory pattern in the code
1049 which has been followed throughout before.
1050
1051 @note: All the repository conversion(or live migration) functions
1052 (ex: decide_repository()) take Rpl_info::internal_id as an
1053 identifier which is always 1 for the case of Master_info and
1054 Relay_log_info. So, in the case of multisource replication,
1055 the decision to convert the repositories shall be made even before
1056 invoking decide_repository(). In other words, if a channel is not a
1057 default channel('') we shall not invoke decide_repository().
1058
1059 @note: In general, the algorithm in creation of slave info object is:
1060 l1: new slave_info;
1061 l2: Initialize the repository handlers
1062 l3: if (default_channel)
1063 check and convert repositories
1064 else
1065 // TABLE type repository
1066 set the value of PK in the TABLE handler.
1067
1068 @note: Update from 5.6 to 5.7(which has Channel_Name in slave_info_tables)
1069 is handled in the upgrade script as usual.
1070
1071
1072 @param[in] mi_option the user provided master_info_repository
1073 @param[in] rli_option the user provided relay_log_info_repository
1074 @param[in] thread_mask thread mask
1075 @param[in] pchannel_map the pointer to the multi source map
1076 (see, rpl_msr.h)
1077
1078 @return
1079 @retval false success
1080 @retval true fail
1081
1082 */
1083
create_slave_info_objects(uint mi_option,uint rli_option,int thread_mask,Multisource_info * pchannel_map)1084 bool Rpl_info_factory::create_slave_info_objects(uint mi_option,
1085 uint rli_option,
1086 int thread_mask,
1087 Multisource_info *pchannel_map)
1088 {
1089 DBUG_ENTER("create_slave_info_objects");
1090
1091 Master_info* mi= NULL;
1092 const char* msg= NULL;
1093 bool error= false, channel_error;
1094 bool default_channel_existed_previously= false;
1095
1096 std::vector<std::string> channel_list;
1097
1098 /* Number of instances of Master_info repository */
1099 uint mi_instances= 0;
1100
1101 /* At this point, the repository in invalid or unknown */
1102 uint mi_repository= INVALID_INFO_REPOSITORY;
1103
1104 /*
1105 Number of instances of Relay_log_info_repository.
1106 (Number of Slave worker objects that will be created by the Coordinator
1107 (when slave_parallel_workers>0) at a later stage and not here).
1108 */
1109 uint rli_instances= 0;
1110
1111 /* At this point, the repository is invalid or unknown */
1112 uint rli_repository= INVALID_INFO_REPOSITORY;
1113
1114 /*
1115 Initialize the repository metadata. This metadata is the
1116 name of files to look in case of FILE type repository, and the
1117 names of table to look in case of TABLE type repository.
1118 */
1119 Rpl_info_factory::init_repository_metadata();
1120
1121 /* Count the number of Master_info and Relay_log_info repositories */
1122 if (scan_repositories(&mi_instances, &mi_repository, mi_table_data,
1123 mi_file_data, &msg) ||
1124 scan_repositories(&rli_instances, &rli_repository, rli_table_data,
1125 rli_file_data, &msg))
1126 {
1127 /* msg will contain the reason of failure */
1128 sql_print_error("Slave: %s", msg);
1129 error= true;
1130 goto end;
1131 }
1132
1133 /* Make a list of all channels if the slave was connected to previously*/
1134 if (load_channel_names_from_repository(channel_list,
1135 mi_instances,
1136 mi_repository,
1137 pchannel_map->get_default_channel(),
1138 &default_channel_existed_previously))
1139 {
1140 sql_print_error("Slave: Could not create channel list");
1141 error= true;
1142 goto end;
1143 }
1144
1145 if ((mi_option == INFO_REPOSITORY_FILE ||
1146 rli_option == INFO_REPOSITORY_FILE) && channel_list.size() > 1)
1147 {
1148 /* Not supported cases of B) C) and D) above */
1149 sql_print_error("Slave: This slave was a multisourced slave previously which"
1150 " is supported only by both TABLE based master info and relay"
1151 " log info repositories. Found one or both of the info repos"
1152 " to be type FILE. Set both repos to type TABLE.");
1153 error= true;
1154 goto end;
1155 }
1156
1157 /* Adding the default channel if needed. */
1158 if (!default_channel_existed_previously)
1159 {
1160 std::string str(pchannel_map->get_default_channel());
1161 channel_list.push_back(str);
1162 }
1163
1164 /*
1165 Create and initialize the channels.
1166
1167 Even if there is an error during one channel creation, we continue to
1168 iterate until we have created the other channels.
1169
1170 For compatibility reasons, we have to separate the print out
1171 of the error messages.
1172 */
1173 for (std::vector<std::string>::iterator it= channel_list.begin();
1174 it != channel_list.end(); ++it)
1175 {
1176 const char* cname= (*it).c_str();
1177 bool is_default_channel= !strcmp(cname, pchannel_map->get_default_channel());
1178 channel_error= !(mi= create_mi_and_rli_objects(mi_option, rli_option, cname,
1179 (channel_list.size() == 1) ? 1 : 0,
1180 pchannel_map));
1181 /*
1182 Read the channel configuration from the repository if the channel name
1183 was read from the repository.
1184 */
1185 if (!channel_error && (!is_default_channel || default_channel_existed_previously))
1186 {
1187 bool ignore_if_no_info= (channel_list.size() == 1) ? true : false;
1188 channel_error= load_mi_and_rli_from_repositories(mi,
1189 ignore_if_no_info,
1190 thread_mask);
1191 }
1192
1193 if (channel_error)
1194 {
1195 sql_print_error("Slave: Failed to initialize the master info structure"
1196 " for channel '%s'; its record may still be present in"
1197 " 'mysql.slave_master_info' table, consider "
1198 "deleting it.", cname);
1199 }
1200 error= error || channel_error;
1201 }
1202 end:
1203 DBUG_RETURN(error);
1204 }
1205
1206
1207 /**
1208 Create Master_info and Relay_log_info objects for a new channel.
1209 Also, set cross dependencies between these objects used all over
1210 the code.
1211
1212 Both master_info and relay_log_info repositories should be of the type
1213 TABLE. We do a check for this here as well.
1214
1215 @param[in] mi_option master info repository
1216 @param[in] rli_option relay log info repository
1217 @param[in] channel the channel for which these objects
1218 should be created.
1219 @param[in] to_decide_repo For this channel, check if repositories
1220 are allowed to convert from one type to other.
1221 @param[in] pchannel_map a pointer to channel_map
1222
1223 @return Pointer pointer to the created Master_info
1224 @return NULL when creation fails
1225
1226 */
1227
1228 Master_info*
create_mi_and_rli_objects(uint mi_option,uint rli_option,const char * channel,bool to_decide_repo,Multisource_info * pchannel_map)1229 Rpl_info_factory::create_mi_and_rli_objects(uint mi_option,
1230 uint rli_option,
1231 const char* channel,
1232 bool to_decide_repo,
1233 Multisource_info* pchannel_map)
1234 {
1235 DBUG_ENTER("Rpl_info_factory::create_mi_and_rli_objects");
1236
1237 Master_info *mi= NULL;
1238 Relay_log_info *rli= NULL;
1239
1240 if (!(mi= Rpl_info_factory::create_mi(mi_option, channel, to_decide_repo)))
1241 DBUG_RETURN(NULL);
1242
1243 if (!(rli= Rpl_info_factory::create_rli(rli_option, relay_log_recovery,
1244 channel, to_decide_repo)))
1245 {
1246 mi->channel_wrlock();
1247 delete mi;
1248 mi= NULL;
1249 DBUG_RETURN(NULL);
1250 }
1251
1252 /* Set the cross dependencies used all over the code */
1253 mi->set_relay_log_info(rli);
1254 rli->set_master_info(mi);
1255
1256 /* Add to multisource map*/
1257 if (pchannel_map->add_mi(channel, mi))
1258 {
1259 mi->channel_wrlock();
1260 delete mi;
1261 delete rli;
1262 DBUG_RETURN(NULL);
1263 }
1264
1265 DBUG_RETURN(mi);
1266 }
1267
1268 /**
1269 Make a list of all the channels if existed on the previos slave run.
1270
1271 @param[out] channel_list the names of all channels that exists
1272 on this slave.
1273
1274 @param[in] mi_instances number of master_info repositories
1275
1276 @param[in] mi_repository Found master_info repository
1277
1278 @param[in] default_channel pointer to default channel.
1279
1280 @param[out] default_channel_existed_previously
1281 Value filled with true if default channel
1282 existed previously. False if it is not.
1283
1284 @return
1285 @retval true fail
1286 @retval false success
1287
1288 */
1289
1290 bool
load_channel_names_from_repository(std::vector<std::string> & channel_list,uint mi_instances,uint mi_repository,const char * default_channel,bool * default_channel_existed_previously)1291 Rpl_info_factory::load_channel_names_from_repository(std::vector<std::string>& channel_list,
1292 uint mi_instances,
1293 uint mi_repository,
1294 const char* default_channel,
1295 bool *default_channel_existed_previously)
1296 {
1297 DBUG_ENTER("Rpl_info_factory::load_channel_names_from_repository");
1298
1299 *default_channel_existed_previously= false;
1300 switch(mi_repository)
1301 {
1302 case INFO_REPOSITORY_FILE:
1303 DBUG_ASSERT(mi_instances == 1);
1304 /* insert default channel */
1305 {
1306 std::string str(default_channel);
1307 channel_list.push_back(str);
1308 }
1309 *default_channel_existed_previously= true;
1310 break;
1311 case INFO_REPOSITORY_TABLE:
1312 if (load_channel_names_from_table(channel_list, default_channel,
1313 default_channel_existed_previously))
1314 DBUG_RETURN(true);
1315 break;
1316 case INVALID_INFO_REPOSITORY:
1317 /* file and table instanaces are zero, nothing to be done*/
1318 break;
1319 default:
1320 DBUG_ASSERT(0);
1321 }
1322
1323 DBUG_RETURN(false);
1324 }
1325
1326
1327 /**
1328 In a multisourced slave, during init_slave(), the repositories
1329 are read to initialize the slave info objects. To initialize
1330 the slave info objects, we need the number of channels the slave
1331 was connected to previously. The following function, finds the
1332 number of channels in the master info repository.
1333 Later, this chanenl list is used to create a pair of {mi, rli}
1334 objects required for IO and SQL threads respectively.
1335
1336 @param [out] channel_list A reference to the channel list.
1337 This will be filled after reading the
1338 master info table, row by row.
1339
1340 @param[in] default_channel pointer to default channel.
1341
1342 @param[out] default_channel_existed_previously
1343 Value filled with true if default channel
1344 existed previously. False if it is not.
1345
1346 @todo: Move it to Rpl_info_table and make it generic to extract
1347 all the PK list from the tables (but it not yet necessary)
1348 */
1349 bool
load_channel_names_from_table(std::vector<std::string> & channel_list,const char * default_channel,bool * default_channel_existed_previously)1350 Rpl_info_factory::load_channel_names_from_table(std::vector<std::string> &channel_list,
1351 const char* default_channel,
1352 bool *default_channel_existed_previously)
1353 {
1354
1355 DBUG_ENTER(" Rpl_info_table::load_channel_names_from_table");
1356
1357 int error= 1;
1358 TABLE *table= 0;
1359 ulong saved_mode;
1360 Open_tables_backup backup;
1361 Rpl_info_table* info= 0;
1362 THD *thd= 0;
1363 char buff[MAX_FIELD_WIDTH];
1364 *default_channel_existed_previously= false;
1365 String str(buff, sizeof(buff), system_charset_info); // to extract channel names
1366
1367 uint channel_field= Master_info::get_channel_field_num() -1;
1368
1369
1370 if(!(info= new Rpl_info_table(mi_table_data.n_fields,
1371 mi_table_data.schema, mi_table_data.name,
1372 mi_table_data.n_pk_fields,
1373 mi_table_data.pk_field_indexes)))
1374 DBUG_RETURN(true);
1375
1376 thd= info->access->create_thd();
1377 saved_mode= thd->variables.sql_mode;
1378
1379 /*
1380 Opens and locks the rpl_info table before accessing it.
1381 */
1382 if (info->access->open_table(thd, info->str_schema, info->str_table,
1383 info->get_number_info(), TL_READ, &table,
1384 &backup))
1385 {
1386 /*
1387 We cannot simply print out a warning message at this
1388 point because this may represent a bootstrap.
1389 */
1390 error= 0;
1391 goto err;
1392 }
1393
1394 /* Do ha_handler random init for full scanning */
1395 if ((error= table->file->ha_rnd_init(true)))
1396 DBUG_RETURN(true);
1397
1398 /* Ensure that the table pk (Channel_name) is at the correct position */
1399 if (info->verify_table_primary_key_fields(table))
1400 {
1401 sql_print_error("Slave: Failed to create a channel from master info "
1402 "table repository.");
1403 error= -1;
1404 goto err;
1405 }
1406
1407 /*
1408 Load all the values in record[0] for each row
1409 and then extract channel name from it
1410 */
1411
1412 do
1413 {
1414 error= table->file->ha_rnd_next(table->record[0]);
1415 switch(error)
1416 {
1417 case 0:
1418 /* extract the channel name from table->field and append to the list */
1419 table->field[channel_field]->val_str(&str);
1420 channel_list.push_back(std::string(str.c_ptr_safe()));
1421 if (!strcmp(str.c_ptr_safe(), default_channel))
1422 *default_channel_existed_previously= true;
1423 break;
1424
1425 case HA_ERR_END_OF_FILE:
1426 break;
1427
1428 default:
1429 DBUG_PRINT("info", ("Failed to get next record"
1430 " (ha_rnd_next returns %d)", error));
1431
1432 }
1433 }
1434 while(!error);
1435
1436 /*close the table */
1437 err:
1438
1439 table->file->ha_rnd_end();
1440 info->access->close_table(thd, table, &backup, error);
1441 thd->variables.sql_mode= saved_mode;
1442 info->access->drop_thd(thd);
1443 delete info;
1444 DBUG_RETURN(error != HA_ERR_END_OF_FILE && error != 0);
1445 }
1446