1 /* Copyright (c) 2006, 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 #ifdef HAVE_REPLICATION
24 #include "rpl_mi.h"
25 
26 #include "dynamic_ids.h"        // Server_ids
27 #include "log.h"                // sql_print_error
28 #include "rpl_msr.h"            // channel_map
29 #include "rpl_slave.h"          // master_retry_count
30 
31 
32 enum {
33   LINES_IN_MASTER_INFO_WITH_SSL= 14,
34 
35   /* 5.1.16 added value of master_ssl_verify_server_cert */
36   LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT= 15,
37 
38   /* 5.5 added value of master_heartbeat_period */
39   LINE_FOR_MASTER_HEARTBEAT_PERIOD= 16,
40 
41   /* MySQL Cluster 6.3 added master_bind */
42   LINE_FOR_MASTER_BIND = 17,
43 
44   /* 6.0 added value of master_ignore_server_id */
45   LINE_FOR_REPLICATE_IGNORE_SERVER_IDS= 18,
46 
47   /* 6.0 added value of master_uuid */
48   LINE_FOR_MASTER_UUID= 19,
49 
50   /* line for master_retry_count */
51   LINE_FOR_MASTER_RETRY_COUNT= 20,
52 
53   /* line for ssl_crl */
54   LINE_FOR_SSL_CRL= 21,
55 
56   /* line for ssl_crl */
57   LINE_FOR_SSL_CRLPATH= 22,
58 
59   /* line for auto_position */
60   LINE_FOR_AUTO_POSITION= 23,
61 
62   /* line for channel */
63   LINE_FOR_CHANNEL= 24,
64 
65   /* line for tls_version */
66   LINE_FOR_TLS_VERSION= 25,
67 
68   /* Number of lines currently used when saving master info file */
69   LINES_IN_MASTER_INFO= LINE_FOR_TLS_VERSION
70 
71 };
72 
73 /*
74   Please every time you add a new field to the mater info, update
75   what follows. For now, this is just used to get the number of
76   fields.
77 */
78 const char *info_mi_fields []=
79 {
80   "number_of_lines",
81   "master_log_name",
82   "master_log_pos",
83   "host",
84   "user",
85   "password",
86   "port",
87   "connect_retry",
88   "ssl",
89   "ssl_ca",
90   "ssl_capath",
91   "ssl_cert",
92   "ssl_cipher",
93   "ssl_key",
94   "ssl_verify_server_cert",
95   "heartbeat_period",
96   "bind",
97   "ignore_server_ids",
98   "uuid",
99   "retry_count",
100   "ssl_crl",
101   "ssl_crlpath",
102   "auto_position",
103   "channel_name",
104   "tls_version",
105 };
106 
107 const uint info_mi_table_pk_field_indexes []=
108 {
109   LINE_FOR_CHANNEL-1,
110 };
111 
Master_info(PSI_mutex_key * param_key_info_run_lock,PSI_mutex_key * param_key_info_data_lock,PSI_mutex_key * param_key_info_sleep_lock,PSI_mutex_key * param_key_info_thd_lock,PSI_mutex_key * param_key_info_data_cond,PSI_mutex_key * param_key_info_start_cond,PSI_mutex_key * param_key_info_stop_cond,PSI_mutex_key * param_key_info_sleep_cond,uint param_id,const char * param_channel)112 Master_info::Master_info(
113 #ifdef HAVE_PSI_INTERFACE
114                          PSI_mutex_key *param_key_info_run_lock,
115                          PSI_mutex_key *param_key_info_data_lock,
116                          PSI_mutex_key *param_key_info_sleep_lock,
117                          PSI_mutex_key *param_key_info_thd_lock,
118                          PSI_mutex_key *param_key_info_data_cond,
119                          PSI_mutex_key *param_key_info_start_cond,
120                          PSI_mutex_key *param_key_info_stop_cond,
121                          PSI_mutex_key *param_key_info_sleep_cond,
122 #endif
123                          uint param_id, const char *param_channel
124                         )
125    :Rpl_info("I/O"
126 #ifdef HAVE_PSI_INTERFACE
127              ,param_key_info_run_lock, param_key_info_data_lock,
128              param_key_info_sleep_lock, param_key_info_thd_lock,
129              param_key_info_data_cond, param_key_info_start_cond,
130              param_key_info_stop_cond, param_key_info_sleep_cond
131 #endif
132              ,param_id, param_channel
133             ),
134    start_user_configured(false),
135    ssl(0), ssl_verify_server_cert(0),
136    port(MYSQL_PORT), connect_retry(DEFAULT_CONNECT_RETRY),
137    clock_diff_with_master(0), heartbeat_period(0),
138    received_heartbeats(0), last_heartbeat(0), master_id(0),
139    checksum_alg_before_fd(binary_log::BINLOG_CHECKSUM_ALG_UNDEF),
140    retry_count(master_retry_count),
141    mi_description_event(NULL),
142    auto_position(false),
143    reset(false)
144 {
145   host[0] = 0; user[0] = 0; bind_addr[0] = 0;
146   password[0]= 0; start_password[0]= 0;
147   ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0;
148   ssl_cipher[0]= 0; ssl_key[0]= 0; tls_version[0]= 0;
149   ssl_crl[0]= 0; ssl_crlpath[0]= 0;
150   master_uuid[0]= 0;
151   start_plugin_auth[0]= 0; start_plugin_dir[0]= 0;
152   start_user[0]= 0;
153   ignore_server_ids= new Server_ids;
154 
155   /*channel is set in base class, rpl_info.cc*/
156   my_snprintf(for_channel_str, sizeof(for_channel_str)-1,
157              " for channel '%s'", channel);
158   my_snprintf(for_channel_uppercase_str, sizeof(for_channel_uppercase_str)-1,
159              " FOR CHANNEL '%s'", channel);
160 
161   m_channel_lock= new Checkable_rwlock(
162 #ifdef HAVE_PSI_INTERFACE
163                                        key_rwlock_channel_lock
164 #endif
165                                       );
166 }
167 
~Master_info()168 Master_info::~Master_info()
169 {
170   /* No one else is using this master_info */
171   m_channel_lock->assert_some_wrlock();
172   /* No other administrative task is able to get this master_info */
173   channel_map.assert_some_wrlock();
174   m_channel_lock->unlock();
175   delete m_channel_lock;
176   delete ignore_server_ids;
177   delete mi_description_event;
178 }
179 
180 /**
181    Reports if the s_id server has been configured to ignore events
182    it generates with
183 
184       CHANGE MASTER IGNORE_SERVER_IDS= ( list of server ids )
185 
186    Method is called from the io thread event receiver filtering.
187 
188    @param      s_id    the master server identifier
189 
190    @retval   TRUE    if s_id is in the list of ignored master  servers,
191    @retval   FALSE   otherwise.
192  */
shall_ignore_server_id(ulong s_id)193 bool Master_info::shall_ignore_server_id(ulong s_id)
194 {
195   return std::binary_search(ignore_server_ids->dynamic_ids.begin(),
196                             ignore_server_ids->dynamic_ids.end(), s_id);
197 }
198 
init_master_log_pos()199 void Master_info::init_master_log_pos()
200 {
201   DBUG_ENTER("Master_info::init_master_log_pos");
202 
203   master_log_name[0]= 0;
204   master_log_pos= BIN_LOG_HEADER_SIZE;             // skip magic number
205 
206   DBUG_VOID_RETURN;
207 }
208 
end_info()209 void Master_info::end_info()
210 {
211   DBUG_ENTER("Master_info::end_info");
212 
213   if (!inited)
214     DBUG_VOID_RETURN;
215 
216   handler->end_info();
217 
218   inited = 0;
219   reset = true;
220 
221   DBUG_VOID_RETURN;
222 }
223 
224 /**
225   Store the file and position where the slave's SQL thread are in the
226    relay log.
227 
228   - This function should be called either from the slave SQL thread,
229     or when the slave thread is not running.  (It reads the
230     group_{relay|master}_log_{pos|name} and delay fields in the rli
231     object.  These may only be modified by the slave SQL thread or by
232     a client thread when the slave SQL thread is not running.)
233 
234   - If there is an active transaction, then we do not update the
235     position in the relay log.  This is to ensure that we re-execute
236     statements if we die in the middle of an transaction that was
237     rolled back.
238 
239   - As a transaction never spans binary logs, we don't have to handle
240     the case where we do a relay-log-rotation in the middle of the
241     transaction.  If transactions could span several binlogs, we would
242     have to ensure that we do not delete the relay log file where the
243     transaction started before switching to a new relay log file.
244 
245   - Error can happen if writing to file fails or if flushing the file
246     fails.
247 
248   @param rli The object representing the Relay_log_info.
249 
250   @todo Change the log file information to a binary format to avoid
251   calling longlong2str.
252 */
flush_info(bool force)253 int Master_info::flush_info(bool force)
254 {
255   DBUG_ENTER("Master_info::flush_info");
256   DBUG_PRINT("enter",("master_pos: %lu", (ulong) master_log_pos));
257 
258   bool skip_flushing = !inited;
259   /*
260     A Master_info of a channel that was inited and then reset must be flushed
261     into the repository or else its connection configuration will be lost in
262     case the server restarts before starting the channel again.
263   */
264   if (force && reset) skip_flushing= false;
265 
266   if (skip_flushing)
267     DBUG_RETURN(0);
268 
269   /*
270     We update the sync_period at this point because only here we
271     now that we are handling a master info. This needs to be
272     update every time we call flush because the option maybe
273     dynamically set.
274   */
275   if (inited)
276     handler->set_sync_period(sync_masterinfo_period);
277 
278   if (write_info(handler))
279     goto err;
280 
281   if (handler->flush_info(force))
282     goto err;
283 
284   DBUG_RETURN(0);
285 
286 err:
287   sql_print_error("Error writing master configuration.");
288   DBUG_RETURN(1);
289 }
290 
set_relay_log_info(Relay_log_info * info)291 void Master_info::set_relay_log_info(Relay_log_info* info)
292 {
293   rli= info;
294 }
295 
296 
297 /**
298   Creates or reads information from the repository, initializing the
299   Master_info.
300 */
mi_init_info()301 int Master_info::mi_init_info()
302 {
303   DBUG_ENTER("Master_info::mi_init_info");
304   enum_return_check check_return= ERROR_CHECKING_REPOSITORY;
305 
306   if (inited)
307     DBUG_RETURN(0);
308 
309   mysql= 0; file_id= 1;
310   if ((check_return= check_info()) == ERROR_CHECKING_REPOSITORY)
311     goto err;
312 
313   if (handler->init_info())
314     goto err;
315 
316   if (check_return == REPOSITORY_DOES_NOT_EXIST)
317   {
318     init_master_log_pos();
319   }
320   else
321   {
322     if (read_info(handler))
323       goto err;
324   }
325 
326   inited= 1;
327   reset= false;
328   if (flush_info(TRUE))
329     goto err;
330 
331   DBUG_RETURN(0);
332 
333 err:
334   handler->end_info();
335   inited= 0;
336   sql_print_error("Error reading master configuration.");
337   DBUG_RETURN(1);
338 }
339 
get_number_info_mi_fields()340 size_t Master_info::get_number_info_mi_fields()
341 {
342   return sizeof(info_mi_fields)/sizeof(info_mi_fields[0]);
343 }
344 
get_channel_field_num()345 uint Master_info::get_channel_field_num()
346 {
347   uint channel_field= LINE_FOR_CHANNEL;
348   return channel_field;
349 }
350 
get_table_pk_field_indexes()351 const uint* Master_info::get_table_pk_field_indexes()
352 {
353   return info_mi_table_pk_field_indexes;
354 }
355 
read_info(Rpl_info_handler * from)356 bool Master_info::read_info(Rpl_info_handler *from)
357 {
358   int lines= 0;
359   char *first_non_digit= NULL;
360   ulong temp_master_log_pos= 0;
361   int temp_ssl= 0;
362   int temp_ssl_verify_server_cert= 0;
363   int temp_auto_position= 0;
364 
365   DBUG_ENTER("Master_info::read_info");
366 
367   /*
368      Starting from 4.1.x master.info has new format. Now its
369      first line contains number of lines in file. By reading this
370      number we will be always distinguish to which version our
371      master.info corresponds to. We can't simply count lines in
372      file since versions before 4.1.x could generate files with more
373      lines than needed.
374      If first line doesn't contain a number or contain number less than
375      LINES_IN_MASTER_INFO_WITH_SSL then such file is treated like file
376      from pre 4.1.1 version.
377      There is no ambiguity when reading an old master.info, as before
378      4.1.1, the first line contained the binlog's name, which is either
379      empty or has an extension (contains a '.'), so can't be confused
380      with an integer.
381 
382      So we're just reading first line and trying to figure which version
383      is this.
384   */
385 
386   if (from->prepare_info_for_read() ||
387       from->get_info(master_log_name, sizeof(master_log_name),
388                      (char *) ""))
389     DBUG_RETURN(true);
390 
391   lines= strtoul(master_log_name, &first_non_digit, 10);
392 
393   if (master_log_name[0]!='\0' &&
394       *first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL)
395   {
396     /* Seems to be new format => read master log name */
397     if (from->get_info(master_log_name, sizeof(master_log_name),
398                        (char *) ""))
399       DBUG_RETURN(true);
400   }
401   else
402     lines= 7;
403 
404   if (from->get_info(&temp_master_log_pos,
405                      (ulong) BIN_LOG_HEADER_SIZE) ||
406       from->get_info(host, sizeof(host), (char *) 0) ||
407       from->get_info(user, sizeof(user), (char *) "test") ||
408       from->get_info(password, sizeof(password), (char *) 0) ||
409       from->get_info((int *) &port, (int) MYSQL_PORT) ||
410       from->get_info((int *) &connect_retry,
411                         (int) DEFAULT_CONNECT_RETRY))
412       DBUG_RETURN(true);
413 
414   /*
415     If file has ssl part use it even if we have server without
416     SSL support. But these options will be ignored later when
417     slave will try connect to master, so in this case warning
418     is printed.
419   */
420   if (lines >= LINES_IN_MASTER_INFO_WITH_SSL)
421   {
422     if (from->get_info(&temp_ssl, 0) ||
423         from->get_info(ssl_ca, sizeof(ssl_ca), (char *) 0) ||
424         from->get_info(ssl_capath, sizeof(ssl_capath), (char *) 0) ||
425         from->get_info(ssl_cert, sizeof(ssl_cert), (char *) 0) ||
426         from->get_info(ssl_cipher, sizeof(ssl_cipher), (char *) 0) ||
427         from->get_info(ssl_key, sizeof(ssl_key), (char *) 0))
428       DBUG_RETURN(true);
429   }
430 
431   /*
432     Starting from 5.1.16 ssl_verify_server_cert might be
433     in the file
434   */
435   if (lines >= LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT)
436   {
437     if (from->get_info(&temp_ssl_verify_server_cert, 0))
438       DBUG_RETURN(true);
439   }
440 
441   /*
442     Starting from 5.5 master_heartbeat_period might be
443     in the file
444   */
445   if (lines >= LINE_FOR_MASTER_HEARTBEAT_PERIOD)
446   {
447     if (from->get_info(&heartbeat_period, (float) 0.0))
448       DBUG_RETURN(true);
449   }
450 
451   /*
452     Starting from 5.5 master_bind might be in the file
453   */
454   if (lines >= LINE_FOR_MASTER_BIND)
455   {
456     if (from->get_info(bind_addr, sizeof(bind_addr), (char *) ""))
457       DBUG_RETURN(true);
458   }
459 
460   /*
461     Starting from 5.5 list of server_id of ignorable servers might be
462     in the file
463   */
464   if (lines >= LINE_FOR_REPLICATE_IGNORE_SERVER_IDS)
465   {
466      if (from->get_info(ignore_server_ids, (Server_ids *) NULL))
467       DBUG_RETURN(true);
468   }
469 
470   /* Starting from 5.5 the master_uuid may be in the repository. */
471   if (lines >= LINE_FOR_MASTER_UUID)
472   {
473     if (from->get_info(master_uuid, sizeof(master_uuid),
474                        (char *) 0))
475       DBUG_RETURN(true);
476   }
477 
478   /* Starting from 5.5 the master_retry_count may be in the repository. */
479   retry_count= master_retry_count;
480   if (lines >= LINE_FOR_MASTER_RETRY_COUNT)
481   {
482     if (from->get_info(&retry_count, master_retry_count))
483       DBUG_RETURN(true);
484   }
485 
486   if (lines >= LINE_FOR_SSL_CRLPATH)
487   {
488     if (from->get_info(ssl_crl, sizeof(ssl_crl), (char *) 0) ||
489         from->get_info(ssl_crlpath, sizeof(ssl_crlpath), (char *) 0))
490       DBUG_RETURN(true);
491   }
492 
493   if (lines >= LINE_FOR_AUTO_POSITION)
494   {
495     if (from->get_info(&temp_auto_position, 0))
496       DBUG_RETURN(true);
497   }
498 
499   if (lines >= LINE_FOR_CHANNEL)
500   {
501     if (from->get_info(channel, sizeof(channel), (char*)0))
502       DBUG_RETURN(true);
503   }
504 
505   if (lines >= LINE_FOR_TLS_VERSION)
506   {
507     if (from->get_info(tls_version, sizeof(tls_version), (char *) 0))
508       DBUG_RETURN(true);
509   }
510 
511   ssl= (my_bool) MY_TEST(temp_ssl);
512   ssl_verify_server_cert= (my_bool) MY_TEST(temp_ssl_verify_server_cert);
513   master_log_pos= (my_off_t) temp_master_log_pos;
514   auto_position= MY_TEST(temp_auto_position);
515 
516 #ifndef HAVE_OPENSSL
517   if (ssl)
518     sql_print_warning("SSL information in the master info file "
519                       "are ignored because this MySQL slave was "
520                       "compiled without SSL support.");
521 #endif /* HAVE_OPENSSL */
522 
523   DBUG_RETURN(false);
524 }
525 
526 
set_info_search_keys(Rpl_info_handler * to)527 bool Master_info::set_info_search_keys(Rpl_info_handler *to)
528 {
529   DBUG_ENTER("Master_info::set_info_search_keys");
530 
531   if (to->set_info(LINE_FOR_CHANNEL-1, channel))
532     DBUG_RETURN(TRUE);
533 
534   DBUG_RETURN(FALSE);
535 }
536 
537 
write_info(Rpl_info_handler * to)538 bool Master_info::write_info(Rpl_info_handler *to)
539 {
540   DBUG_ENTER("Master_info::write_info");
541 
542   /*
543      In certain cases this code may create master.info files that seems
544      corrupted, because of extra lines filled with garbage in the end
545      file (this happens if new contents take less space than previous
546      contents of file). But because of number of lines in the first line
547      of file we don't care about this garbage.
548   */
549   if (to->prepare_info_for_write() ||
550       to->set_info((int) LINES_IN_MASTER_INFO) ||
551       to->set_info(master_log_name) ||
552       to->set_info((ulong) master_log_pos) ||
553       to->set_info(host) ||
554       to->set_info(user) ||
555       to->set_info(password) ||
556       to->set_info((int) port) ||
557       to->set_info((int) connect_retry) ||
558       to->set_info((int) ssl) ||
559       to->set_info(ssl_ca) ||
560       to->set_info(ssl_capath) ||
561       to->set_info(ssl_cert) ||
562       to->set_info(ssl_cipher) ||
563       to->set_info(ssl_key) ||
564       to->set_info((int) ssl_verify_server_cert) ||
565       to->set_info(heartbeat_period) ||
566       to->set_info(bind_addr) ||
567       to->set_info(ignore_server_ids) ||
568       to->set_info(master_uuid) ||
569       to->set_info(retry_count) ||
570       to->set_info(ssl_crl) ||
571       to->set_info(ssl_crlpath) ||
572       to->set_info((int) auto_position) ||
573       to->set_info(channel) ||
574       to->set_info(tls_version))
575     DBUG_RETURN(TRUE);
576 
577   DBUG_RETURN(FALSE);
578 }
579 
set_password(const char * password_arg)580 void Master_info::set_password(const char* password_arg)
581 {
582   DBUG_ENTER("Master_info::set_password");
583 
584   DBUG_ASSERT(password_arg);
585 
586   if (password_arg && start_user_configured)
587     strmake(start_password, password_arg, sizeof(start_password) - 1);
588   else if (password_arg)
589     strmake(password, password_arg, sizeof(password) - 1);
590 
591   DBUG_VOID_RETURN;
592 }
593 
get_password(char * password_arg,size_t * password_arg_size)594 bool Master_info::get_password(char *password_arg, size_t *password_arg_size)
595 {
596   bool ret= true;
597   DBUG_ENTER("Master_info::get_password");
598 
599   if (password_arg && start_user_configured)
600   {
601     *password_arg_size= strlen(start_password);
602     strmake(password_arg, start_password, sizeof(start_password) - 1);
603     ret= false;
604   }
605   else if (password_arg)
606   {
607     *password_arg_size= strlen(password);
608     strmake(password_arg, password, sizeof(password) - 1);
609     ret= false;
610   }
611   DBUG_RETURN(ret);
612 }
613 
reset_start_info()614 void Master_info::reset_start_info()
615 {
616   DBUG_ENTER("Master_info::reset_start_info");
617   start_plugin_auth[0]= 0;
618   start_plugin_dir[0]= 0;
619   start_user_configured= false;
620   start_user[0]= 0;
621   start_password[0]= 0;
622   DBUG_VOID_RETURN;
623 }
624 
channel_rdlock()625 void Master_info::channel_rdlock()
626 {
627   channel_map.assert_some_lock();
628   m_channel_lock->rdlock();
629 }
630 
channel_wrlock()631 void Master_info::channel_wrlock()
632 {
633   channel_map.assert_some_lock();
634   m_channel_lock->wrlock();
635 }
636 
wait_until_no_reference(THD * thd)637 void Master_info::wait_until_no_reference(THD *thd)
638 {
639   PSI_stage_info *old_stage= NULL;
640 
641   thd->enter_stage(&stage_waiting_for_no_channel_reference,
642                    old_stage, __func__, __FILE__, __LINE__);
643 
644   while (references.atomic_get() != 0)
645     my_sleep(10000);
646 
647   THD_STAGE_INFO(thd, *old_stage);
648 }
649 
650 #endif /* HAVE_REPLICATION */
651