repl_failsafe.cc 19.1 KB
Newer Older
Marc Alff's avatar
Marc Alff committed
1
/* Copyright (C) 2001-2006 MySQL AB & Sasha, 2008-2009 Sun Microsystems, Inc
2 3 4

   This program is free software; you can redistribute it and/or modify
   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 8 9 10 11 12 13 14 15

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

16 17 18 19 20 21 22 23 24 25
/**
  @file

  All of the functions defined in this file which are not used (the ones to
  handle failsafe) are not used; their code has not been updated for more
  than one year now so should be considered as BADLY BROKEN. Do not enable
  it. The used functions (to handle LOAD DATA FROM MASTER, plus some small
  functions like register_slave()) are working.
*/

26
#include "mysql_priv.h"
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
27 28
#ifdef HAVE_REPLICATION

29
#include "repl_failsafe.h"
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
30 31
#include "sql_repl.h"
#include "slave.h"
32
#include "rpl_mi.h"
lars@mysql.com's avatar
lars@mysql.com committed
33
#include "rpl_filter.h"
34
#include "log_event.h"
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
35
#include <mysql.h>
36 37 38 39

#define SLAVE_LIST_CHUNK 128
#define SLAVE_ERRMSG_SIZE (FN_REFLEN+64)

40

41
uint rpl_status=RPL_NULL;
Marc Alff's avatar
Marc Alff committed
42 43
mysql_mutex_t LOCK_rpl_status;
mysql_cond_t COND_rpl_status;
44
HASH slave_list;
45

46 47
const char *rpl_role_type[] = {"MASTER","SLAVE",NullS};
TYPELIB rpl_role_typelib = {array_elements(rpl_role_type)-1,"",
48
			    rpl_role_type, NULL};
49

50 51
const char* rpl_status_type[]=
{
52
  "AUTH_MASTER","IDLE_SLAVE","ACTIVE_SLAVE","LOST_SOLDIER","TROOP_SOLDIER",
53 54
  "RECOVERY_CAPTAIN","NULL",NullS
};
55
TYPELIB rpl_status_typelib= {array_elements(rpl_status_type)-1,"",
56
			     rpl_status_type, NULL};
57

58

59 60 61 62
static Slave_log_event* find_slave_event(IO_CACHE* log,
					 const char* log_file_name,
					 char* errmsg);

63 64 65 66 67 68 69
/*
  All of the functions defined in this file which are not used (the ones to
  handle failsafe) are not used; their code has not been updated for more than
  one year now so should be considered as BADLY BROKEN. Do not enable it.
  The used functions (to handle LOAD DATA FROM MASTER, plus some small
  functions like register_slave()) are working.
*/
70

71
#if NOT_USED
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
72 73 74
static int init_failsafe_rpl_thread(THD* thd)
{
  DBUG_ENTER("init_failsafe_rpl_thread");
75
  thd->system_thread = SYSTEM_THREAD_DELAYED_INSERT;
76 77 78 79 80
  /*
    thd->bootstrap is to report errors barely to stderr; if this code is
    enable again one day, one should check if bootstrap is still needed (maybe
    this thread has no other error reporting method).
  */
81
  thd->bootstrap = 1;
82
  thd->security_ctx->skip_grants();
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
83
  my_net_init(&thd->net, 0);
84 85
  thd->net.read_timeout = slave_net_timeout;
  thd->max_client_packet_length=thd->net.max_packet;
Marc Alff's avatar
Marc Alff committed
86
  mysql_mutex_lock(&LOCK_thread_count);
87
  thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
Marc Alff's avatar
Marc Alff committed
88
  mysql_mutex_unlock(&LOCK_thread_count);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
89

90
  if (init_thr_lock() || thd->store_globals())
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
91
  {
92
    /* purecov: begin inspected */
93
    close_connection(thd, ER_OUT_OF_RESOURCES, 1); // is this needed?
94
    statistic_increment(aborted_connects,&LOCK_status);
95
    one_thread_per_connection_end(thd,0);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
96
    DBUG_RETURN(-1);
97
    /* purecov: end */
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
98 99
  }

100
  thd->mem_root->free= thd->mem_root->used= 0;
101
  thd_proc_info(thd, "Thread initialized");
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
102 103 104 105
  thd->version=refresh_version;
  thd->set_time();
  DBUG_RETURN(0);
}
106
#endif
107

