diff --git a/mysql-test/suite/multi_source/load_data.result b/mysql-test/suite/multi_source/load_data.result new file mode 100644 index 00000000000..ef55abc5321 --- /dev/null +++ b/mysql-test/suite/multi_source/load_data.result @@ -0,0 +1,30 @@ +change master '' to master_port=MYPORT_1, master_host='127.0.0.1', master_user='root'; +change master 'master2' to master_port=MYPORT_2, master_host='127.0.0.1', master_user='root'; +start all slaves; +Warnings: +Note 1937 SLAVE 'master2' started +Note 1937 SLAVE '' started +set default_master_connection = ''; +include/wait_for_slave_to_start.inc +set default_master_connection = 'master2'; +include/wait_for_slave_to_start.inc +set default_master_connection = ''; +create table t1 (a varchar(10) character set utf8); +load data infile '../../std_data/loaddata6.dat' into table t1; +create table t2 (a varchar(10) character set utf8); +load data infile '../../std_data/loaddata6.dat' into table t2; +select count(*) from t1; +count(*) +1 +select count(*) from t2; +count(*) +1 +drop table t1; +drop table t2; +stop all slaves; +Warnings: +Note 1938 SLAVE 'master2' stopped +Note 1938 SLAVE '' stopped +include/reset_master_slave.inc +include/reset_master_slave.inc +include/reset_master_slave.inc diff --git a/mysql-test/suite/multi_source/load_data.test b/mysql-test/suite/multi_source/load_data.test new file mode 100644 index 00000000000..e6e1399cbf3 --- /dev/null +++ b/mysql-test/suite/multi_source/load_data.test @@ -0,0 +1,70 @@ +# +# Simple multi-master test +# + +--source include/not_embedded.inc +--let $rpl_server_count= 0 + +--connect (slave,127.0.0.1,root,,,$SERVER_MYPORT_3) +--connect (master1,127.0.0.1,root,,,$SERVER_MYPORT_1) +--connect (master2,127.0.0.1,root,,,$SERVER_MYPORT_2) +--connection slave + +--replace_result $SERVER_MYPORT_1 MYPORT_1 +eval change master '' to master_port=$SERVER_MYPORT_1, master_host='127.0.0.1', master_user='root'; +--replace_result $SERVER_MYPORT_2 MYPORT_2 +eval change master 'master2' to master_port=$SERVER_MYPORT_2, master_host='127.0.0.1', master_user='root'; +start all slaves; + +set default_master_connection = ''; +--source include/wait_for_slave_to_start.inc +set default_master_connection = 'master2'; +--source include/wait_for_slave_to_start.inc + +# +# Now test doing a load data infile from both connections +# +set default_master_connection = ''; +--connection master1 +create table t1 (a varchar(10) character set utf8); +load data infile '../../std_data/loaddata6.dat' into table t1; +--save_master_pos +--connection slave +--sync_with_master 0,'' +--connection master2 +create table t2 (a varchar(10) character set utf8); +load data infile '../../std_data/loaddata6.dat' into table t2; +--save_master_pos +--connection slave +--sync_with_master 0,'master2' +select count(*) from t1; +select count(*) from t2; +--connection master1 +drop table t1; +--connection master2 +drop table t2; + +# +# clean up +# + +--connection master1 +--save_master_pos +--connection slave +--sync_with_master 0,'' +--connection master2 +--save_master_pos +--connection slave +--sync_with_master 0,'master2' + +--connection slave +stop all slaves; + +--source reset_master_slave.inc +--disconnect slave +--connection master1 +--source reset_master_slave.inc +--disconnect master1 +--connection master2 +--source reset_master_slave.inc +--disconnect master2 diff --git a/sql/log_event.cc b/sql/log_event.cc index 83789400924..aa86fa6ff62 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -47,6 +47,7 @@ #include "transaction.h" #include #include "sql_show.h" // append_identifier +#include #endif /* MYSQL_CLIENT */ @@ -518,11 +519,59 @@ pretty_print_str(String *packet, const char *str, int len) #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) /** - Creates a temporary name for load data infile:. + Create a prefix for the temporary files that is to be used for + load data file name for this master + + @param name Store prefix of name here + @param connection_name Connection name + + @return pointer to end of name + + @description + We assume that FN_REFLEN is big enough to hold + MAX_CONNECTION_NAME * MAX_FILENAME_MBWIDTH characters + 2 numbers + + a short extension. + + The resulting file name has the following parts, each separated with a '-' + - PREFIX_SQL_LOAD (SQL_LOAD-) + - If a connection name is given (multi-master setup): + - Add an extra '-' to mark that this is a multi-master file + - connection name in lower case, converted to safe file characters. + (see create_logfile_name_with_suffix()). + - server_id + - A last '-' (after server_id). +*/ + +static char *load_data_tmp_prefix(char *name, + LEX_STRING *connection_name) +{ + name= strmov(name, PREFIX_SQL_LOAD); + if (connection_name->length) + { + uint buf_length; + uint errors; + /* Add marker that this is a multi-master-file */ + *name++='-'; + /* Convert connection_name to a safe filename */ + buf_length= strconvert(system_charset_info, connection_name->str, + &my_charset_filename, name, FN_REFLEN, + &errors); + name+= buf_length; + *name++= '-'; + } + name= int10_to_str(global_system_variables.server_id, name, 10); + *name++ = '-'; + *name= '\0'; // For testing prefixes + return name; +} + + +/** + Creates a temporary name for LOAD DATA INFILE @param buf Store new filename here @param file_id File_id (part of file name) - @param event_server_id Event_id (part of file name) + @param event_server_id Event_id (part of file name) @param ext Extension for file name @return @@ -530,16 +579,14 @@ pretty_print_str(String *packet, const char *str, int len) */ static char *slave_load_file_stem(char *buf, uint file_id, - int event_server_id, const char *ext) + int event_server_id, const char *ext, + LEX_STRING *connection_name) { char *res; - fn_format(buf,PREFIX_SQL_LOAD,slave_load_tmpdir, "", MY_UNPACK_FILENAME); + res= buf+ unpack_dirname(buf, slave_load_tmpdir); to_unix_path(buf); - - buf = strend(buf); - buf = int10_to_str(global_system_variables.server_id, buf, 10); - *buf++ = '-'; - buf = int10_to_str(event_server_id, buf, 10); + buf= load_data_tmp_prefix(res, connection_name); + buf= int10_to_str(event_server_id, buf, 10); *buf++ = '-'; res= int10_to_str(file_id, buf, 10); strmov(res, ext); // Add extension last @@ -554,14 +601,17 @@ static char *slave_load_file_stem(char *buf, uint file_id, Delete all temporary files used for SQL_LOAD. */ -static void cleanup_load_tmpdir() +static void cleanup_load_tmpdir(LEX_STRING *connection_name) { MY_DIR *dirp; FILEINFO *file; uint i; - char fname[FN_REFLEN], prefbuf[31], *p; + char dir[FN_REFLEN], fname[FN_REFLEN]; + char prefbuf[31 + MAX_CONNECTION_NAME* MAX_FILENAME_MBWIDTH + 1]; + DBUG_ENTER("cleanup_load_tmpdir"); - if (!(dirp=my_dir(slave_load_tmpdir,MYF(0)))) + unpack_dirname(dir, slave_load_tmpdir); + if (!(dirp=my_dir(dir, MYF(MY_WME)))) return; /* @@ -572,10 +622,9 @@ static void cleanup_load_tmpdir() we cannot meet Start_log event in the middle of events from one LOAD DATA. */ - p= strmake(prefbuf, STRING_WITH_LEN(PREFIX_SQL_LOAD)); - p= int10_to_str(global_system_variables.server_id, p, 10); - *(p++)= '-'; - *p= 0; + + load_data_tmp_prefix(prefbuf, connection_name); + DBUG_PRINT("enter", ("dir: '%s' prefix: '%s'", dir, prefbuf)); for (i=0 ; i < (uint)dirp->number_of_files; i++) { @@ -588,6 +637,7 @@ static void cleanup_load_tmpdir() } my_dirend(dirp); + DBUG_VOID_RETURN; } #endif @@ -4417,7 +4467,11 @@ int Start_log_event_v3::do_apply_event(Relay_log_info const *rli) if (created) { error= close_temporary_tables(thd); - cleanup_load_tmpdir(); + /* + The following is only false if we get here with a BINLOG statement + */ + if (rli->mi) + cleanup_load_tmpdir(&rli->mi->cmp_connection_name); } else { @@ -7784,7 +7838,8 @@ int Create_file_log_event::do_apply_event(Relay_log_info const *rli) bzero((char*)&file, sizeof(file)); fname_buf= strmov(proc_info, "Making temp file "); - ext= slave_load_file_stem(fname_buf, file_id, server_id, ".info"); + ext= slave_load_file_stem(fname_buf, file_id, server_id, ".info", + &rli->mi->connection_name); thd_proc_info(thd, proc_info); /* old copy may exist already */ mysql_file_delete(key_file_log_event_info, fname_buf, MYF(0)); @@ -7962,7 +8017,8 @@ int Append_block_log_event::do_apply_event(Relay_log_info const *rli) DBUG_ENTER("Append_block_log_event::do_apply_event"); fname= strmov(proc_info, "Making temp file "); - slave_load_file_stem(fname, file_id, server_id, ".data"); + slave_load_file_stem(fname, file_id, server_id, ".data", + &rli->mi->cmp_connection_name); thd_proc_info(thd, proc_info); if (get_create_or_append()) { @@ -8106,7 +8162,8 @@ void Delete_file_log_event::pack_info(THD *thd, Protocol *protocol) int Delete_file_log_event::do_apply_event(Relay_log_info const *rli) { char fname[FN_REFLEN+10]; - char *ext= slave_load_file_stem(fname, file_id, server_id, ".data"); + char *ext= slave_load_file_stem(fname, file_id, server_id, ".data", + &rli->mi->cmp_connection_name); mysql_file_delete(key_file_log_event_data, fname, MYF(MY_WME)); strmov(ext, ".info"); mysql_file_delete(key_file_log_event_info, fname, MYF(MY_WME)); @@ -8210,7 +8267,8 @@ int Execute_load_log_event::do_apply_event(Relay_log_info const *rli) IO_CACHE file; Load_log_event *lev= 0; - ext= slave_load_file_stem(fname, file_id, server_id, ".info"); + ext= slave_load_file_stem(fname, file_id, server_id, ".info", + &rli->mi->cmp_connection_name); if ((fd= mysql_file_open(key_file_log_event_info, fname, O_RDONLY | O_BINARY | O_NOFOLLOW, MYF(MY_WME))) < 0 || @@ -8497,7 +8555,8 @@ Execute_load_query_log_event::do_apply_event(Relay_log_info const *rli) memcpy(p, query, fn_pos_start); p+= fn_pos_start; fname= (p= strmake(p, STRING_WITH_LEN(" INFILE \'"))); - p= slave_load_file_stem(p, file_id, server_id, ".data"); + p= slave_load_file_stem(p, file_id, server_id, ".data", + &rli->mi->cmp_connection_name); fname_end= p= strend(p); // Safer than p=p+5 *(p++)='\''; switch (dup_handling) { diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 38fcc54e891..92dbf68d7a2 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -687,10 +687,11 @@ bool check_master_connection_name(LEX_STRING *name) */ void create_logfile_name_with_suffix(char *res_file_name, size_t length, - const char *info_file, bool append, - LEX_STRING *suffix) + const char *info_file, bool append, + LEX_STRING *suffix) { - char buff[MAX_CONNECTION_NAME+1], res[MAX_CONNECTION_NAME+1], *p; + char buff[MAX_CONNECTION_NAME+1], + res[MAX_CONNECTION_NAME * MAX_FILENAME_MBWIDTH+1], *p; p= strmake(res_file_name, info_file, length); /* If not empty suffix and there is place left for some part of the suffix */ @@ -703,8 +704,6 @@ void create_logfile_name_with_suffix(char *res_file_name, size_t length, /* Create null terminated string */ strmake(buff, suffix->str, suffix->length); - /* Convert to lower case */ - my_casedn_str(system_charset_info, buff); /* Convert to characters usable in a file name */ res_length= strconvert(system_charset_info, buff, &my_charset_filename, res, sizeof(res), &errors); @@ -820,7 +819,7 @@ bool Master_info_index::init_all_master_info() { int thread_mask; int err_num= 0, succ_num= 0; // The number of success read Master_info - char sign[MAX_CONNECTION_NAME]; + char sign[MAX_CONNECTION_NAME+1]; File index_file_nr; DBUG_ENTER("init_all_master_info"); @@ -872,11 +871,14 @@ bool Master_info_index::init_all_master_info() lock_slave_threads(mi); init_thread_mask(&thread_mask,mi,0 /*not inverse*/); - create_logfile_name_with_suffix(buf_master_info_file, sizeof(buf_master_info_file), - master_info_file, 0, &connection_name); + create_logfile_name_with_suffix(buf_master_info_file, + sizeof(buf_master_info_file), + master_info_file, 0, + &mi->cmp_connection_name); create_logfile_name_with_suffix(buf_relay_log_info_file, - sizeof(buf_relay_log_info_file), - relay_log_info_file, 0, &connection_name); + sizeof(buf_relay_log_info_file), + relay_log_info_file, 0, + &mi->cmp_connection_name); if (global_system_variables.log_warnings > 1) sql_print_information("Reading Master_info: '%s' Relay_info:'%s'", buf_master_info_file, buf_relay_log_info_file); diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 7733354b106..ec2ca048976 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -213,17 +213,18 @@ a file name for --relay-log-index option", opt_relaylog_index_name); char buf_relay_logname[FN_REFLEN], buf_relaylog_index_name_buff[FN_REFLEN]; char *buf_relaylog_index_name= opt_relaylog_index_name; - create_logfile_name_with_suffix(buf_relay_logname, sizeof(buf_relay_logname), - ln, 1, &mi->connection_name); + create_logfile_name_with_suffix(buf_relay_logname, + sizeof(buf_relay_logname), + ln, 1, &mi->cmp_connection_name); ln= buf_relay_logname; if (opt_relaylog_index_name) { buf_relaylog_index_name= buf_relaylog_index_name_buff; create_logfile_name_with_suffix(buf_relaylog_index_name_buff, - sizeof(buf_relaylog_index_name_buff), - opt_relaylog_index_name, 0, - &mi->connection_name); + sizeof(buf_relaylog_index_name_buff), + opt_relaylog_index_name, 0, + &mi->cmp_connection_name); } /* diff --git a/sql/slave.cc b/sql/slave.cc index 36d26e76dce..f0a9b27707c 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3712,7 +3712,6 @@ int check_temp_dir(char* tmp_file) MY_DIR *dirp; char tmp_dir[FN_REFLEN]; size_t tmp_dir_size; - DBUG_ENTER("check_temp_dir"); mysql_mutex_lock(&LOCK_thread_count); diff --git a/sql/sql_const.h b/sql/sql_const.h index 7dadbb7b8b4..d0a7a83f3a1 100644 --- a/sql/sql_const.h +++ b/sql/sql_const.h @@ -41,6 +41,7 @@ #define MAX_CONNECTION_NAME NAME_LEN #define MAX_MBWIDTH 3 /* Max multibyte sequence */ +#define MAX_FILENAME_MBWIDTH 5 #define MAX_FIELD_CHARLENGTH 255 #define MAX_FIELD_VARCHARLENGTH 65535 #define MAX_FIELD_BLOBLENGTH UINT_MAX32 /* cf field_blob::get_length() */ diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index f5f503b9fc8..1dac2aa2039 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -2128,11 +2128,12 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) create_logfile_name_with_suffix(master_info_file_tmp, sizeof(master_info_file_tmp), - master_info_file, 0, &mi->connection_name); + master_info_file, 0, + &mi->cmp_connection_name); create_logfile_name_with_suffix(relay_log_info_file_tmp, sizeof(relay_log_info_file_tmp), relay_log_info_file, 0, - &mi->connection_name); + &mi->cmp_connection_name); lock_slave_threads(mi); // this allows us to cleanly read slave_running // Get a mask of _stopped_ threads @@ -2378,11 +2379,13 @@ int reset_slave(THD *thd, Master_info* mi) // and delete these two files create_logfile_name_with_suffix(master_info_file_tmp, - sizeof(master_info_file_tmp), - master_info_file, 0, &mi->connection_name); + sizeof(master_info_file_tmp), + master_info_file, 0, + &mi->cmp_connection_name); create_logfile_name_with_suffix(relay_log_info_file_tmp, - sizeof(relay_log_info_file_tmp), - relay_log_info_file, 0, &mi->connection_name); + sizeof(relay_log_info_file_tmp), + relay_log_info_file, 0, + &mi->cmp_connection_name); fn_format(fname, master_info_file_tmp, mysql_data_home, "", 4+32); if (mysql_file_stat(key_file_master_info, fname, &stat_area, MYF(0)) && @@ -2549,11 +2552,13 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added) thd_proc_info(thd, "Changing master"); create_logfile_name_with_suffix(master_info_file_tmp, - sizeof(master_info_file_tmp), - master_info_file, 0, &mi->connection_name); + sizeof(master_info_file_tmp), + master_info_file, 0, + &mi->cmp_connection_name); create_logfile_name_with_suffix(relay_log_info_file_tmp, - sizeof(relay_log_info_file_tmp), - relay_log_info_file, 0, &mi->connection_name); + sizeof(relay_log_info_file_tmp), + relay_log_info_file, 0, + &mi->cmp_connection_name); /* if new Master_info doesn't exists, add it */ if (!master_info_index->get_master_info(&mi->connection_name,