summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <guilhem@mysql.com>2003-10-30 16:13:38 +0100
committerunknown <guilhem@mysql.com>2003-10-30 16:13:38 +0100
commit8a66a844ceabd418379b53a2457ee464a572d190 (patch)
tree5ee2c9877d899f41333b99ef6463ee8951aaaa5e
parentfaeb0065b78a13823ff5dd8aed2b6efa36c31f91 (diff)
parentb4bc448eba986c5a1daecb8c70df8b093402bd10 (diff)
downloadmariadb-git-8a66a844ceabd418379b53a2457ee464a572d190.tar.gz
Merge gbichot@bk-internal.mysql.com:/home/bk/mysql-4.0
into mysql.com:/home/mysql_src/mysql-4.0
-rw-r--r--mysql-test/mysql-test-run.sh10
-rw-r--r--mysql-test/r/rpl_chain_temp_table.result30
-rw-r--r--mysql-test/t/rpl_chain_temp_table.test89
-rw-r--r--sql/log_event.cc56
-rw-r--r--sql/log_event.h8
-rw-r--r--sql/slave.cc2
-rw-r--r--sql/sql_base.cc25
-rw-r--r--sql/unireg.h2
8 files changed, 204 insertions, 18 deletions
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index 6cba5eecddd..cd409e1ace5 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -336,7 +336,13 @@ while test $# -gt 0; do
EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --gdb"
;;
--valgrind)
- VALGRIND="valgrind --alignment=8 --leak-check=yes --num-callers=16"
+ VALGRIND=`which valgrind` # this will print an error if not found
+ # Give good warning to the user and stop
+ if [ -z "$VALGRIND" ] ; then
+ $ECHO "You need to have the 'valgrind' program in your PATH to run mysql-test-run with option --valgrind. Valgrind's home page is http://developer.kde.org/~sewardj ."
+ exit 1
+ fi
+ VALGRIND="$VALGRIND --alignment=8 --leak-check=yes --num-callers=16"
EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-safemalloc --skip-bdb"
EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-safemalloc --skip-bdb"
SLEEP_TIME_AFTER_RESTART=10
@@ -1161,7 +1167,7 @@ run_testcase ()
echo $tname > $CURRENT_TEST
SKIP_SLAVE=`$EXPR \( $tname : rpl \) = 0`
if [ $USE_MANAGER = 1 ] ; then
- many_slaves=`$EXPR \( $tname : rpl_failsafe \) != 0`
+ many_slaves=`$EXPR \( \( $tname : rpl_failsafe \) != 0 \) \| \( \( $tname : rpl_chain_temp_table \) != 0 \)`
fi
if [ -n "$SKIP_TEST" ] ; then
diff --git a/mysql-test/r/rpl_chain_temp_table.result b/mysql-test/r/rpl_chain_temp_table.result
new file mode 100644
index 00000000000..5ece80565c7
--- /dev/null
+++ b/mysql-test/r/rpl_chain_temp_table.result
@@ -0,0 +1,30 @@
+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;
+reset master;
+change master to master_host='127.0.0.1',master_port=9307, master_user='root';
+start slave;
+create temporary table t1 (a int);
+create temporary table t1 (a int);
+show status like 'slave_open_temp_tables';
+Variable_name Value
+Slave_open_temp_tables 2
+create temporary table t1 (a int);
+create temporary table t1 (a int);
+show status like 'slave_open_temp_tables';
+Variable_name Value
+Slave_open_temp_tables 4
+stop slave;
+insert into t1 values(1);
+create table t2 as select * from t1;
+start slave;
+show status like 'slave_open_temp_tables';
+Variable_name Value
+Slave_open_temp_tables 4
+select * from t2;
+a
+1
+drop table t2;
diff --git a/mysql-test/t/rpl_chain_temp_table.test b/mysql-test/t/rpl_chain_temp_table.test
new file mode 100644
index 00000000000..65701d8a078
--- /dev/null
+++ b/mysql-test/t/rpl_chain_temp_table.test
@@ -0,0 +1,89 @@
+ # This test makes some assumptions about values of thread ids, which should be
+# true if the servers have been restarted for this test. So we want to
+# stop/restart servers. Note that if assumptions are wrong, the test will not
+# fail; it will just fail to test the error-prone scenario.
+# Using the manager is the only way to have more than one slave server.
+
+require_manager;
+server_stop master;
+server_start master;
+server_stop slave;
+server_start slave;
+# no need for slave_sec (no assumptions on thread ids for this server).
+
+source include/master-slave.inc;
+connect (slave_sec,localhost,root,,test,0,slave.sock-1);
+connection master;
+save_master_pos;
+connection slave;
+sync_with_master;
+reset master;
+save_master_pos;
+connection slave_sec;
+eval change master to master_host='127.0.0.1',master_port=$SLAVE_MYPORT, master_user='root';
+start slave;
+sync_with_master;
+
+# :P now we have a chain ready-to-test.
+
+connection master;
+create temporary table t1 (a int);
+save_master_pos;
+connection slave;
+sync_with_master;
+connection master1;
+create temporary table t1 (a int);
+save_master_pos;
+connection slave;
+sync_with_master;
+save_master_pos;
+
+# First test:
+
+connection slave_sec;
+# Before BUG#1686 ("If 2 master threads with same-name temp table, slave makes
+# bad binlog") was fixed, sync_with_master failed
+sync_with_master;
+show status like 'slave_open_temp_tables';
+
+# 'master' and 'master1' usually have thread id 2-3 or 3-4.
+# 'slave' and 'slave1' usually have thread id 2-3.
+connection slave;
+create temporary table t1 (a int);
+connection slave1;
+create temporary table t1 (a int);
+# So it's likely that in the binlog of slave we get
+# server_id=of_master thread_id=3 create temp...
+# server_id=of_slave thread_id=3 create temp...
+# which would confuse slave-sec unless slave-sec uses server id to distinguish
+# between temp tables (here thread id is obviously not enough to distinguish).
+
+save_master_pos;
+
+# Second test:
+
+connection slave_sec;
+# If we did not use the server id to distinguish between temp tables,
+# sync_with_master would fail
+sync_with_master;
+show status like 'slave_open_temp_tables';
+
+# Third test (BUG#1240 "slave of slave breaks when STOP SLAVE was issud on
+# parent slave and temp tables").
+stop slave;
+connection slave;
+insert into t1 values(1);
+create table t2 as select * from t1;
+save_master_pos;
+connection slave_sec;
+start slave;
+sync_with_master;
+show status like 'slave_open_temp_tables';
+select * from t2;
+
+# clean up
+connection slave;
+drop table t2;
+save_master_pos;
+connection slave_sec;
+sync_with_master;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 699d1ff866d..36d2d33ade6 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -834,8 +834,11 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
ulong query_length, bool using_trans)
:Log_event(thd_arg, 0, using_trans), data_buf(0), query(query_arg),
db(thd_arg->db), q_len((uint32) query_length),
- error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno),
- thread_id(thd_arg->thread_id)
+ error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno),
+ thread_id(thd_arg->thread_id),
+ /* save the original thread id; we already know the server id */
+ slave_proxy_id(thd_arg->slave_proxy_id)
+
{
time_t end_time;
time(&end_time);
@@ -918,7 +921,42 @@ int Query_log_event::write_data(IO_CACHE* file)
return -1;
char buf[QUERY_HEADER_LEN];
- int4store(buf + Q_THREAD_ID_OFFSET, thread_id);
+ /*
+ We want to store the thread id:
+ (- as an information for the user when he reads the binlog)
+ - if the query uses temporary table: for the slave SQL thread to know to
+ which master connection the temp table belongs.
+ Now imagine we (write_data()) are called by the slave SQL thread (we are
+ logging a query executed by this thread; the slave runs with
+ --log-slave-updates). Then this query will be logged with
+ thread_id=the_thread_id_of_the_SQL_thread. Imagine that 2 temp tables of the
+ same name were created simultaneously on the master (in the master binlog
+ you have
+ CREATE TEMPORARY TABLE t; (thread 1)
+ CREATE TEMPORARY TABLE t; (thread 2)
+ ...)
+ then in the slave's binlog there will be
+ CREATE TEMPORARY TABLE t; (thread_id_of_the_slave_SQL_thread)
+ CREATE TEMPORARY TABLE t; (thread_id_of_the_slave_SQL_thread)
+ which is bad (same thread id!).
+ To avoid this, we log the thread's thread id EXCEPT for the SQL slave thread
+ for which we log the original (master's) thread id.
+ Now this moves the bug: what happens if the thread id on the master was 10
+ and when the slave replicates the query, a connection number 10 is opened by
+ a normal client on the slave, and updates a temp table of the same name? We
+ get a problem again. To avoid this, in the handling of temp tables
+ (sql_base.cc) we use thread_id AND server_id.
+ TODO when this is merged into 4.1: in 4.1, slave_proxy_id has been renamed
+ to pseudo_thread_id and is a session variable: that's to make mysqlbinlog
+ work with temp tables. We probably need to introduce
+ SET PSEUDO_SERVER_ID
+ for mysqlbinlog in 4.1. mysqlbinlog would print:
+ SET PSEUDO_SERVER_ID=
+ SET PSEUDO_THREAD_ID=
+ for each query using temp tables.
+ */
+ int4store(buf + Q_THREAD_ID_OFFSET, (slave_proxy_id ? slave_proxy_id :
+ thread_id));
int4store(buf + Q_EXEC_TIME_OFFSET, exec_time);
buf[Q_DB_LEN_OFFSET] = (char) db_len;
int2store(buf + Q_ERR_CODE_OFFSET, error_code);
@@ -1019,7 +1057,8 @@ void Rand_log_event::print(FILE* file, bool short_form, char* last_db)
int Load_log_event::write_data_header(IO_CACHE* file)
{
char buf[LOAD_HEADER_LEN];
- int4store(buf + L_THREAD_ID_OFFSET, thread_id);
+ int4store(buf + L_THREAD_ID_OFFSET, (slave_proxy_id ? slave_proxy_id :
+ thread_id));
int4store(buf + L_EXEC_TIME_OFFSET, exec_time);
int4store(buf + L_SKIP_LINES_OFFSET, skip_lines);
buf[L_TBL_LEN_OFFSET] = (char)table_name_len;
@@ -1143,10 +1182,11 @@ Load_log_event::Load_log_event(THD* thd_arg, sql_exchange* ex,
enum enum_duplicates handle_dup,
bool using_trans)
:Log_event(thd_arg, 0, using_trans),thread_id(thd_arg->thread_id),
- num_fields(0),fields(0),
- field_lens(0),field_block_len(0),
- table_name(table_name_arg ? table_name_arg : ""),
- db(db_arg), fname(ex->file_name)
+ slave_proxy_id(thd_arg->slave_proxy_id),
+ num_fields(0),fields(0),
+ field_lens(0),field_block_len(0),
+ table_name(table_name_arg ? table_name_arg : ""),
+ db(db_arg), fname(ex->file_name)
{
time_t end_time;
time(&end_time);
diff --git a/sql/log_event.h b/sql/log_event.h
index 227c0243b9c..2e6b7373dc2 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -320,6 +320,13 @@ public:
uint32 db_len;
uint16 error_code;
ulong thread_id;
+ /*
+ For events created by Query_log_event::exec_event (and
+ Load_log_event::exec_event()) we need the *original* thread id, to be able
+ to log the event with the original (=master's) thread id (fix for
+ BUG#1686).
+ */
+ ulong slave_proxy_id;
#ifndef MYSQL_CLIENT
Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length,
@@ -390,6 +397,7 @@ protected:
public:
ulong thread_id;
+ ulong slave_proxy_id;
uint32 table_name_len;
uint32 db_len;
uint32 fname_len;
diff --git a/sql/slave.cc b/sql/slave.cc
index b679ac2f6b8..90b0cc74fd8 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -2719,8 +2719,6 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
RPL_LOG_NAME, llstr(rli->master_log_pos,llbuff));
err:
- /* Free temporary tables etc */
- thd->cleanup();
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query = thd->db = 0; // extra safety
VOID(pthread_mutex_unlock(&LOCK_thread_count));
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 1010378825f..47529b90b67 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -589,6 +589,8 @@ TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name)
uint key_length= (uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
TABLE *table,**prev;
+ int4store(key+key_length,thd->server_id);
+ key_length += 4;
int4store(key+key_length,thd->slave_proxy_id);
key_length += 4;
@@ -617,18 +619,27 @@ bool close_temporary_table(THD *thd, const char *db, const char *table_name)
return 0;
}
+/*
+ Used by ALTER TABLE when the table is a temporary one. It changes something
+ only if the ALTER contained a RENAME clause (otherwise, table_name is the old
+ name).
+ Prepares a table cache key, which is the concatenation of db, table_name and
+ thd->slave_proxy_id, separated by '\0'.
+*/
bool rename_temporary_table(THD* thd, TABLE *table, const char *db,
const char *table_name)
{
char *key;
if (!(key=(char*) alloc_root(&table->mem_root,
(uint) strlen(db)+
- (uint) strlen(table_name)+6)))
+ (uint) strlen(table_name)+6+4)))
return 1; /* purecov: inspected */
table->key_length=(uint)
(strmov((table->real_name=strmov(table->table_cache_key=key,
db)+1),
table_name) - table->table_cache_key)+1;
+ int4store(key+table->key_length,thd->server_id);
+ table->key_length += 4;
int4store(key+table->key_length,thd->slave_proxy_id);
table->key_length += 4;
return 0;
@@ -783,12 +794,13 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
if (thd->killed)
DBUG_RETURN(0);
key_length= (uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
- int4store(key + key_length, thd->slave_proxy_id);
+ int4store(key + key_length, thd->server_id);
+ int4store(key + key_length + 4, thd->slave_proxy_id);
for (table=thd->temporary_tables; table ; table=table->next)
{
- if (table->key_length == key_length+4 &&
- !memcmp(table->table_cache_key,key,key_length+4))
+ if (table->key_length == key_length+8 &&
+ !memcmp(table->table_cache_key,key,key_length+8))
{
if (table->query_id == thd->query_id)
{
@@ -1596,7 +1608,7 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
total of 6 extra bytes in my_malloc in addition to table/db stuff
*/
if (!(tmp_table=(TABLE*) my_malloc(sizeof(*tmp_table)+(uint) strlen(db)+
- (uint) strlen(table_name)+6,
+ (uint) strlen(table_name)+6+4,
MYF(MY_WME))))
DBUG_RETURN(0); /* purecov: inspected */
@@ -1619,6 +1631,9 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
+1), table_name)
- tmp_table->table_cache_key)+1;
int4store(tmp_table->table_cache_key + tmp_table->key_length,
+ thd->server_id);
+ tmp_table->key_length += 4;
+ int4store(tmp_table->table_cache_key + tmp_table->key_length,
thd->slave_proxy_id);
tmp_table->key_length += 4;
diff --git a/sql/unireg.h b/sql/unireg.h
index f2cace51fa7..37157311e15 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -43,7 +43,7 @@
#define ERRMAPP 1 /* Errormap f|r my_error */
#define LIBLEN FN_REFLEN-FN_LEN /* Max l{ngd p} dev */
-#define MAX_DBKEY_LENGTH (FN_LEN*2+6) /* extra 4 bytes for slave tmp
+#define MAX_DBKEY_LENGTH (FN_LEN*2+1+1+4+4) /* extra 4+4 bytes for slave tmp
* tables */
#define MAX_FIELD_NAME 34 /* Max colum name length +2 */
#define MAX_SYS_VAR_LENGTH 32