108 109
void change_rpl_status(RPL_STATUS from_status, RPL_STATUS to_status)
{
Marc Alff's avatar
Marc Alff committed
110
  mysql_mutex_lock(&LOCK_rpl_status);
111 112
  if (rpl_status == from_status || rpl_status == RPL_ANY)
    rpl_status = to_status;
Marc Alff's avatar
Marc Alff committed
113 114
  mysql_cond_signal(&COND_rpl_status);
  mysql_mutex_unlock(&LOCK_rpl_status);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
115 116
}

117

118
#define get_object(p, obj, msg) \
119 120 121
{\
  uint len = (uint)*p++;  \
  if (p + len > p_end || len >= sizeof(obj)) \
122 123
  {\
    errmsg= msg;\
124
    goto err; \
125
  }\
126 127 128 129
  strmake(obj,(char*) p,len); \
  p+= len; \
}\

130

131 132 133 134 135 136
static inline int cmp_master_pos(Slave_log_event* sev, LEX_MASTER_INFO* mi)
{
  return cmp_master_pos(sev->master_log, sev->master_pos, mi->log_file_name,
			mi->pos);
}

137

138 139 140 141
void unregister_slave(THD* thd, bool only_mine, bool need_mutex)
{
  if (thd->server_id)
  {
142
    if (need_mutex)
Marc Alff's avatar
Marc Alff committed
143
      mysql_mutex_lock(&LOCK_slave_list);
144

145
    SLAVE_INFO* old_si;
Konstantin Osipov's avatar
Konstantin Osipov committed
146 147
    if ((old_si = (SLAVE_INFO*)my_hash_search(&slave_list,
                                              (uchar*)&thd->server_id, 4)) &&
148
	(!only_mine || old_si->thd == thd))
Konstantin Osipov's avatar
Konstantin Osipov committed
149
    my_hash_delete(&slave_list, (uchar*)old_si);
150 151

    if (need_mutex)
Marc Alff's avatar
Marc Alff committed
152
      mysql_mutex_unlock(&LOCK_slave_list);
153 154 155
  }
}

156

157 158
/**
  Register slave in 'slave_list' hash table.
159

160 161 162 163
  @return
    0	ok
  @return
    1	Error.   Error message sent to client
164 165
*/

166 167
int register_slave(THD* thd, uchar* packet, uint packet_length)
{
168
  int res;
169
  SLAVE_INFO *si;
170
  uchar *p= packet, *p_end= packet + packet_length;
171
  const char *errmsg= "Wrong parameters to function register_slave";
172

Marc Alff's avatar
Marc Alff committed
173
  if (check_access(thd, REPL_SLAVE_ACL, any_db, NULL, NULL, 0, 0))
174 175
    return 1;
  if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME))))
176
    goto err2;
177

178 179
  thd->server_id= si->server_id= uint4korr(p);
  p+= 4;
180 181 182
  get_object(p,si->host, "Failed to register slave: too long 'report-host'");
  get_object(p,si->user, "Failed to register slave: too long 'report-user'");
  get_object(p,si->password, "Failed to register slave; too long 'report-password'");
183
  if (p+10 > p_end)
184 185
    goto err;
  si->port= uint2korr(p);
186
  p += 2;
187 188 189 190 191 192 193 194
  /* 
     We need to by pass the bytes used in the fake rpl_recovery_rank
     variable. It was removed in patch for BUG#13963. But this would 
     make a server with that patch unable to connect to an old master.
     See: BUG#49259
  */
  // si->rpl_recovery_rank= uint4korr(p);
  p += 4;
195 196 197
  if (!(si->master_id= uint4korr(p)))
    si->master_id= server_id;
  si->thd= thd;
198

Marc Alff's avatar
Marc Alff committed
199
  mysql_mutex_lock(&LOCK_slave_list);
