slave.cc 154 KB
Newer Older
1
/* Copyright (C) 2000-2003 MySQL AB
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
   
   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
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   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 */

#include "mysql_priv.h"
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
18 19 20

#ifdef HAVE_REPLICATION

bk@work.mysql.com's avatar
bk@work.mysql.com committed
21
#include <mysql.h>
22
#include <myisam.h>
23
#include "slave.h"
24
#include "sql_repl.h"
25
#include "repl_failsafe.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
26
#include <thr_alarm.h>
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
27
#include <my_dir.h>
hf@deer.(none)'s avatar
hf@deer.(none) committed
28
#include <sql_common.h>
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
29

30 31 32
bool use_slave_mask = 0;
MY_BITMAP slave_error_mask;

33 34
typedef bool (*CHECK_KILLED_FUNC)(THD*,void*);

35
volatile bool slave_sql_running = 0, slave_io_running = 0;
36
char* slave_load_tmpdir = 0;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
37
MASTER_INFO *active_mi;
38
HASH replicate_do_table, replicate_ignore_table;
39
DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table;
40
bool do_table_inited = 0, ignore_table_inited = 0;
41
bool wild_do_table_inited = 0, wild_ignore_table_inited = 0;
42
bool table_rules_on= 0, replicate_same_server_id;
43
ulonglong relay_log_space_limit = 0;
44 45 46 47 48 49 50

/*
  When slave thread exits, we need to remember the temporary tables so we
  can re-use them on slave start.

  TODO: move the vars below under MASTER_INFO
*/
51

52
int disconnect_slave_event_count = 0, abort_slave_event_count = 0;
53
int events_till_abort = -1;
54
static int events_till_disconnect = -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
55

56
typedef enum { SLAVE_THD_IO, SLAVE_THD_SQL} SLAVE_THD_TYPE;
57

58
static int process_io_rotate(MASTER_INFO* mi, Rotate_log_event* rev);
59
static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev);
60
static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli);
61 62
static inline bool io_slave_killed(THD* thd,MASTER_INFO* mi);
static inline bool sql_slave_killed(THD* thd,RELAY_LOG_INFO* rli);
63
static int count_relay_log_space(RELAY_LOG_INFO* rli);
64
static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type);
65
static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi);
66 67
static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
			  bool suppress_warnings);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
68
static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
69
			     bool reconnect, bool suppress_warnings);
70 71
static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed,
		      void* thread_killed_arg);
72
static int request_table_dump(MYSQL* mysql, const char* db, const char* table);
73
static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
74
				  const char* table_name, bool overwrite);
75
static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi);
76 77

/*
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
78
  Find out which replications threads are running
79

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
80 81 82 83 84 85 86 87 88 89 90 91 92
  SYNOPSIS
    init_thread_mask()
    mask		Return value here
    mi			master_info for slave
    inverse		If set, returns which threads are not running

  IMPLEMENTATION
    Get a bit mask for which threads are running so that we can later restart
    these threads.

  RETURN
    mask	If inverse == 0, running threads
		If inverse == 1, stopped threads    
93 94
*/

95 96 97 98 99 100 101 102
void init_thread_mask(int* mask,MASTER_INFO* mi,bool inverse)
{
  bool set_io = mi->slave_running, set_sql = mi->rli.slave_running;
  register int tmp_mask=0;
  if (set_io)
    tmp_mask |= SLAVE_IO;
  if (set_sql)
    tmp_mask |= SLAVE_SQL;
103 104
  if (inverse)
    tmp_mask^= (SLAVE_IO | SLAVE_SQL);
105 106 107
  *mask = tmp_mask;
}

108

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
109
/*
110
  lock_slave_threads()
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
111
*/
112

113 114 115 116 117 118 119
void lock_slave_threads(MASTER_INFO* mi)
{
  //TODO: see if we can do this without dual mutex
  pthread_mutex_lock(&mi->run_lock);
  pthread_mutex_lock(&mi->rli.run_lock);
}

120

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
121
/*
122
  unlock_slave_threads()
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
123
*/
124

125 126 127 128 129 130 131
void unlock_slave_threads(MASTER_INFO* mi)
{
  //TODO: see if we can do this without dual mutex
  pthread_mutex_unlock(&mi->rli.run_lock);
  pthread_mutex_unlock(&mi->run_lock);
}

132

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
133
/* Initialize slave structures */
134

135 136
int init_slave()
{
137
  DBUG_ENTER("init_slave");
138

139 140 141 142 143 144
  /*
    This is called when mysqld starts. Before client connections are
    accepted. However bootstrap may conflict with us if it does START SLAVE.
    So it's safer to take the lock.
  */
  pthread_mutex_lock(&LOCK_active_mi);
145 146 147 148
  /*
    TODO: re-write this to interate through the list of files
    for multi-master
  */
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
149
  active_mi= new MASTER_INFO;
150 151

  /*
152 153 154
    If master_host is not specified, try to read it from the master_info file.
    If master_host is specified, create the master_info file if it doesn't
    exists.
155
  */
156 157 158 159 160 161
  if (!active_mi)
  {
    sql_print_error("Failed to allocate memory for the master info structure");
    goto err;
  }
    
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
162
  if (init_master_info(active_mi,master_info_file,relay_log_info_file,
163
		       !master_host))
164
  {
165
    sql_print_error("Failed to initialize the master info structure");
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
166
    goto err;
167
  }
168 169 170 171

  if (server_id && !master_host && active_mi->host[0])
    master_host= active_mi->host;

172 173
  /* If server id is not set, start_slave_thread() will say it */

174
  if (master_host && !opt_skip_slave_start)
175
  {
176 177 178 179 180 181
    if (start_slave_threads(1 /* need mutex */,
			    0 /* no wait for start*/,
			    active_mi,
			    master_info_file,
			    relay_log_info_file,
			    SLAVE_IO | SLAVE_SQL))
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
182
    {
183
      sql_print_error("Failed to create slave threads");
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
184 185
      goto err;
    }
186
  }
187
  pthread_mutex_unlock(&LOCK_active_mi);
188
  DBUG_RETURN(0);
189

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
190
err:
191
  pthread_mutex_unlock(&LOCK_active_mi);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
192
  DBUG_RETURN(1);
193
}
194

195

196 197
static void free_table_ent(TABLE_RULE_ENT* e)
{
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
198
  my_free((gptr) e, MYF(0));
199 200
}

201

202 203 204 205 206 207 208
static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
			   my_bool not_used __attribute__((unused)))
{
  *len = e->key_len;
  return (byte*)e->db;
}

209 210 211 212 213 214 215 216 217 218 219

/*
  Open the given relay log

  SYNOPSIS
    init_relay_log_pos()
    rli			Relay information (will be initialized)
    log			Name of relay log file to read from. NULL = First log
    pos			Position in relay log file 
    need_data_lock	Set to 1 if this functions should do mutex locks
    errmsg		Store pointer to error message here
220 221 222
    look_for_description_event 
                        1 if we should look for such an event. We only need
                        this when the SQL thread starts and opens an existing
223 224 225 226
                        relay log and has to execute it (possibly from an
                        offset >4); then we need to read the first event of
                        the relay log to be able to parse the events we have
                        to execute.
227 228 229 230 231 232 233 234

  DESCRIPTION
  - Close old open relay log files.
  - If we are using the same relay log as the running IO-thread, then set
    rli->cur_log to point to the same IO_CACHE entry.
  - If not, open the 'log' binary file.

  TODO
235
    - check proper initialization of group_master_log_name/group_master_log_pos
236 237 238 239 240

  RETURN VALUES
    0	ok
    1	error.  errmsg is set to point to the error message
*/
241

242 243
int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
		       ulonglong pos, bool need_data_lock,
244 245
		       const char** errmsg,
                       bool look_for_description_event)
246
{
247
  DBUG_ENTER("init_relay_log_pos");
248
  DBUG_PRINT("info", ("pos=%lu", pos));
249

250
  *errmsg=0;
251
  pthread_mutex_t *log_lock=rli->relay_log.get_log_lock();
252
  
253 254
  if (need_data_lock)
    pthread_mutex_lock(&rli->data_lock);
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272

  /*
    Slave threads are not the only users of init_relay_log_pos(). CHANGE MASTER
    is, too, and init_slave() too; these 2 functions allocate a description
    event in init_relay_log_pos, which is not freed by the terminating SQL slave
    thread as that thread is not started by these functions. So we have to free
    the description_event here, in case, so that there is no memory leak in
    running, say, CHANGE MASTER.
  */
  delete rli->relay_log.description_event_for_exec;
  /*
    By default the relay log is in binlog format 3 (4.0).
    Even if format is 4, this will work enough to read the first event
    (Format_desc) (remember that format 4 is just lenghtened compared to format
    3; format 3 is a prefix of format 4). 
  */
  rli->relay_log.description_event_for_exec= new
    Format_description_log_event(3);
273
  
274 275
  pthread_mutex_lock(log_lock);
  
276
  /* Close log file and free buffers if it's already open */
277 278 279 280 281 282 283
  if (rli->cur_log_fd >= 0)
  {
    end_io_cache(&rli->cache_buf);
    my_close(rli->cur_log_fd, MYF(MY_WME));
    rli->cur_log_fd = -1;
  }
  
284
  rli->group_relay_log_pos = rli->event_relay_log_pos = pos;
285

286 287 288 289
  /*
    Test to see if the previous run was with the skip of purging
    If yes, we do not purge when we restart
  */
290
  if (rli->relay_log.find_log_pos(&rli->linfo, NullS, 1))
291 292 293 294
  {
    *errmsg="Could not find first log during relay log initialization";
    goto err;
  }
295

296
  if (log && rli->relay_log.find_log_pos(&rli->linfo, log, 1))
297
  {
298 299
    *errmsg="Could not find target log during relay log initialization";
    goto err;
300
  }
301 302 303 304
  strmake(rli->group_relay_log_name,rli->linfo.log_file_name,
	  sizeof(rli->group_relay_log_name)-1);
  strmake(rli->event_relay_log_name,rli->linfo.log_file_name,
	  sizeof(rli->event_relay_log_name)-1);
305 306
  if (rli->relay_log.is_active(rli->linfo.log_file_name))
  {
307 308 309 310 311
    /*
      The IO thread is using this log file.
      In this case, we will use the same IO_CACHE pointer to
      read data as the IO thread is using to write data.
    */
312 313
    my_b_seek((rli->cur_log=rli->relay_log.get_log_file()), (off_t)0);
    if (check_binlog_magic(rli->cur_log,errmsg))
314
      goto err;
315
    rli->cur_log_old_open_count=rli->relay_log.get_open_count();
316 317 318
  }
  else
  {
319 320 321
    /*
      Open the relay log and set rli->cur_log to point at this one
    */
322 323 324 325 326
    if ((rli->cur_log_fd=open_binlog(&rli->cache_buf,
				     rli->linfo.log_file_name,errmsg)) < 0)
      goto err;
    rli->cur_log = &rli->cache_buf;
  }
327 328 329 330 331 332 333 334 335 336
  /*
    In all cases, check_binlog_magic() has been called so we're at offset 4 for
    sure.
  */
  if (pos > BIN_LOG_HEADER_SIZE) /* If pos<=4, we stay at 4 */
  {
    Log_event* ev;
    while (look_for_description_event) 
    {
      /*
337 338
        Read the possible Format_description_log_event; if position
        was 4, no need, it will be read naturally.
339 340 341 342 343 344 345 346 347 348 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
      */
      DBUG_PRINT("info",("looking for a Format_description_log_event"));

      if (my_b_tell(rli->cur_log) >= pos)
        break;

      /*
        Because of we have rli->data_lock and log_lock, we can safely read an
        event
      */
      if (!(ev=Log_event::read_log_event(rli->cur_log,0,
                                         rli->relay_log.description_event_for_exec)))
      {
        DBUG_PRINT("info",("could not read event, rli->cur_log->error=%d",
                           rli->cur_log->error));
        if (rli->cur_log->error) /* not EOF */
        {
          *errmsg= "I/O error reading event at position 4";
          goto err;
        }
        break;
      }
      else if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT)
      {
        DBUG_PRINT("info",("found Format_description_log_event"));
        delete rli->relay_log.description_event_for_exec;
        rli->relay_log.description_event_for_exec= (Format_description_log_event*) ev;
        /*
          As ev was returned by read_log_event, it has passed is_valid(), so
          my_malloc() in ctor worked, no need to check again.
        */
        /*
          Ok, we found a Format_description event. But it is not sure that this
          describes the whole relay log; indeed, one can have this sequence
          (starting from position 4):
          Format_desc (of slave)
          Rotate (of master)
376
          Format_desc (of master)
377 378 379
          So the Format_desc which really describes the rest of the relay log
          is the 3rd event (it can't be further than that, because we rotate
          the relay log when we queue a Rotate event from the master).
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
          But what describes the Rotate is the first Format_desc.
          So what we do is:
          go on searching for Format_description events, until you exceed the
          position (argument 'pos') or until you find another event than Rotate
          or Format_desc.
        */
      }
      else 
      {
        DBUG_PRINT("info",("found event of another type=%d",
                           ev->get_type_code()));
        look_for_description_event= (ev->get_type_code() == ROTATE_EVENT);
        delete ev;
      }
    }
395
    my_b_seek(rli->cur_log,(off_t)pos);
396 397 398 399 400 401 402 403 404 405
#ifndef DBUG_OFF
  {
    char llbuf1[22], llbuf2[22];
    DBUG_PRINT("info", ("my_b_tell(rli->cur_log)=%s rli->event_relay_log_pos=%s",
                        llstr(my_b_tell(rli->cur_log),llbuf1), 
                        llstr(rli->event_relay_log_pos,llbuf2)));
  }
#endif

  }
406

407
err:
408 409 410 411
  /*
    If we don't purge, we can't honour relay_log_space_limit ;
    silently discard it
  */
412
  if (!relay_log_purge)
413
    rli->log_space_limit= 0;
414
  pthread_cond_broadcast(&rli->data_cond);
415 416 417
  
  pthread_mutex_unlock(log_lock);

418 419
  if (need_data_lock)
    pthread_mutex_unlock(&rli->data_lock);
420 421
  if (!rli->relay_log.description_event_for_exec->is_valid() && !*errmsg)
    *errmsg= "Invalid Format_description log event; could be out of memory";
422

423
  DBUG_RETURN ((*errmsg) ? 1 : 0);
424 425
}

426

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
427
/*
428
  Init function to set up array for errors that should be skipped for slave
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
429

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
430 431 432 433 434 435 436
  SYNOPSIS
    init_slave_skip_errors()
    arg		List of errors numbers to skip, separated with ','

  NOTES
    Called from get_options() in mysqld.cc on start-up
*/
437

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
438
void init_slave_skip_errors(const char* arg)
439
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
440
  const char *p;
441
  if (bitmap_init(&slave_error_mask,0,MAX_SLAVE_ERROR,0))
442 443 444 445 446
  {
    fprintf(stderr, "Badly out of memory, please check your system status\n");
    exit(1);
  }
  use_slave_mask = 1;
447
  for (;my_isspace(system_charset_info,*arg);++arg)
448
    /* empty */;
449
  if (!my_strnncoll(system_charset_info,(uchar*)arg,4,(const uchar*)"all",4))
450 451 452 453 454 455 456 457 458 459 460
  {
    bitmap_set_all(&slave_error_mask);
    return;
  }
  for (p= arg ; *p; )
  {
    long err_code;
    if (!(p= str2int(p, 10, 0, LONG_MAX, &err_code)))
      break;
    if (err_code < MAX_SLAVE_ERROR)
       bitmap_set_bit(&slave_error_mask,(uint)err_code);
461
    while (!my_isdigit(system_charset_info,*p) && *p)
462 463 464 465
      p++;
  }
}

466

pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
467
void st_relay_log_info::inc_group_relay_log_pos(ulonglong log_pos,
468
						bool skip_lock)  
469 470 471
{
  if (!skip_lock)
    pthread_mutex_lock(&data_lock);
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
472
  inc_event_relay_log_pos();
monty@mishka.local's avatar
monty@mishka.local committed
473 474
  group_relay_log_pos= event_relay_log_pos;
  strmake(group_relay_log_name,event_relay_log_name,
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
475
	  sizeof(group_relay_log_name)-1);
monty@mishka.local's avatar
monty@mishka.local committed
476 477 478 479 480 481 482 483 484 485 486 487 488

  notify_group_relay_log_name_update();
        
  /*
    If the slave does not support transactions and replicates a transaction,
    users should not trust group_master_log_pos (which they can display with
    SHOW SLAVE STATUS or read from relay-log.info), because to compute
    group_master_log_pos the slave relies on log_pos stored in the master's
    binlog, but if we are in a master's transaction these positions are always
    the BEGIN's one (excepted for the COMMIT), so group_master_log_pos does
    not advance as it should on the non-transactional slave (it advances by
    big leaps, whereas it should advance by small leaps).
  */
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
  /*
    In 4.x we used the event's len to compute the positions here. This is
    wrong if the event was 3.23/4.0 and has been converted to 5.0, because
    then the event's len is not what is was in the master's binlog, so this
    will make a wrong group_master_log_pos (yes it's a bug in 3.23->4.0
    replication: Exec_master_log_pos is wrong). Only way to solve this is to
    have the original offset of the end of the event the relay log. This is
    what we do in 5.0: log_pos has become "end_log_pos" (because the real use
    of log_pos in 4.0 was to compute the end_log_pos; so better to store
    end_log_pos instead of begin_log_pos.
    If we had not done this fix here, the problem would also have appeared
    when the slave and master are 5.0 but with different event length (for
    example the slave is more recent than the master and features the event
    UID). It would give false MASTER_POS_WAIT, false Exec_master_log_pos in
    SHOW SLAVE STATUS, and so the user would do some CHANGE MASTER using this
    value which would lead to badly broken replication.
    Even the relay_log_pos will be corrupted in this case, because the len is
    the relay log is not "val".
    With the end_log_pos solution, we avoid computations involving lengthes.
  */
509 510
  DBUG_PRINT("info", ("log_pos: %lu  group_master_log_pos: %lu",
		      (long) log_pos, (long) group_master_log_pos));
monty@mishka.local's avatar
monty@mishka.local committed
511 512
  if (log_pos) // 3.23 binlogs don't have log_posx
  {
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
513
    group_master_log_pos= log_pos;
monty@mishka.local's avatar
monty@mishka.local committed
514
  }
515 516 517 518 519 520
  pthread_cond_broadcast(&data_cond);
  if (!skip_lock)
    pthread_mutex_unlock(&data_lock);
}


guilhem@mysql.com's avatar
guilhem@mysql.com committed
521 522 523 524 525 526 527 528 529 530 531 532 533
void st_relay_log_info::close_temporary_tables()
{
  TABLE *table,*next;

  for (table=save_temporary_tables ; table ; table=next)
  {
    next=table->next;
    /*
      Don't ask for disk deletion. For now, anyway they will be deleted when
      slave restarts, but it is a better intention to not delete them.
    */
    close_temporary(table, 0);
  }
534 535
  save_temporary_tables= 0;
  slave_open_temp_tables= 0;
guilhem@mysql.com's avatar
guilhem@mysql.com committed
536
}
537

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
538
/*
539 540
  purge_relay_logs()

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
541 542
  NOTES
    Assumes to have a run lock on rli and that no slave thread are running.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
543 544
*/

545 546
int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
		     const char** errmsg)
547
{
548
  int error=0;
549
  DBUG_ENTER("purge_relay_logs");
550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568

  /*
    Even if rli->inited==0, we still try to empty rli->master_log_* variables.
    Indeed, rli->inited==0 does not imply that they already are empty.
    It could be that slave's info initialization partly succeeded : 
    for example if relay-log.info existed but *relay-bin*.*
    have been manually removed, init_relay_log_info reads the old 
    relay-log.info and fills rli->master_log_*, then init_relay_log_info
    checks for the existence of the relay log, this fails and
    init_relay_log_info leaves rli->inited to 0.
    In that pathological case, rli->master_log_pos* will be properly reinited
    at the next START SLAVE (as RESET SLAVE or CHANGE
    MASTER, the callers of purge_relay_logs, will delete bogus *.info files
    or replace them with correct files), however if the user does SHOW SLAVE
    STATUS before START SLAVE, he will see old, confusing rli->master_log_*.
    In other words, we reinit rli->master_log_* for SHOW SLAVE STATUS 
    to display fine in any case.
  */

569 570
  rli->group_master_log_name[0]= 0;
  rli->group_master_log_pos= 0;
571

572
  if (!rli->inited)
573 574
  {
    DBUG_PRINT("info", ("rli->inited == 0"));
575
    DBUG_RETURN(0);
576
  }
577

578 579
  DBUG_ASSERT(rli->slave_running == 0);
  DBUG_ASSERT(rli->mi->slave_running == 0);
580

581 582
  rli->slave_skip_counter=0;
  pthread_mutex_lock(&rli->data_lock);
583
  if (rli->relay_log.reset_logs(thd))
584 585 586 587 588
  {
    *errmsg = "Failed during log reset";
    error=1;
    goto err;
  }
589
  /* Save name of used relay log file */
590 591 592 593 594
  strmake(rli->group_relay_log_name, rli->relay_log.get_log_fname(),
	  sizeof(rli->group_relay_log_name)-1);
  strmake(rli->event_relay_log_name, rli->relay_log.get_log_fname(),
 	  sizeof(rli->event_relay_log_name)-1);
  rli->group_relay_log_pos= rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
595 596 597 598 599
  if (count_relay_log_space(rli))
  {
    *errmsg= "Error counting relay log space";
    goto err;
  }
600
  if (!just_reset)
601 602
    error= init_relay_log_pos(rli, rli->group_relay_log_name,
                              rli->group_relay_log_pos,
603
  			      0 /* do not need data lock */, errmsg, 0);
604
  
605 606 607 608
err:
#ifndef DBUG_OFF
  char buf[22];
#endif  
609
  DBUG_PRINT("info",("log_space_total: %s",llstr(rli->log_space_total,buf)));
610
  pthread_mutex_unlock(&rli->data_lock);
611
  DBUG_RETURN(error);
612 613
}

614

615 616 617 618 619 620 621
int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock)
{
  if (!mi->inited)
    return 0; /* successfully do nothing */
  int error,force_all = (thread_mask & SLAVE_FORCE_ALL);
  pthread_mutex_t *sql_lock = &mi->rli.run_lock, *io_lock = &mi->run_lock;
  pthread_mutex_t *sql_cond_lock,*io_cond_lock;
622
  DBUG_ENTER("terminate_slave_threads");
623 624 625 626 627 628 629 630 631 632

  sql_cond_lock=sql_lock;
  io_cond_lock=io_lock;
  
  if (skip_lock)
  {
    sql_lock = io_lock = 0;
  }
  if ((thread_mask & (SLAVE_IO|SLAVE_FORCE_ALL)) && mi->slave_running)
  {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
633
    DBUG_PRINT("info",("Terminating IO thread"));
634 635
    mi->abort_slave=1;
    if ((error=terminate_slave_thread(mi->io_thd,io_lock,
636 637 638
				      io_cond_lock,
				      &mi->stop_cond,
				      &mi->slave_running)) &&
639
	!force_all)
640
      DBUG_RETURN(error);
641 642 643
  }
  if ((thread_mask & (SLAVE_SQL|SLAVE_FORCE_ALL)) && mi->rli.slave_running)
  {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
644
    DBUG_PRINT("info",("Terminating SQL thread"));
645 646 647 648 649 650 651
    DBUG_ASSERT(mi->rli.sql_thd != 0) ;
    mi->rli.abort_slave=1;
    if ((error=terminate_slave_thread(mi->rli.sql_thd,sql_lock,
				      sql_cond_lock,
				      &mi->rli.stop_cond,
				      &mi->rli.slave_running)) &&
	!force_all)
652
      DBUG_RETURN(error);
653
  }
654
  DBUG_RETURN(0);
655 656
}

