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