Commit c6255402 authored by sasha@mysql.sashanet.com's avatar sasha@mysql.sashanet.com

Merge work.mysql.com:/home/bk/mysql

into mysql.sashanet.com:/home/sasha/src/bk/mysql
parents f4df5cd2 46400961
...@@ -278,6 +278,7 @@ start_master() ...@@ -278,6 +278,7 @@ start_master()
start_slave() start_slave()
{ {
[ x$SKIP_SLAVE = x1 ] && return
[ -d $GCOV_SLAVE_SRC ] && cd $GCOV_SLAVE_SRC [ -d $GCOV_SLAVE_SRC ] && cd $GCOV_SLAVE_SRC
slave_args="--no-defaults --server-id=2 \ slave_args="--no-defaults --server-id=2 \
--master-user=root \ --master-user=root \
...@@ -362,7 +363,7 @@ run_testcase () ...@@ -362,7 +363,7 @@ run_testcase ()
tname=`$ECHO $tname | $CUT -d . -f 1` tname=`$ECHO $tname | $CUT -d . -f 1`
master_opt_file=$TESTDIR/$tname-master.opt master_opt_file=$TESTDIR/$tname-master.opt
slave_opt_file=$TESTDIR/$tname-slave.opt slave_opt_file=$TESTDIR/$tname-slave.opt
SKIP_SLAVE=`$EXPR \( match $tname rpl \) = 0`
if [ -f $master_opt_file ] ; if [ -f $master_opt_file ] ;
then then
...@@ -443,7 +444,9 @@ run_testcase () ...@@ -443,7 +444,9 @@ run_testcase ()
mysql_install_db mysql_install_db
if [ -z $DO_GDB ] #do not automagically start deamons if we are in gdb or running only one test
#case
if [ -z $DO_GDB ] && [ -z $1 ]
then then
$SETCOLOR_NORMAL && $ECHO -n "Starting mysqld for Testing" $SETCOLOR_NORMAL && $ECHO -n "Starting mysqld for Testing"
mysql_start mysql_start
......
use test;
drop table if exists x;
create table x (n int);
insert into x values(9),(3),(12),(10);
alter table x order by n;
@r/3.23/alt000001.result select * from x;
--disconnect-slave-event-count=1
#this tests the offset off by 22 mystery bug
#must run slave with --disconnect-slave-event-count=1 --master-connect-retry=1
source t/include/master-slave.inc;
connection slave;
drop table if exists foo;
connection master;
drop table if exists foo;
create table foo (n int not null auto_increment primary key);
insert into foo values(NULL);
insert into foo values(2);
connection slave;
sleep 5;
@r/3.23/rpl000010.result select n from foo;
...@@ -81,7 +81,8 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet, ...@@ -81,7 +81,8 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
// if the read hits eof, we must report it as eof // if the read hits eof, we must report it as eof
// so the caller will know it can go into cond_wait to be woken up // so the caller will know it can go into cond_wait to be woken up
// on the next update to the log // on the next update to the log
return file->error >= 0 ? LOG_READ_EOF: LOG_READ_IO; if(!file->error) return LOG_READ_EOF;
return file->error > 0 ? LOG_READ_TRUNC: LOG_READ_IO;
} }
data_len = uint4korr(buf + EVENT_LEN_OFFSET); data_len = uint4korr(buf + EVENT_LEN_OFFSET);
if (data_len < LOG_EVENT_HEADER_LEN || data_len > MAX_EVENT_LEN) if (data_len < LOG_EVENT_HEADER_LEN || data_len > MAX_EVENT_LEN)
......
...@@ -361,6 +361,8 @@ static void dump_local_log_entries(const char* logname) ...@@ -361,6 +361,8 @@ static void dump_local_log_entries(const char* logname)
die("Could not read entry at offset %ld : Error in log format or \ die("Could not read entry at offset %ld : Error in log format or \
read error", read error",
my_b_tell(file)); my_b_tell(file));
else
die("Could not construct event object");
break; break;
} }
if (rec_count >= offset) if (rec_count >= offset)
......
...@@ -2231,7 +2231,8 @@ enum options { ...@@ -2231,7 +2231,8 @@ enum options {
OPT_REPLICATE_REWRITE_DB, OPT_SERVER_ID, OPT_SKIP_SLAVE_START, OPT_REPLICATE_REWRITE_DB, OPT_SERVER_ID, OPT_SKIP_SLAVE_START,
OPT_SKIP_INNOBASE,OPT_SAFEMALLOC_MEM_LIMIT, OPT_SKIP_INNOBASE,OPT_SAFEMALLOC_MEM_LIMIT,
OPT_REPLICATE_DO_TABLE, OPT_REPLICATE_IGNORE_TABLE, OPT_REPLICATE_DO_TABLE, OPT_REPLICATE_IGNORE_TABLE,
OPT_REPLICATE_WILD_DO_TABLE, OPT_REPLICATE_WILD_IGNORE_TABLE OPT_REPLICATE_WILD_DO_TABLE, OPT_REPLICATE_WILD_IGNORE_TABLE,
OPT_DISCONNECT_SLAVE_EVENT_COUNT
}; };
static struct option long_options[] = { static struct option long_options[] = {
...@@ -2287,6 +2288,10 @@ static struct option long_options[] = { ...@@ -2287,6 +2288,10 @@ static struct option long_options[] = {
{"master-info-file", required_argument, 0, (int) OPT_MASTER_INFO_FILE}, {"master-info-file", required_argument, 0, (int) OPT_MASTER_INFO_FILE},
{"myisam-recover", optional_argument, 0, (int) OPT_MYISAM_RECOVER}, {"myisam-recover", optional_argument, 0, (int) OPT_MYISAM_RECOVER},
{"memlock", no_argument, 0, (int) OPT_MEMLOCK}, {"memlock", no_argument, 0, (int) OPT_MEMLOCK},
// needs to be available for the test case to pass in non-debugging mode
// is a no-op
{"disconnect-slave-event-count", required_argument, 0,
(int) OPT_DISCONNECT_SLAVE_EVENT_COUNT},
#if !defined(DBUG_OFF) && defined(SAFEMALLOC) #if !defined(DBUG_OFF) && defined(SAFEMALLOC)
{"safemalloc-mem-limit", required_argument, 0, (int) {"safemalloc-mem-limit", required_argument, 0, (int)
OPT_SAFEMALLOC_MEM_LIMIT}, OPT_SAFEMALLOC_MEM_LIMIT},
...@@ -2888,6 +2893,12 @@ static void get_options(int argc,char **argv) ...@@ -2888,6 +2893,12 @@ static void get_options(int argc,char **argv)
if (optarg && optarg[0]) if (optarg && optarg[0])
opt_bin_logname=my_strdup(optarg,MYF(0)); opt_bin_logname=my_strdup(optarg,MYF(0));
break; break;
// needs to be handled (as no-op) in non-debugging mode for test suite
case (int)OPT_DISCONNECT_SLAVE_EVENT_COUNT:
#ifndef DBUG_OFF
disconnect_slave_event_count = atoi(optarg);
#endif
break;
case (int) OPT_LOG_SLAVE_UPDATES: case (int) OPT_LOG_SLAVE_UPDATES:
opt_log_slave_updates = 1; opt_log_slave_updates = 1;
break; break;
......
...@@ -30,7 +30,11 @@ DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table; ...@@ -30,7 +30,11 @@ DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table;
bool do_table_inited = 0, ignore_table_inited = 0; bool do_table_inited = 0, ignore_table_inited = 0;
bool wild_do_table_inited = 0, wild_ignore_table_inited = 0; bool wild_do_table_inited = 0, wild_ignore_table_inited = 0;
bool table_rules_on = 0; bool table_rules_on = 0;
#ifndef DBUG_OFF
int disconnect_slave_event_count = 0;
static int events_till_disconnect = -1;
static int stuck_count = 0;
#endif
static inline void skip_load_data_infile(NET* net); static inline void skip_load_data_infile(NET* net);
...@@ -668,6 +672,11 @@ static uint read_event(MYSQL* mysql, MASTER_INFO *mi) ...@@ -668,6 +672,11 @@ static uint read_event(MYSQL* mysql, MASTER_INFO *mi)
// being in the interrupted state :-) // being in the interrupted state :-)
// my_real_read() will time us out // my_real_read() will time us out
// we check if we were told to die, and if not, try reading again // we check if we were told to die, and if not, try reading again
#ifndef DBUG_OFF
if(disconnect_slave_event_count && !(events_till_disconnect--))
return packet_error;
#endif
while (!abort_loop && !abort_slave && len == packet_error && read_errno == EINTR ) while (!abort_loop && !abort_slave && len == packet_error && read_errno == EINTR )
{ {
len = mc_net_safe_read(mysql); len = mc_net_safe_read(mysql);
...@@ -970,6 +979,8 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused))) ...@@ -970,6 +979,8 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused)))
pthread_mutex_unlock(&LOCK_slave); pthread_mutex_unlock(&LOCK_slave);
int error = 1; int error = 1;
bool retried_once = 0;
ulonglong last_failed_pos = 0;
my_thread_init(); // needs to be up here, otherwise we get a coredump my_thread_init(); // needs to be up here, otherwise we get a coredump
// trying to use DBUG_ stuff // trying to use DBUG_ stuff
...@@ -1008,13 +1019,21 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused))) ...@@ -1008,13 +1019,21 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused)))
thd->proc_info = "waiting to reconnect after a failed dump request"; thd->proc_info = "waiting to reconnect after a failed dump request";
if(mysql->net.vio) if(mysql->net.vio)
vio_close(mysql->net.vio); vio_close(mysql->net.vio);
safe_sleep(thd, glob_mi.connect_retry); // 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
if(retried_once)
safe_sleep(thd, glob_mi.connect_retry);
else
retried_once = 1;
if(slave_killed(thd)) if(slave_killed(thd))
goto err; goto err;
thd->proc_info = "reconnecting after a failed dump request"; thd->proc_info = "reconnecting after a failed dump request";
sql_print_error("Slave: failed dump request, reconnecting to \
try again, master_log_pos=%ld", last_failed_pos = glob_mi.pos );
safe_reconnect(thd, mysql, &glob_mi); safe_reconnect(thd, mysql, &glob_mi);
if(slave_killed(thd)) if(slave_killed(thd))
goto err; goto err;
...@@ -1025,7 +1044,6 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused))) ...@@ -1025,7 +1044,6 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused)))
while(!slave_killed(thd)) while(!slave_killed(thd))
{ {
bool reset = 0;
thd->proc_info = "reading master update"; thd->proc_info = "reading master update";
uint event_len = read_event(mysql, &glob_mi); uint event_len = read_event(mysql, &glob_mi);
if(slave_killed(thd)) if(slave_killed(thd))
...@@ -1035,19 +1053,22 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused))) ...@@ -1035,19 +1053,22 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused)))
{ {
thd->proc_info = "waiting to reconnect after a failed read"; thd->proc_info = "waiting to reconnect after a failed read";
if(mysql->net.vio) if(mysql->net.vio)
vio_close(mysql->net.vio); vio_close(mysql->net.vio);
safe_sleep(thd, glob_mi.connect_retry); if(retried_once) // punish repeat offender with sleep
safe_sleep(thd, glob_mi.connect_retry);
else
retried_once = 1;
if(slave_killed(thd)) if(slave_killed(thd))
goto err; goto err;
thd->proc_info = "reconnecting after a failed read"; thd->proc_info = "reconnecting after a failed read";
sql_print_error("Slave: Failed reading log event, \
reconnecting to retry, master_log_pos=%ld", last_failed_pos = glob_mi.pos);
safe_reconnect(thd, mysql, &glob_mi); safe_reconnect(thd, mysql, &glob_mi);
if(slave_killed(thd)) if(slave_killed(thd))
goto err; goto err;
reset = 1;
}
if(reset)
break; break;
}
thd->proc_info = "processing master log event"; thd->proc_info = "processing master log event";
if(exec_event(thd, &mysql->net, &glob_mi, event_len)) if(exec_event(thd, &mysql->net, &glob_mi, event_len))
...@@ -1059,6 +1080,28 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused))) ...@@ -1059,6 +1080,28 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused)))
// abort the slave thread, when the problem is fixed, the user // abort the slave thread, when the problem is fixed, the user
// should restart the slave with mysqladmin start-slave // should restart the slave with mysqladmin start-slave
} }
// successful exec with offset advance,
// the slave repents and his sins are forgiven!
if(glob_mi.pos > last_failed_pos)
{
retried_once = 0;
#ifndef DBUG_OFF
stuck_count = 0;
#endif
}
#ifndef DBUG_OFF
else
{
stuck_count++;
// show a little mercy, allow slave to read one more event
// before cutting him off - otherwise he gets stuck
// on Invar events, since they do not advance the offset
// immediately
if(stuck_count > 2)
events_till_disconnect++;
}
#endif
} }
} }
...@@ -1086,6 +1129,9 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused))) ...@@ -1086,6 +1129,9 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused)))
static void safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi) static void safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
// will try to connect until successful // will try to connect until successful
{ {
#ifndef DBUG_OFF
events_till_disconnect = disconnect_slave_event_count;
#endif
while(!slave_killed(thd) && while(!slave_killed(thd) &&
!mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0, !mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0,
mi->port, 0, 0)) mi->port, 0, 0))
...@@ -1107,12 +1153,15 @@ static void safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi) ...@@ -1107,12 +1153,15 @@ static void safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
{ {
mi->pending = 0; // if we lost connection after reading a state set event mi->pending = 0; // if we lost connection after reading a state set event
// we will be re-reading it, so pending needs to be cleared // we will be re-reading it, so pending needs to be cleared
#ifndef DBUG_OFF
events_till_disconnect = disconnect_slave_event_count;
#endif
while(!slave_killed(thd) && mc_mysql_reconnect(mysql)) while(!slave_killed(thd) && mc_mysql_reconnect(mysql))
{ {
sql_print_error( sql_print_error("Slave thread: error connecting to master:\
"Slave thread: error connecting to master:%s, retry in %d sec", %s, retry in %d sec",
mc_mysql_error(mysql), mi->connect_retry); mc_mysql_error(mysql), mi->connect_retry);
safe_sleep(thd, mi->connect_retry); safe_sleep(thd, mi->connect_retry);
} }
} }
......
...@@ -94,6 +94,10 @@ extern bool do_table_inited, ignore_table_inited, ...@@ -94,6 +94,10 @@ extern bool do_table_inited, ignore_table_inited,
wild_do_table_inited, wild_ignore_table_inited; wild_do_table_inited, wild_ignore_table_inited;
extern bool table_rules_on; extern bool table_rules_on;
#ifndef DBUG_OFF
extern int disconnect_slave_event_count ;
#endif
// the master variables are defaults read from my.cnf or command line // the master variables are defaults read from my.cnf or command line
extern uint master_port, master_connect_retry; extern uint master_port, master_connect_retry;
extern my_string master_user, master_password, master_host, extern my_string master_user, master_password, master_host,
......
...@@ -309,6 +309,9 @@ sweepstakes if you report the bug"; ...@@ -309,6 +309,9 @@ sweepstakes if you report the bug";
case LOG_READ_TRUNC: case LOG_READ_TRUNC:
errmsg = "binlog truncated in the middle of event"; errmsg = "binlog truncated in the middle of event";
break; break;
default:
errmsg = "unknown error reading log event on the master";
break;
} }
goto err; goto err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment