slave.cc 157 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, (SLAVE_IO | SLAVE_SQL)))
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
int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
			   pthread_mutex_t *cond_lock,
			   pthread_cond_t* term_cond,
661
			   volatile uint *slave_running)
662
{
663
  DBUG_ENTER("terminate_slave_thread");
664 665 666 667 668 669
  if (term_lock)
  {
    pthread_mutex_lock(term_lock);
    if (!*slave_running)
    {
      pthread_mutex_unlock(term_lock);
670
      DBUG_RETURN(ER_SLAVE_NOT_RUNNING);
671 672 673
    }
  }
  DBUG_ASSERT(thd != 0);
674 675 676
  /*
    Is is criticate to test if the slave is running. Otherwise, we might
    be referening freed memory trying to kick it
677
  */
678
  THD_CHECK_SENTRY(thd);
679 680

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

697

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

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

761

762
/*
763
  start_slave_threads()
764

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
765 766 767 768
  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
769
*/
770

771 772 773 774 775 776 777
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;
778
  DBUG_ENTER("start_slave_threads");
779 780 781 782 783 784 785 786 787 788 789 790 791
  
  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;
  }
792 793 794

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

810

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

819

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

827

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

847

848 849 850 851 852 853 854 855 856 857 858 859 860
/*
  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 
861 862 863 864 865 866 867 868 869 870
    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)).
871

872 873
    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
874 875
    supported Perl regexps we could do it with this pattern: /^abc\.(?!EFG)/
    (I could not find an equivalent in the regex library MySQL uses).
876 877 878 879 880

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

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

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

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

917
  /*
918 919
    If no table was to be updated, ignore statement (no reason we play it on
    slave, slave is supposed to replicate _changes_ only).
920 921 922
    If no explicit rule found and there was a do list, do not replicate.
    If there was no do list, go ahead
  */
923 924
  DBUG_RETURN(some_tables_updating &&
              !do_table_inited && !wild_do_table_inited);
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 976 977
/*
  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;
978 979 980 981 982
}


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

998

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

1003 1004
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
{
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
1005
  const char* dot = strchr(table_spec, '.');
1006
  if (!dot) return 1;
1007 1008 1009
  uint len = (uint)strlen(table_spec);
  TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
						 + len, MYF(MY_WME));
1010
  if (!e) return 1;
1011 1012 1013 1014 1015 1016 1017 1018
  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;
}

1019

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

1032

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

1041

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

  SYNOPSIS
    end_slave()
*/
1048

1049 1050
void end_slave()
{
1051 1052 1053 1054 1055 1056 1057 1058
  /*
    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
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
  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;
  }
1079
  pthread_mutex_unlock(&LOCK_active_mi);
1080
}
1081

1082

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

1090

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

1098

1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
/*
  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
1113
*/
1114

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

1131 1132
}

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

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

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
}

1147

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

1154

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

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

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

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

1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
/*
  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                  
*/
1199

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

1206 1207 1208 1209 1210
  /*
    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
1211
    return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1212

1213 1214 1215 1216
  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
1217

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

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

1239

1240 1241
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
1242
{
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1243 1244 1245 1246 1247 1248 1249
  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
1250
    {
1251 1252 1253 1254
      /*
	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
1255
      int c;
1256
      while (((c=my_b_get(f)) != '\n' && c != my_b_EOF));
1257
    }
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1258 1259 1260 1261
    return 0;
  }
  else if (default_val)
  {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1262
    strmake(var,  default_val, max_size-1);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1263 1264
    return 0;
  }
1265
  return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1266 1267
}

1268

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1269
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
1270 1271 1272
{
  char buf[32];
  
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1273 1274 1275 1276 1277
  if (my_b_gets(f, buf, sizeof(buf))) 
  {
    *var = atoi(buf);
    return 0;
  }
1278
  else if (default_val)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1279 1280 1281 1282
  {
    *var = default_val;
    return 0;
  }
1283
  return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1284 1285
}

1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
/*
  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
*/
1299

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

  /*
    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;
1310
  
1311
  if (!my_isdigit(&my_charset_bin,*mysql->server_version))
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
1312
    errmsg = "Master reported unrecognized MySQL version";
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 1344 1345
  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;
    }
1346
  }
1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359
  
  /* 
     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;
  }
1360 1361 1362 1363 1364 1365 1366 1367

  /* 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;
  }

1368 1369 1370 1371 1372 1373 1374 1375 1376 1377
  /*
    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
1378
  {
1379 1380
    mi->clock_diff_with_master= 
      (long) (time((time_t*) 0) - strtoul(master_row[0], 0, 10));
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1381
  }
1382
  else
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1383
  {
1384
    mi->clock_diff_with_master= 0; /* The "most sensible" value */
1385
    sql_print_warning("\"SELECT UNIX_TIMESTAMP()\" failed on master, \
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411
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
1412 1413
  }

1414 1415 1416
  /*
    Check that the master's global character_set_server and ours are the same.
    Not fatal if query fails (old master?).
1417 1418 1419 1420 1421 1422
    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.
1423 1424 1425 1426 1427 1428
    The test is only relevant if master < 5.0.3 (we'll test only if it's older
    than the 5 branch; < 5.0.3 was alpha...), as >= 5.0.3 master stores
    charset info in each binlog event.
    We don't do it for 3.23 because masters <3.23.50 hang on
    SELECT @@unknown_var (BUG#7965 - see changelog of 3.23.50). So finally we
    test only if master is 4.x.
1429
  */
1430 1431 1432

  /* redundant with rest of code but safer against later additions */
  if (*mysql->server_version == '3')
1433
    goto err;
1434 1435 1436

  if ((*mysql->server_version == '4') &&
      !mysql_real_query(mysql, "SELECT @@GLOBAL.COLLATION_SERVER", 32) &&
1437
      (master_res= mysql_store_result(mysql)))
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1438
  {
1439 1440 1441 1442 1443 1444
    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
1445
  }
1446

1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458
  /*
    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).
1459 1460 1461

    TODO: when the new replication of timezones is sorted out with Dmitri,
    change >= '4' to == '4'.
1462
  */
1463 1464
  if ((*mysql->server_version >= '4') &&
      !mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) &&
1465
      (master_res= mysql_store_result(mysql)))
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1466
  {
1467 1468 1469 1470 1471 1472 1473
    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
1474 1475
  }

1476
err:
1477 1478 1479 1480 1481
  if (errmsg)
  {
    sql_print_error(errmsg);
    return 1;
  }
1482

1483 1484 1485
  return 0;
}

1486 1487 1488 1489
/*
  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.
1490
  db must be non-zero (guarded by assertion).
1491 1492 1493 1494 1495

  RETURN VALUES
    0           success
    1           error
*/
1496

