mariadb/mysql-test/include/rpl_generate_sync_chain.inc
Sven Sandberg 09c80e12c5 BUG#49978: Replication tests don't clean up replication state at the end
Major replication test framework cleanup. This does the following:
 - Ensure that all tests clean up the replication state when they
   finish, by making check-testcase check the output of SHOW SLAVE STATUS.
   This implies:
    - Slave must not be running after test finished. This is good
      because it removes the risk for sporadic errors in subsequent
      tests when a test forgets to sync correctly.
    - Slave SQL and IO errors must be cleared when test ends. This is
      good because we will notice if a test gets an unexpected error in
      the slave threads near the end.
    - We no longer have to clean up before a test starts.
 - Ensure that all tests that wait for an error in one of the slave
   threads waits for a specific error. It is no longer possible to
   source wait_for_slave_[sql|io]_to_stop.inc when there is an error
   in one of the slave threads. This is good because:
    - If a test expects an error but there is a bug that causes
      another error to happen, or if it stops the slave thread without
      an error, then we will notice.
    - When developing tests, wait_for_*_to_[start|stop].inc will fail
      immediately if there is an error in the relevant slave thread.
      Before this patch, we had to wait for the timeout.
 - Remove duplicated and repeated code for setting up unusual replication
   topologies. Now, there is a single file that is capable of setting
   up arbitrary topologies (include/rpl_init.inc, but
   include/master-slave.inc is still available for the most common
   topology). Tests can now end with include/rpl_end.inc, which will clean
   up correctly no matter what topology is used. The topology can be
   changed with include/rpl_change_topology.inc.
 - Improved debug information when tests fail. This includes:
    - debug info is printed on all servers configured by include/rpl_init.inc
    - User can set $rpl_debug=1, which makes auxiliary replication files
      print relevant debug info.
 - Improved documentation for all auxiliary replication files. Now they
   describe purpose, usage, parameters, and side effects.
 - Many small code cleanups:
    - Made have_innodb.inc output a sensible error message.
    - Moved contents of rpl000017-slave.sh into rpl000017.test
    - Added mysqltest variables that expose the current state of
      disable_warnings/enable_warnings and friends.
    - Too many to list here: see per-file comments for details.
2010-12-19 18:07:28 +01:00

122 lines
5.5 KiB
PHP

