1# See the file LICENSE for redistribution information. 2# 3# Copyright (c) 2002,2008 Oracle. All rights reserved. 4# 5# $Id: rep016.tcl,v 12.18 2008/01/08 20:58:53 bostic Exp $ 6# 7# TEST rep016 8# TEST Replication election test with varying required nvotes. 9# TEST 10# TEST Run a modified version of test001 in a replicated master environment; 11# TEST hold an election among a group of clients to make sure they select 12# TEST the master with varying required participants. 13 14proc rep016 { method args } { 15 global errorInfo 16 17 source ./include.tcl 18 if { $is_windows9x_test == 1 } { 19 puts "Skipping replication test on Win 9x platform." 20 return 21 } 22 set tnum "016" 23 24 # Skip for all methods except btree. 25 if { $checking_valid_methods } { 26 set test_methods { btree } 27 return $test_methods 28 } 29 if { [is_btree $method] == 0 } { 30 puts "Rep$tnum: Skipping for method $method." 31 return 32 } 33 34 set nclients 5 35 set logsets [create_logsets [expr $nclients + 1]] 36 37 # Run the body of the test with and without recovery. 38 foreach r $test_recopts { 39 foreach l $logsets { 40 set logindex [lsearch -exact $l "in-memory"] 41 if { $r == "-recover" && $logindex != -1 } { 42 puts "Rep$tnum: Skipping\ 43 for in-memory logs with -recover." 44 continue 45 } 46 puts "Rep$tnum ($method $r): \ 47 Replication elections with varying nvotes." 48 puts "Rep$tnum: Master logs are [lindex $l 0]" 49 for { set i 0 } { $i < $nclients } { incr i } { 50 puts "Rep$tnum: Client $i logs are\ 51 [lindex $l [expr $i + 1]]" 52 } 53 rep016_sub $method $nclients $tnum $l $r $args 54 } 55 } 56} 57 58proc rep016_sub { method nclients tnum logset recargs largs } { 59 source ./include.tcl 60 global rep_verbose 61 global verbose_type 62 63 set verbargs "" 64 if { $rep_verbose == 1 } { 65 set verbargs " -verbose {$verbose_type on} " 66 } 67 68 env_cleanup $testdir 69 70 set niter 5 71 set qdir $testdir/MSGQUEUEDIR 72 replsetup $qdir 73 74 set masterdir $testdir/MASTERDIR 75 file mkdir $masterdir 76 77 set m_logtype [lindex $logset 0] 78 set m_logargs [adjust_logargs $m_logtype] 79 set m_txnargs [adjust_txnargs $m_logtype] 80 81 for { set i 0 } { $i < $nclients } { incr i } { 82 set clientdir($i) $testdir/CLIENTDIR.$i 83 file mkdir $clientdir($i) 84 set c_logtype($i) [lindex $logset [expr $i + 1]] 85 set c_logargs($i) [adjust_logargs $c_logtype($i)] 86 set c_txnargs($i) [adjust_txnargs $c_logtype($i)] 87 } 88 89 # Open a master. 90 set envlist {} 91 repladd 1 92 set env_cmd(M) "berkdb_env_noerr -create -log_max 1000000 \ 93 -event rep_event \ 94 -home $masterdir $m_txnargs $m_logargs -rep_master $verbargs \ 95 -errpfx MASTER -rep_transport \[list 1 replsend\]" 96 set masterenv [eval $env_cmd(M) $recargs] 97 lappend envlist "$masterenv 1" 98 99 # Open the clients. 100 # Don't set -errfile now -- wait until the error catching 101 # portion of the test is complete. 102 for { set i 0 } { $i < $nclients } { incr i } { 103 set envid [expr $i + 2] 104 repladd $envid 105 set env_cmd($i) "berkdb_env_noerr -create -home $clientdir($i) \ 106 -event rep_event \ 107 $c_txnargs($i) $c_logargs($i) -rep_client $verbargs \ 108 -rep_transport \[list $envid replsend\]" 109 set clientenv($i) [eval $env_cmd($i) $recargs] 110 lappend envlist "$clientenv($i) $envid" 111 } 112 # Bring the clients online by processing the startup messages. 113 process_msgs $envlist 114 115 # Run a modified test001 in the master. 116 puts "\tRep$tnum.a: Running rep_test in replicated env." 117 eval rep_test $method $masterenv NULL $niter 0 0 0 0 $largs 118 process_msgs $envlist 119 error_check_good masterenv_close [$masterenv close] 0 120 set envlist [lreplace $envlist 0 0] 121 122 puts "\tRep$tnum.b: Error values for rep_elect" 123 # 124 # Do all the error catching in client0. We do not need to call 125 # start_election here to fork a process because we never get 126 # far enough to send/receive any messages. We just want to 127 # check the error message. 128 # 129 # !!! 130 # We cannot set -errpfx or -errfile or anything in the 131 # env_cmd above. Otherwise the correct output won't be set 132 # in 'ret' below and the test will fail. 133 # 134 # First check negative nvotes. 135 # 136 set nsites [expr $nclients + 1] 137 set priority 2 138 set timeout 5000000 139 # 140 # Setting nsites to 0 acts as a signal for rep_elect to use 141 # the configured nsites, but since we haven't set that yet, 142 # this should still fail. TODO: need another test verifying 143 # the proper operation when we *have* configured nsites. 144 # 145 set nsites 0 146 set nvotes 2 147 set res [catch {$clientenv(0) rep_elect $nsites $nvotes $priority \ 148 $timeout} ret] 149 error_check_bad catch $res 0 150 error_check_good ret [is_substr $ret "is larger than nsites"] 1 151 152 # 153 # Check nvotes > nsites. 154 # 155 set nsites $nclients 156 set nvotes [expr $nsites + 1] 157 set res [catch {$clientenv(0) rep_elect $nsites $nvotes $priority \ 158 $timeout} ret] 159 error_check_bad catch $res 0 160 error_check_good ret [is_substr $ret "is larger than nsites"] 1 161 162 for { set i 0 } { $i < $nclients } { incr i } { 163 replclear [expr $i + 2] 164 # 165 # This test doesn't use the testing hooks, so 166 # initialize err_cmd and crash appropriately. 167 # 168 set err_cmd($i) "none" 169 set crash($i) 0 170 # 171 # Initialize the array pri. We'll set it to 172 # appropriate values when the winner is determined. 173 # 174 set pri($i) 0 175 # 176 if { $rep_verbose == 1 } { 177 $clientenv($i) errpfx CLIENT.$i 178 $clientenv($i) verbose $verbose_type on 179 $clientenv($i) errfile /dev/stderr 180 set env_cmd($i) [concat $env_cmd($i) \ 181 "-errpfx CLIENT.$i -errfile /dev/stderr "] 182 } 183 } 184 set m "Rep$tnum.c" 185 puts "\t$m: Check single master/client can elect itself" 186 # 187 # 2 sites: 1 master, 1 client. Allow lone client to elect itself. 188 # Adjust client env list to reflect the single client. 189 # 190 set oldenvlist $envlist 191 set envlist [lreplace $envlist 1 end] 192 set nsites 2 193 set nvotes 1 194 set orig_ncl $nclients 195 set nclients 1 196 set elector 0 197 set winner 0 198 setpriority pri $nclients $winner 199 run_election env_cmd envlist err_cmd pri crash\ 200 $qdir $m $elector $nsites $nvotes $nclients $winner 1 test.db 201 202 # 203 # Now run with all clients. Client0 should always get elected 204 # because it became master and should have a bigger LSN. 205 # 206 set nclients $orig_ncl 207 set envlist [lreplace $oldenvlist 0 0 [lindex $envlist 0]] 208 209 set m "Rep$tnum.d" 210 puts "\t$m: Elect with 100% client participation" 211 set nsites $nclients 212 set nvotes $nclients 213 set winner [rep016_selectwinner $nsites $nvotes $nclients] 214 setpriority pri $nclients $winner 215 run_election env_cmd envlist err_cmd pri crash\ 216 $qdir $m $elector $nsites $nvotes $nclients $winner 1 test.db 217 218 # 219 # Elect with varying levels of participation. Start with nsites 220 # as nclients+1 (simulating a down master) and require nclients, 221 # and fewer (by 1) until we get down to 2 clients. 222 # 223 set m "Rep$tnum.e" 224 puts "\t$m: Elect with varying participation" 225 set nsites [expr $nclients + 1] 226 set count 0 227 for {set n $nclients} {$n > 1} {incr n -1} { 228 set m "Rep$tnum.e.$count" 229 set winner [rep016_selectwinner $nsites $n $n] 230 setpriority pri $nclients $winner 231 run_election env_cmd envlist err_cmd pri crash\ 232 $qdir $m $elector $nsites $n $n $winner 1 test.db 233 incr count 234 } 235 236 foreach pair $envlist { 237 set cenv [lindex $pair 0] 238 error_check_good cenv_close [$cenv close] 0 239 } 240 replclose $testdir/MSGQUEUEDIR 241} 242 243proc rep016_selectwinner { nsites nvotes nclients } { 244 # 245 # Special case: When we test with 100% participation, we expect 246 # client 0 to always win because it has a bigger LSN than the 247 # rest due to earlier part of the test. This special case is 248 # kinda gross. 249 # 250 if { $nsites != $nvotes } { 251 set win [berkdb random_int 0 [expr $nclients - 1]] 252 } else { 253 set win 0 254 } 255 return $win 256} 257