200
  unregister_slave(thd,0,0);
201
  res= my_hash_insert(&slave_list, (uchar*) si);
Marc Alff's avatar
Marc Alff committed
202
  mysql_mutex_unlock(&LOCK_slave_list);
203 204 205
  return res;

err:
206
  my_free(si, MYF(MY_WME));
207
  my_message(ER_UNKNOWN_ERROR, errmsg, MYF(0)); /* purecov: inspected */
208 209
err2:
  return 1;
210 211
}

212
extern "C" uint32
213
*slave_list_key(SLAVE_INFO* si, size_t *len,
214
		my_bool not_used __attribute__((unused)))
215 216 217 218 219
{
  *len = 4;
  return &si->server_id;
}

220
extern "C" void slave_info_free(void *s)
221
{
222
  my_free(s, MYF(MY_WME));
223 224
}

Marc Alff's avatar
Marc Alff committed
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
#ifdef HAVE_PSI_INTERFACE
static PSI_mutex_key key_LOCK_slave_list;

static PSI_mutex_info all_slave_list_mutexes[]=
{
  { &key_LOCK_slave_list, "LOCK_slave_list", PSI_FLAG_GLOBAL}
};

static void init_all_slave_list_mutexes(void)
{
  const char* category= "sql";
  int count;

  if (PSI_server == NULL)
    return;

  count= array_elements(all_slave_list_mutexes);
  PSI_server->register_mutex(category, all_slave_list_mutexes, count);
}
#endif /* HAVE_PSI_INTERFACE */

246 247
void init_slave_list()
{
Marc Alff's avatar
Marc Alff committed
248 249 250 251
#ifdef HAVE_PSI_INTERFACE
  init_all_slave_list_mutexes();
#endif

Konstantin Osipov's avatar
Konstantin Osipov committed
252 253 254
  my_hash_init(&slave_list, system_charset_info, SLAVE_LIST_CHUNK, 0, 0,
               (my_hash_get_key) slave_list_key,
               (my_hash_free_key) slave_info_free, 0);
Marc Alff's avatar
Marc Alff committed
255
  mysql_mutex_init(key_LOCK_slave_list, &LOCK_slave_list, MY_MUTEX_INIT_FAST);
256 257 258 259
}

void end_slave_list()
{
260
  /* No protection by a mutex needed as we are only called at shutdown */
Konstantin Osipov's avatar
Konstantin Osipov committed
261
  if (my_hash_inited(&slave_list))
262
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
263
    my_hash_free(&slave_list);
Marc Alff's avatar
Marc Alff committed
264
    mysql_mutex_destroy(&LOCK_slave_list);
265
  }
266 267
}

268
static int find_target_pos(LEX_MASTER_INFO *mi, IO_CACHE *log, char *errmsg)
269
{
270
  my_off_t log_pos =	    (my_off_t) mi->pos;
271 272 273 274 275
  uint32 target_server_id = mi->server_id;

  for (;;)
  {
    Log_event* ev;
Marc Alff's avatar
Marc Alff committed
276
    if (!(ev= Log_event::read_log_event(log, (mysql_mutex_t*) 0, 0)))
277 278 279 280 281 282 283 284 285 286
    {
      if (log->error > 0)
	strmov(errmsg, "Binary log truncated in the middle of event");
      else if (log->error < 0)
	strmov(errmsg, "I/O error reading binary log");
      else
	strmov(errmsg, "Could not find target event in the binary log");
      return 1;
    }

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
287
    if (ev->log_pos >= log_pos && ev->server_id == target_server_id)
288 289 290 291 292 293 294
    {
      delete ev;
      mi->pos = my_b_tell(log);
      return 0;
    }
    delete ev;
  }
295
  /* Impossible */
296 297
}

298 299
/**
  @details 
300 301 302 303 304
  Before 4.0.15 we had a member of THD called log_pos, it was meant for
  failsafe replication code in repl_failsafe.cc which is disabled until
  it is reworked. Event's log_pos used to be preserved through 
  log-slave-updates to make code in repl_failsafe.cc work (this 
  function, SHOW NEW MASTER); but on the other side it caused unexpected
305
  values in Exec_Master_Log_Pos in A->B->C replication setup, 
306 307 308 309 310
  synchronization problems in master_pos_wait(), ... So we 
  (Dmitri & Guilhem) removed it.
  
  So for now this function is broken. 
*/
311 312 313 314