# ==== Purpose ====
#
# Setup $rpl_sync_chain, which is used by rpl_sync.inc. You normally
# don't need to source this file, it should only be sourced by
# rpl_sync.inc.
#
# $rpl_sync_chain is set to a string that specifies in what order
# servers should be synchronized in include/rpl_sync.inc. This has the
# form of a sequence of "chains" (with no separator between two
# chains). Each chain begins with $rpl_server_count_length space
# characters, followed by a sequence of numbers, each number
# whitespace-padded to $rpl_server_count_length characters. Each
# number in the sequence denotes a server, and the N'th server is a
# master of the (N+1)'th server. For example, if $rpl_topology is
# '1->2,2->3,3->1,2->4,5->6', then $rpl_sync_chain is ' 56 123124'.
#
#
# ==== Usage ====
#
# [--let $rpl_debug= 1]
# --source include/rpl_generate_sync_chain.inc
#
# Parameters:
# $rpl_debug
# See include/rpl_init.inc
--let $include_filename= rpl_generate_sync_chain.inc
--source include/begin_include_file.inc
# Algorithm:
# 0. Mark all servers as unseen and unsynced.
# 1. Let S be a server that is marked unseen.
# 2. Append S to the list of seen servers.
# 3. Check how S is marked:
# 3.1. If S has no master: append the list of seen servers (in
# order from grand-master to grand-slave) to the end of
# $rpl_sync_chain. Go to 3.
# 3.2. Elseif S is marked as synced: append the list of seen
# servers (in order from grand-master to grand-slave) to the
# end of $rpl_sync_chain. Go to 3.
# 3.3. Elseif S is marked as unsynced but seen: This means that the
# graph of visited servers has a "6-shape": it is a loop with
# a tail, such as 1->2->3->1->4->5. We should first sync the
# loop, and then the tail. To ensure all servers in the loop
# are synced, we must sync the loop two turns minus two
# servers. For example, the loop 1->2->3->4->5->1 is fully
# synced by this sequence of 1-step synchronizations:
# 1->2->3->4->5->1->2->3->4. Hence we do this: in the list of
# traversed servers (in order from grand-master to
# grand-slave), find the first occurrence of S. Take the
# sub-list starting at the 3rd server and ending at the first
# occurrence of S. Append this sub-list it to the end of
# $rpl_sync_chain. Then append the entire list of traversed
# servers (in order from grand-master to grand-slave) to
# $rpl_sync_chain. Go to 3.
# 3.4. Else (i.e., S has a master and is not marked as seen or
# synced): Mark S as seen. Set S=master(S) and go back to 2.
# 4. For each server that is marked as seen, mark it as synced.
# 5. If there are unseen servers, go back to 1.
# $_rpl_server_marks holds the marks of all servers. The i'th character
# corresponds to the mark of server i:
# '0' = unseen & unmarked, '1' = seen & unsynced, '2' = seen & synced.
--let $_rpl_server_marks= `SELECT REPEAT('0', $rpl_server_count)`
--let $_rpl_start_server= $rpl_server_count
--let $rpl_sync_chain=
while ($_rpl_start_server)
{
--let $_rpl_server= `SELECT RPAD('$_rpl_start_server', $rpl_server_count_length, ' ')`
--let $_rpl_seen_list=
--let $_rpl_continue_loop= 1
while ($_rpl_continue_loop)
{
--let $_rpl_master= `SELECT SUBSTRING('$rpl_master_list', 1 + ($_rpl_server - 1) * $rpl_server_count_length, $rpl_server_count_length)`
# We need to delimit elements of $_rpl_seen_list with commas, so
# that LOCATE() below will not find spurious matches that begin in
# the middle of one element and end in the middle of next element.
--let $_rpl_seen_list= $_rpl_server,$_rpl_seen_list
# If server is marked seen or synced, or has no master
if (`SELECT SUBSTRING('$_rpl_server_marks', $_rpl_server, 1) != 0 OR '$_rpl_master' = ''`)
{
# If server is marked seen but not synced.
if (`SELECT SUBSTRING('$_rpl_server_marks', $_rpl_server, 1) = 1`)
{
# Get sub-list of servers to prepend to server list.
# E.g., if topology is 1->2->3->4->1->5, then at this point
# $_rpl_seen_list='1,2,3,4,1,5,' and we have to prepend '4,3,'
# to it. Hence, the sub-list starts at position
# 1+2*($rpl_server_count_length+1) and ends at the first
# occurrence of ',1,' in the list.
--let $_rpl_extra_list= `SELECT SUBSTRING('$_rpl_seen_list', 1 + 2 * ($rpl_server_count_length + 1), LOCATE(',$_rpl_server,', '$_rpl_seen_list') - 2 * ($rpl_server_count_length + 1))`
--let $_rpl_seen_list= $_rpl_extra_list$_rpl_seen_list
}
# Append the seen servers. Only need to append if the list
# contains at least two elements.
if (`SELECT LENGTH('$_rpl_seen_list') > $rpl_server_count_length + 1`)
{
--let $rpl_sync_chain= $rpl_sync_chain$_rpl_no_server$_rpl_seen_list
}
--let $_rpl_continue_loop= 0
}
--let $_rpl_server_marks= `SELECT INSERT('$_rpl_server_marks', $_rpl_server, 1, '1')`
--let $_rpl_server= $_rpl_master
}
# Mark seen servers as synced
--let $_rpl_server_marks= `SELECT REPLACE('$_rpl_server_marks', '1', '2')`
# Get highest-numbered unmarked server.
--let $_rpl_start_server= `SELECT IFNULL(NULLIF($rpl_server_count + 1 - LOCATE('0', REVERSE('$_rpl_server_marks')), $rpl_server_count + 1), 0)`
}
# Strip commas: they were only needed temporarily.
--let $rpl_sync_chain= `SELECT REPLACE('$rpl_sync_chain', ',', '')`
if ($rpl_debug)
{
--echo Generated \$rpl_sync_chain = '$rpl_sync_chain'
}
--let $include_filename= rpl_generate_sync_chain.inc
--source include/end_include_file.inc