MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
rpl_master.cc
1 /* Copyright (c) 2010, 2013, 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 Foundation,
14  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
15 
16 
17 #include "sql_priv.h"
18 #include "unireg.h"
19 #include "sql_parse.h" // check_access
20 #include "global_threads.h"
21 #ifdef HAVE_REPLICATION
22 
23 #include "sql_acl.h" // SUPER_ACL
24 #include "log_event.h"
25 #include "rpl_filter.h"
26 #include <my_dir.h>
27 #include "rpl_handler.h"
28 #include "rpl_master.h"
29 #include "debug_sync.h"
30 
31 int max_binlog_dump_events = 0; // unlimited
32 my_bool opt_sporadic_binlog_dump_fail = 0;
33 
34 #ifndef DBUG_OFF
35 static int binlog_dump_count = 0;
36 #endif
37 
38 #define SLAVE_LIST_CHUNK 128
39 #define SLAVE_ERRMSG_SIZE (FN_REFLEN+64)
40 HASH slave_list;
41 extern TYPELIB binlog_checksum_typelib;
42 
43 
44 #define get_object(p, obj, msg) \
45 {\
46  uint len; \
47  if (p >= p_end) \
48  { \
49  my_error(ER_MALFORMED_PACKET, MYF(0)); \
50  my_free(si); \
51  return 1; \
52  } \
53  len= (uint)*p++; \
54  if (p + len > p_end || len >= sizeof(obj)) \
55  {\
56  errmsg= msg;\
57  goto err; \
58  }\
59  strmake(obj,(char*) p,len); \
60  p+= len; \
61 }\
62 
63 extern "C" uint32
64 *slave_list_key(SLAVE_INFO* si, size_t *len,
65  my_bool not_used __attribute__((unused)))
66 {
67  *len = 4;
68  return &si->server_id;
69 }
70 
71 extern "C" void slave_info_free(void *s)
72 {
73  my_free(s);
74 }
75 
76 #ifdef HAVE_PSI_INTERFACE
77 static PSI_mutex_key key_LOCK_slave_list;
78 
79 static PSI_mutex_info all_slave_list_mutexes[]=
80 {
81  { &key_LOCK_slave_list, "LOCK_slave_list", PSI_FLAG_GLOBAL}
82 };
83 
84 static void init_all_slave_list_mutexes(void)
85 {
86  int count;
87 
88  count= array_elements(all_slave_list_mutexes);
89  mysql_mutex_register("sql", all_slave_list_mutexes, count);
90 }
91 #endif /* HAVE_PSI_INTERFACE */
92 
93 void init_slave_list()
94 {
95 #ifdef HAVE_PSI_INTERFACE
96  init_all_slave_list_mutexes();
97 #endif
98 
99  my_hash_init(&slave_list, system_charset_info, SLAVE_LIST_CHUNK, 0, 0,
100  (my_hash_get_key) slave_list_key,
101  (my_hash_free_key) slave_info_free, 0);
102  mysql_mutex_init(key_LOCK_slave_list, &LOCK_slave_list, MY_MUTEX_INIT_FAST);
103 }
104 
105 void end_slave_list()
106 {
107  /* No protection by a mutex needed as we are only called at shutdown */
108  if (my_hash_inited(&slave_list))
109  {
110  my_hash_free(&slave_list);
111  mysql_mutex_destroy(&LOCK_slave_list);
112  }
113 }
114 
124 int register_slave(THD* thd, uchar* packet, uint packet_length)
125 {
126  int res;
127  SLAVE_INFO *si;
128  uchar *p= packet, *p_end= packet + packet_length;
129  const char *errmsg= "Wrong parameters to function register_slave";
130 
131  if (check_access(thd, REPL_SLAVE_ACL, any_db, NULL, NULL, 0, 0))
132  return 1;
133  if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME))))
134  goto err2;
135 
136  /* 4 bytes for the server id */
137  if (p + 4 > p_end)
138  {
139  my_error(ER_MALFORMED_PACKET, MYF(0));
140  my_free(si);
141  return 1;
142  }
143 
144  thd->server_id= si->server_id= uint4korr(p);
145  p+= 4;
146  get_object(p,si->host, "Failed to register slave: too long 'report-host'");
147  get_object(p,si->user, "Failed to register slave: too long 'report-user'");
148  get_object(p,si->password, "Failed to register slave; too long 'report-password'");
149  if (p+10 > p_end)
150  goto err;
151  si->port= uint2korr(p);
152  p += 2;
153  /*
154  We need to by pass the bytes used in the fake rpl_recovery_rank
155  variable. It was removed in patch for BUG#13963. But this would
156  make a server with that patch unable to connect to an old master.
157  See: BUG#49259
158  */
159  p += 4;
160  if (!(si->master_id= uint4korr(p)))
161  si->master_id= server_id;
162  si->thd= thd;
163 
164  mysql_mutex_lock(&LOCK_slave_list);
165  unregister_slave(thd, false, false/*need_lock_slave_list=false*/);
166  res= my_hash_insert(&slave_list, (uchar*) si);
167  mysql_mutex_unlock(&LOCK_slave_list);
168  return res;
169 
170 err:
171  my_free(si);
172  my_message(ER_UNKNOWN_ERROR, errmsg, MYF(0)); /* purecov: inspected */
173 err2:
174  return 1;
175 }
176 
177 void unregister_slave(THD* thd, bool only_mine, bool need_lock_slave_list)
178 {
179  if (thd->server_id)
180  {
181  if (need_lock_slave_list)
182  mysql_mutex_lock(&LOCK_slave_list);
183  else
184  mysql_mutex_assert_owner(&LOCK_slave_list);
185 
186  SLAVE_INFO* old_si;
187  if ((old_si = (SLAVE_INFO*)my_hash_search(&slave_list,
188  (uchar*)&thd->server_id, 4)) &&
189  (!only_mine || old_si->thd == thd))
190  my_hash_delete(&slave_list, (uchar*)old_si);
191 
192  if (need_lock_slave_list)
193  mysql_mutex_unlock(&LOCK_slave_list);
194  }
195 }
196 
197 
207 bool show_slave_hosts(THD* thd)
208 {
209  List<Item> field_list;
210  Protocol *protocol= thd->protocol;
211  DBUG_ENTER("show_slave_hosts");
212 
213  field_list.push_back(new Item_return_int("Server_id", 10,
214  MYSQL_TYPE_LONG));
215  field_list.push_back(new Item_empty_string("Host", 20));
216  if (opt_show_slave_auth_info)
217  {
218  field_list.push_back(new Item_empty_string("User",20));
219  field_list.push_back(new Item_empty_string("Password",20));
220  }
221  field_list.push_back(new Item_return_int("Port", 7, MYSQL_TYPE_LONG));
222  field_list.push_back(new Item_return_int("Master_id", 10,
223  MYSQL_TYPE_LONG));
224  field_list.push_back(new Item_empty_string("Slave_UUID", UUID_LENGTH));
225 
226  if (protocol->send_result_set_metadata(&field_list,
227  Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
228  DBUG_RETURN(TRUE);
229 
230  mysql_mutex_lock(&LOCK_slave_list);
231 
232  for (uint i = 0; i < slave_list.records; ++i)
233  {
234  SLAVE_INFO* si = (SLAVE_INFO*) my_hash_element(&slave_list, i);
235  protocol->prepare_for_resend();
236  protocol->store((uint32) si->server_id);
237  protocol->store(si->host, &my_charset_bin);
238  if (opt_show_slave_auth_info)
239  {
240  protocol->store(si->user, &my_charset_bin);
241  protocol->store(si->password, &my_charset_bin);
242  }
243  protocol->store((uint32) si->port);
244  protocol->store((uint32) si->master_id);
245 
246  /* get slave's UUID */
247  String slave_uuid;
248  if (get_slave_uuid(si->thd, &slave_uuid))
249  protocol->store(slave_uuid.c_ptr_safe(), &my_charset_bin);
250  if (protocol->write())
251  {
252  mysql_mutex_unlock(&LOCK_slave_list);
253  DBUG_RETURN(TRUE);
254  }
255  }
256  mysql_mutex_unlock(&LOCK_slave_list);
257  my_eof(thd);
258  DBUG_RETURN(FALSE);
259 }
260 
261 
266 inline void fix_checksum(String *packet, ulong ev_offset)
267 {
268  /* recalculate the crc for this event */
269  uint data_len = uint4korr(packet->ptr() + ev_offset + EVENT_LEN_OFFSET);
270  ha_checksum crc= my_checksum(0L, NULL, 0);
271  DBUG_ASSERT(data_len ==
272  LOG_EVENT_MINIMAL_HEADER_LEN + FORMAT_DESCRIPTION_HEADER_LEN +
273  BINLOG_CHECKSUM_ALG_DESC_LEN + BINLOG_CHECKSUM_LEN);
274  crc= my_checksum(crc, (uchar *)packet->ptr() + ev_offset, data_len -
276  int4store(packet->ptr() + ev_offset + data_len - BINLOG_CHECKSUM_LEN, crc);
277 }
278 
279 
280 static user_var_entry * get_binlog_checksum_uservar(THD * thd)
281 {
282  LEX_STRING name= { C_STRING_WITH_LEN("master_binlog_checksum")};
283  user_var_entry *entry=
284  (user_var_entry*) my_hash_search(&thd->user_vars, (uchar*) name.str,
285  name.length);
286  return entry;
287 }
288 
298 static bool is_slave_checksum_aware(THD * thd)
299 {
300  DBUG_ENTER("is_slave_checksum_aware");
301  user_var_entry *entry= get_binlog_checksum_uservar(thd);
302  DBUG_RETURN(entry? true : false);
303 }
304 
319 static uint8 get_binlog_checksum_value_at_connect(THD * thd)
320 {
321  uint8 ret;
322 
323  DBUG_ENTER("get_binlog_checksum_value_at_connect");
324  user_var_entry *entry= get_binlog_checksum_uservar(thd);
325  if (!entry)
326  {
327  ret= BINLOG_CHECKSUM_ALG_UNDEF;
328  }
329  else
330  {
331  DBUG_ASSERT(entry->type() == STRING_RESULT);
332  String str;
333  uint dummy_errors;
334  str.copy(entry->ptr(), entry->length(), &my_charset_bin, &my_charset_bin,
335  &dummy_errors);
336  ret= (uint8) find_type ((char*) str.ptr(), &binlog_checksum_typelib, 1) - 1;
337  DBUG_ASSERT(ret <= BINLOG_CHECKSUM_ALG_CRC32); // while it's just on CRC32 alg
338  }
339  DBUG_RETURN(ret);
340 }
341 
342 /*
343  fake_rotate_event() builds a fake (=which does not exist physically in any
344  binlog) Rotate event, which contains the name of the binlog we are going to
345  send to the slave (because the slave may not know it if it just asked for
346  MASTER_LOG_FILE='', MASTER_LOG_POS=4).
347  < 4.0.14, fake_rotate_event() was called only if the requested pos was 4.
348  After this version we always call it, so that a 3.23.58 slave can rely on
349  it to detect if the master is 4.0 (and stop) (the _fake_ Rotate event has
350  zeros in the good positions which, by chance, make it possible for the 3.23
351  slave to detect that this event is unexpected) (this is luck which happens
352  because the master and slave disagree on the size of the header of
353  Log_event).
354 
355  Relying on the event length of the Rotate event instead of these
356  well-placed zeros was not possible as Rotate events have a variable-length
357  part.
358 */
359 
360 static int fake_rotate_event(NET* net, String* packet, char* log_file_name,
361  ulonglong position, const char** errmsg,
362  uint8 checksum_alg_arg)
363 {
364  DBUG_ENTER("fake_rotate_event");
365  char header[LOG_EVENT_HEADER_LEN], buf[ROTATE_HEADER_LEN+100];
366 
367  /*
368  this Rotate is to be sent with checksum if and only if
369  slave's get_master_version_and_clock time handshake value
370  of master's @@global.binlog_checksum was TRUE
371  */
372 
373  my_bool do_checksum= checksum_alg_arg != BINLOG_CHECKSUM_ALG_OFF &&
374  checksum_alg_arg != BINLOG_CHECKSUM_ALG_UNDEF;
375 
376  /*
377  'when' (the timestamp) is set to 0 so that slave could distinguish between
378  real and fake Rotate events (if necessary)
379  */
380  memset(header, 0, 4);
381  header[EVENT_TYPE_OFFSET] = ROTATE_EVENT;
382 
383  char* p = log_file_name+dirname_length(log_file_name);
384  uint ident_len = (uint) strlen(p);
385  ulong event_len = ident_len + LOG_EVENT_HEADER_LEN + ROTATE_HEADER_LEN +
386  (do_checksum ? BINLOG_CHECKSUM_LEN : 0);
387  int4store(header + SERVER_ID_OFFSET, server_id);
388  int4store(header + EVENT_LEN_OFFSET, event_len);
389  int2store(header + FLAGS_OFFSET, LOG_EVENT_ARTIFICIAL_F);
390 
391  // TODO: check what problems this may cause and fix them
392  int4store(header + LOG_POS_OFFSET, 0);
393 
394  packet->append(header, sizeof(header));
395  int8store(buf+R_POS_OFFSET,position);
396  packet->append(buf, ROTATE_HEADER_LEN);
397  packet->append(p, ident_len);
398 
399  if (do_checksum)
400  {
401  char b[BINLOG_CHECKSUM_LEN];
402  ha_checksum crc= my_checksum(0L, NULL, 0);
403  crc= my_checksum(crc, (uchar*)header, sizeof(header));
404  crc= my_checksum(crc, (uchar*)buf, ROTATE_HEADER_LEN);
405  crc= my_checksum(crc, (uchar*)p, ident_len);
406  int4store(b, crc);
407  packet->append(b, sizeof(b));
408  }
409 
410  if (my_net_write(net, (uchar*) packet->ptr(), packet->length()))
411  {
412  *errmsg = "failed on my_net_write()";
413  DBUG_RETURN(-1);
414  }
415  DBUG_RETURN(0);
416 }
417 
418 /*
419  Reset thread transmit packet buffer for event sending
420 
421  This function allocates header bytes for event transmission, and
422  should be called before store the event data to the packet buffer.
423 */
424 static int reset_transmit_packet(THD *thd, ushort flags,
425  ulong *ev_offset, const char **errmsg)
426 {
427  int ret= 0;
428  String *packet= &thd->packet;
429 
430  /* reserve and set default header */
431  packet->length(0);
432  packet->set("\0", 1, &my_charset_bin);
433 
434  if (RUN_HOOK(binlog_transmit, reserve_header, (thd, flags, packet)))
435  {
436  *errmsg= "Failed to run hook 'reserve_header'";
437  my_errno= ER_UNKNOWN_ERROR;
438  ret= 1;
439  }
440  *ev_offset= packet->length();
441  DBUG_PRINT("info", ("rpl_master.cc:reset_transmit_packet returns %d", ret));
442  return ret;
443 }
444 
445 static int send_file(THD *thd)
446 {
447  NET* net = &thd->net;
448  int fd = -1, error = 1;
449  size_t bytes;
450  char fname[FN_REFLEN+1];
451  const char *errmsg = 0;
452  int old_timeout;
453  unsigned long packet_len;
454  uchar buf[IO_SIZE]; // It's safe to alloc this
455  DBUG_ENTER("send_file");
456 
457  /*
458  The client might be slow loading the data, give him wait_timeout to do
459  the job
460  */
461  old_timeout= net->read_timeout;
462  my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
463 
464  /*
465  We need net_flush here because the client will not know it needs to send
466  us the file name until it has processed the load event entry
467  */
468  if (net_flush(net) || (packet_len = my_net_read(net)) == packet_error)
469  {
470  errmsg = "while reading file name";
471  goto err;
472  }
473 
474  // terminate with \0 for fn_format
475  *((char*)net->read_pos + packet_len) = 0;
476  fn_format(fname, (char*) net->read_pos + 1, "", "", 4);
477  // this is needed to make replicate-ignore-db
478  if (!strcmp(fname,"/dev/null"))
479  goto end;
480 
481  if ((fd= mysql_file_open(key_file_send_file,
482  fname, O_RDONLY, MYF(0))) < 0)
483  {
484  errmsg = "on open of file";
485  goto err;
486  }
487 
488  while ((long) (bytes= mysql_file_read(fd, buf, IO_SIZE, MYF(0))) > 0)
489  {
490  if (my_net_write(net, buf, bytes))
491  {
492  errmsg = "while writing data to client";
493  goto err;
494  }
495  }
496 
497  end:
498  if (my_net_write(net, (uchar*) "", 0) || net_flush(net) ||
499  (my_net_read(net) == packet_error))
500  {
501  errmsg = "while negotiating file transfer close";
502  goto err;
503  }
504  error = 0;
505 
506  err:
507  my_net_set_read_timeout(net, old_timeout);
508  if (fd >= 0)
509  mysql_file_close(fd, MYF(0));
510  if (errmsg)
511  {
512  sql_print_error("Failed in send_file() %s", errmsg);
513  DBUG_PRINT("error", ("%s", errmsg));
514  }
515  DBUG_RETURN(error);
516 }
517 
518 
519 int test_for_non_eof_log_read_errors(int error, const char **errmsg)
520 {
521  if (error == LOG_READ_EOF)
522  return 0;
523  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
524  switch (error) {
525  case LOG_READ_BOGUS:
526  *errmsg = "bogus data in log event";
527  break;
528  case LOG_READ_TOO_LARGE:
529  *errmsg = "log event entry exceeded max_allowed_packet; \
530 Increase max_allowed_packet on master";
531  break;
532  case LOG_READ_IO:
533  *errmsg = "I/O error reading log event";
534  break;
535  case LOG_READ_MEM:
536  *errmsg = "memory allocation failed reading log event";
537  break;
538  case LOG_READ_TRUNC:
539  *errmsg = "binlog truncated in the middle of event; consider out of disk space on master";
540  break;
541  case LOG_READ_CHECKSUM_FAILURE:
542  *errmsg = "event read from binlog did not pass crc check";
543  break;
544  default:
545  *errmsg = "unknown error reading log event on the master";
546  break;
547  }
548  return error;
549 }
550 
551 
561 static ulonglong get_heartbeat_period(THD * thd)
562 {
563  my_bool null_value;
564  LEX_STRING name= { C_STRING_WITH_LEN("master_heartbeat_period")};
565  user_var_entry *entry=
566  (user_var_entry*) my_hash_search(&thd->user_vars, (uchar*) name.str,
567  name.length);
568  return entry? entry->val_int(&null_value) : 0;
569 }
570 
571 /*
572  Function prepares and sends repliation heartbeat event.
573 
574  @param net net object of THD
575  @param packet buffer to store the heartbeat instance
576  @param event_coordinates binlog file name and position of the last
577  real event master sent from binlog
578 
579  @note
580  Among three essential pieces of heartbeat data Log_event::when
581  is computed locally.
582  The error to send is serious and should force terminating
583  the dump thread.
584 */
585 static int send_heartbeat_event(NET* net, String* packet,
586  const struct event_coordinates *coord,
587  uint8 checksum_alg_arg)
588 {
589  DBUG_ENTER("send_heartbeat_event");
590  char header[LOG_EVENT_HEADER_LEN];
591  my_bool do_checksum= checksum_alg_arg != BINLOG_CHECKSUM_ALG_OFF &&
592  checksum_alg_arg != BINLOG_CHECKSUM_ALG_UNDEF;
593  /*
594  'when' (the timestamp) is set to 0 so that slave could distinguish between
595  real and fake Rotate events (if necessary)
596  */
597  memset(header, 0, 4); // when
598 
599  header[EVENT_TYPE_OFFSET] = HEARTBEAT_LOG_EVENT;
600 
601  char* p= coord->file_name + dirname_length(coord->file_name);
602 
603  uint ident_len = strlen(p);
604  ulong event_len = ident_len + LOG_EVENT_HEADER_LEN +
605  (do_checksum ? BINLOG_CHECKSUM_LEN : 0);
606  int4store(header + SERVER_ID_OFFSET, server_id);
607  int4store(header + EVENT_LEN_OFFSET, event_len);
608  int2store(header + FLAGS_OFFSET, 0);
609 
610  int4store(header + LOG_POS_OFFSET, coord->pos); // log_pos
611 
612  packet->append(header, sizeof(header));
613  packet->append(p, ident_len); // log_file_name
614 
615  if (do_checksum)
616  {
617  char b[BINLOG_CHECKSUM_LEN];
618  ha_checksum crc= my_checksum(0L, NULL, 0);
619  crc= my_checksum(crc, (uchar*) header, sizeof(header));
620  crc= my_checksum(crc, (uchar*) p, ident_len);
621  int4store(b, crc);
622  packet->append(b, sizeof(b));
623  }
624 
625  if (my_net_write(net, (uchar*) packet->ptr(), packet->length()) ||
626  net_flush(net))
627  {
628  DBUG_RETURN(-1);
629  }
630  DBUG_RETURN(0);
631 }
632 
633 
653 static int send_last_skip_group_heartbeat(THD *thd, NET* net, String *packet,
654  const struct event_coordinates *last_skip_coord,
655  ulong *ev_offset,
656  uint8 checksum_alg_arg, const char **errmsg)
657 {
658  DBUG_ENTER("send_last_skip_group_heartbeat");
659  String save_packet;
660  int save_offset= *ev_offset;
661 
662  /* Save the current read packet */
663  save_packet.swap(*packet);
664 
665  if (reset_transmit_packet(thd, 0, ev_offset, errmsg))
666  DBUG_RETURN(-1);
667 
668  /* Send heart beat event to the slave to update slave threads coordinates */
669  if (send_heartbeat_event(net, packet, last_skip_coord, checksum_alg_arg))
670  {
671  *errmsg= "Failed on my_net_write()";
672  my_errno= ER_UNKNOWN_ERROR;
673  DBUG_RETURN(-1);
674  }
675 
676  /* Restore the packet and event offset */
677  packet->swap(save_packet);
678  *ev_offset= save_offset;
679 
680  DBUG_PRINT("info", ("rpl_master.cc:send_last_skip_group_heartbeat returns 0"));
681  DBUG_RETURN(0);
682 }
683 
684 
689 #define CHECK_PACKET_SIZE(BYTES) \
690  do { \
691  if (packet_bytes_todo < BYTES) \
692  goto error_malformed_packet; \
693  } while (0)
694 
702 #define READ(DECODE, BYTES) \
703  do { \
704  CHECK_PACKET_SIZE(BYTES); \
705  DECODE; \
706  packet_position+= BYTES; \
707  packet_bytes_todo-= BYTES; \
708  } while (0)
709 
710 #define SKIP(BYTES) READ((void)(0), BYTES)
711 
717 #define READ_INT(VAR, BYTES) \
718  READ(VAR= uint ## BYTES ## korr(packet_position), BYTES)
719 
725 #define READ_STRING(VAR, BYTES, BUFFER_SIZE) \
726  do { \
727  if (BUFFER_SIZE <= BYTES) \
728  goto error_malformed_packet; \
729  READ(memcpy(VAR, packet_position, BYTES), BYTES); \
730  VAR[BYTES]= '\0'; \
731  } while (0)
732 
733 
734 bool com_binlog_dump(THD *thd, char *packet, uint packet_length)
735 {
736  DBUG_ENTER("com_binlog_dump");
737  ulong pos;
738  String slave_uuid;
739  const uchar* packet_position= (uchar *) packet;
740  uint packet_bytes_todo= packet_length;
741 
742  status_var_increment(thd->status_var.com_other);
743  thd->enable_slow_log= opt_log_slow_admin_statements;
744  if (check_global_access(thd, REPL_SLAVE_ACL))
745  DBUG_RETURN(false);
746 
747  /*
748  4 bytes is too little, but changing the protocol would break
749  compatibility. This has been fixed in the new protocol. @see
750  com_binlog_dump_gtid().
751  */
752  READ_INT(pos, 4);
753  SKIP(2); /* flags field is unused */
754  READ_INT(thd->server_id, 4);
755 
756  get_slave_uuid(thd, &slave_uuid);
757  kill_zombie_dump_threads(&slave_uuid);
758 
759  general_log_print(thd, thd->get_command(), "Log: '%s' Pos: %ld",
760  packet + 10, (long) pos);
761  mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, NULL);
762 
763  unregister_slave(thd, true, true/*need_lock_slave_list=true*/);
764  /* fake COM_QUIT -- if we get here, the thread needs to terminate */
765  DBUG_RETURN(true);
766 
767 error_malformed_packet:
768  my_error(ER_MALFORMED_PACKET, MYF(0));
769  DBUG_RETURN(true);
770 }
771 
772 
773 bool com_binlog_dump_gtid(THD *thd, char *packet, uint packet_length)
774 {
775  DBUG_ENTER("com_binlog_dump_gtid");
776  /*
777  Before going GA, we need to make this protocol extensible without
778  breaking compatitibilty. /Alfranio.
779  */
780  String slave_uuid;
781  uint32 data_size= 0;
782  uint64 pos= 0;
783  char name[FN_REFLEN + 1];
784  uint32 name_size= 0;
785  char* gtid_string= NULL;
786  const uchar* packet_position= (uchar *) packet;
787  uint packet_bytes_todo= packet_length;
788  Sid_map sid_map(NULL/*no sid_lock because this is a completely local object*/);
789  Gtid_set slave_gtid_executed(&sid_map);
790 
791  status_var_increment(thd->status_var.com_other);
792  thd->enable_slow_log= opt_log_slow_admin_statements;
793  if (check_global_access(thd, REPL_SLAVE_ACL))
794  DBUG_RETURN(false);
795 
796  SKIP(2); /* flags field is unused */
797  READ_INT(thd->server_id, 4);
798  READ_INT(name_size, 4);
799  READ_STRING(name, name_size, sizeof(name));
800  READ_INT(pos, 8);
801  READ_INT(data_size, 4);
802  CHECK_PACKET_SIZE(data_size);
803  if (slave_gtid_executed.add_gtid_encoding(packet_position, data_size) !=
804  RETURN_STATUS_OK)
805  DBUG_RETURN(true);
806  gtid_string= slave_gtid_executed.to_string();
807  DBUG_PRINT("info", ("Slave %d requested to read %s at position %llu gtid set "
808  "'%s'.", thd->server_id, name, pos, gtid_string));
809 
810  get_slave_uuid(thd, &slave_uuid);
811  kill_zombie_dump_threads(&slave_uuid);
812  general_log_print(thd, thd->get_command(), "Log: '%s' Pos: %llu GTIDs: '%s'",
813  name, pos, gtid_string);
814  my_free(gtid_string);
815  mysql_binlog_send(thd, name, (my_off_t) pos, &slave_gtid_executed);
816 
817  unregister_slave(thd, true, true/*need_lock_slave_list=true*/);
818  /* fake COM_QUIT -- if we get here, the thread needs to terminate */
819  DBUG_RETURN(true);
820 
821 error_malformed_packet:
822  my_error(ER_MALFORMED_PACKET, MYF(0));
823  DBUG_RETURN(true);
824 }
825 
826 
827 void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
828  const Gtid_set* slave_gtid_executed)
829 {
834 #define GOTO_ERR \
835  do { \
836  DBUG_PRINT("info", ("mysql_binlog_send fails; goto err from line %d", \
837  __LINE__)); \
838  goto err; \
839  } while (0)
840  LOG_INFO linfo;
841  char *log_file_name = linfo.log_file_name;
842  char search_file_name[FN_REFLEN], *name;
843 
844  ulong ev_offset;
845  bool using_gtid_protocol= slave_gtid_executed != NULL;
846  bool searching_first_gtid= using_gtid_protocol;
847  bool skip_group= false;
848  bool binlog_has_previous_gtids_log_event= false;
849  Sid_map *sid_map= slave_gtid_executed ? slave_gtid_executed->get_sid_map() : NULL;
850 
851  IO_CACHE log;
852  File file = -1;
853  String* packet = &thd->packet;
854  int error;
855  const char *errmsg = "Unknown error";
856  char error_text[MAX_SLAVE_ERRMSG]; // to be send to slave via my_message()
857  NET* net = &thd->net;
858  mysql_mutex_t *log_lock;
859  mysql_cond_t *log_cond;
860  uint8 current_checksum_alg= BINLOG_CHECKSUM_ALG_UNDEF;
861  Format_description_log_event fdle(BINLOG_VERSION), *p_fdle= &fdle;
862 
863 #ifndef DBUG_OFF
864  int left_events = max_binlog_dump_events;
865 #endif
866  int old_max_allowed_packet= thd->variables.max_allowed_packet;
867  /*
868  Dump thread sends ER_MASTER_FATAL_ERROR_READING_BINLOG instead of the real
869  errors happend on master to slave when erorr is encountered.
870  So set a temporary Diagnostics_area to thd. The low level error is always
871  set into the temporary Diagnostics_area and be ingored. The original
872  Diagnostics_area will be restored at the end of this function.
873  ER_MASTER_FATAL_ERROR_READING_BINLOG will be set to the original
874  Diagnostics_area.
875  */
876  Diagnostics_area temp_da;
877  Diagnostics_area *saved_da= thd->get_stmt_da();
878  thd->set_stmt_da(&temp_da);
879 
880  DBUG_ENTER("mysql_binlog_send");
881  DBUG_PRINT("enter",("log_ident: '%s' pos: %ld", log_ident, (long) pos));
882 
883  memset(&log, 0, sizeof(log));
884  /*
885  heartbeat_period from @master_heartbeat_period user variable
886  */
887  ulonglong heartbeat_period= get_heartbeat_period(thd);
888  struct timespec heartbeat_buf;
889  struct timespec *heartbeat_ts= NULL;
890  const LOG_POS_COORD start_coord= { log_ident, pos },
891  *p_start_coord= &start_coord;
892  LOG_POS_COORD coord_buf= { log_file_name, BIN_LOG_HEADER_SIZE },
893  *p_coord= &coord_buf;
894 
895  /*
896  We use the following variables to send a HB event
897  when groups are skipped during a GTID protocol.
898  */
899  /* Flag to check if last transaction was skipped */
900  bool last_skip_group= skip_group;
901  /* File name where last skip group is present */
902  char last_skip_log_name[FN_REFLEN+1];
903  /* Coordinates of the last skip group */
904  LOG_POS_COORD last_skip_coord_buf= {last_skip_log_name, BIN_LOG_HEADER_SIZE},
905  *p_last_skip_coord= &last_skip_coord_buf;
906 
907  if (heartbeat_period != LL(0))
908  {
909  heartbeat_ts= &heartbeat_buf;
910  set_timespec_nsec(*heartbeat_ts, 0);
911  }
912  if (log_warnings > 1)
913  sql_print_information("Start binlog_dump to master_thread_id(%lu) slave_server(%d), pos(%s, %lu)",
914  thd->thread_id, thd->server_id, log_ident, (ulong)pos);
915  if (RUN_HOOK(binlog_transmit, transmit_start, (thd, 0/*flags*/, log_ident, pos)))
916  {
917  errmsg= "Failed to run hook 'transmit_start'";
918  my_errno= ER_UNKNOWN_ERROR;
919  GOTO_ERR;
920  }
921 
922 #ifndef DBUG_OFF
923  if (opt_sporadic_binlog_dump_fail && (binlog_dump_count++ % 2))
924  {
925  errmsg = "Master fails in COM_BINLOG_DUMP because of --opt-sporadic-binlog-dump-fail";
926  my_errno= ER_UNKNOWN_ERROR;
927  GOTO_ERR;
928  }
929 #endif
930 
931  if (!mysql_bin_log.is_open())
932  {
933  errmsg = "Binary log is not open";
934  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
935  GOTO_ERR;
936  }
937  if (!server_id_supplied)
938  {
939  errmsg = "Misconfigured master - server_id was not set";
940  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
941  GOTO_ERR;
942  }
943 
944  name= search_file_name;
945  if (log_ident[0])
946  mysql_bin_log.make_log_name(search_file_name, log_ident);
947  else
948  {
949  if (using_gtid_protocol)
950  {
951  if (mysql_bin_log.find_first_log_not_in_gtid_set(name,
952  slave_gtid_executed,
953  &errmsg))
954  {
955  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
956  GOTO_ERR;
957  }
958  }
959  else
960  name= 0; // Find first log
961  }
962 
963  linfo.index_file_offset= 0;
964 
965  if (mysql_bin_log.find_log_pos(&linfo, name, 1))
966  {
967  errmsg = "Could not find first log file name in binary log index file";
968  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
969  GOTO_ERR;
970  }
971 
972  mysql_mutex_lock(&LOCK_thread_count);
973  thd->current_linfo = &linfo;
974  mysql_mutex_unlock(&LOCK_thread_count);
975 
976  if ((file=open_binlog_file(&log, log_file_name, &errmsg)) < 0)
977  {
978  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
979  GOTO_ERR;
980  }
981  if (pos < BIN_LOG_HEADER_SIZE)
982  {
983  errmsg= "Client requested master to start replication from position < 4";
984  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
985  GOTO_ERR;
986  }
987  if (pos > my_b_filelength(&log))
988  {
989  errmsg= "Client requested master to start replication from position > file size";
990  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
991  GOTO_ERR;
992  }
993 
994  /* reset transmit packet for the fake rotate event below */
995  if (reset_transmit_packet(thd, 0/*flags*/, &ev_offset, &errmsg))
996  GOTO_ERR;
997 
998  /*
999  Tell the client about the log name with a fake Rotate event;
1000  this is needed even if we also send a Format_description_log_event
1001  just after, because that event does not contain the binlog's name.
1002  Note that as this Rotate event is sent before
1003  Format_description_log_event, the slave cannot have any info to
1004  understand this event's format, so the header len of
1005  Rotate_log_event is FROZEN (so in 5.0 it will have a header shorter
1006  than other events except FORMAT_DESCRIPTION_EVENT).
1007  Before 4.0.14 we called fake_rotate_event below only if (pos ==
1008  BIN_LOG_HEADER_SIZE), because if this is false then the slave
1009  already knows the binlog's name.
1010  Since, we always call fake_rotate_event; if the slave already knew
1011  the log's name (ex: CHANGE MASTER TO MASTER_LOG_FILE=...) this is
1012  useless but does not harm much. It is nice for 3.23 (>=.58) slaves
1013  which test Rotate events to see if the master is 4.0 (then they
1014  choose to stop because they can't replicate 4.0); by always calling
1015  fake_rotate_event we are sure that 3.23.58 and newer will detect the
1016  problem as soon as replication starts (BUG#198).
1017  Always calling fake_rotate_event makes sending of normal
1018  (=from-binlog) Rotate events a priori unneeded, but it is not so
1019  simple: the 2 Rotate events are not equivalent, the normal one is
1020  before the Stop event, the fake one is after. If we don't send the
1021  normal one, then the Stop event will be interpreted (by existing 4.0
1022  slaves) as "the master stopped", which is wrong. So for safety,
1023  given that we want minimum modification of 4.0, we send the normal
1024  and fake Rotates.
1025  */
1026  if (fake_rotate_event(net, packet, log_file_name, pos, &errmsg,
1027  get_binlog_checksum_value_at_connect(current_thd)))
1028  {
1029  /*
1030  This error code is not perfect, as fake_rotate_event() does not
1031  read anything from the binlog; if it fails it's because of an
1032  error in my_net_write(), fortunately it will say so in errmsg.
1033  */
1034  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
1035  GOTO_ERR;
1036  }
1037 
1038  /*
1039  Adding MAX_LOG_EVENT_HEADER_LEN, since a binlog event can become
1040  this larger than the corresponding packet (query) sent
1041  from client to master.
1042  */
1043  thd->variables.max_allowed_packet= MAX_MAX_ALLOWED_PACKET;
1044 
1045  /*
1046  We can set log_lock now, it does not move (it's a member of
1047  mysql_bin_log, and it's already inited, and it will be destroyed
1048  only at shutdown).
1049  */
1050  p_coord->pos= pos; // the first hb matches the slave's last seen value
1051  log_lock= mysql_bin_log.get_log_lock();
1052  log_cond= mysql_bin_log.get_log_cond();
1053  if (pos > BIN_LOG_HEADER_SIZE)
1054  {
1055  /* reset transmit packet for the event read from binary log
1056  file */
1057  if (reset_transmit_packet(thd, 0/*flags*/, &ev_offset, &errmsg))
1058  GOTO_ERR;
1059 
1060  /*
1061  Try to find a Format_description_log_event at the beginning of
1062  the binlog
1063  */
1064  if (!(error = Log_event::read_log_event(&log, packet, log_lock, 0)))
1065  {
1066  DBUG_PRINT("info", ("read_log_event returned 0 on line %d", __LINE__));
1067  /*
1068  The packet has offsets equal to the normal offsets in a
1069  binlog event + ev_offset (the first ev_offset characters are
1070  the header (default \0)).
1071  */
1072  DBUG_PRINT("info",
1073  ("Looked for a Format_description_log_event, found event type %s",
1074  Log_event::get_type_str((Log_event_type)(*packet)[EVENT_TYPE_OFFSET + ev_offset])));
1075  if ((*packet)[EVENT_TYPE_OFFSET + ev_offset] == FORMAT_DESCRIPTION_EVENT)
1076  {
1077  current_checksum_alg= get_checksum_alg(packet->ptr() + ev_offset,
1078  packet->length() - ev_offset);
1079  DBUG_ASSERT(current_checksum_alg == BINLOG_CHECKSUM_ALG_OFF ||
1080  current_checksum_alg == BINLOG_CHECKSUM_ALG_UNDEF ||
1081  current_checksum_alg == BINLOG_CHECKSUM_ALG_CRC32);
1082  if (!is_slave_checksum_aware(thd) &&
1083  current_checksum_alg != BINLOG_CHECKSUM_ALG_OFF &&
1084  current_checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF)
1085  {
1086  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
1087  errmsg= "Slave can not handle replication events with the checksum "
1088  "that master is configured to log";
1089  sql_print_warning("Master is configured to log replication events "
1090  "with checksum, but will not send such events to "
1091  "slaves that cannot process them");
1092  GOTO_ERR;
1093  }
1094  (*packet)[FLAGS_OFFSET+ev_offset] &= ~LOG_EVENT_BINLOG_IN_USE_F;
1095  /*
1096  mark that this event with "log_pos=0", so the slave
1097  should not increment master's binlog position
1098  (rli->group_master_log_pos)
1099  */
1100  int4store((char*) packet->ptr()+LOG_POS_OFFSET+ev_offset, 0);
1101  /*
1102  if reconnect master sends FD event with `created' as 0
1103  to avoid destroying temp tables.
1104  */
1105  int4store((char*) packet->ptr()+LOG_EVENT_MINIMAL_HEADER_LEN+
1106  ST_CREATED_OFFSET+ev_offset, (ulong) 0);
1107 
1108  /* fix the checksum due to latest changes in header */
1109  if (current_checksum_alg != BINLOG_CHECKSUM_ALG_OFF &&
1110  current_checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF)
1111  fix_checksum(packet, ev_offset);
1112 
1113  /* send it */
1114  if (my_net_write(net, (uchar*) packet->ptr(), packet->length()))
1115  {
1116  errmsg = "Failed on my_net_write()";
1117  my_errno= ER_UNKNOWN_ERROR;
1118  GOTO_ERR;
1119  }
1120 
1121  /*
1122  No need to save this event. We are only doing simple reads
1123  (no real parsing of the events) so we don't need it. And so
1124  we don't need the artificial Format_description_log_event of
1125  3.23&4.x.
1126  */
1127  }
1128  }
1129  else
1130  {
1131  if (test_for_non_eof_log_read_errors(error, &errmsg))
1132  GOTO_ERR;
1133  /*
1134  It's EOF, nothing to do, go on reading next events, the
1135  Format_description_log_event will be found naturally if it is written.
1136  */
1137  }
1138  } /* end of if (pos > BIN_LOG_HEADER_SIZE); */
1139  else
1140  {
1141  /* The Format_description_log_event event will be found naturally. */
1142  }
1143 
1144  /* seek to the requested position, to start the requested dump */
1145  my_b_seek(&log, pos); // Seek will done on next read
1146 
1147  while (!net->error && net->vio != 0 && !thd->killed)
1148  {
1149  Log_event_type event_type= UNKNOWN_EVENT;
1150  bool goto_next_binlog= false;
1151 
1152  /* reset the transmit packet for the event read from binary log
1153  file */
1154  if (reset_transmit_packet(thd, 0/*flags*/, &ev_offset, &errmsg))
1155  GOTO_ERR;
1156  DBUG_EXECUTE_IF("semi_sync_3-way_deadlock",
1157  {
1158  const char act[]= "now wait_for signal.rotate_finished";
1159  DBUG_ASSERT(!debug_sync_set_action(current_thd,
1160  STRING_WITH_LEN(act)));
1161  };);
1162  bool is_active_binlog= false;
1163  while (!(error= Log_event::read_log_event(&log, packet, log_lock,
1164  current_checksum_alg,
1165  log_file_name,
1166  &is_active_binlog)))
1167  {
1168  DBUG_PRINT("info", ("read_log_event returned 0 on line %d", __LINE__));
1169 #ifndef DBUG_OFF
1170  if (max_binlog_dump_events && !left_events--)
1171  {
1172  net_flush(net);
1173  errmsg = "Debugging binlog dump abort";
1174  my_errno= ER_UNKNOWN_ERROR;
1175  GOTO_ERR;
1176  }
1177 #endif
1178  /*
1179  log's filename does not change while it's active
1180  */
1181  p_coord->pos= uint4korr(packet->ptr() + ev_offset + LOG_POS_OFFSET);
1182 
1183  event_type= (Log_event_type)((*packet)[LOG_EVENT_OFFSET+ev_offset]);
1184  DBUG_EXECUTE_IF("dump_thread_wait_before_send_xid",
1185  {
1186  if (event_type == XID_EVENT)
1187  {
1188  net_flush(net);
1189  const char act[]=
1190  "now "
1191  "wait_for signal.continue";
1192  DBUG_ASSERT(opt_debug_sync_timeout > 0);
1193  DBUG_ASSERT(!debug_sync_set_action(current_thd,
1194  STRING_WITH_LEN(act)));
1195  }
1196  });
1197 
1198  switch (event_type)
1199  {
1200  case FORMAT_DESCRIPTION_EVENT:
1201  skip_group= false;
1202  current_checksum_alg= get_checksum_alg(packet->ptr() + ev_offset,
1203  packet->length() - ev_offset);
1204  DBUG_ASSERT(current_checksum_alg == BINLOG_CHECKSUM_ALG_OFF ||
1205  current_checksum_alg == BINLOG_CHECKSUM_ALG_UNDEF ||
1206  current_checksum_alg == BINLOG_CHECKSUM_ALG_CRC32);
1207  if (!is_slave_checksum_aware(thd) &&
1208  current_checksum_alg != BINLOG_CHECKSUM_ALG_OFF &&
1209  current_checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF)
1210  {
1211  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
1212  errmsg= "Slave can not handle replication events with the checksum "
1213  "that master is configured to log";
1214  sql_print_warning("Master is configured to log replication events "
1215  "with checksum, but will not send such events to "
1216  "slaves that cannot process them");
1217  GOTO_ERR;
1218  }
1219  (*packet)[FLAGS_OFFSET+ev_offset] &= ~LOG_EVENT_BINLOG_IN_USE_F;
1220  /*
1221  Fixes the information on the checksum algorithm when a new
1222  format description is read. Notice that this only necessary
1223  when we need to filter out some transactions which were
1224  already processed.
1225  */
1226  p_fdle->checksum_alg= current_checksum_alg;
1227  break;
1228 
1229  case ANONYMOUS_GTID_LOG_EVENT:
1230  /* do nothing */
1231  break;
1232  case GTID_LOG_EVENT:
1233  if (gtid_mode == 0)
1234  {
1235  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
1236  errmsg= ER(ER_FOUND_GTID_EVENT_WHEN_GTID_MODE_IS_OFF);
1237  GOTO_ERR;
1238  }
1239  if (using_gtid_protocol)
1240  {
1241  /*
1242  The current implementation checks if the GTID was not processed
1243  by the slave. This means that everytime a GTID is read, one needs
1244  to check if it was already processed by the slave. If this is the
1245  case, the group is not sent. Otherwise, it must be sent.
1246 
1247  I think we can do better than that. /Alfranio.
1248  */
1249  ulonglong checksum_size=
1250  ((p_fdle->checksum_alg != BINLOG_CHECKSUM_ALG_OFF &&
1251  p_fdle->checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF) ?
1252  BINLOG_CHECKSUM_LEN + ev_offset : ev_offset);
1257  Gtid_log_event gtid_ev(packet->ptr() + ev_offset,
1258  packet->length() - checksum_size,
1259  p_fdle);
1260  skip_group= slave_gtid_executed->contains_gtid(gtid_ev.get_sidno(sid_map),
1261  gtid_ev.get_gno());
1262  searching_first_gtid= skip_group;
1263  DBUG_PRINT("info", ("Dumping GTID sidno(%d) gno(%lld) skip group(%d) "
1264  "searching gtid(%d).",
1265  gtid_ev.get_sidno(sid_map), gtid_ev.get_gno(),
1266  skip_group, searching_first_gtid));
1267  }
1268  break;
1269 
1270  case STOP_EVENT:
1271  case INCIDENT_EVENT:
1272  skip_group= searching_first_gtid;
1273  break;
1274 
1275  case PREVIOUS_GTIDS_LOG_EVENT:
1276  binlog_has_previous_gtids_log_event= true;
1277  if (gtid_mode == 0)
1278  {
1279  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
1280  errmsg= ER(ER_FOUND_GTID_EVENT_WHEN_GTID_MODE_IS_OFF);
1281  GOTO_ERR;
1282  }
1283  /* FALLTHROUGH */
1284  case ROTATE_EVENT:
1285  skip_group= false;
1286  break;
1287 
1288  default:
1289  if (!binlog_has_previous_gtids_log_event && using_gtid_protocol)
1290  /*
1291  If we come here, it means we are seeing a 'normal' DML/DDL
1292  event (e.g. query_log_event) without having seen any
1293  Previous_gtid_log_event. That means we are in an old
1294  binlog (no previous_gtids_log_event). When using the GTID
1295  protocol, that means we must skip the entire binary log
1296  and jump to the next one.
1297  */
1298  goto_next_binlog= true;
1299 
1300  break;
1301  }
1302 
1303  if (goto_next_binlog)
1304  // stop reading from this binlog
1305  break;
1306 
1307  DBUG_PRINT("info", ("EVENT_TYPE %d SEARCHING %d SKIP_GROUP %d file %s pos %lld\n",
1308  event_type, searching_first_gtid, skip_group, log_file_name,
1309  my_b_tell(&log)));
1310  pos = my_b_tell(&log);
1311  if (RUN_HOOK(binlog_transmit, before_send_event,
1312  (thd, 0/*flags*/, packet, log_file_name, pos)))
1313  {
1314  my_errno= ER_UNKNOWN_ERROR;
1315  errmsg= "run 'before_send_event' hook failed";
1316  GOTO_ERR;
1317  }
1318 
1319  /* The present event was skipped, so store the event coordinates */
1320  if (skip_group)
1321  {
1322  p_last_skip_coord->pos= p_coord->pos;
1323  strcpy(p_last_skip_coord->file_name, p_coord->file_name);
1324  }
1325 
1326  if (!skip_group && last_skip_group
1327  && event_type != FORMAT_DESCRIPTION_EVENT)
1328  {
1329  /*
1330  Dump thread is ready to send it's first transaction after
1331  one or more skipped transactions. Send a heart beat event
1332  to update slave IO thread coordinates before that happens.
1333 
1334  Notice that for a new binary log file, FORMAT_DESCRIPTION_EVENT
1335  is the first event to be sent to the slave. In this case, it is
1336  no need to send a HB event (which might have coordinates
1337  of previous binlog file).
1338  */
1339 
1340  if (send_last_skip_group_heartbeat(thd, net, packet, p_last_skip_coord,
1341  &ev_offset, current_checksum_alg,
1342  &errmsg))
1343  {
1344  GOTO_ERR;
1345  }
1346  }
1347 
1348  /* save this flag for next iteration */
1349  last_skip_group= skip_group;
1350 
1351  if (skip_group == false && my_net_write(net, (uchar*) packet->ptr(), packet->length()))
1352  {
1353  errmsg = "Failed on my_net_write()";
1354  my_errno= ER_UNKNOWN_ERROR;
1355  GOTO_ERR;
1356  }
1357 
1358 
1359  DBUG_EXECUTE_IF("dump_thread_wait_before_send_xid",
1360  {
1361  if (event_type == XID_EVENT)
1362  {
1363  net_flush(net);
1364  }
1365  });
1366 
1367  DBUG_PRINT("info", ("log event code %d", event_type));
1368  if (skip_group == false && event_type == LOAD_EVENT)
1369  {
1370  if (send_file(thd))
1371  {
1372  errmsg = "failed in send_file()";
1373  my_errno= ER_UNKNOWN_ERROR;
1374  GOTO_ERR;
1375  }
1376  }
1377 
1378  if (RUN_HOOK(binlog_transmit, after_send_event, (thd, 0/*flags*/, packet,
1379  log_file_name, skip_group ? pos : 0)))
1380  {
1381  errmsg= "Failed to run hook 'after_send_event'";
1382  my_errno= ER_UNKNOWN_ERROR;
1383  GOTO_ERR;
1384  }
1385 
1386  /* reset transmit packet for next loop */
1387  if (reset_transmit_packet(thd, 0/*flags*/, &ev_offset, &errmsg))
1388  GOTO_ERR;
1389  }
1390 
1391  DBUG_EXECUTE_IF("wait_after_binlog_EOF",
1392  {
1393  const char act[]= "now wait_for signal.rotate_finished";
1394  DBUG_ASSERT(!debug_sync_set_action(current_thd,
1395  STRING_WITH_LEN(act)));
1396  };);
1397 
1398  /*
1399  TODO: now that we are logging the offset, check to make sure
1400  the recorded offset and the actual match.
1401  Guilhem 2003-06: this is not true if this master is a slave
1402  <4.0.15 running with --log-slave-updates, because then log_pos may
1403  be the offset in the-master-of-this-master's binlog.
1404  */
1405  if (test_for_non_eof_log_read_errors(error, &errmsg))
1406  GOTO_ERR;
1407 
1408  if (!is_active_binlog)
1409  goto_next_binlog= true;
1410 
1411  if (!goto_next_binlog)
1412  {
1413  /*
1414  Block until there is more data in the log
1415  */
1416  if (net_flush(net))
1417  {
1418  errmsg = "failed on net_flush()";
1419  my_errno= ER_UNKNOWN_ERROR;
1420  GOTO_ERR;
1421  }
1422 
1423  /*
1424  We may have missed the update broadcast from the log
1425  that has just happened, let's try to catch it if it did.
1426  If we did not miss anything, we just wait for other threads
1427  to signal us.
1428  */
1429  {
1430  log.error=0;
1431  bool read_packet = 0;
1432 
1433 #ifndef DBUG_OFF
1434  if (max_binlog_dump_events && !left_events--)
1435  {
1436  errmsg = "Debugging binlog dump abort";
1437  my_errno= ER_UNKNOWN_ERROR;
1438  GOTO_ERR;
1439  }
1440 #endif
1441 
1442  /* reset the transmit packet for the event read from binary log
1443  file */
1444  if (reset_transmit_packet(thd, 0/*flags*/, &ev_offset, &errmsg))
1445  GOTO_ERR;
1446 
1447  /*
1448  No one will update the log while we are reading
1449  now, but we'll be quick and just read one record
1450 
1451  TODO:
1452  Add an counter that is incremented for each time we update the
1453  binary log. We can avoid the following read if the counter
1454  has not been updated since last read.
1455  */
1456 
1457  mysql_mutex_lock(log_lock);
1458  switch (error= Log_event::read_log_event(&log, packet, (mysql_mutex_t*) 0,
1459  current_checksum_alg)) {
1460  case 0:
1461  DBUG_PRINT("info", ("read_log_event returned 0 on line %d",
1462  __LINE__));
1463  /* we read successfully, so we'll need to send it to the slave */
1464  mysql_mutex_unlock(log_lock);
1465  read_packet = 1;
1466  p_coord->pos= uint4korr(packet->ptr() + ev_offset + LOG_POS_OFFSET);
1467  event_type= (Log_event_type)((*packet)[LOG_EVENT_OFFSET+ev_offset]);
1468  DBUG_ASSERT(event_type != FORMAT_DESCRIPTION_EVENT);
1469  break;
1470 
1471  case LOG_READ_EOF:
1472  {
1473  int ret;
1474  ulong signal_cnt;
1475  DBUG_PRINT("wait",("waiting for data in binary log"));
1476  if (thd->server_id==0) // for mysqlbinlog (mysqlbinlog.server_id==0)
1477  {
1478  mysql_mutex_unlock(log_lock);
1479  DBUG_EXECUTE_IF("inject_hb_event_on_mysqlbinlog_dump_thread",
1480  {
1481  /*
1482  Send one HB event (with anything in it, content is irrelevant).
1483  We just want to check that mysqlbinlog will be able to ignore it.
1484 
1485  Suicide on failure, since if it happens the entire purpose of the
1486  test is comprimised.
1487  */
1488  if (reset_transmit_packet(thd, 0/*flags*/, &ev_offset, &errmsg) ||
1489  send_heartbeat_event(net, packet, p_coord, current_checksum_alg))
1490  DBUG_SUICIDE();
1491  });
1492  goto end;
1493  }
1494 
1495 #ifndef DBUG_OFF
1496  ulong hb_info_counter= 0;
1497 #endif
1498  PSI_stage_info old_stage;
1499  signal_cnt= mysql_bin_log.signal_cnt;
1500 
1501  do
1502  {
1503  if (heartbeat_period != 0)
1504  {
1505  DBUG_ASSERT(heartbeat_ts);
1506  set_timespec_nsec(*heartbeat_ts, heartbeat_period);
1507  }
1508  thd->ENTER_COND(log_cond, log_lock,
1509  &stage_master_has_sent_all_binlog_to_slave,
1510  &old_stage);
1511  /*
1512  When using GTIDs, if the dump thread has reached the end of the
1513  binary log and the last transaction is skipped,
1514  send one heartbeat event even when the heartbeat is off.
1515  If the heartbeat is on, it is better to send a heartbeat
1516  event as the time_out of certain functions (Ex: master_pos_wait()
1517  or semi sync ack timeout) might be less than heartbeat period.
1518  */
1519  if (skip_group)
1520  {
1521  if (send_last_skip_group_heartbeat(thd, net, packet,
1522  p_coord, &ev_offset,
1523  current_checksum_alg, &errmsg))
1524  {
1525  thd->EXIT_COND(&old_stage);
1526  GOTO_ERR;
1527  }
1528  last_skip_group= false; /*A HB for this pos has been sent. */
1529  }
1530 
1531  ret= mysql_bin_log.wait_for_update_bin_log(thd, heartbeat_ts);
1532  DBUG_ASSERT(ret == 0 || (heartbeat_period != 0));
1533  if (ret == ETIMEDOUT || ret == ETIME)
1534  {
1535 #ifndef DBUG_OFF
1536  if (hb_info_counter < 3)
1537  {
1538  sql_print_information("master sends heartbeat message");
1539  hb_info_counter++;
1540  if (hb_info_counter == 3)
1541  sql_print_information("the rest of heartbeat info skipped ...");
1542  }
1543 #endif
1544  /* reset transmit packet for the heartbeat event */
1545  if (reset_transmit_packet(thd, 0/*flags*/, &ev_offset, &errmsg))
1546  {
1547  thd->EXIT_COND(&old_stage);
1548  GOTO_ERR;
1549  }
1550  if (send_heartbeat_event(net, packet, p_coord, current_checksum_alg))
1551  {
1552  errmsg = "Failed on my_net_write()";
1553  my_errno= ER_UNKNOWN_ERROR;
1554  thd->EXIT_COND(&old_stage);
1555  GOTO_ERR;
1556  }
1557  }
1558  else
1559  {
1560  DBUG_PRINT("wait",("binary log received update or a broadcast signal caught"));
1561  }
1562  } while (signal_cnt == mysql_bin_log.signal_cnt && !thd->killed);
1563  thd->EXIT_COND(&old_stage);
1564  }
1565  break;
1566 
1567  default:
1568  mysql_mutex_unlock(log_lock);
1569  test_for_non_eof_log_read_errors(error, &errmsg);
1570  GOTO_ERR;
1571  }
1572 
1573  if (read_packet)
1574  {
1575  switch (event_type)
1576  {
1577  case ANONYMOUS_GTID_LOG_EVENT:
1578  /* do nothing */
1579  break;
1580  case GTID_LOG_EVENT:
1581  if (gtid_mode == 0)
1582  {
1583  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
1584  errmsg= ER(ER_FOUND_GTID_EVENT_WHEN_GTID_MODE_IS_OFF);
1585  GOTO_ERR;
1586  }
1587  if (using_gtid_protocol)
1588  {
1589  ulonglong checksum_size=
1590  ((p_fdle->checksum_alg != BINLOG_CHECKSUM_ALG_OFF &&
1591  p_fdle->checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF) ?
1592  BINLOG_CHECKSUM_LEN + ev_offset : ev_offset);
1593  Gtid_log_event gtid_ev(packet->ptr() + ev_offset,
1594  packet->length() - checksum_size,
1595  p_fdle);
1596  skip_group=
1597  slave_gtid_executed->contains_gtid(gtid_ev.get_sidno(sid_map),
1598  gtid_ev.get_gno());
1599  searching_first_gtid= skip_group;
1600  DBUG_PRINT("info", ("Dumping GTID sidno(%d) gno(%lld) "
1601  "skip group(%d) searching gtid(%d).",
1602  gtid_ev.get_sidno(sid_map), gtid_ev.get_gno(),
1603  skip_group, searching_first_gtid));
1604  }
1605  break;
1606 
1607  case STOP_EVENT:
1608  case INCIDENT_EVENT:
1609  skip_group= searching_first_gtid;
1610  break;
1611 
1612  case PREVIOUS_GTIDS_LOG_EVENT:
1613  binlog_has_previous_gtids_log_event= true;
1614  if (gtid_mode == 0)
1615  {
1616  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
1617  errmsg= ER(ER_FOUND_GTID_EVENT_WHEN_GTID_MODE_IS_OFF);
1618  GOTO_ERR;
1619  }
1620  /* FALLTHROUGH */
1621  case ROTATE_EVENT:
1622  skip_group= false;
1623  break;
1624  default:
1625  if (!binlog_has_previous_gtids_log_event && using_gtid_protocol)
1626  /*
1627  If we come here, it means we are seeing a 'normal' DML/DDL
1628  event (e.g. query_log_event) without having seen any
1629  Previous_gtid_log_event. That means we are in an old
1630  binlog (no previous_gtids_log_event). When using the GTID
1631  protocol, that means we must skip the entire binary log
1632  and jump to the next one.
1633  */
1634  goto_next_binlog= true;
1635 
1636  break;
1637  }
1638 
1639  /* The present event was skipped in a GTID protocol, store the coordinates */
1640  if (skip_group)
1641  {
1642  p_last_skip_coord->pos= p_coord->pos;
1643  strcpy(p_last_skip_coord->file_name, p_coord->file_name);
1644  }
1645 
1646  if (!skip_group && !goto_next_binlog)
1647  {
1648  /* If the last group was skipped, send a HB event */
1649  if (last_skip_group &&
1650  send_last_skip_group_heartbeat(thd, net, packet,
1651  p_last_skip_coord, &ev_offset,
1652  current_checksum_alg, &errmsg))
1653  {
1654  GOTO_ERR;
1655  }
1656 
1657  THD_STAGE_INFO(thd, stage_sending_binlog_event_to_slave);
1658  pos = my_b_tell(&log);
1659  if (RUN_HOOK(binlog_transmit, before_send_event,
1660  (thd, 0/*flags*/, packet, log_file_name, pos)))
1661  {
1662  my_errno= ER_UNKNOWN_ERROR;
1663  errmsg= "run 'before_send_event' hook failed";
1664  GOTO_ERR;
1665  }
1666 
1667  if (my_net_write(net, (uchar*) packet->ptr(), packet->length()) )
1668  {
1669  errmsg = "Failed on my_net_write()";
1670  my_errno= ER_UNKNOWN_ERROR;
1671  GOTO_ERR;
1672  }
1673 
1674  if (event_type == LOAD_EVENT)
1675  {
1676  if (send_file(thd))
1677  {
1678  errmsg = "failed in send_file()";
1679  my_errno= ER_UNKNOWN_ERROR;
1680  GOTO_ERR;
1681  }
1682  }
1683  }
1684 
1685  if(!goto_next_binlog)
1686  {
1687  if (RUN_HOOK(binlog_transmit, after_send_event, (thd, 0/*flags*/, packet,
1688  log_file_name, skip_group ? pos : 0)))
1689  {
1690  my_errno= ER_UNKNOWN_ERROR;
1691  errmsg= "Failed to run hook 'after_send_event'";
1692  GOTO_ERR;
1693  }
1694  }
1695 
1696  /* Save the skip group for next iteration */
1697  last_skip_group= skip_group;
1698 
1699  }
1700 
1701  log.error=0;
1702  }
1703  }
1704 
1705  if (goto_next_binlog)
1706  {
1707  // clear flag because we open a new binlog
1708  binlog_has_previous_gtids_log_event= false;
1709 
1710  THD_STAGE_INFO(thd, stage_finished_reading_one_binlog_switching_to_next_binlog);
1711  switch (mysql_bin_log.find_next_log(&linfo, 1)) {
1712  case 0:
1713  break;
1714  default:
1715  errmsg = "could not find next log";
1716  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
1717  GOTO_ERR;
1718  }
1719 
1720  end_io_cache(&log);
1721  mysql_file_close(file, MYF(MY_WME));
1722 
1723  /* reset transmit packet for the possible fake rotate event */
1724  if (reset_transmit_packet(thd, 0/*flags*/, &ev_offset, &errmsg))
1725  GOTO_ERR;
1726 
1727  /*
1728  Call fake_rotate_event() in case the previous log (the one which
1729  we have just finished reading) did not contain a Rotate event.
1730  There are at least two cases when this can happen:
1731 
1732  - The previous binary log was the last one before the master was
1733  shutdown and restarted.
1734 
1735  - The previous binary log was GTID-free (did not contain a
1736  Previous_gtids_log_event) and the slave is connecting using
1737  the GTID protocol.
1738 
1739  This way we tell the slave about the new log's name and
1740  position. If the binlog is 5.0 or later, the next event we
1741  are going to read and send is Format_description_log_event.
1742  */
1743  if ((file=open_binlog_file(&log, log_file_name, &errmsg)) < 0 ||
1744  fake_rotate_event(net, packet, log_file_name, BIN_LOG_HEADER_SIZE,
1745  &errmsg, current_checksum_alg))
1746  {
1747  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
1748  GOTO_ERR;
1749  }
1750 
1751  p_coord->file_name= log_file_name; // reset to the next
1752  }
1753  }
1754 
1755 end:
1756  thd->set_stmt_da(saved_da);
1757  end_io_cache(&log);
1758  mysql_file_close(file, MYF(MY_WME));
1759 
1760  (void) RUN_HOOK(binlog_transmit, transmit_stop, (thd, 0/*flags*/));
1761  my_eof(thd);
1762  THD_STAGE_INFO(thd, stage_waiting_to_finalize_termination);
1763  mysql_mutex_lock(&LOCK_thread_count);
1764  thd->current_linfo = 0;
1765  mysql_mutex_unlock(&LOCK_thread_count);
1766  thd->variables.max_allowed_packet= old_max_allowed_packet;
1767  DBUG_VOID_RETURN;
1768 
1769 err:
1770  THD_STAGE_INFO(thd, stage_waiting_to_finalize_termination);
1771  if (my_errno == ER_MASTER_FATAL_ERROR_READING_BINLOG && my_b_inited(&log))
1772  {
1773  /*
1774  detailing the fatal error message with coordinates
1775  of the last position read.
1776  */
1777  my_snprintf(error_text, sizeof(error_text),
1778  "%s; the first event '%s' at %lld, "
1779  "the last event read from '%s' at %lld, "
1780  "the last byte read from '%s' at %lld.",
1781  errmsg,
1782  p_start_coord->file_name, p_start_coord->pos,
1783  p_coord->file_name, p_coord->pos,
1784  log_file_name, my_b_tell(&log));
1785  }
1786  else
1787  {
1788  strncpy(error_text, errmsg, sizeof(error_text));
1789  error_text[sizeof(error_text) - 1]= '\0';
1790  }
1791  end_io_cache(&log);
1792  (void) RUN_HOOK(binlog_transmit, transmit_stop, (thd, 0/*flags*/));
1793  /*
1794  Exclude iteration through thread list
1795  this is needed for purge_logs() - it will iterate through
1796  thread list and update thd->current_linfo->index_file_offset
1797  this mutex will make sure that it never tried to update our linfo
1798  after we return from this stack frame
1799  */
1800  mysql_mutex_lock(&LOCK_thread_count);
1801  thd->current_linfo = 0;
1802  mysql_mutex_unlock(&LOCK_thread_count);
1803  if (file >= 0)
1804  mysql_file_close(file, MYF(MY_WME));
1805  thd->variables.max_allowed_packet= old_max_allowed_packet;
1806 
1807  thd->set_stmt_da(saved_da);
1808  my_message(my_errno, error_text, MYF(0));
1809  DBUG_VOID_RETURN;
1810 }
1811 
1812 
1821 String *get_slave_uuid(THD *thd, String *value)
1822 {
1823  uchar name[]= "slave_uuid";
1824 
1825  if (value == NULL)
1826  return NULL;
1827  user_var_entry *entry=
1828  (user_var_entry*) my_hash_search(&thd->user_vars, name, sizeof(name)-1);
1829  if (entry && entry->length() > 0)
1830  {
1831  value->copy(entry->ptr(), entry->length(), NULL);
1832  return value;
1833  }
1834  else
1835  return NULL;
1836 }
1837 
1838 /*
1839 
1840  Kill all Binlog_dump threads which previously talked to the same slave
1841  ("same" means with the same server id). Indeed, if the slave stops, if the
1842  Binlog_dump thread is waiting (mysql_cond_wait) for binlog update, then it
1843  will keep existing until a query is written to the binlog. If the master is
1844  idle, then this could last long, and if the slave reconnects, we could have 2
1845  Binlog_dump threads in SHOW PROCESSLIST, until a query is written to the
1846  binlog. To avoid this, when the slave reconnects and sends COM_BINLOG_DUMP,
1847  the master kills any existing thread with the slave's server id (if this id is
1848  not zero; it will be true for real slaves, but false for mysqlbinlog when it
1849  sends COM_BINLOG_DUMP to get a remote binlog dump).
1850 
1851  SYNOPSIS
1852  kill_zombie_dump_threads()
1853  slave_uuid the slave's UUID
1854 
1855 */
1856 
1857 
1858 void kill_zombie_dump_threads(String *slave_uuid)
1859 {
1860  if (slave_uuid->length() == 0)
1861  return;
1862  DBUG_ASSERT(slave_uuid->length() == UUID_LENGTH);
1863 
1864  mysql_mutex_lock(&LOCK_thread_count);
1865  THD *tmp= NULL;
1866  Thread_iterator it= global_thread_list_begin();
1867  Thread_iterator end= global_thread_list_end();
1868  for (; it != end; ++it)
1869  {
1870  if ((*it) != current_thd && ((*it)->get_command() == COM_BINLOG_DUMP ||
1871  (*it)->get_command() == COM_BINLOG_DUMP_GTID))
1872  {
1873  String tmp_uuid;
1874  if (get_slave_uuid((*it), &tmp_uuid) != NULL &&
1875  !strncmp(slave_uuid->c_ptr(), tmp_uuid.c_ptr(), UUID_LENGTH))
1876  {
1877  tmp= *it;
1878  mysql_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete
1879  break;
1880  }
1881  }
1882  }
1883  mysql_mutex_unlock(&LOCK_thread_count);
1884  if (tmp)
1885  {
1886  /*
1887  Here we do not call kill_one_thread() as
1888  it will be slow because it will iterate through the list
1889  again. We just to do kill the thread ourselves.
1890  */
1891  tmp->awake(THD::KILL_QUERY);
1892  mysql_mutex_unlock(&tmp->LOCK_thd_data);
1893  }
1894 }
1895 
1896 
1906 int reset_master(THD* thd)
1907 {
1908  if (!mysql_bin_log.is_open())
1909  {
1910  my_message(ER_FLUSH_MASTER_BINLOG_CLOSED,
1911  ER(ER_FLUSH_MASTER_BINLOG_CLOSED), MYF(ME_BELL+ME_WAITTANG));
1912  return 1;
1913  }
1914 
1915  if (mysql_bin_log.reset_logs(thd))
1916  return 1;
1917  (void) RUN_HOOK(binlog_transmit, after_reset_master, (thd, 0 /* flags */));
1918  return 0;
1919 }
1920 
1921 
1931 bool show_master_status(THD* thd)
1932 {
1933  Protocol *protocol= thd->protocol;
1934  char* gtid_set_buffer= NULL;
1935  int gtid_set_size= 0;
1936  List<Item> field_list;
1937 
1938  DBUG_ENTER("show_binlog_info");
1939 
1940  global_sid_lock->wrlock();
1941  const Gtid_set* gtid_set= gtid_state->get_logged_gtids();
1942  if ((gtid_set_size= gtid_set->to_string(&gtid_set_buffer)) < 0)
1943  {
1944  global_sid_lock->unlock();
1945  my_eof(thd);
1946  my_free(gtid_set_buffer);
1947  DBUG_RETURN(true);
1948  }
1949  global_sid_lock->unlock();
1950 
1951  field_list.push_back(new Item_empty_string("File", FN_REFLEN));
1952  field_list.push_back(new Item_return_int("Position",20,
1953  MYSQL_TYPE_LONGLONG));
1954  field_list.push_back(new Item_empty_string("Binlog_Do_DB",255));
1955  field_list.push_back(new Item_empty_string("Binlog_Ignore_DB",255));
1956  field_list.push_back(new Item_empty_string("Executed_Gtid_Set",
1957  gtid_set_size));
1958 
1959  if (protocol->send_result_set_metadata(&field_list,
1960  Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
1961  {
1962  my_free(gtid_set_buffer);
1963  DBUG_RETURN(true);
1964  }
1965  protocol->prepare_for_resend();
1966 
1967  if (mysql_bin_log.is_open())
1968  {
1969  LOG_INFO li;
1970  mysql_bin_log.get_current_log(&li);
1971  int dir_len = dirname_length(li.log_file_name);
1972  protocol->store(li.log_file_name + dir_len, &my_charset_bin);
1973  protocol->store((ulonglong) li.pos);
1974  protocol->store(binlog_filter->get_do_db());
1975  protocol->store(binlog_filter->get_ignore_db());
1976  protocol->store(gtid_set_buffer, &my_charset_bin);
1977  if (protocol->write())
1978  {
1979  my_free(gtid_set_buffer);
1980  DBUG_RETURN(true);
1981  }
1982  }
1983  my_eof(thd);
1984  my_free(gtid_set_buffer);
1985  DBUG_RETURN(false);
1986 }
1987 
1988 
1998 bool show_binlogs(THD* thd)
1999 {
2000  IO_CACHE *index_file;
2001  LOG_INFO cur;
2002  File file;
2003  char fname[FN_REFLEN];
2004  List<Item> field_list;
2005  uint length;
2006  int cur_dir_len;
2007  Protocol *protocol= thd->protocol;
2008  DBUG_ENTER("show_binlogs");
2009 
2010  if (!mysql_bin_log.is_open())
2011  {
2012  my_error(ER_NO_BINARY_LOGGING, MYF(0));
2013  DBUG_RETURN(TRUE);
2014  }
2015 
2016  field_list.push_back(new Item_empty_string("Log_name", 255));
2017  field_list.push_back(new Item_return_int("File_size", 20,
2018  MYSQL_TYPE_LONGLONG));
2019  if (protocol->send_result_set_metadata(&field_list,
2020  Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
2021  DBUG_RETURN(TRUE);
2022 
2023  mysql_mutex_lock(mysql_bin_log.get_log_lock());
2024  mysql_bin_log.lock_index();
2025  index_file=mysql_bin_log.get_index_file();
2026 
2027  mysql_bin_log.raw_get_current_log(&cur); // dont take mutex
2028  mysql_mutex_unlock(mysql_bin_log.get_log_lock()); // lockdep, OK
2029 
2030  cur_dir_len= dirname_length(cur.log_file_name);
2031 
2032  reinit_io_cache(index_file, READ_CACHE, (my_off_t) 0, 0, 0);
2033 
2034  /* The file ends with EOF or empty line */
2035  while ((length=my_b_gets(index_file, fname, sizeof(fname))) > 1)
2036  {
2037  int dir_len;
2038  ulonglong file_length= 0; // Length if open fails
2039  fname[--length] = '\0'; // remove the newline
2040 
2041  protocol->prepare_for_resend();
2042  dir_len= dirname_length(fname);
2043  length-= dir_len;
2044  protocol->store(fname + dir_len, length, &my_charset_bin);
2045 
2046  if (!(strncmp(fname+dir_len, cur.log_file_name+cur_dir_len, length)))
2047  file_length= cur.pos; /* The active log, use the active position */
2048  else
2049  {
2050  /* this is an old log, open it and find the size */
2051  if ((file= mysql_file_open(key_file_binlog,
2052  fname, O_RDONLY | O_SHARE | O_BINARY,
2053  MYF(0))) >= 0)
2054  {
2055  file_length= (ulonglong) mysql_file_seek(file, 0L, MY_SEEK_END, MYF(0));
2056  mysql_file_close(file, MYF(0));
2057  }
2058  }
2059  protocol->store(file_length);
2060  if (protocol->write())
2061  {
2062  DBUG_PRINT("info", ("stopping dump thread because protocol->write failed at line %d", __LINE__));
2063  goto err;
2064  }
2065  }
2066  if(index_file->error == -1)
2067  goto err;
2068  mysql_bin_log.unlock_index();
2069  my_eof(thd);
2070  DBUG_RETURN(FALSE);
2071 
2072 err:
2073  mysql_bin_log.unlock_index();
2074  DBUG_RETURN(TRUE);
2075 }
2076 
2077 #endif /* HAVE_REPLICATION */