slave.cc 168 KB
Newer Older
1
/* Copyright (C) 2000-2003 MySQL AB
2

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3 4
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
kent@mysql.com/kent-amd64.(none)'s avatar
kent@mysql.com/kent-amd64.(none) committed
5
   the Free Software Foundation; version 2 of the License.
6

bk@work.mysql.com's avatar
bk@work.mysql.com committed
7 8 9 10
   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.
11

bk@work.mysql.com's avatar
bk@work.mysql.com committed
12 13 14 15 16
   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
17 18 19

#ifdef HAVE_REPLICATION

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

29
#define MAX_SLAVE_RETRY_PAUSE 5
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 43
bool table_rules_on= 0;
my_bool replicate_same_server_id;
44
ulonglong relay_log_space_limit = 0;
45 46 47 48 49 50 51

/*
  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
*/
52

53
int disconnect_slave_event_count = 0, abort_slave_event_count = 0;
54
int events_till_abort = -1;
55
#ifndef DBUG_OFF
56
static int events_till_disconnect = -1;
57
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
58

59
typedef enum { SLAVE_THD_IO, SLAVE_THD_SQL} SLAVE_THD_TYPE;
60

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

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

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
83 84 85 86 87 88 89 90 91 92 93 94 95
  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    
96 97
*/

98 99 100 101 102 103 104 105
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;
106 107
  if (inverse)
    tmp_mask^= (SLAVE_IO | SLAVE_SQL);
108 109 110
  *mask = tmp_mask;
}

111

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
112
/*
113
  lock_slave_threads()
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
114
*/
115

116 117 118 119 120 121 122
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);
}

123

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
124
/*
125
  unlock_slave_threads()
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
126
*/
127

128 129 130 131 132 133 134
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);
}

135

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
136
/* Initialize slave structures */
137

138 139
int init_slave()
{
140
  DBUG_ENTER("init_slave");
141

142 143 144 145 146 147
  /*
    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);
148 149 150 151
  /*
    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
152
  active_mi= new MASTER_INFO;
153 154

  /*
155 156 157
    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.
158
  */
159 160 161 162 163
  if (!active_mi)
  {
    sql_print_error("Failed to allocate memory for the master info structure");
    goto err;
  }
164

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
165
  if (init_master_info(active_mi,master_info_file,relay_log_info_file,
166
		       !master_host, (SLAVE_IO | SLAVE_SQL)))
167
  {
168
    sql_print_error("Failed to initialize the master info structure");
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
169
    goto err;
170
  }
171 172 173 174

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

175 176
  /* If server id is not set, start_slave_thread() will say it */

177
  if (master_host && !opt_skip_slave_start)
178
  {
179 180 181 182 183 184
    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
185
    {
186
      sql_print_error("Failed to create slave threads");
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
187 188
      goto err;
    }
189
  }
190
  pthread_mutex_unlock(&LOCK_active_mi);
191
  DBUG_RETURN(0);
192

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
193
err:
194
  pthread_mutex_unlock(&LOCK_active_mi);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
195
  DBUG_RETURN(1);
196
}
197

198

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

204

205 206 207 208 209 210 211
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;
}

212 213 214 215 216 217 218 219 220 221 222

/*
  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
223 224 225
    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
226 227 228 229
                        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.
230 231 232 233 234 235 236 237

  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
238
    - check proper initialization of group_master_log_name/group_master_log_pos
239 240 241 242 243

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

245 246
int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
		       ulonglong pos, bool need_data_lock,
247 248
		       const char** errmsg,
                       bool look_for_description_event)
249
{
250
  DBUG_ENTER("init_relay_log_pos");
251
  DBUG_PRINT("info", ("pos: %lu", (long) pos));
252

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

  /*
    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);
276
  
277 278
  pthread_mutex_lock(log_lock);
  
279
  /* Close log file and free buffers if it's already open */
280 281 282 283 284 285 286
  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;
  }
  
287
  rli->group_relay_log_pos = rli->event_relay_log_pos = pos;
288

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

299
  if (log && rli->relay_log.find_log_pos(&rli->linfo, log, 1))
300
  {
301 302
    *errmsg="Could not find target log during relay log initialization";
    goto err;
303
  }
304 305 306 307
  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);
308 309
  if (rli->relay_log.is_active(rli->linfo.log_file_name))
  {
310 311 312 313 314
    /*
      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.
    */
315 316
    my_b_seek((rli->cur_log=rli->relay_log.get_log_file()), (off_t)0);
    if (check_binlog_magic(rli->cur_log,errmsg))
317
      goto err;
318
    rli->cur_log_old_open_count=rli->relay_log.get_open_count();
319 320 321
  }
  else
  {
322 323 324
    /*
      Open the relay log and set rli->cur_log to point at this one
    */
325 326 327 328 329
    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;
  }
330 331 332 333 334 335 336 337 338 339
  /*
    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) 
    {
      /*
340 341
        Read the possible Format_description_log_event; if position
        was 4, no need, it will be read naturally.
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 376 377 378
      */
      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)
379
          Format_desc (of master)
380 381 382
          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).
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
          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;
      }
    }
398
    my_b_seek(rli->cur_log,(off_t)pos);
399 400 401 402 403 404 405 406 407 408
#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

  }
409

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

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

426
  DBUG_RETURN ((*errmsg) ? 1 : 0);
427 428
}

429

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
430
/*
431
  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
432

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
433 434 435 436 437 438 439
  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
*/
440

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
441
void init_slave_skip_errors(const char* arg)
442
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
443
  const char *p;
444
  if (bitmap_init(&slave_error_mask,0,MAX_SLAVE_ERROR,0))
445 446 447 448 449
  {
    fprintf(stderr, "Badly out of memory, please check your system status\n");
    exit(1);
  }
  use_slave_mask = 1;
450
  for (;my_isspace(system_charset_info,*arg);++arg)
451
    /* empty */;
452
  if (!my_strnncoll(system_charset_info,(uchar*)arg,4,(const uchar*)"all",4))
453 454 455 456 457 458 459 460 461 462 463
  {
    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);
464
    while (!my_isdigit(system_charset_info,*p) && *p)
465 466 467 468
      p++;
  }
}

469

pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
470
void st_relay_log_info::inc_group_relay_log_pos(ulonglong log_pos,
471
						bool skip_lock)  
472 473 474
{
  if (!skip_lock)
    pthread_mutex_lock(&data_lock);
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
475
  inc_event_relay_log_pos();
monty@mishka.local's avatar
monty@mishka.local committed
476 477
  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
478
	  sizeof(group_relay_log_name)-1);
monty@mishka.local's avatar
monty@mishka.local committed
479 480 481 482 483 484 485 486 487 488 489 490 491

  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
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
  /*
    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.
  */
512 513
  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
514 515
  if (log_pos) // 3.23 binlogs don't have log_posx
  {
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
516
    group_master_log_pos= log_pos;
monty@mishka.local's avatar
monty@mishka.local committed
517
  }
518 519 520 521 522 523
  pthread_cond_broadcast(&data_cond);
  if (!skip_lock)
    pthread_mutex_unlock(&data_lock);
}


guilhem@mysql.com's avatar
guilhem@mysql.com committed
524 525 526 527 528 529 530 531 532 533 534 535 536
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);
  }
537 538
  save_temporary_tables= 0;
  slave_open_temp_tables= 0;
guilhem@mysql.com's avatar
guilhem@mysql.com committed
539
}
540

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
541
/*
542 543
  purge_relay_logs()

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
544 545
  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
546 547
*/

548 549
int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
		     const char** errmsg)
550
{
551
  int error=0;
552
  DBUG_ENTER("purge_relay_logs");
553 554 555 556

  /*
    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.
557
    It could be that slave's info initialization partly succeeded :
558
    for example if relay-log.info existed but *relay-bin*.*
559
    have been manually removed, init_relay_log_info reads the old
560 561 562 563 564 565 566 567
    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_*.
568
    In other words, we reinit rli->master_log_* for SHOW SLAVE STATUS
569 570 571
    to display fine in any case.
  */

572 573
  rli->group_master_log_name[0]= 0;
  rli->group_master_log_pos= 0;
574

575
  if (!rli->inited)
576 577
  {
    DBUG_PRINT("info", ("rli->inited == 0"));
578
    DBUG_RETURN(0);
579
  }
580

581 582
  DBUG_ASSERT(rli->slave_running == 0);
  DBUG_ASSERT(rli->mi->slave_running == 0);
583

584 585
  rli->slave_skip_counter=0;
  pthread_mutex_lock(&rli->data_lock);
586 587 588 589 590 591 592 593 594 595 596 597 598 599

  /* 
    we close the relay log fd possibly left open by the slave SQL thread, 
    to be able to delete it; the relay log fd possibly left open by the slave
    I/O thread will be closed naturally in reset_logs() by the 
    close(LOG_CLOSE_TO_BE_OPENED) call
  */
  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;
  }

600
  if (rli->relay_log.reset_logs(thd))
601 602 603 604 605
  {
    *errmsg = "Failed during log reset";
    error=1;
    goto err;
  }
606
  /* Save name of used relay log file */
607 608 609 610 611
  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;
612 613 614 615 616
  if (count_relay_log_space(rli))
  {
    *errmsg= "Error counting relay log space";
    goto err;
  }
617
  if (!just_reset)
618 619
    error= init_relay_log_pos(rli, rli->group_relay_log_name,
                              rli->group_relay_log_pos,
620
  			      0 /* do not need data lock */, errmsg, 0);
621
  
622 623 624 625
err:
#ifndef DBUG_OFF
  char buf[22];
#endif  
626
  DBUG_PRINT("info",("log_space_total: %s",llstr(rli->log_space_total,buf)));
627
  pthread_mutex_unlock(&rli->data_lock);
628
  DBUG_RETURN(error);
629 630
}

631

632 633 634 635 636 637 638
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;
639
  DBUG_ENTER("terminate_slave_threads");
640 641 642 643 644 645 646 647 648 649

  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
650
    DBUG_PRINT("info",("Terminating IO thread"));
651 652
    mi->abort_slave=1;
    if ((error=terminate_slave_thread(mi->io_thd,io_lock,
653 654 655
				      io_cond_lock,
				      &mi->stop_cond,
				      &mi->slave_running)) &&
656
	!force_all)
657
      DBUG_RETURN(error);
658 659 660
  }
  if ((thread_mask & (SLAVE_SQL|SLAVE_FORCE_ALL)) && mi->rli.slave_running)
  {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
661
    DBUG_PRINT("info",("Terminating SQL thread"));
662 663 664 665 666 667 668
    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)
669
      DBUG_RETURN(error);
670
  }
671
  DBUG_RETURN(0);
672 673
}

674

675 676 677
int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
			   pthread_mutex_t *cond_lock,
			   pthread_cond_t* term_cond,
678
			   volatile uint *slave_running)
679
{
680
  DBUG_ENTER("terminate_slave_thread");
681 682 683 684 685 686
  if (term_lock)
  {
    pthread_mutex_lock(term_lock);
    if (!*slave_running)
    {
      pthread_mutex_unlock(term_lock);
687
      DBUG_RETURN(ER_SLAVE_NOT_RUNNING);
688 689 690
    }
  }
  DBUG_ASSERT(thd != 0);
691
  THD_CHECK_SENTRY(thd);
692
  /*
693
    Is is critical to test if the slave is running. Otherwise, we might
694
    be referening freed memory trying to kick it
695
  */
696 697

  while (*slave_running)			// Should always be true
698
  {
699
    DBUG_PRINT("loop", ("killing slave thread"));
700
    KICK_SLAVE(thd);
701 702 703
    /*
      There is a small chance that slave thread might miss the first
      alarm. To protect againts it, resend the signal until it reacts
704 705
    */
    struct timespec abstime;
706
    set_timespec(abstime,2);
707 708 709 710
    pthread_cond_timedwait(term_cond, cond_lock, &abstime);
  }
  if (term_lock)
    pthread_mutex_unlock(term_lock);
711
  DBUG_RETURN(0);
712 713
}

714

715
int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
716
		       pthread_mutex_t *cond_lock,
717
		       pthread_cond_t *start_cond,
718
		       volatile uint *slave_running,
719
		       volatile ulong *slave_run_id,
720 721
		       MASTER_INFO* mi,
                       bool high_priority)
722 723
{
  pthread_t th;
724
  ulong start_id;
725
  DBUG_ASSERT(mi->inited);
726 727
  DBUG_ENTER("start_slave_thread");

728 729 730 731 732 733 734 735 736
  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");
737
    DBUG_RETURN(ER_BAD_SLAVE);
738 739 740
  }
  
  if (*slave_running)
741 742 743 744 745
  {
    if (start_cond)
      pthread_cond_broadcast(start_cond);
    if (start_lock)
      pthread_mutex_unlock(start_lock);
746
    DBUG_RETURN(ER_SLAVE_MUST_STOP);
747
  }
748 749
  start_id= *slave_run_id;
  DBUG_PRINT("info",("Creating new slave thread"));
750 751
  if (high_priority)
    my_pthread_attr_setprio(&connection_attrib,CONNECT_PRIOR);
752 753 754 755
  if (pthread_create(&th, &connection_attrib, h_func, (void*)mi))
  {
    if (start_lock)
      pthread_mutex_unlock(start_lock);
756
    DBUG_RETURN(ER_SLAVE_THREAD);
757
  }
guilhem@mysql.com's avatar
guilhem@mysql.com committed
758
  if (start_cond && cond_lock) // caller has cond_lock
759 760
  {
    THD* thd = current_thd;
761
    while (start_id == *slave_run_id)
762
    {
763
      DBUG_PRINT("sleep",("Waiting for slave thread to start"));
764
      const char* old_msg = thd->enter_cond(start_cond,cond_lock,
765
					    "Waiting for slave thread to start");
766 767
      pthread_cond_wait(start_cond,cond_lock);
      thd->exit_cond(old_msg);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
768
      pthread_mutex_lock(cond_lock); // re-acquire it as exit_cond() released
769
      if (thd->killed)
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
770
	DBUG_RETURN(thd->killed_errno());
771 772 773 774
    }
  }
  if (start_lock)
    pthread_mutex_unlock(start_lock);
775
  DBUG_RETURN(0);
776
}
777

778

779
/*
780
  start_slave_threads()
781

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
782 783 784 785
  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
786
*/
787

788 789 790 791 792 793 794
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;
795
  DBUG_ENTER("start_slave_threads");
796 797 798 799 800 801 802 803 804 805 806 807 808
  
  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;
  }
809 810 811

  if (thread_mask & SLAVE_IO)
    error=start_slave_thread(handle_slave_io,lock_io,lock_cond_io,
812 813
			     cond_io,
			     &mi->slave_running, &mi->slave_run_id,
814
			     mi, 1); //high priority, to read the most possible
815
  if (!error && (thread_mask & SLAVE_SQL))
816
  {
817 818
    error=start_slave_thread(handle_slave_sql,lock_sql,lock_cond_sql,
			     cond_sql,
819
			     &mi->rli.slave_running, &mi->rli.slave_run_id,
820
			     mi, 0);
821 822 823
    if (error)
      terminate_slave_threads(mi, thread_mask & SLAVE_IO, 0);
  }
824
  DBUG_RETURN(error);
825
}
826

827

828 829
void init_table_rule_hash(HASH* h, bool* h_inited)
{
830
  hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0,
831
	    (hash_get_key) get_table_key,
832
	    (hash_free_key) free_table_ent, 0);
833 834
  *h_inited = 1;
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
835

836

837 838
void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited)
{
839
  my_init_dynamic_array(a, sizeof(TABLE_RULE_ENT*), TABLE_RULE_ARR_SIZE,
840 841 842 843
		     TABLE_RULE_ARR_SIZE);
  *a_inited = 1;
}

844

845 846 847 848 849
static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
{
  uint i;
  const char* key_end = key + len;
  
850
  for (i = 0; i < a->elements; i++)
851 852 853
    {
      TABLE_RULE_ENT* e ;
      get_dynamic(a, (gptr)&e, i);
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
854
      if (!my_wildcmp(system_charset_info, key, key_end, 
855
                            (const char*)e->db,
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
856 857
			    (const char*)(e->db + e->key_len),
			    '\\',wild_one,wild_many))
858 859 860 861 862 863
	return e;
    }
  
  return 0;
}

864

865 866 867 868 869 870
/*
  Checks whether tables match some (wild_)do_table and (wild_)ignore_table
  rules (for replication)

  SYNOPSIS
    tables_ok()
871
    thd             thread (SQL slave thread normally). Mustn't be null.
872 873 874 875 876 877
    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 
878 879
    rules because they may get unpredicted results (precedence order is
    explained in the manual).
880

881 882
    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
883 884
    supported Perl regexps we could do it with this pattern: /^abc\.(?!EFG)/
    (I could not find an equivalent in the regex library MySQL uses).
885 886 887 888 889

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

891
bool tables_ok(THD* thd, TABLE_LIST* tables)
892
{
893
  bool some_tables_updating= 0;
894 895
  DBUG_ENTER("tables_ok");

896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912
  /*
    In routine, can't reliably pick and choose substatements, so always
    replicate.
    We can't reliably know if one substatement should be executed or not:
    consider the case of this substatement: a SELECT on a non-replicated
    constant table; if we don't execute it maybe it was going to fill a
    variable which was going to be used by the next substatement to update
    a replicated table? If we execute it maybe the constant non-replicated
    table does not exist (and so we'll fail) while there was no need to
    execute this as this SELECT does not influence replicated tables in the
    rest of the routine? In other words: users are used to replicate-*-table
    specifying how to handle updates to tables, these options don't say
    anything about reads to tables; we can't guess.
  */
  if (thd->spcont)
    DBUG_RETURN(1);

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
913
  for (; tables; tables= tables->next_global)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
914
  {
915 916 917 918
    char hash_key[2*NAME_LEN+2];
    char *end;
    uint len;

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
919 920
    if (!tables->updating) 
      continue;
921
    some_tables_updating= 1;
922 923
    end= strmov(hash_key, tables->db ? tables->db : thd->db);
    *end++= '.';
924
    len= (uint) (strmov(end, tables->table_name) - hash_key);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
925
    if (do_table_inited) // if there are any do's
926
    {
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
927
      if (hash_search(&replicate_do_table, (byte*) hash_key, len))
928
	DBUG_RETURN(1);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
929
    }
930
    if (ignore_table_inited) // if there are any ignores
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
931 932
    {
      if (hash_search(&replicate_ignore_table, (byte*) hash_key, len))
933
	DBUG_RETURN(0); 
934
    }
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
935 936
    if (wild_do_table_inited && find_wild(&replicate_wild_do_table,
					  hash_key, len))
937
      DBUG_RETURN(1);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
938 939
    if (wild_ignore_table_inited && find_wild(&replicate_wild_ignore_table,
					      hash_key, len))
940
      DBUG_RETURN(0);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
941
  }
942

943
  /*
944 945
    If no table was to be updated, ignore statement (no reason we play it on
    slave, slave is supposed to replicate _changes_ only).
946 947 948
    If no explicit rule found and there was a do list, do not replicate.
    If there was no do list, go ahead
  */
949 950
  DBUG_RETURN(some_tables_updating &&
              !do_table_inited && !wild_do_table_inited);
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 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003
/*
  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;
1004 1005 1006 1007 1008
}


int add_table_rule(HASH* h, const char* table_spec)
{
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
1009
  const char* dot = strchr(table_spec, '.');
1010
  if (!dot) return 1;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1011
  // len is always > 0 because we know the there exists a '.'
1012 1013 1014
  uint len = (uint)strlen(table_spec);
  TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
						 + len, MYF(MY_WME));
1015
  if (!e) return 1;
1016 1017 1018 1019
  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
1020
  (void)my_hash_insert(h, (byte*)e);
1021 1022 1023
  return 0;
}

1024

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1025 1026 1027
/*
  Add table expression with wildcards to dynamic array
*/
1028

1029 1030
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
{
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
1031
  const char* dot = strchr(table_spec, '.');
1032
  if (!dot) return 1;
1033 1034 1035
  uint len = (uint)strlen(table_spec);
  TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
						 + len, MYF(MY_WME));
1036
  if (!e) return 1;
1037 1038 1039 1040 1041 1042 1043 1044
  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;
}

1045

1046 1047 1048
static void free_string_array(DYNAMIC_ARRAY *a)
{
  uint i;
1049
  for (i = 0; i < a->elements; i++)
1050 1051
    {
      char* p;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1052
      get_dynamic(a, (gptr) &p, i);
1053 1054 1055 1056 1057
      my_free(p, MYF(MY_WME));
    }
  delete_dynamic(a);
}

1058

1059
#ifdef NOT_USED_YET
1060 1061 1062 1063 1064
static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/)
{
  end_master_info(mi);
  return 0;
}
1065
#endif
1066

1067

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1068 1069 1070 1071 1072 1073
/*
  Free all resources used by slave

  SYNOPSIS
    end_slave()
*/
1074

1075 1076
void end_slave()
{
1077 1078 1079 1080 1081 1082 1083 1084
  /*
    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
1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104
  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;
  }
1105
  pthread_mutex_unlock(&LOCK_active_mi);
1106
}
1107

1108

1109
static bool io_slave_killed(THD* thd, MASTER_INFO* mi)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1110
{
1111
  DBUG_ASSERT(mi->io_thd == thd);
1112
  DBUG_ASSERT(mi->slave_running); // tracking buffer overrun
1113
  return mi->abort_slave || abort_loop || thd->killed;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1114 1115
}

1116

1117
static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli)
1118 1119 1120 1121 1122 1123
{
  DBUG_ASSERT(rli->sql_thd == thd);
  DBUG_ASSERT(rli->slave_running == 1);// tracking buffer overrun
  return rli->abort_slave || abort_loop || thd->killed;
}

1124

1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
/*
  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
1139
*/
1140

1141
void slave_print_error(RELAY_LOG_INFO* rli, int err_code, const char* msg, ...)
1142 1143 1144
{
  va_list args;
  va_start(args,msg);
1145 1146 1147
  my_vsnprintf(rli->last_slave_error,
	       sizeof(rli->last_slave_error), msg, args);
  rli->last_slave_errno = err_code;
1148 1149
  /* If the error string ends with '.', do not add a ',' it would be ugly */
  if (rli->last_slave_error[0] && 
1150 1151
      (*(strend(rli->last_slave_error)-1) == '.'))
    sql_print_error("Slave: %s Error_code: %d", rli->last_slave_error,
1152 1153
                    err_code);
  else
1154
    sql_print_error("Slave: %s, Error_code: %d", rli->last_slave_error,
1155 1156
                    err_code);

1157 1158
}

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1159
/*
1160 1161
  skip_load_data_infile()

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1162 1163 1164
  NOTES
    This is used to tell a 3.23 master to break send_file()
*/
1165 1166 1167 1168 1169 1170 1171 1172

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
}

1173

1174
bool net_request_file(NET* net, const char* fname)
1175
{
1176 1177
  DBUG_ENTER("net_request_file");
  DBUG_RETURN(net_write_command(net, 251, fname, strlen(fname), "", 0));
1178 1179 1180
}


1181 1182
/*
  From other comments and tests in code, it looks like
1183
  sometimes Query_log_event and Load_log_event can have db == 0
1184 1185 1186
  (see rewrite_db() above for example)
  (cases where this happens are unclear; it may be when the master is 3.23).
*/
1187 1188

const char *print_slave_db_safe(const char* db)
1189
{
1190
  return (db ? db : "");
1191
}
1192

1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206
/*
  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                  
*/
1207

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1208 1209 1210
int db_ok(const char* db, I_List<i_string> &do_list,
	  I_List<i_string> &ignore_list )
{
1211
  if (do_list.is_empty() && ignore_list.is_empty())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1212 1213
    return 1; // ok to replicate if the user puts no constraints

1214 1215 1216 1217 1218
  /*
    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
1219
    return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1220

1221 1222 1223 1224
  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
1225

1226 1227 1228 1229
    while ((tmp=it++))
    {
      if (!strcmp(tmp->ptr, db))
	return 1; // match
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1230
    }
1231 1232
    return 0;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1233
  else // there are some elements in the don't, otherwise we cannot get here
1234 1235 1236
  {
    I_List_iterator<i_string> it(ignore_list);
    i_string* tmp;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1237

1238 1239 1240 1241
    while ((tmp=it++))
    {
      if (!strcmp(tmp->ptr, db))
	return 0; // match
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1242
    }
1243 1244
    return 1;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1245 1246
}

1247

1248 1249
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
1250
{
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1251 1252 1253 1254 1255 1256 1257
  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
1258
    {
1259 1260 1261 1262
      /*
	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
1263
      int c;
1264
      while (((c=my_b_get(f)) != '\n' && c != my_b_EOF));
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
1265
    }
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1266 1267 1268 1269
    return 0;
  }
  else if (default_val)
  {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1270
    strmake(var,  default_val, max_size-1);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1271 1272
    return 0;
  }
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
1273
  return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1274 1275
}

1276

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1277
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
1278 1279 1280
{
  char buf[32];
  
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1281 1282 1283 1284 1285
  if (my_b_gets(f, buf, sizeof(buf))) 
  {
    *var = atoi(buf);
    return 0;
  }
1286
  else if (default_val)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1287 1288 1289 1290
  {
    *var = default_val;
    return 0;
  }
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
1291
  return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1292 1293
}

1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306
/*
  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
*/
1307

guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1308
static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi)
1309
{
1310
  const char* errmsg= 0;
1311 1312 1313 1314 1315 1316 1317

  /*
    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;
1318
  
1319
  if (!my_isdigit(&my_charset_bin,*mysql->server_version))
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
1320
    errmsg = "Master reported unrecognized MySQL version";
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 1346 1347 1348 1349 1350 1351 1352 1353
  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;
    }
1354
  }
1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367
  
  /* 
     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;
  }
1368 1369 1370 1371 1372 1373 1374 1375

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

1376 1377 1378 1379 1380 1381 1382
  /*
    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;
  
1383
  if (!mysql_real_query(mysql, STRING_WITH_LEN("SELECT UNIX_TIMESTAMP()")) &&
1384 1385
      (master_res= mysql_store_result(mysql)) &&
      (master_row= mysql_fetch_row(master_res)))
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1386
  {
1387 1388
    mi->clock_diff_with_master= 
      (long) (time((time_t*) 0) - strtoul(master_row[0], 0, 10));
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1389
  }
1390
  else
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1391
  {
1392
    mi->clock_diff_with_master= 0; /* The "most sensible" value */
1393
    sql_print_warning("\"SELECT UNIX_TIMESTAMP()\" failed on master, \
1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408
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.
  */
1409 1410
  if (!mysql_real_query(mysql,
                        STRING_WITH_LEN("SHOW VARIABLES LIKE 'SERVER_ID'")) &&
1411 1412 1413 1414 1415 1416 1417 1418 1419 1420
      (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
1421 1422
  }

1423 1424 1425
  /*
    Check that the master's global character_set_server and ours are the same.
    Not fatal if query fails (old master?).
1426 1427 1428 1429 1430 1431
    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.
1432
    The test is only relevant if master < 5.0.3 (we'll test only if it's older
1433
    than the 5 branch; < 5.0.3 was alpha...), as >= 5.0.3 master stores
1434 1435 1436 1437
    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.
1438
  */
1439 1440 1441

  /* redundant with rest of code but safer against later additions */
  if (*mysql->server_version == '3')
1442
    goto err;
1443 1444

  if ((*mysql->server_version == '4') &&
1445 1446
      !mysql_real_query(mysql,
                        STRING_WITH_LEN("SELECT @@GLOBAL.COLLATION_SERVER")) &&
1447
      (master_res= mysql_store_result(mysql)))
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1448
  {
1449 1450 1451 1452 1453 1454
    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
1455
  }
1456

1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468
  /*
    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).
1469 1470
    This check is only necessary for 4.x masters (and < 5.0.4 masters but
    those were alpha).
1471
  */
1472
  if ((*mysql->server_version == '4') &&
1473
      !mysql_real_query(mysql, STRING_WITH_LEN("SELECT @@GLOBAL.TIME_ZONE")) &&
1474
      (master_res= mysql_store_result(mysql)))
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1475
  {
1476 1477 1478 1479 1480 1481 1482
    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
1483 1484
  }

1485
err:
1486 1487 1488 1489 1490
  if (errmsg)
  {
    sql_print_error(errmsg);
    return 1;
  }
1491

1492 1493 1494
  return 0;
}

1495 1496 1497 1498
/*
  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.
1499
  db must be non-zero (guarded by assertion).
1500 1501 1502 1503 1504

  RETURN VALUES
    0           success
    1           error
*/
1505

1506
static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
1507
				  const char* table_name, bool overwrite)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1508
{
1509
  ulong packet_len;
1510 1511
  char *query, *save_db;
  uint32 save_db_length;
1512 1513
  Vio* save_vio;
  HA_CHECK_OPT check_opt;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1514
  TABLE_LIST tables;
1515 1516
  int error= 1;
  handler *file;
1517
  ulonglong save_options;
1518
  NET *net= &mysql->net;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1519 1520
  DBUG_ENTER("create_table_from_dump");  

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

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1549 1550
  bzero((char*) &tables,sizeof(tables));
  tables.db = (char*)db;
1551
  tables.alias= tables.table_name= (char*)table_name;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1552

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1553 1554 1555 1556 1557 1558 1559
  /* 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;
  }

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

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

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

err:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1613 1614
  close_thread_tables(thd);
  thd->net.no_send_ok = 0;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1615
  DBUG_RETURN(error); 
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1616 1617
}

1618

1619
int fetch_master_table(THD *thd, const char *db_name, const char *table_name,
1620
		       MASTER_INFO *mi, MYSQL *mysql, bool overwrite)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1621
{
1622 1623 1624 1625 1626 1627
  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
1628

monty@work.mysql.com's avatar
merge  
monty@work.mysql.com committed
1629
  if (!called_connected)
1630
  { 
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1631
    if (!(mysql = mysql_init(NULL)))
1632 1633 1634
    {
      DBUG_RETURN(1);
    }
monty@work.mysql.com's avatar
merge  
monty@work.mysql.com committed
1635
    if (connect_to_master(thd, mysql, mi))
1636
    {
1637
      my_error(ER_CONNECT_TO_MASTER, MYF(0), mysql_error(mysql));
1638 1639 1640 1641 1642 1643 1644 1645 1646
      /*
        We need to clear the active VIO since, theoretically, somebody
        might issue an awake() on this thread.  If we are then in the
        middle of closing and destroying the VIO inside the
        mysql_close(), we will have a problem.
       */
#ifdef SIGNAL_WITH_VIO_CLOSE
      thd->clear_active_vio();
#endif
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1647
      mysql_close(mysql);
1648
      DBUG_RETURN(1);
1649
    }
1650 1651
    if (thd->killed)
      goto err;
1652
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1653

sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
1654
  if (request_table_dump(mysql, db_name, table_name))
1655
  {
1656 1657
    error= ER_UNKNOWN_ERROR;
    errmsg= "Failed on table dump request";
1658 1659
    goto err;
  }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1660 1661 1662
  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
1663
  error = 0;
1664

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1665
 err:
1666
  thd->net.no_send_ok = 0; // Clear up garbage after create_table_from_dump
1667
  if (!called_connected)
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1668
    mysql_close(mysql);
1669
  if (errmsg && thd->vio_ok())
1670
    my_message(error, errmsg, MYF(0));
1671
  DBUG_RETURN(test(error));			// Return 1 on error
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1672 1673
}

1674

1675 1676
void end_master_info(MASTER_INFO* mi)
{
1677 1678
  DBUG_ENTER("end_master_info");

1679
  if (!mi->inited)
1680
    DBUG_VOID_RETURN;
1681 1682
  end_relay_log_info(&mi->rli);
  if (mi->fd >= 0)
1683 1684 1685 1686 1687
  {
    end_io_cache(&mi->file);
    (void)my_close(mi->fd, MYF(MY_WME));
    mi->fd = -1;
  }
1688
  mi->inited = 0;
1689 1690

  DBUG_VOID_RETURN;
1691 1692
}

1693

1694 1695
static int init_relay_log_info(RELAY_LOG_INFO* rli,
                               const char* info_fname)