1497
static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
1498
				  const char* table_name, bool overwrite)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1499
{
1500
  ulong packet_len;
1501 1502
  char *query, *save_db;
  uint32 save_db_length;
1503 1504
  Vio* save_vio;
  HA_CHECK_OPT check_opt;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1505
  TABLE_LIST tables;
1506 1507
  int error= 1;
  handler *file;
1508
  ulong save_options;
1509
  NET *net= &mysql->net;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1510 1511
  DBUG_ENTER("create_table_from_dump");  

1512
  packet_len= my_net_read(net); // read create table statement
1513 1514
  if (packet_len == packet_error)
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1515
    my_message(ER_MASTER_NET_READ, ER(ER_MASTER_NET_READ), MYF(0));
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1516
    DBUG_RETURN(1);
1517 1518 1519
  }
  if (net->read_pos[0] == 255) // error from master
  {
1520 1521 1522 1523
    char *err_msg; 
    err_msg= (char*) net->read_pos + ((mysql->server_capabilities &
				       CLIENT_PROTOCOL_41) ?
				      3+SQLSTATE_LENGTH+1 : 3);
1524
    my_error(ER_MASTER, MYF(0), err_msg);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1525
    DBUG_RETURN(1);
1526
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1527
  thd->command = COM_TABLE_DUMP;
1528
  thd->query_length= packet_len;
1529
  /* Note that we should not set thd->query until the area is initalized */
1530
  if (!(query = thd->strmake((char*) net->read_pos, packet_len)))
1531 1532
  {
    sql_print_error("create_table_from_dump: out of memory");
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1533
    my_message(ER_GET_ERRNO, "Out of memory", MYF(0));
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1534
    DBUG_RETURN(1);
1535
  }
1536
  thd->query= query;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1537 1538
  thd->query_error = 0;
  thd->net.no_send_ok = 1;
1539

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1540 1541
  bzero((char*) &tables,sizeof(tables));
  tables.db = (char*)db;
1542
  tables.alias= tables.table_name= (char*)table_name;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1543

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1544 1545 1546 1547 1548 1549 1550
  /* 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;
  }

1551
  /* Create the table. We do not want to log the "create table" statement */
1552
  save_options = thd->options;
1553
  thd->options &= ~(ulong) (OPTION_BIN_LOG);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1554
  thd->proc_info = "Creating table from master dump";
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1555
  // save old db in case we are creating in a different database
1556
  save_db = thd->db;
1557
  save_db_length= thd->db_length;
1558
  thd->db = (char*)db;
1559 1560
  DBUG_ASSERT(thd->db);
  thd->db_length= strlen(thd->db);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1561
  mysql_parse(thd, thd->query, packet_len); // run create table
1562
  thd->db = save_db;		// leave things the way the were before
1563
  thd->db_length= save_db_length;
1564
  thd->options = save_options;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1565
  
1566 1567
  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
1568 1569

  thd->proc_info = "Opening master dump table";
1570
  tables.lock_type = TL_WRITE;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1571 1572 1573
  if (!open_ltable(thd, &tables, TL_WRITE))
  {
    sql_print_error("create_table_from_dump: could not open created table");
1574
    goto err;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1575
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1576
  
1577
  file = tables.table->file;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1578
  thd->proc_info = "Reading master dump table data";
1579
  /* Copy the data file */
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1580 1581
  if (file->net_read_dump(net))
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1582
    my_message(ER_MASTER_NET_READ, ER(ER_MASTER_NET_READ), MYF(0));
1583
    sql_print_error("create_table_from_dump: failed in\
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1584
 handler::net_read_dump()");
1585
    goto err;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1586
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1587 1588

  check_opt.init();
serg@serg.mysql.com's avatar
serg@serg.mysql.com committed
1589
  check_opt.flags|= T_VERY_SILENT | T_CALC_CHECKSUM | T_QUICK;
jcole@tetra.spaceapes.com's avatar
jcole@tetra.spaceapes.com committed
1590
  thd->proc_info = "Rebuilding the index on master dump table";
1591 1592 1593 1594 1595
  /*
    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.
  */
1596
  save_vio = thd->net.vio;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1597
  thd->net.vio = 0;
1598
  /* Rebuild the index file from the copied data file (with REPAIR) */
1599
  error=file->repair(thd,&check_opt) != 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1600
  thd->net.vio = save_vio;
1601
  if (error)
1602
    my_error(ER_INDEX_REBUILD, MYF(0), tables.table->s->table_name);
1603 1604

err:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1605 1606
  close_thread_tables(thd);
  thd->net.no_send_ok = 0;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1607
  DBUG_RETURN(error); 
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1608 1609
}

1610

1611
int fetch_master_table(THD *thd, const char *db_name, const char *table_name,
1612
		       MASTER_INFO *mi, MYSQL *mysql, bool overwrite)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1613
{
1614 1615 1616 1617 1618 1619
  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
1620

monty@work.mysql.com's avatar
merge  
monty@work.mysql.com committed
1621
  if (!called_connected)
1622
  { 
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1623
    if (!(mysql = mysql_init(NULL)))
1624 1625 1626
    {
      DBUG_RETURN(1);
    }
monty@work.mysql.com's avatar
merge  
monty@work.mysql.com committed
1627
    if (connect_to_master(thd, mysql, mi))
1628
    {
1629
      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
1630
      mysql_close(mysql);
1631
      DBUG_RETURN(1);
1632
    }
1633 1634
    if (thd->killed)
      goto err;
1635
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1636

sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
1637
  if (request_table_dump(mysql, db_name, table_name))
1638
  {
1639 1640
    error= ER_UNKNOWN_ERROR;
    errmsg= "Failed on table dump request";
1641 1642
    goto err;
  }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1643 1644 1645
  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
1646
  error = 0;
1647

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1648
 err:
1649
  thd->net.no_send_ok = 0; // Clear up garbage after create_table_from_dump
1650
  if (!called_connected)
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1651
    mysql_close(mysql);
1652
  if (errmsg && thd->vio_ok())
1653
    my_message(error, errmsg, MYF(0));
1654
  DBUG_RETURN(test(error));			// Return 1 on error
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1655 1656
}

1657

1658 1659
void end_master_info(MASTER_INFO* mi)
{
1660 1661
  DBUG_ENTER("end_master_info");

1662
  if (!mi->inited)
1663
    DBUG_VOID_RETURN;
1664 1665
  end_relay_log_info(&mi->rli);
  if (mi->fd >= 0)
1666 1667 1668 1669 1670
  {
    end_io_cache(&mi->file);
    (void)my_close(mi->fd, MYF(MY_WME));
    mi->fd = -1;
  }
1671
  mi->inited = 0;
1672 1673

  DBUG_VOID_RETURN;
1674 1675
}

1676

1677 1678 1679 1680 1681 1682
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;
1683
  DBUG_ENTER("init_relay_log_info");
1684

1685
  if (rli->inited)				// Set if this function called
1686 1687
    DBUG_RETURN(0);
  fn_format(fname, info_fname, mysql_data_home, "", 4+32);
1688 1689 1690 1691
  pthread_mutex_lock(&rli->data_lock);
  info_fd = rli->info_fd;
  rli->cur_log_fd = -1;
  rli->slave_skip_counter=0;
1692
  rli->abort_pos_wait=0;
1693 1694
  rli->log_space_limit= relay_log_space_limit;
  rli->log_space_total= 0;
1695

1696 1697 1698 1699
  // TODO: make this work with multi-master
  if (!opt_relay_logname)
  {
    char tmp[FN_REFLEN];
1700 1701 1702
    /*
      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.
1703 1704 1705 1706 1707
    */
    strmake(tmp,glob_hostname,FN_REFLEN-5);
    strmov(strcend(tmp,'.'),"-relay-bin");
    opt_relay_logname=my_strdup(tmp,MYF(MY_WME));
  }
1708 1709

  /*
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1710 1711 1712
    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).
1713 1714
  */

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1715 1716 1717 1718 1719 1720 1721 1722 1723 1724
  /*
    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).
  */

1725 1726 1727
  if (open_log(&rli->relay_log, glob_hostname, opt_relay_logname,
	       "-relay-bin", opt_relaylog_index_name,
	       LOG_BIN, 1 /* read_append cache */,
1728
	       0 /* starting from 5.0 we want relay logs to have auto events */,
1729
               max_relay_log_size ? max_relay_log_size : max_binlog_size))
1730
  {
1731
    pthread_mutex_unlock(&rli->data_lock);
1732
    sql_print_error("Failed in open_log() called from init_relay_log_info()");
1733
    DBUG_RETURN(1);
1734
  }
1735

1736
  /* if file does not exist */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1737
  if (access(fname,F_OK))
1738
  {
1739 1740 1741 1742
    /*
      If someone removed the file from underneath our feet, just close
      the old descriptor and re-create the old file
    */
1743 1744
    if (info_fd >= 0)
      my_close(info_fd, MYF(MY_WME));
1745
    if ((info_fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
1746
    {
1747 1748 1749 1750 1751 1752 1753
      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))) 
1754
    {
1755 1756
      sql_print_error("Failed to create a cache on relay log info file '%s'",
		      fname);
1757 1758
      msg= current_thd->net.last_error;
      goto err;
1759
    }
1760 1761 1762

    /* 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 */,
1763
			   &msg, 0))
1764
    {
1765
      sql_print_error("Failed to open the relay log 'FIRST' (relay_log_pos 4)");
1766
      goto err;
1767
    }
1768 1769
    rli->group_master_log_name[0]= 0;
    rli->group_master_log_pos= 0;		
1770
    rli->info_fd= info_fd;
1771 1772 1773
  }
  else // file exists
  {
1774
    if (info_fd >= 0)
1775
      reinit_io_cache(&rli->info_file, READ_CACHE, 0L,0,0);
1776
    else 
1777
    {
1778 1779 1780
      int error=0;
      if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
      {
1781 1782 1783
        sql_print_error("\
Failed to open the existing relay log info file '%s' (errno %d)",
			fname, my_errno);
1784 1785 1786 1787 1788
        error= 1;
      }
      else if (init_io_cache(&rli->info_file, info_fd,
                             IO_SIZE*2, READ_CACHE, 0L, 0, MYF(MY_WME)))
      {
1789 1790
        sql_print_error("Failed to create a cache on relay log info file '%s'",
			fname);
1791 1792 1793 1794 1795 1796 1797
        error= 1;
      }
      if (error)
      {
        if (info_fd >= 0)
          my_close(info_fd, MYF(0));
        rli->info_fd= -1;
1798
        rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
1799 1800 1801
        pthread_mutex_unlock(&rli->data_lock);
        DBUG_RETURN(1);
      }
1802
    }
1803
         
1804
    rli->info_fd = info_fd;
1805
    int relay_log_pos, master_log_pos;
1806
    if (init_strvar_from_file(rli->group_relay_log_name,
monty@mysql.com's avatar
monty@mysql.com committed
1807 1808
			      sizeof(rli->group_relay_log_name),
                              &rli->info_file, "") ||
1809
       init_intvar_from_file(&relay_log_pos,
1810
			     &rli->info_file, BIN_LOG_HEADER_SIZE) ||
1811
       init_strvar_from_file(rli->group_master_log_name,
monty@mysql.com's avatar
monty@mysql.com committed
1812 1813
			     sizeof(rli->group_master_log_name),
                             &rli->info_file, "") ||
1814
       init_intvar_from_file(&master_log_pos, &rli->info_file, 0))
1815 1816 1817 1818
    {
      msg="Error reading slave log configuration";
      goto err;
    }
1819 1820 1821 1822
    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;
1823

1824
    if (init_relay_log_pos(rli,
1825 1826
			   rli->group_relay_log_name,
			   rli->group_relay_log_pos,
1827
			   0 /* no data lock*/,
1828
			   &msg, 0))
1829 1830
    {
      char llbuf[22];
1831
      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
1832 1833
		      rli->group_relay_log_name,
		      llstr(rli->group_relay_log_pos, llbuf));
1834
      goto err;
1835
    }
1836
  }
1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848

#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

1849 1850 1851 1852
  /*
    Now change the cache from READ to WRITE - must do this
    before flush_relay_log_info
  */
1853
  reinit_io_cache(&rli->info_file, WRITE_CACHE,0L,0,1);
1854 1855
  if ((error= flush_relay_log_info(rli)))
    sql_print_error("Failed to flush relay log info file");
1856 1857 1858 1859 1860
  if (count_relay_log_space(rli))
  {
    msg="Error counting relay log space";
    goto err;
  }
1861
  rli->inited= 1;
1862
  pthread_mutex_unlock(&rli->data_lock);
1863
  DBUG_RETURN(error);
1864 1865 1866 1867

err:
  sql_print_error(msg);
  end_io_cache(&rli->info_file);
1868 1869
  if (info_fd >= 0)
    my_close(info_fd, MYF(0));
1870
  rli->info_fd= -1;
1871
  rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
1872
  pthread_mutex_unlock(&rli->data_lock);
1873
  DBUG_RETURN(1);
1874 1875
}

1876

1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890
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)));
1891
#endif  
1892 1893 1894
  DBUG_RETURN(0);
}

1895

1896 1897
static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli)
{
1898
  bool slave_killed=0;
1899
  MASTER_INFO* mi = rli->mi;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1900
  const char *save_proc_info;
1901
  THD* thd = mi->io_thd;
1902

1903
  DBUG_ENTER("wait_for_relay_log_space");
1904

1905
  pthread_mutex_lock(&rli->log_space_lock);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1906 1907
  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
1908
				  "\
1909
Waiting for the slave SQL thread to free enough relay log space");
1910
  while (rli->log_space_limit < rli->log_space_total &&
1911 1912
	 !(slave_killed=io_slave_killed(thd,mi)) &&
         !rli->ignore_log_space_limit)
1913
    pthread_cond_wait(&rli->log_space_cond, &rli->log_space_lock);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
1914
  thd->exit_cond(save_proc_info);
1915 1916 1917
  DBUG_RETURN(slave_killed);
}

1918

1919 1920 1921 1922
static int count_relay_log_space(RELAY_LOG_INFO* rli)
{
  LOG_INFO linfo;
  DBUG_ENTER("count_relay_log_space");
1923
  rli->log_space_total= 0;
1924
  if (rli->relay_log.find_log_pos(&linfo, NullS, 1))
1925 1926 1927 1928
  {
    sql_print_error("Could not find first log while counting relay log space");
    DBUG_RETURN(1);
  }
1929
  do
1930 1931 1932
  {
    if (add_relay_log(rli,&linfo))
      DBUG_RETURN(1);
1933
  } while (!rli->relay_log.find_next_log(&linfo, 1));
1934 1935 1936 1937 1938 1939
  /* 
     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();
1940 1941
  DBUG_RETURN(0);
}
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1942

1943

guilhem@mysql.com's avatar
guilhem@mysql.com committed
1944 1945 1946 1947 1948 1949 1950 1951 1952 1953
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
1954
    strmake(mi->password, master_password, MAX_PASSWORD_LENGTH);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
1955 1956
  mi->port = master_port;
  mi->connect_retry = master_connect_retry;
dlenev@mysql.com's avatar
dlenev@mysql.com committed
1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968
  
  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
1969 1970
}

1971
void clear_slave_error(RELAY_LOG_INFO* rli)
guilhem@mysql.com's avatar
guilhem@mysql.com committed
1972
{
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1973 1974 1975
  /* 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
1976
}
1977

1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991
/*
    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;
}


1992
#define LINES_IN_MASTER_INFO_WITH_SSL 14
1993

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

1995
int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
1996
		     const char* slave_info_fname,
1997 1998
		     bool abort_if_no_master_info_file,
		     int thread_mask)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1999
{
2000 2001 2002 2003
  int fd,error;
  char fname[FN_REFLEN+128];
  DBUG_ENTER("init_master_info");

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2004
  if (mi->inited)
2005 2006 2007 2008 2009 2010 2011
  {
    /*
      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.
2012 2013 2014 2015 2016
      
      We only rewind the read position if we are starting the SQL
      thread. The handle_slave_sql thread assumes that the read
      position is at the beginning of the file, and will read the
      "signature" and then fast-forward to the last position read.
2017
    */
monty@mysql.com's avatar
monty@mysql.com committed
2018 2019
    if (thread_mask & SLAVE_SQL)
    {
2020 2021
      my_b_seek(mi->rli.cur_log, (my_off_t) 0);
    }
2022
    DBUG_RETURN(0);
2023 2024
  }

2025 2026
  mi->mysql=0;
  mi->file_id=1;
2027
  fn_format(fname, master_info_fname, mysql_data_home, "", 4+32);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2028

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2029 2030 2031 2032
  /*
    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
2033

2034
  pthread_mutex_lock(&mi->data_lock);
2035
  fd = mi->fd;
2036 2037

  /* does master.info exist ? */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2038
  