int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg)
{
  LOG_INFO linfo;
315
  char last_log_name[FN_REFLEN];
316 317
  IO_CACHE log;
  File file = -1, last_file = -1;
Marc Alff's avatar
Marc Alff committed
318
  mysql_mutex_t *log_lock;
319 320 321 322 323 324
  const char* errmsg_p;
  Slave_log_event* sev = 0;
  my_off_t last_pos = 0;
  int error = 1;
  int cmp_res;
  LINT_INIT(cmp_res);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
325
  DBUG_ENTER("translate_master");
326 327 328 329

  if (!mysql_bin_log.is_open())
  {
    strmov(errmsg,"Binary log is not open");
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
330
    DBUG_RETURN(1);
331 332 333 334 335
  }

  if (!server_id_supplied)
  {
    strmov(errmsg, "Misconfigured master - server id was not set");
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
336
    DBUG_RETURN(1);
337 338
  }

339
  if (mysql_bin_log.find_log_pos(&linfo, NullS, 1))
340 341
  {
    strmov(errmsg,"Could not find first log");
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
342
    DBUG_RETURN(1);
343 344 345 346 347
  }
  thd->current_linfo = &linfo;

  bzero((char*) &log,sizeof(log));
  log_lock = mysql_bin_log.get_log_lock();
Marc Alff's avatar
Marc Alff committed
348
  mysql_mutex_lock(log_lock);
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379

  for (;;)
  {
    if ((file=open_binlog(&log, linfo.log_file_name, &errmsg_p)) < 0)
    {
      strmov(errmsg, errmsg_p);
      goto err;
    }

    if (!(sev = find_slave_event(&log, linfo.log_file_name, errmsg)))
      goto err;

    cmp_res = cmp_master_pos(sev, mi);
    delete sev;

    if (!cmp_res)
    {
      /* Copy basename */
      fn_format(mi->log_file_name, linfo.log_file_name, "","",1);
      mi->pos = my_b_tell(&log);
      goto mi_inited;
    }
    else if (cmp_res > 0)
    {
      if (!last_pos)
      {
	strmov(errmsg,
	       "Slave event in first log points past the target position");
	goto err;
      }
      end_io_cache(&log);
Marc Alff's avatar
Marc Alff committed
380
      mysql_file_close(file, MYF(MY_WME));
381 382 383 384 385 386 387 388 389 390 391 392
      if (init_io_cache(&log, (file = last_file), IO_SIZE, READ_CACHE, 0, 0,
			MYF(MY_WME)))
      {
	errmsg[0] = 0;
	goto err;
      }
      break;
    }

    strmov(last_log_name, linfo.log_file_name);
    last_pos = my_b_tell(&log);

393
    switch (mysql_bin_log.find_next_log(&linfo, 1)) {
394 395
    case LOG_INFO_EOF:
      if (last_file >= 0)
Marc Alff's avatar
Marc Alff committed
396
       mysql_file_close(last_file, MYF(MY_WME));
397 398 399 400 401 402 403 404 405 406 407
      last_file = -1;
      goto found_log;
    case 0:
      break;
    default:
      strmov(errmsg, "Error reading log index");
      goto err;
    }

    end_io_cache(&log);
    if (last_file >= 0)
Marc Alff's avatar
Marc Alff committed
408
      mysql_file_close(last_file, MYF(MY_WME));
409 410 411 412 413 414 415 416 417 418 419 420
    last_file = file;
  }

found_log:
  my_b_seek(&log, last_pos);
  if (find_target_pos(mi,&log,errmsg))
    goto err;
  fn_format(mi->log_file_name, last_log_name, "","",1);  /* Copy basename */

mi_inited:
  error = 0;
err:
Marc Alff's avatar
Marc Alff committed
421
  mysql_mutex_unlock(log_lock);
422
  end_io_cache(&log);
Marc Alff's avatar
Marc Alff committed
423
  mysql_mutex_lock(&LOCK_thread_count);
424
  thd->current_linfo = 0;
Marc Alff's avatar
Marc Alff committed
425
  mysql_mutex_unlock(&LOCK_thread_count);
426
  if (file >= 0)
Marc Alff's avatar
Marc Alff committed
427
    mysql_file_close(file, MYF(MY_WME));
428
  if (last_file >= 0 && last_file != file)
Marc Alff's avatar
Marc Alff committed
429
    mysql_file_close(last_file, MYF(MY_WME));
430

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
431
  DBUG_RETURN(error);
432 433
}