1696 1697 1698 1699
{
  char fname[FN_REFLEN+128];
  int info_fd;
  const char* msg = 0;
1700
  int error;
1701
  DBUG_ENTER("init_relay_log_info");
1702

1703
  if (rli->inited)                       // Set if this function called
1704 1705
    DBUG_RETURN(0);
  fn_format(fname, info_fname, mysql_data_home, "", 4+32);
1706 1707 1708 1709
  pthread_mutex_lock(&rli->data_lock);
  info_fd = rli->info_fd;
  rli->cur_log_fd = -1;
  rli->slave_skip_counter=0;
1710
  rli->abort_pos_wait=0;
1711 1712
  rli->log_space_limit= relay_log_space_limit;
  rli->log_space_total= 0;
1713

1714
  /*
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
1715
    The relay log will now be opened, as a SEQ_READ_APPEND IO_CACHE.
1716 1717
    Note that the I/O thread flushes it to disk after writing every
    event, in flush_master_info(mi, 1).
1718 1719
  */

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1720 1721 1722 1723 1724 1725 1726 1727 1728
  /*
    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).
  */
1729
  {
1730 1731
    char buf[FN_REFLEN];
    const char *ln;
1732
    static bool name_warning_sent= 0;
1733 1734
    ln= rli->relay_log.generate_name(opt_relay_logname, "-relay-bin",
                                     1, buf);
1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751
    /* We send the warning only at startup, not after every RESET SLAVE */
    if (!opt_relay_logname && !opt_relaylog_index_name && !name_warning_sent)
    {
      /*
        User didn't give us info to name the relay log index file.
        Picking `hostname`-relay-bin.index like we do, causes replication to
        fail if this slave's hostname is changed later. So, we would like to
        instead require a name. But as we don't want to break many existing
        setups, we only give warning, not error.
      */
      sql_print_warning("Neither --relay-log nor --relay-log-index were used;"
                        " so replication "
                        "may break when this MySQL server acts as a "
                        "slave and has his hostname changed!! Please "
                        "use '--relay-log=%s' to avoid this problem.", ln);
      name_warning_sent= 1;
    }
1752 1753 1754 1755 1756 1757 1758
    /*
      note, that if open() fails, we'll still have index file open
      but a destructor will take care of that
    */
    if (rli->relay_log.open_index_file(opt_relaylog_index_name, ln) ||
        rli->relay_log.open(ln, LOG_BIN, 0, SEQ_READ_APPEND, 0,
                            (max_relay_log_size ? max_relay_log_size :
1759
                            max_binlog_size), 1))
1760 1761 1762 1763 1764
    {
      pthread_mutex_unlock(&rli->data_lock);
      sql_print_error("Failed in open_log() called from init_relay_log_info()");
      DBUG_RETURN(1);
    }
1765
  }
1766

1767
  /* if file does not exist */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1768
  if (access(fname,F_OK))
1769
  {
1770 1771 1772 1773
    /*
      If someone removed the file from underneath our feet, just close
      the old descriptor and re-create the old file
    */
1774 1775
    if (info_fd >= 0)
      my_close(info_fd, MYF(MY_WME));
1776
    if ((info_fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
1777
    {
1778 1779 1780 1781 1782 1783 1784
      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))) 
1785
    {
1786 1787
      sql_print_error("Failed to create a cache on relay log info file '%s'",
		      fname);
1788 1789
      msg= current_thd->net.last_error;
      goto err;
1790
    }
1791 1792 1793

    /* 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 */,
1794
			   &msg, 0))
1795
    {
1796
      sql_print_error("Failed to open the relay log 'FIRST' (relay_log_pos 4)");
1797
      goto err;
1798
    }
1799 1800
    rli->group_master_log_name[0]= 0;
    rli->group_master_log_pos= 0;		
1801
    rli->info_fd= info_fd;
1802 1803 1804
  }
  else // file exists
  {
1805
    error= 0;
1806
    if (info_fd >= 0)
1807
      reinit_io_cache(&rli->info_file, READ_CACHE, 0L,0,0);
1808
    else 
1809
    {
1810 1811
      if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
      {
1812 1813 1814
        sql_print_error("\
Failed to open the existing relay log info file '%s' (errno %d)",
			fname, my_errno);
1815 1816 1817 1818 1819
        error= 1;
      }
      else if (init_io_cache(&rli->info_file, info_fd,
                             IO_SIZE*2, READ_CACHE, 0L, 0, MYF(MY_WME)))
      {
1820 1821
        sql_print_error("Failed to create a cache on relay log info file '%s'",
			fname);
1822 1823 1824 1825 1826 1827 1828
        error= 1;
      }
      if (error)
      {
        if (info_fd >= 0)
          my_close(info_fd, MYF(0));
        rli->info_fd= -1;
1829
        rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
1830 1831 1832
        pthread_mutex_unlock(&rli->data_lock);
        DBUG_RETURN(1);
      }
1833
    }
1834
         
1835
    rli->info_fd = info_fd;
1836
    int relay_log_pos, master_log_pos;
1837
    if (init_strvar_from_file(rli->group_relay_log_name,
monty@mysql.com's avatar
monty@mysql.com committed
1838 1839
			      sizeof(rli->group_relay_log_name),
                              &rli->info_file, "") ||
1840
       init_intvar_from_file(&relay_log_pos,
1841
			     &rli->info_file, BIN_LOG_HEADER_SIZE) ||
1842
       init_strvar_from_file(rli->group_master_log_name,
monty@mysql.com's avatar
monty@mysql.com committed
1843 1844
			     sizeof(rli->group_master_log_name),
                             &rli->info_file, "") ||
1845
       init_intvar_from_file(&master_log_pos, &rli->info_file, 0))
1846 1847 1848 1849
    {
      msg="Error reading slave log configuration";
      goto err;
    }
1850 1851 1852 1853
    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;
1854

1855
    if (init_relay_log_pos(rli,
1856 1857
			   rli->group_relay_log_name,
			   rli->group_relay_log_pos,
1858
			   0 /* no data lock*/,
1859
			   &msg, 0))
1860 1861
    {
      char llbuf[22];
1862
      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
1863 1864
		      rli->group_relay_log_name,
		      llstr(rli->group_relay_log_pos, llbuf));
1865
      goto err;
1866
    }
1867
  }
1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879

#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

1880 1881 1882 1883
  /*
    Now change the cache from READ to WRITE - must do this
    before flush_relay_log_info
  */
1884
  reinit_io_cache(&rli->info_file, WRITE_CACHE,0L,0,1);
1885 1886
  if ((error= flush_relay_log_info(rli)))
    sql_print_error("Failed to flush relay log info file");
1887 1888 1889 1890 1891
  if (count_relay_log_space(rli))
  {
    msg="Error counting relay log space";
    goto err;
  }
1892
  rli->inited= 1;
1893
  pthread_mutex_unlock(&rli->data_lock);
1894
  DBUG_RETURN(error);
1895 1896 1897 1898

err:
  sql_print_error(msg);
  end_io_cache(&rli->info_file);
1899 1900
  if (info_fd >= 0)
    my_close(info_fd, MYF(0));
1901
  rli->info_fd= -1;
1902
  rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
1903
  pthread_mutex_unlock(&rli->data_lock);
1904
  DBUG_RETURN(1);
1905 1906
}

1907

1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921
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)));
1922
#endif  
1923 1924 1925
  DBUG_RETURN(0);
}

1926

1927 1928
static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli)
{
1929
  bool slave_killed=0;
1930
  MASTER_INFO* mi = rli->mi;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1931
  const char *save_proc_info;
1932
  THD* thd = mi->io_thd;
1933

1934
  DBUG_ENTER("wait_for_relay_log_space");
1935

1936
  pthread_mutex_lock(&rli->log_space_lock);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1937 1938
  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
1939
				  "\
1940
Waiting for the slave SQL thread to free enough relay log space");
1941
  while (rli->log_space_limit < rli->log_space_total &&
1942 1943
	 !(slave_killed=io_slave_killed(thd,mi)) &&
         !rli->ignore_log_space_limit)
1944
    pthread_cond_wait(&rli->log_space_cond, &rli->log_space_lock);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
1945
  thd->exit_cond(save_proc_info);
1946 1947 1948
  DBUG_RETURN(slave_killed);
}

1949

1950 1951 1952 1953
static int count_relay_log_space(RELAY_LOG_INFO* rli)
{
  LOG_INFO linfo;
  DBUG_ENTER("count_relay_log_space");
1954
  rli->log_space_total= 0;
1955
  if (rli->relay_log.find_log_pos(&linfo, NullS, 1))
1956 1957 1958 1959
  {
    sql_print_error("Could not find first log while counting relay log space");
    DBUG_RETURN(1);
  }
1960
  do
1961 1962 1963
  {
    if (add_relay_log(rli,&linfo))
      DBUG_RETURN(1);
1964
  } while (!rli->relay_log.find_next_log(&linfo, 1));
1965 1966 1967 1968 1969 1970
  /* 
     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();
1971 1972
  DBUG_RETURN(0);
}
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1973

1974

1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010
/*
  Builds a Rotate from the ignored events' info and writes it to relay log.

  SYNOPSIS
  write_ignored_events_info_to_relay_log()
    thd             pointer to I/O thread's thd
    mi

  DESCRIPTION
    Slave I/O thread, going to die, must leave a durable trace of the
    ignored events' end position for the use of the slave SQL thread, by
    calling this function. Only that thread can call it (see assertion).
 */
static void write_ignored_events_info_to_relay_log(THD *thd, MASTER_INFO *mi)
{
  RELAY_LOG_INFO *rli= &mi->rli;
  pthread_mutex_t *log_lock= rli->relay_log.get_log_lock();
  DBUG_ASSERT(thd == mi->io_thd);
  pthread_mutex_lock(log_lock);
  if (rli->ign_master_log_name_end[0])
  {
    DBUG_PRINT("info",("writing a Rotate event to track down ignored events"));
    Rotate_log_event *ev= new Rotate_log_event(thd, rli->ign_master_log_name_end,
                                               0, rli->ign_master_log_pos_end,
                                               Rotate_log_event::DUP_NAME);
    rli->ign_master_log_name_end[0]= 0;
    /* can unlock before writing as slave SQL thd will soon see our Rotate */
    pthread_mutex_unlock(log_lock);
    if (likely((bool)ev))
    {
      ev->server_id= 0; // don't be ignored by slave SQL thread
      if (unlikely(rli->relay_log.append(ev)))
        sql_print_error("Slave I/O thread failed to write a Rotate event"
                        " to the relay log, "
                        "SHOW SLAVE STATUS may be inaccurate");
      rli->relay_log.harvest_bytes_written(&rli->log_space_total);
2011 2012
      if (flush_master_info(mi, 1))
        sql_print_error("Failed to flush master info file");
2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024
      delete ev;
    }
    else
      sql_print_error("Slave I/O thread failed to create a Rotate event"
                      " (out of memory?), "
                      "SHOW SLAVE STATUS may be inaccurate");
  }
  else
    pthread_mutex_unlock(log_lock);
}


guilhem@mysql.com's avatar
guilhem@mysql.com committed
2025 2026 2027 2028 2029 2030 2031 2032 2033 2034
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
2035
    strmake(mi->password, master_password, MAX_PASSWORD_LENGTH);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2036 2037
  mi->port = master_port;
  mi->connect_retry = master_connect_retry;
dlenev@mysql.com's avatar
dlenev@mysql.com committed
2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049
  
  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
2050 2051
}

2052
void clear_slave_error(RELAY_LOG_INFO* rli)
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2053
{
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2054 2055 2056
  /* 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
2057
}
2058

2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072
/*
    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;
}


2073
#define LINES_IN_MASTER_INFO_WITH_SSL 14
2074

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

2076
int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
2077 2078 2079
                     const char* slave_info_fname,
                     bool abort_if_no_master_info_file,
                     int thread_mask)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2080
{
2081 2082 2083 2084
  int fd,error;
  char fname[FN_REFLEN+128];
  DBUG_ENTER("init_master_info");

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2085
  if (mi->inited)
monty@mysql.com's avatar
monty@mysql.com committed
2086 2087 2088 2089 2090 2091 2092
  {
    /*
      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.
2093

2094 2095 2096 2097
      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.
monty@mysql.com's avatar
monty@mysql.com committed
2098
    */
monty@mysql.com's avatar
monty@mysql.com committed
2099 2100
    if (thread_mask & SLAVE_SQL)
    {
2101 2102
      my_b_seek(mi->rli.cur_log, (my_off_t) 0);
    }
2103
    DBUG_RETURN(0);
monty@mysql.com's avatar
monty@mysql.com committed
2104 2105
  }

2106 2107
  mi->mysql=0;
  mi->file_id=1;
2108
  fn_format(fname, master_info_fname, mysql_data_home, "", 4+32);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2109

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2110 2111 2112 2113
  /*
    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
2114

2115
  pthread_mutex_lock(&mi->data_lock);
2116
  fd = mi->fd;
2117 2118

  /* does master.info exist ? */
2119

2120
  if (access(fname,F_OK))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2121
  {
2122 2123 2124 2125 2126
    if (abort_if_no_master_info_file)
    {
      pthread_mutex_unlock(&mi->data_lock);
      DBUG_RETURN(0);
    }
2127 2128 2129 2130
    /*
      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
2131 2132
    if (fd >= 0)
      my_close(fd, MYF(MY_WME));
2133 2134 2135 2136 2137 2138 2139
    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,
2140
		      MYF(MY_WME)))
2141 2142 2143
    {
      sql_print_error("Failed to create a cache on master info file (\
file '%s')", fname);
2144
      goto err;
2145
    }
2146

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2147
    mi->fd = fd;
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2148 2149
    init_master_info_with_options(mi);

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2150
  }
2151
  else // file exists
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2152
  {
2153
    if (fd >= 0)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2154
      reinit_io_cache(&mi->file, READ_CACHE, 0L,0,0);
2155
    else
2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170
    {
      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
2171

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2172
    mi->fd = fd;
2173 2174
    int port, connect_retry, master_log_pos, ssl= 0, lines;
    char *first_non_digit;
2175

2176 2177
    /*
       Starting from 4.1.x master.info has new format. Now its
2178 2179 2180
       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
2181 2182
       file since versions before 4.1.x could generate files with more
       lines than needed.
2183
       If first line doesn't contain a number or contain number less than
2184
       14 then such file is treated like file from pre 4.1.1 version.
2185
       There is no ambiguity when reading an old master.info, as before
2186
       4.1.1, the first line contained the binlog's name, which is either
2187
       empty or has an extension (contains a '.'), so can't be confused
2188 2189
       with an integer.

2190
       So we're just reading first line and trying to figure which version
2191 2192
       is this.
    */
2193 2194 2195 2196

    /*
       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
2197 2198
       overwritten by the second row later.
    */
2199
    if (init_strvar_from_file(mi->master_log_name,
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2200
			      sizeof(mi->master_log_name), &mi->file,
2201 2202
			      ""))
      goto errwithmsg;
2203

2204 2205
    lines= strtoul(mi->master_log_name, &first_non_digit, 10);

2206
    if (mi->master_log_name[0]!='\0' &&
2207 2208
        *first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL)
    {                                          // Seems to be new format
2209
      if (init_strvar_from_file(mi->master_log_name,
2210 2211 2212 2213 2214
            sizeof(mi->master_log_name), &mi->file, ""))
        goto errwithmsg;
    }
    else
      lines= 7;
2215

2216
    if (init_intvar_from_file(&master_log_pos, &mi->file, 4) ||
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2217 2218 2219
	init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file,
			      master_host) ||
	init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file,
2220
			      master_user) ||
2221 2222
        init_strvar_from_file(mi->password, SCRAMBLED_PASSWORD_CHAR_LENGTH+1,
                              &mi->file, master_password) ||
2223 2224
	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
2225
			      master_connect_retry))
2226 2227
      goto errwithmsg;

2228 2229 2230 2231
    /*
       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
2232 2233
       is printed.
     */