2039
  if (access(fname,F_OK))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2040
  {
2041 2042 2043 2044 2045
    if (abort_if_no_master_info_file)
    {
      pthread_mutex_unlock(&mi->data_lock);
      DBUG_RETURN(0);
    }
2046 2047 2048 2049
    /*
      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
2050 2051
    if (fd >= 0)
      my_close(fd, MYF(MY_WME));
2052 2053 2054 2055 2056 2057 2058
    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,
2059
		      MYF(MY_WME)))
2060 2061 2062
    {
      sql_print_error("Failed to create a cache on master info file (\
file '%s')", fname);
2063
      goto err;
2064
    }
2065

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2066
    mi->fd = fd;
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2067 2068
    init_master_info_with_options(mi);

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2069
  }
2070
  else // file exists
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2071
  {
2072
    if (fd >= 0)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2073
      reinit_io_cache(&mi->file, READ_CACHE, 0L,0,0);
2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089
    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
2090

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2091
    mi->fd = fd;
2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117
    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.
    */
2118
    if (init_strvar_from_file(mi->master_log_name,
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2119
			      sizeof(mi->master_log_name), &mi->file,
2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135
			      ""))
      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
2136 2137 2138 2139
	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) || 
2140 2141
        init_strvar_from_file(mi->password, SCRAMBLED_PASSWORD_CHAR_LENGTH+1,
                              &mi->file, master_password) ||
2142 2143
	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
2144
			      master_connect_retry))
2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167
      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)
2168
      sql_print_warning("SSL information in the master info file "
2169 2170 2171 2172
                      "('%s') are ignored because this MySQL slave was compiled "
                      "without SSL support.", fname);
#endif /* HAVE_OPENSSL */
    
2173 2174 2175 2176 2177 2178 2179
    /*
      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;
2180
    mi->ssl= (my_bool) ssl;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2181
  }
2182 2183 2184
  DBUG_PRINT("master_info",("log_file_name: %s  position: %ld",
			    mi->master_log_name,
			    (ulong) mi->master_log_pos));
2185

2186
  mi->rli.mi = mi;
2187 2188 2189
  if (init_relay_log_info(&mi->rli, slave_info_fname))
    goto err;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2190
  mi->inited = 1;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2191
  // now change cache READ -> WRITE - must do this before flush_master_info
2192
  reinit_io_cache(&mi->file, WRITE_CACHE,0L,0,1);
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2193
  if ((error=test(flush_master_info(mi, 1))))
2194
    sql_print_error("Failed to flush master info file");
2195
  pthread_mutex_unlock(&mi->data_lock);
2196
  DBUG_RETURN(error);
2197 2198 2199 2200
  
errwithmsg:
  sql_print_error("Error reading master configuration");
  
2201
err:
2202 2203 2204 2205 2206 2207
  if (fd >= 0)
  {
    my_close(fd, MYF(0));
    end_io_cache(&mi->file);
  }
  mi->fd= -1;
2208
  pthread_mutex_unlock(&mi->data_lock);
2209
  DBUG_RETURN(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2210 2211
}

2212

2213 2214
int register_slave_on_master(MYSQL* mysql)
{
2215 2216
  char buf[1024], *pos= buf;
  uint report_host_len, report_user_len=0, report_password_len=0;
2217

2218
  if (!report_host)
2219
    return 0;
2220
  report_host_len= strlen(report_host);
2221
  if (report_user)
2222
    report_user_len= strlen(report_user);
2223
  if (report_password)
2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238
    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
2239
  if (simple_command(mysql, COM_REGISTER_SLAVE, (char*) buf,
2240
			(uint) (pos- buf), 0))
2241
  {
2242
    sql_print_error("Error on COM_REGISTER_SLAVE: %d '%s'",
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2243 2244
		    mysql_errno(mysql),
		    mysql_error(mysql));
2245 2246 2247 2248 2249
    return 1;
  }
  return 0;
}

2250

2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292
/*
  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);
  }
}

2293
bool show_master_info(THD* thd, MASTER_INFO* mi)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2294
{
2295
  // TODO: fix this for multi-master
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2296
  List<Item> field_list;
2297 2298 2299
  Protocol *protocol= thd->protocol;
  DBUG_ENTER("show_master_info");

guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2300 2301
  field_list.push_back(new Item_empty_string("Slave_IO_State",
						     14));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2302
  field_list.push_back(new Item_empty_string("Master_Host",
2303
						     sizeof(mi->host)));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2304
  field_list.push_back(new Item_empty_string("Master_User",
2305
						     sizeof(mi->user)));
2306 2307
  field_list.push_back(new Item_return_int("Master_Port", 7,
					   MYSQL_TYPE_LONG));
2308
  field_list.push_back(new Item_return_int("Connect_Retry", 10,
2309
					   MYSQL_TYPE_LONG));
2310
  field_list.push_back(new Item_empty_string("Master_Log_File",
2311 2312 2313
					     FN_REFLEN));
  field_list.push_back(new Item_return_int("Read_Master_Log_Pos", 10,
					   MYSQL_TYPE_LONGLONG));
2314
  field_list.push_back(new Item_empty_string("Relay_Log_File",
2315 2316 2317
					     FN_REFLEN));
  field_list.push_back(new Item_return_int("Relay_Log_Pos", 10,
					   MYSQL_TYPE_LONGLONG));
2318
  field_list.push_back(new Item_empty_string("Relay_Master_Log_File",
2319
					     FN_REFLEN));
2320 2321
  field_list.push_back(new Item_empty_string("Slave_IO_Running", 3));
  field_list.push_back(new Item_empty_string("Slave_SQL_Running", 3));
2322 2323 2324 2325 2326 2327
  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",
2328
					     28));
2329 2330 2331
  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,
2332
					   MYSQL_TYPE_LONG));
2333
  field_list.push_back(new Item_return_int("Exec_Master_Log_Pos", 10,
2334
					   MYSQL_TYPE_LONGLONG));
2335
  field_list.push_back(new Item_return_int("Relay_Log_Space", 10,
2336
					   MYSQL_TYPE_LONGLONG));
2337
  field_list.push_back(new Item_empty_string("Until_Condition", 6));
2338
  field_list.push_back(new Item_empty_string("Until_Log_File", FN_REFLEN));
2339
  field_list.push_back(new Item_return_int("Until_Log_Pos", 10, 
2340
                                           MYSQL_TYPE_LONGLONG));
2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351
  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)));
2352
  field_list.push_back(new Item_return_int("Seconds_Behind_Master", 10,
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2353
                                           MYSQL_TYPE_LONGLONG));
2354
  
2355 2356
  if (protocol->send_fields(&field_list,
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
2357
    DBUG_RETURN(TRUE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2358

2359 2360
  if (mi->host[0])
  {
2361
    DBUG_PRINT("info",("host is set: '%s'", mi->host));
2362
    String *packet= &thd->packet;
2363
    protocol->prepare_for_resend();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2364
  
2365 2366 2367 2368 2369
    /*
      TODO: we read slave_running without run_lock, whereas these variables
      are updated under run_lock and not data_lock. In 5.0 we should lock
      run_lock on top of data_lock (with good order).
    */
2370 2371
    pthread_mutex_lock(&mi->data_lock);
    pthread_mutex_lock(&mi->rli.data_lock);
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2372 2373

    protocol->store(mi->io_thd ? mi->io_thd->proc_info : "", &my_charset_bin);
2374 2375
    protocol->store(mi->host, &my_charset_bin);
    protocol->store(mi->user, &my_charset_bin);
2376 2377
    protocol->store((uint32) mi->port);
    protocol->store((uint32) mi->connect_retry);
2378
    protocol->store(mi->master_log_name, &my_charset_bin);
2379
    protocol->store((ulonglong) mi->master_log_pos);
2380
    protocol->store(mi->rli.group_relay_log_name +
2381 2382
		    dirname_length(mi->rli.group_relay_log_name),
		    &my_charset_bin);
2383 2384
    protocol->store((ulonglong) mi->rli.group_relay_log_pos);
    protocol->store(mi->rli.group_master_log_name, &my_charset_bin);
2385 2386
    protocol->store(mi->slave_running ? "Yes":"No", &my_charset_bin);
    protocol->store(mi->rli.slave_running ? "Yes":"No", &my_charset_bin);
2387 2388
    protocol->store(&replicate_do_db);
    protocol->store(&replicate_ignore_db);
2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405
    /*
      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);

2406
    protocol->store((uint32) mi->rli.last_slave_errno);
2407
    protocol->store(mi->rli.last_slave_error, &my_charset_bin);
2408
    protocol->store((uint32) mi->rli.slave_skip_counter);
2409
    protocol->store((ulonglong) mi->rli.group_master_log_pos);
2410
    protocol->store((ulonglong) mi->rli.log_space_total);
2411 2412 2413 2414 2415 2416 2417 2418

    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);
    
2419 2420 2421 2422 2423 2424 2425 2426 2427 2428
#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
2429

2430 2431 2432 2433 2434 2435
    /*
      Seconds_Behind_Master: if SQL thread is running and I/O thread is
      connected, we can compute it otherwise show NULL (i.e. unknown).
    */
    if ((mi->slave_running == MYSQL_SLAVE_RUN_CONNECT) &&
        mi->rli.slave_running)
2436 2437 2438 2439 2440
    {
      long tmp= (long)((time_t)time((time_t*) 0)
                               - mi->rli.last_master_timestamp)
        - mi->clock_diff_with_master;
      /*
2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454
        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.
2455 2456 2457 2458
        This confuses users, so we don't go below 0: hence the max().

        last_master_timestamp == 0 (an "impossible" timestamp 1970) is a
        special marker to say "consider we have caught up".
2459
      */
2460 2461
      protocol->store((longlong)(mi->rli.last_master_timestamp ? max(0, tmp)
                                 : 0));
2462
    }
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2463 2464 2465
    else
      protocol->store_null();

2466 2467
    pthread_mutex_unlock(&mi->rli.data_lock);
    pthread_mutex_unlock(&mi->data_lock);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2468
  
2469
    if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length()))
2470
      DBUG_RETURN(TRUE);
2471
  }
2472
  send_eof(thd);
2473
  DBUG_RETURN(FALSE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2474 2475
}

2476

guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2477
bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2478
{
2479
  IO_CACHE* file = &mi->file;
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
2480
  char lbuf[22];
2481 2482 2483
  DBUG_ENTER("flush_master_info");
  DBUG_PRINT("enter",("master_pos: %ld", (long) mi->master_log_pos));

2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507
  /*
    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).
  */

2508 2509 2510 2511 2512 2513 2514 2515
  /*
     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.
  */
  
2516
  my_b_seek(file, 0L);
2517 2518 2519
  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),
2520
	      mi->host, mi->user,
2521 2522 2523
	      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);
2524
  flush_io_cache(file);
2525
  DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2526 2527
}

2528

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2529
st_relay_log_info::st_relay_log_info()
2530 2531
  :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
2532 2533 2534 2535
   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)
2536
{
monty@mysql.com's avatar
monty@mysql.com committed
2537 2538
  group_relay_log_name[0]= event_relay_log_name[0]=
    group_master_log_name[0]= 0;
2539 2540
  last_slave_error[0]=0; until_log_name[0]= 0;

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2541 2542
  bzero((char*) &info_file, sizeof(info_file));
  bzero((char*) &cache_buf, sizeof(cache_buf));
2543
  cached_charset_invalidate();
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2544 2545 2546 2547 2548 2549 2550
  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
2551
  relay_log.init_pthread_objects();
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565
}


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);
}

2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589
/*
  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
 */
2590

