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