2234
    if (lines >= LINES_IN_MASTER_INFO_WITH_SSL &&
2235
        (init_intvar_from_file(&ssl, &mi->file, master_ssl) ||
2236
         init_strvar_from_file(mi->ssl_ca, sizeof(mi->ssl_ca),
2237
                               &mi->file, master_ssl_ca) ||
2238
         init_strvar_from_file(mi->ssl_capath, sizeof(mi->ssl_capath),
2239 2240 2241 2242 2243 2244 2245 2246 2247 2248
                               &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)
2249
      sql_print_warning("SSL information in the master info file "
2250 2251 2252
                      "('%s') are ignored because this MySQL slave was compiled "
                      "without SSL support.", fname);
#endif /* HAVE_OPENSSL */
2253

2254 2255 2256 2257 2258 2259 2260
    /*
      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;
2261
    mi->ssl= (my_bool) ssl;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2262
  }
2263 2264 2265
  DBUG_PRINT("master_info",("log_file_name: %s  position: %ld",
			    mi->master_log_name,
			    (ulong) mi->master_log_pos));
2266

2267
  mi->rli.mi = mi;
2268 2269 2270
  if (init_relay_log_info(&mi->rli, slave_info_fname))
    goto err;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2271
  mi->inited = 1;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2272
  // now change cache READ -> WRITE - must do this before flush_master_info
2273
  reinit_io_cache(&mi->file, WRITE_CACHE, 0L, 0, 1);
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2274
  if ((error=test(flush_master_info(mi, 1))))
2275
    sql_print_error("Failed to flush master info file");
2276
  pthread_mutex_unlock(&mi->data_lock);
2277
  DBUG_RETURN(error);
2278

2279 2280
errwithmsg:
  sql_print_error("Error reading master configuration");
2281

2282
err:
2283 2284 2285 2286 2287 2288
  if (fd >= 0)
  {
    my_close(fd, MYF(0));
    end_io_cache(&mi->file);
  }
  mi->fd= -1;
2289
  pthread_mutex_unlock(&mi->data_lock);
2290
  DBUG_RETURN(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2291 2292
}

2293

2294 2295
int register_slave_on_master(MYSQL* mysql)
{
2296 2297
  char buf[1024], *pos= buf;
  uint report_host_len, report_user_len=0, report_password_len=0;
2298

2299
  if (!report_host)
2300
    return 0;
2301
  report_host_len= strlen(report_host);
2302
  if (report_user)
2303
    report_user_len= strlen(report_user);
2304
  if (report_password)
2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319
    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
2320
  if (simple_command(mysql, COM_REGISTER_SLAVE, (char*) buf,
2321
			(uint) (pos- buf), 0))
2322
  {
2323
    sql_print_error("Error on COM_REGISTER_SLAVE: %d '%s'",
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2324 2325
		    mysql_errno(mysql),
		    mysql_error(mysql));
2326 2327 2328 2329 2330
    return 1;
  }
  return 0;
}

2331

2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373
/*
  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);
  }
}

2374
bool show_master_info(THD* thd, MASTER_INFO* mi)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2375
{
2376
  // TODO: fix this for multi-master
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2377
  List<Item> field_list;
2378 2379 2380
  Protocol *protocol= thd->protocol;
  DBUG_ENTER("show_master_info");

guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2381 2382
  field_list.push_back(new Item_empty_string("Slave_IO_State",
						     14));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2383
  field_list.push_back(new Item_empty_string("Master_Host",
2384
						     sizeof(mi->host)));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2385
  field_list.push_back(new Item_empty_string("Master_User",
2386
						     sizeof(mi->user)));
2387 2388
  field_list.push_back(new Item_return_int("Master_Port", 7,
					   MYSQL_TYPE_LONG));
2389
  field_list.push_back(new Item_return_int("Connect_Retry", 10,
2390
					   MYSQL_TYPE_LONG));
2391
  field_list.push_back(new Item_empty_string("Master_Log_File",
2392 2393 2394
					     FN_REFLEN));
  field_list.push_back(new Item_return_int("Read_Master_Log_Pos", 10,
					   MYSQL_TYPE_LONGLONG));
2395
  field_list.push_back(new Item_empty_string("Relay_Log_File",
2396 2397 2398
					     FN_REFLEN));
  field_list.push_back(new Item_return_int("Relay_Log_Pos", 10,
					   MYSQL_TYPE_LONGLONG));
2399
  field_list.push_back(new Item_empty_string("Relay_Master_Log_File",
2400
					     FN_REFLEN));
2401 2402
  field_list.push_back(new Item_empty_string("Slave_IO_Running", 3));
  field_list.push_back(new Item_empty_string("Slave_SQL_Running", 3));
2403 2404 2405 2406 2407 2408
  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",
2409
					     28));
2410 2411 2412
  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,
2413
					   MYSQL_TYPE_LONG));
2414
  field_list.push_back(new Item_return_int("Exec_Master_Log_Pos", 10,
2415
					   MYSQL_TYPE_LONGLONG));
2416
  field_list.push_back(new Item_return_int("Relay_Log_Space", 10,
2417
					   MYSQL_TYPE_LONGLONG));
2418
  field_list.push_back(new Item_empty_string("Until_Condition", 6));
2419
  field_list.push_back(new Item_empty_string("Until_Log_File", FN_REFLEN));
2420
  field_list.push_back(new Item_return_int("Until_Log_Pos", 10, 
2421
                                           MYSQL_TYPE_LONGLONG));
2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432
  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)));
2433
  field_list.push_back(new Item_return_int("Seconds_Behind_Master", 10,
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2434
                                           MYSQL_TYPE_LONGLONG));
2435
  
2436 2437
  if (protocol->send_fields(&field_list,
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
2438
    DBUG_RETURN(TRUE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2439

2440 2441
  if (mi->host[0])
  {
2442
    DBUG_PRINT("info",("host is set: '%s'", mi->host));
2443
    String *packet= &thd->packet;
2444
    protocol->prepare_for_resend();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2445
  
2446 2447 2448 2449 2450
    /*
      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).
    */
2451 2452
    pthread_mutex_lock(&mi->data_lock);
    pthread_mutex_lock(&mi->rli.data_lock);
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2453 2454

    protocol->store(mi->io_thd ? mi->io_thd->proc_info : "", &my_charset_bin);
2455 2456
    protocol->store(mi->host, &my_charset_bin);
    protocol->store(mi->user, &my_charset_bin);
2457 2458
    protocol->store((uint32) mi->port);
    protocol->store((uint32) mi->connect_retry);
2459
    protocol->store(mi->master_log_name, &my_charset_bin);
2460
    protocol->store((ulonglong) mi->master_log_pos);
2461
    protocol->store(mi->rli.group_relay_log_name +
2462 2463
		    dirname_length(mi->rli.group_relay_log_name),
		    &my_charset_bin);
2464 2465
    protocol->store((ulonglong) mi->rli.group_relay_log_pos);
    protocol->store(mi->rli.group_master_log_name, &my_charset_bin);
monty@mysql.com's avatar
monty@mysql.com committed
2466 2467
    protocol->store(mi->slave_running == MYSQL_SLAVE_RUN_CONNECT ?
                    "Yes" : "No", &my_charset_bin);
2468
    protocol->store(mi->rli.slave_running ? "Yes":"No", &my_charset_bin);
2469 2470
    protocol->store(&replicate_do_db);
    protocol->store(&replicate_ignore_db);
2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487
    /*
      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);

2488
    protocol->store((uint32) mi->rli.last_slave_errno);
2489
    protocol->store(mi->rli.last_slave_error, &my_charset_bin);
2490
    protocol->store((uint32) mi->rli.slave_skip_counter);
2491
    protocol->store((ulonglong) mi->rli.group_master_log_pos);
2492
    protocol->store((ulonglong) mi->rli.log_space_total);
2493 2494 2495 2496 2497 2498 2499 2500

    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);
    
2501 2502 2503 2504 2505 2506 2507 2508 2509 2510
#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
2511

2512 2513 2514 2515 2516 2517
    /*
      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)
2518
    {
2519 2520 2521
      long time_diff= ((long)((time_t)time((time_t*) 0)
                              - mi->rli.last_master_timestamp)
                       - mi->clock_diff_with_master);
2522
      /*
2523 2524
        Apparently on some systems time_diff can be <0. Here are possible
        reasons related to MySQL:
2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536
        - 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.
2537 2538 2539 2540
        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".
2541
      */
2542 2543
      protocol->store((longlong)(mi->rli.last_master_timestamp ?
                                 max(0, time_diff) : 0));
2544
    }
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
2545 2546 2547
    else
      protocol->store_null();

2548 2549
    pthread_mutex_unlock(&mi->rli.data_lock);
    pthread_mutex_unlock(&mi->data_lock);
2550

2551
    if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length()))
2552
      DBUG_RETURN(TRUE);
2553
  }
2554
  send_eof(thd);
2555
  DBUG_RETURN(FALSE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2556 2557
}

2558 2559 2560 2561 2562 2563 2564
/*
  RETURN
     2 - flush relay log failed
     1 - flush master info failed
     0 - all ok
*/
int flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2565
{
2566
  IO_CACHE* file = &mi->file;
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
2567
  char lbuf[22];
2568 2569 2570
  DBUG_ENTER("flush_master_info");
  DBUG_PRINT("enter",("master_pos: %ld", (long) mi->master_log_pos));

2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582
  /*
    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.
  */
2583 2584 2585
  if (flush_relay_log_cache &&
      flush_io_cache(mi->rli.relay_log.get_log_file()))
    DBUG_RETURN(2);
2586 2587 2588 2589 2590 2591 2592 2593 2594 2595

  /*
    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).
  */

2596
  /*
2597 2598 2599 2600
     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
2601 2602
     of file we don't care about this garbage.
  */
2603

2604
  my_b_seek(file, 0L);
2605 2606 2607
  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),
2608
	      mi->host, mi->user,
2609 2610 2611
	      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);
2612
  DBUG_RETURN(-flush_io_cache(file));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2613 2614
}

2615

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2616
st_relay_log_info::st_relay_log_info()
2617 2618
  :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
2619 2620 2621
   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),
2622
   until_log_pos(0), retried_trans(0)
2623
{
monty@mysql.com's avatar
monty@mysql.com committed
2624 2625
  group_relay_log_name[0]= event_relay_log_name[0]=
    group_master_log_name[0]= 0;
2626
  last_slave_error[0]= until_log_name[0]= ign_master_log_name_end[0]= 0;
2627

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2628 2629
  bzero((char*) &info_file, sizeof(info_file));
  bzero((char*) &cache_buf, sizeof(cache_buf));
2630
  cached_charset_invalidate();
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2631 2632 2633 2634 2635 2636 2637
  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
2638
  relay_log.init_pthread_objects();
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650
}


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);
2651
  relay_log.cleanup();
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2652 2653
}

2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677
/*
  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
 */
2678

2679
int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
2680 2681
                                    longlong log_pos,
                                    longlong timeout)
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
2682
{
2683 2684
  if (!inited)
    return -1;
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
2685
  int event_count = 0;
2686
  ulong init_abort_pos_wait;
2687 2688
  int error=0;
  struct timespec abstime; // for timeout checking
2689
  const char *msg;
2690
  DBUG_ENTER("wait_for_pos");
2691 2692
  DBUG_PRINT("enter",("log_name: '%s'  log_pos: %lu  timeout: %lu",
                      log_name->c_ptr(), (ulong) log_pos, (ulong) timeout));
2693

2694
  set_timespec(abstime,timeout);
2695
  pthread_mutex_lock(&data_lock);
2696 2697 2698
  msg= thd->enter_cond(&data_cond, &data_lock,
                       "Waiting for the slave SQL thread to "
                       "advance position");
2699
  /* 
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2700 2701 2702 2703 2704 2705 2706 2707
     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:
2708
     STOP SLAVE;CHANGE MASTER/RESET SLAVE; START SLAVE;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2709 2710
     the change may happen very quickly and we may not notice that
     slave_running briefly switches between 1/0/1.
2711
  */
2712
  init_abort_pos_wait= abort_pos_wait;
2713

2714
  /*
2715
    We'll need to
2716
    handle all possible log names comparisons (e.g. 999 vs 1000).
2717
    We use ulong for string->number conversion ; this is no
2718 2719 2720 2721
    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
2722 2723 2724

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

2725 2726
  char *p= fn_ext(log_name_tmp);
  char *p_end;
2727
  if (!*p || log_pos<0)
2728 2729 2730 2731
  {
    error= -2; //means improper arguments
    goto err;
  }
2732 2733
  // 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
2734
  /* p points to '.' */
2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746
  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
2747
  /* The "compare and wait" main loop */
2748
  while (!thd->killed &&
2749
         init_abort_pos_wait == abort_pos_wait &&
2750
         slave_running)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2751
  {
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
2752 2753
    bool pos_reached;
    int cmp_result= 0;
monty@mysql.com's avatar
monty@mysql.com committed
2754

2755 2756 2757 2758 2759 2760
    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));

2761
    /*
monty@mysql.com's avatar
monty@mysql.com committed
2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772
      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 "".
2773
    */
2774
    if (*group_master_log_name)
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
2775
    {
monty@mysql.com's avatar
monty@mysql.com committed
2776 2777
      char *basename= (group_master_log_name +
                       dirname_length(group_master_log_name));
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2778
      /*
2779 2780 2781 2782
        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
2783
      */
2784 2785 2786 2787 2788 2789 2790 2791
      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;
2792 2793
      ulong group_master_log_name_extension= strtoul(q, &q_end, 10);
      if (group_master_log_name_extension < log_name_extension)
2794
        cmp_result= -1 ;
2795
      else
2796
        cmp_result= (group_master_log_name_extension > log_name_extension) ? 1 : 0 ;
2797

monty@mysql.com's avatar
monty@mysql.com committed
2798
      pos_reached= ((!cmp_result && group_master_log_pos >= (ulonglong)log_pos) ||
2799 2800
                    cmp_result > 0);
      if (pos_reached || thd->killed)
2801
        break;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2802
    }
2803 2804

    //wait for master update, with optional timeout.
2805
    
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2806
    DBUG_PRINT("info",("Waiting for master update"));
2807 2808 2809 2810
    /*
      We are going to pthread_cond_(timed)wait(); if the SQL thread stops it
      will wake us up.
    */
2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827
    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
2828
    DBUG_PRINT("info",("Got signal of master update or timed out"));
monty@mysql.com's avatar
monty@mysql.com committed
2829
    if (error == ETIMEDOUT || error == ETIME)
2830 2831 2832 2833
    {
      error= -1;
      break;
    }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2834
    error=0;
2835
    event_count++;
2836
    DBUG_PRINT("info",("Testing if killed or SQL thread not running"));
2837
  }
2838 2839

err:
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2840
  thd->exit_cond(msg);
2841
  DBUG_PRINT("exit",("killed: %d  abort: %d  slave_running: %d \
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2842
improper_arguments: %d  timed_out: %d",
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2843
                     thd->killed_errno(),
2844
                     (int) (init_abort_pos_wait != abort_pos_wait),
2845
                     (int) slave_running,
2846 2847 2848
                     (int) (error == -2),
                     (int) (error == -1)));
  if (thd->killed || init_abort_pos_wait != abort_pos_wait ||
2849
      !slave_running) 
2850 2851 2852 2853
  {
    error= -2;
  }
  DBUG_RETURN( error ? error : event_count );
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
2854 2855
}

2856 2857
void set_slave_thread_options(THD* thd)
{
2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872
  /*
     It's nonsense to constrain the slave threads with max_join_size; if a
     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.
  */
  ulonglong options= thd->options | OPTION_BIG_SELECTS;
  if (opt_log_slave_updates)
    options|= OPTION_BIN_LOG;
  else
    options&= ~OPTION_BIN_LOG;
  thd->options= options;
2873
  thd->variables.completion_type= 0;
2874
}
2875

2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887
void set_slave_thread_default_charset(THD* thd, RELAY_LOG_INFO *rli)
{
  thd->variables.character_set_client=
    global_system_variables.character_set_client;
  thd->variables.collation_connection=
    global_system_variables.collation_connection;
  thd->variables.collation_server=
    global_system_variables.collation_server;
  thd->update_charset();
  rli->cached_charset_invalidate();
}

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2888
/*
2889
  init_slave_thread()
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2890
*/
2891

