summaryrefslogtreecommitdiff
path: root/sql/slave.cc
diff options
context:
space:
mode:
authorunknown <pem@mysql.com>2004-05-07 18:52:06 +0200
committerunknown <pem@mysql.com>2004-05-07 18:52:06 +0200
commite9c1e75b48e5d2c0047a3e88b35667a33d6395e4 (patch)
tree2f7b236a8721d14f1b398964b898d922fd133131 /sql/slave.cc
parentf3d691a970627f34ed825a9cf7b84520dcdd43b3 (diff)
parente3211fbd6a59c3dc6a97066c97ab86bfc67d382f (diff)
downloadmariadb-git-e9c1e75b48e5d2c0047a3e88b35667a33d6395e4.tar.gz
Merge 4.1 -> 5.0
BitKeeper/etc/ignore: auto-union BitKeeper/etc/logging_ok: auto-union VC++Files/sql/mysqld.dsp: Auto merged configure.in: Auto merged include/my_global.h: Auto merged include/mysql_com.h: Auto merged libmysql/libmysql.c: Auto merged libmysqld/Makefile.am: Auto merged myisam/myisamchk.c: Auto merged myisam/myisamdef.h: Auto merged mysql-test/install_test_db.sh: Auto merged mysql-test/r/func_time.result: Auto merged mysql-test/r/mysqldump.result: Auto merged mysql-test/r/show_check.result: Auto merged mysql-test/r/subselect.result: Auto merged mysql-test/r/union.result: Auto merged mysql-test/t/func_time.test: Auto merged mysql-test/t/subselect.test: Auto merged scripts/make_binary_distribution.sh: Auto merged scripts/mysql_install_db.sh: Auto merged sql/ha_berkeley.cc: Auto merged mysql-test/t/rpl_error_ignored_table.test: Auto merged sql/ha_berkeley.h: Auto merged sql/ha_innodb.cc: Auto merged sql/ha_innodb.h: Auto merged sql/ha_myisam.cc: Auto merged sql/handler.cc: Auto merged sql/handler.h: Auto merged sql/item.cc: Auto merged sql/item.h: Auto merged sql/item_cmpfunc.cc: Auto merged sql/item_cmpfunc.h: Auto merged sql/item_subselect.cc: Auto merged sql/item_sum.cc: Auto merged sql/item_sum.h: Auto merged sql/lex.h: Auto merged sql/log.cc: Auto merged sql/mysql_priv.h: Auto merged sql/mysqld.cc: Auto merged sql/protocol.cc: Auto merged sql/records.cc: Auto merged sql/set_var.cc: Auto merged sql/sql_acl.cc: Auto merged sql/sql_acl.h: Auto merged sql/sql_base.cc: Auto merged sql/sql_cache.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_db.cc: Auto merged sql/sql_delete.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_load.cc: Auto merged sql/sql_prepare.cc: Auto merged sql/sql_select.h: Auto merged sql/sql_show.cc: Auto merged sql/sql_string.cc: Auto merged sql/sql_test.cc: Auto merged sql/sql_update.cc: Auto merged sql/sql_yacc.yy: Auto merged sql/table.h: Auto merged tests/client_test.c: Auto merged
Diffstat (limited to 'sql/slave.cc')
-rw-r--r--sql/slave.cc127
1 files changed, 108 insertions, 19 deletions
diff --git a/sql/slave.cc b/sql/slave.cc
index ad4cc820409..3fddc4dc783 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -39,7 +39,7 @@ HASH replicate_do_table, replicate_ignore_table;
DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table;
bool do_table_inited = 0, 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;
/*
@@ -463,6 +463,55 @@ void init_slave_skip_errors(const char* arg)
}
}
+
+void st_relay_log_info::inc_group_relay_log_pos(ulonglong val,
+ ulonglong log_pos,
+ bool skip_lock)
+{
+ if (!skip_lock)
+ pthread_mutex_lock(&data_lock);
+ inc_event_relay_log_pos(val);
+ group_relay_log_pos= event_relay_log_pos;
+ strmake(group_relay_log_name,event_relay_log_name,
+ sizeof(group_relay_log_name)-1);
+
+ 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).
+ */
+ if (log_pos) // 3.23 binlogs don't have log_posx
+ {
+#if MYSQL_VERSION_ID < 50000
+ /*
+ If the event was converted from a 3.23 format, get_event_len() has
+ grown by 6 bytes (at least for most events, except LOAD DATA INFILE
+ which is already a big problem for 3.23->4.0 replication); 6 bytes is
+ the difference between the header's size in 4.0 (LOG_EVENT_HEADER_LEN)
+ and the header's size in 3.23 (OLD_HEADER_LEN). Note that using
+ mi->old_format will not help if the I/O thread has not started yet.
+ Yes this is a hack but it's just to make 3.23->4.x replication work;
+ 3.23->5.0 replication is working much better.
+ */
+ group_master_log_pos= log_pos + val -
+ (mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0);
+#else
+ group_master_log_pos= log_pos+ val;
+#endif /* MYSQL_VERSION_ID < 5000 */
+ }
+ pthread_cond_broadcast(&data_cond);
+ if (!skip_lock)
+ pthread_mutex_unlock(&data_lock);
+}
+
+
void st_relay_log_info::close_temporary_tables()
{
TABLE *table,*next;
@@ -802,7 +851,17 @@ static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
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
- rules because they may get unpredicted results.
+ rules because they may get unpredicted results (precedence order is
+ explained in the manual).
+ If no table of the list is marked "updating" (so far this can only happen
+ if the statement is a multi-delete (SQLCOM_DELETE_MULTI) and the "tables"
+ is the tables in the FROM): then we always return 0, because there is no
+ reason we play this statement on this slave if it updates nothing. In the
+ case of SQLCOM_DELETE_MULTI, there will be a second call to tables_ok(),
+ with tables having "updating==TRUE" (those after the DELETE), so this
+ second call will make the decision (because
+ all_tables_not_ok() = !tables_ok(1st_list) && !tables_ok(2nd_list)).
+
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
supported Perl regexps we could do it with this pattern: /^abc\.(?!EFG)/
@@ -815,6 +874,7 @@ static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
int tables_ok(THD* thd, TABLE_LIST* tables)
{
+ bool some_tables_updating= 0;
DBUG_ENTER("tables_ok");
for (; tables; tables = tables->next)
@@ -825,6 +885,7 @@ int tables_ok(THD* thd, TABLE_LIST* tables)
if (!tables->updating)
continue;
+ some_tables_updating= 1;
end= strmov(hash_key, tables->db ? tables->db : thd->db);
*end++= '.';
len= (uint) (strmov(end, tables->real_name) - hash_key);
@@ -847,10 +908,13 @@ int tables_ok(THD* thd, TABLE_LIST* tables)
}
/*
+ If no table was to be updated, ignore statement (no reason we play it on
+ slave, slave is supposed to replicate _changes_ only).
If no explicit rule found and there was a do list, do not replicate.
If there was no do list, go ahead
*/
- DBUG_RETURN(!do_table_inited && !wild_do_table_inited);
+ DBUG_RETURN(some_tables_updating &&
+ !do_table_inited && !wild_do_table_inited);
}
@@ -1645,13 +1709,13 @@ Failed to open the existing relay log info file '%s' (errno %d)",
rli->info_fd = info_fd;
int relay_log_pos, master_log_pos;
if (init_strvar_from_file(rli->group_relay_log_name,
- sizeof(rli->group_relay_log_name), &rli->info_file,
- "") ||
+ sizeof(rli->group_relay_log_name),
+ &rli->info_file, "") ||
init_intvar_from_file(&relay_log_pos,
&rli->info_file, BIN_LOG_HEADER_SIZE) ||
init_strvar_from_file(rli->group_master_log_name,
- sizeof(rli->group_master_log_name), &rli->info_file,
- "") ||
+ sizeof(rli->group_master_log_name),
+ &rli->info_file, "") ||
init_intvar_from_file(&master_log_pos, &rli->info_file, 0))
{
msg="Error reading slave log configuration";
@@ -2358,7 +2422,8 @@ st_relay_log_info::st_relay_log_info()
inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE),
until_log_pos(0)
{
- group_relay_log_name[0]= event_relay_log_name[0]= group_master_log_name[0]= 0;
+ group_relay_log_name[0]= event_relay_log_name[0]=
+ group_master_log_name[0]= 0;
last_slave_error[0]=0; until_log_name[0]= 0;
bzero((char*) &info_file, sizeof(info_file));
@@ -2460,6 +2525,8 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
error= -2; //means improper arguments
goto err;
}
+ // Convert 0-3 to 4
+ log_pos= max(log_pos, BIN_LOG_HEADER_SIZE);
/* p points to '.' */
log_name_extension= strtoul(++p, &p_end, 10);
/*
@@ -2480,14 +2547,24 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
init_abort_pos_wait == abort_pos_wait &&
slave_running)
{
+
/*
- 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).
+ 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 "".
*/
if (*group_master_log_name)
{
- char *basename= group_master_log_name + dirname_length(group_master_log_name);
+ char *basename= (group_master_log_name +
+ dirname_length(group_master_log_name));
/*
First compare the parts before the extension.
Find the dot in the master's log basename,
@@ -2504,14 +2581,16 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
char *q_end;
ulong group_master_log_name_extension= strtoul(q, &q_end, 10);
if (group_master_log_name_extension < log_name_extension)
- cmp_result = -1 ;
+ cmp_result= -1 ;
else
- cmp_result= (group_master_log_name_extension > log_name_extension) ?
- 1 : 0 ;
- if (((!cmp_result && group_master_log_pos >= (ulonglong)log_pos) ||
- cmp_result > 0) || thd->killed)
+ cmp_result= (group_master_log_name_extension > log_name_extension) ? 1 : 0 ;
+
+ pos_reached= ((!cmp_result && group_master_log_pos >= (ulonglong)log_pos) ||
+ cmp_result > 0);
+ if (pos_reached || thd->killed)
break;
}
+
//wait for master update, with optional timeout.
DBUG_PRINT("info",("Waiting for master update"));
@@ -2945,6 +3024,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
DBUG_PRINT("info",("type_code=%d, server_id=%d",type_code,ev->server_id));
if ((ev->server_id == (uint32) ::server_id &&
+ !replicate_same_server_id &&
type_code!= FORMAT_DESCRIPTION_EVENT) ||
(rli->slave_skip_counter &&
type_code != ROTATE_EVENT && type_code != STOP_EVENT &&
@@ -3738,7 +3818,15 @@ static int queue_binlog_ver_1_event(MASTER_INFO *mi, const char *buf,
DBUG_RETURN(1);
}
memcpy(tmp_buf,buf,event_len);
- tmp_buf[event_len]=0; // Create_file constructor wants null-term buffer
+ /*
+ 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;
+ int4store(tmp_buf+EVENT_LEN_OFFSET, event_len);
buf = (const char*)tmp_buf;
}
/*
@@ -4016,7 +4104,8 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
direct master (an unsupported, useless setup!).
*/
- if (uint4korr(buf + SERVER_ID_OFFSET) == ::server_id)
+ if ((uint4korr(buf + SERVER_ID_OFFSET) == ::server_id) &&
+ !replicate_same_server_id)
{
/*
Do not write it to the relay log.