Commit 7ff27a61 authored by unknown's avatar unknown
Browse files

Fix for BUG#13023: "SQL Thread is up but doesn't move forward". Details in slave.cc;

in short we now record whenever the slave I/O thread ignores a master's event because of its server id,
and use this info in the slave SQL thread to advance Exec_master_log_pos. Because if we
do not, this variable stays at the position of the last executed event, i.e. the last *non-ignored*
executed one, which may not be the last of the master's binlog (and so the slave *looks* behind
the master though it's data-wise it's not).


mysql-test/t/rpl_dual_pos_advance-master.opt:
  empty; its goal is just to trigger a server restart after running the test,
  so that the master forgets that it was a slave (otherwise it affects the following tests).
sql/log.cc:
  No more default arguments for Rotate_log_event constructor.
  MYSQL_LOG::appendv() is now called without mutex.
sql/log_event.cc:
  Moving one Rotate_log_event constructor from log_event.h. Support for on-demand choice of
  duplicating the string argument of the constructor or not (because there now are needs for both
  alternatives, see slave.cc).
sql/log_event.h:
  We now have a case where a Rotate_log_event is executed by the slave SQL thread while
  not being in the relay log, so it needs to pretend its length is 0: a ZERO_LEN flag for that;
  a flag DUP_NAME (replaces "bool alloced") to be able to choose if we want the constructor
  to duplicate the string argument or not.
sql/slave.cc:
  A comment for BUG#13861 (to be fixed). llstr() instead of %ld as the number is ulonglong.
  mi->rli becomes rli in some places.
  Fix for BUG#13023:
  - in the slave I/O thread, whenever we ignore an event because of its server id we update
  a couple of coordinates in memory
  - in the slave SQL thread, whenever we bump into the end of the latest relay log, we check
  this couple of coordinates to see if we should advance our Exec_master_log_pos.
  - when the slave I/O thread terminates it saves these in-memory coordinates into a Rotate event
  in the relay log, so that they are durable.
sql/slave.h:
  A couple of coordinates in RELAY_LOG_INFO to keep track of the last ignored events received
  by the slave I/O thread (ignored because of the server id).
mysql-test/r/rpl_dual_pos_advance.result:
  New BitKeeper file ``mysql-test/r/rpl_dual_pos_advance.result''
mysql-test/t/rpl_dual_pos_advance.test:
  Test for BUG#13023 (with a part, disabled, to test BUG#13861 when I fix it).
  Before the fix, this test used to hang.
parent e0c38d58
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
reset master;
change master to master_host="127.0.0.1",master_port=SLAVE_PORT,master_user="root";
start slave;
create table t1 (n int);
create table t4 (n int);
create table t5 (n int);
create table t6 (n int);
show tables;
Tables_in_test
t1
t4
t5
t6
stop slave;
reset slave;
drop table t1,t4,t5,t6;
+0 −0

Empty file added.

+108 −0
Original line number Diff line number Diff line
# This test checks that in a dual-head setup
# A->B->A, where A has --log-slave-updates (why would it?
# assume that there is a C as slave of A),
# then the Exec_master_log_pos of SHOW SLAVE STATUS does
# not stay too low on B(BUG#13023 due to events ignored because
# of their server id).
# It also will test BUG#13861.

source include/master-slave.inc;


# set up "dual head"

connection slave;
reset master;

connection master;
--replace_result $SLAVE_MYPORT SLAVE_PORT
eval change master to master_host="127.0.0.1",master_port=$SLAVE_MYPORT,master_user="root";

start slave;

# now we test it

connection slave;

create table t1 (n int);

save_master_pos;
connection master;
sync_with_master;

# Now test BUG#13861. This will be enabled when Guilhem fixes this
# bug.

# stop slave

# create table t2 (n int); # create one ignored event

# save_master_pos;
# connection slave;
# sync_with_master;

# connection slave;

# show tables;

# save_master_pos;

# create table t3 (n int);

# connection master;

# bug is that START SLAVE UNTIL may stop too late, we test that by
# asking it to stop before creation of t3.

# start slave until master_log_file="slave-bin.000001",master_log_pos=195;

# wait until it's started (the position below is the start of "CREATE
# TABLE t2") (otherwise wait_for_slave_to_stop may return at once)

# select master_pos_wait("slave-bin.000001",137);

# wait_for_slave_to_stop;

# then BUG#13861 causes t3 to show up below (because stopped too
# late).

# show tables;

# start slave;

# BUG#13023 is that Exec_master_log_pos may stay too low "forever":

connection master;

