From 4ac091636b0f366282a8a1c2ad2ff448a5c4a6f8 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 17 Jan 2001 05:47:33 -0700 Subject: [PATCH 1/2] rpl000016.test sync rpl000001.result BitKeeper file /home/sasha/src/bk/mysql/mysql-test/r/rpl000001.result ignore Added BitKeeper/tmp/bkr3sAHD to the ignore list slave.h MASTER_POS_WAIT lex.h MASTER_POS_WAIT slave.cc MASTER_POS_WAIT, do automagic restart on debugging abort, skip rotate events in slave.cc debug abort count sql_repl.cc announce the log name at the start of the log with a fake rotate event item_create.h MASTER_POS_WAIT item_func.cc MASTER_POS_WAIT item_func.h MASTER_POS_WAIT sql_class.h enter_cond(), exit_cond() helper inliners item_create.cc added MASTER_POS_WAIT mysql-test-run.sh speed improvement fixes rpl000007.test sync rpl000003.test sleep -> sync rpl000004.test sleep -> sync, fixed clean up bug rpl000014.test sync rpl000009.test sync rpl000013.test sync rpl000001.test sleep -> sync rpl000008.test sync rpl000006.test sync on cleanup rpl000011.test sync rpl000012.test sync rpl000005.test sleep -> sync rpl000010.test sync rpl000015.test sync rpl000002.test sleep -> sync rpl000014.result we now know the master log name as soon as we connect mysql.cc added optional agrument to --wait mysqltest.c added save_master_pos and sync_with_master commands client/mysql.cc: added optional agrument to --wait client/mysqltest.c: added save_master_pos and sync_with_master commands mysql-test/mysql-test-run.sh: speed improvement fixes mysql-test/r/rpl000014.result: we now know the master log name as soon as we connect mysql-test/t/rpl000001.test: sleep -> sync mysql-test/t/rpl000002.test: sleep -> sync mysql-test/t/rpl000003.test: sleep -> sync mysql-test/t/rpl000004.test: sleep -> sync, fixed clean up bug mysql-test/t/rpl000005.test: sleep -> sync mysql-test/t/rpl000006.test: sync on cleanup mysql-test/t/rpl000007.test: sync mysql-test/t/rpl000008.test: sync mysql-test/t/rpl000009.test: sync mysql-test/t/rpl000010.test: sync mysql-test/t/rpl000011.test: sync mysql-test/t/rpl000012.test: sync mysql-test/t/rpl000013.test: sync mysql-test/t/rpl000014.test: sync mysql-test/t/rpl000015.test: sync BitKeeper/etc/ignore: Added BitKeeper/tmp/bkr3sAHD to the ignore list mysql-test/t/rpl000016.test: sync sql/item_create.cc: added MASTER_POS_WAIT sql/item_create.h: MASTER_POS_WAIT sql/item_func.cc: MASTER_POS_WAIT sql/item_func.h: MASTER_POS_WAIT sql/lex.h: MASTER_POS_WAIT sql/slave.cc: MASTER_POS_WAIT, do automagic restart on debugging abort, skip rotate events in debug abort count sql/slave.h: MASTER_POS_WAIT sql/sql_class.h: enter_cond(), exit_cond() helper inliners sql/sql_repl.cc: announce the log name at the start of the log with a fake rotate event --- .bzrignore | 1 + client/mysql.cc | 12 ++++-- client/mysqltest.c | 60 ++++++++++++++++++++++++++++- mysql-test/mysql-test-run.sh | 16 ++++++-- mysql-test/r/rpl000001.result | 5 +++ mysql-test/r/rpl000014.result | 8 ++-- mysql-test/t/rpl000001.test | 11 ++++-- mysql-test/t/rpl000002.test | 7 +++- mysql-test/t/rpl000003.test | 7 +++- mysql-test/t/rpl000004.test | 7 ++++ mysql-test/t/rpl000005.test | 6 ++- mysql-test/t/rpl000006.test | 3 ++ mysql-test/t/rpl000007.test | 6 ++- mysql-test/t/rpl000008.test | 7 +++- mysql-test/t/rpl000009.test | 11 +++++- mysql-test/t/rpl000010.test | 6 ++- mysql-test/t/rpl000011.test | 9 ++++- mysql-test/t/rpl000012.test | 9 ++++- mysql-test/t/rpl000013.test | 20 +++++----- mysql-test/t/rpl000014.test | 10 +++-- mysql-test/t/rpl000015.test | 7 +++- mysql-test/t/rpl000016.test | 9 +++-- sql/item_create.cc | 5 +++ sql/item_create.h | 1 + sql/item_func.cc | 23 +++++++++++ sql/item_func.h | 12 ++++++ sql/lex.h | 2 + sql/slave.cc | 58 +++++++++++++++++++++++++++- sql/slave.h | 6 +++ sql/sql_class.h | 19 +++++++++ sql/sql_repl.cc | 72 ++++++++++++++++++++++------------- 31 files changed, 361 insertions(+), 74 deletions(-) create mode 100644 mysql-test/r/rpl000001.result diff --git a/.bzrignore b/.bzrignore index 9b2e3387390..8fac7c488a0 100644 --- a/.bzrignore +++ b/.bzrignore @@ -188,3 +188,4 @@ Docs/my_sys.doc tmp/* extra/resolve_stack_dump sql/share/*.sys +BitKeeper/tmp/bkr3sAHD diff --git a/client/mysql.cc b/client/mysql.cc index edc2f7903df..695d11d039c 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -125,6 +125,7 @@ static char *current_host,*current_db,*current_user=0,*opt_password=0, *default_charset; static char *histfile; static String glob_buffer,old_buffer; +static int wait_time = 5; static STATUS status; static ulong select_limit,max_join_size,opt_connect_timeout=0; static char default_pager[FN_REFLEN]; @@ -427,7 +428,7 @@ static struct option long_options[] = {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"vertical", no_argument, 0, 'E'}, - {"wait", no_argument, 0, 'w'}, + {"wait", optional_argument, 0, 'w'}, {0, 0, 0, 0} }; @@ -560,7 +561,7 @@ static int get_options(int argc, char **argv) set_all_changeable_vars(changeable_vars); while ((c=getopt_long(argc,argv, - "?ABCD:LfgGHinNoqrstTU::vVwWEe:h:O:P:S:u:#::p::", + "?ABCD:LfgGHinNoqrstTU::vVw::WEe:h:O:P:S:u:#::p::", long_options, &option_index)) != EOF) { switch(c) { @@ -664,7 +665,10 @@ static int get_options(int argc, char **argv) case 'n': unbuffered=1; break; case 'v': verbose++; break; case 'E': vertical=1; break; - case 'w': wait_flag=1; break; + case 'w': + wait_flag=1; + if(optarg) wait_time = atoi(optarg) ; + break; case 'A': no_rehash=1; break; case 'G': no_named_cmds=0; break; case 'g': no_named_cmds=1; break; @@ -2114,7 +2118,7 @@ sql_connect(char *host,char *database,char *user,char *password,uint silent) message=1; tee_fputs("Waiting",stderr); (void) fflush(stderr); } - (void) sleep(5); + (void) sleep(wait_time); if (!silent) { putc('.',stderr); (void) fflush(stderr); diff --git a/client/mysqltest.c b/client/mysqltest.c index d2efead3413..e9fc6a07961 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -91,6 +91,12 @@ int *cur_block, *block_stack_end; DYNAMIC_ARRAY q_lines; +typedef struct +{ + char file[FN_REFLEN]; + ulong pos; +} MASTER_POS ; + struct connection { MYSQL mysql; @@ -104,6 +110,7 @@ typedef } PARSER; PARSER parser; +MASTER_POS master_pos; int block_ok = 1; /* set to 0 if the current block should not be executed */ int false_block_depth = 0; const char* result_file = 0; /* if set, all results are concated and @@ -137,13 +144,15 @@ struct st_query enum { Q_CONNECTION=1, Q_QUERY, Q_CONNECT, Q_SLEEP, Q_INC, Q_DEC,Q_SOURCE, Q_DISCONNECT,Q_LET, Q_ECHO, Q_WHILE, Q_END_BLOCK, - Q_SYSTEM, Q_RESULT, Q_REQUIRE, + Q_SYSTEM, Q_RESULT, Q_REQUIRE, Q_SAVE_MASTER_POS, + Q_SYNC_WITH_MASTER, Q_UNKNOWN, Q_COMMENT, Q_COMMENT_WITH_COMMAND} type; }; const char *command_names[] = { "connection", "query","connect","sleep","inc","dec","source","disconnect", -"let","echo","while","end","system","result", "require",0 +"let","echo","while","end","system","result", "require", "save_master_pos", + "sync_with_master", 0 }; TYPELIB command_typelib= {array_elements(command_names),"", @@ -471,6 +480,50 @@ int do_echo(struct st_query* q) return 0; } +int do_sync_with_master() +{ + MYSQL_RES* res; + MYSQL_ROW row; + MYSQL* mysql = &cur_con->mysql; + char query_buf[FN_REFLEN+128]; + sprintf(query_buf, "select master_pos_wait('%s', %ld)", master_pos.file, + master_pos.pos); + if(mysql_query(mysql, query_buf)) + die("At line %u: failed in %s: %d: %s", start_lineno, query_buf, + mysql_errno(mysql), mysql_error(mysql)); + + if(!(res = mysql_store_result(mysql))) + die("line %u: mysql_store_result() retuned NULL", start_lineno); + if(!(row = mysql_fetch_row(res))) + die("line %u: empty result in %s", start_lineno, query_buf); + if(!row[0]) + die("Error on slave while syncing with master"); + mysql_free_result(res); + + return 0; +} + +int do_save_master_pos() +{ + MYSQL_RES* res; + MYSQL_ROW row; + MYSQL* mysql = &cur_con->mysql; + if(mysql_query(mysql, "show master status")) + die("At line %u: failed in show master status: %d: %s", start_lineno, + mysql_errno(mysql), mysql_error(mysql)); + + if(!(res = mysql_store_result(mysql))) + die("line %u: mysql_store_result() retuned NULL", start_lineno); + if(!(row = mysql_fetch_row(res))) + die("line %u: empty result in show master status", start_lineno); + strncpy(master_pos.file, row[0], sizeof(master_pos.file)); + master_pos.pos = strtoul(row[1], (char**) 0, 10); + mysql_free_result(res); + + return 0; +} + + int do_let(struct st_query* q) { char* p=q->first_argument; @@ -1299,6 +1352,7 @@ int main(int argc, char** argv) cur_con = cons; memset(file_stack, 0, sizeof(file_stack)); + memset(&master_pos, 0, sizeof(master_pos)); file_stack_end = file_stack + MAX_INCLUDE_DEPTH; cur_file = file_stack; lineno = lineno_stack; @@ -1361,6 +1415,8 @@ int main(int argc, char** argv) get_file_name(save_file,q); require_file=1; break; + case Q_SAVE_MASTER_POS: do_save_master_pos(q); break; + case Q_SYNC_WITH_MASTER: do_sync_with_master(q); break; case Q_COMMENT: /* Ignore row */ case Q_COMMENT_WITH_COMMAND: default: processed = 0; break; diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 0af315e9774..9d7145fed49 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -192,11 +192,13 @@ if [ x$SOURCE_DIST = x1 ] ; then MYSQLD="$BASEDIR/sql/mysqld" MYSQL_TEST="$BASEDIR/client/mysqltest" MYSQLADMIN="$BASEDIR/client/mysqladmin" + MYSQL="$BASEDIR/client/mysql" INSTALL_DB="./install_test_db" else MYSQLD="$BASEDIR/bin/mysqld" MYSQL_TEST="$BASEDIR/bin/mysqltest" MYSQLADMIN="$BASEDIR/bin/mysqladmin" + MYSQL="$BASEDIR/bin/mysql" INSTALL_DB="./install_test_db -bin" fi @@ -230,6 +232,11 @@ SLAVE_MYSQLD=$MYSQLD #this can be changed later if we are doing gcov #++ # Function Definitions #-- +wait_for_server_start () + { + $MYSQL -e "select 1" --silent -w1 --host=127.0.0.1 --port=$1 \ + >/dev/null + } prompt_user () { @@ -320,6 +327,7 @@ gcov_collect () { $ECHO "gcov info in $GCOV_MSG, errors in $GCOV_ERR" } + start_master() { [ x$MASTER_RUNNING = 1 ] && return @@ -354,6 +362,7 @@ start_master() else $MYSQLD $master_args >> $MASTER_MYERR 2>&1 & fi + wait_for_server_start $MASTER_MYPORT MASTER_RUNNING=1 } @@ -399,6 +408,7 @@ start_slave() else $SLAVE_MYSQLD $slave_args >> $SLAVE_MYERR 2>&1 & fi + wait_for_server_start $SLAVE_MYPORT SLAVE_RUNNING=1 } @@ -407,7 +417,6 @@ mysql_start () { start_master start_slave cd $MYSQL_TEST_DIR - sleep $SLEEP_TIME # Give mysqld time to start properly return 1 } @@ -430,7 +439,6 @@ stop_slave () fi fi SLAVE_RUNNING=0 - sleep $SLEEP_TIME # Give mysqld time to go down properly fi } @@ -453,7 +461,6 @@ stop_master () fi fi MASTER_RUNNING=0 - sleep $SLEEP_TIME # Give mysqld time to go down properly fi } @@ -463,7 +470,10 @@ mysql_stop () $ECHO "Shutting-down MySQL daemon" $ECHO "" stop_master + $ECHO "Master shutdown finished" stop_slave + $ECHO "Slave shutdown finished" + return 1 } diff --git a/mysql-test/r/rpl000001.result b/mysql-test/r/rpl000001.result new file mode 100644 index 00000000000..a15ce85526c --- /dev/null +++ b/mysql-test/r/rpl000001.result @@ -0,0 +1,5 @@ +n +1 +2 +sum(length(word)) +71 diff --git a/mysql-test/r/rpl000014.result b/mysql-test/r/rpl000014.result index 40421f71fee..9e45b9c10a3 100644 --- a/mysql-test/r/rpl000014.result +++ b/mysql-test/r/rpl000014.result @@ -1,13 +1,13 @@ File Position Binlog_do_db Binlog_ignore_db master-bin.001 73 Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db -127.0.0.1 root 9306 1 73 Yes +127.0.0.1 root 9306 1 master-bin.001 73 Yes Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db -127.0.0.1 root 9306 1 73 No +127.0.0.1 root 9306 1 master-bin.001 73 No Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db -127.0.0.1 root 9306 1 73 Yes +127.0.0.1 root 9306 1 master-bin.001 73 Yes Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db -127.0.0.1 root 9306 1 173 Yes +127.0.0.1 root 9306 1 master-bin.001 173 Yes File Position Binlog_do_db Binlog_ignore_db master-bin.001 73 n diff --git a/mysql-test/t/rpl000001.test b/mysql-test/t/rpl000001.test index 426624ee989..a26580d7ef7 100644 --- a/mysql-test/t/rpl000001.test +++ b/mysql-test/t/rpl000001.test @@ -7,12 +7,15 @@ load data infile '../../std_data/words.dat' into table t1; drop table if exists foo; create table foo(n int); insert into foo values(1),(2); +save_master_pos; connection slave; -sleep 2; +sync_with_master; use test; -@r/rpl000001.a.result select * from foo; -@r/rpl000001.b.result select sum(length(word)) from t1; +select * from foo; +select sum(length(word)) from t1; connection master; drop table t1; - +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/rpl000002.test b/mysql-test/t/rpl000002.test index 7a29088dc7a..c982bd54b8c 100644 --- a/mysql-test/t/rpl000002.test +++ b/mysql-test/t/rpl000002.test @@ -5,8 +5,13 @@ drop table if exists t1; create table t1 (n int auto_increment primary key); set insert_id = 2000; insert into t1 values (NULL),(NULL),(NULL); +save_master_pos; connection slave; use test; -sleep 2; +sync_with_master; @r/rpl000002.result select * from t1; +connection master; drop table t1; +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/rpl000003.test b/mysql-test/t/rpl000003.test index 38befa8b9c3..b5957615c5b 100644 --- a/mysql-test/t/rpl000003.test +++ b/mysql-test/t/rpl000003.test @@ -4,7 +4,12 @@ drop table if exists t1; create table t1(n int primary key); !insert into t1 values (1),(2),(2); insert into t1 values (3); +save_master_pos; connection slave; -sleep 2; +sync_with_master; @r/rpl000003.result select * from t1; +connection master; drop table t1; +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/rpl000004.test b/mysql-test/t/rpl000004.test index cd23078112d..9959c272adb 100644 --- a/mysql-test/t/rpl000004.test +++ b/mysql-test/t/rpl000004.test @@ -16,4 +16,11 @@ drop table if exists t2; load table t2 from master; @r/rpl000004.a.result check table t1; @r/rpl000004.b.result select count(*) from t2; +connection master; +set SQL_LOG_BIN=1; drop table if exists t1,t2; +save_master_pos; +connection slave; +sync_with_master; +create table t1(n int); +drop table t1; diff --git a/mysql-test/t/rpl000005.test b/mysql-test/t/rpl000005.test index 59b52f1a0cf..3e1d14912b2 100644 --- a/mysql-test/t/rpl000005.test +++ b/mysql-test/t/rpl000005.test @@ -7,8 +7,12 @@ INSERT t1 SET name='Jacob', age=2; INSERT into t1 SET name='Caleb', age=1; ALTER TABLE t1 ADD id int(8) ZEROFILL AUTO_INCREMENT PRIMARY KEY; @r/rpl000005.result select * from t1; +save_master_pos; connection slave; -sleep 2; +sync_with_master; @r/rpl000005.result select * from t1; connection master; drop table t1; +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/rpl000006.test b/mysql-test/t/rpl000006.test index 01475d9fbd9..ffab3ebfc1e 100644 --- a/mysql-test/t/rpl000006.test +++ b/mysql-test/t/rpl000006.test @@ -12,3 +12,6 @@ load table foo from master; @r/rpl000006.result select unix_timestamp(t) from foo; connection master; drop table foo; +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/rpl000007.test b/mysql-test/t/rpl000007.test index cc98b054212..5b121afaa99 100644 --- a/mysql-test/t/rpl000007.test +++ b/mysql-test/t/rpl000007.test @@ -15,8 +15,12 @@ insert into foo values('five'); drop table if exists bar; create table bar (m int); insert into bar values(15); +save_master_pos; connection slave; -sleep 2; +sync_with_master; @r/rpl000007.result select foo.n,bar.m from foo,bar; connection master; drop table if exists bar,foo; +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/rpl000008.test b/mysql-test/t/rpl000008.test index d17190ef31d..8cbc724c3a6 100644 --- a/mysql-test/t/rpl000008.test +++ b/mysql-test/t/rpl000008.test @@ -17,8 +17,13 @@ insert into bar values(15); drop table if exists choo; create table choo (k int); insert into choo values(55); +save_master_pos; connection slave; -sleep 3; +sync_with_master; @r/rpl000008.result select foo.n,bar.m,choo.k from foo,bar,choo; connection master; drop table if exists foo,bar,choo; +save_master_pos; +connection slave; +sync_with_master; +drop table if exists foo,bar,choo; diff --git a/mysql-test/t/rpl000009.test b/mysql-test/t/rpl000009.test index 9297da3bb6b..1f20981f7d0 100644 --- a/mysql-test/t/rpl000009.test +++ b/mysql-test/t/rpl000009.test @@ -6,8 +6,9 @@ drop database if exists foo; create database foo; drop database if exists bar; create database bar; +save_master_pos; connection slave; -sleep 2; +sync_with_master; drop table if exists foo.foo; create table foo.foo (n int); insert into foo.foo values(4); @@ -18,9 +19,15 @@ insert into foo.foo values(5); drop table if exists bar.bar; create table bar.bar (m int); insert into bar.bar values(15); +save_master_pos; connection slave; -sleep 2; +sync_with_master; @r/rpl000009.result select foo.foo.n,bar.bar.m from foo.foo,bar.bar; connection master; drop database if exists bar; drop database if exists foo; +save_master_pos; +connection slave; +sync_with_master; +drop database if exists bar; +drop database if exists foo; diff --git a/mysql-test/t/rpl000010.test b/mysql-test/t/rpl000010.test index 653f8c3fe8c..ab68f0ae45f 100644 --- a/mysql-test/t/rpl000010.test +++ b/mysql-test/t/rpl000010.test @@ -8,8 +8,12 @@ drop table if exists t1; create table t1 (n int not null auto_increment primary key); insert into t1 values(NULL); insert into t1 values(2); +save_master_pos; connection slave; -sleep 5; +sync_with_master; @r/rpl000010.result select n from t1; connection master; drop table t1; +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/rpl000011.test b/mysql-test/t/rpl000011.test index 14280be45cf..78483027405 100644 --- a/mysql-test/t/rpl000011.test +++ b/mysql-test/t/rpl000011.test @@ -4,16 +4,21 @@ use test; drop table if exists t1; create table t1 (n int); insert into t1 values(1); +save_master_pos; connection slave; #give slave some breathing room to get started -sleep 2; +sync_with_master; slave stop; slave start; connection master; insert into t1 values(2); +save_master_pos; connection slave; #let slave catch up -sleep 2; +sync_with_master; @r/rpl000011.result select * from t1; connection master; drop table t1; +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/rpl000012.test b/mysql-test/t/rpl000012.test index d4b40a48386..495cb81167e 100644 --- a/mysql-test/t/rpl000012.test +++ b/mysql-test/t/rpl000012.test @@ -14,13 +14,18 @@ disconnect master; connection master1; insert into t2 values(6); disconnect master1; +connect (master2,localhost,root,,test,0,mysql-master.sock); +connection master2; +save_master_pos; connection slave; -sleep 1; +sync_with_master; @r/rpl000012.result select * from t2; @r/rpl000012.status.result show status like 'Slave_open_temp_tables'; # # Clean up # -connect (master2,localhost,root,,test,0,mysql-master.sock); connection master2; drop table if exists t1,t2; +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/rpl000013.test b/mysql-test/t/rpl000013.test index 4d4dc3f491a..f5056839791 100644 --- a/mysql-test/t/rpl000013.test +++ b/mysql-test/t/rpl000013.test @@ -1,5 +1,9 @@ source include/master-slave.inc; connection master; +save_master_pos; +connection slave; +sync_with_master; +connection master; drop table if exists t2; create table t2(n int); create temporary table t1 (n int); @@ -12,21 +16,19 @@ insert into t2 select * from t1; disconnect master; connection master1; insert into t2 values(6); -sleep 2; disconnect master1; +connect (master2,localhost,root,,test,0,mysql-master.sock); +connection master2; +save_master_pos; connection slave; -let $1=12; -while ($1) -{ - !slave start; - sleep 0.2; - dec $1; -} +sync_with_master; @r/rpl000013.result select * from t2; @r/rpl000013.status.result show status like 'Slave_open_temp_tables'; # # Clean up # -connect (master2,localhost,root,,test,0,mysql-master.sock); connection master2; drop table if exists t1,t2; +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/rpl000014.test b/mysql-test/t/rpl000014.test index 1a2ce014813..34e160a760c 100644 --- a/mysql-test/t/rpl000014.test +++ b/mysql-test/t/rpl000014.test @@ -2,11 +2,11 @@ source include/master-slave.inc; source include/have_default_master.inc; connection master; show master status; +save_master_pos; connection slave; -sleep 0.2; +sync_with_master; show slave status; change master to master_log_pos=73; -sleep 0.2; slave stop; change master to master_log_pos=73; show slave status; @@ -20,9 +20,13 @@ create table if not exists foo(n int); drop table if exists foo; create table foo (n int); insert into foo values (1),(2),(3); +save_master_pos; connection slave; change master to master_log_pos=73; -sleep 2; +sync_with_master; select * from foo; connection master; drop table foo; +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/rpl000015.test b/mysql-test/t/rpl000015.test index a2528aa9b42..ac4d5d7d08c 100644 --- a/mysql-test/t/rpl000015.test +++ b/mysql-test/t/rpl000015.test @@ -18,8 +18,13 @@ connection master; drop table if exists foo; create table foo (n int); insert into foo values (10),(45),(90); +save_master_pos; connection slave; -sleep 2; +sync_with_master; select * from foo; connection master; drop table foo; +save_master_pos; +connection slave; +sync_with_master; + diff --git a/mysql-test/t/rpl000016.test b/mysql-test/t/rpl000016.test index 2ee68cd230f..115dea734cf 100644 --- a/mysql-test/t/rpl000016.test +++ b/mysql-test/t/rpl000016.test @@ -15,8 +15,9 @@ connection master; drop table if exists t1; create table t1 (s text); insert into t1 values('Could not break slave'),('Tried hard'); +save_master_pos; connection slave; -sleep 2; +sync_with_master; select * from t1; connection master; flush logs; @@ -24,12 +25,14 @@ drop table if exists t2; create table t2(m int); insert into t2 values (34),(67),(123); flush logs; -sleep 0.3; show master logs; purge master logs to 'master-bin.003'; show master logs; insert into t2 values (65); +save_master_pos; connection slave; -sleep 2; +sync_with_master; select * from t2; drop table if exists t1,t2; +connection master; +drop table if exists t1,t2; diff --git a/sql/item_create.cc b/sql/item_create.cc index 8e6332d4e16..ef9f5f2d38b 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -376,3 +376,8 @@ Item *create_load_file(Item* a) { return new Item_load_file(a); } + +Item *create_wait_for_master_pos(Item* a, Item* b) +{ + return new Item_master_pos_wait(a, b); +} diff --git a/sql/item_create.h b/sql/item_create.h index de2726b32b0..cc7497b0183 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -85,3 +85,4 @@ Item *create_func_ucase(Item* a); Item *create_func_version(void); Item *create_func_weekday(Item* a); Item *create_load_file(Item* a); +Item *create_wait_for_master_pos(Item* a, Item* b); diff --git a/sql/item_func.cc b/sql/item_func.cc index bad789479b2..592ef9ae3d4 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -26,6 +26,7 @@ #include #include #include +#include "slave.h" // for wait_for_master_pos /* return TRUE if item is a constant */ @@ -1387,6 +1388,28 @@ void item_user_lock_release(ULL *ull) delete ull; } +/* + Wait until we are at or past the given position in the master binlog + on the slave + */ + +longlong Item_master_pos_wait::val_int() +{ + THD* thd = current_thd; + String *log_name = args[0]->val_str(&value); + int event_count; + + if(thd->slave_thread || !log_name || !log_name->length()) + { + null_value = 1; + return 0; + } + ulong pos = (ulong)args[1]->val_int(); + if((event_count = glob_mi.wait_for_pos(thd, log_name, pos)) == -1) + null_value = 1;; + return event_count; +} + /* Get a user level lock. If the thread has an old lock this is first released. Returns 1: Got lock diff --git a/sql/item_func.h b/sql/item_func.h index 90400b4181a..5810307e81c 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -778,6 +778,18 @@ class Item_func_release_lock :public Item_int_func void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1;} }; +/* replication functions */ + +class Item_master_pos_wait :public Item_int_func +{ + String value; + public: + Item_master_pos_wait(Item *a,Item *b) :Item_int_func(a,b) {} + longlong val_int(); + const char *func_name() const { return "master_pos_wait"; } + void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1;} +}; + /* Handling of user definiable variables */ diff --git a/sql/lex.h b/sql/lex.h index 399106bfd77..bff45eb0f06 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -397,6 +397,8 @@ static SYMBOL sql_functions[] = { { "LOWER", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_lcase)}, { "LPAD", SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_lpad)}, { "LTRIM", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ltrim)}, + { "MASTER_POS_WAIT", SYM(FUNC_ARG2),0, + CREATE_FUNC(create_wait_for_master_pos)}, { "MAKE_SET", SYM(MAKE_SET_SYM),0,0}, { "MAX", SYM(MAX_SYM),0,0}, { "MD5", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_md5)}, diff --git a/sql/slave.cc b/sql/slave.cc index 246dbdde93d..d27bb76c065 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -616,6 +616,46 @@ int flush_master_info(MASTER_INFO* mi) return 0; } +int st_master_info::wait_for_pos(THD* thd, String* log_name, ulong log_pos) +{ + if(!inited) return -1; + bool pos_reached = 0; + int event_count = 0; + for(;!pos_reached && !thd->killed;) + { + int cmp_result; + char* basename; + pthread_mutex_lock(&lock); + if(*log_file_name) + { + basename = strrchr(log_file_name, FN_LIBCHAR); + if(basename) + ++basename; + else + basename = log_file_name; + cmp_result = strncmp(basename, log_name->ptr(), + log_name->length()); + } + else + cmp_result = 0; + + pos_reached = ((!cmp_result && pos >= log_pos) || cmp_result > 0); + if(!pos_reached && !thd->killed) + { + const char* msg = thd->enter_cond(&cond, &lock, + "Waiting for master update"); + pthread_cond_wait(&cond, &lock); + thd->exit_cond(msg); + event_count++; + } + pthread_mutex_unlock(&lock); + if(thd->killed) + return -1; + } + + return event_count; +} + static int init_slave_thread(THD* thd) { @@ -1003,10 +1043,17 @@ static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len) { Rotate_log_event* rev = (Rotate_log_event*)ev; int ident_len = rev->ident_len; + pthread_mutex_lock(&mi->lock); memcpy(mi->log_file_name, rev->new_log_ident,ident_len ); mi->log_file_name[ident_len] = 0; mi->pos = 4; // skip magic number + pthread_cond_broadcast(&mi->cond); + pthread_mutex_unlock(&mi->lock); flush_master_info(mi); +#ifndef DBUG_OFF + if(abort_slave_event_count) + ++events_till_abort; +#endif delete ev; break; } @@ -1045,6 +1092,9 @@ static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len) pthread_handler_decl(handle_slave,arg __attribute__((unused))) { +#ifndef DBUG_OFF + slave_begin: +#endif THD *thd; // needs to be first for thread_stack MYSQL *mysql = NULL ; @@ -1068,8 +1118,8 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused))) #ifndef DBUG_OFF events_till_abort = abort_slave_event_count; #endif - pthread_cond_broadcast(&COND_slave_start); - pthread_mutex_unlock(&LOCK_slave); + pthread_cond_broadcast(&COND_slave_start); + pthread_mutex_unlock(&LOCK_slave); int error = 1; bool retried_once = 0; @@ -1241,6 +1291,10 @@ position %ld", net_end(&thd->net); // destructor will not free it, because we are weird delete thd; my_thread_end(); +#ifndef DBUG_OFF + if(abort_slave_event_count && !events_till_abort) + goto slave_begin; +#endif pthread_exit(0); DBUG_RETURN(0); // Can't return anything here } diff --git a/sql/slave.h b/sql/slave.h index c26be966fc3..b7e2d783749 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -14,17 +14,20 @@ typedef struct st_master_info uint port; uint connect_retry; pthread_mutex_t lock; + pthread_cond_t cond; bool inited; st_master_info():pending(0),fd(-1),inited(0) { host[0] = 0; user[0] = 0; password[0] = 0; pthread_mutex_init(&lock, NULL); + pthread_cond_init(&cond, NULL); } ~st_master_info() { pthread_mutex_destroy(&lock); + pthread_cond_destroy(&cond); } inline void inc_pending(ulonglong val) { @@ -35,6 +38,7 @@ typedef struct st_master_info pthread_mutex_lock(&lock); pos += val + pending; pending = 0; + pthread_cond_broadcast(&cond); pthread_mutex_unlock(&lock); } // thread safe read of position - not needed if we are in the slave thread, @@ -45,6 +49,8 @@ typedef struct st_master_info var = pos; pthread_mutex_unlock(&lock); } + + int wait_for_pos(THD* thd, String* log_name, ulong log_pos); } MASTER_INFO; typedef struct st_table_rule_ent diff --git a/sql/sql_class.h b/sql/sql_class.h index 46c37e1b57f..ef42eaf594c 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -281,6 +281,25 @@ public: THD(); ~THD(); bool store_globals(); + inline const char* enter_cond(pthread_cond_t *cond, pthread_mutex_t* mutex, + const char* msg) + { + const char* old_msg = proc_info; + pthread_mutex_lock(&mysys_var->mutex); + mysys_var->current_mutex = mutex; + mysys_var->current_cond = cond; + proc_info = msg; + pthread_mutex_unlock(&mysys_var->mutex); + return old_msg; + } + inline void exit_cond(const char* old_msg) + { + pthread_mutex_lock(&mysys_var->mutex); + mysys_var->current_mutex = 0; + mysys_var->current_cond = 0; + proc_info = old_msg; + pthread_mutex_unlock(&mysys_var->mutex); + } inline time_t query_start() { query_start_used=1; return start_time; } inline void set_time() { if (user_time) start_time=time_after_lock=user_time; else time_after_lock=time(&start_time); } inline void end_time() { time(&start_time); } diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 0aaaf027ea3..5e37d590c47 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -26,6 +26,36 @@ extern const char* any_db; extern pthread_handler_decl(handle_slave,arg); +static int fake_rotate_event(NET* net, String* packet, + const char* log_file_name); + +static int fake_rotate_event(NET* net, String* packet, char* log_file_name, + const char**errmsg) +{ + char header[LOG_EVENT_HEADER_LEN]; + memset(header, 0, 4); // when does not matter + header[EVENT_TYPE_OFFSET] = ROTATE_EVENT; + char* p = strrchr(log_file_name, FN_LIBCHAR); + // find the last slash + if(p) + p++; + else + p = log_file_name; + + uint ident_len = (uint) strlen(p); + ulong event_len = ident_len + sizeof(header); + int4store(header + EVENT_TYPE_OFFSET + 1, server_id); + int4store(header + EVENT_LEN_OFFSET, event_len); + packet->append(header, sizeof(header)); + packet->append(p,ident_len); + if(my_net_write(net, (char*)packet->ptr(), packet->length())) + { + *errmsg = "failed on my_net_write()"; + return -1; + } + return 0; +} + static int send_file(THD *thd) { @@ -281,6 +311,15 @@ sweepstakes if you report the bug"; // we need to start a packet with something other than 255 // to distiquish it from error + if(pos == 4) // tell the client log name with a fake rotate_event + // if we are at the start of the log + { + if(fake_rotate_event(net, packet, log_file_name, &errmsg)) + goto err; + packet->length(0); + packet->append("\0", 1); + } + while(!net->error && net->vio != 0 && !thd->killed) { pthread_mutex_t *log_lock = mysql_bin_log.get_log_lock(); @@ -437,36 +476,15 @@ sweepstakes if you report the bug"; end_io_cache(&log); (void) my_close(file, MYF(MY_WME)); - if ((file=open_log(&log, log_file_name, &errmsg)) < 0) - goto err; - + // fake Rotate_log event just in case it did not make it to the log // otherwise the slave make get confused about the offset - { - char header[LOG_EVENT_HEADER_LEN]; - memset(header, 0, 4); // when does not matter - header[EVENT_TYPE_OFFSET] = ROTATE_EVENT; - char* p = strrchr(log_file_name, FN_LIBCHAR); - // find the last slash - if(p) - p++; - else - p = log_file_name; + if ((file=open_log(&log, log_file_name, &errmsg)) < 0 || + fake_rotate_event(net, packet, log_file_name, &errmsg)) + goto err; - uint ident_len = (uint) strlen(p); - ulong event_len = ident_len + sizeof(header); - int4store(header + EVENT_TYPE_OFFSET + 1, server_id); - int4store(header + EVENT_LEN_OFFSET, event_len); - packet->append(header, sizeof(header)); - packet->append(p,ident_len); - if(my_net_write(net, (char*)packet->ptr(), packet->length())) - { - errmsg = "failed on my_net_write()"; - goto err; - } - packet->length(0); - packet->append("\0",1); - } + packet->length(0); + packet->append("\0",1); } } From d06404c43f24cded1bdbe1e720c2314d934aa2de Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 17 Jan 2001 16:08:36 -0700 Subject: [PATCH 2/2] replication updates Docs/manual.texi: replications updates --- Docs/manual.texi | 329 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 262 insertions(+), 67 deletions(-) diff --git a/Docs/manual.texi b/Docs/manual.texi index a784b51f3b4..aade0441a33 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -17382,6 +17382,17 @@ Addresses may be 4 or 8 byte addresses: mysql> select INET_ATON("209.207.224.40"); -> 3520061480 @end example +@findex MASTER_POS_WAIT() +@item MASTER_POS_WAIT(log_name, log_pos) +Blocks until the slave reaches the specified position in the master log during +replication. If master information is not initialized, returns NULL. If the +slave is not running, will block and wait until it is started and goes to or +past +the specified postion. If the slave is already past the specified postion, +returns immediately. The return value is the number of log events it had to +wait to get to the specified position, or NULL in case of error. Useful for +control of master-slave synchronization, but was originally written to +facilate replication testing. @end table @findex GROUP BY functions @@ -25589,6 +25600,7 @@ tables}. * Replication Options:: Replication Options in my.cnf * Replication SQL:: SQL Commands related to replication * Replication FAQ:: Frequently Asked Questions about replication +* Troubleshooting Replication:: Troubleshooting Replication @end menu @node Replication Intro, Replication Implementation, Replication, Replication @@ -25605,10 +25617,11 @@ Starting in Version 3.23.15, @strong{MySQL} supports one-way replication internally. One server acts as the master, while the other acts as the slave. Note that one server could play the roles of master in one pair and slave in the other. The master server keeps a binary log of updates -and an index file to binary logs to keep track of log rotation. The -slave upon connecting informs the master where it left off since the -last successfully propagated update, catches up on the updates, and then -blocks and waits for the master to notify it of the new updates. +(@xref{Binary log}.) and an index file to binary logs to keep track of +log rotation. The slave, upon connecting, informs the master where it +left off since the last successfully propagated update, catches up on +the updates, and then blocks and waits for the master to notify it of +the new updates. Note that if you are replicating a database, all updates to this database should be done through the master! @@ -25620,54 +25633,107 @@ On older servers one can use the update log to do simple replication. @node Replication Implementation, Replication HOWTO, Replication Intro, Replication @section Replication Implementation Overview -@strong{MySQL} internal replication uses the master-slave approach. One -server is designated as the master, while the other (or others) as -slave(s). The master keeps a binary log of updates. @xref{Binary log}. -The slave connects to the master, catches up on the missed updates, and -then starts receiving updates immediately as they come to the master. If -the connection is lost, the slave will reconnect. If the master goes -down, the slave will keep trying to connect every -@code{master-connect-retry} seconds until the master comes back up and -the connection can be established. The slave keeps track of where it -left off in the replication process, so it can use the information in case -it goes down and gets restarted later. +@strong{MySQL} replication is based on the server keeping track of all +changes to your database (updates, deletes, etc) in the binary +log. (@xref{Binary log}.) and the slave server(s) reading the saved +queries from the master server's binary log so that the slave can +execute the same queries on its copy of the data. + +It is @strong{very important} to realize that the binary log is simply a +record starting from a fixed point in time (the moment you enable binary +logging). Any slaves which you set up will need copies of all the data +from your master as it existed the moment that you enabled binary +logging on the master. If you start your slaves with data that doesn't +agree with what was on the master @strong{when the binary log was +started}, your slaves may fail. + +A future version (4.0) of @strong{MySQL} will remove the need to keep a +(possibly large) snapshot of data for new slaves that you might wish to +set up through the live backup functionality with no locking required. +However, at this time, it is necessary to block all writes either with a +global read lock or by shutting down the master while taking a snapshot. + +Once a slave is properly configured and running, it will simply connect +to the master and wait for updates to process. If the master goes away +or the slave loses connectivity with your master, it will keep trying to +connect every @code{master-connect-retry} seconds until it is able to +reconnect and resume listening for updates. + +Each slave keeps track of where it left off. The master server has no +knowledge of how many slaves there are or which ones are up-to-date at +any given time. + +The next section explains the master/slave setup process in more detail. @node Replication HOWTO, Replication Features, Replication Implementation, Replication @section HOWTO -Below is a quick HOWTO on how to set up replication on your current -system: +Below is a quick description of how to set up complete replication on +your current @strong{MySQL} server. It assumes you want to replicate all +your databases and have not configured replication before. You will need +to shutdown your master server briefly to complete the steops outlined +below. -@itemize @bullet +@enumerate @item -Upgrade both slave and master to Version 3.23.15 or higher. We recommend -that you always use the latest release of Version 3.23 on both the slave -and the master. The binary log format has also changed a couple of times -during development (before 3.23.29) so you should delete old binary logs -when upgrading @strong{MySQL}. In addition, the newer version will fix -some bugs and add new features. Please, do not report bugs until you -have verified that the problem is present in the latest release. +Make you have a recent version of @strong{MySQL} installed on the master +and slave(s). + +Use Version 3.23.29 or higher. Previous releases used a different binary +log format and had bugs which have been fixed in newer releases. Please, +do not report bugs until you have verified that the problem is present +in the latest release. @item -Set up special replication user(s) on the master with the @code{FILE} +Set up special a replication user on the master with the @code{FILE} privilege and permission to connect from all the slaves. If the user is -only doing replication, you don't need to grant him other privileges. +only doing replication (recommended), you don't need to grant any +additional privileges. + +For example, to create a user named @code{repl} which can access your +master from any host, you might use this command: + +@example +GRANT FILE ON *.* TO repl@@"%" IDENTIFIED BY ''; +@end example + @item -Take a snapshot of all the tables/databases on the master that could -possibly be involved in the update queries before taking the next step. -Starting in Version 3.23.21, there is a command that allows you to take -a snapshot of a table on the master and copy it to the slave, called -@code{LOAD TABLE FROM MASTER}. Until Version 3.23.23, though, it has a -serious bug, and we recommend that you do not use it until you have -upgraded. +Shut down @strong{MySQL} on the master. + +@example +mysqladmin -u root -p shutdown +@end example + +@item +Snapshot all the data on your master server. + +The easiest way to do this (on Unix) is to simply use @strong{tar} to +produce an archvie of your entrie data directory. The exact data +directory location depends on your installation. + +@example +tar -cvf /tmp/mysql-snapshot.tar /path/to/data-dir +@end example + +Windows users can use WinZip or similar software to create an archive of +the data directory. @item In @code{my.cnf} on the master add @code{log-bin} and -@code{server-id=unique number} and restart it. Make sure there are no -important updates to the master between the time you have taken the -snapshot and the time the master is restarted with @code{log-bin} -option. +@code{server-id=unique number} to the @code{[mysqld]} section and +restart it. It is very important that the id of the slave is different from +the id of the master. Think of @code{server-id} as something similar +to the IP address - it uniquely identifies the server instance in the +comminity of replication partners. + +@example +[mysqld] +log-bin +server-id=1 +@end example + @item -Load the snapshot of the master to all the slaves. +Restart @strong{MySQL} on the master. + @item Add the following to @code{my.cnf} on the slave(s): @@ -25675,32 +25741,53 @@ Add the following to @code{my.cnf} on the slave(s): master-host= master-user= master-password= -server-id= +server-id= @end example replacing the values in <> with what is relevant to your system. @code{server-id} must be different for each server participating in -replication. If you don't specify a server-id, it will be set to -1 if you have not defined @code{master-host}, else it will be set to 2. +replication. If you don't specify a server-id, it will be set to 1 if +you have not defined @code{master-host}, else it will be set to 2. Note +that in the case of @code{server-id} omission the master will refuse +connections from all slaves, and the slave will refuse to connect to a +master. Thus, omitting @code{server-id} is only good for backup with a +binary log. + + +@item +Copy the snapshot data into your data directory on your slave(s). Make +sure that the privileges on the files and directories are correct. The +user which @strong{MySQL} runs as needs to be able to read and write to +them, just as on the master. @item Restart the slave(s). -@end itemize +@end enumerate -After you have done the above, the master and the slave(s) should be in -sync. +After you have done the above, the slave(s) should connect to the master +and catch up on any updates which happened since the snapshot was taken. -If you have forgot to set server-id for the slave you will get the following -error in the error log file: +If you have forgotten to set @code{server-id} for the slave you will get +the following error in the error log file: @example Warning: one should set server_id to a non-0 value if master_host is set. The server will not act as a slave. @end example -If you have forgot to do this for the master, the slaves will not be able to -connect to the master. +If you have forgot to do this for the master, the slaves will not be +able to connect to the master. + +If a slave is not able to replicate for any reason, you will find error +messages in the error log on the slave. + +Once a slave is replicating, you will find a file called +@code{master.info} in the same directory as your error log. The +@code{master.info} file is used by the slave to keep track of how much +of the master's binary log is has processed. @strong{Do not} remove or +edit the file, unless you really know what you are doing. Even in that case, +it is preferred that you use @code{CHANGE MASTER TO} command. @cindex options, replication @cindex @code{my.cnf} file @@ -25715,6 +25802,11 @@ Below is an explanation of what is supported and what is not: Replication will be done correctly with @code{AUTO_INCREMENT}, @code{LAST_INSERT_ID}, and @code{TIMESTAMP} values. @item +@code{RAND()} in updates does not replicate properly. Use + @code{RAND(some_non_rand_expr)} if you are replcating updates with +@code{RAND()}. You can, for example, use @code{UNIX_TIMESTAMP()} for the +argument to @code{RAND()}. +@item @code{LOAD DATA INFILE} will be handled properly as long as the file still resides on the master server at the time of update propagation. @code{LOAD LOCAL DATA INFILE} will be skipped. @@ -25779,15 +25871,17 @@ Starting in Version 3.23.19, you can clean up stale replication leftovers when something goes wrong and you want a clean start with @code{FLUSH MASTER} and @code{FLUSH SLAVE} commands. In Version 3.23.26 we have renamed them to @code{RESET MASTER} and @code{RESET SLAVE} respectively to clarify -what they do. The old @code{FLUSH} variants still work, though for +what they do. The old @code{FLUSH} variants still work, though, for compatibility. @item Starting in Version 3.23.21, you can use @code{LOAD TABLE FROM MASTER} for -network backup and to set up replication initially. +network backup and to set up replication initially. We have recently +received a number of bug reports concerning it that we are investigating, so +we recommend that you use it only in testing until we make it more stable. @item -Starting in Version 3.23.23, you can change masters with @code{CHANGE MASTER -TO}. +Starting in Version 3.23.23, you can change masters and adjust log position +with @code{CHANGE MASTER TO}. @item Starting in Version 3.23.23, you tell the master that updates in certain databases should not be logged to the binary log with @code{binlog-ignore-db}. @@ -25803,7 +25897,7 @@ to get rid of old logs while the slave is running. @node Replication Options, Replication SQL, Replication Features, Replication @section Replication Options in my.cnf -If you are using replication, we recommend you to use MySQL Version 3.23.28 or +If you are using replication, we recommend you to use MySQL Version 3.23.30 or later. Older versions work, but they do have some bugs and are missing some features. @@ -26056,7 +26150,7 @@ last log on the list), backup all the logs you are about to delete @end multitable -@node Replication FAQ, , Replication SQL, Replication +@node Replication FAQ,Troubleshooting Replication, Replication SQL, Replication @section Replication FAQ @cindex @code{Binlog_Dump} @@ -26114,12 +26208,10 @@ the slave can stay down for some time - since the master is logging all the updates, the slave will be able to catch up once it is up and can connect. -We plan to make post 3.23.26 versions to be backwards compatible -for replication down to Version 3.23.26, so upgrade should be just a matter -of plug and play. Of course, as one joke goes, plug and play works -usually only 50% of the time - just the plug part. We hope to do much -better than that, though. - +After 3.23.26, we have locked the replication protocol for modifications, so +you can upgrade masters and slave on the fly to a newer 3.23 version and you +can have different versions of @code{MySQL} running on the slave and the +master, as long as they are both newer than 3.23.26. @cindex replication, two-way @strong{Q}: What issues should I be aware of when setting up two-way @@ -26139,10 +26231,6 @@ two-way replication relationship, unless you are sure that you updates can safely happen in any order, or unless you take care of mis-ordered updates somehow in the client code. -Until we implement @code{server_id} variable, you cannot have more than -two servers in a co-master replication relationship, and you must -run @code{mysqld} without @code{log-slave-updates} (default) to avoid -infinite update loops. You must also realize that two-way replication actually does not improve performance very much, if at all, as far as updates are concerned. Both @@ -26248,7 +26336,7 @@ to all servers) So if N = 0, which means we have no replication, our system can handle 1200/11, about 109 writes per second (which means we will have 9 times -as many reads to the nature of our application). +as many reads due to the nature of our application). If N = 1, we can get up to 184 writes per second. @@ -26311,6 +26399,105 @@ We are currently working on intergrating an automatic master election system into @strong{MySQL}, but until it is ready, you will have to create your own monitoring tools. +@node Troubleshooting Replication, ,Replication FAQ, Replication +@section Troubleshooting Replication + +If you have followed the instructions, and your replication setup is not +working, first elliminate the user error factor by checking the following: + +@itemize @bullet +@item +Is the master logging to the binary log? Check with @code{SHOW MASTER STATUS}. +If it is, @code{Position} will be non-zero. If not, verify that you have +given the master @code{log-bin} option and have set @code{server-id}. +@item +Is the slave running? Check with @code{SHOW SLAVE STATUS}. The answer is found +in @code{Slave_running} column. If not, verify slave options and check the +error log for messages. +@item +If the slave is running, did it establish connection with the master? Do +@code{SHOW PROCESSLIST}, find the thread with @code{system user} value in +@code{User} column and @code{none} in the @code{Host} column, and check the +@code{State} column. If it says @code{connecting to master}, verify the +privileges for the replication user on the master, master host name, your +DNS setup, whether the master is actually running, whether it is reachable +from the slave, and if all that seems ok, read the error logs. +@item +If the slave was running, but then stopped, check the error logs. It usually +happens when some query that succeeded on the master fails on the slave. This +should never happen if you have taken a proper snapshot of the master, and +never modify the data on the slave outside of the slave thread. If it does, +it is a bug, read below on how to report it. +@item +Make sure you are not running into an old bug by upgrading to the most recent +version. +@item +If all else fails, read the error logs. If they are big, +@code{grep -i slave /path/to/your-log.err} on the slave. There is no +generic pattern to search for on the master, as the only errors it logs +are general system errors - if it can, it will send the error to the slave +when things go wrong. +@end itemize + +When you have determined that there is no user error involved, and replication +still either does not work at all or is unstable, it is time to start working +on a bug report. We need to get as much info as possible from you to be able +to track down the bug. Please do spend some time and effort preparing a good +bug report. Ideally, we would like to have a test case in the format found in +@code{mysql-test/t/rpl*} directory of the source tree. If you submit a test +case like that, you can expect a patch within a day or two in most cases, +although, of course, you mileage may vary depending on a number of factors. + +Second best option is a just program with easily configurable connection +arguments for the master and the slave that will demonstrate the problem on our +systems. You can write one in Perl or in C, depending on which language you +know better. + +If you have one of the above ways to demonstrate the bug, use +@code{mysqlbug} to prepare a bug report and send it to +@email{bugs@@lists.mysql.com}. If you have a phantom - a problem that +does occur but you cannot duplicate "at will": + +@itemize @bullet +@item +Verify that there is no user error involved. For example, if you update the +slave outside of the slave thread, the data will be out of sync, and you can +have unique key violations on updates, in which case the slave thread will +stop and wait for you to clean up the tables manually to bring them in sync. +@item +Run slave with @code{log-slave-updates} and @code{log-bin} - this will keep +a log of all updates on the slave. +@item +Save all evidence before reseting the replication. If we have no or only +sketchy information, it would take us a while to track down the problem. The +evidence you should collect is: +@itemize @bullet +@item +all binary logs on the master +@item +all binary log on the slave +@item +the output of @code{SHOW MASTER STATUS} on the master at the time +you have discovered the problem +@item +the output of @code{SHOW SLAVE STATUS} on the master at the time +you have discovered the problem +@item +Error logs on the master and on the slave +@end itemize +@item +Use @code{mysqlbinlog} to examine the binary logs. The following should +be helpful +to find the trouble query, for example: +@example +mysqlbinlog -j pos_from_slave_status /path/to/log_from_slave_status | head +@end example +@end itemize + +Once you have collected the evidence on the phantom problem, try hard to +isolate it into a separate test case first. Then report the problem to +@email{bugs@@lists.mysql.com} with as much info as possible. + @cindex performance, maximizing @cindex optimization @@ -40283,6 +40470,7 @@ version. The replication and BerkeleyDB code is still under development, though, so Version 3.23 is not released as a stable version yet. @menu +* News-3.23.32:: Changes in release 3.23.32 * News-3.23.31:: Changes in release 3.23.31 * News-3.23.30:: Changes in release 3.23.30 * News-3.23.29:: Changes in release 3.23.29 @@ -40317,7 +40505,14 @@ though, so Version 3.23 is not released as a stable version yet. * News-3.23.0:: Changes in release 3.23.0 @end menu -@node News-3.23.31, News-3.23.30, News-3.23.x, News-3.23.x +@node News-3.23.32, News-3.23.31, News-3.23.x, News-3.23.x +@appendixsubsec Changes in release 3.23.32 +@itemize @bullet +@item +Added MASTER_POS_WAIT() +@end itemize + +@node News-3.23.31, News-3.23.30, News-3.23.32, News-3.23.x @appendixsubsec Changes in release 3.23.31 @itemize @bullet @item