MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
rpl_change_topology.inc
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 $use_gtids= 1]
30 # [--let $rpl_skip_change_master= 1]
31 # [--let $rpl_master_log_file= 1:master-bin.000001,3:master-bin.000003]
32 # [--let $rpl_master_log_pos= 1:4711,3:107]
33 # [--let $rpl_debug= 1]
34 # [--let $rpl_unconditional_change_master= 1]
35 # --source include/rpl_change_topology.inc
36 #
37 # Parameters:
38 # $use_gtids
39 # Use option MASTER_AUTO_POSITION = 1 to CHANGE MASTER.
40 #
41 # $rpl_master_log_file
42 # By default, CHANGE MASTER is executed with MASTER_LOG_FILE set
43 # to the name of the last binlog file on the master (retrieved by
44 # executing SHOW MASTER STATUS). This variable can be set to
45 # specify another filename. This variable should be a
46 # comma-separated list of the following form:
47 #
48 # SERVER_NUMBER_1:FILE_NAME_1,SERVER_NUMBER_2:FILE_NAME_2,...
49 #
50 # Before CHANGE MASTER is executed on server N, this script checks
51 # if $rpl_master_log_file contains the text N:FILE_NAME. If it
52 # does, then MASTER_LOG_FILE is set to FILE_NAME. Otherwise,
53 # MASTER_LOG_FILE is set to the last binlog on the master. For
54 # example, to specify that server_1 should start replicate from
55 # master-bin.000007 and server_5 should start replicate from
56 # master-bin.012345, do:
57 # --let $rpl_master_log_file= 1:master-bin.000007,5:master-bin.012345
58 #
59 # $rpl_master_log_pos
60 # By default, CHANGE MASTER is executed without specifying the
61 # MASTER_LOG_POS parameter. This variable can be set to set a
62 # specific position. It has the same form as $rpl_master_log_file
63 # (see above). For example, to specify that server_3 should start
64 # replicate from position 4711 of its master, do:
65 # --let $rpl_master_log_pos= 3:4711
66 #
67 # $rpl_unconditional_change_master
68 # This script remembers the topology set by previous invokations
69 # of either rpl_init.inc or of this script. By default, this
70 # script only executes CHANGE MASTER on servers that actually have
71 # a new master. If $rpl_unconditiona_change_master is set, then
72 # this script unconditionally executes CHANGE MASTER on all
73 # servers that have a master. This is useful either if you have
74 # changed the topology without invoking the scripts or if you want
75 # to set some other parameters of CHANGE MASTER.
76 #
77 # $rpl_server_count, $rpl_topology, $rpl_debug, $rpl_skip_change_master
78 # See include/rpl_init.inc
79 #
80 #
81 # ==== Internal variables configured by this file ====
82 #
83 # This file sets up the following variables, which are used by other
84 # low-level replication files such as:
85 # include/rpl_sync.inc
86 # include/rpl_start_slaves.inc
87 # include/rpl_stop_slaves.inc
88 # include/rpl_end.inc
89 #
90 # $rpl_server_count_length:
91 # Set to LENGTH($rpl_server_count). So if $rpl_server_count < 10,
92 # then $rpl_server_count_length = 1; if 10 <= $rpl_server_count <
93 # 100, then $rpl_server_count_length = 2, etc.
94 #
95 # $rpl_master_list
96 # Set to a string consisting of $rpl_server_count numbers, each one
97 # whitespace-padded to $rpl_server_count_length characters. If
98 # server N is a slave, then the N'th number is the master of server
99 # N. If server N is not a slave, then the N'th number is just spaces
100 # (so in fact it is not a number). For example, if $rpl_topology is
101 # '1->2,2->3,3->1,2->4,5->6', then $rpl_master_list is '3122 6'.
102 #
103 # $rpl_sync_chain_dirty
104 # This variable is set to 1. This tells include/rpl_sync.inc to
105 # compute a new value for $rpl_sync_chain next time that
106 # include/rpl_sync.inc is sourced. See
107 # include/rpl_generate_sync_chain.inc and include/rpl_sync.inc for
108 # details.
109 
110 
111 # Remove whitespace from $rpl_topology
112 --let $rpl_topology= `SELECT REPLACE('$rpl_topology', ' ', '')`
113 
114 --let $include_filename= rpl_change_topology.inc [new topology=$rpl_topology]
115 --source include/begin_include_file.inc
116 
117 
118 if ($rpl_debug)
119 {
120  --echo ---- Check input ----
121 }
122 
123 
124 if (`SELECT '$rpl_topology' = '' OR '$rpl_server_count' = ''`)
125 {
126  --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
127 }
128 --let $_rpl_topology= $rpl_topology
129 if ($_rpl_topology == 'none')
130 {
131  --let $_rpl_topology=
132 }
133 if ($rpl_master_list == '')
134 {
135  --die You must source include/rpl_init.inc before you source include/rpl_change_topology.inc
136 }
137 --let $_rpl_old_master_list= $rpl_master_list
138 
139 if ($rpl_debug)
140 {
141  --echo \$rpl_server_count='$rpl_server_count'
142  --echo \$rpl_server_count_length='$rpl_server_count_length'
143  --echo new \$rpl_topology='$_rpl_topology'
144  --echo old \$rpl_master_list='$rpl_master_list'
145  --echo old \$rpl_sync_chain='$rpl_sync_chain'
146 }
147 
148 
149 if ($rpl_debug)
150 {
151  --echo ---- Generate \$rpl_server_count_length and \$rpl_master_list ----
152 }
153 
154 --let $rpl_server_count_length= `SELECT LENGTH('$rpl_server_count')`
155 --let $rpl_master_list=
156 --let $_rpl_no_server= `SELECT REPEAT(' ', $rpl_server_count_length)`
157 --let $rpl_master_list= `SELECT REPEAT('$_rpl_no_server', $rpl_server_count)`
158 while ($_rpl_topology)
159 {
160  # Get 's1->s2' from 's1->s2->s3->...' or from 's1->s2,s3->s4,...'
161  --let $_rpl_master_slave= `SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('$_rpl_topology', ',', 1), '->', 2)`
162  # Modify $_rpl_topology as follows:
163  # - If it starts with 's1->s2,', remove 's1->s2,'
164  # - If it starts with 's1->s2->', remove 's1->'
165  # - If it is equal to 's1->s2', remove 's1->s2'
166  --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)`
167  # Get 's1' from 's1->s2'
168  --let $_rpl_master= `SELECT SUBSTRING_INDEX('$_rpl_master_slave', '->', 1)`
169  # Get 's2' from 's1->s2'
170  --let $_rpl_slave= `SELECT SUBSTRING('$_rpl_master_slave', LENGTH('$_rpl_master') + 3)`
171  # Check that s2 does not have another master.
172  if (`SELECT SUBSTR('$rpl_master_list', 1 + ($_rpl_slave - 1) * $rpl_server_count_length, $rpl_server_count_length) != '$_rpl_no_server'`)
173  {
174  --echo ERROR IN TEST: Server '$_rpl_slave' has more than one master in topology '$rpl_topology'
175  --die ERROR IN TEST: found a server with more than one master in the $rpl_topology variable
176  }
177  # Save 's1' at position 's2' in $rpl_master_list
178  --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, ' '))`
179 }
180 
181 if ($rpl_debug)
182 {
183  --echo new \$rpl_server_count_length = '$rpl_server_count_length'
184  --echo new \$rpl_master_list = '$rpl_master_list'
185 }
186 
187 if (!$rpl_skip_change_master)
188 {
189  if ($rpl_debug)
190  {
191  --echo ---- Execute CHANGE MASTER on all servers ----
192  }
193 
194  if (!$rpl_debug)
195  {
196  --disable_query_log
197  }
198 
199  --let $_rpl_server= $rpl_server_count
200  while ($_rpl_server)
201  {
202  if (!$rpl_unconditional_change_master)
203  {
204  # The following statement evaluates to:
205  # - The master server, if we need to execute CHANGE MASTER on
206  # server_$_rpl_server.
207  # - The empty string otherwise; i.e., if server_$_rpl_server is
208  # not a slave or if server_$_rpl_server has the same master
209  # as before.
210  let $_rpl_master=
211  `SELECT TRIM(IFNULL(NULLIF(
212  SUBSTRING('$rpl_master_list',
213  1 + ($_rpl_server - 1) * $rpl_server_count_length,
214  $rpl_server_count_length),
215  SUBSTRING('$_rpl_old_master_list',
216  1 + ($_rpl_server - 1) * $rpl_server_count_length,
217  $rpl_server_count_length)
218  ), ''))`;
219  }
220  if ($rpl_unconditional_change_master)
221  {
222  # The following statement evaluates to the master server, or to
223  # the empty string if the server_$_rpl_server is not a slave.
224  let $_rpl_master= `SELECT TRIM(
225  SUBSTRING('$rpl_master_list',
226  1 + ($_rpl_server - 1) * $rpl_server_count_length,
227  $rpl_server_count_length)
228  )`;
229  }
230  if ($rpl_debug)
231  {
232  --echo \$_rpl_server='$_rpl_server' \$_rpl_master='$_rpl_master'
233  }
234  if ($_rpl_master != '')
235  {
236  # Get port number
237  --let $_rpl_port= \$SERVER_MYPORT_$_rpl_master
238  if ($use_gtids)
239  {
240  --let $_rpl_change_master_position= MASTER_AUTO_POSITION = 1
241  --let $rpl_connection_name= server_$_rpl_server
242  --source include/rpl_connection.inc
243  }
244  if (!$use_gtids)
245  {
246  # Get MASTER_LOG_FILE
247  --let $_rpl_master_log_file_index= `SELECT LOCATE('$_rpl_server:', '$rpl_master_log_file')`
248  if ($_rpl_master_log_file_index)
249  {
250  # Get text from after ':' and before ',', starting at
251  # $_rpl_master_log_file
252  --let $_rpl_master_log_file= `SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING('$rpl_master_log_file', $_rpl_master_log_file_index), ',', 1), ':', -1)`
253  }
254  if (!$_rpl_master_log_file_index)
255  {
256  --let $rpl_connection_name= server_$_rpl_master
257  --source include/rpl_connection.inc
258  --let $_rpl_master_log_file= query_get_value(SHOW MASTER STATUS, File, 1)
259  }
260  --let $_rpl_change_master_position= MASTER_LOG_FILE = '$_rpl_master_log_file'
261  # Change connection.
262  --let $rpl_connection_name= server_$_rpl_server
263  --source include/rpl_connection.inc
264  # Get MASTER_LOG_POS
265  --let $_rpl_master_log_pos_index= `SELECT LOCATE('$_rpl_server:', '$rpl_master_log_pos')`
266  if ($_rpl_master_log_pos_index)
267  {
268  --let $_rpl_master_log_pos= `SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING('$rpl_master_log_pos', $_rpl_master_log_pos_index), ',', 1), ':', -1)`
269  --let $_rpl_change_master_position= $_rpl_change_master_position, MASTER_LOG_POS = $_rpl_master_log_pos
270  }
271  }
272  --replace_regex /[0-9]{4}/####/
273  eval CHANGE MASTER TO MASTER_HOST = '127.0.0.1', MASTER_PORT = $_rpl_port, MASTER_USER = 'root', $_rpl_change_master_position, MASTER_CONNECT_RETRY = 1;
274  }
275  if ($_rpl_master == '')
276  {
277  # This un-configures the server so that it's not a slave.
278  # After BUG#28796, such configuration is not possible any more.
279  #--let $rpl_connection_name= server_$_rpl_server
280  #--source include/rpl_connection.inc
281  #CHANGE MASTER TO MASTER_HOST = '';
282  }
283  --dec $_rpl_server
284  }
285 }
286 
287 
288 --let $rpl_sync_chain_dirty= 1
289 
290 
291 --let $include_filename= rpl_change_topology.inc
292 --source include/end_include_file.inc