diff --git a/mysql-test/include/begin_include_file.inc b/mysql-test/include/begin_include_file.inc index 1b69fb0e52d..6c438f3df30 100644 --- a/mysql-test/include/begin_include_file.inc +++ b/mysql-test/include/begin_include_file.inc @@ -48,6 +48,11 @@ # must be provided both for begin_include_file.inc and # end_include_file.inc. # +# $keep_include_silent +# This specifies whether it should be echoed to the result file +# the following string: include/$include_filename +# If not set, the string will be echoed. +# # $rpl_debug # If set, this script will print the following text: # ==== BEGIN include/$include_filename.inc ==== @@ -59,7 +64,10 @@ # recursively. if (!$_include_file_depth) { - --echo include/$include_filename + if (!$keep_include_silent) + { + --echo include/$include_filename + } --let $_include_file_depth= 0 } --inc $_include_file_depth diff --git a/mysql-test/suite/rpl/r/rpl_binlog_index.result b/mysql-test/suite/rpl/r/rpl_binlog_index.result new file mode 100644 index 00000000000..9861a156a62 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_binlog_index.result @@ -0,0 +1,35 @@ +include/master-slave.inc +[connection master] +CREATE TABLE t1 (a INT); +FLUSH BINARY LOGS; +INSERT INTO t1 VALUES (1); +# Shutdown master +include/rpl_stop_server.inc [server_number=1] +# Move the master binlog files and the index file to a new place +# Restart master with log-bin option set to the new path +# Master has restarted successfully +# Create the master-bin.index file with the old format +# Shutdown master +include/rpl_stop_server.inc [server_number=1] +# Move back the master binlog files +# Remove the unneeded master-bin.index file +# Restart master with log-bin option set to default +# Master has restarted successfully +include/stop_slave.inc +# Move the slave binlog and relay log files and index to the new place +# Shutdown slave +include/rpl_stop_server.inc [server_number=2] +# Restart slave with options log-bin, relay-log set to the new paths +# Slave has restarted successfully +include/start_slave.inc +include/stop_slave.inc +FLUSH LOGS; +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (2); +FLUSH LOGS; +FLUSH LOGS; +include/start_slave.inc +include/diff_tables.inc [master:t1,slave:t1] +DROP TABLE t1; diff --git a/mysql-test/suite/rpl/t/rpl_binlog_index.test b/mysql-test/suite/rpl/t/rpl_binlog_index.test new file mode 100644 index 00000000000..900a6819c2f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_binlog_index.test @@ -0,0 +1,160 @@ +# ==== Purpose ==== +# +# Test that server can work fine after moving binlog or relay log +# files to another directory and setting binlog or relay log paths to +# the new path. +# +# ==== Method ==== +# +# Start replication, and then shutdown the master, move the binary +# logs and the log index file to a another directory and then restart +# the server with option to set the new binlog directory. After master +# restarted successfully, do the similar on slave to check the relay +# log of slave. +# +# ==== Reference ==== +# +# BUG#12133 master.index file keeps mysqld from starting if bin log has been moved +# BUG#42576 Relay logs in relay-log.info&localhost-relay-bin.index not processed after move + +source include/master-slave.inc; +# There is no need to run this test case on all binlog format +source include/have_binlog_format_row.inc; + +connection master; +--let $master_datadir= `select @@datadir` +connection slave; +--let $slave_datadir= `select @@datadir` +connection master; +--let $tmpdir= $MYSQLTEST_VARDIR/tmp/rpl_binlog_index +--mkdir $tmpdir + +CREATE TABLE t1 (a INT); +# flush to generate one more binlog file. +FLUSH BINARY LOGS; +INSERT INTO t1 VALUES (1); + +sync_slave_with_master; + + +# +# Test on master +# +connection master; +--echo # Shutdown master +--let $rpl_server_number=1 +source include/rpl_stop_server.inc; + +--echo # Move the master binlog files and the index file to a new place +--move_file $master_datadir/master-bin.000001 $tmpdir/master-bin.000001 +--move_file $master_datadir/master-bin.000002 $tmpdir/master-bin.000002 +--move_file $master_datadir/master-bin.index $tmpdir/master-bin.index + +--echo # Restart master with log-bin option set to the new path +--let $rpl_server_parameters=--log-bin=$tmpdir/master-bin +--let $keep_include_silent=1 +source include/rpl_start_server.inc; +--let $keep_include_silent=0 + +--echo # Master has restarted successfully + +# +# Test master can handle old format with directory path in index file +# +--let $is_windows= `select convert(@@version_compile_os using latin1) in ('Win32', 'Win64', 'Windows')` + +# write_var_to_file.inc will call SELECT INTO DUMPFILE, which has to be +# done before shutdown the server +--echo # Create the master-bin.index file with the old format +--let $write_to_file= $master_datadir/master-bin.index +if ($is_windows) +{ + --let $write_var= .\\master-bin.000001\n.\\master-bin.000002\n +} +if (!$is_windows) +{ + --let $write_var= ./master-bin.000001\n./master-bin.000002\n +} +--disable_query_log +source include/write_var_to_file.inc; +--enable_query_log + +--echo # Shutdown master +--let $rpl_server_number=1 +source include/rpl_stop_server.inc; + +--echo # Move back the master binlog files +--move_file $tmpdir/master-bin.000001 $master_datadir/master-bin.000001 +--move_file $tmpdir/master-bin.000002 $master_datadir/master-bin.000002 + +--echo # Remove the unneeded master-bin.index file +--remove_file $tmpdir/master-bin.index + +--echo # Restart master with log-bin option set to default +--let $rpl_server_parameters=--log-bin=$master_datadir/master-bin +--let $keep_include_silent=1 +source include/rpl_start_server.inc; +--let $keep_include_silent=0 + +--echo # Master has restarted successfully + +connection slave; +source include/stop_slave.inc; + +--disable_query_log +# slave-relay-bin.* files can vary, so read the slave-relay-bin.index +# to figure out the slave-relay-bin.* files +CREATE TEMPORARY TABLE tmp (id INT AUTO_INCREMENT PRIMARY KEY, filename VARCHAR(1024)); +# chmod to allow the following LOAD DATA +--chmod 0666 $slave_datadir/slave-relay-bin.index +--eval LOAD DATA INFILE '$slave_datadir/slave-relay-bin.index' INTO TABLE tmp (filename) +--let $count= `SELECT count(*) FROM tmp` +--echo # Move the slave binlog and relay log files and index to the new place +--move_file $slave_datadir/slave-bin.index $tmpdir/slave-bin.index +--move_file $slave_datadir/slave-bin.000001 $tmpdir/slave-bin.000001 +--move_file $slave_datadir/slave-relay-bin.index $tmpdir/slave-relay-bin.index +while ($count) +{ + --let $filename= `select filename from tmp where id=$count` + --move_file $slave_datadir/$filename $tmpdir/$filename + --dec $count +} +DROP TEMPORARY TABLE tmp; +--enable_query_log + +--echo # Shutdown slave +--let $rpl_server_number=2 +source include/rpl_stop_server.inc; + +--echo # Restart slave with options log-bin, relay-log set to the new paths +--let $rpl_server_parameters=--log-bin=$tmpdir/slave-bin --relay-log=$tmpdir/slave-relay-bin +--let $keep_include_silent=1 +source include/rpl_start_server.inc; +--let $keep_include_silent=0 + +--echo # Slave has restarted successfully +source include/start_slave.inc; +--source include/stop_slave.inc + +connection master; +FLUSH LOGS; +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (2); + +FLUSH LOGS; + +connection slave; +FLUSH LOGS; +--source include/start_slave.inc +connection master; +sync_slave_with_master; +--let $diff_tables= master:t1,slave:t1 +source include/diff_tables.inc; + +connection master; +DROP TABLE t1; +sync_slave_with_master; +--remove_files_wildcard $tmpdir * +--rmdir $tmpdir diff --git a/sql/log.cc b/sql/log.cc index 77ba7aa6283..ec4c01003e0 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3242,10 +3242,11 @@ int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name, bool need_lock) { int error= 0; - char *fname= linfo->log_file_name; - uint log_name_len= log_name ? (uint) strlen(log_name) : 0; + char *full_fname= linfo->log_file_name; + char full_log_name[FN_REFLEN], fname[FN_REFLEN]; + uint log_name_len= 0, fname_len= 0; DBUG_ENTER("find_log_pos"); - DBUG_PRINT("enter",("log_name: %s", log_name ? log_name : "NULL")); + full_log_name[0]= full_fname[0]= 0; /* Mutex needed because we need to make sure the file pointer does not @@ -3255,6 +3256,20 @@ int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name, mysql_mutex_lock(&LOCK_index); mysql_mutex_assert_owner(&LOCK_index); + // extend relative paths for log_name to be searched + if (log_name) + { + if(normalize_binlog_name(full_log_name, log_name, is_relay_log)) + { + error= LOG_INFO_EOF; + goto end; + } + } + + log_name_len= log_name ? (uint) strlen(full_log_name) : 0; + DBUG_PRINT("enter", ("log_name: %s, full_log_name: %s", + log_name ? log_name : "NULL", full_log_name)); + /* As the file is flushed, we can't get an error here */ (void) reinit_io_cache(&index_file, READ_CACHE, (my_off_t) 0, 0, 0); @@ -3273,19 +3288,28 @@ int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name, break; } + // extend relative paths and match against full path + if (normalize_binlog_name(full_fname, fname, is_relay_log)) + { + error= LOG_INFO_EOF; + break; + } + fname_len= (uint) strlen(full_fname); + // if the log entry matches, null string matching anything if (!log_name || - (log_name_len == length-1 && fname[log_name_len] == '\n' && - !memcmp(fname, log_name, log_name_len))) + (log_name_len == fname_len-1 && full_fname[log_name_len] == '\n' && + !memcmp(full_fname, full_log_name, log_name_len))) { - DBUG_PRINT("info",("Found log file entry")); - fname[length-1]=0; // remove last \n + DBUG_PRINT("info", ("Found log file entry")); + full_fname[fname_len-1]= 0; // remove last \n linfo->index_file_start_offset= offset; linfo->index_file_offset = my_b_tell(&index_file); break; } } +end: if (need_lock) mysql_mutex_unlock(&LOCK_index); DBUG_RETURN(error); @@ -3320,7 +3344,8 @@ int MYSQL_BIN_LOG::find_next_log(LOG_INFO* linfo, bool need_lock) { int error= 0; uint length; - char *fname= linfo->log_file_name; + char fname[FN_REFLEN]; + char *full_fname= linfo->log_file_name; if (need_lock) mysql_mutex_lock(&LOCK_index); @@ -3336,8 +3361,19 @@ int MYSQL_BIN_LOG::find_next_log(LOG_INFO* linfo, bool need_lock) error = !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO; goto err; } - fname[length-1]=0; // kill \n - linfo->index_file_offset = my_b_tell(&index_file); + + if (fname[0] != 0) + { + if(normalize_binlog_name(full_fname, fname, is_relay_log)) + { + error= LOG_INFO_EOF; + goto err; + } + length= strlen(full_fname); + } + + full_fname[length-1]= 0; // kill \n + linfo->index_file_offset= my_b_tell(&index_file); err: if (need_lock) diff --git a/sql/log.h b/sql/log.h index 481bd545960..2e9d308e5e5 100644 --- a/sql/log.h +++ b/sql/log.h @@ -715,4 +715,66 @@ char *make_log_name(char *buff, const char *name, const char* log_ext); extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log; extern LOGGER logger; + +/** + Turns a relative log binary log path into a full path, based on the + opt_bin_logname or opt_relay_logname. + + @param from The log name we want to make into an absolute path. + @param to The buffer where to put the results of the + normalization. + @param is_relay_log Switch that makes is used inside to choose which + option (opt_bin_logname or opt_relay_logname) to + use when calculating the base path. + + @returns true if a problem occurs, false otherwise. + */ + +inline bool normalize_binlog_name(char *to, const char *from, bool is_relay_log) +{ + DBUG_ENTER("normalize_binlog_name"); + bool error= false; + char buff[FN_REFLEN]; + char *ptr= (char*) from; + char *opt_name= is_relay_log ? opt_relay_logname : opt_bin_logname; + + DBUG_ASSERT(from); + + /* opt_name is not null and not empty and from is a relative path */ + if (opt_name && opt_name[0] && from && !test_if_hard_path(from)) + { + // take the path from opt_name + // take the filename from from + char log_dirpart[FN_REFLEN], log_dirname[FN_REFLEN]; + size_t log_dirpart_len, log_dirname_len; + dirname_part(log_dirpart, opt_name, &log_dirpart_len); + dirname_part(log_dirname, from, &log_dirname_len); + + /* log may be empty => relay-log or log-bin did not + hold paths, just filename pattern */ + if (log_dirpart_len > 0) + { + /* create the new path name */ + if(fn_format(buff, from+log_dirname_len, log_dirpart, "", + MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH)) == NULL) + { + error= true; + goto end; + } + + ptr= buff; + } + } + + DBUG_ASSERT(ptr); + + if (ptr) + strmake(to, ptr, strlen(ptr)); + +end: + DBUG_RETURN(error); +} + + + #endif /* LOG_H */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 0f5087c6ccf..285b10154ce 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -652,7 +652,7 @@ ulong master_retry_count=0; char *master_info_file; char *relay_log_info_file, *report_user, *report_password, *report_host; char *opt_relay_logname = 0, *opt_relaylog_index_name=0; -char *opt_logname, *opt_slow_logname; +char *opt_logname, *opt_slow_logname, *opt_bin_logname; /* Static variables */ @@ -677,7 +677,6 @@ static char **defaults_argv; static int remaining_argc; /** Remaining command line arguments (arguments), filtered by handle_options().*/ static char **remaining_argv; -static char *opt_bin_logname; int orig_argc; char **orig_argv; diff --git a/sql/mysqld.h b/sql/mysqld.h index fc9182ed02e..70089f56e4e 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -139,7 +139,8 @@ extern my_bool relay_log_recovery; extern uint test_flags,select_errors,ha_open_options; extern uint protocol_version, mysqld_port, dropping_tables; extern ulong delay_key_write_options; -extern char *opt_logname, *opt_slow_logname; +extern char *opt_logname, *opt_slow_logname, *opt_bin_logname, + *opt_relay_logname; extern char *opt_backup_history_logname, *opt_backup_progress_logname, *opt_backup_settings_name; extern const char *log_output_str;