434

435 436
/**
  Caller must delete result when done.
437 438
*/

439 440 441 442 443 444 445 446
static Slave_log_event* find_slave_event(IO_CACHE* log,
					 const char* log_file_name,
					 char* errmsg)
{
  Log_event* ev;
  int i;
  bool slave_event_found = 0;
  LINT_INIT(ev);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
447

448 449
  for (i = 0; i < 2; i++)
  {
Marc Alff's avatar
Marc Alff committed
450
    if (!(ev= Log_event::read_log_event(log, (mysql_mutex_t*)0, 0)))
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
    {
      my_snprintf(errmsg, SLAVE_ERRMSG_SIZE,
		  "Error reading event in log '%s'",
		  (char*)log_file_name);
      return 0;
    }
    if (ev->get_type_code() == SLAVE_EVENT)
    {
      slave_event_found = 1;
      break;
    }
    delete ev;
  }
  if (!slave_event_found)
  {
    my_snprintf(errmsg, SLAVE_ERRMSG_SIZE,
		"Could not find slave event in log '%s'",
		(char*)log_file_name);
    return 0;
  }

  return (Slave_log_event*)ev;
}

475 476 477 478 479
/**
  This function is broken now. 

  @seealso translate_master()
*/
480

481
bool show_new_master(THD* thd)
482
{
483
  Protocol *protocol= thd->protocol;
484 485 486
  DBUG_ENTER("show_new_master");
  List<Item> field_list;
  char errmsg[SLAVE_ERRMSG_SIZE];
487
  LEX_MASTER_INFO* lex_mi= &thd->lex->mi;
488 489 490 491 492

  errmsg[0]=0;					// Safety
  if (translate_master(thd, lex_mi, errmsg))
  {
    if (errmsg[0])
493 494
      my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
               "SHOW NEW MASTER", errmsg);
495
    DBUG_RETURN(TRUE);
496 497 498 499
  }
  else
  {
    field_list.push_back(new Item_empty_string("Log_name", 20));
500 501
    field_list.push_back(new Item_return_int("Log_pos", 10,
					     MYSQL_TYPE_LONGLONG));
502
    if (protocol->send_result_set_metadata(&field_list,
503
                              Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
504
      DBUG_RETURN(TRUE);
505
    protocol->prepare_for_resend();
506
    protocol->store(lex_mi->log_file_name, &my_charset_bin);
507 508
    protocol->store((ulonglong) lex_mi->pos);
    if (protocol->write())
509
      DBUG_RETURN(TRUE);
510
    my_eof(thd);
511
    DBUG_RETURN(FALSE);
512 513 514
  }
}

515
/**
516
  Asks the master for the list of its other connected slaves.
517 518

  This is for failsafe replication:
519 520 521 522
  in order for failsafe replication to work, the servers involved in
  replication must know of each other. We accomplish this by having each
  slave report to the master how to reach it, and on connection, each
  slave receives information about where the other slaves are.
523

524 525
  @param mysql           pre-existing connection to the master
  @param mi              master info
526

527
  @note
528 529 530 531
    mi is used only to give detailed error messages which include the
    hostname/port of the master, the username used by the slave to connect to
    the master.
    If the user used by the slave to connect to the master does not have the
532 533
    REPLICATION SLAVE privilege, it will pop in this function because
    SHOW SLAVE HOSTS will fail on the master.
534

535
  @retval
536
    1           error
537
  @retval
538
    0           success
539
*/
540

541
int update_slave_list(MYSQL* mysql, Master_info* mi)
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
542 543 544 545 546 547
{
  MYSQL_RES* res=0;
  MYSQL_ROW row;
  const char* error=0;
  bool have_auth_info;
  int port_ind;
548
  DBUG_ENTER("update_slave_list");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
549

550
  if (mysql_real_query(mysql, STRING_WITH_LEN("SHOW SLAVE HOSTS")) ||
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
551
      !(res = mysql_store_result(mysql)))
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
552
  {
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
553
    error= mysql_error(mysql);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
554 555 556
    goto err;
  }

hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
557
  switch (mysql_num_fields(res)) {
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
558 559 560 561 562 563 564 565 566
  case 5:
    have_auth_info = 0;
    port_ind=2;
    break;
  case 7:
    have_auth_info = 1;
    port_ind=4;
    break;
  default:
567 568
    error= "the master returned an invalid number of fields for SHOW SLAVE \
HOSTS";
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
569 570 571
    goto err;
  }

Marc Alff's avatar
Marc Alff committed
572
  mysql_mutex_lock(&LOCK_slave_list);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
573

hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
574
  while ((row= mysql_fetch_row(res)))
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
575
  {
576
    uint32 log_server_id;
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
577
    SLAVE_INFO* si, *old_si;
578
    log_server_id = atoi(row[0]);
Konstantin Osipov's avatar
Konstantin Osipov committed
579 580
    if ((old_si= (SLAVE_INFO*)my_hash_search(&slave_list,
                                             (uchar*)&log_server_id,4)))
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
581 582 583 584 585
      si = old_si;
    else
    {
      if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME))))
      {
586
	error= "the slave is out of memory";
Marc Alff's avatar
Marc Alff committed
587
        mysql_mutex_unlock(&LOCK_slave_list);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
588 589
	goto err;
      }
