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