2892
static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2893 2894
{
  DBUG_ENTER("init_slave_thread");
2895 2896
  thd->system_thread = (thd_type == SLAVE_THD_SQL) ?
    SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO; 
2897
  thd->security_ctx->skip_grants();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2898
  my_net_init(&thd->net, 0);
2899 2900 2901 2902 2903
/*
  Adding MAX_LOG_EVENT_HEADER_LEN to the max_allowed_packet on all
  slave threads, since a replication event can become this much larger
  than the corresponding packet (query) sent from client to master.
*/
2904
  thd->variables.max_allowed_packet= global_system_variables.max_allowed_packet
2905
    + MAX_LOG_EVENT_HEADER;  /* note, incr over the global not session var */
2906
  thd->slave_thread = 1;
2907
  set_slave_thread_options(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2908
  thd->client_capabilities = CLIENT_LOCAL_FILES;
2909
  thd->real_id=pthread_self();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2910 2911 2912 2913
  pthread_mutex_lock(&LOCK_thread_count);
  thd->thread_id = thread_id++;
  pthread_mutex_unlock(&LOCK_thread_count);

2914
  if (init_thr_lock() || thd->store_globals())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2915
  {
2916 2917
    thd->cleanup();
    delete thd;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2918 2919 2920
    DBUG_RETURN(-1);
  }

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2921
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2922 2923 2924 2925 2926
  sigset_t set;
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
#endif

2927
  if (thd_type == SLAVE_THD_SQL)
2928
    thd->proc_info= "Waiting for the next event in relay log";
2929
  else
2930
    thd->proc_info= "Waiting for master update";
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2931 2932 2933 2934 2935
  thd->version=refresh_version;
  thd->set_time();
  DBUG_RETURN(0);
}

2936

2937 2938
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
2939
{
2940
  int nap_time;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2941 2942 2943 2944 2945
  thr_alarm_t alarmed;
  thr_alarm_init(&alarmed);
  time_t start_time= time((time_t*) 0);
  time_t end_time= start_time+sec;

2946
  while ((nap_time= (int) (end_time - start_time)) > 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2947
  {
2948
    ALARM alarm_buff;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2949
    /*
2950
      The only reason we are asking for alarm is so that
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2951 2952 2953
      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
    */
2954
    thr_alarm(&alarmed, 2 * nap_time, &alarm_buff);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2955
    sleep(nap_time);
2956
    thr_end_alarm(&alarmed);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2957
    
2958
    if ((*thread_killed)(thd,thread_killed_arg))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2959 2960 2961 2962 2963 2964
      return 1;
    start_time=time((time_t*) 0);
  }
  return 0;
}

2965

2966 2967
static int request_dump(MYSQL* mysql, MASTER_INFO* mi,
			bool *suppress_warnings)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2968
{
2969
  char buf[FN_REFLEN + 10];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2970 2971
  int len;
  int binlog_flags = 0; // for now
2972
  char* logname = mi->master_log_name;
2973 2974
  DBUG_ENTER("request_dump");

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2975
  // TODO if big log files: Change next to int8store()
monty@mysql.com's avatar
monty@mysql.com committed
2976
  int4store(buf, (ulong) mi->master_log_pos);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2977
  int2store(buf + 4, binlog_flags);
2978
  int4store(buf + 6, server_id);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2979
  len = (uint) strlen(logname);
2980
  memcpy(buf + 10, logname,len);
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2981
  if (simple_command(mysql, COM_BINLOG_DUMP, buf, len + 10, 1))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2982
  {
2983 2984 2985 2986 2987
    /*
      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
2988
    if (mysql_errno(mysql) == ER_NET_READ_INTERRUPTED)
2989 2990
      *suppress_warnings= 1;			// Suppress reconnect warning
    else
2991
      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
2992
		      mysql_errno(mysql), mysql_error(mysql),
2993 2994
		      master_connect_retry);
    DBUG_RETURN(1);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2995
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2996

2997
  DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2998 2999
}

3000

3001
static int request_table_dump(MYSQL* mysql, const char* db, const char* table)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3002 3003 3004
{
  char buf[1024];
  char * p = buf;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3005 3006
  uint table_len = (uint) strlen(table);
  uint db_len = (uint) strlen(db);
3007
  if (table_len + db_len > sizeof(buf) - 2)
3008 3009 3010 3011
  {
    sql_print_error("request_table_dump: Buffer overrun");
    return 1;
  } 
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3012 3013 3014 3015 3016 3017 3018
  
  *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
3019
  if (simple_command(mysql, COM_TABLE_DUMP, buf, p - buf + table_len, 1))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3020 3021
  {
    sql_print_error("request_table_dump: Error sending the table dump \
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3022
command");
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3023 3024
    return 1;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3025 3026 3027 3028

  return 0;
}

3029

3030
/*
3031
  Read one event from the master
3032 3033 3034 3035 3036 3037 3038 3039 3040
  
  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.
3041

3042 3043 3044 3045 3046 3047
    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
3048
{
3049
  ulong len;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3050

3051
  *suppress_warnings= 0;
3052 3053 3054
  /*
    my_real_read() will time us out
    We check if we were told to die, and if not, try reading again
3055 3056

    TODO:  Move 'events_till_disconnect' to the MASTER_INFO structure
3057
  */
3058
#ifndef DBUG_OFF
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3059
  if (disconnect_slave_event_count && !(events_till_disconnect--))
3060 3061 3062
    return packet_error;      
#endif
  
3063
  len = cli_safe_read(mysql);
3064
  if (len == packet_error || (long) len < 1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3065
  {
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3066
    if (mysql_errno(mysql) == ER_NET_READ_INTERRUPTED)
3067 3068 3069 3070 3071 3072 3073 3074 3075
    {
      /*
	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
3076
      sql_print_error("Error reading packet from server: %s ( server_errno=%d)",
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3077
		      mysql_error(mysql), mysql_errno(mysql));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3078 3079 3080
    return packet_error;
  }

3081 3082
  /* Check if eof packet */
  if (len < 8 && mysql->net.read_pos[0] == 254)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3083
  {
3084 3085
    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
3086
		     mysql_error(mysql));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3087
     return packet_error;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3088
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3089
  
3090
  DBUG_PRINT("info",( "len: %lu  net->read_pos[4]: %d\n",
3091
		      len, mysql->net.read_pos[4]));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3092 3093 3094
  return len - 1;   
}

3095

3096
int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int expected_error)
3097
{
3098 3099 3100 3101 3102 3103 3104 3105 3106
  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;
  }
3107
}
3108

3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156
/*
     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)
  {
3157 3158 3159 3160 3161 3162
    /*
      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).
3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186
    */

    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
3187
        return TRUE;
3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198
      }
    }
    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);
}

3199

3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217
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;
}