590
      si->server_id = log_server_id;
591 592 593
      if (my_hash_insert(&slave_list, (uchar*)si))
      {
        error= "the slave is out of memory";
Marc Alff's avatar
Marc Alff committed
594
        mysql_mutex_unlock(&LOCK_slave_list);
595 596
        goto err;
      }
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
597
    }
598
    strmake(si->host, row[1], sizeof(si->host)-1);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
599 600 601 602 603
    si->port = atoi(row[port_ind]);
    si->rpl_recovery_rank = atoi(row[port_ind+1]);
    si->master_id = atoi(row[port_ind+2]);
    if (have_auth_info)
    {
604 605
      strmake(si->user, row[2], sizeof(si->user)-1);
      strmake(si->password, row[3], sizeof(si->password)-1);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
606 607
    }
  }
Marc Alff's avatar
Marc Alff committed
608
  mysql_mutex_unlock(&LOCK_slave_list);
609

sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
610 611
err:
  if (res)
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
612
    mysql_free_result(res);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
613 614
  if (error)
  {
615 616
    sql_print_error("While trying to obtain the list of slaves from the master "
                    "'%s:%d', user '%s' got the following error: '%s'", 
617
                    mi->host, mi->port, mi->user, error);
618
    DBUG_RETURN(1);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
619
  }
620
  DBUG_RETURN(0);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
621 622
}

623

624
#if NOT_USED
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
625 626 627 628
int find_recovery_captain(THD* thd, MYSQL* mysql)
{
  return 0;
}
629
#endif
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
630