2591
int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
2592 2593
                                    longlong log_pos,
                                    longlong timeout)
2594
{
2595 2596
  if (!inited)
    return -1;
2597
  int event_count = 0;
2598
  ulong init_abort_pos_wait;
2599 2600
  int error=0;
  struct timespec abstime; // for timeout checking
2601
  const char *msg;
2602
  DBUG_ENTER("wait_for_pos");
2603 2604
  DBUG_PRINT("enter",("log_name: '%s'  log_pos: %lu  timeout: %lu",
                      log_name->c_ptr(), (ulong) log_pos, (ulong) timeout));
2605

2606
  set_timespec(abstime,timeout);
2607
  pthread_mutex_lock(&data_lock);
2608 2609 2610
  msg= thd->enter_cond(&data_cond, &data_lock,
                       "Waiting for the slave SQL thread to "
                       "advance position");
2611
  /* 
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2612 2613 2614 2615 2616 2617 2618 2619
     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:
2620
     STOP SLAVE;CHANGE MASTER/RESET SLAVE; START SLAVE;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2621 2622
     the change may happen very quickly and we may not notice that
     slave_running briefly switches between 1/0/1.
2623
  */
2624
  init_abort_pos_wait= abort_pos_wait;
2625

2626
  /*
2627
    We'll need to
2628
    handle all possible log names comparisons (e.g. 999 vs 1000).
2629
    We use ulong for string->number conversion ; this is no
2630 2631 2632 2633
    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
2634 2635 2636

  strmake(log_name_tmp, log_name->ptr(), min(log_name->length(), FN_REFLEN-1));

2637 2638
  char *p= fn_ext(log_name_tmp);
  char *p_end;
2639
  if (!*p || log_pos<0)
2640 2641 2642 2643
  {
    error= -2; //means improper arguments
    goto err;
  }
2644 2645
  // 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
2646
  /* p points to '.' */
2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658
  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
2659
  /* The "compare and wait" main loop */
2660
  while (!thd->killed &&
2661
         init_abort_pos_wait == abort_pos_wait &&
2662
         slave_running)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2663
  {
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
2664 2665
    bool pos_reached;
    int cmp_result= 0;
monty@mysql.com's avatar
monty@mysql.com committed
2666

2667 2668 2669 2670 2671 2672
    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));

2673
    /*
monty@mysql.com's avatar
monty@mysql.com committed
2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684
      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 "".
2685
    */
2686
    if (*group_master_log_name)
2687
    {
monty@mysql.com's avatar
monty@mysql.com committed
2688 2689
      char *basename= (group_master_log_name +
                       dirname_length(group_master_log_name));
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2690
      /*
2691 2692 2693 2694
        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
2695
      */
2696 2697 2698 2699 2700 2701 2702 2703
      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;
2704 2705
      ulong group_master_log_name_extension= strtoul(q, &q_end, 10);
      if (group_master_log_name_extension < log_name_extension)
2706
        cmp_result= -1 ;
2707
      else
2708
        cmp_result= (group_master_log_name_extension > log_name_extension) ? 1 : 0 ;
2709

monty@mysql.com's avatar
monty@mysql.com committed
2710
      pos_reached= ((!cmp_result && group_master_log_pos >= (ulonglong)log_pos) ||
2711 2712
                    cmp_result > 0);
      if (pos_reached || thd->killed)
2713
        break;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2714
    }
2715 2716

    //wait for master update, with optional timeout.
2717
    
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2718
    DBUG_PRINT("info",("Waiting for master update"));
2719 2720 2721 2722
    /*
      We are going to pthread_cond_(timed)wait(); if the SQL thread stops it
      will wake us up.
    */
2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739
    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
2740
    DBUG_PRINT("info",("Got signal of master update or timed out"));
2741 2742 2743 2744 2745
    if (error == ETIMEDOUT || error == ETIME)
    {
      error= -1;
      break;
    }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2746
    error=0;
2747
    event_count++;
2748
    DBUG_PRINT("info",("Testing if killed or SQL thread not running"));
2749
  }
2750 2751

err:
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2752
  thd->exit_cond(msg);
2753
  DBUG_PRINT("exit",("killed: %d  abort: %d  slave_running: %d \
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2754
improper_arguments: %d  timed_out: %d",
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2755
                     thd->killed_errno(),
2756
                     (int) (init_abort_pos_wait != abort_pos_wait),
2757
                     (int) slave_running,
2758 2759 2760
                     (int) (error == -2),
                     (int) (error == -1)));
  if (thd->killed || init_abort_pos_wait != abort_pos_wait ||
2761
      !slave_running) 
2762 2763 2764 2765
  {
    error= -2;
  }
  DBUG_RETURN( error ? error : event_count );
2766 2767
}

2768 2769 2770 2771 2772
void set_slave_thread_options(THD* thd)
{
  thd->options = ((opt_log_slave_updates) ? OPTION_BIN_LOG:0) |
    OPTION_AUTO_IS_NULL;
}
2773

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2774
/*
2775
  init_slave_thread()
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2776
*/
2777

2778
static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2779 2780
{
  DBUG_ENTER("init_slave_thread");
2781 2782
  thd->system_thread = (thd_type == SLAVE_THD_SQL) ?
    SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO; 
2783
  thd->host_or_ip= "";
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2784 2785
  thd->client_capabilities = 0;
  my_net_init(&thd->net, 0);
2786
  thd->net.read_timeout = slave_net_timeout;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2787 2788
  thd->master_access= ~0;
  thd->priv_user = 0;
2789
  thd->slave_thread = 1;
2790
  set_slave_thread_options(thd);
2791
  /* 
2792
     It's nonsense to constrain the slave threads with max_join_size; if a
2793 2794 2795 2796 2797 2798
     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.
2799
  */
2800 2801
  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
2802
  thd->client_capabilities = CLIENT_LOCAL_FILES;
2803
  thd->real_id=pthread_self();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2804 2805 2806 2807
  pthread_mutex_lock(&LOCK_thread_count);
  thd->thread_id = thread_id++;
  pthread_mutex_unlock(&LOCK_thread_count);

2808
  if (init_thr_lock() || thd->store_globals())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2809
  {
2810 2811
    thd->cleanup();
    delete thd;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2812 2813 2814
    DBUG_RETURN(-1);
  }

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2815
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2816 2817 2818 2819 2820
  sigset_t set;
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
#endif

2821
  if (thd_type == SLAVE_THD_SQL)
2822
    thd->proc_info= "Waiting for the next event in relay log";
2823
  else
2824
    thd->proc_info= "Waiting for master update";
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2825 2826 2827 2828 2829
  thd->version=refresh_version;
  thd->set_time();
  DBUG_RETURN(0);
}

2830

2831 2832
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
2833
{
2834
  int nap_time;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2835 2836 2837 2838 2839
  thr_alarm_t alarmed;
  thr_alarm_init(&alarmed);
  time_t start_time= time((time_t*) 0);
  time_t end_time= start_time+sec;

2840
  while ((nap_time= (int) (end_time - start_time)) > 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2841
  {
2842
    ALARM alarm_buff;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2843
    /*
2844
      The only reason we are asking for alarm is so that
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2845 2846 2847
      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
    */
2848
    thr_alarm(&alarmed, 2 * nap_time, &alarm_buff);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2849
    sleep(nap_time);
2850
    thr_end_alarm(&alarmed);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2851
    
2852
    if ((*thread_killed)(thd,thread_killed_arg))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2853 2854 2855 2856 2857 2858
      return 1;
    start_time=time((time_t*) 0);
  }
  return 0;
}

2859

2860 2861
static int request_dump(MYSQL* mysql, MASTER_INFO* mi,
			bool *suppress_warnings)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2862
{
2863
  char buf[FN_REFLEN + 10];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2864 2865
  int len;
  int binlog_flags = 0; // for now
2866
  char* logname = mi->master_log_name;
2867 2868
  DBUG_ENTER("request_dump");

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2869
  // TODO if big log files: Change next to int8store()
monty@mysql.com's avatar
monty@mysql.com committed
2870
  int4store(buf, (ulong) mi->master_log_pos);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2871
  int2store(buf + 4, binlog_flags);
2872
  int4store(buf + 6, server_id);
2873
  len = (uint) strlen(logname);
2874
  memcpy(buf + 10, logname,len);
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2875
  if (simple_command(mysql, COM_BINLOG_DUMP, buf, len + 10, 1))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2876
  {
2877 2878 2879 2880 2881
    /*
      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
2882
    if (mysql_errno(mysql) == ER_NET_READ_INTERRUPTED)
2883 2884
      *suppress_warnings= 1;			// Suppress reconnect warning
    else
2885
      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
2886
		      mysql_errno(mysql), mysql_error(mysql),
2887 2888
		      master_connect_retry);
    DBUG_RETURN(1);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2889
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2890

2891
  DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2892 2893
}

2894

2895
static int request_table_dump(MYSQL* mysql, const char* db, const char* table)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2896 2897 2898
{
  char buf[1024];
  char * p = buf;
2899 2900
  uint table_len = (uint) strlen(table);
  uint db_len = (uint) strlen(db);
2901
  if (table_len + db_len > sizeof(buf) - 2)
2902 2903 2904 2905
  {
    sql_print_error("request_table_dump: Buffer overrun");
    return 1;
  } 
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2906 2907 2908 2909 2910 2911 2912
  
  *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
2913
  if (simple_command(mysql, COM_TABLE_DUMP, buf, p - buf + table_len, 1))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2914 2915
  {
    sql_print_error("request_table_dump: Error sending the table dump \
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2916
command");
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2917 2918
    return 1;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2919 2920 2921 2922

  return 0;
}

2923

2924
/*
2925
  Read one event from the master
2926 2927 2928 2929 2930 2931 2932 2933 2934
  
  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.
2935

2936 2937 2938 2939 2940 2941
    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
2942
{
2943
  ulong len;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2944

2945
  *suppress_warnings= 0;
2946 2947 2948
  /*
    my_real_read() will time us out
    We check if we were told to die, and if not, try reading again
2949 2950

    TODO:  Move 'events_till_disconnect' to the MASTER_INFO structure
2951
  */
2952
#ifndef DBUG_OFF
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2953
  if (disconnect_slave_event_count && !(events_till_disconnect--))
2954 2955 2956
    return packet_error;      
#endif
  
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2957
  len = net_safe_read(mysql);
2958
  if (len == packet_error || (long) len < 1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2959
  {
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2960
    if (mysql_errno(mysql) == ER_NET_READ_INTERRUPTED)
2961 2962 2963 2964 2965 2966 2967 2968 2969 2970
    {
      /*
	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 (\
2971
server_errno=%d)",
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2972
		      mysql_error(mysql), mysql_errno(mysql));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2973 2974 2975
    return packet_error;
  }

2976 2977
  /* Check if eof packet */
  if (len < 8 && mysql->net.read_pos[0] == 254)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2978
  {
2979 2980
    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
2981
		     mysql_error(mysql));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2982
     return packet_error;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2983
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2984 2985
  
  DBUG_PRINT("info",( "len=%u, net->read_pos[4] = %d\n",
2986
		      len, mysql->net.read_pos[4]));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2987 2988 2989
  return len - 1;   
}

2990

2991
int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int expected_error)
2992
{
2993 2994 2995 2996 2997 2998 2999 3000 3001
  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;
  }
3002
}
3003

3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051
/*
     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)
  {
3052 3053 3054 3055 3056 3057
    /*
      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).
3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081
    */

    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
3082
        return TRUE;
3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093
      }
    }
    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);
}

3094

3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112
void st_relay_log_info::cached_charset_invalidate()
{
  /* Full of zeroes means uninitialized. */
  bzero(cached_charset, sizeof(cached_charset));
}