create table t4 (n int); # create 3 ignored events
create table t5 (n int);
create table t6 (n int);

save_master_pos;
connection slave;
sync_with_master;

connection slave;

save_master_pos;

connection master;

# then BUG#13023 caused hang below ("master" looks behind, while it's
# not in terms of updates done).

sync_with_master;

show tables;

# cleanup

stop slave;
reset slave;
drop table t1,t4,t5,t6; # add t2 and t3 later

save_master_pos;
connection slave;
sync_with_master;

# End of 4.1 tests
+3 −3
Original line number Diff line number Diff line
@@ -1028,7 +1028,8 @@ void MYSQL_LOG::new_file(bool need_lock)
        to change base names at some point.
      */
      THD *thd = current_thd; /* may be 0 if we are reacting to SIGHUP */
      Rotate_log_event r(thd,new_name+dirname_length(new_name));
      Rotate_log_event r(thd,new_name+dirname_length(new_name),
                         0, LOG_EVENT_OFFSET, 0);
      r.set_log_pos(this);
      r.write(&log_file);
      bytes_written += r.get_event_len();
@@ -1106,7 +1107,7 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...)
  
  DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
  
  pthread_mutex_lock(&LOCK_log);
  safe_mutex_assert_owner(&LOCK_log);
  do
  {
    if (my_b_append(&log_file,(byte*) buf,len))
@@ -1125,7 +1126,6 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...)
  }

err:
  pthread_mutex_unlock(&LOCK_log);
  if (!error)
    signal_update();
  DBUG_RETURN(error);
+33 −9
Original line number Diff line number Diff line
@@ -2013,18 +2013,44 @@ void Rotate_log_event::print(FILE* file, bool short_form, char* last_db)
#endif /* MYSQL_CLIENT */



/*
  Rotate_log_event::Rotate_log_event()
  Rotate_log_event::Rotate_log_event() (2 constructors)
*/


#ifndef MYSQL_CLIENT
Rotate_log_event::Rotate_log_event(THD* thd_arg,
                                   const char* new_log_ident_arg,
                                   uint ident_len_arg, ulonglong pos_arg,
                                   uint flags_arg)
  :Log_event(), new_log_ident(new_log_ident_arg),
   pos(pos_arg),ident_len(ident_len_arg ? ident_len_arg :
                          (uint) strlen(new_log_ident_arg)), flags(flags_arg)
{
#ifndef DBUG_OFF
  char buff[22];
  DBUG_ENTER("Rotate_log_event::Rotate_log_event(THD*,...)");
  DBUG_PRINT("enter",("new_log_ident %s pos %s flags %lu", new_log_ident_arg,
                      llstr(pos_arg, buff), flags));
#endif
  if (flags & DUP_NAME)
    new_log_ident= my_strdup_with_length(new_log_ident_arg,
                                         ident_len,
                                         MYF(MY_WME));
  DBUG_VOID_RETURN;
}
#endif


Rotate_log_event::Rotate_log_event(const char* buf, int event_len,
				   bool old_format)
  :Log_event(buf, old_format),new_log_ident(NULL),alloced(0)
  :Log_event(buf, old_format), new_log_ident(0), flags(DUP_NAME)
{
  // The caller will ensure that event_len is what we have at EVENT_LEN_OFFSET
  int header_size = (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
  uint ident_offset;
  DBUG_ENTER("Rotate_log_event");
  DBUG_ENTER("Rotate_log_event::Rotate_log_event(char*,...)");

  if (event_len < header_size)
    DBUG_VOID_RETURN;
@@ -2043,12 +2069,9 @@ Rotate_log_event::Rotate_log_event(const char* buf, int event_len,
    ident_offset = ROTATE_HEADER_LEN;
  }
  set_if_smaller(ident_len,FN_REFLEN-1);
  if (!(new_log_ident= my_strdup_with_length((byte*) buf +
					     ident_offset,
  new_log_ident= my_strdup_with_length((byte*) buf + ident_offset,
                                       (uint) ident_len,
					     MYF(MY_WME))))
    DBUG_VOID_RETURN;
  alloced = 1;
                                       MYF(MY_WME));
  DBUG_VOID_RETURN;
}

@@ -2060,6 +2083,7 @@ Rotate_log_event::Rotate_log_event(const char* buf, int event_len,
int Rotate_log_event::write_data(IO_CACHE* file)
{
  char buf[ROTATE_HEADER_LEN];
  DBUG_ASSERT(!(flags & ZERO_LEN)); // such an event cannot be written
  int8store(buf + R_POS_OFFSET, pos);
  return (my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) ||
	  my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len));
Loading