657

658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
			   pthread_mutex_t *cond_lock,
			   pthread_cond_t* term_cond,
			   volatile bool* slave_running)
{
  if (term_lock)
  {
    pthread_mutex_lock(term_lock);
    if (!*slave_running)
    {
      pthread_mutex_unlock(term_lock);
      return ER_SLAVE_NOT_RUNNING;
    }
  }
  DBUG_ASSERT(thd != 0);
673 674 675
  /*
    Is is criticate to test if the slave is running. Otherwise, we might
    be referening freed memory trying to kick it
676
  */
677
  THD_CHECK_SENTRY(thd);
678 679

  while (*slave_running)			// Should always be true
680 681
  {
    KICK_SLAVE(thd);
682 683 684
    /*
      There is a small chance that slave thread might miss the first
      alarm. To protect againts it, resend the signal until it reacts
685 686
    */
    struct timespec abstime;
687
    set_timespec(abstime,2);
688 689 690 691 692 693 694
    pthread_cond_timedwait(term_cond, cond_lock, &abstime);
  }
  if (term_lock)
    pthread_mutex_unlock(term_lock);
  return 0;
}

695

696
int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
697
		       pthread_mutex_t *cond_lock,
698 699 700
		       pthread_cond_t *start_cond,
		       volatile bool *slave_running,
		       volatile ulong *slave_run_id,
701 702
		       MASTER_INFO* mi,
                       bool high_priority)
703 704
{
  pthread_t th;
705
  ulong start_id;
706
  DBUG_ASSERT(mi->inited);
707 708
  DBUG_ENTER("start_slave_thread");

709 710 711 712 713 714 715 716 717
  if (start_lock)
    pthread_mutex_lock(start_lock);
  if (!server_id)
  {
    if (start_cond)
      pthread_cond_broadcast(start_cond);
    if (start_lock)
      pthread_mutex_unlock(start_lock);
    sql_print_error("Server id not set, will not start slave");
718
    DBUG_RETURN(ER_BAD_SLAVE);
719 720 721
  }
  
  if (*slave_running)
722 723 724 725 726
  {
    if (start_cond)
      pthread_cond_broadcast(start_cond);
    if (start_lock)
      pthread_mutex_unlock(start_lock);
727
    DBUG_RETURN(ER_SLAVE_MUST_STOP);
728
  }
729 730
  start_id= *slave_run_id;
  DBUG_PRINT("info",("Creating new slave thread"));
731 732
  if (high_priority)
    my_pthread_attr_setprio(&connection_attrib,CONNECT_PRIOR);
733 734 735 736
  if (pthread_create(&th, &connection_attrib, h_func, (void*)mi))
  {
    if (start_lock)
      pthread_mutex_unlock(start_lock);
737
    DBUG_RETURN(ER_SLAVE_THREAD);
738
  }
guilhem@mysql.com's avatar
guilhem@mysql.com committed
739
  if (start_cond && cond_lock) // caller has cond_lock
740 741
  {
    THD* thd = current_thd;
742
    while (start_id == *slave_run_id)
743
    {
744
      DBUG_PRINT("sleep",("Waiting for slave thread to start"));
745
      const char* old_msg = thd->enter_cond(start_cond,cond_lock,
746
					    "Waiting for slave thread to start");
747 748
      pthread_cond_wait(start_cond,cond_lock);
      thd->exit_cond(old_msg);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
749
      pthread_mutex_lock(cond_lock); // re-acquire it as exit_cond() released
750
      if (thd->killed)
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
751
	DBUG_RETURN(thd->killed_errno());
752 753 754 755
    }
  }
  if (start_lock)
    pthread_mutex_unlock(start_lock);
756
  DBUG_RETURN(0);
757
}
758

759

760
/*
761
  start_slave_threads()
762

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
763 764 765 766
  NOTES
    SLAVE_FORCE_ALL is not implemented here on purpose since it does not make
    sense to do that for starting a slave--we always care if it actually
    started the threads that were not previously running
767
*/
768

769 770 771 772 773 774 775
int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
			MASTER_INFO* mi, const char* master_info_fname,
			const char* slave_info_fname, int thread_mask)
{
  pthread_mutex_t *lock_io=0,*lock_sql=0,*lock_cond_io=0,*lock_cond_sql=0;
  pthread_cond_t* cond_io=0,*cond_sql=0;
  int error=0;
776
  DBUG_ENTER("start_slave_threads");
777 778 779 780 781 782 783 784 785 786 787 788 789
  
  if (need_slave_mutex)
  {
    lock_io = &mi->run_lock;
    lock_sql = &mi->rli.run_lock;
  }
  if (wait_for_start)
  {
    cond_io = &mi->start_cond;
    cond_sql = &mi->rli.start_cond;
    lock_cond_io = &mi->run_lock;
    lock_cond_sql = &mi->rli.run_lock;
  }
790 791 792

  if (thread_mask & SLAVE_IO)
    error=start_slave_thread(handle_slave_io,lock_io,lock_cond_io,
793 794
			     cond_io,
			     &mi->slave_running, &mi->slave_run_id,
795
			     mi, 1); //high priority, to read the most possible
796
  if (!error && (thread_mask & SLAVE_SQL))
797
  {
798 799
    error=start_slave_thread(handle_slave_sql,lock_sql,lock_cond_sql,
			     cond_sql,
800
			     &mi->rli.slave_running, &mi->rli.slave_run_id,
801
			     mi, 0);
802 803 804
    if (error)
      terminate_slave_threads(mi, thread_mask & SLAVE_IO, 0);
  }
805
  DBUG_RETURN(error);
806
}
807

808

809 810
void init_table_rule_hash(HASH* h, bool* h_inited)
{
811
  hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0,
812
	    (hash_get_key) get_table_key,
813
	    (hash_free_key) free_table_ent, 0);
814 815
  *h_inited = 1;
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
816

817

818 819
void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited)
{
820
  my_init_dynamic_array(a, sizeof(TABLE_RULE_ENT*), TABLE_RULE_ARR_SIZE,
821 822 823 824
		     TABLE_RULE_ARR_SIZE);
  *a_inited = 1;
}

825

826 827 828 829 830
static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
{
  uint i;
  const char* key_end = key + len;
  
831
  for (i = 0; i < a->elements; i++)
832 833 834
    {
      TABLE_RULE_ENT* e ;
      get_dynamic(a, (gptr)&e, i);
835
      if (!my_wildcmp(system_charset_info, key, key_end, 
836
                            (const char*)e->db,
837 838
			    (const char*)(e->db + e->key_len),
			    '\\',wild_one,wild_many))
839 840 841 842 843 844
	return e;
    }
  
  return 0;
}

845

846 847 848 849 850 851 852 853 854 855 856 857 858
/*
  Checks whether tables match some (wild_)do_table and (wild_)ignore_table
  rules (for replication)

  SYNOPSIS
    tables_ok()
    thd             thread (SQL slave thread normally)
    tables          list of tables to check

  NOTES
    Note that changing the order of the tables in the list can lead to
    different results. Note also the order of precedence of the do/ignore 
    rules (see code below). For that reason, users should not set conflicting 
859 860 861 862 863 864 865 866 867 868
    rules because they may get unpredicted results (precedence order is
    explained in the manual).
    If no table of the list is marked "updating" (so far this can only happen
    if the statement is a multi-delete (SQLCOM_DELETE_MULTI) and the "tables"
    is the tables in the FROM): then we always return 0, because there is no
    reason we play this statement on this slave if it updates nothing. In the
    case of SQLCOM_DELETE_MULTI, there will be a second call to tables_ok(),
    with tables having "updating==TRUE" (those after the DELETE), so this
    second call will make the decision (because
    all_tables_not_ok() = !tables_ok(1st_list) && !tables_ok(2nd_list)).
869

870 871
    Thought which arose from a question of a big customer "I want to include
    all tables like "abc.%" except the "%.EFG"". This can't be done now. If we
872 873
    supported Perl regexps we could do it with this pattern: /^abc\.(?!EFG)/
    (I could not find an equivalent in the regex library MySQL uses).
874 875 876 877 878

  RETURN VALUES
    0           should not be logged/replicated
    1           should be logged/replicated                  
*/
879

880 881
int tables_ok(THD* thd, TABLE_LIST* tables)
{
882
  bool some_tables_updating= 0;
883 884
  DBUG_ENTER("tables_ok");

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
885
  for (; tables; tables= tables->next_global)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
886
  {
887 888 889 890
    char hash_key[2*NAME_LEN+2];
    char *end;
    uint len;

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
891 892
    if (!tables->updating) 
      continue;
893
    some_tables_updating= 1;
894 895 896
    end= strmov(hash_key, tables->db ? tables->db : thd->db);
    *end++= '.';
    len= (uint) (strmov(end, tables->real_name) - hash_key);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
897
    if (do_table_inited) // if there are any do's
898
    {
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
899
      if (hash_search(&replicate_do_table, (byte*) hash_key, len))
900
	DBUG_RETURN(1);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
901
    }
902
    if (ignore_table_inited) // if there are any ignores
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
903 904
    {
      if (hash_search(&replicate_ignore_table, (byte*) hash_key, len))
905
	DBUG_RETURN(0); 
906
    }
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
907 908
    if (wild_do_table_inited && find_wild(&replicate_wild_do_table,
					  hash_key, len))
909
      DBUG_RETURN(1);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
910 911
    if (wild_ignore_table_inited && find_wild(&replicate_wild_ignore_table,
					      hash_key, len))
912
      DBUG_RETURN(0);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
913
  }
914

915
  /*
916 917
    If no table was to be updated, ignore statement (no reason we play it on
    slave, slave is supposed to replicate _changes_ only).
918 919 920
    If no explicit rule found and there was a do list, do not replicate.
    If there was no do list, go ahead
  */
921 922
  DBUG_RETURN(some_tables_updating &&
              !do_table_inited && !wild_do_table_inited);
923 924
}

925

926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975
/*
  Checks whether a db matches wild_do_table and wild_ignore_table
  rules (for replication)

  SYNOPSIS
    db_ok_with_wild_table()
    db		name of the db to check.
		Is tested with check_db_name() before calling this function.

  NOTES
    Here is the reason for this function.
    We advise users who want to exclude a database 'db1' safely to do it
    with replicate_wild_ignore_table='db1.%' instead of binlog_ignore_db or
    replicate_ignore_db because the two lasts only check for the selected db,
    which won't work in that case:
    USE db2;
    UPDATE db1.t SET ... #this will be replicated and should not
    whereas replicate_wild_ignore_table will work in all cases.
    With replicate_wild_ignore_table, we only check tables. When
    one does 'DROP DATABASE db1', tables are not involved and the
    statement will be replicated, while users could expect it would not (as it
    rougly means 'DROP db1.first_table, DROP db1.second_table...').
    In other words, we want to interpret 'db1.%' as "everything touching db1".
    That is why we want to match 'db1' against 'db1.%' wild table rules.

  RETURN VALUES
    0           should not be logged/replicated
    1           should be logged/replicated
 */

int db_ok_with_wild_table(const char *db)
{
  char hash_key[NAME_LEN+2];
  char *end;
  int len;
  end= strmov(hash_key, db);
  *end++= '.';
  len= end - hash_key ;
  if (wild_do_table_inited && find_wild(&replicate_wild_do_table,
                                        hash_key, len))
    return 1;
  if (wild_ignore_table_inited && find_wild(&replicate_wild_ignore_table,
                                            hash_key, len))
    return 0;
  
  /*
    If no explicit rule found and there was a do list, do not replicate.
    If there was no do list, go ahead
  */
  return !wild_do_table_inited;
976 977 978 979 980
}


int add_table_rule(HASH* h, const char* table_spec)
{
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
981
  const char* dot = strchr(table_spec, '.');
982
  if (!dot) return 1;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
983
  // len is always > 0 because we know the there exists a '.'
984 985 986
  uint len = (uint)strlen(table_spec);
  TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
						 + len, MYF(MY_WME));
987
  if (!e) return 1;
988 989 990 991
  e->db = (char*)e + sizeof(TABLE_RULE_ENT);
  e->tbl_name = e->db + (dot - table_spec) + 1;
  e->key_len = len;
  memcpy(e->db, table_spec, len);
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
992
  (void)my_hash_insert(h, (byte*)e);
993 994 995
  return 0;
}

996

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
997 998 999
/*
  Add table expression with wildcards to dynamic array
*/
1000

1001 1002
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
{
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
1003
  const char* dot = strchr(table_spec, '.');
1004
  if (!dot) return 1;
1005 1006 1007
  uint len = (uint)strlen(table_spec);
  TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
						 + len, MYF(MY_WME));
1008
  if (!e) return 1;
1009 1010 1011 1012 1013 1014 1015 1016
  e->db = (char*)e + sizeof(TABLE_RULE_ENT);
  e->tbl_name = e->db + (dot - table_spec) + 1;
  e->key_len = len;
  memcpy(e->db, table_spec, len);
  insert_dynamic(a, (gptr)&e);
  return 0;
}

1017

1018 1019 1020
static void free_string_array(DYNAMIC_ARRAY *a)
{
  uint i;
1021
  for (i = 0; i < a->elements; i++)
1022 1023
    {
      char* p;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1024
      get_dynamic(a, (gptr) &p, i);
1025 1026 1027 1028 1029
      my_free(p, MYF(MY_WME));
    }
  delete_dynamic(a);
}

1030

1031
#ifdef NOT_USED_YET
1032 1033 1034 1035 1036
static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/)
{
  end_master_info(mi);
  return 0;
}
1037
#endif
1038

1039

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1040 1041 1042 1043 1044 1045
/*
  Free all resources used by slave

  SYNOPSIS
    end_slave()
*/
1046

1047 1048
void end_slave()
{
1049 1050 1051 1052 1053 1054 1055 1056
  /*
    This is called when the server terminates, in close_connections().
    It terminates slave threads. However, some CHANGE MASTER etc may still be
    running presently. If a START SLAVE was in progress, the mutex lock below
    will make us wait until slave threads have started, and START SLAVE
    returns, then we terminate them here.
  */
  pthread_mutex_lock(&LOCK_active_mi);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076
  if (active_mi)
  {
    /*
      TODO: replace the line below with
      list_walk(&master_list, (list_walk_action)end_slave_on_walk,0);
      once multi-master code is ready.
    */
    terminate_slave_threads(active_mi,SLAVE_FORCE_ALL);
    end_master_info(active_mi);
    if (do_table_inited)
      hash_free(&replicate_do_table);
    if (ignore_table_inited)
      hash_free(&replicate_ignore_table);
    if (wild_do_table_inited)
      free_string_array(&replicate_wild_do_table);
    if (wild_ignore_table_inited)
      free_string_array(&replicate_wild_ignore_table);
    delete active_mi;
    active_mi= 0;
  }
1077
  pthread_mutex_unlock(&LOCK_active_mi);
1078
}
1079

1080

1081
static bool io_slave_killed(THD* thd, MASTER_INFO* mi)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1082
{
1083 1084 1085
  DBUG_ASSERT(mi->io_thd == thd);
  DBUG_ASSERT(mi->slave_running == 1); // tracking buffer overrun
  return mi->abort_slave || abort_loop || thd->killed;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1086 1087
}

1088

1089
static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli)
1090 1091 1092 1093 1094 1095
{
  DBUG_ASSERT(rli->sql_thd == thd);
  DBUG_ASSERT(rli->slave_running == 1);// tracking buffer overrun
  return rli->abort_slave || abort_loop || thd->killed;
}

1096

1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
/*
  Writes an error message to rli->last_slave_error and rli->last_slave_errno
  (which will be displayed by SHOW SLAVE STATUS), and prints it to stderr.

  SYNOPSIS
    slave_print_error()
    rli		
    err_code    The error code
    msg         The error message (usually related to the error code, but can
                contain more information).
    ...         (this is printf-like format, with % symbols in msg)

  RETURN VALUES
    void
1111
*/
1112

1113
void slave_print_error(RELAY_LOG_INFO* rli, int err_code, const char* msg, ...)
1114 1115 1116
{
  va_list args;
  va_start(args,msg);
1117 1118 1119
  my_vsnprintf(rli->last_slave_error,
	       sizeof(rli->last_slave_error), msg, args);
  rli->last_slave_errno = err_code;
1120 1121
  /* If the error string ends with '.', do not add a ',' it would be ugly */
  if (rli->last_slave_error[0] && 
1122 1123
      (*(strend(rli->last_slave_error)-1) == '.'))
    sql_print_error("Slave: %s Error_code: %d", rli->last_slave_error,
1124 1125
                    err_code);
  else
1126
    sql_print_error("Slave: %s, Error_code: %d", rli->last_slave_error,
1127 1128
                    err_code);

1129 1130
}

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1131
/*
1132 1133
  skip_load_data_infile()

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1134 1135 1136
  NOTES
    This is used to tell a 3.23 master to break send_file()
*/
1137 1138 1139 1140 1141 1142 1143 1144

void skip_load_data_infile(NET *net)
{
  (void)net_request_file(net, "/dev/null");
  (void)my_net_read(net);				// discard response
  (void)net_write_command(net, 0, "", 0, "", 0);	// Send ok
}

1145

1146
bool net_request_file(NET* net, const char* fname)
1147
{
1148 1149
  DBUG_ENTER("net_request_file");
  DBUG_RETURN(net_write_command(net, 251, fname, strlen(fname), "", 0));
1150 1151
}

1152

1153
const char *rewrite_db(const char* db, uint32 *new_len)
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
1154
{
1155 1156
  if (replicate_rewrite_db.is_empty() || !db)
    return db;
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
1157 1158 1159
  I_List_iterator<i_string_pair> it(replicate_rewrite_db);
  i_string_pair* tmp;

1160 1161 1162
  while ((tmp=it++))
  {
    if (!strcmp(tmp->key, db))
1163
    {
1164
      *new_len= (uint32)strlen(tmp->val);
1165
      return tmp->val;
1166
    }
1167
  }
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
1168 1169
  return db;
}
1170

1171 1172
/*
  From other comments and tests in code, it looks like
1173
  sometimes Query_log_event and Load_log_event can have db == 0
1174 1175 1176
  (see rewrite_db() above for example)
  (cases where this happens are unclear; it may be when the master is 3.23).
*/
1177 1178

const char *print_slave_db_safe(const char* db)
1179
{
1180
  return (db ? db : "");
1181
}
1182

1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
/*
  Checks whether a db matches some do_db and ignore_db rules
  (for logging or replication)

  SYNOPSIS
    db_ok()
    db              name of the db to check
    do_list         either binlog_do_db or replicate_do_db
    ignore_list     either binlog_ignore_db or replicate_ignore_db

  RETURN VALUES
    0           should not be logged/replicated
    1           should be logged/replicated                  
*/
1197

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1198 1199 1200
int db_ok(const char* db, I_List<i_string> &do_list,
	  I_List<i_string> &ignore_list )
{
1201
  if (do_list.is_empty() && ignore_list.is_empty())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1202 1203
    return 1; // ok to replicate if the user puts no constraints

1204 1205 1206 1207 1208
  /*
    If the user has specified restrictions on which databases to replicate
    and db was not selected, do not replicate.
  */
  if (!db)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1209
    return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1210

1211 1212 1213 1214
  if (!do_list.is_empty()) // if the do's are not empty
  {
    I_List_iterator<i_string> it(do_list);
    i_string* tmp;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1215

1216 1217 1218 1219
    while ((tmp=it++))
    {
      if (!strcmp(tmp->ptr, db))
	return 1; // match
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1220
    }
1221 1222
    return 0;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1223
  else // there are some elements in the don't, otherwise we cannot get here
1224 1225 1226
  {
    I_List_iterator<i_string> it(ignore_list);
    i_string* tmp;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1227

1228 1229 1230 1231
    while ((tmp=it++))
    {
      if (!strcmp(tmp->ptr, db))
	return 0; // match
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1232
    }
1233 1234
    return 1;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1235 1236
}

1237

1238 1239
static int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
				 const char *default_val)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1240
{
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1241 1242 1243 1244 1245 1246 1247
  uint length;
  if ((length=my_b_gets(f,var, max_size)))
  {
    char* last_p = var + length -1;
    if (*last_p == '\n')
      *last_p = 0; // if we stopped on newline, kill it
    else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1248
    {
1249 1250 1251 1252
      /*
	If we truncated a line or stopped on last char, remove all chars
	up to and including newline.
      */
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1253
      int c;
1254
      while (((c=my_b_get(f)) != '\n' && c != my_b_EOF));
1255
    }
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1256 1257 1258 1259
    return 0;
  }
  else if (default_val)
  {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1260
    strmake(var,  default_val, max_size-1);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1261 1262
    return 0;
  }
1263
  return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1264 1265
}

1266

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1267
static int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1268 1269 1270
{
  char buf[32];
  
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1271 1272 1273 1274 1275
  if (my_b_gets(f, buf, sizeof(buf))) 
  {
    *var = atoi(buf);
    return 0;
  }
1276
  else if (default_val)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1277 1278 1279 1280
  {
    *var = default_val;
    return 0;
  }
1281
  return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1282 1283
}

1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296
/*
  Note that we rely on the master's version (3.23, 4.0.14 etc) instead of
  relying on the binlog's version. This is not perfect: imagine an upgrade
  of the master without waiting that all slaves are in sync with the master;
  then a slave could be fooled about the binlog's format. This is what happens
  when people upgrade a 3.23 master to 4.0 without doing RESET MASTER: 4.0
  slaves are fooled. So we do this only to distinguish between 3.23 and more
  recent masters (it's too late to change things for 3.23).
  
  RETURNS
  0       ok
  1       error
*/
1297

guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1298
static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi)
1299
{
1300
  const char* errmsg= 0;
1301 1302 1303 1304 1305 1306 1307

  /*
    Free old description_event_for_queue (that is needed if we are in
    a reconnection).
  */
  delete mi->rli.relay_log.description_event_for_queue;
  mi->rli.relay_log.description_event_for_queue= 0;
1308
  
1309
  if (!my_isdigit(&my_charset_bin,*mysql->server_version))
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
1310
    errmsg = "Master reported unrecognized MySQL version";
1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343
  else
  {
    /*
      Note the following switch will bug when we have MySQL branch 30 ;)
    */
    switch (*mysql->server_version) 
    {
    case '0':
    case '1':
    case '2':
      errmsg = "Master reported unrecognized MySQL version";
      break;
    case '3':
      mi->rli.relay_log.description_event_for_queue= new
        Format_description_log_event(1, mysql->server_version); 
      break;
    case '4':
      mi->rli.relay_log.description_event_for_queue= new
        Format_description_log_event(3, mysql->server_version); 
      break;
    default: 
      /*
        Master is MySQL >=5.0. Give a default Format_desc event, so that we can
        take the early steps (like tests for "is this a 3.23 master") which we
        have to take before we receive the real master's Format_desc which will
        override this one. Note that the Format_desc we create below is garbage
        (it has the format of the *slave*); it's only good to help know if the
        master is 3.23, 4.0, etc.
      */
      mi->rli.relay_log.description_event_for_queue= new
        Format_description_log_event(4, mysql->server_version); 
      break;
    }
1344
  }
1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357
  
  /* 
     This does not mean that a 5.0 slave will be able to read a 6.0 master; but
     as we don't know yet, we don't want to forbid this for now. If a 5.0 slave
     can't read a 6.0 master, this will show up when the slave can't read some
     events sent by the master, and there will be error messages.
  */
  
  if (errmsg)
  {
    sql_print_error(errmsg);
    return 1;
  }
1358 1359 1360 1361 1362 1363 1364 1365

  /* as we are here, we tried to allocate the event */
  if (!mi->rli.relay_log.description_event_for_queue)
  {
    sql_print_error("Slave I/O thread failed to create a default Format_description_log_event");
    return 1;
  }

1366 1367 1368 1369 1370 1371 1372 1373 1374 1375
  /*
    Compare the master and slave's clock. Do not die if master's clock is
    unavailable (very old master not supporting UNIX_TIMESTAMP()?).
  */
  MYSQL_RES *master_res= 0;
  MYSQL_ROW master_row;
  
  if (!mysql_real_query(mysql, "SELECT UNIX_TIMESTAMP()", 23) &&
      (master_res= mysql_store_result(mysql)) &&
      (master_row= mysql_fetch_row(master_res)))
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1376
  {
1377 1378
    mi->clock_diff_with_master= 
      (long) (time((time_t*) 0) - strtoul(master_row[0], 0, 10));
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1379
  }
1380
  else
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1381
  {
1382
    mi->clock_diff_with_master= 0; /* The "most sensible" value */
1383
    sql_print_warning("\"SELECT UNIX_TIMESTAMP()\" failed on master, \
1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409
do not trust column Seconds_Behind_Master of SHOW SLAVE STATUS");
  }
  if (master_res)
    mysql_free_result(master_res);      
 
  /*
    Check that the master's server id and ours are different. Because if they
    are equal (which can result from a simple copy of master's datadir to slave,
    thus copying some my.cnf), replication will work but all events will be
    skipped.
    Do not die if SHOW VARIABLES LIKE 'SERVER_ID' fails on master (very old
    master?).
    Note: we could have put a @@SERVER_ID in the previous SELECT
    UNIX_TIMESTAMP() instead, but this would not have worked on 3.23 masters.
  */
  if (!mysql_real_query(mysql, "SHOW VARIABLES LIKE 'SERVER_ID'", 31) &&
      (master_res= mysql_store_result(mysql)))
  {
    if ((master_row= mysql_fetch_row(master_res)) &&
        (::server_id == strtoul(master_row[1], 0, 10)) &&
        !replicate_same_server_id)
      errmsg= "The slave I/O thread stops because master and slave have equal \
MySQL server ids; these ids must be different for replication to work (or \
the --replicate-same-server-id option must be used on slave but this does \
not always make sense; please check the manual before using it).";
    mysql_free_result(master_res);
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1410 1411
  }

1412 1413 1414
  /*
    Check that the master's global character_set_server and ours are the same.
    Not fatal if query fails (old master?).
1415 1416 1417 1418 1419 1420
    Note that we don't check for equality of global character_set_client and
    collation_connection (neither do we prevent their setting in
    set_var.cc). That's because from what I (Guilhem) have tested, the global
    values of these 2 are never used (new connections don't use them).
    We don't test equality of global collation_database either as it's is
    going to be deprecated (made read-only) in 4.1 very soon.
1421 1422 1423
  */
  if (!mysql_real_query(mysql, "SELECT @@GLOBAL.COLLATION_SERVER", 32) &&
      (master_res= mysql_store_result(mysql)))
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1424
  {
1425 1426 1427 1428 1429 1430
    if ((master_row= mysql_fetch_row(master_res)) &&
        strcmp(master_row[0], global_system_variables.collation_server->name))
      errmsg= "The slave I/O thread stops because master and slave have \
different values for the COLLATION_SERVER global variable. The values must \
be equal for replication to work";
    mysql_free_result(master_res);
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1431
  }
1432

1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447
  /*
    Perform analogous check for time zone. Theoretically we also should
    perform check here to verify that SYSTEM time zones are the same on
    slave and master, but we can't rely on value of @@system_time_zone
    variable (it is time zone abbreviation) since it determined at start
    time and so could differ for slave and master even if they are really
    in the same system time zone. So we are omiting this check and just
    relying on documentation. Also according to Monty there are many users
    who are using replication between servers in various time zones. Hence 
    such check will broke everything for them. (And now everything will 
    work for them because by default both their master and slave will have 
    'SYSTEM' time zone).
  */
  if (!mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) &&
      (master_res= mysql_store_result(mysql)))
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1448
  {
1449 1450 1451 1452 1453 1454 1455
    if ((master_row= mysql_fetch_row(master_res)) &&
        strcmp(master_row[0], 
               global_system_variables.time_zone->get_name()->ptr()))
      errmsg= "The slave I/O thread stops because master and slave have \
different values for the TIME_ZONE global variable. The values must \
be equal for replication to work";
    mysql_free_result(master_res);
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1456 1457
  }

1458 1459 1460 1461 1462
  if (errmsg)
  {
    sql_print_error(errmsg);
    return 1;
  }
1463

1464 1465 1466
  return 0;
}