bool st_relay_log_info::cached_charset_compare(char *charset)
{
  if (bcmp(cached_charset, charset, sizeof(cached_charset)))
  {
    memcpy(cached_charset, charset, sizeof(cached_charset));
    return 1;
  }
  return 0;
}


3113
static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3114
{
3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125
  /*
     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"
3126
                    " UNTIL position %ld", (long) rli->until_pos());
3127 3128 3129 3130 3131 3132 3133 3134 3135
    /* 
      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;
  }
  
3136
  Log_event * ev = next_event(rli);
3137
  
3138
  DBUG_ASSERT(rli->sql_thd==thd);
3139
  
3140
  if (sql_slave_killed(thd,rli))
3141
  {
3142
    pthread_mutex_unlock(&rli->data_lock);
3143
    delete ev;
3144
    return 1;
3145
  }
3146 3147
  if (ev)
  {
3148
    int type_code = ev->get_type_code();
3149
    int exec_res;
3150 3151

    /*
3152 3153 3154 3155 3156 3157 3158
      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
3159
      log files themselves.
3160 3161 3162
      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).
3163
    */
3164 3165 3166 3167
    
    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
3168
         !replicate_same_server_id &&
3169
         type_code != FORMAT_DESCRIPTION_EVENT) ||
3170 3171 3172
 	(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
3173
    {
3174
      DBUG_PRINT("info", ("event skipped"));
3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185
      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);
      }
3186
      
3187
      /*
3188 3189 3190
 	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.
3191 3192
      */
      if (rli->slave_skip_counter && 
3193 3194 3195
 	  !((type_code == INTVAR_EVENT ||
             type_code == RAND_EVENT || 
             type_code == USER_VAR_EVENT) &&
3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208
 	    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)))
3209 3210
        --rli->slave_skip_counter;
      pthread_mutex_unlock(&rli->data_lock);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3211 3212
      delete ev;     
      return 0;					// avoid infinite update loops
3213
    } 
3214
    pthread_mutex_unlock(&rli->data_lock);
3215 3216
  
    thd->server_id = ev->server_id; // use the original server id for logging
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3217
    thd->set_time();				// time the query
pem@mysql.telia.com's avatar
pem@mysql.telia.com committed
3218
    thd->lex->current_select= 0;
3219
    if (!ev->when)
3220
      ev->when = time(NULL);
3221
    ev->thd = thd;
3222 3223
    exec_res = ev->exec_event(rli);
    DBUG_ASSERT(rli->sql_thd==thd);
3224 3225 3226 3227 3228 3229 3230 3231 3232 3233
    /* 
       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;
    }
3234
    return exec_res;
3235
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3236
  else
3237
  {
3238
    pthread_mutex_unlock(&rli->data_lock);
3239
    slave_print_error(rli, 0, "\
3240 3241 3242 3243 3244 3245 3246
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
3247
");
3248 3249
    return 1;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3250 3251
}

3252

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

3255
extern "C" pthread_handler_decl(handle_slave_io,arg)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3256
{
3257 3258 3259 3260 3261 3262 3263 3264
  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();
3265
  DBUG_ENTER("handle_slave_io");
3266

3267
#ifndef DBUG_OFF
3268
slave_begin:
3269
#endif  
3270
  DBUG_ASSERT(mi->inited);
3271 3272 3273
  mysql= NULL ;
  retry_count= 0;

3274
  pthread_mutex_lock(&mi->run_lock);
3275 3276 3277
  /* Inform waiting threads that slave has started */
  mi->slave_run_id++;

3278
#ifndef DBUG_OFF  
3279
  mi->events_till_abort = abort_slave_event_count;
3280
#endif  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3281
  
3282
  thd= new THD; // note that contructor of THD uses DBUG_ !
