MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
rpl_mi.cc
1 /* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include <my_global.h> // For HAVE_REPLICATION
17 #include "sql_priv.h"
18 #include <my_dir.h>
19 #include "unireg.h" // REQUIRED by other includes
20 #include "rpl_mi.h"
21 #include "rpl_slave.h" // SLAVE_MAX_HEARTBEAT_PERIOD
22 
23 using std::min;
24 using std::max;
25 
26 #ifdef HAVE_REPLICATION
27 
28 enum {
29  LINES_IN_MASTER_INFO_WITH_SSL= 14,
30 
31  /* 5.1.16 added value of master_ssl_verify_server_cert */
32  LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT= 15,
33 
34  /* 5.5 added value of master_heartbeat_period */
35  LINE_FOR_MASTER_HEARTBEAT_PERIOD= 16,
36 
37  /* MySQL Cluster 6.3 added master_bind */
38  LINE_FOR_MASTER_BIND = 17,
39 
40  /* 6.0 added value of master_ignore_server_id */
41  LINE_FOR_REPLICATE_IGNORE_SERVER_IDS= 18,
42 
43  /* 6.0 added value of master_uuid */
44  LINE_FOR_MASTER_UUID= 19,
45 
46  /* line for master_retry_count */
47  LINE_FOR_MASTER_RETRY_COUNT= 20,
48 
49  /* line for ssl_crl */
50  LINE_FOR_SSL_CRL= 21,
51 
52  /* line for ssl_crl */
53  LINE_FOR_SSL_CRLPATH= 22,
54 
55  /* line for auto_position */
56  LINE_FOR_AUTO_POSITION= 23,
57 
58  /* Number of lines currently used when saving master info file */
59  LINES_IN_MASTER_INFO= LINE_FOR_AUTO_POSITION
60 };
61 
62 /*
63  Please every time you add a new field to the mater info, update
64  what follows. For now, this is just used to get the number of
65  fields.
66 */
67 const char *info_mi_fields []=
68 {
69  "number_of_lines",
70  "master_log_name",
71  "master_log_pos",
72  "host",
73  "user",
74  "password",
75  "port",
76  "connect_retry",
77  "ssl",
78  "ssl_ca",
79  "ssl_capath",
80  "ssl_cert",
81  "ssl_cipher",
82  "ssl_key",
83  "ssl_verify_server_cert",
84  "heartbeat_period",
85  "bind",
86  "ignore_server_ids",
87  "uuid",
88  "retry_count",
89  "ssl_crl",
90  "ssl_crlpath",
91  "auto_position"
92 };
93 
94 Master_info::Master_info(
95 #ifdef HAVE_PSI_INTERFACE
96  PSI_mutex_key *param_key_info_run_lock,
97  PSI_mutex_key *param_key_info_data_lock,
98  PSI_mutex_key *param_key_info_sleep_lock,
99  PSI_mutex_key *param_key_info_data_cond,
100  PSI_mutex_key *param_key_info_start_cond,
101  PSI_mutex_key *param_key_info_stop_cond,
102  PSI_mutex_key *param_key_info_sleep_cond,
103 #endif
104  uint param_id
105  )
106  :Rpl_info("I/O"
107 #ifdef HAVE_PSI_INTERFACE
108  ,param_key_info_run_lock, param_key_info_data_lock,
109  param_key_info_sleep_lock,
110  param_key_info_data_cond, param_key_info_start_cond,
111  param_key_info_stop_cond, param_key_info_sleep_cond
112 #endif
113  ,param_id
114  ),
115  start_user_configured(false),
116  ssl(0), ssl_verify_server_cert(0),
117  port(MYSQL_PORT), connect_retry(DEFAULT_CONNECT_RETRY),
118  clock_diff_with_master(0), heartbeat_period(0),
119  received_heartbeats(0), last_heartbeat(0), master_id(0),
120  checksum_alg_before_fd(BINLOG_CHECKSUM_ALG_UNDEF),
121  retry_count(master_retry_count), master_gtid_mode(0),
122  mi_description_event(NULL),
123  auto_position(false)
124 {
125  host[0] = 0; user[0] = 0; bind_addr[0] = 0;
126  password[0]= 0; start_password[0]= 0;
127  ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0;
128  ssl_cipher[0]= 0; ssl_key[0]= 0;
129  ssl_crl[0]= 0; ssl_crlpath[0]= 0;
130  master_uuid[0]= 0;
131  start_plugin_auth[0]= 0; start_plugin_dir[0]= 0;
132  start_user[0]= 0;
133  ignore_server_ids= new Server_ids(sizeof(::server_id));
134 }
135 
136 Master_info::~Master_info()
137 {
138  delete ignore_server_ids;
139  delete mi_description_event;
140 }
141 
149 int change_master_server_id_cmp(ulong *id1, ulong *id2)
150 {
151  return *id1 < *id2? -1 : (*id1 > *id2? 1 : 0);
152 }
153 
167 bool Master_info::shall_ignore_server_id(ulong s_id)
168 {
169  if (likely(ignore_server_ids->dynamic_ids.elements == 1))
170  return (* (ulong*)
171  dynamic_array_ptr(&(ignore_server_ids->dynamic_ids), 0)) == s_id;
172  else
173  return bsearch((const ulong *) &s_id,
174  ignore_server_ids->dynamic_ids.buffer,
175  ignore_server_ids->dynamic_ids.elements, sizeof(ulong),
176  (int (*) (const void*, const void*)) change_master_server_id_cmp)
177  != NULL;
178 }
179 
180 void Master_info::clear_in_memory_info(bool all)
181 {
182  init_master_log_pos();
183  if (all)
184  {
185  port= MYSQL_PORT;
186  host[0] = 0; user[0] = 0; password[0] = 0;
187  }
188 }
189 
190 void Master_info::init_master_log_pos()
191 {
192  DBUG_ENTER("Master_info::init_master_log_pos");
193 
194  master_log_name[0]= 0;
195  master_log_pos= BIN_LOG_HEADER_SIZE; // skip magic number
196 
197  /* Intentionally init ssl_verify_server_cert to 0, no option available */
198  ssl_verify_server_cert= 0;
199  /*
200  always request heartbeat unless master_heartbeat_period is set
201  explicitly zero. Here is the default value for heartbeat period
202  if CHANGE MASTER did not specify it. (no data loss in conversion
203  as hb period has a max)
204  */
205  heartbeat_period= min<float>(SLAVE_MAX_HEARTBEAT_PERIOD,
206  (slave_net_timeout/2.0));
207  DBUG_ASSERT(heartbeat_period > (float) 0.001
208  || heartbeat_period == 0);
209 
210  DBUG_VOID_RETURN;
211 }
212 
213 void Master_info::end_info()
214 {
215  DBUG_ENTER("Master_info::end_info");
216 
217  if (!inited)
218  DBUG_VOID_RETURN;
219 
220  handler->end_info();
221 
222  inited = 0;
223 
224  DBUG_VOID_RETURN;
225 }
226 
256 int Master_info::flush_info(bool force)
257 {
258  DBUG_ENTER("Master_info::flush_info");
259  DBUG_PRINT("enter",("master_pos: %lu", (ulong) master_log_pos));
260 
261  if (!inited)
262  DBUG_RETURN(0);
263 
264  /*
265  We update the sync_period at this point because only here we
266  now that we are handling a master info. This needs to be
267  update every time we call flush because the option maybe
268  dinamically set.
269  */
270  handler->set_sync_period(sync_masterinfo_period);
271 
272  if (write_info(handler))
273  goto err;
274 
275  if (handler->flush_info(force))
276  goto err;
277 
278  DBUG_RETURN(0);
279 
280 err:
281  sql_print_error("Error writing master configuration.");
282  DBUG_RETURN(1);
283 }
284 
285 void Master_info::set_relay_log_info(Relay_log_info* info)
286 {
287  rli= info;
288 }
289 
290 
295 int Master_info::mi_init_info()
296 {
297  DBUG_ENTER("Master_info::mi_init_info");
298  enum_return_check check_return= ERROR_CHECKING_REPOSITORY;
299 
300  if (inited)
301  DBUG_RETURN(0);
302 
303  mysql= 0; file_id= 1;
304  if ((check_return= check_info()) == ERROR_CHECKING_REPOSITORY)
305  goto err;
306 
307  if (handler->init_info())
308  goto err;
309 
310  if (check_return == REPOSITORY_DOES_NOT_EXIST)
311  {
312  init_master_log_pos();
313  }
314  else
315  {
316  if (read_info(handler))
317  goto err;
318  }
319 
320  inited= 1;
321  if (flush_info(TRUE))
322  goto err;
323 
324  DBUG_RETURN(0);
325 
326 err:
327  handler->end_info();
328  inited= 0;
329  sql_print_error("Error reading master configuration.");
330  DBUG_RETURN(1);
331 }
332 
333 size_t Master_info::get_number_info_mi_fields()
334 {
335  return sizeof(info_mi_fields)/sizeof(info_mi_fields[0]);
336 }
337 
338 bool Master_info::read_info(Rpl_info_handler *from)
339 {
340  int lines= 0;
341  char *first_non_digit= NULL;
342  ulong temp_master_log_pos= 0;
343  int temp_ssl= 0;
344  int temp_ssl_verify_server_cert= 0;
345  int temp_auto_position= 0;
346 
347  DBUG_ENTER("Master_info::read_info");
348 
349  /*
350  Starting from 4.1.x master.info has new format. Now its
351  first line contains number of lines in file. By reading this
352  number we will be always distinguish to which version our
353  master.info corresponds to. We can't simply count lines in
354  file since versions before 4.1.x could generate files with more
355  lines than needed.
356  If first line doesn't contain a number or contain number less than
357  LINES_IN_MASTER_INFO_WITH_SSL then such file is treated like file
358  from pre 4.1.1 version.
359  There is no ambiguity when reading an old master.info, as before
360  4.1.1, the first line contained the binlog's name, which is either
361  empty or has an extension (contains a '.'), so can't be confused
362  with an integer.
363 
364  So we're just reading first line and trying to figure which version
365  is this.
366  */
367 
368  if (from->prepare_info_for_read() ||
369  from->get_info(master_log_name, (size_t) sizeof(master_log_name),
370  (char *) ""))
371  DBUG_RETURN(true);
372 
373  lines= strtoul(master_log_name, &first_non_digit, 10);
374 
375  if (master_log_name[0]!='\0' &&
376  *first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL)
377  {
378  /* Seems to be new format => read master log name */
379  if (from->get_info(master_log_name, (size_t) sizeof(master_log_name),
380  (char *) ""))
381  DBUG_RETURN(true);
382  }
383  else
384  lines= 7;
385 
386  if (from->get_info(&temp_master_log_pos,
387  (ulong) BIN_LOG_HEADER_SIZE) ||
388  from->get_info(host, (size_t) sizeof(host), (char *) 0) ||
389  from->get_info(user, (size_t) sizeof(user), (char *) "test") ||
390  from->get_info(password, (size_t) sizeof(password), (char *) 0) ||
391  from->get_info((int *) &port, (int) MYSQL_PORT) ||
392  from->get_info((int *) &connect_retry,
393  (int) DEFAULT_CONNECT_RETRY))
394  DBUG_RETURN(true);
395 
396  /*
397  If file has ssl part use it even if we have server without
398  SSL support. But these options will be ignored later when
399  slave will try connect to master, so in this case warning
400  is printed.
401  */
402  if (lines >= LINES_IN_MASTER_INFO_WITH_SSL)
403  {
404  if (from->get_info(&temp_ssl, 0) ||
405  from->get_info(ssl_ca, (size_t) sizeof(ssl_ca), (char *) 0) ||
406  from->get_info(ssl_capath, (size_t) sizeof(ssl_capath), (char *) 0) ||
407  from->get_info(ssl_cert, (size_t) sizeof(ssl_cert), (char *) 0) ||
408  from->get_info(ssl_cipher, (size_t) sizeof(ssl_cipher), (char *) 0) ||
409  from->get_info(ssl_key, (size_t) sizeof(ssl_key), (char *) 0))
410  DBUG_RETURN(true);
411  }
412 
413  /*
414  Starting from 5.1.16 ssl_verify_server_cert might be
415  in the file
416  */
417  if (lines >= LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT)
418  {
419  if (from->get_info(&temp_ssl_verify_server_cert, (int) 0))
420  DBUG_RETURN(true);
421  }
422 
423  /*
424  Starting from 5.5 master_heartbeat_period might be
425  in the file
426  */
427  if (lines >= LINE_FOR_MASTER_HEARTBEAT_PERIOD)
428  {
429  if (from->get_info(&heartbeat_period, (float) 0.0))
430  DBUG_RETURN(true);
431  }
432 
433  /*
434  Starting from 5.5 master_bind might be in the file
435  */
436  if (lines >= LINE_FOR_MASTER_BIND)
437  {
438  if (from->get_info(bind_addr, (size_t) sizeof(bind_addr), (char *) ""))
439  DBUG_RETURN(true);
440  }
441 
442  /*
443  Starting from 5.5 list of server_id of ignorable servers might be
444  in the file
445  */
446  if (lines >= LINE_FOR_REPLICATE_IGNORE_SERVER_IDS)
447  {
448  if (from->get_info(ignore_server_ids, (Dynamic_ids *) NULL))
449  DBUG_RETURN(true);
450  }
451 
452  /* Starting from 5.5 the master_uuid may be in the repository. */
453  if (lines >= LINE_FOR_MASTER_UUID)
454  {
455  if (from->get_info(master_uuid, (size_t) sizeof(master_uuid),
456  (char *) 0))
457  DBUG_RETURN(true);
458  }
459 
460  /* Starting from 5.5 the master_retry_count may be in the repository. */
461  retry_count= master_retry_count;
462  if (lines >= LINE_FOR_MASTER_RETRY_COUNT)
463  {
464  if (from->get_info(&retry_count, master_retry_count))
465  DBUG_RETURN(true);
466  }
467 
468  if (lines >= LINE_FOR_SSL_CRLPATH)
469  {
470  if (from->get_info(ssl_crl, sizeof(ssl_crl), (char *) 0) ||
471  from->get_info(ssl_crlpath, sizeof(ssl_crlpath), (char *) 0))
472  DBUG_RETURN(true);
473  }
474 
475  if (lines >= LINE_FOR_AUTO_POSITION)
476  {
477  if (from->get_info(&temp_auto_position, (int) 0))
478  DBUG_RETURN(true);
479  }
480 
481  ssl= (my_bool) test(temp_ssl);
482  ssl_verify_server_cert= (my_bool) test(temp_ssl_verify_server_cert);
483  master_log_pos= (my_off_t) temp_master_log_pos;
484  auto_position= test(temp_auto_position);
485 
486  if (auto_position != 0 && gtid_mode != 3)
487  {
488  my_error(ER_AUTO_POSITION_REQUIRES_GTID_MODE_ON, MYF(0));
489  DBUG_RETURN(true);
490  }
491 
492 #ifndef HAVE_OPENSSL
493  if (ssl)
494  sql_print_warning("SSL information in the master info file "
495  "are ignored because this MySQL slave was "
496  "compiled without SSL support.");
497 #endif /* HAVE_OPENSSL */
498 
499  DBUG_RETURN(false);
500 }
501 
502 bool Master_info::write_info(Rpl_info_handler *to)
503 {
504  DBUG_ENTER("Master_info::write_info");
505 
506  /*
507  In certain cases this code may create master.info files that seems
508  corrupted, because of extra lines filled with garbage in the end
509  file (this happens if new contents take less space than previous
510  contents of file). But because of number of lines in the first line
511  of file we don't care about this garbage.
512  */
513  if (to->prepare_info_for_write() ||
514  to->set_info((int) LINES_IN_MASTER_INFO) ||
515  to->set_info(master_log_name) ||
516  to->set_info((ulong) master_log_pos) ||
517  to->set_info(host) ||
518  to->set_info(user) ||
519  to->set_info(password) ||
520  to->set_info((int) port) ||
521  to->set_info((int) connect_retry) ||
522  to->set_info((int) ssl) ||
523  to->set_info(ssl_ca) ||
524  to->set_info(ssl_capath) ||
525  to->set_info(ssl_cert) ||
526  to->set_info(ssl_cipher) ||
527  to->set_info(ssl_key) ||
528  to->set_info((int) ssl_verify_server_cert) ||
529  to->set_info(heartbeat_period) ||
530  to->set_info(bind_addr) ||
531  to->set_info(ignore_server_ids) ||
532  to->set_info(master_uuid) ||
533  to->set_info(retry_count) ||
534  to->set_info(ssl_crl) ||
535  to->set_info(ssl_crlpath) ||
536  to->set_info((int) auto_position))
537  DBUG_RETURN(TRUE);
538 
539  DBUG_RETURN(FALSE);
540 }
541 
542 bool Master_info::set_password(const char* password_arg,
543  int password_arg_size __attribute__((unused)))
544 {
545  bool ret= true;
546  DBUG_ENTER("Master_info::set_password");
547 
548  if (password_arg && start_user_configured)
549  {
550  strmake(start_password, password_arg, sizeof(start_password) - 1);
551  ret= false;
552  }
553  else if (password_arg)
554  {
555  strmake(password, password_arg, sizeof(password) - 1);
556  ret= false;
557  }
558  DBUG_RETURN(ret);
559 }
560 
561 bool Master_info::get_password(char *password_arg, int *password_arg_size)
562 {
563  bool ret= true;
564  DBUG_ENTER("Master_info::get_password");
565 
566  if (password_arg && start_user_configured)
567  {
568  *password_arg_size= strlen(start_password);
569  strmake(password_arg, start_password, sizeof(start_password) - 1);
570  ret= false;
571  }
572  else if (password_arg)
573  {
574  *password_arg_size= strlen(password);
575  strmake(password_arg, password, sizeof(password) - 1);
576  ret= false;
577  }
578  DBUG_RETURN(ret);
579 }
580 
581 void Master_info::reset_start_info()
582 {
583  DBUG_ENTER("Master_info::reset_start_info");
584  start_plugin_auth[0]= 0;
585  start_plugin_dir[0]= 0;
586  start_user_configured= false;
587  start_user[0]= 0;
588  start_password[0]= 0;
589  DBUG_VOID_RETURN;
590 }
591 #endif /* HAVE_REPLICATION */