3218
static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3219
{
3220 3221
  /*
     We acquire this mutex since we need it for all operations except
3222
     event execution. But we will release it in places where we will
3223 3224 3225
     wait for something for example inside of next_event().
   */
  pthread_mutex_lock(&rli->data_lock);
3226 3227 3228 3229 3230 3231 3232 3233
  /*
    This tests if the position of the end of the last previous executed event
    hits the UNTIL barrier.
    We would prefer to test if the position of the start (or possibly) end of
    the to-be-read event hits the UNTIL barrier, this is different if there
    was an event ignored by the I/O thread just before (BUG#13861 to be
    fixed).
  */
3234 3235
  if (rli->until_condition!=RELAY_LOG_INFO::UNTIL_NONE &&
      rli->is_until_satisfied())
3236
  {
3237
    char buf[22];
3238
    sql_print_information("Slave SQL thread stopped because it reached its"
3239
                    " UNTIL position %s", llstr(rli->until_pos(), buf));
3240
    /*
3241 3242 3243 3244 3245 3246 3247
      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;
  }
3248

3249
  Log_event * ev = next_event(rli);
3250

3251
  DBUG_ASSERT(rli->sql_thd==thd);
3252

3253
  if (sql_slave_killed(thd,rli))
3254
  {
3255
    pthread_mutex_unlock(&rli->data_lock);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3256
    delete ev;
3257
    return 1;
3258
  }
3259 3260
  if (ev)
  {
3261
    int type_code = ev->get_type_code();
3262
    int exec_res;
3263 3264

    /*
3265 3266 3267 3268 3269 3270 3271
      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
3272
      log files themselves.
3273 3274 3275
      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).
3276
    */
3277

3278
    DBUG_PRINT("info",("type_code=%d, server_id=%d",type_code,ev->server_id));
3279

3280
    if ((ev->server_id == (uint32) ::server_id &&
pem@mysql.com's avatar
pem@mysql.com committed
3281
         !replicate_same_server_id &&
3282
         type_code != FORMAT_DESCRIPTION_EVENT) ||
3283
        (rli->slave_skip_counter &&
3284 3285
         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
3286
    {
3287
      DBUG_PRINT("info", ("event skipped"));
3288 3289 3290 3291
      if (thd->options & OPTION_BEGIN)
        rli->inc_event_relay_log_pos();
      else
      {
3292
        rli->inc_group_relay_log_pos((type_code == ROTATE_EVENT ||
3293 3294 3295 3296 3297 3298
                                      type_code == STOP_EVENT ||
                                      type_code == FORMAT_DESCRIPTION_EVENT) ?
                                     LL(0) : ev->log_pos,
                                     1/* skip lock*/);
        flush_relay_log_info(rli);
      }
3299

3300
      /*
3301 3302 3303
        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.
3304
      */
3305 3306 3307
      if (rli->slave_skip_counter &&
          !((type_code == INTVAR_EVENT ||
             type_code == RAND_EVENT ||
3308
             type_code == USER_VAR_EVENT) &&
3309
            rli->slave_skip_counter == 1) &&
3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321
          /*
            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)))
3322 3323
        --rli->slave_skip_counter;
      pthread_mutex_unlock(&rli->data_lock);
3324 3325 3326
      delete ev;
      return 0;                                 // avoid infinite update loops
    }
3327
    pthread_mutex_unlock(&rli->data_lock);
3328

3329
    thd->server_id = ev->server_id; // use the original server id for logging
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3330
    thd->set_time();				// time the query
pem@mysql.telia.com's avatar
pem@mysql.telia.com committed
3331
    thd->lex->current_select= 0;
3332
    if (!ev->when)
3333
      ev->when = time(NULL);
3334
    ev->thd = thd;
3335 3336
    exec_res = ev->exec_event(rli);
    DBUG_ASSERT(rli->sql_thd==thd);
3337
    /*
3338 3339 3340 3341 3342 3343 3344 3345 3346
       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;
    }
3347 3348 3349 3350 3351 3352 3353 3354 3355 3356
    if (slave_trans_retries)
    {
      if (exec_res &&
          (thd->net.last_errno == ER_LOCK_DEADLOCK ||
           thd->net.last_errno == ER_LOCK_WAIT_TIMEOUT) &&
          !thd->is_fatal_error)
      {
        const char *errmsg;
        /*
          We were in a transaction which has been rolled back because of a
3357 3358 3359
        Sonera  deadlock. if lock wait timeout (innodb_lock_wait_timeout exceeded)
	  there is no rollback since 5.0.13 (ref: manual).
	  let's seek back to BEGIN log event and retry it all again.
3360 3361 3362 3363 3364 3365 3366 3367
          We have to not only seek but also
          a) init_master_info(), to seek back to hot relay log's start for later
          (for when we will come back to this hot log after re-processing the
          possibly existing old logs where BEGIN is: check_binlog_magic() will
          then need the cache to be at position 0 (see comments at beginning of
          init_master_info()).
          b) init_relay_log_pos(), because the BEGIN may be an older relay log.
        */
3368
        if (rli->trans_retries < slave_trans_retries)
3369 3370 3371 3372 3373 3374
        {
          if (init_master_info(rli->mi, 0, 0, 0, SLAVE_SQL))
            sql_print_error("Failed to initialize the master info structure");
          else if (init_relay_log_pos(rli,
                                      rli->group_relay_log_name,
                                      rli->group_relay_log_pos,
3375
                                      1, &errmsg, 1))
3376 3377 3378 3379 3380
            sql_print_error("Error initializing relay log position: %s",
                            errmsg);
          else
          {
            exec_res= 0;
3381
	    end_trans(thd, ROLLBACK);
3382 3383 3384 3385 3386 3387 3388 3389 3390 3391
	    /* chance for concurrent connection to get more locks */
            safe_sleep(thd, min(rli->trans_retries, MAX_SLAVE_RETRY_PAUSE),
		       (CHECK_KILLED_FUNC)sql_slave_killed, (void*)rli);
            pthread_mutex_lock(&rli->data_lock); // because of SHOW STATUS
	    rli->trans_retries++;
            rli->retried_trans++;
            pthread_mutex_unlock(&rli->data_lock);
            DBUG_PRINT("info", ("Slave retries transaction "
                                "rli->trans_retries: %lu", rli->trans_retries));
	  }
3392 3393 3394 3395 3396 3397 3398
        }
        else
          sql_print_error("Slave SQL thread retried transaction %lu time(s) "
                          "in vain, giving up. Consider raising the value of "
                          "the slave_transaction_retries variable.",
                          slave_trans_retries);
      }
3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409
      else if (!((thd->options & OPTION_BEGIN) && opt_using_transactions))
      {
        /*
          Only reset the retry counter if the event succeeded or
          failed with a non-transient error.  On a successful event,
          the execution will proceed as usual; in the case of a
          non-transient error, the slave will stop with an error.
	*/
        rli->trans_retries= 0; // restart from fresh
      }
    }
3410
    return exec_res;
3411
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3412
  else
3413
  {
3414
    pthread_mutex_unlock(&rli->data_lock);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
3415
    slave_print_error(rli, 0, "\
3416 3417 3418 3419 3420 3421 3422
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
3423
");
3424 3425
    return 1;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3426 3427
}

3428

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

3431
pthread_handler_t handle_slave_io(void *arg)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3432
{
3433 3434
  THD *thd; // needs to be first for thread_stack
  MYSQL *mysql;
3435
  MASTER_INFO *mi = (MASTER_INFO*)arg;
3436
  RELAY_LOG_INFO *rli= &mi->rli;
3437 3438
  char llbuff[22];
  uint retry_count;
3439

3440 3441
  // needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff
  my_thread_init();
3442
  DBUG_ENTER("handle_slave_io");
3443

sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
3444
#ifndef DBUG_OFF
3445
slave_begin:
3446
#endif
3447
  DBUG_ASSERT(mi->inited);
3448 3449 3450
  mysql= NULL ;
  retry_count= 0;

3451
  pthread_mutex_lock(&mi->run_lock);
3452 3453 3454
  /* Inform waiting threads that slave has started */
  mi->slave_run_id++;

3455
#ifndef DBUG_OFF
3456
  mi->events_till_abort = abort_slave_event_count;
3457 3458
#endif

3459
  thd= new THD; // note that contructor of THD uses DBUG_ !
3460
  THD_CHECK_SENTRY(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3461 3462

  pthread_detach_this_thread();
3463
  thd->thread_stack= (char*) &thd; // remember where our stack is
3464
  if (init_slave_thread(thd, SLAVE_THD_IO))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3465 3466 3467 3468 3469 3470
  {
    pthread_cond_broadcast(&mi->start_cond);
    pthread_mutex_unlock(&mi->run_lock);
    sql_print_error("Failed during slave I/O thread initialization");
    goto err;
  }
3471
  mi->io_thd = thd;
3472
  pthread_mutex_lock(&LOCK_thread_count);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3473
  threads.append(thd);
3474
  pthread_mutex_unlock(&LOCK_thread_count);
3475 3476 3477
  mi->slave_running = 1;
  mi->abort_slave = 0;
  pthread_mutex_unlock(&mi->run_lock);
3478
  pthread_cond_broadcast(&mi->start_cond);
3479

3480 3481 3482
  DBUG_PRINT("master_info",("log_file_name: '%s'  position: %s",
			    mi->master_log_name,
			    llstr(mi->master_log_pos,llbuff)));
3483

hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3484
  if (!(mi->mysql = mysql = mysql_init(NULL)))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3485
  {
3486
    sql_print_error("Slave I/O thread: error in mysql_init()");
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3487 3488
    goto err;
  }
3489

3490
  thd->proc_info = "Connecting to master";
3491
  // we can get killed during safe_connect
3492
  if (!safe_connect(thd, mysql, mi))
3493
  {
3494
    sql_print_information("Slave I/O thread: connected to master '%s@%s:%d',\
3495
  replication started in log '%s' at position %s", mi->user,
3496 3497 3498
			  mi->host, mi->port,
			  IO_RPL_LOG_NAME,
			  llstr(mi->master_log_pos,llbuff));
3499 3500 3501 3502 3503
  /*
    Adding MAX_LOG_EVENT_HEADER_LEN to the max_packet_size on the I/O
    thread, since a replication event can become this much larger than
    the corresponding packet (query) sent from client to master.
  */
3504 3505
    mysql->net.max_packet_size= thd->net.max_packet_size+= MAX_LOG_EVENT_HEADER;
  }
3506
  else
3507
  {
3508
    sql_print_information("Slave I/O thread killed while connecting to master");
3509 3510
    goto err;
  }
3511

3512
connected:
3513

3514 3515
  // TODO: the assignment below should be under mutex (5.0)
  mi->slave_running= MYSQL_SLAVE_RUN_CONNECT;
3516
  thd->slave_net = &mysql->net;
3517
  thd->proc_info = "Checking master version";
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
3518
  if (get_master_version_and_clock(mysql, mi))
3519
    goto err;
3520 3521

  if (mi->rli.relay_log.description_event_for_queue->binlog_version > 1)
3522
  {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3523 3524 3525 3526 3527
    /*
      Register ourselves with the master.
      If fails, this is not fatal - we just print the error message and go
      on with life.
    */
3528
    thd->proc_info = "Registering slave on master";
3529
    if (register_slave_on_master(mysql) ||  update_slave_list(mysql, mi))
3530 3531
      goto err;
  }
3532

3533
  DBUG_PRINT("info",("Starting reading binary log from master"));
3534
  while (!io_slave_killed(thd,mi))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3535
  {
3536
    bool suppress_warnings= 0;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3537
    thd->proc_info = "Requesting binlog dump";
3538
    if (request_dump(mysql, mi, &suppress_warnings))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3539 3540
    {
      sql_print_error("Failed on request_dump()");
3541
      if (io_slave_killed(thd,mi))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3542
      {
3543
	sql_print_information("Slave I/O thread killed while requesting master \
3544
dump");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3545 3546
	goto err;
      }
3547

3548
      mi->slave_running= MYSQL_SLAVE_RUN_NOT_CONNECT;
3549
      thd->proc_info= "Waiting to reconnect after a failed binlog dump request";
3550 3551 3552
#ifdef SIGNAL_WITH_VIO_CLOSE
      thd->clear_active_vio();
#endif
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3553
      end_server(mysql);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3554 3555 3556 3557 3558
      /*
	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
      */
3559 3560 3561 3562
      if (retry_count++)
      {
	if (retry_count > master_retry_count)
	  goto err;				// Don't retry forever
3563 3564
	safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed,
		   (void*)mi);
3565
      }
3566
      if (io_slave_killed(thd,mi))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3567
      {
3568
	sql_print_information("Slave I/O thread killed while retrying master \
3569
dump");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3570 3571
	goto err;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3572

3573
      thd->proc_info = "Reconnecting after a failed binlog dump request";
3574 3575
      if (!suppress_warnings)
	sql_print_error("Slave I/O thread: failed dump request, \
3576
reconnecting to try again, log '%s' at postion %s", IO_RPL_LOG_NAME,
3577 3578 3579
			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
3580
      {
3581
	sql_print_information("Slave I/O thread killed during or \
3582
after reconnect");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3583 3584
	goto err;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3585

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3586 3587
      goto connected;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3588

3589
    while (!io_slave_killed(thd,mi))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3590
    {
3591 3592 3593
      ulong event_len;

      suppress_warnings= 0;
3594
      /*
3595
         We say "waiting" because read_event() will wait if there's nothing to
3596 3597 3598
         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.
3599
      */
3600 3601
      thd->proc_info= "Waiting for master to send event";
      event_len= read_event(mysql, mi, &suppress_warnings);
3602
      if (io_slave_killed(thd,mi))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3603
      {
3604
	if (global_system_variables.log_warnings)
3605
	  sql_print_information("Slave I/O thread killed while reading event");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3606 3607
	goto err;
      }
3608

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3609 3610
      if (event_len == packet_error)
      {
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3611
	uint mysql_error_number= mysql_errno(mysql);
3612
	if (mysql_error_number == ER_NET_PACKET_TOO_LARGE)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3613
	{
3614 3615 3616 3617
	  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",
3618
			  thd->variables.max_allowed_packet);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3619 3620
	  goto err;
	}
3621 3622 3623
	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
3624
			  mysql_error(mysql));
3625 3626
	  goto err;
	}
3627
        mi->slave_running= MYSQL_SLAVE_RUN_NOT_CONNECT;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3628
	thd->proc_info = "Waiting to reconnect after a failed master event read";
3629 3630 3631
#ifdef SIGNAL_WITH_VIO_CLOSE
        thd->clear_active_vio();
#endif
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3632
	end_server(mysql);
3633 3634 3635 3636
	if (retry_count++)
	{
	  if (retry_count > master_retry_count)
	    goto err;				// Don't retry forever
3637
	  safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed,
3638
		     (void*) mi);
3639
	}
3640
	if (io_slave_killed(thd,mi))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3641
	{
3642
	  if (global_system_variables.log_warnings)
3643
	    sql_print_information("Slave I/O thread killed while waiting to \
3644
reconnect after a failed read");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3645 3646
	  goto err;
	}
3647
	thd->proc_info = "Reconnecting after a failed master event read";
3648
	if (!suppress_warnings)
3649
	  sql_print_information("Slave I/O thread: Failed reading log event, \
3650
reconnecting to retry, log '%s' position %s", IO_RPL_LOG_NAME,
3651 3652 3653
			  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
3654
	{
3655
	  if (global_system_variables.log_warnings)
3656
	    sql_print_information("Slave I/O thread killed during or after a \
3657
reconnect done to recover from failed read");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3658 3659 3660
	  goto err;
	}
	goto connected;
3661
      } // if (event_len == packet_error)
3662

3663
      retry_count=0;			// ok event, reset retry counter
3664
      thd->proc_info = "Queueing master event to the relay log";
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3665 3666 3667
      if (queue_event(mi,(const char*)mysql->net.read_pos + 1,
		      event_len))
      {
3668
	sql_print_error("Slave I/O thread could not queue event from master");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3669 3670
	goto err;
      }
3671 3672 3673 3674 3675
      if (flush_master_info(mi, 1))
      {
        sql_print_error("Failed to flush master info file");
        goto err;
      }
3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687
      /*
        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.
      */
3688 3689 3690 3691 3692
#ifndef DBUG_OFF
      {
        char llbuf1[22], llbuf2[22];
        DBUG_PRINT("info", ("log_space_limit=%s log_space_total=%s \
ignore_log_space_limit=%d",
3693 3694 3695
                            llstr(rli->log_space_limit,llbuf1),
                            llstr(rli->log_space_total,llbuf2),
                            (int) rli->ignore_log_space_limit)); 
3696 3697 3698
      }
#endif

3699 3700 3701 3702
      if (rli->log_space_limit && rli->log_space_limit <
	  rli->log_space_total &&
          !rli->ignore_log_space_limit)
	if (wait_for_relay_log_space(rli))
3703 3704 3705 3706 3707
	{
	  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
3708
      // TODO: check debugging abort code
3709
#ifndef DBUG_OFF
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3710 3711 3712 3713 3714
      if (abort_slave_event_count && !--events_till_abort)
      {
	sql_print_error("Slave I/O thread: debugging abort");
	goto err;
      }
3715
#endif
3716
    } 
3717
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3718

monty@donna.mysql.fi's avatar
monty@donna.mysql.fi committed
3719
  // error = 0;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3720
err:
3721
  // print the current replication position
3722
  sql_print_information("Slave I/O thread exiting, read up to log '%s', position %s",
3723
		  IO_RPL_LOG_NAME, llstr(mi->master_log_pos,llbuff));
3724
  VOID(pthread_mutex_lock(&LOCK_thread_count));
3725 3726 3727
  thd->query= 0; // extra safety
  thd->query_length= 0;
  thd->reset_db(NULL, 0);
3728
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
3729 3730
  if (mysql)
  {
3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741
    /*
      Here we need to clear the active VIO before closing the
      connection with the master.  The reason is that THD::awake()
      might be called from terminate_slave_thread() because somebody
      issued a STOP SLAVE.  If that happends, the close_active_vio()
      can be called in the middle of closing the VIO associated with
      the 'mysql' object, causing a crash.
    */
#ifdef SIGNAL_WITH_VIO_CLOSE
    thd->clear_active_vio();
#endif
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3742
    mysql_close(mysql);
3743 3744
    mi->mysql=0;
  }
3745
  write_ignored_events_info_to_relay_log(thd, mi);
jcole@tetra.spaceapes.com's avatar
jcole@tetra.spaceapes.com committed
3746
  thd->proc_info = "Waiting for slave mutex on exit";
3747
  pthread_mutex_lock(&mi->run_lock);
3748

3749 3750 3751
  /* Forget the relay log's format */
  delete mi->rli.relay_log.description_event_for_queue;
  mi->rli.relay_log.description_event_for_queue= 0;
3752
  // TODO: make rpl_status part of MASTER_INFO
3753
  change_rpl_status(RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE);
3754
  DBUG_ASSERT(thd->net.buff != 0);
3755
  net_end(&thd->net); // destructor will not free it, because net.vio is 0
monty@mysql.com's avatar
monty@mysql.com committed
3756
  close_thread_tables(thd, 0);
3757
  pthread_mutex_lock(&LOCK_thread_count);
3758
  THD_CHECK_SENTRY(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3759
  delete thd;
3760
  pthread_mutex_unlock(&LOCK_thread_count);
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
3761 3762 3763
  mi->abort_slave= 0;
  mi->slave_running= 0;
  mi->io_thd= 0;
3764
  pthread_mutex_unlock(&mi->run_lock);
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
3765
  pthread_cond_broadcast(&mi->stop_cond);       // tell the world we are done
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
3766
#ifndef DBUG_OFF
3767
  if (abort_slave_event_count && !events_till_abort)
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
3768
    goto slave_begin;
3769
#endif
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3770
  my_thread_end();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3771 3772 3773 3774
  pthread_exit(0);
  DBUG_RETURN(0);				// Can't return anything here
}

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

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

3778
pthread_handler_t handle_slave_sql(void *arg)
3779
{
3780
  THD *thd;			/* needs to be first for thread_stack */
3781
  char llbuff[22],llbuff1[22];
3782
  RELAY_LOG_INFO* rli = &((MASTER_INFO*)arg)->rli;
3783 3784 3785 3786
  const char *errmsg;

  // needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff
  my_thread_init();
3787
  DBUG_ENTER("handle_slave_sql");
3788 3789

#ifndef DBUG_OFF
3790
slave_begin:
3791 3792
#endif  

3793 3794 3795
  DBUG_ASSERT(rli->inited);
  pthread_mutex_lock(&rli->run_lock);
  DBUG_ASSERT(!rli->slave_running);
3796
  errmsg= 0;
3797 3798 3799
#ifndef DBUG_OFF  
  rli->events_till_abort = abort_slave_event_count;
#endif  
3800

3801
  thd = new THD; // note that contructor of THD uses DBUG_ !
3802 3803
  thd->thread_stack = (char*)&thd; // remember where our stack is
  
3804 3805 3806
  /* Inform waiting threads that slave has started */
  rli->slave_run_id++;

3807 3808
  pthread_detach_this_thread();
  if (init_slave_thread(thd, SLAVE_THD_SQL))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3809 3810 3811 3812 3813 3814 3815 3816 3817 3818
  {
    /*
      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;
  }
3819
  thd->init_for_queries();
3820
  rli->sql_thd= thd;
3821
  thd->temporary_tables = rli->save_temporary_tables; // restore temp tables
3822
  pthread_mutex_lock(&LOCK_thread_count);
3823
  threads.append(thd);
3824
  pthread_mutex_unlock(&LOCK_thread_count);
3825 3826 3827 3828 3829 3830 3831 3832
  /*
    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.
  */
3833 3834 3835
  rli->slave_running = 1;
  rli->abort_slave = 0;
  pthread_mutex_unlock(&rli->run_lock);
3836
  pthread_cond_broadcast(&rli->start_cond);
3837

guilhem@mysql.com's avatar
guilhem@mysql.com committed
3838 3839 3840
  /*
    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
3841
    though there's no problem anymore). Do not reset the master timestamp
3842 3843 3844 3845
    (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
3846
    But the master timestamp is reset by RESET SLAVE & CHANGE MASTER.
guilhem@mysql.com's avatar
guilhem@mysql.com committed
3847
  */
guilhem@gbichot2's avatar
guilhem@gbichot2 committed
3848
  clear_slave_error(rli);
3849 3850

  //tell the I/O thread to take relay_log_space_limit into account from now on
3851
  pthread_mutex_lock(&rli->log_space_lock);
3852
  rli->ignore_log_space_limit= 0;
3853
  pthread_mutex_unlock(&rli->log_space_lock);
3854
  rli->trans_retries= 0; // start from "no error"
3855

3856
  if (init_relay_log_pos(rli,
3857 3858
			 rli->group_relay_log_name,
			 rli->group_relay_log_pos,
3859 3860
			 1 /*need data lock*/, &errmsg,
                         1 /*look for a description_event*/))
3861 3862 3863 3864 3865
  {
    sql_print_error("Error initializing relay log position: %s",
		    errmsg);
    goto err;
  }
3866
  THD_CHECK_SENTRY(thd);
3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890
#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
3891
  DBUG_ASSERT(rli->sql_thd == thd);
3892 3893

  DBUG_PRINT("master_info",("log_file_name: %s  position: %s",
3894 3895
			    rli->group_master_log_name,
			    llstr(rli->group_master_log_pos,llbuff)));
3896
  if (global_system_variables.log_warnings)
3897
    sql_print_information("Slave SQL thread initialized, starting replication in \
3898
log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
3899 3900
		    llstr(rli->group_master_log_pos,llbuff),rli->group_relay_log_name,
		    llstr(rli->group_relay_log_pos,llbuff1));
3901

gluh@gluh.mysql.r18.ru's avatar
SCRUM:  
gluh@gluh.mysql.r18.ru committed
3902
  /* execute init_slave variable */
3903
  if (sys_init_slave.value_length)
gluh@gluh.mysql.r18.ru's avatar
SCRUM:  
gluh@gluh.mysql.r18.ru committed
3904
  {
3905
    execute_init_command(thd, &sys_init_slave, &LOCK_sys_init_slave);
gluh@gluh.mysql.r18.ru's avatar
SCRUM:  
gluh@gluh.mysql.r18.ru committed
3906 3907 3908 3909 3910 3911 3912 3913
    if (thd->query_error)
    {
      sql_print_error("\
Slave SQL thread aborted. Can't execute init_slave query");
      goto err;
    }
  }

3914 3915
  /* Read queries from the IO/THREAD until this thread is killed */

3916
  while (!sql_slave_killed(thd,rli))
3917
  {
3918
    thd->proc_info = "Reading event from the relay log";
3919
    DBUG_ASSERT(rli->sql_thd == thd);
3920
    THD_CHECK_SENTRY(thd);
3921 3922 3923
    if (exec_relay_log_event(thd,rli))
    {
      // do not scare the user if SQL thread was simply killed or stopped
3924
      if (!sql_slave_killed(thd,rli))
3925 3926
        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
3927
the slave SQL thread with \"SLAVE START\". We stopped at log \
3928
'%s' position %s", RPL_LOG_NAME, llstr(rli->group_master_log_pos, llbuff));
3929 3930
      goto err;
    }
3931
  }
3932

3933
  /* Thread stopped. Print the current replication position to the log */
monty@mysql.com's avatar
monty@mysql.com committed
3934 3935 3936
  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));
3937 3938

 err:
3939
  VOID(pthread_mutex_lock(&LOCK_thread_count));
3940 3941 3942 3943 3944
  /*
    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)).
  */
3945 3946 3947 3948
  thd->catalog= 0; 
  thd->reset_db(NULL, 0);
  thd->query= 0; 
  thd->query_length= 0;
3949
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
3950 3951
  thd->proc_info = "Waiting for slave mutex on exit";
  pthread_mutex_lock(&rli->run_lock);
3952 3953
  /* We need data_lock, at least to wake up any waiting master_pos_wait() */
  pthread_mutex_lock(&rli->data_lock);
3954
  DBUG_ASSERT(rli->slave_running == 1); // tracking buffer overrun
3955 3956
  /* When master_pos_wait() wakes up it will check this and terminate */
  rli->slave_running= 0; 
3957 3958 3959
  /* Forget the relay log's format */
  delete rli->relay_log.description_event_for_exec;
  rli->relay_log.description_event_for_exec= 0;
3960 3961 3962 3963
  /* 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
3964
  rli->ignore_log_space_limit= 0; /* don't need any lock */
3965 3966
  /* we die so won't remember charset - re-update them on next thread start */
  rli->cached_charset_invalidate();
3967
  rli->save_temporary_tables = thd->temporary_tables;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3968 3969 3970 3971 3972

  /*
    TODO: see if we can do this conditionally in next_event() instead
    to avoid unneeded position re-init
  */
3973 3974 3975 3976
  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);
3977
  THD_CHECK_SENTRY(thd);
3978
  rli->sql_thd= 0;
3979
  pthread_mutex_lock(&LOCK_thread_count);
3980
  THD_CHECK_SENTRY(thd);
3981 3982 3983
  delete thd;
  pthread_mutex_unlock(&LOCK_thread_count);
  pthread_cond_broadcast(&rli->stop_cond);
3984

3985
#ifndef DBUG_OFF
3986 3987 3988 3989 3990
  /*
    Bug #19938 Valgrind error (race) in handle_slave_sql()
    Read the value of rli->event_till_abort before releasing the mutex
  */
  const int eta= rli->events_till_abort;
3991
#endif
3992

3993
  // tell the world we are done
3994
  pthread_mutex_unlock(&rli->run_lock);
3995
#ifndef DBUG_OFF // TODO: reconsider the code below
3996
  if (abort_slave_event_count && !eta)
3997
    goto slave_begin;
3998
#endif  
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3999
  my_thread_end();
4000 4001 4002
  pthread_exit(0);
  DBUG_RETURN(0);				// Can't return anything here
}
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
4003

4004

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4005
/*
4006
  process_io_create_file()
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4007
*/
4008

4009 4010 4011 4012 4013
static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev)
{
  int error = 1;
  ulong num_bytes;
  bool cev_not_written;
4014 4015
  THD *thd = mi->io_thd;
  NET *net = &mi->mysql->net;
4016
  DBUG_ENTER("process_io_create_file");
4017 4018

  if (unlikely(!cev->is_valid()))
4019
    DBUG_RETURN(1);
4020 4021 4022 4023 4024 4025
  /*
    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);
4026
    DBUG_RETURN(0);
4027 4028 4029
  }
  DBUG_ASSERT(cev->inited_from_old);
  thd->file_id = cev->file_id = mi->file_id++;
4030
  thd->server_id = cev->server_id;
4031 4032 4033 4034 4035 4036 4037 4038 4039
  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
4040 4041 4042 4043
  /*
    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
4044 4045
  */
  {
4046
    Append_block_log_event aev(thd,0,0,0,0);
4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057
  
    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 */
      {
4058
	net_write_command(net, 0, "", 0, "", 0);/* 3.23 master wants it */
monty@mysql.com's avatar
monty@mysql.com committed
4059 4060 4061 4062 4063 4064 4065 4066
        /*
          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
4067
	Execute_load_log_event xev(thd,0,0);
4068
	xev.log_pos = cev->log_pos;
4069 4070 4071 4072 4073 4074
	if (unlikely(mi->rli.relay_log.append(&xev)))
	{
	  sql_print_error("Slave I/O: error writing Exec_load event to \
relay log");
	  goto err;
	}
4075
	mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total);
4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088
	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;
4089
	mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total);
4090 4091 4092 4093 4094
      }
      else
      {
	aev.block = (char*)net->read_pos;
	aev.block_len = num_bytes;
4095
	aev.log_pos = cev->log_pos;
4096 4097 4098 4099 4100 4101
	if (unlikely(mi->rli.relay_log.append(&aev)))
	{
	  sql_print_error("Slave I/O: error writing Append_block event to \
relay log");
	  goto err;
	}
4102
	mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total) ;
4103 4104 4105 4106 4107
      }
    }
  }
  error=0;
err:
4108
  DBUG_RETURN(error);
4109
}
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4110

4111

4112
/*
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4113 4114 4115 4116 4117 4118 4119 4120
  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
4121
    Updates the master info with the place in the next binary
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4122
    log where we should start reading.
4123
    Rotate the relay log to avoid mixed-format relay logs.
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4124 4125 4126 4127 4128 4129 4130

  NOTES
    We assume we already locked mi->data_lock

  RETURN VALUES
    0		ok
    1	        Log event is illegal
4131 4132 4133

*/

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4134
static int process_io_rotate(MASTER_INFO *mi, Rotate_log_event *rev)
4135
{
4136
  DBUG_ENTER("process_io_rotate");
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4137
  safe_mutex_assert_owner(&mi->data_lock);
4138

4139
  if (unlikely(!rev->is_valid()))
4140
    DBUG_RETURN(1);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4141

4142
  /* Safe copy as 'rev' has been "sanitized" in Rotate_log_event's ctor */
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4143 4144
  memcpy(mi->master_log_name, rev->new_log_ident, rev->ident_len+1);
  mi->master_log_pos= rev->pos;
4145
  DBUG_PRINT("info", ("master_log_pos: '%s' %lu",
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4146
		      mi->master_log_name, (ulong) mi->master_log_pos));
4147
#ifndef DBUG_OFF
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4148 4149 4150 4151 4152 4153
  /*
    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++;
4154
#endif
4155

4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169
  /*
    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);
  }
4170 4171 4172 4173
  /*
    Rotate the relay log makes binlog format detection easier (at next slave
    start or mysqlbinlog)
  */
4174
  rotate_relay_log(mi); /* will take the right mutexes */
4175
  DBUG_RETURN(0);
4176 4177
}

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4178
/*
4179 4180
  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
4181
*/
4182
static int queue_binlog_ver_1_event(MASTER_INFO *mi, const char *buf,
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4183
			   ulong event_len)
4184
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4185
  const char *errmsg = 0;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4186 4187 4188 4189
  ulong inc_pos;
  bool ignore_event= 0;
  char *tmp_buf = 0;
  RELAY_LOG_INFO *rli= &mi->rli;
4190
  DBUG_ENTER("queue_binlog_ver_1_event");
4191

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4192 4193 4194
  /*
    If we get Load event, we need to pass a non-reusable buffer
    to read_log_event, so we do a trick
4195 4196 4197 4198 4199 4200
  */
  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");
4201
      DBUG_RETURN(1);
4202 4203
    }
    memcpy(tmp_buf,buf,event_len);
4204 4205 4206 4207 4208 4209 4210 4211
    /*
      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;
serg@serg.mylan's avatar
serg@serg.mylan committed
4212
    int4store(tmp_buf+EVENT_LEN_OFFSET, event_len);
4213 4214
    buf = (const char*)tmp_buf;
  }
4215 4216 4217 4218 4219 4220
  /*
    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
4221
  Log_event *ev = Log_event::read_log_event(buf,event_len, &errmsg,
4222
                                            mi->rli.relay_log.description_event_for_queue);
4223
  if (unlikely(!ev))
4224 4225
  {
    sql_print_error("Read invalid event from master: '%s',\
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4226
 master could be corrupt but a more likely cause of this is a bug",
4227
		    errmsg);
4228 4229
    my_free((char*) tmp_buf, MYF(MY_ALLOW_ZERO_PTR));
    DBUG_RETURN(1);
4230
  }
4231
  pthread_mutex_lock(&mi->data_lock);
4232
  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
4233
  switch (ev->get_type_code()) {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4234
  case STOP_EVENT:
4235
    ignore_event= 1;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4236 4237
    inc_pos= event_len;
    break;
4238
  case ROTATE_EVENT:
4239
    if (unlikely(process_io_rotate(mi,(Rotate_log_event*)ev)))
4240 4241
    {
      delete ev;
4242
      pthread_mutex_unlock(&mi->data_lock);
4243
      DBUG_RETURN(1);
4244
    }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4245
    inc_pos= 0;
4246
    break;
4247
  case CREATE_FILE_EVENT:
4248 4249 4250 4251 4252 4253
    /*
      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.
    */
4254
  {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4255
    /* We come here when and only when tmp_buf != 0 */
4256
    DBUG_ASSERT(tmp_buf != 0);
4257 4258
    inc_pos=event_len;
    ev->log_pos+= inc_pos;
4259
    int error = process_io_create_file(mi,(Create_file_log_event*)ev);
4260
    delete ev;
4261
    mi->master_log_pos += inc_pos;
4262
    DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
4263
    pthread_mutex_unlock(&mi->data_lock);
4264
    my_free((char*)tmp_buf, MYF(0));
4265
    DBUG_RETURN(error);
4266
  }
4267
  default:
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4268
    inc_pos= event_len;
4269 4270
    break;
  }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4271
  if (likely(!ignore_event))
4272
  {
4273 4274 4275 4276 4277 4278
    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
4279
    if (unlikely(rli->relay_log.append(ev)))
4280 4281 4282
    {
      delete ev;
      pthread_mutex_unlock(&mi->data_lock);
4283
      DBUG_RETURN(1);
4284
    }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4285
    rli->relay_log.harvest_bytes_written(&rli->log_space_total);
4286 4287
  }
  delete ev;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4288
  mi->master_log_pos+= inc_pos;
4289
  DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
4290
  pthread_mutex_unlock(&mi->data_lock);
4291
  DBUG_RETURN(0);
4292 4293
}

4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344
/*
  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:
4345
  DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376
  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;
  }
}
4377

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4378
/*
4379 4380
  queue_event()

4381 4382 4383 4384 4385
  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
4386 4387 4388
*/

int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
4389
{
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4390 4391 4392
  int error= 0;
  ulong inc_pos;
  RELAY_LOG_INFO *rli= &mi->rli;
4393
  pthread_mutex_t *log_lock= rli->relay_log.get_log_lock();
4394 4395
  DBUG_ENTER("queue_event");

4396 4397
  LINT_INIT(inc_pos);

4398 4399
  if (mi->rli.relay_log.description_event_for_queue->binlog_version<4 &&
      buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT /* a way to escape */)
4400
    DBUG_RETURN(queue_old_event(mi,buf,event_len));
4401 4402

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

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4404
  switch (buf[EVENT_TYPE_OFFSET]) {
4405
  case STOP_EVENT:
4406 4407
    /*
      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
4408 4409 4410
      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
4411
      prepared statements' deletion are TODO only when we binlog prep stmts).
4412
      
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4413 4414 4415 4416
      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).
4417 4418
    */
    goto err;
4419 4420
  case ROTATE_EVENT:
  {
4421
    Rotate_log_event rev(buf,event_len,mi->rli.relay_log.description_event_for_queue); 
4422
    if (unlikely(process_io_rotate(mi,&rev)))
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4423
    {
4424 4425
      error= 1;
      goto err;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4426
    }
4427 4428 4429 4430
    /*
      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
4431
    inc_pos= 0;
4432 4433
    break;
  }
4434 4435 4436 4437 4438 4439 4440
  case FORMAT_DESCRIPTION_EVENT:
  {
    /*
      Create an event, and save it (when we rotate the relay log, we will have
      to write this event again).
    */
    /*
4441 4442 4443
      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).
4444
    */
4445
    Format_description_log_event* tmp;
4446
    const char* errmsg;
4447
    if (!(tmp= (Format_description_log_event*)
4448
          Log_event::read_log_event(buf, event_len, &errmsg,
4449
                                    mi->rli.relay_log.description_event_for_queue)))
4450 4451 4452 4453
    {
      error= 2;
      goto err;
    }
4454 4455
    delete mi->rli.relay_log.description_event_for_queue;
    mi->rli.relay_log.description_event_for_queue= tmp;
4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469
    /* 
       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;
4470
  default:
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4471
    inc_pos= event_len;
4472 4473
    break;
  }
4474 4475 4476 4477

  /* 
     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
4478 4479
     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
4480 4481 4482 4483 4484 4485 4486 4487
     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!).
  */

4488 4489
  pthread_mutex_lock(log_lock);

guilhem@mysql.com's avatar
guilhem@mysql.com committed
4490 4491
  if ((uint4korr(buf + SERVER_ID_OFFSET) == ::server_id) &&
      !replicate_same_server_id)
4492
  {
4493 4494
    /*
      Do not write it to the relay log.
4495 4496 4497 4498 4499 4500 4501 4502
      a) We still want to increment mi->master_log_pos, 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).
      b) We want to record that we are skipping events, for the information of
      the slave SQL thread, otherwise that thread may let
      rli->group_relay_log_pos stay too small if the last binlog's event is
      ignored.
4503 4504 4505
      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.
4506
    */
4507 4508 4509
    if (buf[EVENT_TYPE_OFFSET]!=FORMAT_DESCRIPTION_EVENT &&
        buf[EVENT_TYPE_OFFSET]!=ROTATE_EVENT &&
        buf[EVENT_TYPE_OFFSET]!=STOP_EVENT)
guilhem@mysql.com's avatar
guilhem@mysql.com committed
4510
    {
4511
      mi->master_log_pos+= inc_pos;
guilhem@mysql.com's avatar
guilhem@mysql.com committed
4512 4513 4514 4515
      memcpy(rli->ign_master_log_name_end, mi->master_log_name, FN_REFLEN);
      DBUG_ASSERT(rli->ign_master_log_name_end[0]);
      rli->ign_master_log_pos_end= mi->master_log_pos;
    }
4516
    rli->relay_log.signal_update(); // the slave SQL thread needs to re-check
4517 4518
    DBUG_PRINT("info", ("master_log_pos: %lu  event originating from the same server, ignored",
                        (ulong) mi->master_log_pos));
4519
  }  
monty@mysql.com's avatar
monty@mysql.com committed
4520 4521 4522
  else
  {
    /* write the event to the relay log */
4523
    if (likely(!(rli->relay_log.appendv(buf,event_len,0))))
4524 4525
    {
      mi->master_log_pos+= inc_pos;
4526
      DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
4527 4528
      rli->relay_log.harvest_bytes_written(&rli->log_space_total);
    }
4529
    else
4530
      error= 3;
4531
    rli->ign_master_log_name_end[0]= 0; // last event is not ignored
monty@mysql.com's avatar
monty@mysql.com committed
4532
  }
4533
  pthread_mutex_unlock(log_lock);
4534 4535 4536


err:
4537
  pthread_mutex_unlock(&mi->data_lock);
4538
  DBUG_PRINT("info", ("error: %d", error));
4539
  DBUG_RETURN(error);
4540 4541
}

4542

4543 4544
void end_relay_log_info(RELAY_LOG_INFO* rli)
{
4545 4546
  DBUG_ENTER("end_relay_log_info");

4547
  if (!rli->inited)
4548
    DBUG_VOID_RETURN;
4549
  if (rli->info_fd >= 0)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4550 4551
  {
    end_io_cache(&rli->info_file);
4552
    (void) my_close(rli->info_fd, MYF(MY_WME));
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4553 4554
    rli->info_fd = -1;
  }
4555
  if (rli->cur_log_fd >= 0)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4556 4557 4558 4559 4560
  {
    end_io_cache(&rli->cache_buf);
    (void)my_close(rli->cur_log_fd, MYF(MY_WME));
    rli->cur_log_fd = -1;
  }
4561
  rli->inited = 0;
4562
  rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
4563
  rli->relay_log.harvest_bytes_written(&rli->log_space_total);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
4564 4565 4566 4567 4568 4569
  /*
    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();
4570
  DBUG_VOID_RETURN;
4571 4572
}

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4573 4574
/*
  Try to connect until successful or slave killed
4575

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4576 4577 4578 4579 4580
  SYNPOSIS
    safe_connect()
    thd			Thread handler for slave
    mysql		MySQL connection handle
    mi			Replication handle
4581

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4582 4583 4584 4585
  RETURN
    0	ok
    #	Error
*/
4586

4587
static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4588
{
4589
  return connect_to_master(thd, mysql, mi, 0, 0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4590 4591
}

4592

4593
/*
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4594 4595
  SYNPOSIS
    connect_to_master()
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4596

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4597 4598 4599
  IMPLEMENTATION
    Try to connect until successful or slave killed or we have retried
    master_retry_count times
4600
*/
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4601

sasha@mysql.sashanet.com's avatar
cleanup  
sasha@mysql.sashanet.com committed
4602
static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
4603
			     bool reconnect, bool suppress_warnings)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4604
{
4605
  int slave_was_killed;
4606 4607
  int last_errno= -2;				// impossible error
  ulong err_count=0;
4608
  char llbuff[22];
4609
  DBUG_ENTER("connect_to_master");
4610

4611 4612 4613
#ifndef DBUG_OFF
  events_till_disconnect = disconnect_slave_event_count;
#endif
4614
  ulong client_flag= CLIENT_REMEMBER_OPTIONS;
4615 4616 4617
  if (opt_slave_compressed_protocol)
    client_flag=CLIENT_COMPRESS;		/* We will use compression */

4618 4619
  mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout);
  mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, (char *) &slave_net_timeout);
4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630
 
#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

4631 4632 4633 4634
  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);

4635
  while (!(slave_was_killed = io_slave_killed(thd,mi)) &&
4636 4637 4638
	 (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
4639
  {
4640
    /* Don't repeat last error */
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
4641
    if ((int)mysql_errno(mysql) != last_errno)
4642
    {
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
4643
      last_errno=mysql_errno(mysql);
4644
      suppress_warnings= 0;
4645
      sql_print_error("Slave I/O thread: error %s to master \
4646
'%s@%s:%d': \
4647
Error: '%s'  errno: %d  retry-time: %d  retries: %lu",
4648
		      (reconnect ? "reconnecting" : "connecting"),
4649
		      mi->user,mi->host,mi->port,
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
4650
		      mysql_error(mysql), last_errno,
4651 4652
		      mi->connect_retry,
		      master_retry_count);
4653
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4654 4655 4656
    /*
      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
4657
      do not want to have election triggered on the first failure to
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4658
      connect
4659
    */
4660
    if (++err_count == master_retry_count)
4661 4662
    {
      slave_was_killed=1;
sasha@mysql.sashanet.com's avatar
cleanup  
sasha@mysql.sashanet.com committed
4663 4664
      if (reconnect)
        change_rpl_status(RPL_ACTIVE_SLAVE,RPL_LOST_SOLDIER);
4665 4666
      break;
    }
4667 4668
    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
4669
  }
4670

4671 4672
  if (!slave_was_killed)
  {
sasha@mysql.sashanet.com's avatar
cleanup  
sasha@mysql.sashanet.com committed
4673
    if (reconnect)
4674
    { 
4675
      if (!suppress_warnings && global_system_variables.log_warnings)
4676
	sql_print_information("Slave: connected to master '%s@%s:%d',\
4677
replication resumed in log '%s' at position %s", mi->user,
4678 4679 4680 4681
			mi->host, mi->port,
			IO_RPL_LOG_NAME,
			llstr(mi->master_log_pos,llbuff));
    }
sasha@mysql.sashanet.com's avatar
cleanup  
sasha@mysql.sashanet.com committed
4682 4683 4684 4685
    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
4686
		      mi->user, mi->host, mi->port);
sasha@mysql.sashanet.com's avatar
cleanup  
sasha@mysql.sashanet.com committed
4687
    }
4688
#ifdef SIGNAL_WITH_VIO_CLOSE
4689
    thd->set_active_vio(mysql->net.vio);
4690
#endif      
4691
  }
4692
  mysql->reconnect= 1;
4693 4694
  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
4695 4696
}

4697

sasha@mysql.sashanet.com's avatar
cleanup  
sasha@mysql.sashanet.com committed
4698
/*
4699
  safe_reconnect()
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4700

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4701 4702 4703
  IMPLEMENTATION
    Try to connect until successful or slave killed or we have retried
    master_retry_count times
sasha@mysql.sashanet.com's avatar
cleanup  
sasha@mysql.sashanet.com committed
4704 4705
*/

4706 4707
static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
			  bool suppress_warnings)
sasha@mysql.sashanet.com's avatar
cleanup  
sasha@mysql.sashanet.com committed
4708
{
4709 4710
  DBUG_ENTER("safe_reconnect");
  DBUG_RETURN(connect_to_master(thd, mysql, mi, 1, suppress_warnings));
sasha@mysql.sashanet.com's avatar
cleanup  
sasha@mysql.sashanet.com committed
4711 4712
}

4713

4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743
/*
  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)
4744
{
4745 4746 4747 4748
  bool error=0;
  IO_CACHE *file = &rli->info_file;
  char buff[FN_REFLEN*2+22*2+4], *pos;

4749
  my_b_seek(file, 0L);
4750
  pos=strmov(buff, rli->group_relay_log_name);
4751
  *pos++='\n';
4752
  pos=longlong2str(rli->group_relay_log_pos, pos, 10);
4753
  *pos++='\n';
4754
  pos=strmov(pos, rli->group_master_log_name);
4755
  *pos++='\n';
4756
  pos=longlong2str(rli->group_master_log_pos, pos, 10);
4757
  *pos='\n';
4758
  if (my_b_write(file, (byte*) buff, (ulong) (pos-buff)+1))
4759 4760 4761
    error=1;
  if (flush_io_cache(file))
    error=1;
4762
  /* Flushing the relay log is done by the slave I/O thread */
4763
  return error;
4764 4765
}

4766

4767
/*
4768
  Called when we notice that the current "hot" log got rotated under our feet.
4769 4770 4771
*/

static IO_CACHE *reopen_relay_log(RELAY_LOG_INFO *rli, const char **errmsg)
4772 4773 4774
{
  DBUG_ASSERT(rli->cur_log != &rli->cache_buf);
  DBUG_ASSERT(rli->cur_log_fd == -1);
4775 4776 4777
  DBUG_ENTER("reopen_relay_log");

  IO_CACHE *cur_log = rli->cur_log=&rli->cache_buf;
4778
  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
4779
				   errmsg)) <0)
4780
    DBUG_RETURN(0);
4781 4782 4783 4784 4785
  /*
    We want to start exactly where we was before:
    relay_log_pos	Current log pos
    pending		Number of bytes already processed from the event
  */
4786
  rli->event_relay_log_pos= max(rli->event_relay_log_pos, BIN_LOG_HEADER_SIZE);
4787
  my_b_seek(cur_log,rli->event_relay_log_pos);
4788
  DBUG_RETURN(cur_log);
4789 4790
}

4791

4792 4793 4794 4795
Log_event* next_event(RELAY_LOG_INFO* rli)
{
  Log_event* ev;
  IO_CACHE* cur_log = rli->cur_log;
4796
  pthread_mutex_t *log_lock = rli->relay_log.get_log_lock(); 
4797 4798
  const char* errmsg=0;
  THD* thd = rli->sql_thd;
4799
  
4800
  DBUG_ENTER("next_event");
4801 4802
  DBUG_ASSERT(thd != 0);

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4803 4804
  /*
    For most operations we need to protect rli members with data_lock,
4805 4806 4807 4808
    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
4809
  */
4810
  safe_mutex_assert_owner(&rli->data_lock);
4811
  
4812
  while (!sql_slave_killed(thd,rli))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4813 4814 4815
  {
    /*
      We can have two kinds of log reading:
4816 4817 4818 4819 4820 4821 4822 4823
      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
4824
    */
4825 4826 4827 4828 4829
    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
4830 4831

      /*
4832
	Reading xxx_file_id is safe because the log will only
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4833 4834
	be rotated when we hold relay_log.LOCK_log
      */
4835
      if (rli->relay_log.get_open_count() != rli->cur_log_old_open_count)
4836
      {
4837 4838 4839 4840
	// 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
4841
	  goto err;
4842
	hot_log=0;				// Using old binary log
4843 4844
      }
    }
4845 4846 4847 4848 4849 4850 4851
    /* 
      As there is no guarantee that the relay is open (for example, an I/O
      error during a write by the slave I/O thread may have closed it), we
      have to test it.
    */
    if (!my_b_inited(cur_log))
      goto err;
4852 4853
#ifndef DBUG_OFF
    {
4854
      /* This is an assertion which sometimes fails, let's try to track it */
4855
      char llbuf1[22], llbuf2[22];
4856
      DBUG_PRINT("info", ("my_b_tell(cur_log)=%s rli->event_relay_log_pos=%s",
4857
                          llstr(my_b_tell(cur_log),llbuf1),
4858 4859 4860
                          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);
4861 4862
    }
#endif
4863 4864
    /*
      Relay log is always in new format - if the master is 3.23, the
4865
      I/O thread will convert the format for us.
4866 4867
      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
4868 4869
      logs, which may even have been deleted. So we need to write this
      description event at the beginning of the relay log.
4870 4871
      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.
4872 4873
      But if the relay log is created by new_file(): then the solution is:
      MYSQL_LOG::open() will write the buffered description event.
4874
    */
4875 4876
    if ((ev=Log_event::read_log_event(cur_log,0,
                                      rli->relay_log.description_event_for_exec)))
4877

4878 4879
    {
      DBUG_ASSERT(thd==rli->sql_thd);
4880 4881 4882 4883 4884
      /*
        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);
4885 4886
      if (hot_log)
	pthread_mutex_unlock(log_lock);
4887
      DBUG_RETURN(ev);
4888 4889
    }
    DBUG_ASSERT(thd==rli->sql_thd);
4890
    if (opt_reckless_slave)			// For mysql-test
4891
      cur_log->error = 0;
4892
    if (cur_log->error < 0)
4893 4894
    {
      errmsg = "slave SQL thread aborted because of I/O error";
4895 4896
      if (hot_log)
	pthread_mutex_unlock(log_lock);
4897 4898
      goto err;
    }
4899 4900
    if (!cur_log->error) /* EOF */
    {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4901 4902 4903 4904 4905
      /*
	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
      */
4906 4907
      if (hot_log)
      {
4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922
        /*
          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;

4923 4924
	DBUG_ASSERT(rli->relay_log.get_open_count() ==
                    rli->cur_log_old_open_count);
4925 4926 4927 4928 4929 4930 4931

        if (rli->ign_master_log_name_end[0])
        {
          /* We generate and return a Rotate, to make our positions advance */
          DBUG_PRINT("info",("seeing an ignored end segment"));
          ev= new Rotate_log_event(thd, rli->ign_master_log_name_end,
                                   0, rli->ign_master_log_pos_end,
guilhem@mysql.com's avatar
guilhem@mysql.com committed
4932
                                   Rotate_log_event::DUP_NAME);
4933
          rli->ign_master_log_name_end[0]= 0;
4934
          pthread_mutex_unlock(log_lock);
4935 4936 4937 4938 4939 4940 4941 4942 4943 4944
          if (unlikely(!ev))
          {
            errmsg= "Slave SQL thread failed to create a Rotate event "
              "(out of memory?), SHOW SLAVE STATUS may be inaccurate";
            goto err;
          }
          ev->server_id= 0; // don't be ignored by slave SQL thread
          DBUG_RETURN(ev);
        }

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4945 4946 4947 4948
	/*
	  We can, and should release data_lock while we are waiting for
	  update. If we do not, show slave status will block
	*/
4949
	pthread_mutex_unlock(&rli->data_lock);
4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971

        /*
          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
4972 4973
          be stopped, and the SQL thread sets ignore_log_space_limit to 0 when
          it stops.
4974 4975 4976 4977
        */
        pthread_mutex_lock(&rli->log_space_lock);
        // prevent the I/O thread from blocking next times
        rli->ignore_log_space_limit= 1; 
4978 4979 4980 4981 4982 4983
        /*
          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.
        */
4984
        pthread_mutex_unlock(&rli->log_space_lock);
4985
        pthread_cond_broadcast(&rli->log_space_cond);
4986
        // Note that wait_for_update unlocks lock_log !
4987
        rli->relay_log.wait_for_update(rli->sql_thd, 1);
4988 4989
        // re-acquire data lock since we released it earlier
        pthread_mutex_lock(&rli->data_lock);
4990
        rli->last_master_timestamp= save_timestamp;
4991 4992
	continue;
      }
4993 4994 4995 4996 4997 4998 4999 5000 5001 5002
      /*
	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;
	
5003
      if (relay_log_purge)
5004
      {
5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019
	/*
          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)))
5020
	{
5021
	  errmsg = "Error purging processed logs";
5022 5023 5024
	  goto err;
	}
      }
5025 5026
      else
      {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
5027
	/*
5028 5029 5030 5031 5032
	  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
5033
	*/
5034
	if (rli->relay_log.find_next_log(&rli->linfo, !hot_log))
5035
	{
5036 5037
	  errmsg = "error switching to the next log";
	  goto err;
5038
	}
5039 5040 5041
	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);
5042 5043
	flush_relay_log_info(rli);
      }
5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057

      /*
        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);
5058 5059
      if (rli->relay_log.is_active(rli->linfo.log_file_name))
      {
5060
#ifdef EXTRA_DEBUG
monty@mysql.com's avatar
monty@mysql.com committed
5061
	if (global_system_variables.log_warnings)
5062 5063
	  sql_print_information("next log '%s' is currently active",
                                rli->linfo.log_file_name);
5064
#endif	  
5065 5066 5067
	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);
5068
	  
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
5069
	/*
5070
	  Read pointer has to be at the start since we are the only
5071 5072 5073 5074
	  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
5075
	*/
5076
	if (check_binlog_magic(cur_log,&errmsg))
5077 5078
        {
          if (!hot_log) pthread_mutex_unlock(log_lock);
5079
	  goto err;
5080 5081
        }
        if (!hot_log) pthread_mutex_unlock(log_lock);
5082
	continue;
5083
      }
5084
      if (!hot_log) pthread_mutex_unlock(log_lock);
5085
      /*
5086 5087 5088
	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.
5089 5090
      */
#ifdef EXTRA_DEBUG
monty@mysql.com's avatar
monty@mysql.com committed
5091
      if (global_system_variables.log_warnings)
5092 5093
	sql_print_information("next log '%s' is not active",
                              rli->linfo.log_file_name);
5094 5095 5096 5097 5098
#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;
5099
    }
5100
    else
5101
    {
5102 5103 5104 5105 5106 5107
      /*
	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);
5108
      sql_print_error("Slave SQL thread: I/O error reading \
5109
event(errno: %d  cur_log->error: %d)",
5110
		      my_errno,cur_log->error);
5111
      // set read position to the beginning of the event
5112
      my_b_seek(cur_log,rli->event_relay_log_pos);
5113 5114
      /* otherwise, we have had a partial read */
      errmsg = "Aborting slave SQL thread because of partial event read";
5115
      break;					// To end of function
5116 5117
    }
  }
5118
  if (!errmsg && global_system_variables.log_warnings)
5119 5120 5121 5122 5123
  {
    sql_print_information("Error reading relay log event: %s", 
                          "slave SQL thread was killed");
    DBUG_RETURN(0);
  }
5124

5125
err:
5126 5127
  if (errmsg)
    sql_print_error("Error reading relay log event: %s", errmsg);
5128
  DBUG_RETURN(0);
5129 5130
}

5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141
/*
  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
5142

5143 5144 5145
  /* 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
5146 5147 5148 5149
  /* 
     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).
  */
5150 5151
  if (!rli->inited)
  {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
5152
    DBUG_PRINT("info", ("rli->inited == 0"));
guilhem@mysql.com's avatar
guilhem@mysql.com committed
5153
    goto end;
5154
  }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
5155

5156 5157
  /* 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
5158

5159 5160 5161 5162
  /*
    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
5163 5164 5165 5166 5167 5168
    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.
5169 5170 5171 5172
    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
5173
end:
5174
  pthread_mutex_unlock(&mi->run_lock);
5175 5176 5177
  DBUG_VOID_RETURN;
}

sasha@mysql.sashanet.com's avatar
cleanup  
sasha@mysql.sashanet.com committed
5178

5179
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5180
template class I_List_iterator<i_string>;
sasha@mysql.sashanet.com's avatar
sasha@mysql.sashanet.com committed
5181
template class I_List_iterator<i_string_pair>;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5182
#endif
5183

5184

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