3283
  THD_CHECK_SENTRY(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3284 3285

  pthread_detach_this_thread();
3286
  if (init_slave_thread(thd, SLAVE_THD_IO))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3287 3288 3289 3290 3291 3292
  {
    pthread_cond_broadcast(&mi->start_cond);
    pthread_mutex_unlock(&mi->run_lock);
    sql_print_error("Failed during slave I/O thread initialization");
    goto err;
  }
3293
  mi->io_thd = thd;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3294
  thd->thread_stack = (char*)&thd; // remember where our stack is
3295
  pthread_mutex_lock(&LOCK_thread_count);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3296
  threads.append(thd);
3297
  pthread_mutex_unlock(&LOCK_thread_count);
3298 3299 3300
  mi->slave_running = 1;
  mi->abort_slave = 0;
  pthread_mutex_unlock(&mi->run_lock);
3301
  pthread_cond_broadcast(&mi->start_cond);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3302
  
3303 3304 3305
  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
3306
  
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3307
  if (!(mi->mysql = mysql = mysql_init(NULL)))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3308
  {
3309
    sql_print_error("Slave I/O thread: error in mysql_init()");
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3310 3311
    goto err;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3312
  
3313

3314
  thd->proc_info = "Connecting to master";
3315
  // we can get killed during safe_connect
3316
  if (!safe_connect(thd, mysql, mi))
3317
    sql_print_information("Slave I/O thread: connected to master '%s@%s:%d',\
3318
  replication started in log '%s' at position %s", mi->user,
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3319 3320 3321
		    mi->host, mi->port,
		    IO_RPL_LOG_NAME,
		    llstr(mi->master_log_pos,llbuff));
3322
  else
3323
  {
3324
    sql_print_information("Slave I/O thread killed while connecting to master");
3325 3326
    goto err;
  }
3327

3328
connected:
3329

3330 3331
  // TODO: the assignment below should be under mutex (5.0)
  mi->slave_running= MYSQL_SLAVE_RUN_CONNECT;
3332
  thd->slave_net = &mysql->net;
3333
  thd->proc_info = "Checking master version";
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
3334
  if (get_master_version_and_clock(mysql, mi))
3335
    goto err;
3336 3337

  if (mi->rli.relay_log.description_event_for_queue->binlog_version > 1)
3338
  {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3339 3340 3341 3342 3343
    /*
      Register ourselves with the master.
      If fails, this is not fatal - we just print the error message and go
      on with life.
    */
3344
    thd->proc_info = "Registering slave on master";
3345
    if (register_slave_on_master(mysql) ||  update_slave_list(mysql, mi))
3346 3347
      goto err;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3348
  
3349
  DBUG_PRINT("info",("Starting reading binary log from master"));
3350
  while (!io_slave_killed(thd,mi))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3351
  {
3352
    bool suppress_warnings= 0;    
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3353
    thd->proc_info = "Requesting binlog dump";
3354
    if (request_dump(mysql, mi, &suppress_warnings))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3355 3356
    {
      sql_print_error("Failed on request_dump()");
3357
      if (io_slave_killed(thd,mi))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3358
      {
3359
	sql_print_information("Slave I/O thread killed while requesting master \
3360
dump");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3361 3362
	goto err;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3363
	  
3364
      mi->slave_running= MYSQL_SLAVE_RUN_NOT_CONNECT;
3365
      thd->proc_info= "Waiting to reconnect after a failed binlog dump request";
3366 3367 3368
#ifdef SIGNAL_WITH_VIO_CLOSE
      thd->clear_active_vio();
#endif
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3369
      end_server(mysql);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3370 3371 3372 3373 3374
      /*
	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
      */
3375 3376 3377 3378
      if (retry_count++)
      {
	if (retry_count > master_retry_count)
	  goto err;				// Don't retry forever
3379 3380
	safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed,
		   (void*)mi);
3381
      }
3382
      if (io_slave_killed(thd,mi))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3383
      {
3384
	sql_print_information("Slave I/O thread killed while retrying master \
3385
dump");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3386 3387
	goto err;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3388

3389
      thd->proc_info = "Reconnecting after a failed binlog dump request";
3390 3391
      if (!suppress_warnings)
	sql_print_error("Slave I/O thread: failed dump request, \
3392
reconnecting to try again, log '%s' at postion %s", IO_RPL_LOG_NAME,
3393 3394 3395
			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
3396
      {
3397
	sql_print_information("Slave I/O thread killed during or \
3398
after reconnect");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3399 3400
	goto err;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3401

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3402 3403
      goto connected;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3404

3405
    while (!io_slave_killed(thd,mi))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3406
    {
3407
      bool suppress_warnings= 0;    
3408 3409 3410 3411 3412 3413 3414
      /* 
         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";
3415
      ulong event_len = read_event(mysql, mi, &suppress_warnings);
3416
      if (io_slave_killed(thd,mi))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3417
      {
3418
	if (global_system_variables.log_warnings)
3419
	  sql_print_information("Slave I/O thread killed while reading event");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3420 3421
	goto err;
      }
3422
	  	  
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3423 3424
      if (event_len == packet_error)
      {
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3425
	uint mysql_error_number= mysql_errno(mysql);
3426
	if (mysql_error_number == ER_NET_PACKET_TOO_LARGE)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3427
	{
3428 3429 3430 3431
	  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",
3432
			  thd->variables.max_allowed_packet);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3433 3434
	  goto err;
	}
3435 3436 3437
	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
3438
			  mysql_error(mysql));
3439 3440
	  goto err;
	}
3441
        mi->slave_running= MYSQL_SLAVE_RUN_NOT_CONNECT;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3442
	thd->proc_info = "Waiting to reconnect after a failed master event read";
3443 3444 3445
#ifdef SIGNAL_WITH_VIO_CLOSE
        thd->clear_active_vio();
#endif
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3446
	end_server(mysql);
3447 3448 3449 3450
	if (retry_count++)
	{
	  if (retry_count > master_retry_count)
	    goto err;				// Don't retry forever
3451
	  safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed,
3452 3453
		     (void*) mi);
	}	    
3454
	if (io_slave_killed(thd,mi))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3455
	{
3456
	  if (global_system_variables.log_warnings)
3457
	    sql_print_information("Slave I/O thread killed while waiting to \
3458
reconnect after a failed read");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3459 3460
	  goto err;
	}
3461
	thd->proc_info = "Reconnecting after a failed master event read";
3462
	if (!suppress_warnings)
3463
	  sql_print_information("Slave I/O thread: Failed reading log event, \
3464
reconnecting to retry, log '%s' position %s", IO_RPL_LOG_NAME,
3465 3466 3467
			  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
3468
	{
3469
	  if (global_system_variables.log_warnings)
3470
	    sql_print_information("Slave I/O thread killed during or after a \
3471
reconnect done to recover from failed read");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3472 3473 3474
	  goto err;
	}
	goto connected;
3475
      } // if (event_len == packet_error)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3476
	  
3477
      retry_count=0;			// ok event, reset retry counter
3478
      thd->proc_info = "Queueing master event to the relay log";
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3479 3480 3481
      if (queue_event(mi,(const char*)mysql->net.read_pos + 1,
		      event_len))
      {
3482
	sql_print_error("Slave I/O thread could not queue event from master");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3483 3484
	goto err;
      }
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
3485
      flush_master_info(mi, 1); /* sure that we can flush the relay log */
3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497
      /*
        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.
      */
3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508
#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

3509
      if (mi->rli.log_space_limit && mi->rli.log_space_limit <
3510 3511
	  mi->rli.log_space_total &&
          !mi->rli.ignore_log_space_limit)
3512 3513 3514 3515 3516 3517
	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
3518
      // TODO: check debugging abort code
3519
#ifndef DBUG_OFF
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3520 3521 3522 3523 3524
      if (abort_slave_event_count && !--events_till_abort)
      {
	sql_print_error("Slave I/O thread: debugging abort");
	goto err;
      }
3525
#endif
3526
    } 
3527
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3528

monty@donna.mysql.fi's avatar
monty@donna.mysql.fi committed
3529
  // error = 0;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3530
err:
3531
  // print the current replication position
3532
  sql_print_information("Slave I/O thread exiting, read up to log '%s', position %s",
3533
		  IO_RPL_LOG_NAME, llstr(mi->master_log_pos,llbuff));
3534
  VOID(pthread_mutex_lock(&LOCK_thread_count));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3535
  thd->query = thd->db = 0; // extra safety
3536
  thd->query_length= thd->db_length= 0;
3537
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
3538 3539
  if (mysql)
  {
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3540
    mysql_close(mysql);
3541 3542
    mi->mysql=0;
  }
jcole@tetra.spaceapes.com's avatar
jcole@tetra.spaceapes.com committed
3543
  thd->proc_info = "Waiting for slave mutex on exit";
3544 3545 3546
  pthread_mutex_lock(&mi->run_lock);
  mi->slave_running = 0;
  mi->io_thd = 0;
3547 3548 3549
  /* Forget the relay log's format */
  delete mi->rli.relay_log.description_event_for_queue;
  mi->rli.relay_log.description_event_for_queue= 0;
3550
  // TODO: make rpl_status part of MASTER_INFO
3551
  change_rpl_status(RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE);
3552 3553
  mi->abort_slave = 0; // TODO: check if this is needed
  DBUG_ASSERT(thd->net.buff != 0);
3554
  net_end(&thd->net); // destructor will not free it, because net.vio is 0
3555
  pthread_mutex_lock(&LOCK_thread_count);
3556
  THD_CHECK_SENTRY(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3557
  delete thd;
3558
  pthread_mutex_unlock(&LOCK_thread_count);
3559
  pthread_cond_broadcast(&mi->stop_cond);	// tell the world we are done
3560
  pthread_mutex_unlock(&mi->run_lock);
3561
#ifndef DBUG_OFF
3562
  if (abort_slave_event_count && !events_till_abort)
3563 3564
    goto slave_begin;
#endif  
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3565
  my_thread_end();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3566 3567 3568 3569
  pthread_exit(0);
  DBUG_RETURN(0);				// Can't return anything here
}

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

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

3573
extern "C" pthread_handler_decl(handle_slave_sql,arg)
3574
{
3575
  THD *thd;			/* needs to be first for thread_stack */
3576 3577
  char llbuff[22],llbuff1[22];
  RELAY_LOG_INFO* rli = &((MASTER_INFO*)arg)->rli; 
3578 3579 3580 3581
  const char *errmsg;

  // needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff
  my_thread_init();
3582
  DBUG_ENTER("handle_slave_sql");
3583 3584 3585 3586 3587

#ifndef DBUG_OFF
slave_begin:  
#endif  

3588 3589 3590
  DBUG_ASSERT(rli->inited);
  pthread_mutex_lock(&rli->run_lock);
  DBUG_ASSERT(!rli->slave_running);
3591
  errmsg= 0;
3592 3593 3594
#ifndef DBUG_OFF  
  rli->events_till_abort = abort_slave_event_count;
#endif  
3595

3596
  thd = new THD; // note that contructor of THD uses DBUG_ !
3597 3598
  thd->thread_stack = (char*)&thd; // remember where our stack is
  
3599 3600 3601
  /* Inform waiting threads that slave has started */
  rli->slave_run_id++;

3602 3603
  pthread_detach_this_thread();
  if (init_slave_thread(thd, SLAVE_THD_SQL))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3604 3605 3606 3607 3608 3609 3610 3611 3612 3613
  {
    /*
      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;
  }
3614
  thd->init_for_queries();
3615
  rli->sql_thd= thd;
3616
  thd->temporary_tables = rli->save_temporary_tables; // restore temp tables
3617
  pthread_mutex_lock(&LOCK_thread_count);
3618
  threads.append(thd);
3619
  pthread_mutex_unlock(&LOCK_thread_count);
3620 3621 3622 3623 3624 3625 3626 3627
  /*
    We are going to set slave_running to 1. Assuming slave I/O thread is
    alive and connected, this is going to make Seconds_Behind_Master be 0
    i.e. "caught up". Even if we're just at start of thread. Well it's ok, at
    the moment we start we can think we are caught up, and the next second we
    start receiving data so we realize we are not caught up and
    Seconds_Behind_Master grows. No big deal.
  */
3628 3629 3630
  rli->slave_running = 1;
  rli->abort_slave = 0;
  pthread_mutex_unlock(&rli->run_lock);
3631
  pthread_cond_broadcast(&rli->start_cond);
3632

guilhem@mysql.com's avatar
guilhem@mysql.com committed
3633 3634 3635
  /*
    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
3636
    though there's no problem anymore). Do not reset the master timestamp
3637 3638 3639 3640
    (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
3641
    But the master timestamp is reset by RESET SLAVE & CHANGE MASTER.
guilhem@mysql.com's avatar
guilhem@mysql.com committed
3642
  */
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
3643
  clear_slave_error(rli);
3644 3645

  //tell the I/O thread to take relay_log_space_limit into account from now on
3646
  pthread_mutex_lock(&rli->log_space_lock);
3647
  rli->ignore_log_space_limit= 0;
3648
  pthread_mutex_unlock(&rli->log_space_lock);
3649

3650
  if (init_relay_log_pos(rli,
3651 3652
			 rli->group_relay_log_name,
			 rli->group_relay_log_pos,
3653 3654
			 1 /*need data lock*/, &errmsg,
                         1 /*look for a description_event*/))
3655 3656 3657 3658 3659
  {
    sql_print_error("Error initializing relay log position: %s",
		    errmsg);
    goto err;
  }
3660
  THD_CHECK_SENTRY(thd);
3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684
#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
3685
  DBUG_ASSERT(rli->sql_thd == thd);
3686 3687

  DBUG_PRINT("master_info",("log_file_name: %s  position: %s",
3688 3689
			    rli->group_master_log_name,
			    llstr(rli->group_master_log_pos,llbuff)));
3690
  if (global_system_variables.log_warnings)
3691
    sql_print_information("Slave SQL thread initialized, starting replication in \
3692
log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
3693 3694
		    llstr(rli->group_master_log_pos,llbuff),rli->group_relay_log_name,
		    llstr(rli->group_relay_log_pos,llbuff1));
3695

gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
3696
  /* execute init_slave variable */
3697
  if (sys_init_slave.value_length)
gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
3698
  {
3699
    execute_init_command(thd, &sys_init_slave, &LOCK_sys_init_slave);
gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
3700 3701 3702 3703 3704 3705 3706 3707
    if (thd->query_error)
    {
      sql_print_error("\
Slave SQL thread aborted. Can't execute init_slave query");
      goto err;
    }
  }

3708 3709
  /* Read queries from the IO/THREAD until this thread is killed */

3710
  while (!sql_slave_killed(thd,rli))
3711
  {
3712
    thd->proc_info = "Reading event from the relay log";
3713
    DBUG_ASSERT(rli->sql_thd == thd);
3714
    THD_CHECK_SENTRY(thd);
3715 3716 3717
    if (exec_relay_log_event(thd,rli))
    {
      // do not scare the user if SQL thread was simply killed or stopped
3718
      if (!sql_slave_killed(thd,rli))
3719 3720
        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
3721
the slave SQL thread with \"SLAVE START\". We stopped at log \
3722
'%s' position %s", RPL_LOG_NAME, llstr(rli->group_master_log_pos, llbuff));
3723 3724
      goto err;
    }
3725
  }
3726

3727
  /* Thread stopped. Print the current replication position to the log */
monty@mysql.com's avatar
monty@mysql.com committed
3728 3729 3730
  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));
3731 3732

 err:
3733
  VOID(pthread_mutex_lock(&LOCK_thread_count));
3734 3735 3736 3737 3738 3739
  /*
    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; 
3740
  thd->query_length= thd->db_length= 0;
3741
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
3742 3743
  thd->proc_info = "Waiting for slave mutex on exit";
  pthread_mutex_lock(&rli->run_lock);
3744 3745
  /* We need data_lock, at least to wake up any waiting master_pos_wait() */
  pthread_mutex_lock(&rli->data_lock);
3746
  DBUG_ASSERT(rli->slave_running == 1); // tracking buffer overrun
3747 3748
  /* When master_pos_wait() wakes up it will check this and terminate */
  rli->slave_running= 0; 
3749 3750 3751
  /* Forget the relay log's format */
  delete rli->relay_log.description_event_for_exec;
  rli->relay_log.description_event_for_exec= 0;
3752 3753 3754 3755
  /* 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
3756
  rli->ignore_log_space_limit= 0; /* don't need any lock */
3757 3758
  /* we die so won't remember charset - re-update them on next thread start */
  rli->cached_charset_invalidate();
3759
  rli->save_temporary_tables = thd->temporary_tables;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3760 3761 3762 3763 3764

  /*
    TODO: see if we can do this conditionally in next_event() instead
    to avoid unneeded position re-init
  */
3765 3766 3767 3768
  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);
3769
  THD_CHECK_SENTRY(thd);
3770
  rli->sql_thd= 0;
3771
  pthread_mutex_lock(&LOCK_thread_count);
3772
  THD_CHECK_SENTRY(thd);
3773 3774 3775 3776 3777 3778 3779 3780 3781
  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
3782
  my_thread_end();
3783 3784 3785
  pthread_exit(0);
  DBUG_RETURN(0);				// Can't return anything here
}
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3786

3787

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3788
/*
3789
  process_io_create_file()
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3790
*/
3791

3792 3793 3794 3795 3796
static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev)
{
  int error = 1;
  ulong num_bytes;
  bool cev_not_written;
3797 3798
  THD *thd = mi->io_thd;
  NET *net = &mi->mysql->net;
3799
  DBUG_ENTER("process_io_create_file");
3800 3801

  if (unlikely(!cev->is_valid()))
3802
    DBUG_RETURN(1);
3803 3804 3805 3806 3807 3808
  /*
    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);
3809
    DBUG_RETURN(0);
3810 3811 3812
  }
  DBUG_ASSERT(cev->inited_from_old);
  thd->file_id = cev->file_id = mi->file_id++;
3813
  thd->server_id = cev->server_id;
3814 3815 3816 3817 3818 3819 3820 3821 3822
  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
3823 3824 3825 3826
  /*
    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
3827 3828
  */
  {
3829
    Append_block_log_event aev(thd,0,0,0,0);
3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840
  
    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 */
      {
3841
	net_write_command(net, 0, "", 0, "", 0);/* 3.23 master wants it */
monty@mysql.com's avatar
monty@mysql.com committed
3842 3843 3844 3845 3846 3847 3848 3849
        /*
          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
3850
	Execute_load_log_event xev(thd,0,0);
3851
	xev.log_pos = cev->log_pos;
3852 3853 3854 3855 3856 3857
	if (unlikely(mi->rli.relay_log.append(&xev)))
	{
	  sql_print_error("Slave I/O: error writing Exec_load event to \
relay log");
	  goto err;
	}
3858
	mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total);
3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871
	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;
3872
	mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total);
3873 3874 3875 3876 3877
      }
      else
      {
	aev.block = (char*)net->read_pos;
	aev.block_len = num_bytes;
3878
	aev.log_pos = cev->log_pos;
3879 3880 3881 3882 3883 3884
	if (unlikely(mi->rli.relay_log.append(&aev)))
	{
	  sql_print_error("Slave I/O: error writing Append_block event to \
relay log");
	  goto err;
	}
3885
	mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total) ;
3886 3887 3888 3889 3890
      }
    }
  }
  error=0;
err:
3891
  DBUG_RETURN(error);
3892
}
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3893

3894

3895
/*
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3896 3897 3898 3899 3900 3901 3902 3903
  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
3904
    Updates the master info with the place in the next binary
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3905
    log where we should start reading.
3906
    Rotate the relay log to avoid mixed-format relay logs.
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3907 3908 3909 3910 3911 3912 3913

  NOTES
    We assume we already locked mi->data_lock

  RETURN VALUES
    0		ok
    1	        Log event is illegal
3914 3915 3916

*/

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3917
static int process_io_rotate(MASTER_INFO *mi, Rotate_log_event *rev)
3918
{
3919
  DBUG_ENTER("process_io_rotate");
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3920
  safe_mutex_assert_owner(&mi->data_lock);
3921

3922
  if (unlikely(!rev->is_valid()))
3923
    DBUG_RETURN(1);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3924 3925 3926 3927 3928

  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));
3929
#ifndef DBUG_OFF
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3930 3931 3932 3933 3934 3935
  /*
    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++;
3936
#endif
3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950
  /*
    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);
  }
3951 3952 3953 3954
  /*
    Rotate the relay log makes binlog format detection easier (at next slave
    start or mysqlbinlog)
  */
3955
  rotate_relay_log(mi); /* will take the right mutexes */
3956
  DBUG_RETURN(0);
3957 3958
}

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3959
/*
3960 3961
  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
3962
*/
3963
static int queue_binlog_ver_1_event(MASTER_INFO *mi, const char *buf,
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3964
			   ulong event_len)
3965
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3966
  const char *errmsg = 0;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3967 3968 3969 3970
  ulong inc_pos;
  bool ignore_event= 0;
  char *tmp_buf = 0;
  RELAY_LOG_INFO *rli= &mi->rli;
3971
  DBUG_ENTER("queue_binlog_ver_1_event");
3972

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3973 3974 3975
  /*
    If we get Load event, we need to pass a non-reusable buffer
    to read_log_event, so we do a trick
3976 3977 3978 3979 3980 3981
  */
  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");
3982
      DBUG_RETURN(1);
3983 3984
    }
    memcpy(tmp_buf,buf,event_len);
3985 3986 3987 3988 3989 3990 3991 3992
    /*
      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;
3993
    int4store(tmp_buf+EVENT_LEN_OFFSET, event_len);
3994 3995
    buf = (const char*)tmp_buf;
  }
3996 3997 3998 3999 4000 4001
  /*
    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
4002
  Log_event *ev = Log_event::read_log_event(buf,event_len, &errmsg,
4003
                                            mi->rli.relay_log.description_event_for_queue);
4004
  if (unlikely(!ev))
4005 4006
  {
    sql_print_error("Read invalid event from master: '%s',\
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4007
 master could be corrupt but a more likely cause of this is a bug",
4008
		    errmsg);
4009 4010
    my_free((char*) tmp_buf, MYF(MY_ALLOW_ZERO_PTR));
    DBUG_RETURN(1);
4011
  }
4012
  pthread_mutex_lock(&mi->data_lock);
4013
  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
4014
  switch (ev->get_type_code()) {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4015
  case STOP_EVENT:
4016
    ignore_event= 1;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4017 4018
    inc_pos= event_len;
    break;
4019
  case ROTATE_EVENT:
4020
    if (unlikely(process_io_rotate(mi,(Rotate_log_event*)ev)))
4021 4022
    {
      delete ev;
4023
      pthread_mutex_unlock(&mi->data_lock);
4024
      DBUG_RETURN(1);
4025
    }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4026
    inc_pos= 0;
4027
    break;
4028
  case CREATE_FILE_EVENT:
4029 4030 4031 4032 4033 4034
    /*
      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.
    */
4035
  {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4036 4037
    /* We come here when and only when tmp_buf != 0 */
    DBUG_ASSERT(tmp_buf);
4038 4039
    inc_pos=event_len;
    ev->log_pos+= inc_pos;
4040
    int error = process_io_create_file(mi,(Create_file_log_event*)ev);
4041
    delete ev;
4042
    mi->master_log_pos += inc_pos;
4043
    DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos));
4044
    pthread_mutex_unlock(&mi->data_lock);
4045
    my_free((char*)tmp_buf, MYF(0));
4046
    DBUG_RETURN(error);
4047
  }
4048
  default:
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4049
    inc_pos= event_len;
4050 4051
    break;
  }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4052
  if (likely(!ignore_event))
4053
  {
4054 4055 4056 4057 4058 4059
    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
4060
    if (unlikely(rli->relay_log.append(ev)))
4061 4062 4063
    {
      delete ev;
      pthread_mutex_unlock(&mi->data_lock);
4064
      DBUG_RETURN(1);
4065
    }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4066
    rli->relay_log.harvest_bytes_written(&rli->log_space_total);
4067 4068
  }
  delete ev;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4069
  mi->master_log_pos+= inc_pos;
4070
  DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos));
4071
  pthread_mutex_unlock(&mi->data_lock);
4072
  DBUG_RETURN(0);
4073 4074
}

4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157
/*
  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;
  }
}
4158

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4159
/*
4160 4161
  queue_event()

4162 4163 4164 4165 4166
  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
4167 4168 4169
*/

int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
4170
{
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4171 4172 4173
  int error= 0;
  ulong inc_pos;
  RELAY_LOG_INFO *rli= &mi->rli;
4174 4175
  DBUG_ENTER("queue_event");

4176 4177
  if (mi->rli.relay_log.description_event_for_queue->binlog_version<4 &&
      buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT /* a way to escape */)
4178
    DBUG_RETURN(queue_old_event(mi,buf,event_len));
4179 4180

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

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4182 4183
  /*
    TODO: figure out if other events in addition to Rotate
4184 4185
    require special processing.
    Guilhem 2003-06 : I don't think so.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4186 4187
  */
  switch (buf[EVENT_TYPE_OFFSET]) {
4188
  case STOP_EVENT:
4189 4190
    /*
      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
4191 4192 4193 4194
      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).
4195
      
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4196 4197 4198 4199
      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).
4200 4201
    */
    goto err;
4202 4203
  case ROTATE_EVENT:
  {
4204
    Rotate_log_event rev(buf,event_len,mi->rli.relay_log.description_event_for_queue); 
4205
    if (unlikely(process_io_rotate(mi,&rev)))
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4206
    {
4207 4208
      error= 1;
      goto err;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4209
    }
4210 4211 4212 4213
    /*
      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
4214
    inc_pos= 0;
4215 4216
    break;
  }
4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227
  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).
    */
4228
    Format_description_log_event* tmp;
4229
    const char* errmsg;
4230
    if (!(tmp= (Format_description_log_event*)
4231
          Log_event::read_log_event(buf, event_len, &errmsg,
4232
                                    mi->rli.relay_log.description_event_for_queue)))
4233 4234 4235 4236
    {
      error= 2;
      goto err;
    }
4237 4238
    delete mi->rli.relay_log.description_event_for_queue;
    mi->rli.relay_log.description_event_for_queue= tmp;
4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252
    /* 
       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;
4253
  default:
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4254
    inc_pos= event_len;
4255 4256
    break;
  }
4257 4258 4259 4260

  /* 
     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
4261 4262
     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
4263 4264 4265 4266 4267 4268 4269 4270
     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
4271 4272
  if ((uint4korr(buf + SERVER_ID_OFFSET) == ::server_id) &&
      !replicate_same_server_id)
4273
  {
4274 4275 4276 4277 4278
    /*
      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).
4279 4280 4281
      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.
4282
    */
4283 4284 4285 4286
    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;
4287 4288
    DBUG_PRINT("info", ("master_log_pos: %d, event originating from the same server, ignored", (ulong) mi->master_log_pos));
  }  
4289 4290 4291
  else
  {
    /* write the event to the relay log */
4292
    if (likely(!(rli->relay_log.appendv(buf,event_len,0))))
4293 4294 4295 4296 4297
    {
      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);
    }
4298 4299
    else
      error=3;
4300
  }
4301 4302

err:
4303
  pthread_mutex_unlock(&mi->data_lock);
4304
  DBUG_PRINT("info", ("error=%d", error));
4305
  DBUG_RETURN(error);
4306 4307
}

4308

4309 4310
void end_relay_log_info(RELAY_LOG_INFO* rli)
{
4311 4312
  DBUG_ENTER("end_relay_log_info");

4313
  if (!rli->inited)
4314
    DBUG_VOID_RETURN;
4315
  if (rli->info_fd >= 0)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4316 4317
  {
    end_io_cache(&rli->info_file);
4318
    (void) my_close(rli->info_fd, MYF(MY_WME));
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4319 4320
    rli->info_fd = -1;
  }
4321
  if (rli->cur_log_fd >= 0)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4322 4323 4324 4325 4326
  {
    end_io_cache(&rli->cache_buf);
    (void)my_close(rli->cur_log_fd, MYF(MY_WME));
    rli->cur_log_fd = -1;
  }
4327
  rli->inited = 0;
4328
  rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
4329
  rli->relay_log.harvest_bytes_written(&rli->log_space_total);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
4330 4331 4332 4333 4334 4335
  /*
    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();
4336
  DBUG_VOID_RETURN;
4337 4338
}

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4339 4340
/*
  Try to connect until successful or slave killed
4341

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4342 4343 4344 4345 4346
  SYNPOSIS
    safe_connect()
    thd			Thread handler for slave
    mysql		MySQL connection handle
    mi			Replication handle
4347

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4348 4349 4350 4351
  RETURN
    0	ok
    #	Error
*/
4352

4353
static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4354
{
4355
  return connect_to_master(thd, mysql, mi, 0, 0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4356 4357
}

4358

4359
/*
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4360 4361
  SYNPOSIS
    connect_to_master()
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4362

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4363 4364 4365
  IMPLEMENTATION
    Try to connect until successful or slave killed or we have retried
    master_retry_count times
4366
*/
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4367

sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
4368
static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
4369
			     bool reconnect, bool suppress_warnings)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4370
{
4371
  int slave_was_killed;
4372 4373
  int last_errno= -2;				// impossible error
  ulong err_count=0;
4374
  char llbuff[22];
4375
  DBUG_ENTER("connect_to_master");
4376

4377 4378 4379
#ifndef DBUG_OFF
  events_till_disconnect = disconnect_slave_event_count;
#endif
4380
  ulong client_flag= CLIENT_REMEMBER_OPTIONS;
4381 4382 4383
  if (opt_slave_compressed_protocol)
    client_flag=CLIENT_COMPRESS;		/* We will use compression */

4384 4385
  mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout);
  mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, (char *) &slave_net_timeout);
4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396
 
#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

4397 4398 4399 4400
  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);

4401
  while (!(slave_was_killed = io_slave_killed(thd,mi)) &&
4402 4403 4404
	 (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
4405
  {
4406
    /* Don't repeat last error */
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
4407
    if ((int)mysql_errno(mysql) != last_errno)
4408
    {
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
4409
      last_errno=mysql_errno(mysql);
4410
      suppress_warnings= 0;
4411
      sql_print_error("Slave I/O thread: error %s to master \
4412
'%s@%s:%d': \
4413
Error: '%s'  errno: %d  retry-time: %d  retries: %d",
4414
		      (reconnect ? "reconnecting" : "connecting"),
4415
		      mi->user,mi->host,mi->port,
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
4416
		      mysql_error(mysql), last_errno,
4417 4418
		      mi->connect_retry,
		      master_retry_count);
4419
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4420 4421 4422
    /*
      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
4423
      do not want to have election triggered on the first failure to
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4424
      connect
4425
    */
4426
    if (++err_count == master_retry_count)
4427 4428
    {
      slave_was_killed=1;
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
4429 4430
      if (reconnect)
        change_rpl_status(RPL_ACTIVE_SLAVE,RPL_LOST_SOLDIER);
4431 4432
      break;
    }
4433 4434
    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
4435
  }
4436

4437 4438
  if (!slave_was_killed)
  {
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
4439
    if (reconnect)
4440
    { 
4441
      if (!suppress_warnings && global_system_variables.log_warnings)
4442
	sql_print_information("Slave: connected to master '%s@%s:%d',\
4443
replication resumed in log '%s' at position %s", mi->user,
4444 4445 4446 4447
			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
4448 4449 4450 4451
    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
4452
		      mi->user, mi->host, mi->port);
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
4453
    }
4454
#ifdef SIGNAL_WITH_VIO_CLOSE
4455
    thd->set_active_vio(mysql->net.vio);
4456
#endif      
4457
  }
4458
  mysql->reconnect= 1;
4459 4460
  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
4461 4462
}

4463

sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
4464
/*
4465
  safe_reconnect()
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4466

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4467 4468 4469
  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
4470 4471
*/

4472 4473
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
4474
{
4475 4476
  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
4477 4478
}

4479

4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509
/*
  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)
4510
{
4511 4512 4513 4514
  bool error=0;
  IO_CACHE *file = &rli->info_file;
  char buff[FN_REFLEN*2+22*2+4], *pos;

4515
  my_b_seek(file, 0L);
4516
  pos=strmov(buff, rli->group_relay_log_name);
4517
  *pos++='\n';
4518
  pos=longlong2str(rli->group_relay_log_pos, pos, 10);
4519
  *pos++='\n';
4520
  pos=strmov(pos, rli->group_master_log_name);
4521
  *pos++='\n';
4522
  pos=longlong2str(rli->group_master_log_pos, pos, 10);
4523
  *pos='\n';
4524
  if (my_b_write(file, (byte*) buff, (ulong) (pos-buff)+1))
4525 4526 4527
    error=1;
  if (flush_io_cache(file))
    error=1;
4528
  /* Flushing the relay log is done by the slave I/O thread */
4529
  return error;
4530 4531
}

4532

4533
/*
4534
  Called when we notice that the current "hot" log got rotated under our feet.
4535 4536 4537
*/

static IO_CACHE *reopen_relay_log(RELAY_LOG_INFO *rli, const char **errmsg)
4538 4539 4540
{
  DBUG_ASSERT(rli->cur_log != &rli->cache_buf);
  DBUG_ASSERT(rli->cur_log_fd == -1);
4541 4542 4543
  DBUG_ENTER("reopen_relay_log");

  IO_CACHE *cur_log = rli->cur_log=&rli->cache_buf;
4544
  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
4545
				   errmsg)) <0)
