Commit 3fc39188 authored by guilhem@mysql.com's avatar guilhem@mysql.com

A new option --replicate-same-server-id to force a slave to execute queries originating from itself

(WL#794). This can be of interest in some recovery-from-backup scenarios, and also when you have
two databases in one mysqld, having a certain similarity and you want one db to be updated when the other is
(some sort of trigger).
Plus small fix for BUG#3568 "MySQL server crashes when built --with-debug and CHANGE MASTER +MASTER_POS_WAIT"
parent 93797a0d
slave stop;
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;
slave start;
drop table if exists t1;
create table t1 (n int);
reset master;
stop slave;
change master to master_port=9307;
show slave status;
Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space
127.0.0.1 root SLAVE_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 #
start slave;
insert into t1 values (1);
show status like "slave_running";
Variable_name Value
Slave_running ON
select * from t1;
n
1
drop table t1;
slave stop;
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;
slave start;
drop table if exists t1;
create table t1 (n int);
reset master;
stop slave;
change master to master_port=9307;
show slave status;
Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space
127.0.0.1 root SLAVE_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 #
start slave;
insert into t1 values (1);
select * from t1;
n
1
1
drop table t1;
# This test checks that a slave does not execute queries originating
# from itself, by default.
source include/master-slave.inc;
connection slave;
drop table if exists t1;
create table t1 (n int);
reset master;
# replicate ourselves
stop slave;
eval change master to master_port=$SLAVE_MYPORT;
--replace_result $SLAVE_MYPORT SLAVE_PORT
--replace_column 18 #
show slave status;
start slave;
insert into t1 values (1);
# can't MASTER_POS_WAIT(), it does not work in this weird setup
# (when slave is its own master without --replicate-same-server-id)
sleep 2; # enough time for the event to be replicated (it should not)
show status like "slave_running";
select * from t1;
drop table t1;
--disable-log-slave-updates --replicate-same-server-id
# This test checks that a slave DOES execute queries originating
# from itself, if running with --replicate-same-server-id.
source include/master-slave.inc;
connection slave;
drop table if exists t1;
create table t1 (n int);
reset master;
# replicate ourselves
stop slave;
eval change master to master_port=$SLAVE_MYPORT;
--replace_result $SLAVE_MYPORT SLAVE_PORT
--replace_column 18 #
show slave status;
start slave;
insert into t1 values (1);
save_master_pos;
sync_with_master;
select * from t1; # check that indeed 2 were inserted
drop table t1;
...@@ -2379,6 +2379,15 @@ Warning: you need to use --log-bin to make --log-slave-updates work. \ ...@@ -2379,6 +2379,15 @@ Warning: you need to use --log-bin to make --log-slave-updates work. \
Now disabling --log-slave-updates."); Now disabling --log-slave-updates.");
} }
if (opt_log_slave_updates && replicate_same_server_id)
{
sql_print_error("\
Error: using --replicate-same-server-id in conjunction with \
--log-slave-updates is impossible, it would lead to infinite loops in this \
server.");
unireg_abort(1);
}
if (opt_bootstrap) if (opt_bootstrap)
{ {
int error=bootstrap(stdin); int error=bootstrap(stdin);
...@@ -3203,7 +3212,7 @@ enum options_mysqld { ...@@ -3203,7 +3212,7 @@ enum options_mysqld {
OPT_SKIP_SLAVE_START, OPT_SKIP_INNOBASE, OPT_SKIP_SLAVE_START, OPT_SKIP_INNOBASE,
OPT_SAFEMALLOC_MEM_LIMIT, OPT_REPLICATE_DO_TABLE, OPT_SAFEMALLOC_MEM_LIMIT, OPT_REPLICATE_DO_TABLE,
OPT_REPLICATE_IGNORE_TABLE, OPT_REPLICATE_WILD_DO_TABLE, OPT_REPLICATE_IGNORE_TABLE, OPT_REPLICATE_WILD_DO_TABLE,
OPT_REPLICATE_WILD_IGNORE_TABLE, OPT_REPLICATE_WILD_IGNORE_TABLE, OPT_REPLICATE_SAME_SERVER_ID,
OPT_DISCONNECT_SLAVE_EVENT_COUNT, OPT_DISCONNECT_SLAVE_EVENT_COUNT,
OPT_ABORT_SLAVE_EVENT_COUNT, OPT_ABORT_SLAVE_EVENT_COUNT,
OPT_INNODB_DATA_HOME_DIR, OPT_INNODB_DATA_HOME_DIR,
...@@ -3613,6 +3622,13 @@ Does nothing yet.", ...@@ -3613,6 +3622,13 @@ Does nothing yet.",
{"replicate-rewrite-db", OPT_REPLICATE_REWRITE_DB, {"replicate-rewrite-db", OPT_REPLICATE_REWRITE_DB,
"Updates to a database with a different name than the original. Example: replicate-rewrite-db=master_db_name->slave_db_name", "Updates to a database with a different name than the original. Example: replicate-rewrite-db=master_db_name->slave_db_name",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"replicate-same-server-id", OPT_REPLICATE_SAME_SERVER_ID,
"In replication, if set to 1, do not skip events having our server id. \
Default value is 0 (to break infinite loops in circular replication). \
Can't be set to 1 if --log-slave-updates is used.",
(gptr*) &replicate_same_server_id,
(gptr*) &replicate_same_server_id,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
// In replication, we may need to tell the other servers how to connect // In replication, we may need to tell the other servers how to connect
{"report-host", OPT_REPORT_HOST, {"report-host", OPT_REPORT_HOST,
"Hostname or IP of the slave to be reported to to the master during slave registration. Will appear in the output of SHOW SLAVE HOSTS. Leave unset if you do not want the slave to register itself with the master. Note that it is not sufficient for the master to simply read the IP of the slave off the socket once the slave connects. Due to NAT and other routing issues, that IP may not be valid for connecting to the slave from the master or other hosts.", "Hostname or IP of the slave to be reported to to the master during slave registration. Will appear in the output of SHOW SLAVE HOSTS. Leave unset if you do not want the slave to register itself with the master. Note that it is not sufficient for the master to simply read the IP of the slave off the socket once the slave connects. Due to NAT and other routing issues, that IP may not be valid for connecting to the slave from the master or other hosts.",
......
...@@ -38,7 +38,7 @@ HASH replicate_do_table, replicate_ignore_table; ...@@ -38,7 +38,7 @@ HASH replicate_do_table, replicate_ignore_table;
DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table; 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, replicate_same_server_id;
ulonglong relay_log_space_limit = 0; ulonglong relay_log_space_limit = 0;
/* /*
...@@ -1999,6 +1999,8 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, ...@@ -1999,6 +1999,8 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
error= -2; //means improper arguments error= -2; //means improper arguments
goto err; goto err;
} }
// Convert 0-3 to 4
log_pos= max(log_pos, BIN_LOG_HEADER_SIZE);
/* p points to '.' */ /* p points to '.' */
log_name_extension= strtoul(++p, &p_end, 10); log_name_extension= strtoul(++p, &p_end, 10);
/* /*
...@@ -2019,7 +2021,18 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, ...@@ -2019,7 +2021,18 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
{ {
bool pos_reached; bool pos_reached;
int cmp_result= 0; int cmp_result= 0;
DBUG_ASSERT(*master_log_name || master_log_pos == 0); /*
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 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 master_log_pos will
grow and master_log_name will stay "".
*/
if (*master_log_name) if (*master_log_name)
{ {
char *basename= master_log_name + dirname_length(master_log_name); char *basename= master_log_name + dirname_length(master_log_name);
...@@ -2039,14 +2052,15 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, ...@@ -2039,14 +2052,15 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
char *q_end; char *q_end;
ulong master_log_name_extension= strtoul(q, &q_end, 10); ulong master_log_name_extension= strtoul(q, &q_end, 10);
if (master_log_name_extension < log_name_extension) if (master_log_name_extension < log_name_extension)
cmp_result = -1 ; cmp_result= -1 ;
else else
cmp_result= (master_log_name_extension > log_name_extension) ? 1 : 0 ; cmp_result= (master_log_name_extension > log_name_extension) ? 1 : 0 ;
pos_reached= ((!cmp_result && master_log_pos >= (ulonglong)log_pos) ||
cmp_result > 0);
if (pos_reached || thd->killed)
break;
} }
pos_reached = ((!cmp_result && master_log_pos >= (ulonglong)log_pos) ||
cmp_result > 0);
if (pos_reached || thd->killed)
break;
//wait for master update, with optional timeout. //wait for master update, with optional timeout.
...@@ -2351,7 +2365,12 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) ...@@ -2351,7 +2365,12 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
log files themselves. log files themselves.
*/ */
if (ev->server_id == (uint32) ::server_id || /*
TODO: when this is merged into 4.1, one needs to update queue_event() to
add a similar test for replicate_same_server_id, because in 4.1 the I/O
thread is also filtering events based on the server id.
*/
if ((ev->server_id == (uint32) ::server_id && !replicate_same_server_id) ||
(rli->slave_skip_counter && type_code != ROTATE_EVENT)) (rli->slave_skip_counter && type_code != ROTATE_EVENT))
{ {
/* TODO: I/O thread should not even log events with the same server id */ /* TODO: I/O thread should not even log events with the same server id */
......
...@@ -418,7 +418,7 @@ extern HASH replicate_do_table, replicate_ignore_table; ...@@ -418,7 +418,7 @@ extern HASH replicate_do_table, replicate_ignore_table;
extern DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table; extern DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table;
extern bool do_table_inited, ignore_table_inited, 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, replicate_same_server_id;
extern int disconnect_slave_event_count, abort_slave_event_count ; extern int disconnect_slave_event_count, abort_slave_event_count ;
......
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