1467 1468 1469 1470
/*
  Used by fetch_master_table (used by LOAD TABLE tblname FROM MASTER and LOAD
  DATA FROM MASTER). Drops the table (if 'overwrite' is true) and recreates it
  from the dump. Honours replication inclusion/exclusion rules.
1471
  db must be non-zero (guarded by assertion).
1472 1473 1474 1475 1476

  RETURN VALUES
    0           success
    1           error
*/
1477

1478
static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
1479
				  const char* table_name, bool overwrite)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1480
{
1481
  ulong packet_len;
1482 1483
  char *query, *save_db;
  uint32 save_db_length;
1484 1485
  Vio* save_vio;
  HA_CHECK_OPT check_opt;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1486
  TABLE_LIST tables;
1487 1488
  int error= 1;
  handler *file;
1489
  ulong save_options;
1490
  NET *net= &mysql->net;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1491 1492
  DBUG_ENTER("create_table_from_dump");  

1493
  packet_len= my_net_read(net); // read create table statement
1494 1495
  if (packet_len == packet_error)
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1496
    my_message(ER_MASTER_NET_READ, ER(ER_MASTER_NET_READ), MYF(0));
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1497
    DBUG_RETURN(1);
1498 1499 1500
  }
  if (net->read_pos[0] == 255) // error from master
  {
1501 1502 1503 1504
    char *err_msg; 
    err_msg= (char*) net->read_pos + ((mysql->server_capabilities &
				       CLIENT_PROTOCOL_41) ?
				      3+SQLSTATE_LENGTH+1 : 3);
1505
    my_error(ER_MASTER, MYF(0), err_msg);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1506
    DBUG_RETURN(1);
1507
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1508
  thd->command = COM_TABLE_DUMP;
1509
  thd->query_length= packet_len;
1510
  /* Note that we should not set thd->query until the area is initalized */
1511
  if (!(query = thd->strmake((char*) net->read_pos, packet_len)))
1512 1513
  {
    sql_print_error("create_table_from_dump: out of memory");
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1514
    my_message(ER_GET_ERRNO, "Out of memory", MYF(0));
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1515
    DBUG_RETURN(1);
1516
  }
1517
  thd->query= query;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1518 1519
  thd->query_error = 0;
  thd->net.no_send_ok = 1;
1520

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1521 1522 1523
  bzero((char*) &tables,sizeof(tables));
  tables.db = (char*)db;
  tables.alias= tables.real_name= (char*)table_name;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1524

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1525 1526 1527 1528 1529 1530 1531
  /* Drop the table if 'overwrite' is true */
  if (overwrite && mysql_rm_table(thd,&tables,1,0)) /* drop if exists */
  {
    sql_print_error("create_table_from_dump: failed to drop the table");
    goto err;
  }

1532
  /* Create the table. We do not want to log the "create table" statement */
1533
  save_options = thd->options;
1534
  thd->options &= ~(ulong) (OPTION_BIN_LOG);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1535
  thd->proc_info = "Creating table from master dump";
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1536
  // save old db in case we are creating in a different database
1537
  save_db = thd->db;
1538
  save_db_length= thd->db_length;
1539
  thd->db = (char*)db;
1540 1541
  DBUG_ASSERT(thd->db);
  thd->db_length= strlen(thd->db);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1542
  mysql_parse(thd, thd->query, packet_len); // run create table
1543
  thd->db = save_db;		// leave things the way the were before
1544
  thd->db_length= save_db_length;
1545
  thd->options = save_options;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1546
  
1547 1548
  if (thd->query_error)
    goto err;			// mysql_parse took care of the error send
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1549 1550

  thd->proc_info = "Opening master dump table";
1551
  tables.lock_type = TL_WRITE;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1552 1553 1554
  if (!open_ltable(thd, &tables, TL_WRITE))
  {
    sql_print_error("create_table_from_dump: could not open created table");
1555
    goto err;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1556
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1557
  
1558
  file = tables.table->file;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1559
  thd->proc_info = "Reading master dump table data";
1560
  /* Copy the data file */
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1561 1562
  if (file->net_read_dump(net))
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1563
    my_message(ER_MASTER_NET_READ, ER(ER_MASTER_NET_READ), MYF(0));
1564
    sql_print_error("create_table_from_dump: failed in\
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1565
 handler::net_read_dump()");
1566
    goto err;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1567
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1568 1569

  check_opt.init();
serg@serg.mysql.com's avatar
serg@serg.mysql.com committed
1570
  check_opt.flags|= T_VERY_SILENT | T_CALC_CHECKSUM | T_QUICK;
jcole@tetra.spaceapes.com's avatar
jcole@tetra.spaceapes.com committed
1571
  thd->proc_info = "Rebuilding the index on master dump table";
1572 1573 1574 1575 1576
  /*
    We do not want repair() to spam us with messages
    just send them to the error log, and report the failure in case of
    problems.
  */
1577
  save_vio = thd->net.vio;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1578
  thd->net.vio = 0;
1579
  /* Rebuild the index file from the copied data file (with REPAIR) */
1580
  error=file->repair(thd,&check_opt) != 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1581
  thd->net.vio = save_vio;
1582
  if (error)
1583
    my_error(ER_INDEX_REBUILD, MYF(0), tables.table->real_name);
1584 1585

err:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1586 1587
  close_thread_tables(thd);
  thd->net.no_send_ok = 0;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1588
  DBUG_RETURN(error); 
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1589 1590
}

1591

1592
int fetch_master_table(THD *thd, const char *db_name, const char *table_name,
1593
		       MASTER_INFO *mi, MYSQL *mysql, bool overwrite)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1594
{
1595 1596 1597 1598 1599 1600
  int error= 1;
  const char *errmsg=0;
  bool called_connected= (mysql != NULL);
  DBUG_ENTER("fetch_master_table");
  DBUG_PRINT("enter", ("db_name: '%s'  table_name: '%s'",
		       db_name,table_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1601

monty@work.mysql.com's avatar
merge  
monty@work.mysql.com committed
1602
  if (!called_connected)
1603
  { 
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1604
    if (!(mysql = mysql_init(NULL)))
1605 1606 1607
    {
      DBUG_RETURN(1);
    }
monty@work.mysql.com's avatar
merge  
monty@work.mysql.com committed
1608
    if (connect_to_master(thd, mysql, mi))
1609
    {
1610
      my_error(ER_CONNECT_TO_MASTER, MYF(0), mysql_error(mysql));
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1611
      mysql_close(mysql);
1612
      DBUG_RETURN(1);
1613
    }
1614 1615
    if (thd->killed)
      goto err;
1616
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1617

sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
1618
  if (request_table_dump(mysql, db_name, table_name))
1619
  {
1620 1621
    error= ER_UNKNOWN_ERROR;
    errmsg= "Failed on table dump request";
1622 1623
    goto err;
  }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1624 1625 1626
  if (create_table_from_dump(thd, mysql, db_name,
			     table_name, overwrite))
    goto err;    // create_table_from_dump have sent the error already
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1627
  error = 0;
1628

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1629
 err:
1630
  thd->net.no_send_ok = 0; // Clear up garbage after create_table_from_dump
1631
  if (!called_connected)
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1632
    mysql_close(mysql);
1633
  if (errmsg && thd->vio_ok())
1634
    my_message(error, errmsg, MYF(0));
1635
  DBUG_RETURN(test(error));			// Return 1 on error
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1636 1637
}

1638

1639 1640
void end_master_info(MASTER_INFO* mi)
{
1641 1642
  DBUG_ENTER("end_master_info");

1643
  if (!mi->inited)
1644
    DBUG_VOID_RETURN;
1645 1646
  end_relay_log_info(&mi->rli);
  if (mi->fd >= 0)
1647 1648 1649 1650 1651
  {
    end_io_cache(&mi->file);
    (void)my_close(mi->fd, MYF(MY_WME));
    mi->fd = -1;
  }
1652
  mi->inited = 0;
1653 1654

  DBUG_VOID_RETURN;
1655 1656
}

1657

1658 1659 1660 1661 1662 1663
int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
{
  char fname[FN_REFLEN+128];
  int info_fd;
  const char* msg = 0;
  int error = 0;
1664
  DBUG_ENTER("init_relay_log_info");
1665

1666
  if (rli->inited)				// Set if this function called
1667 1668
    DBUG_RETURN(0);
  fn_format(fname, info_fname, mysql_data_home, "", 4+32);
1669 1670 1671 1672
  pthread_mutex_lock(&rli->data_lock);
  info_fd = rli->info_fd;
  rli->cur_log_fd = -1;
  rli->slave_skip_counter=0;
1673
  rli->abort_pos_wait=0;
1674 1675
  rli->log_space_limit= relay_log_space_limit;
  rli->log_space_total= 0;
1676

1677 1678 1679 1680
  // TODO: make this work with multi-master
  if (!opt_relay_logname)
  {
    char tmp[FN_REFLEN];
1681 1682 1683
    /*
      TODO: The following should be using fn_format();  We just need to
      first change fn_format() to cut the file name if it's too long.
1684 1685 1686 1687 1688
    */
    strmake(tmp,glob_hostname,FN_REFLEN-5);
    strmov(strcend(tmp,'.'),"-relay-bin");
    opt_relay_logname=my_strdup(tmp,MYF(MY_WME));
  }
1689 1690

  /*
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1691 1692 1693
    The relay log will now be opened, as a SEQ_READ_APPEND IO_CACHE.
    Note that the I/O thread flushes it to disk after writing every event, in
    flush_master_info(mi, 1).
1694 1695
  */

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1696 1697 1698 1699 1700 1701 1702 1703 1704 1705
  /*
    For the maximum log size, we choose max_relay_log_size if it is
    non-zero, max_binlog_size otherwise. If later the user does SET
    GLOBAL on one of these variables, fix_max_binlog_size and
    fix_max_relay_log_size will reconsider the choice (for example
    if the user changes max_relay_log_size to zero, we have to
    switch to using max_binlog_size for the relay log) and update
    rli->relay_log.max_size (and mysql_bin_log.max_size).
  */

1706 1707 1708
  if (open_log(&rli->relay_log, glob_hostname, opt_relay_logname,
	       "-relay-bin", opt_relaylog_index_name,
	       LOG_BIN, 1 /* read_append cache */,
1709
	       0 /* starting from 5.0 we want relay logs to have auto events */,
1710
               max_relay_log_size ? max_relay_log_size : max_binlog_size))
1711
  {
1712
    pthread_mutex_unlock(&rli->data_lock);
1713
    sql_print_error("Failed in open_log() called from init_relay_log_info()");
1714
    DBUG_RETURN(1);
1715
  }
1716

1717
  /* if file does not exist */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1718
  if (access(fname,F_OK))
1719
  {
1720 1721 1722 1723
    /*
      If someone removed the file from underneath our feet, just close
      the old descriptor and re-create the old file
    */
1724 1725
    if (info_fd >= 0)
      my_close(info_fd, MYF(MY_WME));
1726
    if ((info_fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
1727
    {
1728 1729 1730 1731 1732 1733 1734
      sql_print_error("Failed to create a new relay log info file (\
file '%s', errno %d)", fname, my_errno);
      msg= current_thd->net.last_error;
      goto err;
    }
    if (init_io_cache(&rli->info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0,
		      MYF(MY_WME))) 
1735
    {
1736 1737
      sql_print_error("Failed to create a cache on relay log info file '%s'",
		      fname);
1738 1739
      msg= current_thd->net.last_error;
      goto err;
1740
    }
1741 1742 1743

    /* Init relay log with first entry in the relay index file */
    if (init_relay_log_pos(rli,NullS,BIN_LOG_HEADER_SIZE,0 /* no data lock */,
1744
			   &msg, 0))
1745
    {
1746
      sql_print_error("Failed to open the relay log 'FIRST' (relay_log_pos 4)");
1747
      goto err;
1748
    }
1749 1750
    rli->group_master_log_name[0]= 0;
    rli->group_master_log_pos= 0;		
1751
    rli->info_fd= info_fd;
1752 1753 1754
  }
  else // file exists
  {
1755
    if (info_fd >= 0)
1756
      reinit_io_cache(&rli->info_file, READ_CACHE, 0L,0,0);
1757
    else 
1758
    {
1759 1760 1761
      int error=0;
      if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
      {
1762 1763 1764
        sql_print_error("\
Failed to open the existing relay log info file '%s' (errno %d)",
			fname, my_errno);
1765 1766 1767 1768 1769
        error= 1;
      }
      else if (init_io_cache(&rli->info_file, info_fd,
                             IO_SIZE*2, READ_CACHE, 0L, 0, MYF(MY_WME)))
      {
1770 1771
        sql_print_error("Failed to create a cache on relay log info file '%s'",
			fname);
1772 1773 1774 1775 1776 1777 1778
        error= 1;
      }
      if (error)
      {
        if (info_fd >= 0)
          my_close(info_fd, MYF(0));
        rli->info_fd= -1;
1779
        rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
1780 1781 1782
        pthread_mutex_unlock(&rli->data_lock);
        DBUG_RETURN(1);
      }
1783
    }
1784
         
1785
    rli->info_fd = info_fd;
1786
    int relay_log_pos, master_log_pos;
1787
    if (init_strvar_from_file(rli->group_relay_log_name,
monty@mysql.com's avatar
monty@mysql.com committed
1788 1789
			      sizeof(rli->group_relay_log_name),
                              &rli->info_file, "") ||
1790
       init_intvar_from_file(&relay_log_pos,
1791
			     &rli->info_file, BIN_LOG_HEADER_SIZE) ||
1792
       init_strvar_from_file(rli->group_master_log_name,
monty@mysql.com's avatar
monty@mysql.com committed
1793 1794
			     sizeof(rli->group_master_log_name),
                             &rli->info_file, "") ||
1795
       init_intvar_from_file(&master_log_pos, &rli->info_file, 0))
1796 1797 1798 1799
    {
      msg="Error reading slave log configuration";
      goto err;
    }
1800 1801 1802 1803
    strmake(rli->event_relay_log_name,rli->group_relay_log_name,
            sizeof(rli->event_relay_log_name)-1);
    rli->group_relay_log_pos= rli->event_relay_log_pos= relay_log_pos;
    rli->group_master_log_pos= master_log_pos;
1804

1805
    if (init_relay_log_pos(rli,
1806 1807
			   rli->group_relay_log_name,
			   rli->group_relay_log_pos,
1808
			   0 /* no data lock*/,
1809
			   &msg, 0))
1810 1811
    {
      char llbuf[22];
1812
      sql_print_error("Failed to open the relay log '%s' (relay_log_pos %s)",
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1813 1814
		      rli->group_relay_log_name,
		      llstr(rli->group_relay_log_pos, llbuf));
1815
      goto err;
1816
    }
1817
  }
1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829

#ifndef DBUG_OFF
  {
    char llbuf1[22], llbuf2[22];
    DBUG_PRINT("info", ("my_b_tell(rli->cur_log)=%s rli->event_relay_log_pos=%s",
                        llstr(my_b_tell(rli->cur_log),llbuf1), 
                        llstr(rli->event_relay_log_pos,llbuf2)));
    DBUG_ASSERT(rli->event_relay_log_pos >= BIN_LOG_HEADER_SIZE);
    DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->event_relay_log_pos);
  }
#endif

1830 1831 1832 1833
  /*
    Now change the cache from READ to WRITE - must do this
    before flush_relay_log_info
  */
1834
  reinit_io_cache(&rli->info_file, WRITE_CACHE,0L,0,1);
1835 1836
  if ((error= flush_relay_log_info(rli)))
    sql_print_error("Failed to flush relay log info file");
1837 1838 1839 1840 1841
  if (count_relay_log_space(rli))
  {
    msg="Error counting relay log space";
    goto err;
  }
1842
  rli->inited= 1;
1843
  pthread_mutex_unlock(&rli->data_lock);
1844
  DBUG_RETURN(error);
1845 1846 1847 1848

err:
  sql_print_error(msg);
  end_io_cache(&rli->info_file);
1849 1850
  if (info_fd >= 0)
    my_close(info_fd, MYF(0));
1851
  rli->info_fd= -1;
1852
  rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
1853
  pthread_mutex_unlock(&rli->data_lock);
1854
  DBUG_RETURN(1);
1855 1856
}

1857

1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871
static inline int add_relay_log(RELAY_LOG_INFO* rli,LOG_INFO* linfo)
{
  MY_STAT s;
  DBUG_ENTER("add_relay_log");
  if (!my_stat(linfo->log_file_name,&s,MYF(0)))
  {
    sql_print_error("log %s listed in the index, but failed to stat",
		    linfo->log_file_name);
    DBUG_RETURN(1);
  }
  rli->log_space_total += s.st_size;
#ifndef DBUG_OFF
  char buf[22];
  DBUG_PRINT("info",("log_space_total: %s", llstr(rli->log_space_total,buf)));
1872
#endif  
1873 1874 1875
  DBUG_RETURN(0);
}

1876

1877 1878
static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli)
{
1879
  bool slave_killed=0;
1880
  MASTER_INFO* mi = rli->mi;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1881
  const char *save_proc_info;
1882
  THD* thd = mi->io_thd;
1883

1884
  DBUG_ENTER("wait_for_relay_log_space");
1885

1886
  pthread_mutex_lock(&rli->log_space_lock);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1887 1888
  save_proc_info= thd->enter_cond(&rli->log_space_cond,
				  &rli->log_space_lock, 
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1889
				  "\
1890
Waiting for the slave SQL thread to free enough relay log space");
1891
  while (rli->log_space_limit < rli->log_space_total &&
1892 1893
	 !(slave_killed=io_slave_killed(thd,mi)) &&
         !rli->ignore_log_space_limit)
1894
    pthread_cond_wait(&rli->log_space_cond, &rli->log_space_lock);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
1895
  thd->exit_cond(save_proc_info);
1896 1897 1898
  DBUG_RETURN(slave_killed);
}

1899

1900 1901 1902 1903
static int count_relay_log_space(RELAY_LOG_INFO* rli)
{
  LOG_INFO linfo;
  DBUG_ENTER("count_relay_log_space");
1904
  rli->log_space_total= 0;
1905
  if (rli->relay_log.find_log_pos(&linfo, NullS, 1))
1906 1907 1908 1909
  {
    sql_print_error("Could not find first log while counting relay log space");
    DBUG_RETURN(1);
  }
1910
  do
1911 1912 1913
  {
    if (add_relay_log(rli,&linfo))
      DBUG_RETURN(1);
1914
  } while (!rli->relay_log.find_next_log(&linfo, 1));
1915 1916 1917 1918 1919 1920
  /* 
     As we have counted everything, including what may have written in a
     preceding write, we must reset bytes_written, or we may count some space 
     twice.
  */
  rli->relay_log.reset_bytes_written();
1921 1922
  DBUG_RETURN(0);
}
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1923

1924

guilhem@mysql.com's avatar
guilhem@mysql.com committed
1925 1926 1927 1928 1929 1930 1931 1932 1933 1934
void init_master_info_with_options(MASTER_INFO* mi)
{
  mi->master_log_name[0] = 0;
  mi->master_log_pos = BIN_LOG_HEADER_SIZE;		// skip magic number
  
  if (master_host)
    strmake(mi->host, master_host, sizeof(mi->host) - 1);
  if (master_user)
    strmake(mi->user, master_user, sizeof(mi->user) - 1);
  if (master_password)
kostja@oak.local's avatar
kostja@oak.local committed
1935
    strmake(mi->password, master_password, MAX_PASSWORD_LENGTH);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
1936 1937
  mi->port = master_port;
  mi->connect_retry = master_connect_retry;
dlenev@mysql.com's avatar
dlenev@mysql.com committed
1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949
  
  mi->ssl= master_ssl;
  if (master_ssl_ca)
    strmake(mi->ssl_ca, master_ssl_ca, sizeof(mi->ssl_ca)-1);
  if (master_ssl_capath)
    strmake(mi->ssl_capath, master_ssl_capath, sizeof(mi->ssl_capath)-1);
  if (master_ssl_cert)
    strmake(mi->ssl_cert, master_ssl_cert, sizeof(mi->ssl_cert)-1);
  if (master_ssl_cipher)
    strmake(mi->ssl_cipher, master_ssl_cipher, sizeof(mi->ssl_cipher)-1);
  if (master_ssl_key)
    strmake(mi->ssl_key, master_ssl_key, sizeof(mi->ssl_key)-1);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
1950 1951
}

guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1952
static void clear_slave_error(RELAY_LOG_INFO* rli)
guilhem@mysql.com's avatar
guilhem@mysql.com committed
1953
{
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1954 1955 1956
  /* Clear the errors displayed by SHOW SLAVE STATUS */
  rli->last_slave_error[0]= 0;
  rli->last_slave_errno= 0;
guilhem@mysql.com's avatar
guilhem@mysql.com committed
1957
}
1958

guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1959 1960 1961 1962 1963
void clear_slave_error_timestamp(RELAY_LOG_INFO* rli)
{
  rli->last_master_timestamp= 0;
  clear_slave_error(rli);
}
dlenev@mysql.com's avatar
dlenev@mysql.com committed
1964

1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978
/*
    Reset UNTIL condition for RELAY_LOG_INFO
   SYNOPSYS
    clear_until_condition()
      rli - RELAY_LOG_INFO structure where UNTIL condition should be reset
 */
void clear_until_condition(RELAY_LOG_INFO* rli)
{
  rli->until_condition= RELAY_LOG_INFO::UNTIL_NONE;
  rli->until_log_name[0]= 0;
  rli->until_log_pos= 0;
}


1979
#define LINES_IN_MASTER_INFO_WITH_SSL 14
1980

dlenev@mysql.com's avatar
dlenev@mysql.com committed
1981

1982
int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
1983 1984
		     const char* slave_info_fname,
		     bool abort_if_no_master_info_file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1985
{
1986 1987 1988 1989
  int fd,error;
  char fname[FN_REFLEN+128];
  DBUG_ENTER("init_master_info");

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1990
  if (mi->inited)
1991 1992 1993 1994 1995 1996 1997 1998 1999
  {
    /*
      We have to reset read position of relay-log-bin as we may have
      already been reading from 'hotlog' when the slave was stopped
      last time. If this case pos_in_file would be set and we would
      get a crash when trying to read the signature for the binary
      relay log.
    */
    my_b_seek(mi->rli.cur_log, (my_off_t) 0);
2000
    DBUG_RETURN(0);
2001 2002
  }

2003 2004
  mi->mysql=0;
  mi->file_id=1;
2005
  fn_format(fname, master_info_fname, mysql_data_home, "", 4+32);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2006

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2007 2008 2009 2010
  /*
    We need a mutex while we are changing master info parameters to
    keep other threads from reading bogus info
  */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2011

2012
  pthread_mutex_lock(&mi->data_lock);
2013
  fd = mi->fd;
2014 2015

  /* does master.info exist ? */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2016
  
2017
  if (access(fname,F_OK))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2018
  {
2019 2020 2021 2022 2023
    if (abort_if_no_master_info_file)
    {
      pthread_mutex_unlock(&mi->data_lock);
      DBUG_RETURN(0);
    }
2024 2025 2026 2027
    /*
      if someone removed the file from underneath our feet, just close
      the old descriptor and re-create the old file
    */
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2028 2029
    if (fd >= 0)
      my_close(fd, MYF(MY_WME));
2030 2031 2032 2033 2034 2035 2036
    if ((fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
    {
      sql_print_error("Failed to create a new master info file (\
file '%s', errno %d)", fname, my_errno);
      goto err;
    }
    if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,0,
2037
		      MYF(MY_WME)))
2038 2039 2040
    {
      sql_print_error("Failed to create a cache on master info file (\
file '%s')", fname);
2041
      goto err;
2042
    }
2043

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2044
    mi->fd = fd;
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2045 2046
    init_master_info_with_options(mi);

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2047
  }
2048
  else // file exists
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2049
  {
2050
    if (fd >= 0)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2051
      reinit_io_cache(&mi->file, READ_CACHE, 0L,0,0);
2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067
    else 
    {
      if ((fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
      {
        sql_print_error("Failed to open the existing master info file (\
file '%s', errno %d)", fname, my_errno);
        goto err;
      }
      if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,
                        0, MYF(MY_WME)))
      {
        sql_print_error("Failed to create a cache on master info file (\
file '%s')", fname);
        goto err;
      }
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2068

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2069
    mi->fd = fd;
2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095
    int port, connect_retry, master_log_pos, ssl= 0, lines;
    char *first_non_digit;
    
    /*
       Starting from 4.1.x master.info has new format. Now its
       first line contains number of lines in file. By reading this 
       number we will be always distinguish to which version our 
       master.info corresponds to. We can't simply count lines in 
       file since versions before 4.1.x could generate files with more
       lines than needed.
       If first line doesn't contain a number or contain number less than 
       14 then such file is treated like file from pre 4.1.1 version.
       There is no ambiguity when reading an old master.info, as before 
       4.1.1, the first line contained the binlog's name, which is either
       empty or has an extension (contains a '.'), so can't be confused 
       with an integer.

       So we're just reading first line and trying to figure which version 
       is this.
    */
    
    /* 
       The first row is temporarily stored in mi->master_log_name, 
       if it is line count and not binlog name (new format) it will be 
       overwritten by the second row later.
    */
2096
    if (init_strvar_from_file(mi->master_log_name,
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2097
			      sizeof(mi->master_log_name), &mi->file,
2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113
			      ""))
      goto errwithmsg;
    
    lines= strtoul(mi->master_log_name, &first_non_digit, 10);

    if (mi->master_log_name[0]!='\0' && 
        *first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL)
    {                                          // Seems to be new format
      if (init_strvar_from_file(mi->master_log_name,     
            sizeof(mi->master_log_name), &mi->file, ""))
        goto errwithmsg;
    }
    else
      lines= 7;
    
    if (init_intvar_from_file(&master_log_pos, &mi->file, 4) ||
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2114 2115 2116 2117
	init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file,
			      master_host) ||
	init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file,
			      master_user) || 
2118 2119
        init_strvar_from_file(mi->password, SCRAMBLED_PASSWORD_CHAR_LENGTH+1,
                              &mi->file, master_password) ||
2120 2121
	init_intvar_from_file(&port, &mi->file, master_port) ||
	init_intvar_from_file(&connect_retry, &mi->file,
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2122
			      master_connect_retry))
2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145
      goto errwithmsg;

    /* 
       If file has ssl part use it even if we have server without 
       SSL support. But these option will be ignored later when 
       slave will try connect to master, so in this case warning 
       is printed.
     */
    if (lines >= LINES_IN_MASTER_INFO_WITH_SSL && 
        (init_intvar_from_file(&ssl, &mi->file, master_ssl) ||
         init_strvar_from_file(mi->ssl_ca, sizeof(mi->ssl_ca), 
                               &mi->file, master_ssl_ca) ||
         init_strvar_from_file(mi->ssl_capath, sizeof(mi->ssl_capath), 
                               &mi->file, master_ssl_capath) ||
         init_strvar_from_file(mi->ssl_cert, sizeof(mi->ssl_cert),
                               &mi->file, master_ssl_cert) ||
         init_strvar_from_file(mi->ssl_cipher, sizeof(mi->ssl_cipher),
                               &mi->file, master_ssl_cipher) ||
         init_strvar_from_file(mi->ssl_key, sizeof(mi->ssl_key),
                              &mi->file, master_ssl_key)))
      goto errwithmsg;
#ifndef HAVE_OPENSSL
    if (ssl)
2146
      sql_print_warning("SSL information in the master info file "
2147 2148 2149 2150
                      "('%s') are ignored because this MySQL slave was compiled "
                      "without SSL support.", fname);
#endif /* HAVE_OPENSSL */
    
2151 2152 2153 2154 2155 2156 2157
    /*
      This has to be handled here as init_intvar_from_file can't handle
      my_off_t types
    */
    mi->master_log_pos= (my_off_t) master_log_pos;
    mi->port= (uint) port;
    mi->connect_retry= (uint) connect_retry;
2158
    mi->ssl= (my_bool) ssl;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2159
  }
2160 2161 2162
  DBUG_PRINT("master_info",("log_file_name: %s  position: %ld",
			    mi->master_log_name,
			    (ulong) mi->master_log_pos));
2163

2164
  mi->rli.mi = mi;
2165 2166 2167
  if (init_relay_log_info(&mi->rli, slave_info_fname))
    goto err;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2168
  mi->inited = 1;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2169
  // now change cache READ -> WRITE - must do this before flush_master_info
2170
  reinit_io_cache(&mi->file, WRITE_CACHE,0L,0,1);
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2171
  if ((error=test(flush_master_info(mi, 1))))
2172
    sql_print_error("Failed to flush master info file");
2173
  pthread_mutex_unlock(&mi->data_lock);
2174
  DBUG_RETURN(error);
2175 2176 2177 2178
  
errwithmsg:
  sql_print_error("Error reading master configuration");
  
2179
err:
2180 2181 2182 2183 2184 2185
  if (fd >= 0)
  {
    my_close(fd, MYF(0));
    end_io_cache(&mi->file);
  }
  mi->fd= -1;
2186
  pthread_mutex_unlock(&mi->data_lock);
2187
  DBUG_RETURN(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2188 2189
}

2190

2191 2192
int register_slave_on_master(MYSQL* mysql)
{
2193 2194
  char buf[1024], *pos= buf;
  uint report_host_len, report_user_len=0, report_password_len=0;
2195

2196
  if (!report_host)
2197
    return 0;
2198
  report_host_len= strlen(report_host);
2199
  if (report_user)
2200
    report_user_len= strlen(report_user);
2201
  if (report_password)
2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216
    report_password_len= strlen(report_password);
  /* 30 is a good safety margin */
  if (report_host_len + report_user_len + report_password_len + 30 >
      sizeof(buf))
    return 0;					// safety

  int4store(pos, server_id); pos+= 4;
  pos= net_store_data(pos, report_host, report_host_len); 
  pos= net_store_data(pos, report_user, report_user_len);
  pos= net_store_data(pos, report_password, report_password_len);
  int2store(pos, (uint16) report_port); pos+= 2;
  int4store(pos, rpl_recovery_rank);	pos+= 4;
  /* The master will fill in master_id */
  int4store(pos, 0);			pos+= 4;

hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2217
  if (simple_command(mysql, COM_REGISTER_SLAVE, (char*) buf,
2218
			(uint) (pos- buf), 0))
2219
  {
2220
    sql_print_error("Error on COM_REGISTER_SLAVE: %d '%s'",
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2221 2222
		    mysql_errno(mysql),
		    mysql_error(mysql));
2223 2224 2225 2226 2227
    return 1;
  }
  return 0;
}

2228

2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270
/*
  Builds a String from a HASH of TABLE_RULE_ENT. Cannot be used for any other 
  hash, as it assumes that the hash entries are TABLE_RULE_ENT.

  SYNOPSIS
    table_rule_ent_hash_to_str()
    s               pointer to the String to fill
    h               pointer to the HASH to read

  RETURN VALUES
    none
*/

void table_rule_ent_hash_to_str(String* s, HASH* h)
{
  s->length(0);
  for (uint i=0 ; i < h->records ; i++)
  {
    TABLE_RULE_ENT* e= (TABLE_RULE_ENT*) hash_element(h, i);
    if (s->length())
      s->append(',');
    s->append(e->db,e->key_len);
  }
}

/*
  Mostly the same thing as above
*/

void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a)
{
  s->length(0);
  for (uint i=0 ; i < a->elements ; i++)
  {
    TABLE_RULE_ENT* e;
    get_dynamic(a, (gptr)&e, i);
    if (s->length())
      s->append(',');
    s->append(e->db,e->key_len);
  }
}

2271
bool show_master_info(THD* thd, MASTER_INFO* mi)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2272
{
2273
  // TODO: fix this for multi-master
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2274
  List<Item> field_list;
2275 2276 2277
  Protocol *protocol= thd->protocol;
  DBUG_ENTER("show_master_info");

guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2278 2279
  field_list.push_back(new Item_empty_string("Slave_IO_State",
						     14));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2280
  field_list.push_back(new Item_empty_string("Master_Host",
2281
						     sizeof(mi->host)));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2282
  field_list.push_back(new Item_empty_string("Master_User",
2283
						     sizeof(mi->user)));
2284 2285
  field_list.push_back(new Item_return_int("Master_Port", 7,
					   MYSQL_TYPE_LONG));
2286
  field_list.push_back(new Item_return_int("Connect_Retry", 10,
2287
					   MYSQL_TYPE_LONG));
2288
  field_list.push_back(new Item_empty_string("Master_Log_File",
2289 2290 2291
					     FN_REFLEN));
  field_list.push_back(new Item_return_int("Read_Master_Log_Pos", 10,
					   MYSQL_TYPE_LONGLONG));
2292
  field_list.push_back(new Item_empty_string("Relay_Log_File",
2293 2294 2295
					     FN_REFLEN));
  field_list.push_back(new Item_return_int("Relay_Log_Pos", 10,
					   MYSQL_TYPE_LONGLONG));
2296
  field_list.push_back(new Item_empty_string("Relay_Master_Log_File",
2297
					     FN_REFLEN));
2298 2299
  field_list.push_back(new Item_empty_string("Slave_IO_Running", 3));
  field_list.push_back(new Item_empty_string("Slave_SQL_Running", 3));
2300 2301 2302 2303 2304 2305
  field_list.push_back(new Item_empty_string("Replicate_Do_DB", 20));
  field_list.push_back(new Item_empty_string("Replicate_Ignore_DB", 20));
  field_list.push_back(new Item_empty_string("Replicate_Do_Table", 20));
  field_list.push_back(new Item_empty_string("Replicate_Ignore_Table", 23));
  field_list.push_back(new Item_empty_string("Replicate_Wild_Do_Table", 24));
  field_list.push_back(new Item_empty_string("Replicate_Wild_Ignore_Table",
2306
					     28));
2307 2308 2309
  field_list.push_back(new Item_return_int("Last_Errno", 4, MYSQL_TYPE_LONG));
  field_list.push_back(new Item_empty_string("Last_Error", 20));
  field_list.push_back(new Item_return_int("Skip_Counter", 10,
2310
					   MYSQL_TYPE_LONG));
2311
  field_list.push_back(new Item_return_int("Exec_Master_Log_Pos", 10,
2312
					   MYSQL_TYPE_LONGLONG));
2313
  field_list.push_back(new Item_return_int("Relay_Log_Space", 10,
2314
					   MYSQL_TYPE_LONGLONG));
2315
  field_list.push_back(new Item_empty_string("Until_Condition", 6));
2316
  field_list.push_back(new Item_empty_string("Until_Log_File", FN_REFLEN));
2317
  field_list.push_back(new Item_return_int("Until_Log_Pos", 10, 
2318
                                           MYSQL_TYPE_LONGLONG));
2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329
  field_list.push_back(new Item_empty_string("Master_SSL_Allowed", 7));
  field_list.push_back(new Item_empty_string("Master_SSL_CA_File",
                                             sizeof(mi->ssl_ca)));
  field_list.push_back(new Item_empty_string("Master_SSL_CA_Path", 
                                             sizeof(mi->ssl_capath)));
  field_list.push_back(new Item_empty_string("Master_SSL_Cert", 
                                             sizeof(mi->ssl_cert)));
  field_list.push_back(new Item_empty_string("Master_SSL_Cipher", 
                                             sizeof(mi->ssl_cipher)));
  field_list.push_back(new Item_empty_string("Master_SSL_Key", 
                                             sizeof(mi->ssl_key)));
2330
  field_list.push_back(new Item_return_int("Seconds_Behind_Master", 10,
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2331
                                           MYSQL_TYPE_LONGLONG));
2332
  
2333 2334
  if (protocol->send_fields(&field_list,
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
2335
    DBUG_RETURN(TRUE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2336

2337 2338
  if (mi->host[0])
  {
2339
    DBUG_PRINT("info",("host is set: '%s'", mi->host));
2340
    String *packet= &thd->packet;
2341
    protocol->prepare_for_resend();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2342
  
2343 2344
    pthread_mutex_lock(&mi->data_lock);
    pthread_mutex_lock(&mi->rli.data_lock);
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2345 2346

    protocol->store(mi->io_thd ? mi->io_thd->proc_info : "", &my_charset_bin);
2347 2348
    protocol->store(mi->host, &my_charset_bin);
    protocol->store(mi->user, &my_charset_bin);
2349 2350
    protocol->store((uint32) mi->port);
    protocol->store((uint32) mi->connect_retry);
2351
    protocol->store(mi->master_log_name, &my_charset_bin);
2352
    protocol->store((ulonglong) mi->master_log_pos);
2353
    protocol->store(mi->rli.group_relay_log_name +
2354 2355
		    dirname_length(mi->rli.group_relay_log_name),
		    &my_charset_bin);
2356 2357
    protocol->store((ulonglong) mi->rli.group_relay_log_pos);
    protocol->store(mi->rli.group_master_log_name, &my_charset_bin);
2358 2359
    protocol->store(mi->slave_running ? "Yes":"No", &my_charset_bin);
    protocol->store(mi->rli.slave_running ? "Yes":"No", &my_charset_bin);
2360 2361
    protocol->store(&replicate_do_db);
    protocol->store(&replicate_ignore_db);
2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378
    /*
      We can't directly use some protocol->store for 
      replicate_*_table,
      as Protocol doesn't know the TABLE_RULE_ENT struct.
      We first build Strings and then pass them to protocol->store.
    */
    char buf[256];
    String tmp(buf, sizeof(buf), &my_charset_bin);
    table_rule_ent_hash_to_str(&tmp, &replicate_do_table);
    protocol->store(&tmp);
    table_rule_ent_hash_to_str(&tmp, &replicate_ignore_table);
    protocol->store(&tmp);
    table_rule_ent_dynamic_array_to_str(&tmp, &replicate_wild_do_table);
    protocol->store(&tmp);
    table_rule_ent_dynamic_array_to_str(&tmp, &replicate_wild_ignore_table);
    protocol->store(&tmp);

2379
    protocol->store((uint32) mi->rli.last_slave_errno);
2380
    protocol->store(mi->rli.last_slave_error, &my_charset_bin);
2381
    protocol->store((uint32) mi->rli.slave_skip_counter);
2382
    protocol->store((ulonglong) mi->rli.group_master_log_pos);
2383
    protocol->store((ulonglong) mi->rli.log_space_total);
2384 2385 2386 2387 2388 2389 2390 2391

    protocol->store(
      mi->rli.until_condition==RELAY_LOG_INFO::UNTIL_NONE ? "None": 
        ( mi->rli.until_condition==RELAY_LOG_INFO::UNTIL_MASTER_POS? "Master":
          "Relay"), &my_charset_bin);
    protocol->store(mi->rli.until_log_name, &my_charset_bin);
    protocol->store((ulonglong) mi->rli.until_log_pos);
    
2392 2393 2394 2395 2396 2397 2398 2399 2400 2401
#ifdef HAVE_OPENSSL 
    protocol->store(mi->ssl? "Yes":"No", &my_charset_bin);
#else
    protocol->store(mi->ssl? "Ignored":"No", &my_charset_bin);
#endif
    protocol->store(mi->ssl_ca, &my_charset_bin);
    protocol->store(mi->ssl_capath, &my_charset_bin);
    protocol->store(mi->ssl_cert, &my_charset_bin);
    protocol->store(mi->ssl_cipher, &my_charset_bin);
    protocol->store(mi->ssl_key, &my_charset_bin);
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2402 2403

    if (mi->rli.last_master_timestamp)
2404 2405 2406 2407 2408
    {
      long tmp= (long)((time_t)time((time_t*) 0)
                               - mi->rli.last_master_timestamp)
        - mi->clock_diff_with_master;
      /*
2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423
        Apparently on some systems tmp can be <0. Here are possible reasons
        related to MySQL:
        - the master is itself a slave of another master whose time is ahead.
        - somebody used an explicit SET TIMESTAMP on the master.
        Possible reason related to granularity-to-second of time functions
        (nothing to do with MySQL), which can explain a value of -1:
        assume the master's and slave's time are perfectly synchronized, and
        that at slave's connection time, when the master's timestamp is read,
        it is at the very end of second 1, and (a very short time later) when
        the slave's timestamp is read it is at the very beginning of second
        2. Then the recorded value for master is 1 and the recorded value for
        slave is 2. At SHOW SLAVE STATUS time, assume that the difference
        between timestamp of slave and rli->last_master_timestamp is 0
        (i.e. they are in the same second), then we get 0-(2-1)=-1 as a result.
        This confuses users, so we don't go below 0.
2424 2425 2426
      */
      protocol->store((longlong)(max(0, tmp)));
    }
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2427 2428 2429
    else
      protocol->store_null();

2430 2431
    pthread_mutex_unlock(&mi->rli.data_lock);
    pthread_mutex_unlock(&mi->data_lock);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2432
  
2433
    if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length()))
2434
      DBUG_RETURN(TRUE);
2435
  }
2436
  send_eof(thd);
2437
  DBUG_RETURN(FALSE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2438 2439
}

2440

guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2441
bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2442
{
2443
  IO_CACHE* file = &mi->file;
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
2444
  char lbuf[22];
2445 2446 2447
  DBUG_ENTER("flush_master_info");
  DBUG_PRINT("enter",("master_pos: %ld", (long) mi->master_log_pos));

2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471
  /*
    Flush the relay log to disk. If we don't do it, then the relay log while
    have some part (its last kilobytes) in memory only, so if the slave server
    dies now, with, say, from master's position 100 to 150 in memory only (not
    on disk), and with position 150 in master.info, then when the slave
    restarts, the I/O thread will fetch binlogs from 150, so in the relay log
    we will have "[0, 100] U [150, infinity[" and nobody will notice it, so the
    SQL thread will jump from 100 to 150, and replication will silently break.

    When we come to this place in code, relay log may or not be initialized;
    the caller is responsible for setting 'flush_relay_log_cache' accordingly.
  */
  if (flush_relay_log_cache)
    flush_io_cache(mi->rli.relay_log.get_log_file());

  /*
    We flushed the relay log BEFORE the master.info file, because if we crash
    now, we will get a duplicate event in the relay log at restart. If we
    flushed in the other order, we would get a hole in the relay log.
    And duplicate is better than hole (with a duplicate, in later versions we
    can add detection and scrap one event; with a hole there's nothing we can
    do).
  */

2472 2473 2474 2475 2476 2477 2478 2479
  /*
     In certain cases this code may create master.info files that seems 
     corrupted, because of extra lines filled with garbage in the end 
     file (this happens if new contents take less space than previous 
     contents of file). But because of number of lines in the first line 
     of file we don't care about this garbage.
  */
  
2480
  my_b_seek(file, 0L);
2481 2482 2483
  my_b_printf(file, "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n",
	      LINES_IN_MASTER_INFO_WITH_SSL,
              mi->master_log_name, llstr(mi->master_log_pos, lbuf),
2484
	      mi->host, mi->user,
2485 2486 2487
	      mi->password, mi->port, mi->connect_retry,
              (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert,
              mi->ssl_cipher, mi->ssl_key);
2488
  flush_io_cache(file);
2489
  DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2490 2491
}

2492

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2493
st_relay_log_info::st_relay_log_info()
2494 2495
  :info_fd(-1), cur_log_fd(-1), save_temporary_tables(0),
   cur_log_old_open_count(0), group_master_log_pos(0), log_space_total(0),
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2496 2497 2498 2499
   ignore_log_space_limit(0), last_master_timestamp(0), slave_skip_counter(0),
   abort_pos_wait(0), slave_run_id(0), sql_thd(0), last_slave_errno(0),
   inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE),
   until_log_pos(0)
2500
{
monty@mysql.com's avatar
monty@mysql.com committed
2501 2502
  group_relay_log_name[0]= event_relay_log_name[0]=
    group_master_log_name[0]= 0;
2503 2504
  last_slave_error[0]=0; until_log_name[0]= 0;

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2505 2506
  bzero((char*) &info_file, sizeof(info_file));
  bzero((char*) &cache_buf, sizeof(cache_buf));
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2507 2508 2509 2510 2511 2512 2513
  pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
  pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
  pthread_mutex_init(&log_space_lock, MY_MUTEX_INIT_FAST);
  pthread_cond_init(&data_cond, NULL);
  pthread_cond_init(&start_cond, NULL);
  pthread_cond_init(&stop_cond, NULL);
  pthread_cond_init(&log_space_cond, NULL);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2514
  relay_log.init_pthread_objects();
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528
}


st_relay_log_info::~st_relay_log_info()
{
  pthread_mutex_destroy(&run_lock);
  pthread_mutex_destroy(&data_lock);
  pthread_mutex_destroy(&log_space_lock);
  pthread_cond_destroy(&data_cond);
  pthread_cond_destroy(&start_cond);
  pthread_cond_destroy(&stop_cond);
  pthread_cond_destroy(&log_space_cond);
}

2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552
/*
  Waits until the SQL thread reaches (has executed up to) the
  log/position or timed out.

  SYNOPSIS
    wait_for_pos()
    thd             client thread that sent SELECT MASTER_POS_WAIT
    log_name        log name to wait for
    log_pos         position to wait for 
    timeout         timeout in seconds before giving up waiting

  NOTES
    timeout is longlong whereas it should be ulong ; but this is
    to catch if the user submitted a negative timeout.

  RETURN VALUES
    -2          improper arguments (log_pos<0)
                or slave not running, or master info changed
                during the function's execution,
                or client thread killed. -2 is translated to NULL by caller
    -1          timed out
    >=0         number of log events the function had to wait
                before reaching the desired log/position
 */
2553

2554
int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
2555 2556
                                    longlong log_pos,
                                    longlong timeout)
2557
{
2558 2559
  if (!inited)
    return -1;
2560
  int event_count = 0;
2561
  ulong init_abort_pos_wait;
2562 2563
  int error=0;
  struct timespec abstime; // for timeout checking
2564
  const char *msg;
2565
  DBUG_ENTER("wait_for_pos");
2566 2567
  DBUG_PRINT("enter",("log_name: '%s'  log_pos: %lu  timeout: %lu",
                      log_name->c_ptr(), (ulong) log_pos, (ulong) timeout));
2568

2569
  set_timespec(abstime,timeout);
2570
  pthread_mutex_lock(&data_lock);
2571 2572 2573
  msg= thd->enter_cond(&data_cond, &data_lock,
                       "Waiting for the slave SQL thread to "
                       "advance position");
2574
  /* 
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2575 2576 2577 2578 2579 2580 2581 2582
     This function will abort when it notices that some CHANGE MASTER or
     RESET MASTER has changed the master info.
     To catch this, these commands modify abort_pos_wait ; We just monitor
     abort_pos_wait and see if it has changed.
     Why do we have this mechanism instead of simply monitoring slave_running
     in the loop (we do this too), as CHANGE MASTER/RESET SLAVE require that
     the SQL thread be stopped?
     This is becasue if someones does:
2583
     STOP SLAVE;CHANGE MASTER/RESET SLAVE; START SLAVE;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2584 2585
     the change may happen very quickly and we may not notice that
     slave_running briefly switches between 1/0/1.
2586
  */
2587
  init_abort_pos_wait= abort_pos_wait;
2588

2589 2590 2591 2592 2593 2594 2595 2596
  /*
    We'll need to 
    handle all possible log names comparisons (e.g. 999 vs 1000).
    We use ulong for string->number conversion ; this is no 
    stronger limitation than in find_uniq_filename in sql/log.cc
  */
  ulong log_name_extension;
  char log_name_tmp[FN_REFLEN]; //make a char[] from String
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2597 2598
  char *end= strmake(log_name_tmp, log_name->ptr(), min(log_name->length(),
							FN_REFLEN-1));
2599 2600 2601 2602 2603 2604 2605
  char *p= fn_ext(log_name_tmp);
  char *p_end;
  if (!*p || log_pos<0)   
  {
    error= -2; //means improper arguments
    goto err;
  }
2606 2607
  // Convert 0-3 to 4
  log_pos= max(log_pos, BIN_LOG_HEADER_SIZE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2608
  /* p points to '.' */
2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620
  log_name_extension= strtoul(++p, &p_end, 10);
  /*
    p_end points to the first invalid character.
    If it equals to p, no digits were found, error.
    If it contains '\0' it means conversion went ok.
  */
  if (p_end==p || *p_end)
  {
    error= -2;
    goto err;
  }    

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2621
  /* The "compare and wait" main loop */
2622
  while (!thd->killed &&
2623
         init_abort_pos_wait == abort_pos_wait &&
2624
         slave_running)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2625
  {
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
2626 2627
    bool pos_reached;
    int cmp_result= 0;
monty@mysql.com's avatar
monty@mysql.com committed
2628

2629 2630 2631 2632 2633 2634
    DBUG_PRINT("info",
               ("init_abort_pos_wait: %ld  abort_pos_wait: %ld",
                init_abort_pos_wait, abort_pos_wait));
    DBUG_PRINT("info",("group_master_log_name: '%s'  pos: %lu",
                       group_master_log_name, (ulong) group_master_log_pos));

2635
    /*
monty@mysql.com's avatar
monty@mysql.com committed
2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646
      group_master_log_name can be "", if we are just after a fresh
      replication start or after a CHANGE MASTER TO MASTER_HOST/PORT
      (before we have executed one Rotate event from the master) or
      (rare) if the user is doing a weird slave setup (see next
      paragraph).  If group_master_log_name is "", we assume we don't
      have enough info to do the comparison yet, so we just wait until
      more data. In this case master_log_pos is always 0 except if
      somebody (wrongly) sets this slave to be a slave of itself
      without using --replicate-same-server-id (an unsupported
      configuration which does nothing), then group_master_log_pos
      will grow and group_master_log_name will stay "".
2647
    */
2648
    if (*group_master_log_name)
2649
    {
monty@mysql.com's avatar
monty@mysql.com committed
2650 2651
      char *basename= (group_master_log_name +
                       dirname_length(group_master_log_name));
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2652
      /*
2653 2654 2655 2656
        First compare the parts before the extension.
        Find the dot in the master's log basename,
        and protect against user's input error :
        if the names do not match up to '.' included, return error
2657
      */
2658 2659 2660 2661 2662 2663 2664 2665
      char *q= (char*)(fn_ext(basename)+1);
      if (strncmp(basename, log_name_tmp, (int)(q-basename)))
      {
        error= -2;
        break;
      }
      // Now compare extensions.
      char *q_end;
2666 2667
      ulong group_master_log_name_extension= strtoul(q, &q_end, 10);
      if (group_master_log_name_extension < log_name_extension)
2668
        cmp_result= -1 ;
2669
      else
2670
        cmp_result= (group_master_log_name_extension > log_name_extension) ? 1 : 0 ;
2671

monty@mysql.com's avatar
monty@mysql.com committed
2672
      pos_reached= ((!cmp_result && group_master_log_pos >= (ulonglong)log_pos) ||
2673 2674
                    cmp_result > 0);
      if (pos_reached || thd->killed)
2675
        break;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2676
    }
2677 2678

    //wait for master update, with optional timeout.
2679
    
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2680
    DBUG_PRINT("info",("Waiting for master update"));
2681 2682 2683 2684
    /*
      We are going to pthread_cond_(timed)wait(); if the SQL thread stops it
      will wake us up.
    */
2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701
    if (timeout > 0)
    {
      /*
        Note that pthread_cond_timedwait checks for the timeout
        before for the condition ; i.e. it returns ETIMEDOUT 
        if the system time equals or exceeds the time specified by abstime
        before the condition variable is signaled or broadcast, _or_ if
        the absolute time specified by abstime has already passed at the time
        of the call.
        For that reason, pthread_cond_timedwait will do the "timeoutting" job
        even if its condition is always immediately signaled (case of a loaded
        master).
      */
      error=pthread_cond_timedwait(&data_cond, &data_lock, &abstime);
    }
    else
      pthread_cond_wait(&data_cond, &data_lock);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2702
    DBUG_PRINT("info",("Got signal of master update or timed out"));
2703 2704 2705 2706 2707
    if (error == ETIMEDOUT || error == ETIME)
    {
      error= -1;
      break;
    }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2708
    error=0;
2709
    event_count++;
2710
    DBUG_PRINT("info",("Testing if killed or SQL thread not running"));
2711
  }
2712 2713

err:
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2714
  thd->exit_cond(msg);
2715
  DBUG_PRINT("exit",("killed: %d  abort: %d  slave_running: %d \
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2716
improper_arguments: %d  timed_out: %d",
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2717
                     thd->killed_errno(),
2718
                     (int) (init_abort_pos_wait != abort_pos_wait),
2719
                     (int) slave_running,
2720 2721 2722
                     (int) (error == -2),
                     (int) (error == -1)));
  if (thd->killed || init_abort_pos_wait != abort_pos_wait ||
2723
      !slave_running) 
2724 2725 2726 2727
  {
    error= -2;
  }
  DBUG_RETURN( error ? error : event_count );
2728 2729
}

2730 2731 2732 2733 2734
void set_slave_thread_options(THD* thd)
{
  thd->options = ((opt_log_slave_updates) ? OPTION_BIN_LOG:0) |
    OPTION_AUTO_IS_NULL;
}
2735

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2736
/*
2737
  init_slave_thread()
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2738
*/
2739

2740
static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2741 2742
{
  DBUG_ENTER("init_slave_thread");
2743 2744
  thd->system_thread = (thd_type == SLAVE_THD_SQL) ?
    SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO; 
2745
  thd->host_or_ip= "";
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2746 2747
  thd->client_capabilities = 0;
  my_net_init(&thd->net, 0);
2748
  thd->net.read_timeout = slave_net_timeout;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2749 2750
  thd->master_access= ~0;
  thd->priv_user = 0;
2751
  thd->slave_thread = 1;
2752
  set_slave_thread_options(thd);
2753
  /* 
2754
     It's nonsense to constrain the slave threads with max_join_size; if a
2755 2756 2757 2758 2759 2760
     query succeeded on master, we HAVE to execute it. So set
     OPTION_BIG_SELECTS. Setting max_join_size to HA_POS_ERROR is not enough
     (and it's not needed if we have OPTION_BIG_SELECTS) because an INSERT
     SELECT examining more than 4 billion rows would still fail (yes, because
     when max_join_size is 4G, OPTION_BIG_SELECTS is automatically set, but
     only for client threads.
2761
  */
2762 2763
  thd->options = ((opt_log_slave_updates) ? OPTION_BIN_LOG:0) |
    OPTION_AUTO_IS_NULL | OPTION_BIG_SELECTS;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2764
  thd->client_capabilities = CLIENT_LOCAL_FILES;
2765
  thd->real_id=pthread_self();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2766 2767 2768 2769
  pthread_mutex_lock(&LOCK_thread_count);
  thd->thread_id = thread_id++;
  pthread_mutex_unlock(&LOCK_thread_count);

2770
  if (init_thr_lock() || thd->store_globals())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2771
  {
2772 2773
    thd->cleanup();
    delete thd;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2774 2775 2776
    DBUG_RETURN(-1);
  }

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2777
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2778 2779 2780 2781 2782
  sigset_t set;
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
#endif

2783
  if (thd_type == SLAVE_THD_SQL)
2784
    thd->proc_info= "Waiting for the next event in relay log";
2785
  else
2786
    thd->proc_info= "Waiting for master update";
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2787 2788 2789 2790 2791
  thd->version=refresh_version;
  thd->set_time();
  DBUG_RETURN(0);
}

2792

2793 2794
static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed,
		      void* thread_killed_arg)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2795
{
2796
  int nap_time;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2797 2798 2799 2800 2801
  thr_alarm_t alarmed;
  thr_alarm_init(&alarmed);
  time_t start_time= time((time_t*) 0);
  time_t end_time= start_time+sec;

2802
  while ((nap_time= (int) (end_time - start_time)) > 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2803
  {
2804
    ALARM alarm_buff;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2805
    /*
2806
      The only reason we are asking for alarm is so that
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2807 2808 2809
      we will be woken up in case of murder, so if we do not get killed,
      set the alarm so it goes off after we wake up naturally
    */
2810
    thr_alarm(&alarmed, 2 * nap_time, &alarm_buff);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2811
    sleep(nap_time);
2812
    thr_end_alarm(&alarmed);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2813
    
2814
    if ((*thread_killed)(thd,thread_killed_arg))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2815 2816 2817 2818 2819 2820
      return 1;
    start_time=time((time_t*) 0);
  }
  return 0;
}

2821

2822 2823
static int request_dump(MYSQL* mysql, MASTER_INFO* mi,
			bool *suppress_warnings)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2824
{
2825
  char buf[FN_REFLEN + 10];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2826 2827
  int len;
  int binlog_flags = 0; // for now
2828
  char* logname = mi->master_log_name;
2829 2830
  DBUG_ENTER("request_dump");

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2831
  // TODO if big log files: Change next to int8store()
monty@mysql.com's avatar
monty@mysql.com committed
2832
  int4store(buf, (ulong) mi->master_log_pos);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2833
  int2store(buf + 4, binlog_flags);
2834
  int4store(buf + 6, server_id);
2835
  len = (uint) strlen(logname);
2836
  memcpy(buf + 10, logname,len);
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2837
  if (simple_command(mysql, COM_BINLOG_DUMP, buf, len + 10, 1))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2838
  {
2839 2840 2841 2842 2843
    /*
      Something went wrong, so we will just reconnect and retry later
      in the future, we should do a better error analysis, but for
      now we just fill up the error log :-)
    */
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2844
    if (mysql_errno(mysql) == ER_NET_READ_INTERRUPTED)
2845 2846
      *suppress_warnings= 1;			// Suppress reconnect warning
    else
2847
      sql_print_error("Error on COM_BINLOG_DUMP: %d  %s, will retry in %d secs",
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2848
		      mysql_errno(mysql), mysql_error(mysql),
2849 2850
		      master_connect_retry);
    DBUG_RETURN(1);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2851
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2852

2853
  DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2854 2855
}

2856

2857
static int request_table_dump(MYSQL* mysql, const char* db, const char* table)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2858 2859 2860
{
  char buf[1024];
  char * p = buf;
2861 2862
  uint table_len = (uint) strlen(table);
  uint db_len = (uint) strlen(db);
2863
  if (table_len + db_len > sizeof(buf) - 2)
2864 2865 2866 2867
  {
    sql_print_error("request_table_dump: Buffer overrun");
    return 1;
  } 
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2868 2869 2870 2871 2872 2873 2874
  
  *p++ = db_len;
  memcpy(p, db, db_len);
  p += db_len;
  *p++ = table_len;
  memcpy(p, table, table_len);
  
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2875
  if (simple_command(mysql, COM_TABLE_DUMP, buf, p - buf + table_len, 1))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2876 2877
  {
    sql_print_error("request_table_dump: Error sending the table dump \
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2878
command");
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2879 2880
    return 1;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2881 2882 2883 2884

  return 0;
}

2885

2886
/*
2887
  Read one event from the master
2888 2889 2890 2891 2892 2893 2894 2895 2896
  
  SYNOPSIS
    read_event()
    mysql		MySQL connection
    mi			Master connection information
    suppress_warnings	TRUE when a normal net read timeout has caused us to
			try a reconnect.  We do not want to print anything to
			the error log in this case because this a anormal
			event in an idle server.
2897

2898 2899 2900 2901 2902 2903
    RETURN VALUES
    'packet_error'	Error
    number		Length of packet
*/

static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2904
{
2905
  ulong len;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2906

2907
  *suppress_warnings= 0;
2908 2909 2910
  /*
    my_real_read() will time us out
    We check if we were told to die, and if not, try reading again
2911 2912

    TODO:  Move 'events_till_disconnect' to the MASTER_INFO structure
2913
  */
2914
#ifndef DBUG_OFF
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2915
  if (disconnect_slave_event_count && !(events_till_disconnect--))
2916 2917 2918
    return packet_error;      
#endif
  
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2919
  len = net_safe_read(mysql);
2920
  if (len == packet_error || (long) len < 1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2921
  {
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2922
    if (mysql_errno(mysql) == ER_NET_READ_INTERRUPTED)
2923 2924 2925 2926 2927 2928 2929 2930 2931 2932
    {
      /*
	We are trying a normal reconnect after a read timeout;
	we suppress prints to .err file as long as the reconnect
	happens without problems
      */
      *suppress_warnings= TRUE;
    }
    else
      sql_print_error("Error reading packet from server: %s (\
2933
server_errno=%d)",
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2934
		      mysql_error(mysql), mysql_errno(mysql));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2935 2936 2937
    return packet_error;
  }

2938 2939
  /* Check if eof packet */
  if (len < 8 && mysql->net.read_pos[0] == 254)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2940
  {
2941 2942
    sql_print_information("Slave: received end packet from server, apparent "
                          "master shutdown: %s",
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2943
		     mysql_error(mysql));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2944
     return packet_error;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2945
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2946 2947
  
  DBUG_PRINT("info",( "len=%u, net->read_pos[4] = %d\n",
2948
		      len, mysql->net.read_pos[4]));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2949 2950 2951
  return len - 1;   
}

2952

2953
int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int expected_error)
2954
{
2955 2956 2957 2958 2959 2960 2961 2962 2963
  switch (expected_error) {
  case ER_NET_READ_ERROR:
  case ER_NET_ERROR_ON_WRITE:  
  case ER_SERVER_SHUTDOWN:  
  case ER_NEW_ABORTING_CONNECTION:
    return 1;
  default:
    return 0;
  }
2964
}
2965

2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013
/*
     Check if condition stated in UNTIL clause of START SLAVE is reached.
   SYNOPSYS
     st_relay_log_info::is_until_satisfied()
   DESCRIPTION
     Checks if UNTIL condition is reached. Uses caching result of last 
     comparison of current log file name and target log file name. So cached 
     value should be invalidated if current log file name changes 
     (see st_relay_log_info::notify_... functions).
     
     This caching is needed to avoid of expensive string comparisons and 
     strtol() conversions needed for log names comparison. We don't need to
     compare them each time this function is called, we only need to do this 
     when current log name changes. If we have UNTIL_MASTER_POS condition we 
     need to do this only after Rotate_log_event::exec_event() (which is 
     rare, so caching gives real benifit), and if we have UNTIL_RELAY_POS 
     condition then we should invalidate cached comarison value after 
     inc_group_relay_log_pos() which called for each group of events (so we
     have some benefit if we have something like queries that use 
     autoincrement or if we have transactions).
     
     Should be called ONLY if until_condition != UNTIL_NONE !
   RETURN VALUE
     true - condition met or error happened (condition seems to have 
            bad log file name)
     false - condition not met
*/

bool st_relay_log_info::is_until_satisfied()
{
  const char *log_name;
  ulonglong log_pos;

  DBUG_ASSERT(until_condition != UNTIL_NONE);
  
  if (until_condition == UNTIL_MASTER_POS)
  {
    log_name= group_master_log_name;
    log_pos= group_master_log_pos;
  }
  else
  { /* until_condition == UNTIL_RELAY_POS */
    log_name= group_relay_log_name;
    log_pos= group_relay_log_pos;
  }
  
  if (until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_UNKNOWN)
  {
3014 3015 3016 3017 3018 3019
    /*
      We have no cached comparison results so we should compare log names
      and cache result.
      If we are after RESET SLAVE, and the SQL slave thread has not processed
      any event yet, it could be that group_master_log_name is "". In that case,
      just wait for more events (as there is no sensible comparison to do).
3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043
    */

    if (*log_name)
    {
      const char *basename= log_name + dirname_length(log_name);
      
      const char *q= (const char*)(fn_ext(basename)+1);
      if (strncmp(basename, until_log_name, (int)(q-basename)) == 0)
      {
        /* Now compare extensions. */
        char *q_end;
        ulong log_name_extension= strtoul(q, &q_end, 10);
        if (log_name_extension < until_log_name_extension)
          until_log_names_cmp_result= UNTIL_LOG_NAMES_CMP_LESS;
        else
          until_log_names_cmp_result= 
            (log_name_extension > until_log_name_extension) ? 
            UNTIL_LOG_NAMES_CMP_GREATER : UNTIL_LOG_NAMES_CMP_EQUAL ;
      }
      else  
      {
        /* Probably error so we aborting */
        sql_print_error("Slave SQL thread is stopped because UNTIL "
                        "condition is bad.");
monty@mysql.com's avatar
monty@mysql.com committed
3044
        return TRUE;
3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055
      }
    }
    else
      return until_log_pos == 0;
  }
    
  return ((until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_EQUAL && 
           log_pos >= until_log_pos) ||
          until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_GREATER);
}

3056

3057
static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3058
{
3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069
  /*
     We acquire this mutex since we need it for all operations except
     event execution. But we will release it in places where we will 
     wait for something for example inside of next_event().
   */
  pthread_mutex_lock(&rli->data_lock);
  
  if (rli->until_condition!=RELAY_LOG_INFO::UNTIL_NONE && 
      rli->is_until_satisfied()) 
  {
    sql_print_error("Slave SQL thread stopped because it reached its"
3070
                    " UNTIL position %ld", (long) rli->until_pos());
3071 3072 3073 3074 3075 3076 3077 3078 3079
    /* 
      Setting abort_slave flag because we do not want additional message about
      error in query execution to be printed.
    */
    rli->abort_slave= 1;
    pthread_mutex_unlock(&rli->data_lock);
    return 1;
  }
  
3080
  Log_event * ev = next_event(rli);
3081
  
3082
  DBUG_ASSERT(rli->sql_thd==thd);
3083
  
3084
  if (sql_slave_killed(thd,rli))
3085
  {
3086
    pthread_mutex_unlock(&rli->data_lock);
3087
    delete ev;
3088
    return 1;
3089
  }
3090 3091
  if (ev)
  {
3092
    int type_code = ev->get_type_code();
3093
    int exec_res;
3094 3095

    /*
3096 3097 3098 3099 3100 3101 3102
      Queries originating from this server must be skipped.
      Low-level events (Format_desc, Rotate, Stop) from this server
      must also be skipped. But for those we don't want to modify
      group_master_log_pos, because these events did not exist on the master.
      Format_desc is not completely skipped.
      Skip queries specified by the user in slave_skip_counter.
      We can't however skip events that has something to do with the
3103
      log files themselves.
3104 3105 3106
      Filtering on own server id is extremely important, to ignore execution of
      events created by the creation/rotation of the relay log (remember that
      now the relay log starts with its Format_desc, has a Rotate etc).
3107
    */
3108 3109 3110 3111
    
    DBUG_PRINT("info",("type_code=%d, server_id=%d",type_code,ev->server_id));
    
    if ((ev->server_id == (uint32) ::server_id &&
pem@mysql.com's avatar
pem@mysql.com committed
3112
         !replicate_same_server_id &&
3113
         type_code != FORMAT_DESCRIPTION_EVENT) ||
3114 3115 3116
 	(rli->slave_skip_counter && 
         type_code != ROTATE_EVENT && type_code != STOP_EVENT &&
         type_code != START_EVENT_V3 && type_code!= FORMAT_DESCRIPTION_EVENT))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3117
    {
3118
      DBUG_PRINT("info", ("event skipped"));
3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129
      if (thd->options & OPTION_BEGIN)
        rli->inc_event_relay_log_pos();
      else
      {
        rli->inc_group_relay_log_pos((type_code == ROTATE_EVENT || 
                                      type_code == STOP_EVENT ||
                                      type_code == FORMAT_DESCRIPTION_EVENT) ?
                                     LL(0) : ev->log_pos,
                                     1/* skip lock*/);
        flush_relay_log_info(rli);
      }
3130
      
3131
      /*
3132 3133 3134
 	Protect against common user error of setting the counter to 1
 	instead of 2 while recovering from an insert which used auto_increment,
 	rand or user var.
3135 3136
      */
      if (rli->slave_skip_counter && 
3137 3138 3139
 	  !((type_code == INTVAR_EVENT ||
             type_code == RAND_EVENT || 
             type_code == USER_VAR_EVENT) &&
3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152
 	    rli->slave_skip_counter == 1) &&
          /*
            The events from ourselves which have something to do with the relay
            log itself must be skipped, true, but they mustn't decrement
            rli->slave_skip_counter, because the user is supposed to not see
            these events (they are not in the master's binlog) and if we
            decremented, START SLAVE would for example decrement when it sees
            the Rotate, so the event which the user probably wanted to skip
            would not be skipped.
          */
          !(ev->server_id == (uint32) ::server_id &&
            (type_code == ROTATE_EVENT || type_code == STOP_EVENT ||
             type_code == START_EVENT_V3 || type_code == FORMAT_DESCRIPTION_EVENT)))
3153 3154
        --rli->slave_skip_counter;
      pthread_mutex_unlock(&rli->data_lock);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3155 3156
      delete ev;     
      return 0;					// avoid infinite update loops
3157
    } 
3158
    pthread_mutex_unlock(&rli->data_lock);
3159 3160
  
    thd->server_id = ev->server_id; // use the original server id for logging
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3161
    thd->set_time();				// time the query
pem@mysql.telia.com's avatar
pem@mysql.telia.com committed
3162
    thd->lex->current_select= 0;
3163
    if (!ev->when)
3164
      ev->when = time(NULL);
3165
    ev->thd = thd;
3166 3167
    exec_res = ev->exec_event(rli);
    DBUG_ASSERT(rli->sql_thd==thd);
3168 3169 3170 3171 3172 3173 3174 3175 3176 3177
    /* 
       Format_description_log_event should not be deleted because it will be
       used to read info about the relay log's format; it will be deleted when
       the SQL thread does not need it, i.e. when this thread terminates.
    */
    if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
    {
      DBUG_PRINT("info", ("Deleting the event after it has been executed"));
      delete ev;
    }
3178
    return exec_res;
3179
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3180
  else
3181
  {
3182
    pthread_mutex_unlock(&rli->data_lock);
3183
    slave_print_error(rli, 0, "\
3184 3185 3186 3187 3188 3189 3190
Could not parse relay log event entry. The possible reasons are: the master's \
binary log is corrupted (you can check this by running 'mysqlbinlog' on the \
binary log), the slave's relay log is corrupted (you can check this by running \
'mysqlbinlog' on the relay log), a network problem, or a bug in the master's \
or slave's MySQL code. If you want to check the master's binary log or slave's \
relay log, you will be able to know their names by issuing 'SHOW SLAVE STATUS' \
on this slave.\
jcole@tetra.spaceapes.com's avatar
jcole@tetra.spaceapes.com committed
3191
");
3192 3193
    return 1;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3194 3195
}

3196

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3197
/* Slave I/O Thread entry point */
3198

3199
extern "C" pthread_handler_decl(handle_slave_io,arg)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3200
{
3201 3202 3203 3204 3205 3206 3207 3208
  THD *thd; // needs to be first for thread_stack
  MYSQL *mysql;
  MASTER_INFO *mi = (MASTER_INFO*)arg; 
  char llbuff[22];
  uint retry_count;
  
  // needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff
  my_thread_init();
3209
  DBUG_ENTER("handle_slave_io");
3210

3211
#ifndef DBUG_OFF
3212
slave_begin:
3213
#endif  
3214
  DBUG_ASSERT(mi->inited);
3215 3216 3217
  mysql= NULL ;
  retry_count= 0;

3218
  pthread_mutex_lock(&mi->run_lock);
3219 3220 3221
  /* Inform waiting threads that slave has started */
  mi->slave_run_id++;

3222
#ifndef DBUG_OFF  
3223
  mi->events_till_abort = abort_slave_event_count;
3224
#endif  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3225
  
3226
  thd= new THD; // note that contructor of THD uses DBUG_ !
3227
  THD_CHECK_SENTRY(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3228 3229

  pthread_detach_this_thread();
3230
  if (init_slave_thread(thd, SLAVE_THD_IO))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3231 3232 3233 3234 3235 3236
  {
    pthread_cond_broadcast(&mi->start_cond);
    pthread_mutex_unlock(&mi->run_lock);
    sql_print_error("Failed during slave I/O thread initialization");
    goto err;
  }
3237
  mi->io_thd = thd;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3238
  thd->thread_stack = (char*)&thd; // remember where our stack is
3239
  pthread_mutex_lock(&LOCK_thread_count);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3240
  threads.append(thd);
3241
  pthread_mutex_unlock(&LOCK_thread_count);
3242 3243 3244
  mi->slave_running = 1;
  mi->abort_slave = 0;
  pthread_mutex_unlock(&mi->run_lock);
3245
  pthread_cond_broadcast(&mi->start_cond);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3246
  
3247 3248 3249
  DBUG_PRINT("master_info",("log_file_name: '%s'  position: %s",
			    mi->master_log_name,
			    llstr(mi->master_log_pos,llbuff)));
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3250
  
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3251
  if (!(mi->mysql = mysql = mysql_init(NULL)))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3252
  {
3253
    sql_print_error("Slave I/O thread: error in mysql_init()");
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3254 3255
    goto err;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3256
  
3257

3258
  thd->proc_info = "Connecting to master";
3259
  // we can get killed during safe_connect
3260
  if (!safe_connect(thd, mysql, mi))
3261
    sql_print_information("Slave I/O thread: connected to master '%s@%s:%d',\
3262
  replication started in log '%s' at position %s", mi->user,
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3263 3264 3265
		    mi->host, mi->port,
		    IO_RPL_LOG_NAME,
		    llstr(mi->master_log_pos,llbuff));
3266
  else
3267
  {
3268
    sql_print_information("Slave I/O thread killed while connecting to master");
3269 3270
    goto err;
  }
3271

3272
connected:
3273

3274
  thd->slave_net = &mysql->net;
3275
  thd->proc_info = "Checking master version";
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
3276
  if (get_master_version_and_clock(mysql, mi))
3277
    goto err;
3278 3279

  if (mi->rli.relay_log.description_event_for_queue->binlog_version > 1)
3280
  {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3281 3282 3283 3284 3285
    /*
      Register ourselves with the master.
      If fails, this is not fatal - we just print the error message and go
      on with life.
    */
3286
    thd->proc_info = "Registering slave on master";
3287
    if (register_slave_on_master(mysql) ||  update_slave_list(mysql, mi))
3288 3289
      goto err;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3290
  
3291
  DBUG_PRINT("info",("Starting reading binary log from master"));
3292
  while (!io_slave_killed(thd,mi))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3293
  {
3294
    bool suppress_warnings= 0;    
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3295
    thd->proc_info = "Requesting binlog dump";
3296
    if (request_dump(mysql, mi, &suppress_warnings))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3297 3298
    {
      sql_print_error("Failed on request_dump()");
3299
      if (io_slave_killed(thd,mi))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3300
      {
3301
	sql_print_information("Slave I/O thread killed while requesting master \
3302
dump");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3303 3304
	goto err;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3305
	  
3306
      thd->proc_info= "Waiting to reconnect after a failed binlog dump request";
3307 3308 3309
#ifdef SIGNAL_WITH_VIO_CLOSE
      thd->clear_active_vio();
#endif
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3310
      end_server(mysql);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3311 3312 3313 3314 3315
      /*
	First time retry immediately, assuming that we can recover
	right away - if first time fails, sleep between re-tries
	hopefuly the admin can fix the problem sometime
      */
3316 3317 3318 3319
      if (retry_count++)
      {
	if (retry_count > master_retry_count)
	  goto err;				// Don't retry forever
3320 3321
	safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed,
		   (void*)mi);
3322
      }
3323
      if (io_slave_killed(thd,mi))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3324
      {
3325
	sql_print_information("Slave I/O thread killed while retrying master \
3326
dump");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3327 3328
	goto err;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3329

3330
      thd->proc_info = "Reconnecting after a failed binlog dump request";
3331 3332
      if (!suppress_warnings)
	sql_print_error("Slave I/O thread: failed dump request, \
3333
reconnecting to try again, log '%s' at postion %s", IO_RPL_LOG_NAME,
3334 3335 3336
			llstr(mi->master_log_pos,llbuff));
      if (safe_reconnect(thd, mysql, mi, suppress_warnings) ||
	  io_slave_killed(thd,mi))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3337
      {
3338
	sql_print_information("Slave I/O thread killed during or \
3339
after reconnect");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3340 3341
	goto err;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3342

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3343 3344
      goto connected;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3345

3346
    while (!io_slave_killed(thd,mi))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3347
    {
3348
      bool suppress_warnings= 0;    
3349 3350 3351 3352 3353 3354 3355
      /* 
         We say "waiting" because read_event() will wait if there's nothing to
         read. But if there's something to read, it will not wait. The important
         thing is to not confuse users by saying "reading" whereas we're in fact
         receiving nothing.
      */
      thd->proc_info = "Waiting for master to send event";
3356
      ulong event_len = read_event(mysql, mi, &suppress_warnings);
3357
      if (io_slave_killed(thd,mi))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3358
      {
3359
	if (global_system_variables.log_warnings)
3360
	  sql_print_information("Slave I/O thread killed while reading event");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3361 3362
	goto err;
      }
3363
	  	  
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3364 3365
      if (event_len == packet_error)
      {
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3366
	uint mysql_error_number= mysql_errno(mysql);
3367
	if (mysql_error_number == ER_NET_PACKET_TOO_LARGE)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3368
	{
3369 3370 3371 3372
	  sql_print_error("\
Log entry on master is longer than max_allowed_packet (%ld) on \
slave. If the entry is correct, restart the server with a higher value of \
max_allowed_packet",
3373
			  thd->variables.max_allowed_packet);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3374 3375
	  goto err;
	}
3376 3377 3378
	if (mysql_error_number == ER_MASTER_FATAL_ERROR_READING_BINLOG)
	{
	  sql_print_error(ER(mysql_error_number), mysql_error_number,
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3379
			  mysql_error(mysql));
3380 3381
	  goto err;
	}
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3382
	thd->proc_info = "Waiting to reconnect after a failed master event read";
3383 3384 3385
#ifdef SIGNAL_WITH_VIO_CLOSE
        thd->clear_active_vio();
#endif
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3386
	end_server(mysql);
3387 3388 3389 3390
	if (retry_count++)
	{
	  if (retry_count > master_retry_count)
	    goto err;				// Don't retry forever
3391
	  safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed,
3392 3393
		     (void*) mi);
	}	    
3394
	if (io_slave_killed(thd,mi))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3395
	{
3396
	  if (global_system_variables.log_warnings)
3397
	    sql_print_information("Slave I/O thread killed while waiting to \
3398
reconnect after a failed read");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3399 3400
	  goto err;
	}
3401
	thd->proc_info = "Reconnecting after a failed master event read";
3402
	if (!suppress_warnings)
3403
	  sql_print_information("Slave I/O thread: Failed reading log event, \
3404
reconnecting to retry, log '%s' position %s", IO_RPL_LOG_NAME,
3405 3406 3407
			  llstr(mi->master_log_pos, llbuff));
	if (safe_reconnect(thd, mysql, mi, suppress_warnings) ||
	    io_slave_killed(thd,mi))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3408
	{
3409
	  if (global_system_variables.log_warnings)
3410
	    sql_print_information("Slave I/O thread killed during or after a \
3411
reconnect done to recover from failed read");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3412 3413 3414
	  goto err;
	}
	goto connected;
3415
      } // if (event_len == packet_error)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3416
	  
3417
      retry_count=0;			// ok event, reset retry counter
3418
      thd->proc_info = "Queueing master event to the relay log";
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3419 3420 3421
      if (queue_event(mi,(const char*)mysql->net.read_pos + 1,
		      event_len))
      {
3422
	sql_print_error("Slave I/O thread could not queue event from master");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3423 3424
	goto err;
      }
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
3425
      flush_master_info(mi, 1); /* sure that we can flush the relay log */
3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437
      /*
        See if the relay logs take too much space.
        We don't lock mi->rli.log_space_lock here; this dirty read saves time
        and does not introduce any problem:
        - if mi->rli.ignore_log_space_limit is 1 but becomes 0 just after (so
        the clean value is 0), then we are reading only one more event as we
        should, and we'll block only at the next event. No big deal.
        - if mi->rli.ignore_log_space_limit is 0 but becomes 1 just after (so
        the clean value is 1), then we are going into wait_for_relay_log_space()
        for no reason, but this function will do a clean read, notice the clean
        value and exit immediately.
      */
3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448
#ifndef DBUG_OFF
      {
        char llbuf1[22], llbuf2[22];
        DBUG_PRINT("info", ("log_space_limit=%s log_space_total=%s \
ignore_log_space_limit=%d",
                            llstr(mi->rli.log_space_limit,llbuf1),
                            llstr(mi->rli.log_space_total,llbuf2),
                            (int) mi->rli.ignore_log_space_limit)); 
      }
#endif

3449
      if (mi->rli.log_space_limit && mi->rli.log_space_limit <
3450 3451
	  mi->rli.log_space_total &&
          !mi->rli.ignore_log_space_limit)
3452 3453 3454 3455 3456 3457
	if (wait_for_relay_log_space(&mi->rli))
	{
	  sql_print_error("Slave I/O thread aborted while waiting for relay \
log space");
	  goto err;
	}
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3458
      // TODO: check debugging abort code
3459
#ifndef DBUG_OFF
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3460 3461 3462 3463 3464
      if (abort_slave_event_count && !--events_till_abort)
      {
	sql_print_error("Slave I/O thread: debugging abort");
	goto err;
      }
3465
#endif
3466
    } 
3467
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3468

monty@donna.mysql.fi's avatar
monty@donna.mysql.fi committed
3469
  // error = 0;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3470
err:
3471
  // print the current replication position
3472
  sql_print_information("Slave I/O thread exiting, read up to log '%s', position %s",
3473
		  IO_RPL_LOG_NAME, llstr(mi->master_log_pos,llbuff));
3474
  VOID(pthread_mutex_lock(&LOCK_thread_count));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3475
  thd->query = thd->db = 0; // extra safety
3476
  thd->query_length= thd->db_length= 0;
3477
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
3478 3479
  if (mysql)
  {
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3480
    mysql_close(mysql);
3481 3482
    mi->mysql=0;
  }
jcole@tetra.spaceapes.com's avatar
jcole@tetra.spaceapes.com committed
3483
  thd->proc_info = "Waiting for slave mutex on exit";
3484 3485 3486
  pthread_mutex_lock(&mi->run_lock);
  mi->slave_running = 0;
  mi->io_thd = 0;
3487 3488 3489
  /* Forget the relay log's format */
  delete mi->rli.relay_log.description_event_for_queue;
  mi->rli.relay_log.description_event_for_queue= 0;
3490
  // TODO: make rpl_status part of MASTER_INFO
3491
  change_rpl_status(RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE);
3492 3493
  mi->abort_slave = 0; // TODO: check if this is needed
  DBUG_ASSERT(thd->net.buff != 0);
3494
  net_end(&thd->net); // destructor will not free it, because net.vio is 0
3495
  pthread_mutex_lock(&LOCK_thread_count);
3496
  THD_CHECK_SENTRY(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3497
  delete thd;
3498
  pthread_mutex_unlock(&LOCK_thread_count);
3499
  pthread_cond_broadcast(&mi->stop_cond);	// tell the world we are done
3500
  pthread_mutex_unlock(&mi->run_lock);
3501
#ifndef DBUG_OFF
3502
  if (abort_slave_event_count && !events_till_abort)
3503 3504
    goto slave_begin;
#endif  
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3505
  my_thread_end();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3506 3507 3508 3509
  pthread_exit(0);
  DBUG_RETURN(0);				// Can't return anything here
}

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3510

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3511
/* Slave SQL Thread entry point */
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3512

3513
extern "C" pthread_handler_decl(handle_slave_sql,arg)
3514
{
3515
  THD *thd;			/* needs to be first for thread_stack */
3516 3517
  char llbuff[22],llbuff1[22];
  RELAY_LOG_INFO* rli = &((MASTER_INFO*)arg)->rli; 
3518 3519 3520 3521
  const char *errmsg;

  // needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff
  my_thread_init();
3522
  DBUG_ENTER("handle_slave_sql");
3523 3524 3525 3526 3527

#ifndef DBUG_OFF
slave_begin:  
#endif  

3528 3529 3530
  DBUG_ASSERT(rli->inited);
  pthread_mutex_lock(&rli->run_lock);
  DBUG_ASSERT(!rli->slave_running);
3531
  errmsg= 0;
3532 3533 3534
#ifndef DBUG_OFF  
  rli->events_till_abort = abort_slave_event_count;
#endif  
3535

3536
  thd = new THD; // note that contructor of THD uses DBUG_ !
3537 3538
  thd->thread_stack = (char*)&thd; // remember where our stack is
  
3539 3540 3541
  /* Inform waiting threads that slave has started */
  rli->slave_run_id++;

3542 3543
  pthread_detach_this_thread();
  if (init_slave_thread(thd, SLAVE_THD_SQL))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3544 3545 3546 3547 3548 3549 3550 3551 3552 3553
  {
    /*
      TODO: this is currently broken - slave start and change master
      will be stuck if we fail here
    */
    pthread_cond_broadcast(&rli->start_cond);
    pthread_mutex_unlock(&rli->run_lock);
    sql_print_error("Failed during slave thread initialization");
    goto err;
  }
3554
  thd->init_for_queries();
3555
  rli->sql_thd= thd;
3556
  thd->temporary_tables = rli->save_temporary_tables; // restore temp tables
3557
  pthread_mutex_lock(&LOCK_thread_count);
3558
  threads.append(thd);
3559
  pthread_mutex_unlock(&LOCK_thread_count);
3560 3561 3562
  rli->slave_running = 1;
  rli->abort_slave = 0;
  pthread_mutex_unlock(&rli->run_lock);
3563
  pthread_cond_broadcast(&rli->start_cond);
3564

guilhem@mysql.com's avatar
guilhem@mysql.com committed
3565 3566 3567
  /*
    Reset errors for a clean start (otherwise, if the master is idle, the SQL
    thread may execute no Query_log_event, so the error will remain even
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
3568
    though there's no problem anymore). Do not reset the master timestamp
3569 3570 3571 3572
    (imagine the slave has caught everything, the STOP SLAVE and START SLAVE:
    as we are not sure that we are going to receive a query, we want to
    remember the last master timestamp (to say how many seconds behind we are
    now.
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
3573
    But the master timestamp is reset by RESET SLAVE & CHANGE MASTER.
guilhem@mysql.com's avatar
guilhem@mysql.com committed
3574
  */
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
3575
  clear_slave_error(rli);
3576 3577

  //tell the I/O thread to take relay_log_space_limit into account from now on
3578
  pthread_mutex_lock(&rli->log_space_lock);
3579
  rli->ignore_log_space_limit= 0;
3580
  pthread_mutex_unlock(&rli->log_space_lock);
3581

3582
  if (init_relay_log_pos(rli,
3583 3584
			 rli->group_relay_log_name,
			 rli->group_relay_log_pos,
3585 3586
			 1 /*need data lock*/, &errmsg,
                         1 /*look for a description_event*/))
3587 3588 3589 3590 3591
  {
    sql_print_error("Error initializing relay log position: %s",
		    errmsg);
    goto err;
  }
3592
  THD_CHECK_SENTRY(thd);
3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616
#ifndef DBUG_OFF
  {
    char llbuf1[22], llbuf2[22];
    DBUG_PRINT("info", ("my_b_tell(rli->cur_log)=%s rli->event_relay_log_pos=%s",
                        llstr(my_b_tell(rli->cur_log),llbuf1), 
                        llstr(rli->event_relay_log_pos,llbuf2)));
    DBUG_ASSERT(rli->event_relay_log_pos >= BIN_LOG_HEADER_SIZE);
    /*
      Wonder if this is correct. I (Guilhem) wonder if my_b_tell() returns the
      correct position when it's called just after my_b_seek() (the questionable
      stuff is those "seek is done on next read" comments in the my_b_seek()
      source code).
      The crude reality is that this assertion randomly fails whereas
      replication seems to work fine. And there is no easy explanation why it
      fails (as we my_b_seek(rli->event_relay_log_pos) at the very end of
      init_relay_log_pos() called above). Maybe the assertion would be
      meaningful if we held rli->data_lock between the my_b_seek() and the
      DBUG_ASSERT().
    */
#ifdef SHOULD_BE_CHECKED
    DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->event_relay_log_pos);
#endif
  }
#endif
3617
  DBUG_ASSERT(rli->sql_thd == thd);
3618 3619

  DBUG_PRINT("master_info",("log_file_name: %s  position: %s",
3620 3621
			    rli->group_master_log_name,
			    llstr(rli->group_master_log_pos,llbuff)));
3622
  if (global_system_variables.log_warnings)
3623
    sql_print_information("Slave SQL thread initialized, starting replication in \
3624
log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
3625 3626
		    llstr(rli->group_master_log_pos,llbuff),rli->group_relay_log_name,
		    llstr(rli->group_relay_log_pos,llbuff1));
3627

gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
3628
  /* execute init_slave variable */
3629
  if (sys_init_slave.value_length)
gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
3630
  {
3631
    execute_init_command(thd, &sys_init_slave, &LOCK_sys_init_slave);
gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
3632 3633 3634 3635 3636 3637 3638 3639
    if (thd->query_error)
    {
      sql_print_error("\
Slave SQL thread aborted. Can't execute init_slave query");
      goto err;
    }
  }

3640 3641
  /* Read queries from the IO/THREAD until this thread is killed */

3642
  while (!sql_slave_killed(thd,rli))
3643
  {
3644
    thd->proc_info = "Reading event from the relay log";
3645
    DBUG_ASSERT(rli->sql_thd == thd);
3646
    THD_CHECK_SENTRY(thd);
3647 3648 3649
    if (exec_relay_log_event(thd,rli))
    {
      // do not scare the user if SQL thread was simply killed or stopped
3650
      if (!sql_slave_killed(thd,rli))
3651 3652
        sql_print_error("\
Error running query, slave SQL thread aborted. Fix the problem, and restart \
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3653
the slave SQL thread with \"SLAVE START\". We stopped at log \
3654
'%s' position %s", RPL_LOG_NAME, llstr(rli->group_master_log_pos, llbuff));
3655 3656
      goto err;
    }
3657
  }
3658

3659
  /* Thread stopped. Print the current replication position to the log */
monty@mysql.com's avatar
monty@mysql.com committed
3660 3661 3662
  sql_print_information("Slave SQL thread exiting, replication stopped in log "
 			"'%s' at position %s",
		        RPL_LOG_NAME, llstr(rli->group_master_log_pos,llbuff));
3663 3664

 err:
3665
  VOID(pthread_mutex_lock(&LOCK_thread_count));
3666 3667 3668 3669 3670 3671
  /*
    Some extra safety, which should not been needed (normally, event deletion
    should already have done these assignments (each event which sets these
    variables is supposed to set them to 0 before terminating)).
  */
  thd->query= thd->db= thd->catalog= 0; 
3672
  thd->query_length= thd->db_length= 0;
3673
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
3674 3675
  thd->proc_info = "Waiting for slave mutex on exit";
  pthread_mutex_lock(&rli->run_lock);
3676 3677
  /* We need data_lock, at least to wake up any waiting master_pos_wait() */
  pthread_mutex_lock(&rli->data_lock);
3678
  DBUG_ASSERT(rli->slave_running == 1); // tracking buffer overrun
3679 3680
  /* When master_pos_wait() wakes up it will check this and terminate */
  rli->slave_running= 0; 
3681 3682 3683
  /* Forget the relay log's format */
  delete rli->relay_log.description_event_for_exec;
  rli->relay_log.description_event_for_exec= 0;
3684 3685 3686 3687
  /* Wake up master_pos_wait() */
  pthread_mutex_unlock(&rli->data_lock);
  DBUG_PRINT("info",("Signaling possibly waiting master_pos_wait() functions"));
  pthread_cond_broadcast(&rli->data_cond);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
3688
  rli->ignore_log_space_limit= 0; /* don't need any lock */
3689
  rli->save_temporary_tables = thd->temporary_tables;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3690 3691 3692 3693 3694

  /*
    TODO: see if we can do this conditionally in next_event() instead
    to avoid unneeded position re-init
  */
3695 3696 3697 3698
  thd->temporary_tables = 0; // remove tempation from destructor to close them
  DBUG_ASSERT(thd->net.buff != 0);
  net_end(&thd->net); // destructor will not free it, because we are weird
  DBUG_ASSERT(rli->sql_thd == thd);
3699
  THD_CHECK_SENTRY(thd);
3700
  rli->sql_thd= 0;
3701
  pthread_mutex_lock(&LOCK_thread_count);
3702
  THD_CHECK_SENTRY(thd);
3703 3704 3705 3706 3707 3708 3709 3710 3711
  delete thd;
  pthread_mutex_unlock(&LOCK_thread_count);
  pthread_cond_broadcast(&rli->stop_cond);
  // tell the world we are done
  pthread_mutex_unlock(&rli->run_lock);
#ifndef DBUG_OFF // TODO: reconsider the code below
  if (abort_slave_event_count && !rli->events_till_abort)
    goto slave_begin;
#endif  
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3712
  my_thread_end();
3713 3714 3715
  pthread_exit(0);
  DBUG_RETURN(0);				// Can't return anything here
}
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3716

3717

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3718
/*
3719
  process_io_create_file()
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3720
*/
3721

3722 3723 3724 3725 3726
static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev)
{
  int error = 1;
  ulong num_bytes;
  bool cev_not_written;
3727 3728
  THD *thd = mi->io_thd;
  NET *net = &mi->mysql->net;
3729
  DBUG_ENTER("process_io_create_file");
3730 3731

  if (unlikely(!cev->is_valid()))
3732
    DBUG_RETURN(1);
3733 3734 3735 3736 3737 3738
  /*
    TODO: fix to honor table rules, not only db rules
  */
  if (!db_ok(cev->db, replicate_do_db, replicate_ignore_db))
  {
    skip_load_data_infile(net);
3739
    DBUG_RETURN(0);
3740 3741 3742
  }
  DBUG_ASSERT(cev->inited_from_old);
  thd->file_id = cev->file_id = mi->file_id++;
3743
  thd->server_id = cev->server_id;
3744 3745 3746 3747 3748 3749 3750 3751 3752
  cev_not_written = 1;
  
  if (unlikely(net_request_file(net,cev->fname)))
  {
    sql_print_error("Slave I/O: failed requesting download of '%s'",
		    cev->fname);
    goto err;
  }

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3753 3754 3755 3756
  /*
    This dummy block is so we could instantiate Append_block_log_event
    once and then modify it slightly instead of doing it multiple times
    in the loop
3757 3758
  */
  {
3759
    Append_block_log_event aev(thd,0,0,0,0);
3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770
  
    for (;;)
    {
      if (unlikely((num_bytes=my_net_read(net)) == packet_error))
      {
	sql_print_error("Network read error downloading '%s' from master",
			cev->fname);
	goto err;
      }
      if (unlikely(!num_bytes)) /* eof */
      {
3771
	net_write_command(net, 0, "", 0, "", 0);/* 3.23 master wants it */
monty@mysql.com's avatar
monty@mysql.com committed
3772 3773 3774 3775 3776 3777 3778 3779
        /*
          If we wrote Create_file_log_event, then we need to write
          Execute_load_log_event. If we did not write Create_file_log_event,
          then this is an empty file and we can just do as if the LOAD DATA
          INFILE had not existed, i.e. write nothing.
        */
        if (unlikely(cev_not_written))
	  break;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3780
	Execute_load_log_event xev(thd,0,0);
3781
	xev.log_pos = cev->log_pos;
3782 3783 3784 3785 3786 3787
	if (unlikely(mi->rli.relay_log.append(&xev)))
	{
	  sql_print_error("Slave I/O: error writing Exec_load event to \
relay log");
	  goto err;
	}
3788
	mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total);
3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801
	break;
      }
      if (unlikely(cev_not_written))
      {
	cev->block = (char*)net->read_pos;
	cev->block_len = num_bytes;
	if (unlikely(mi->rli.relay_log.append(cev)))
	{
	  sql_print_error("Slave I/O: error writing Create_file event to \
relay log");
	  goto err;
	}
	cev_not_written=0;
3802
	mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total);
3803 3804 3805 3806 3807
      }
      else
      {
	aev.block = (char*)net->read_pos;
	aev.block_len = num_bytes;
3808
	aev.log_pos = cev->log_pos;
3809 3810 3811 3812 3813 3814
	if (unlikely(mi->rli.relay_log.append(&aev)))
	{
	  sql_print_error("Slave I/O: error writing Append_block event to \
relay log");
	  goto err;
	}
3815
	mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total) ;
3816 3817 3818 3819 3820
      }
    }
  }
  error=0;
err:
3821
  DBUG_RETURN(error);
3822
}
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3823

3824

3825
/*
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3826 3827 3828 3829 3830 3831 3832 3833
  Start using a new binary log on the master

  SYNOPSIS
    process_io_rotate()
    mi			master_info for the slave
    rev			The rotate log event read from the binary log

  DESCRIPTION
3834
    Updates the master info with the place in the next binary
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3835
    log where we should start reading.
3836
    Rotate the relay log to avoid mixed-format relay logs.
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3837 3838 3839 3840 3841 3842 3843

  NOTES
    We assume we already locked mi->data_lock

  RETURN VALUES
    0		ok
    1	        Log event is illegal
3844 3845 3846

*/

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3847
static int process_io_rotate(MASTER_INFO *mi, Rotate_log_event *rev)
3848
{
3849
  DBUG_ENTER("process_io_rotate");
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3850
  safe_mutex_assert_owner(&mi->data_lock);
3851

3852
  if (unlikely(!rev->is_valid()))
3853
    DBUG_RETURN(1);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3854 3855 3856 3857 3858

  memcpy(mi->master_log_name, rev->new_log_ident, rev->ident_len+1);
  mi->master_log_pos= rev->pos;
  DBUG_PRINT("info", ("master_log_pos: '%s' %d",
		      mi->master_log_name, (ulong) mi->master_log_pos));
3859
#ifndef DBUG_OFF
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3860 3861 3862 3863 3864 3865
  /*
    If we do not do this, we will be getting the first
    rotate event forever, so we need to not disconnect after one.
  */
  if (disconnect_slave_event_count)
    events_till_disconnect++;
3866
#endif
3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880
  /*
    If description_event_for_queue is format <4, there is conversion in the
    relay log to the slave's format (4). And Rotate can mean upgrade or
    nothing. If upgrade, it's to 5.0 or newer, so we will get a Format_desc, so
    no need to reset description_event_for_queue now. And if it's nothing (same
    master version as before), no need (still using the slave's format).
  */
  if (mi->rli.relay_log.description_event_for_queue->binlog_version >= 4)
  {
    delete mi->rli.relay_log.description_event_for_queue;
    /* start from format 3 (MySQL 4.0) again */
    mi->rli.relay_log.description_event_for_queue= new
      Format_description_log_event(3);
  }
3881 3882 3883 3884
  /*
    Rotate the relay log makes binlog format detection easier (at next slave
    start or mysqlbinlog)
  */
3885
  rotate_relay_log(mi); /* will take the right mutexes */
3886
  DBUG_RETURN(0);
3887 3888
}

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3889
/*
3890 3891
  Reads a 3.23 event and converts it to the slave's format. This code was copied
  from MySQL 4.0.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3892
*/
3893
static int queue_binlog_ver_1_event(MASTER_INFO *mi, const char *buf,
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3894
			   ulong event_len)
3895
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3896
  const char *errmsg = 0;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3897 3898 3899 3900
  ulong inc_pos;
  bool ignore_event= 0;
  char *tmp_buf = 0;
  RELAY_LOG_INFO *rli= &mi->rli;
3901
  DBUG_ENTER("queue_binlog_ver_1_event");
3902

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3903 3904 3905
  /*
    If we get Load event, we need to pass a non-reusable buffer
    to read_log_event, so we do a trick
3906 3907 3908 3909 3910 3911
  */
  if (buf[EVENT_TYPE_OFFSET] == LOAD_EVENT)
  {
    if (unlikely(!(tmp_buf=(char*)my_malloc(event_len+1,MYF(MY_WME)))))
    {
      sql_print_error("Slave I/O: out of memory for Load event");
3912
      DBUG_RETURN(1);
3913 3914
    }
    memcpy(tmp_buf,buf,event_len);
3915 3916 3917 3918 3919 3920 3921 3922
    /*
      Create_file constructor wants a 0 as last char of buffer, this 0 will
      serve as the string-termination char for the file's name (which is at the
      end of the buffer)
      We must increment event_len, otherwise the event constructor will not see
      this end 0, which leads to segfault.
    */
    tmp_buf[event_len++]=0;
3923
    int4store(tmp_buf+EVENT_LEN_OFFSET, event_len);
3924 3925
    buf = (const char*)tmp_buf;
  }
3926 3927 3928 3929 3930 3931
  /*
    This will transform LOAD_EVENT into CREATE_FILE_EVENT, ask the master to
    send the loaded file, and write it to the relay log in the form of
    Append_block/Exec_load (the SQL thread needs the data, as that thread is not
    connected to the master).
  */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3932
  Log_event *ev = Log_event::read_log_event(buf,event_len, &errmsg,
3933
                                            mi->rli.relay_log.description_event_for_queue);
3934
  if (unlikely(!ev))
3935 3936
  {
    sql_print_error("Read invalid event from master: '%s',\
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3937
 master could be corrupt but a more likely cause of this is a bug",
3938
		    errmsg);
3939 3940
    my_free((char*) tmp_buf, MYF(MY_ALLOW_ZERO_PTR));
    DBUG_RETURN(1);
3941
  }
3942
  pthread_mutex_lock(&mi->data_lock);
3943
  ev->log_pos= mi->master_log_pos; /* 3.23 events don't contain log_pos */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3944
  switch (ev->get_type_code()) {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3945
  case STOP_EVENT:
3946
    ignore_event= 1;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3947 3948
    inc_pos= event_len;
    break;
3949
  case ROTATE_EVENT:
3950
    if (unlikely(process_io_rotate(mi,(Rotate_log_event*)ev)))
3951 3952
    {
      delete ev;
3953
      pthread_mutex_unlock(&mi->data_lock);
3954
      DBUG_RETURN(1);
3955
    }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3956
    inc_pos= 0;
3957
    break;
3958
  case CREATE_FILE_EVENT:
3959 3960 3961 3962 3963 3964
    /*
      Yes it's possible to have CREATE_FILE_EVENT here, even if we're in
      queue_old_event() which is for 3.23 events which don't comprise
      CREATE_FILE_EVENT. This is because read_log_event() above has just
      transformed LOAD_EVENT into CREATE_FILE_EVENT.
    */
3965
  {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3966 3967
    /* We come here when and only when tmp_buf != 0 */
    DBUG_ASSERT(tmp_buf);
3968 3969
    inc_pos=event_len;
    ev->log_pos+= inc_pos;
3970
    int error = process_io_create_file(mi,(Create_file_log_event*)ev);
3971
    delete ev;
3972
    mi->master_log_pos += inc_pos;
3973
    DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos));
3974
    pthread_mutex_unlock(&mi->data_lock);
3975
    my_free((char*)tmp_buf, MYF(0));
3976
    DBUG_RETURN(error);
3977
  }
3978
  default:
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3979
    inc_pos= event_len;
3980 3981
    break;
  }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3982
  if (likely(!ignore_event))
3983
  {
3984 3985 3986 3987 3988 3989
    if (ev->log_pos) 
      /* 
         Don't do it for fake Rotate events (see comment in
      Log_event::Log_event(const char* buf...) in log_event.cc).
      */
      ev->log_pos+= event_len; /* make log_pos be the pos of the end of the event */
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3990
    if (unlikely(rli->relay_log.append(ev)))
3991 3992 3993
    {
      delete ev;
      pthread_mutex_unlock(&mi->data_lock);
3994
      DBUG_RETURN(1);
3995
    }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3996
    rli->relay_log.harvest_bytes_written(&rli->log_space_total);
3997 3998
  }
  delete ev;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3999
  mi->master_log_pos+= inc_pos;
4000
  DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos));
4001
  pthread_mutex_unlock(&mi->data_lock);
4002
  DBUG_RETURN(0);
4003 4004
}

4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087
/*
  Reads a 4.0 event and converts it to the slave's format. This code was copied
  from queue_binlog_ver_1_event(), with some affordable simplifications.
*/
static int queue_binlog_ver_3_event(MASTER_INFO *mi, const char *buf,
			   ulong event_len)
{
  const char *errmsg = 0;
  ulong inc_pos;
  char *tmp_buf = 0;
  RELAY_LOG_INFO *rli= &mi->rli;
  DBUG_ENTER("queue_binlog_ver_3_event");

  /* read_log_event() will adjust log_pos to be end_log_pos */
  Log_event *ev = Log_event::read_log_event(buf,event_len, &errmsg,
                                            mi->rli.relay_log.description_event_for_queue);
  if (unlikely(!ev))
  {
    sql_print_error("Read invalid event from master: '%s',\
 master could be corrupt but a more likely cause of this is a bug",
		    errmsg);
    my_free((char*) tmp_buf, MYF(MY_ALLOW_ZERO_PTR));
    DBUG_RETURN(1);
  }
  pthread_mutex_lock(&mi->data_lock);
  switch (ev->get_type_code()) {
  case STOP_EVENT:
    goto err;
  case ROTATE_EVENT:
    if (unlikely(process_io_rotate(mi,(Rotate_log_event*)ev)))
    {
      delete ev;
      pthread_mutex_unlock(&mi->data_lock);
      DBUG_RETURN(1);
    }
    inc_pos= 0;
    break;
  default:
    inc_pos= event_len;
    break;
  }
  if (unlikely(rli->relay_log.append(ev)))
  {
    delete ev;
    pthread_mutex_unlock(&mi->data_lock);
    DBUG_RETURN(1);
  }
  rli->relay_log.harvest_bytes_written(&rli->log_space_total);
  delete ev;
  mi->master_log_pos+= inc_pos;
err:
  DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos));
  pthread_mutex_unlock(&mi->data_lock);
  DBUG_RETURN(0);
}

/*
  queue_old_event()

  Writes a 3.23 or 4.0 event to the relay log, after converting it to the 5.0
  (exactly, slave's) format. To do the conversion, we create a 5.0 event from
  the 3.23/4.0 bytes, then write this event to the relay log.

  TODO: 
    Test this code before release - it has to be tested on a separate
    setup with 3.23 master or 4.0 master
*/

static int queue_old_event(MASTER_INFO *mi, const char *buf,
			   ulong event_len)
{
  switch (mi->rli.relay_log.description_event_for_queue->binlog_version)
  {
  case 1:
      return queue_binlog_ver_1_event(mi,buf,event_len);
  case 3:
      return queue_binlog_ver_3_event(mi,buf,event_len);
  default: /* unsupported format; eg version 2 */
    DBUG_PRINT("info",("unsupported binlog format %d in queue_old_event()",
                       mi->rli.relay_log.description_event_for_queue->binlog_version));  
    return 1;
  }
}
4088

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4089
/*
4090 4091
  queue_event()

4092 4093 4094 4095 4096
  If the event is 3.23/4.0, passes it to queue_old_event() which will convert
  it. Otherwise, writes a 5.0 (or newer) event to the relay log. Then there is
  no format conversion, it's pure read/write of bytes.
  So a 5.0.0 slave's relay log can contain events in the slave's format or in
  any >=5.0.0 format.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4097 4098 4099
*/

int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
4100
{
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4101 4102 4103
  int error= 0;
  ulong inc_pos;
  RELAY_LOG_INFO *rli= &mi->rli;
4104 4105
  DBUG_ENTER("queue_event");

4106 4107
  if (mi->rli.relay_log.description_event_for_queue->binlog_version<4 &&
      buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT /* a way to escape */)
4108
    DBUG_RETURN(queue_old_event(mi,buf,event_len));
4109 4110

  pthread_mutex_lock(&mi->data_lock);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4111

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4112 4113
  /*
    TODO: figure out if other events in addition to Rotate
4114 4115
    require special processing.
    Guilhem 2003-06 : I don't think so.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4116 4117
  */
  switch (buf[EVENT_TYPE_OFFSET]) {
4118
  case STOP_EVENT:
4119 4120
    /*
      We needn't write this event to the relay log. Indeed, it just indicates a
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4121 4122 4123 4124
      master server shutdown. The only thing this does is cleaning. But
      cleaning is already done on a per-master-thread basis (as the master
      server is shutting down cleanly, it has written all DROP TEMPORARY TABLE
      and DO RELEASE_LOCK; prepared statements' deletion are TODO).
4125
      
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4126 4127 4128 4129
      We don't even increment mi->master_log_pos, because we may be just after
      a Rotate event. Btw, in a few milliseconds we are going to have a Start
      event from the next binlog (unless the master is presently running
      without --log-bin).
4130 4131
    */
    goto err;
4132 4133
  case ROTATE_EVENT:
  {
4134
    Rotate_log_event rev(buf,event_len,mi->rli.relay_log.description_event_for_queue); 
4135
    if (unlikely(process_io_rotate(mi,&rev)))
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4136
    {
4137 4138
      error= 1;
      goto err;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4139
    }
4140 4141 4142 4143
    /*
      Now the I/O thread has just changed its mi->master_log_name, so
      incrementing mi->master_log_pos is nonsense.
    */
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4144
    inc_pos= 0;
4145 4146
    break;
  }
4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157
  case FORMAT_DESCRIPTION_EVENT:
  {
    /*
      Create an event, and save it (when we rotate the relay log, we will have
      to write this event again).
    */
    /*
      We are the only thread which reads/writes description_event_for_queue. The
      relay_log struct does not move (though some members of it can change), so
      we needn't any lock (no rli->data_lock, no log lock).
    */
4158
    Format_description_log_event* tmp;
4159
    const char* errmsg;
4160
    if (!(tmp= (Format_description_log_event*)
4161
          Log_event::read_log_event(buf, event_len, &errmsg,
4162
                                    mi->rli.relay_log.description_event_for_queue)))
4163 4164 4165 4166
    {
      error= 2;
      goto err;
    }
4167 4168
    delete mi->rli.relay_log.description_event_for_queue;
    mi->rli.relay_log.description_event_for_queue= tmp;
4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182
    /* 
       Though this does some conversion to the slave's format, this will
       preserve the master's binlog format version, and number of event types. 
    */
    /* 
       If the event was not requested by the slave (the slave did not ask for
       it), i.e. has end_log_pos=0, we do not increment mi->master_log_pos 
    */
    inc_pos= uint4korr(buf+LOG_POS_OFFSET) ? event_len : 0;
    DBUG_PRINT("info",("binlog format is now %d",
                       mi->rli.relay_log.description_event_for_queue->binlog_version));  

  }
  break;
4183
  default:
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4184
    inc_pos= event_len;
4185 4186
    break;
  }
4187 4188 4189 4190

  /* 
     If this event is originating from this server, don't queue it. 
     We don't check this for 3.23 events because it's simpler like this; 3.23
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4191 4192
     will be filtered anyway by the SQL slave thread which also tests the
     server id (we must also keep this test in the SQL thread, in case somebody
4193 4194 4195 4196 4197 4198 4199 4200
     upgrades a 4.0 slave which has a not-filtered relay log).

     ANY event coming from ourselves can be ignored: it is obvious for queries;
     for STOP_EVENT/ROTATE_EVENT/START_EVENT: these cannot come from ourselves
     (--log-slave-updates would not log that) unless this slave is also its
     direct master (an unsupported, useless setup!).
  */

guilhem@mysql.com's avatar
guilhem@mysql.com committed
4201 4202
  if ((uint4korr(buf + SERVER_ID_OFFSET) == ::server_id) &&
      !replicate_same_server_id)
4203
  {
4204 4205 4206 4207 4208
    /*
      Do not write it to the relay log.
      We still want to increment, so that we won't re-read this event from the
      master if the slave IO thread is now stopped/restarted (more efficient if
      the events we are ignoring are big LOAD DATA INFILE).
4209 4210 4211
      But events which were generated by this slave and which do not exist in
      the master's binlog (i.e. Format_desc, Rotate & Stop) should not increment
      mi->master_log_pos.
4212
    */
4213 4214 4215 4216
    if (buf[EVENT_TYPE_OFFSET]!=FORMAT_DESCRIPTION_EVENT &&
        buf[EVENT_TYPE_OFFSET]!=ROTATE_EVENT &&
        buf[EVENT_TYPE_OFFSET]!=STOP_EVENT)
      mi->master_log_pos+= inc_pos;
4217 4218
    DBUG_PRINT("info", ("master_log_pos: %d, event originating from the same server, ignored", (ulong) mi->master_log_pos));
  }  
4219 4220 4221
  else
  {
    /* write the event to the relay log */
4222
    if (likely(!(rli->relay_log.appendv(buf,event_len,0))))
4223 4224 4225 4226 4227
    {
      mi->master_log_pos+= inc_pos;
      DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos));
      rli->relay_log.harvest_bytes_written(&rli->log_space_total);
    }
4228 4229
    else
      error=3;
4230
  }
4231 4232

err:
4233
  pthread_mutex_unlock(&mi->data_lock);
4234
  DBUG_PRINT("info", ("error=%d", error));
4235
  DBUG_RETURN(error);
4236 4237
}

4238

4239 4240
void end_relay_log_info(RELAY_LOG_INFO* rli)
{
4241 4242
  DBUG_ENTER("end_relay_log_info");

4243
  if (!rli->inited)
4244
    DBUG_VOID_RETURN;
4245
  if (rli->info_fd >= 0)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4246 4247
  {
    end_io_cache(&rli->info_file);
4248
    (void) my_close(rli->info_fd, MYF(MY_WME));
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4249 4250
    rli->info_fd = -1;
  }
4251
  if (rli->cur_log_fd >= 0)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4252 4253 4254 4255 4256
  {
    end_io_cache(&rli->cache_buf);
    (void)my_close(rli->cur_log_fd, MYF(MY_WME));
    rli->cur_log_fd = -1;
  }
4257
  rli->inited = 0;
4258
  rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
4259
  rli->relay_log.harvest_bytes_written(&rli->log_space_total);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
4260 4261 4262 4263 4264 4265
  /*
    Delete the slave's temporary tables from memory.
    In the future there will be other actions than this, to ensure persistance
    of slave's temp tables after shutdown.
  */
  rli->close_temporary_tables();
4266
  DBUG_VOID_RETURN;
4267 4268
}

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4269 4270
/*
  Try to connect until successful or slave killed
4271

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4272 4273 4274 4275 4276
  SYNPOSIS
    safe_connect()
    thd			Thread handler for slave
    mysql		MySQL connection handle
    mi			Replication handle
4277

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4278 4279 4280 4281
  RETURN
    0	ok
    #	Error
*/
4282

4283
static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4284
{
4285
  return connect_to_master(thd, mysql, mi, 0, 0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4286 4287
}

4288

4289
/*
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4290 4291
  SYNPOSIS
    connect_to_master()
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4292

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4293 4294 4295
  IMPLEMENTATION
    Try to connect until successful or slave killed or we have retried
    master_retry_count times
4296
*/
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4297

sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
4298
static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
4299
			     bool reconnect, bool suppress_warnings)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4300
{
4301
  int slave_was_killed;
4302 4303
  int last_errno= -2;				// impossible error
  ulong err_count=0;
4304
  char llbuff[22];
4305
  DBUG_ENTER("connect_to_master");
4306

4307 4308 4309
#ifndef DBUG_OFF
  events_till_disconnect = disconnect_slave_event_count;
#endif
4310
  ulong client_flag= CLIENT_REMEMBER_OPTIONS;
4311 4312 4313
  if (opt_slave_compressed_protocol)
    client_flag=CLIENT_COMPRESS;		/* We will use compression */

4314 4315
  mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout);
  mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, (char *) &slave_net_timeout);
4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326
 
#ifdef HAVE_OPENSSL
  if (mi->ssl)
    mysql_ssl_set(mysql, 
                  mi->ssl_key[0]?mi->ssl_key:0,
                  mi->ssl_cert[0]?mi->ssl_cert:0, 
                  mi->ssl_ca[0]?mi->ssl_ca:0,
                  mi->ssl_capath[0]?mi->ssl_capath:0,
                  mi->ssl_cipher[0]?mi->ssl_cipher:0);
#endif

4327 4328 4329 4330
  mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset_info->csname);
  /* This one is not strictly needed but we have it here for completeness */
  mysql_options(mysql, MYSQL_SET_CHARSET_DIR, (char *) charsets_dir);

4331
  while (!(slave_was_killed = io_slave_killed(thd,mi)) &&
4332 4333 4334
	 (reconnect ? mysql_reconnect(mysql) != 0 :
	  mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0,
			     mi->port, 0, client_flag) == 0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4335
  {
4336
    /* Don't repeat last error */
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
4337
    if ((int)mysql_errno(mysql) != last_errno)
4338
    {
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
4339
      last_errno=mysql_errno(mysql);
4340
      suppress_warnings= 0;
4341
      sql_print_error("Slave I/O thread: error %s to master \
4342
'%s@%s:%d': \
4343
Error: '%s'  errno: %d  retry-time: %d  retries: %d",
4344
		      (reconnect ? "reconnecting" : "connecting"),
4345
		      mi->user,mi->host,mi->port,
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
4346
		      mysql_error(mysql), last_errno,
4347 4348
		      mi->connect_retry,
		      master_retry_count);
4349
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4350 4351 4352
    /*
      By default we try forever. The reason is that failure will trigger
      master election, so if the user did not set master_retry_count we
4353
      do not want to have election triggered on the first failure to
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4354
      connect
4355
    */
4356
    if (++err_count == master_retry_count)
4357 4358
    {
      slave_was_killed=1;
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
4359 4360
      if (reconnect)
        change_rpl_status(RPL_ACTIVE_SLAVE,RPL_LOST_SOLDIER);
4361 4362
      break;
    }
4363 4364
    safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed,
	       (void*)mi);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4365
  }
4366

4367 4368
  if (!slave_was_killed)
  {
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
4369
    if (reconnect)
4370
    { 
4371
      if (!suppress_warnings && global_system_variables.log_warnings)
4372
	sql_print_information("Slave: connected to master '%s@%s:%d',\
4373
replication resumed in log '%s' at position %s", mi->user,
4374 4375 4376 4377
			mi->host, mi->port,
			IO_RPL_LOG_NAME,
			llstr(mi->master_log_pos,llbuff));
    }
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
4378 4379 4380 4381
    else
    {
      change_rpl_status(RPL_IDLE_SLAVE,RPL_ACTIVE_SLAVE);
      mysql_log.write(thd, COM_CONNECT_OUT, "%s@%s:%d",
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4382
		      mi->user, mi->host, mi->port);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
4383
    }
4384
#ifdef SIGNAL_WITH_VIO_CLOSE
4385
    thd->set_active_vio(mysql->net.vio);
4386
#endif      
4387
  }
4388 4389
  DBUG_PRINT("exit",("slave_was_killed: %d", slave_was_killed));
  DBUG_RETURN(slave_was_killed);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4390 4391
}

4392

sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
4393
/*
4394
  safe_reconnect()
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4395

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4396 4397 4398
  IMPLEMENTATION
    Try to connect until successful or slave killed or we have retried
    master_retry_count times
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
4399 4400
*/

4401 4402
static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
			  bool suppress_warnings)
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
4403
{
4404 4405
  DBUG_ENTER("safe_reconnect");
  DBUG_RETURN(connect_to_master(thd, mysql, mi, 1, suppress_warnings));
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
4406 4407
}

4408

4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438
/*
  Store the file and position where the execute-slave thread are in the
  relay log.

  SYNOPSIS
    flush_relay_log_info()
    rli			Relay log information

  NOTES
    - As this is only called by the slave thread, we don't need to
      have a lock on this.
    - If there is an active transaction, then we don't update the position
      in the relay log.  This is to ensure that we re-execute statements
      if we die in the middle of an transaction that was rolled back.
    - As a transaction never spans binary logs, we don't have to handle the
      case where we do a relay-log-rotation in the middle of the transaction.
      If this would not be the case, we would have to ensure that we
      don't delete the relay log file where the transaction started when
      we switch to a new relay log file.

  TODO
    - Change the log file information to a binary format to avoid calling
      longlong2str.

  RETURN VALUES
    0	ok
    1	write error
*/

bool flush_relay_log_info(RELAY_LOG_INFO* rli)
4439
{
4440 4441 4442 4443
  bool error=0;
  IO_CACHE *file = &rli->info_file;
  char buff[FN_REFLEN*2+22*2+4], *pos;

4444
  my_b_seek(file, 0L);
4445
  pos=strmov(buff, rli->group_relay_log_name);
4446
  *pos++='\n';
4447
  pos=longlong2str(rli->group_relay_log_pos, pos, 10);
4448
  *pos++='\n';
4449
  pos=strmov(pos, rli->group_master_log_name);
4450
  *pos++='\n';
4451
  pos=longlong2str(rli->group_master_log_pos, pos, 10);
4452
  *pos='\n';
4453
  if (my_b_write(file, (byte*) buff, (ulong) (pos-buff)+1))
4454 4455 4456
    error=1;
  if (flush_io_cache(file))
    error=1;
4457
  /* Flushing the relay log is done by the slave I/O thread */
4458
  return error;
4459 4460
}

4461

4462
/*
4463
  Called when we notice that the current "hot" log got rotated under our feet.
4464 4465 4466
*/

static IO_CACHE *reopen_relay_log(RELAY_LOG_INFO *rli, const char **errmsg)
4467 4468 4469
{
  DBUG_ASSERT(rli->cur_log != &rli->cache_buf);
  DBUG_ASSERT(rli->cur_log_fd == -1);
4470 4471 4472
  DBUG_ENTER("reopen_relay_log");

  IO_CACHE *cur_log = rli->cur_log=&rli->cache_buf;
4473
  if ((rli->cur_log_fd=open_binlog(cur_log,rli->event_relay_log_name,
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4474
				   errmsg)) <0)
4475
    DBUG_RETURN(0);
4476 4477 4478 4479 4480
  /*
    We want to start exactly where we was before:
    relay_log_pos	Current log pos
    pending		Number of bytes already processed from the event
  */
4481
  rli->event_relay_log_pos= max(rli->event_relay_log_pos, BIN_LOG_HEADER_SIZE);
4482
  my_b_seek(cur_log,rli->event_relay_log_pos);
4483
  DBUG_RETURN(cur_log);
4484 4485
}

4486

4487 4488 4489 4490
Log_event* next_event(RELAY_LOG_INFO* rli)
{
  Log_event* ev;
  IO_CACHE* cur_log = rli->cur_log;
4491
  pthread_mutex_t *log_lock = rli->relay_log.get_log_lock(); 
4492 4493
  const char* errmsg=0;
  THD* thd = rli->sql_thd;
4494
  
4495
  DBUG_ENTER("next_event");
4496 4497
  DBUG_ASSERT(thd != 0);

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4498 4499
  /*
    For most operations we need to protect rli members with data_lock,
4500 4501 4502 4503
    so we assume calling function acquired this mutex for us and we will
    hold it for the most of the loop below However, we will release it
    whenever it is worth the hassle,  and in the cases when we go into a
    pthread_cond_wait() with the non-data_lock mutex
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4504
  */
4505
  safe_mutex_assert_owner(&rli->data_lock);
4506
  
4507
  while (!sql_slave_killed(thd,rli))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4508 4509 4510
  {
    /*
      We can have two kinds of log reading:
4511 4512 4513 4514 4515 4516 4517 4518
      hot_log:
        rli->cur_log points at the IO_CACHE of relay_log, which
        is actively being updated by the I/O thread. We need to be careful
        in this case and make sure that we are not looking at a stale log that
        has already been rotated. If it has been, we reopen the log.

      The other case is much simpler:
        We just have a read only log that nobody else will be updating.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4519
    */
4520 4521 4522 4523 4524
    bool hot_log;
    if ((hot_log = (cur_log != &rli->cache_buf)))
    {
      DBUG_ASSERT(rli->cur_log_fd == -1); // foreign descriptor
      pthread_mutex_lock(log_lock);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4525 4526

      /*
4527
	Reading xxx_file_id is safe because the log will only
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4528 4529
	be rotated when we hold relay_log.LOCK_log
      */
4530
      if (rli->relay_log.get_open_count() != rli->cur_log_old_open_count)
4531
      {
4532 4533 4534 4535
	// The master has switched to a new log file; Reopen the old log file
	cur_log=reopen_relay_log(rli, &errmsg);
	pthread_mutex_unlock(log_lock);
	if (!cur_log)				// No more log files
4536
	  goto err;
4537
	hot_log=0;				// Using old binary log
4538 4539
      }
    }
4540

4541 4542
#ifndef DBUG_OFF
    {
4543
      /* This is an assertion which sometimes fails, let's try to track it */
4544
      char llbuf1[22], llbuf2[22];
4545
      DBUG_PRINT("info", ("my_b_tell(cur_log)=%s rli->event_relay_log_pos=%s",
4546
                          llstr(my_b_tell(cur_log),llbuf1), 
4547 4548 4549
                          llstr(rli->event_relay_log_pos,llbuf2)));
      DBUG_ASSERT(my_b_tell(cur_log) >= BIN_LOG_HEADER_SIZE);
      DBUG_ASSERT(my_b_tell(cur_log) == rli->event_relay_log_pos);
4550 4551
    }
#endif
4552 4553
    /*
      Relay log is always in new format - if the master is 3.23, the
4554
      I/O thread will convert the format for us.
4555 4556
      A problem: the description event may be in a previous relay log. So if
      the slave has been shutdown meanwhile, we would have to look in old relay
4557 4558
      logs, which may even have been deleted. So we need to write this
      description event at the beginning of the relay log.
4559 4560
      When the relay log is created when the I/O thread starts, easy: the
      master will send the description event and we will queue it.
4561 4562
      But if the relay log is created by new_file(): then the solution is:
      MYSQL_LOG::open() will write the buffered description event.
4563
    */
4564 4565 4566
    if ((ev=Log_event::read_log_event(cur_log,0,
                                      rli->relay_log.description_event_for_exec)))
      
4567 4568
    {
      DBUG_ASSERT(thd==rli->sql_thd);
4569 4570 4571 4572 4573
      /*
        read it while we have a lock, to avoid a mutex lock in
        inc_event_relay_log_pos()
      */
      rli->future_event_relay_log_pos= my_b_tell(cur_log);
4574 4575
      if (hot_log)
	pthread_mutex_unlock(log_lock);
4576
      DBUG_RETURN(ev);
4577 4578
    }
    DBUG_ASSERT(thd==rli->sql_thd);
4579
    if (opt_reckless_slave)			// For mysql-test
4580
      cur_log->error = 0;
4581
    if (cur_log->error < 0)
4582 4583
    {
      errmsg = "slave SQL thread aborted because of I/O error";
4584 4585
      if (hot_log)
	pthread_mutex_unlock(log_lock);
4586 4587
      goto err;
    }
4588 4589
    if (!cur_log->error) /* EOF */
    {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4590 4591 4592 4593 4594
      /*
	On a hot log, EOF means that there are no more updates to
	process and we must block until I/O thread adds some and
	signals us to continue
      */
4595 4596
      if (hot_log)
      {
4597
	DBUG_ASSERT(rli->relay_log.get_open_count() == rli->cur_log_old_open_count);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4598 4599 4600 4601
	/*
	  We can, and should release data_lock while we are waiting for
	  update. If we do not, show slave status will block
	*/
4602
	pthread_mutex_unlock(&rli->data_lock);
4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624

        /*
          Possible deadlock : 
          - the I/O thread has reached log_space_limit
          - the SQL thread has read all relay logs, but cannot purge for some
          reason:
            * it has already purged all logs except the current one
            * there are other logs than the current one but they're involved in
            a transaction that finishes in the current one (or is not finished)
          Solution :
          Wake up the possibly waiting I/O thread, and set a boolean asking
          the I/O thread to temporarily ignore the log_space_limit
          constraint, because we do not want the I/O thread to block because of
          space (it's ok if it blocks for any other reason (e.g. because the
          master does not send anything). Then the I/O thread stops waiting 
          and reads more events.
          The SQL thread decides when the I/O thread should take log_space_limit
          into account again : ignore_log_space_limit is reset to 0 
          in purge_first_log (when the SQL thread purges the just-read relay
          log), and also when the SQL thread starts. We should also reset
          ignore_log_space_limit to 0 when the user does RESET SLAVE, but in
          fact, no need as RESET SLAVE requires that the slave
guilhem@mysql.com's avatar
guilhem@mysql.com committed
4625 4626
          be stopped, and the SQL thread sets ignore_log_space_limit to 0 when
          it stops.
4627 4628 4629 4630
        */
        pthread_mutex_lock(&rli->log_space_lock);
        // prevent the I/O thread from blocking next times
        rli->ignore_log_space_limit= 1; 
4631 4632 4633 4634 4635 4636
        /*
          If the I/O thread is blocked, unblock it.
          Ok to broadcast after unlock, because the mutex is only destroyed in
          ~st_relay_log_info(), i.e. when rli is destroyed, and rli will not be
          destroyed before we exit the present function.
        */
4637
        pthread_mutex_unlock(&rli->log_space_lock);
4638
        pthread_cond_broadcast(&rli->log_space_cond);
4639
        // Note that wait_for_update unlocks lock_log !
4640
        rli->relay_log.wait_for_update(rli->sql_thd, 1);
4641 4642
        // re-acquire data lock since we released it earlier
        pthread_mutex_lock(&rli->data_lock);
4643 4644
	continue;
      }
4645 4646 4647 4648 4649 4650 4651 4652 4653 4654
      /*
	If the log was not hot, we need to move to the next log in
	sequence. The next log could be hot or cold, we deal with both
	cases separately after doing some common initialization
      */
      end_io_cache(cur_log);
      DBUG_ASSERT(rli->cur_log_fd >= 0);
      my_close(rli->cur_log_fd, MYF(MY_WME));
      rli->cur_log_fd = -1;
	
4655
      if (relay_log_purge)
4656
      {
4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671
	/*
          purge_first_log will properly set up relay log coordinates in rli.
          If the group's coordinates are equal to the event's coordinates
          (i.e. the relay log was not rotated in the middle of a group),
          we can purge this relay log too.
          We do ulonglong and string comparisons, this may be slow but
          - purging the last relay log is nice (it can save 1GB of disk), so we
          like to detect the case where we can do it, and given this,
          - I see no better detection method
          - purge_first_log is not called that often
        */
	if (rli->relay_log.purge_first_log
            (rli,
             rli->group_relay_log_pos == rli->event_relay_log_pos
             && !strcmp(rli->group_relay_log_name,rli->event_relay_log_name)))
4672
	{
4673
	  errmsg = "Error purging processed logs";
4674 4675 4676
	  goto err;
	}
      }
4677 4678
      else
      {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4679
	/*
4680 4681 4682 4683 4684
	  If hot_log is set, then we already have a lock on
	  LOCK_log.  If not, we have to get the lock.

	  According to Sasha, the only time this code will ever be executed
	  is if we are recovering from a bug.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4685
	*/
4686
	if (rli->relay_log.find_next_log(&rli->linfo, !hot_log))
4687
	{
4688 4689
	  errmsg = "error switching to the next log";
	  goto err;
4690
	}
4691 4692 4693
	rli->event_relay_log_pos = BIN_LOG_HEADER_SIZE;
	strmake(rli->event_relay_log_name,rli->linfo.log_file_name,
		sizeof(rli->event_relay_log_name)-1);
4694 4695
	flush_relay_log_info(rli);
      }
4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709

      /*
        Now we want to open this next log. To know if it's a hot log (the one
        being written by the I/O thread now) or a cold log, we can use
        is_active(); if it is hot, we use the I/O cache; if it's cold we open
        the file normally. But if is_active() reports that the log is hot, this
        may change between the test and the consequence of the test. So we may
        open the I/O cache whereas the log is now cold, which is nonsense.
        To guard against this, we need to have LOCK_log.
      */

      DBUG_PRINT("info",("hot_log: %d",hot_log));
      if (!hot_log) /* if hot_log, we already have this mutex */
        pthread_mutex_lock(log_lock);
4710 4711
      if (rli->relay_log.is_active(rli->linfo.log_file_name))
      {
4712
#ifdef EXTRA_DEBUG
4713
	if (global_system_variables.log_warnings)
4714 4715
	  sql_print_information("next log '%s' is currently active",
                                rli->linfo.log_file_name);
4716
#endif	  
4717 4718 4719
	rli->cur_log= cur_log= rli->relay_log.get_log_file();
	rli->cur_log_old_open_count= rli->relay_log.get_open_count();
	DBUG_ASSERT(rli->cur_log_fd == -1);
4720
	  
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4721
	/*
4722
	  Read pointer has to be at the start since we are the only
4723 4724 4725 4726
	  reader.
          We must keep the LOCK_log to read the 4 first bytes, as this is a hot
          log (same as when we call read_log_event() above: for a hot log we
          take the mutex).
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4727
	*/
4728
	if (check_binlog_magic(cur_log,&errmsg))
4729 4730
        {
          if (!hot_log) pthread_mutex_unlock(log_lock);
4731
	  goto err;
4732 4733
        }
        if (!hot_log) pthread_mutex_unlock(log_lock);
4734
	continue;
4735
      }
4736
      if (!hot_log) pthread_mutex_unlock(log_lock);
4737
      /*
4738 4739 4740
	if we get here, the log was not hot, so we will have to open it
	ourselves. We are sure that the log is still not hot now (a log can get
	from hot to cold, but not from cold to hot). No need for LOCK_log.
4741 4742
      */
#ifdef EXTRA_DEBUG
4743
      if (global_system_variables.log_warnings)
4744 4745
	sql_print_information("next log '%s' is not active",
                              rli->linfo.log_file_name);
4746 4747 4748 4749 4750
#endif	  
      // open_binlog() will check the magic header
      if ((rli->cur_log_fd=open_binlog(cur_log,rli->linfo.log_file_name,
				       &errmsg)) <0)
	goto err;
4751
    }
4752
    else
4753
    {
4754 4755 4756 4757 4758 4759
      /*
	Read failed with a non-EOF error.
	TODO: come up with something better to handle this error
      */
      if (hot_log)
	pthread_mutex_unlock(log_lock);
4760
      sql_print_error("Slave SQL thread: I/O error reading \
4761
event(errno: %d  cur_log->error: %d)",
4762
		      my_errno,cur_log->error);
4763
      // set read position to the beginning of the event
4764
      my_b_seek(cur_log,rli->event_relay_log_pos);
4765 4766
      /* otherwise, we have had a partial read */
      errmsg = "Aborting slave SQL thread because of partial event read";
4767
      break;					// To end of function
4768 4769
    }
  }
4770
  if (!errmsg && global_system_variables.log_warnings)
4771 4772 4773 4774 4775
  {
    sql_print_information("Error reading relay log event: %s", 
                          "slave SQL thread was killed");
    DBUG_RETURN(0);
  }
4776

4777
err:
4778 4779
  if (errmsg)
    sql_print_error("Error reading relay log event: %s", errmsg);
4780
  DBUG_RETURN(0);
4781 4782
}

4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793
/*
  Rotate a relay log (this is used only by FLUSH LOGS; the automatic rotation
  because of size is simpler because when we do it we already have all relevant
  locks; here we don't, so this function is mainly taking locks). 
  Returns nothing as we cannot catch any error (MYSQL_LOG::new_file() is void).
*/

void rotate_relay_log(MASTER_INFO* mi)
{
  DBUG_ENTER("rotate_relay_log");
  RELAY_LOG_INFO* rli= &mi->rli;
guilhem@mysql.com's avatar
guilhem@mysql.com committed
4794

4795 4796 4797
  /* We don't lock rli->run_lock. This would lead to deadlocks. */
  pthread_mutex_lock(&mi->run_lock);

guilhem@mysql.com's avatar
guilhem@mysql.com committed
4798 4799 4800 4801
  /* 
     We need to test inited because otherwise, new_file() will attempt to lock
     LOCK_log, which may not be inited (if we're not a slave).
  */
4802 4803
  if (!rli->inited)
  {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4804
    DBUG_PRINT("info", ("rli->inited == 0"));
guilhem@mysql.com's avatar
guilhem@mysql.com committed
4805
    goto end;
4806
  }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4807

4808 4809
  /* If the relay log is closed, new_file() will do nothing. */
  rli->relay_log.new_file(1);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4810

4811 4812 4813 4814
  /*
    We harvest now, because otherwise BIN_LOG_HEADER_SIZE will not immediately
    be counted, so imagine a succession of FLUSH LOGS  and assume the slave
    threads are started:
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4815 4816 4817 4818 4819 4820
    relay_log_space decreases by the size of the deleted relay log, but does
    not increase, so flush-after-flush we may become negative, which is wrong.
    Even if this will be corrected as soon as a query is replicated on the
    slave (because the I/O thread will then call harvest_bytes_written() which
    will harvest all these BIN_LOG_HEADER_SIZE we forgot), it may give strange
    output in SHOW SLAVE STATUS meanwhile. So we harvest now.
4821 4822 4823 4824
    If the log is closed, then this will just harvest the last writes, probably
    0 as they probably have been harvested.
  */
  rli->relay_log.harvest_bytes_written(&rli->log_space_total);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
4825
end:
4826
  pthread_mutex_unlock(&mi->run_lock);
4827 4828 4829
  DBUG_VOID_RETURN;
}

sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
4830

bk@work.mysql.com's avatar
bk@work.mysql.com committed
4831 4832
#ifdef __GNUC__
template class I_List_iterator<i_string>;
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
4833
template class I_List_iterator<i_string_pair>;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4834
#endif
4835

4836

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