4546
    DBUG_RETURN(0);
4547 4548 4549 4550 4551
  /*
    We want to start exactly where we was before:
    relay_log_pos	Current log pos
    pending		Number of bytes already processed from the event
  */
4552
  rli->event_relay_log_pos= max(rli->event_relay_log_pos, BIN_LOG_HEADER_SIZE);
4553
  my_b_seek(cur_log,rli->event_relay_log_pos);
4554
  DBUG_RETURN(cur_log);
4555 4556
}

4557

4558 4559 4560 4561
Log_event* next_event(RELAY_LOG_INFO* rli)
{
  Log_event* ev;
  IO_CACHE* cur_log = rli->cur_log;
4562
  pthread_mutex_t *log_lock = rli->relay_log.get_log_lock(); 
4563 4564
  const char* errmsg=0;
  THD* thd = rli->sql_thd;
4565
  
4566
  DBUG_ENTER("next_event");
4567 4568
  DBUG_ASSERT(thd != 0);

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4569 4570
  /*
    For most operations we need to protect rli members with data_lock,
4571 4572 4573 4574
    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
4575
  */
4576
  safe_mutex_assert_owner(&rli->data_lock);
4577
  
4578
  while (!sql_slave_killed(thd,rli))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4579 4580 4581
  {
    /*
      We can have two kinds of log reading:
4582 4583 4584 4585 4586 4587 4588 4589
      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
4590
    */
4591 4592 4593 4594 4595
    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
4596 4597

      /*
4598
	Reading xxx_file_id is safe because the log will only
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4599 4600
	be rotated when we hold relay_log.LOCK_log
      */
4601
      if (rli->relay_log.get_open_count() != rli->cur_log_old_open_count)
4602
      {
4603 4604 4605 4606
	// 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
4607
	  goto err;
4608
	hot_log=0;				// Using old binary log
4609 4610
      }
    }
4611

4612 4613
#ifndef DBUG_OFF
    {
4614
      /* This is an assertion which sometimes fails, let's try to track it */
4615
      char llbuf1[22], llbuf2[22];
4616
      DBUG_PRINT("info", ("my_b_tell(cur_log)=%s rli->event_relay_log_pos=%s",
4617
                          llstr(my_b_tell(cur_log),llbuf1), 
4618 4619 4620
                          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);
4621 4622
    }
#endif
4623 4624
    /*
      Relay log is always in new format - if the master is 3.23, the
4625
      I/O thread will convert the format for us.
4626 4627
      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
4628 4629
      logs, which may even have been deleted. So we need to write this
      description event at the beginning of the relay log.
4630 4631
      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.
4632 4633
      But if the relay log is created by new_file(): then the solution is:
      MYSQL_LOG::open() will write the buffered description event.
4634
    */
4635 4636 4637
    if ((ev=Log_event::read_log_event(cur_log,0,
                                      rli->relay_log.description_event_for_exec)))
      
4638 4639
    {
      DBUG_ASSERT(thd==rli->sql_thd);
4640 4641 4642 4643 4644
      /*
        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);
4645 4646
      if (hot_log)
	pthread_mutex_unlock(log_lock);
4647
      DBUG_RETURN(ev);
4648 4649
    }
    DBUG_ASSERT(thd==rli->sql_thd);
4650
    if (opt_reckless_slave)			// For mysql-test
4651
      cur_log->error = 0;
4652
    if (cur_log->error < 0)
4653 4654
    {
      errmsg = "slave SQL thread aborted because of I/O error";
4655 4656
      if (hot_log)
	pthread_mutex_unlock(log_lock);
4657 4658
      goto err;
    }
4659 4660
    if (!cur_log->error) /* EOF */
    {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4661 4662 4663 4664 4665
      /*
	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
      */
4666 4667
      if (hot_log)
      {
4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682
        /*
          We say in Seconds_Behind_Master that we have "caught up". Note that
          for example if network link is broken but I/O slave thread hasn't
          noticed it (slave_net_timeout not elapsed), then we'll say "caught
          up" whereas we're not really caught up. Fixing that would require
          internally cutting timeout in smaller pieces in network read, no
          thanks. Another example: SQL has caught up on I/O, now I/O has read
          a new event and is queuing it; the false "0" will exist until SQL
          finishes executing the new event; it will be look abnormal only if
          the events have old timestamps (then you get "many", 0, "many").
          Transient phases like this can't really be fixed.
        */
        time_t save_timestamp= rli->last_master_timestamp;
        rli->last_master_timestamp= 0;

4683
	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
4684 4685 4686 4687
	/*
	  We can, and should release data_lock while we are waiting for
	  update. If we do not, show slave status will block
	*/
4688
	pthread_mutex_unlock(&rli->data_lock);
4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710

        /*
          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
4711 4712
          be stopped, and the SQL thread sets ignore_log_space_limit to 0 when
          it stops.
4713 4714 4715 4716
        */
        pthread_mutex_lock(&rli->log_space_lock);
        // prevent the I/O thread from blocking next times
        rli->ignore_log_space_limit= 1; 
4717 4718 4719 4720 4721 4722
        /*
          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.
        */
4723
        pthread_mutex_unlock(&rli->log_space_lock);
4724
        pthread_cond_broadcast(&rli->log_space_cond);
4725
        // Note that wait_for_update unlocks lock_log !
4726
        rli->relay_log.wait_for_update(rli->sql_thd, 1);
4727 4728
        // re-acquire data lock since we released it earlier
        pthread_mutex_lock(&rli->data_lock);
4729
        rli->last_master_timestamp= save_timestamp;
4730 4731
	continue;
      }
4732 4733 4734 4735 4736 4737 4738 4739 4740 4741
      /*
	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;
	
4742
      if (relay_log_purge)
4743
      {
4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758
	/*
          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)))
4759
	{
4760
	  errmsg = "Error purging processed logs";
4761 4762 4763
	  goto err;
	}
      }
4764 4765
      else
      {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4766
	/*
4767 4768 4769 4770 4771
	  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
4772
	*/
4773
	if (rli->relay_log.find_next_log(&rli->linfo, !hot_log))
4774
	{
4775 4776
	  errmsg = "error switching to the next log";
	  goto err;
4777
	}
4778 4779 4780
	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);
4781 4782
	flush_relay_log_info(rli);
      }
4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796

      /*
        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);
4797 4798
      if (rli->relay_log.is_active(rli->linfo.log_file_name))
      {
4799
#ifdef EXTRA_DEBUG
4800
	if (global_system_variables.log_warnings)
4801 4802
	  sql_print_information("next log '%s' is currently active",
                                rli->linfo.log_file_name);
4803
#endif	  
4804 4805 4806
	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);
4807
	  
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4808
	/*
4809
	  Read pointer has to be at the start since we are the only
4810 4811 4812 4813
	  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
4814
	*/
4815
	if (check_binlog_magic(cur_log,&errmsg))
4816 4817
        {
          if (!hot_log) pthread_mutex_unlock(log_lock);
4818
	  goto err;
4819 4820
        }
        if (!hot_log) pthread_mutex_unlock(log_lock);
4821
	continue;
4822
      }
4823
      if (!hot_log) pthread_mutex_unlock(log_lock);
4824
      /*
4825 4826 4827
	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.
4828 4829
      */
#ifdef EXTRA_DEBUG
4830
      if (global_system_variables.log_warnings)
4831 4832
	sql_print_information("next log '%s' is not active",
                              rli->linfo.log_file_name);
4833 4834 4835 4836 4837
#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;
4838
    }
4839
    else
4840
    {
4841 4842 4843 4844 4845 4846
      /*
	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);
4847
      sql_print_error("Slave SQL thread: I/O error reading \
4848
event(errno: %d  cur_log->error: %d)",
4849
		      my_errno,cur_log->error);
4850
      // set read position to the beginning of the event
4851
      my_b_seek(cur_log,rli->event_relay_log_pos);
4852 4853
      /* otherwise, we have had a partial read */
      errmsg = "Aborting slave SQL thread because of partial event read";
4854
      break;					// To end of function
4855 4856
    }
  }
4857
  if (!errmsg && global_system_variables.log_warnings)
4858 4859 4860 4861 4862
  {
    sql_print_information("Error reading relay log event: %s", 
                          "slave SQL thread was killed");
    DBUG_RETURN(0);
  }
4863

4864
err:
4865 4866
  if (errmsg)
    sql_print_error("Error reading relay log event: %s", errmsg);
4867
  DBUG_RETURN(0);
4868 4869
}

4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880
/*
  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
4881

4882 4883 4884
  /* 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
4885 4886 4887 4888
  /* 
     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).
  */
4889 4890
  if (!rli->inited)
  {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4891
    DBUG_PRINT("info", ("rli->inited == 0"));
guilhem@mysql.com's avatar
guilhem@mysql.com committed
4892
    goto end;
4893
  }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4894

4895 4896
  /* 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
4897

4898 4899 4900 4901
  /*
    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
4902 4903 4904 4905 4906 4907
    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.
4908 4909 4910 4911
    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
4912
end:
4913
  pthread_mutex_unlock(&mi->run_lock);
4914 4915 4916
  DBUG_VOID_RETURN;
}

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
4918 4919
#ifdef __GNUC__
template class I_List_iterator<i_string>;
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
4920
template class I_List_iterator<i_string_pair>;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4921
#endif
4922

4923

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