631
#if NOT_USED
632
pthread_handler_t handle_failsafe_rpl(void *arg)
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
633 634 635 636 637
{
  DBUG_ENTER("handle_failsafe_rpl");
  THD *thd = new THD;
  thd->thread_stack = (char*)&thd;
  MYSQL* recovery_captain = 0;
guilhem@mysql.com's avatar
guilhem@mysql.com committed
638 639
  const char* msg;

sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
640
  pthread_detach_this_thread();
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
641
  if (init_failsafe_rpl_thread(thd) || !(recovery_captain=mysql_init(0)))
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
642 643 644 645
  {
    sql_print_error("Could not initialize failsafe replication thread");
    goto err;
  }
Marc Alff's avatar
Marc Alff committed
646
  mysql_mutex_lock(&LOCK_rpl_status);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
647 648
  msg= thd->enter_cond(&COND_rpl_status,
                       &LOCK_rpl_status, "Waiting for request");
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
649 650 651
  while (!thd->killed && !abort_loop)
  {
    bool break_req_chain = 0;
Marc Alff's avatar
Marc Alff committed
652
    mysql_cond_wait(&COND_rpl_status, &LOCK_rpl_status);
653
    thd_proc_info(thd, "Processing request");
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
654 655
    while (!break_req_chain)
    {
656
      switch (rpl_status) {
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
657 658 659 660 661 662 663 664 665 666 667 668 669
      case RPL_LOST_SOLDIER:
	if (find_recovery_captain(thd, recovery_captain))
	  rpl_status=RPL_TROOP_SOLDIER;
	else
	  rpl_status=RPL_RECOVERY_CAPTAIN;
	break_req_chain=1; /* for now until other states are implemented */
	break;
      default:
	break_req_chain=1;
	break;
      }
    }
  }
guilhem@mysql.com's avatar
guilhem@mysql.com committed
670
  thd->exit_cond(msg);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
671 672
err:
  if (recovery_captain)
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
673
    mysql_close(recovery_captain);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
674
  delete thd;
675 676

  DBUG_LEAVE;                                   // Must match DBUG_ENTER()
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
677 678
  my_thread_end();
  pthread_exit(0);
679
  return 0;                                     // Avoid compiler warnings
680
}
681
#endif
682

683 684 685 686 687 688 689 690 691 692

/**
  Execute a SHOW SLAVE HOSTS statement.

  @param thd Pointer to THD object for the client thread executing the
  statement.

  @retval FALSE success
  @retval TRUE failure
*/
693
bool show_slave_hosts(THD* thd)
694 695
{
  List<Item> field_list;
696
  Protocol *protocol= thd->protocol;
697 698
  DBUG_ENTER("show_slave_hosts");

699 700
  field_list.push_back(new Item_return_int("Server_id", 10,
					   MYSQL_TYPE_LONG));
701 702 703 704 705 706
  field_list.push_back(new Item_empty_string("Host", 20));
  if (opt_show_slave_auth_info)
  {
    field_list.push_back(new Item_empty_string("User",20));
    field_list.push_back(new Item_empty_string("Password",20));
  }
707 708 709
  field_list.push_back(new Item_return_int("Port", 7, MYSQL_TYPE_LONG));
  field_list.push_back(new Item_return_int("Master_id", 10,
					   MYSQL_TYPE_LONG));
710

711
  if (protocol->send_result_set_metadata(&field_list,
712
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
713
    DBUG_RETURN(TRUE);
714

Marc Alff's avatar
Marc Alff committed
715
  mysql_mutex_lock(&LOCK_slave_list);
716 717 718

  for (uint i = 0; i < slave_list.records; ++i)
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
719
    SLAVE_INFO* si = (SLAVE_INFO*) my_hash_element(&slave_list, i);
720 721
    protocol->prepare_for_resend();
    protocol->store((uint32) si->server_id);
722
    protocol->store(si->host, &my_charset_bin);
723 724
    if (opt_show_slave_auth_info)
    {
725 726
      protocol->store(si->user, &my_charset_bin);
      protocol->store(si->password, &my_charset_bin);
727
    }
728 729 730
    protocol->store((uint32) si->port);
    protocol->store((uint32) si->master_id);
    if (protocol->write())
731
    {
Marc Alff's avatar
Marc Alff committed
732
      mysql_mutex_unlock(&LOCK_slave_list);
733
      DBUG_RETURN(TRUE);
734 735
    }
  }
Marc Alff's avatar
Marc Alff committed
736
  mysql_mutex_unlock(&LOCK_slave_list);
737
  my_eof(thd);
738
  DBUG_RETURN(FALSE);
739 740
}

hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
741
#endif /* HAVE_REPLICATION */
742