1# ==== Purpose ==== 2# 3# Changes replication topology. This file is normally sourced from 4# include/rpl_init.inc, but test cases can also source it if they 5# need to change topology after they have sourced include/rpl_init.inc 6# 7# This file sets up variables needed by include/rpl_sync.inc and many 8# other replication scripts in the include/ directory. It also issues 9# CHANGE MASTER on all servers where the configuration changes from 10# what it was before. It does not issue START SLAVE (use 11# include/rpl_start_slaves.inc for that). 12# 13# Note: it is not currently possible to change the number of servers 14# after the rpl_init.inc, without first calling rpl_end.inc. So the 15# test has to set $rpl_server_count to the total number of servers 16# that the test uses, before it sources include/rpl_init.inc. After 17# that, $rpl_server_count must not change until after next time the 18# test sources include/rpl_end.inc. 19# 20# Note: Since this script issues CHANGE MASTER, the test case must 21# ensure that all slaves where the configuration changes have stopped 22# both the IO thread and the SQL thread before this script is sourced. 23# 24# 25# ==== Usage ==== 26# 27# [--let $rpl_server_count= 7] 28# --let $rpl_topology= 1->2->3->1->4, 2->5, 6->7 29# [--let $rpl_skip_change_master= 1] 30# [--let $rpl_master_log_file= 1:master-bin.000001,3:master-bin.000003] 31# [--let $rpl_master_log_pos= 1:4711,3:107] 32# [--let $rpl_debug= 1] 33# --source include/rpl_change_topology.inc 34# 35# Parameters: 36# $rpl_master_log_file 37# By default, CHANGE MASTER is executed with MASTER_LOG_FILE set 38# to the name of the last binlog file on the master (retrieved by 39# executing SHOW MASTER STATUS). This variable can be set to 40# specify another filename. This variable should be a 41# comma-separated list of the following form: 42# 43# SERVER_NUMBER_1:FILE_NAME_1,SERVER_NUMBER_2:FILE_NAME_2,... 44# 45# Before CHANGE MASTER is executed on server N, this script checks 46# if $rpl_master_log_file contains the text N:FILE_NAME. If it 47# does, then MASTER_LOG_FILE is set to FILE_NAME. Otherwise, 48# MASTER_LOG_FILE is set to the last binlog on the master. For 49# example, to specify that server_1 should start replicate from 50# master-bin.000007 and server_5 should start replicate from 51# master-bin.012345, do: 52# --let $rpl_master_log_file= 1:master-bin.000007,5:master-bin.012345 53# 54# $rpl_master_log_pos 55# By default, CHANGE MASTER is executed without specifying the 56# MASTER_LOG_POS parameter. This variable can be set to set a 57# specific position. It has the same form as $rpl_master_log_file 58# (see above). For example, to specify that server_3 should start 59# replicate from position 4711 of its master, do: 60# --let $rpl_master_log_pos= 3:4711 61# 62# $rpl_server_count, $rpl_topology, $rpl_debug, $rpl_skip_change_master 63# See include/rpl_init.inc 64# 65# 66# ==== Internal variables configured by this file ==== 67# 68# This file sets up the following variables, which are used by other 69# low-level replication files such as: 70# include/rpl_sync.inc 71# include/rpl_start_slaves.inc 72# include/rpl_stop_slaves.inc 73# include/rpl_end.inc 74# 75# $rpl_server_count_length: 76# Set to LENGTH($rpl_server_count). So if $rpl_server_count < 10, 77# then $rpl_server_count_length = 1; if 10 <= $rpl_server_count < 78# 100, then $rpl_server_count_length = 2, etc. 79# 80# $rpl_master_list 81# Set to a string consisting of $rpl_server_count numbers, each one 82# whitespace-padded to $rpl_server_count_length characters. If 83# server N is a slave, then the N'th number is the master of server 84# N. If server N is not a slave, then the N'th number is just spaces 85# (so in fact it is not a number). For example, if $rpl_topology is 86# '1->2,2->3,3->1,2->4,5->6', then $rpl_master_list is '3122 6'. 87# 88# $rpl_sync_chain_dirty 89# This variable is set to 1. This tells include/rpl_sync.inc to 90# compute a new value for $rpl_sync_chain next time that 91# include/rpl_sync.inc is sourced. See 92# include/rpl_generate_sync_chain.inc and include/rpl_sync.inc for 93# details. 94 95 96# Remove whitespace from $rpl_topology 97--let $rpl_topology= `SELECT REPLACE('$rpl_topology', ' ', '')` 98 99--let $include_filename= rpl_change_topology.inc [new topology=$rpl_topology] 100--source include/begin_include_file.inc 101 102 103if ($rpl_debug) 104{ 105 --echo ---- Check input ---- 106} 107 108 109if (`SELECT '$rpl_topology' = '' OR '$rpl_server_count' = ''`) 110{ 111 --die You must set $rpl_topology and $rpl_server_count before you source rpl_change_topology.inc. If you really want to change to the empty topology, set $rpl_topology= none 112} 113--let $_rpl_topology= $rpl_topology 114if ($_rpl_topology == 'none') 115{ 116 --let $_rpl_topology= 117} 118if ($rpl_master_list == '') 119{ 120 --die You must source include/rpl_init.inc before you source include/rpl_change_topology.inc 121} 122--let $_rpl_old_master_list= $rpl_master_list 123 124if ($rpl_debug) 125{ 126 --echo \$rpl_server_count='$rpl_server_count' 127 --echo \$rpl_server_count_length='$rpl_server_count_length' 128 --echo new \$rpl_topology='$_rpl_topology' 129 --echo old \$rpl_master_list='$rpl_master_list' 130 --echo old \$rpl_sync_chain='$rpl_sync_chain' 131} 132 133 134if ($rpl_debug) 135{ 136 --echo ---- Generate \$rpl_server_count_length and \$rpl_master_list ---- 137} 138 139--let $rpl_server_count_length= `SELECT LENGTH('$rpl_server_count')` 140--let $rpl_master_list= 141--let $_rpl_no_server= `SELECT REPEAT(' ', $rpl_server_count_length)` 142--let $rpl_master_list= `SELECT REPEAT('$_rpl_no_server', $rpl_server_count)` 143while ($_rpl_topology) 144{ 145 # Get 's1->s2' from 's1->s2->s3->...' or from 's1->s2,s3->s4,...' 146 --let $_rpl_master_slave= `SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('$_rpl_topology', ',', 1), '->', 2)` 147 # Modify $_rpl_topology as follows: 148 # - If it starts with 's1->s2,', remove 's1->s2,' 149 # - If it starts with 's1->s2->', remove 's1->' 150 # - If it is equal to 's1->s2', remove 's1->s2' 151 --let $_rpl_topology= `SELECT SUBSTR('$_rpl_topology', IF(SUBSTR('$_rpl_topology', LENGTH('$_rpl_master_slave') + 1, 2) != '->', LENGTH('$_rpl_master_slave'), LOCATE('->', '$_rpl_master_slave')) + 2)` 152 # Get 's1' from 's1->s2' 153 --let $_rpl_master= `SELECT SUBSTRING_INDEX('$_rpl_master_slave', '->', 1)` 154 # Get 's2' from 's1->s2' 155 --let $_rpl_slave= `SELECT SUBSTRING('$_rpl_master_slave', LENGTH('$_rpl_master') + 3)` 156 # Check that s2 does not have another master. 157 if (`SELECT SUBSTR('$rpl_master_list', 1 + ($_rpl_slave - 1) * $rpl_server_count_length, $rpl_server_count_length) != '$_rpl_no_server'`) 158 { 159 --echo ERROR IN TEST: Server '$_rpl_slave' has more than one master in topology '$rpl_topology' 160 --die ERROR IN TEST: found a server with more than one master in the $rpl_topology variable 161 } 162 # Save 's1' at position 's2' in $rpl_master_list 163 --let $rpl_master_list= `SELECT INSERT('$rpl_master_list', 1 + ($_rpl_slave - 1) * $rpl_server_count_length, $rpl_server_count_length, RPAD('$_rpl_master', $rpl_server_count_length, ' '))` 164} 165 166if ($rpl_debug) 167{ 168 --echo new \$rpl_server_count_length = '$rpl_server_count_length' 169 --echo new \$rpl_master_list = '$rpl_master_list' 170} 171 172if (!$rpl_skip_change_master) 173{ 174 if ($rpl_debug) 175 { 176 --echo ---- Execute CHANGE MASTER on all servers ---- 177 } 178 179 if (!$rpl_debug) 180 { 181 --disable_query_log 182 } 183 184 --let $_rpl_server= $rpl_server_count 185 while ($_rpl_server) 186 { 187 # The following statement evaluates to: 188 # 0, if server_$_rpl_server has the same master as before. 189 # The master's server, if server_$_rpl_server is a slave. 190 # The empty string, if server_$_rpl_server is not a slave. 191 --let $_rpl_master= `SELECT TRIM(IFNULL(NULLIF(SUBSTRING('$rpl_master_list', 1 + ($_rpl_server - 1) * $rpl_server_count_length, $rpl_server_count_length), SUBSTRING('$_rpl_old_master_list', 1 + ($_rpl_server - 1) * $rpl_server_count_length, $rpl_server_count_length)), 0))` 192 if ($rpl_debug) 193 { 194 --echo \$_rpl_server='$_rpl_server' \$_rpl_master='$_rpl_master' 195 } 196 if ($_rpl_master) 197 { 198 # Get port number 199 --let $_rpl_port= \$SERVER_MYPORT_$_rpl_master 200 # Get MASTER_LOG_FILE 201 --let $_rpl_master_log_file_index= `SELECT LOCATE('$_rpl_server:', '$rpl_master_log_file')` 202 if ($_rpl_master_log_file_index) 203 { 204 # Get text from after ':' and before ',', starting at 205 # $_rpl_master_log_file 206 --let $_rpl_master_log_file= `SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING('$rpl_master_log_file', $_rpl_master_log_file_index), ',', 1), ':', -1)` 207 } 208 if (!$_rpl_master_log_file_index) 209 { 210 --let $rpl_connection_name= server_$_rpl_master 211 --source include/rpl_connection.inc 212 --let $_rpl_master_log_file= query_get_value(SHOW MASTER STATUS, File, 1) 213 } 214 # Change connection. 215 --let $rpl_connection_name= server_$_rpl_server 216 --source include/rpl_connection.inc 217 # Get MASTER_LOG_POS 218 --let $_rpl_master_log_pos_index= `SELECT LOCATE('$_rpl_server:', '$rpl_master_log_pos')` 219 if ($_rpl_master_log_pos_index) 220 { 221 --let $_rpl_master_log_pos= `SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING('$rpl_master_log_pos', $_rpl_master_log_pos_index), ',', 1), ':', -1)` 222 --let $_rpl_master_log_pos= , MASTER_LOG_POS = $_rpl_master_log_pos 223 } 224 if (!$_rpl_master_log_pos_index) 225 { 226 --let $_rpl_master_log_pos= 227 } 228 eval CHANGE MASTER TO MASTER_HOST = '127.0.0.1', MASTER_PORT = $_rpl_port, MASTER_USER = 'root', MASTER_LOG_FILE = '$_rpl_master_log_file'$_rpl_master_log_pos, MASTER_CONNECT_RETRY = 1; 229 } 230 if ($_rpl_master == '') 231 { 232 # This un-configures the server so that it's not a slave. 233 # After BUG#28796, such configuration is not possible any more. 234 #--let $rpl_connection_name= server_$_rpl_server 235 #--source include/rpl_connection.inc 236 #CHANGE MASTER TO MASTER_HOST = ''; 237 } 238 --dec $_rpl_server 239 } 240} 241 242 243--let $rpl_sync_chain_dirty= 1 244 245 246--let $include_filename= rpl_change_topology.inc 247--source include/end_include_file.inc 248