1# See the file LICENSE for redistribution information. 2# 3# Copyright (c) 2001-2009 Oracle. All rights reserved. 4# 5# $Id$ 6# 7# TEST rep012 8# TEST Replication and dead DB handles. 9# TEST 10# TEST Run a modified version of test001 in a replicated master env. 11# TEST Run in replicated environment with secondary indices too. 12# TEST Make additional changes to master, but not to the client. 13# TEST Downgrade the master and upgrade the client with open db handles. 14# TEST Verify that the roll back on clients gives dead db handles. 15proc rep012 { method { niter 10 } { tnum "012" } args } { 16 17 source ./include.tcl 18 global databases_in_memory 19 global repfiles_in_memory 20 21 if { $is_windows9x_test == 1 } { 22 puts "Skipping replication test on Win 9x platform." 23 return 24 } 25 26 # Run for all access methods. 27 if { $checking_valid_methods } { 28 return "ALL" 29 } 30 31 set args [convert_args $method $args] 32 set logsets [create_logsets 3] 33 34 set msg "using on-disk databases" 35 if { $databases_in_memory } { 36 set msg "using named in-memory databases" 37 if { [is_queueext $method] } { 38 puts -nonewline "Skipping rep$tnum for method " 39 puts "$method with named in-memory databases." 40 return 41 } 42 } 43 44 set msg2 "and on-disk replication files" 45 if { $repfiles_in_memory } { 46 set msg2 "and in-memory replication files" 47 } 48 49 # Run the body of the test with and without recovery. 50 foreach r $test_recopts { 51 foreach l $logsets { 52 set logindex [lsearch -exact $l "in-memory"] 53 if { $r == "-recover" && $logindex != -1 } { 54 puts "Rep$tnum: Skipping\ 55 for in-memory logs with -recover." 56 continue 57 } 58 puts "Rep$tnum ($method $r):\ 59 Replication and dead db handles $msg $msg2." 60 puts "Rep$tnum: Master logs are [lindex $l 0]" 61 puts "Rep$tnum: Client 0 logs are [lindex $l 1]" 62 puts "Rep$tnum: Client 1 logs are [lindex $l 2]" 63 rep012_sub $method $niter $tnum $l $r $args 64 } 65 } 66} 67 68proc rep012_sub { method niter tnum logset recargs largs } { 69 global testdir 70 global databases_in_memory 71 global repfiles_in_memory 72 global verbose_check_secondaries 73 global rep_verbose 74 global verbose_type 75 76 set verbargs "" 77 if { $rep_verbose == 1 } { 78 set verbargs " -verbose {$verbose_type on} " 79 } 80 81 set repmemargs "" 82 if { $repfiles_in_memory } { 83 set repmemargs "-rep_inmem_files " 84 } 85 86 env_cleanup $testdir 87 set orig_tdir $testdir 88 89 replsetup $testdir/MSGQUEUEDIR 90 91 set masterdir $testdir/MASTERDIR 92 set clientdir $testdir/CLIENTDIR 93 set clientdir2 $testdir/CLIENTDIR.2 94 file mkdir $masterdir 95 file mkdir $clientdir 96 file mkdir $clientdir2 97 98 set m_logtype [lindex $logset 0] 99 set c_logtype [lindex $logset 1] 100 set c2_logtype [lindex $logset 2] 101 102 # In-memory logs require a large log buffer, and cannot 103 # be used with -txn nosync. 104 set m_logargs [adjust_logargs $m_logtype] 105 set c_logargs [adjust_logargs $c_logtype] 106 set c2_logargs [adjust_logargs $c2_logtype] 107 set m_txnargs [adjust_txnargs $m_logtype] 108 set c_txnargs [adjust_txnargs $c_logtype] 109 set c2_txnargs [adjust_txnargs $c2_logtype] 110 111 # Open a master. 112 repladd 1 113 set ma_envcmd "berkdb_env_noerr -create $m_txnargs \ 114 $m_logargs -errpfx ENV0 $verbargs $repmemargs \ 115 -home $masterdir -rep_transport \[list 1 replsend\]" 116 set env0 [eval $ma_envcmd $recargs -rep_master] 117 set masterenv $env0 118 119 # Open two clients 120 repladd 2 121 set cl_envcmd "berkdb_env_noerr -create $c_txnargs \ 122 $c_logargs -errpfx ENV1 $verbargs $repmemargs \ 123 -home $clientdir -rep_transport \[list 2 replsend\]" 124 set env1 [eval $cl_envcmd $recargs -rep_client] 125 set clientenv $env1 126 127 repladd 3 128 set cl2_envcmd "berkdb_env_noerr -create $c2_txnargs \ 129 $c2_logargs -errpfx ENV2 $verbargs $repmemargs \ 130 -home $clientdir2 -rep_transport \[list 3 replsend\]" 131 set cl2env [eval $cl2_envcmd $recargs -rep_client] 132 133 if { $databases_in_memory } { 134 set testfile { "" test$tnum.db } 135 set pname { "" primary$tnum.db } 136 set sname { "" secondary$tnum.db } 137 } else { 138 set testfile "test$tnum.db" 139 set pname "primary$tnum.db" 140 set sname "secondary$tnum.db" 141 } 142 set omethod [convert_method $method] 143 set env0db [eval {berkdb_open_noerr -env $env0 -auto_commit \ 144 -create -mode 0644} $largs $omethod $testfile] 145 error_check_good dbopen [is_valid_db $env0db] TRUE 146 set masterdb $env0db 147 148 set do_secondary 0 149 if { [is_btree $method] || [is_hash $method] } { 150 set do_secondary 1 151 # Open the primary 152 set mpdb [eval {berkdb_open_noerr -env $env0 -auto_commit \ 153 -create -mode 0644} $largs $omethod $pname] 154 error_check_good dbopen [is_valid_db $mpdb] TRUE 155 156 # Open the secondary 157 # Open a 2nd handle to the same secondary 158 set msdb [eval {berkdb_open_noerr -env $env0 -auto_commit \ 159 -create -mode 0644} $largs $omethod $sname] 160 error_check_good dbopen [is_valid_db $msdb] TRUE 161 error_check_good associate [$mpdb associate \ 162 [callback_n 0] $msdb] 0 163 } 164 165 # Bring the clients online by processing the startup messages. 166 set envlist "{$env0 1} {$env1 2} {$cl2env 3}" 167 process_msgs $envlist 168 169 set env1db [eval {berkdb_open_noerr -env $env1 -auto_commit \ 170 -mode 0644} $largs $omethod $testfile] 171 set clientdb $env1db 172 error_check_good dbopen [is_valid_db $env1db] TRUE 173 set env2db [eval {berkdb_open_noerr -env $cl2env -auto_commit \ 174 -mode 0644} $largs $omethod $testfile] 175 error_check_good dbopen [is_valid_db $env2db] TRUE 176 177 # Run a modified test001 in the master (and update clients). 178 puts "\tRep$tnum.a.0: Running rep_test in replicated env." 179 eval rep_test $method $masterenv $masterdb $niter 0 0 0 $largs 180 process_msgs $envlist 181 182 if { $do_secondary } { 183 # Put some data into the primary 184 puts "\tRep$tnum.a.1: Putting primary/secondary data on master." 185 eval rep012_sec $method $mpdb $niter keys data 186 process_msgs $envlist 187 188 set verbose_check_secondaries 1 189 check_secondaries $mpdb $msdb $niter keys data "Rep$tnum.b" 190 } else { 191 puts "\tRep$tnum.b: Skipping secondaries for method $method" 192 } 193 194 # Check that databases are in-memory or on-disk as expected. 195 # We can only check the secondaries if secondaries are allowed for 196 # this access method. 197 set names [list $testfile] 198 if { $do_secondary } { 199 lappend names $pname $sname 200 } 201 foreach name $names { 202 eval check_db_location $masterenv $name 203 eval check_db_location $clientenv $name 204 eval check_db_location $cl2env $name 205 } 206 207 puts "\tRep$tnum.c: Run test in master and client 2 only" 208 set nstart $niter 209 eval rep_test\ 210 $method $masterenv $masterdb $niter $nstart $nstart 0 $largs 211 212 # Ignore messages for $env1. 213 set envlist "{$env0 1} {$cl2env 3}" 214 process_msgs $envlist 215 216 # Nuke those for client about to become master. 217 replclear 2 218 tclsleep 3 219 puts "\tRep$tnum.d: Swap envs" 220 set tmp $masterenv 221 set masterenv $clientenv 222 set clientenv $tmp 223 error_check_good downgrade [$clientenv rep_start -client] 0 224 error_check_good upgrade [$masterenv rep_start -master] 0 225 set envlist "{$env0 1} {$env1 2} {$cl2env 3}" 226 process_msgs $envlist 227 228 # 229 # At this point, env0 should have rolled back across a txn commit. 230 # If we do any operation on env0db, we should get an error that 231 # the handle is dead. 232 puts "\tRep$tnum.e: Try to access db handle after rollback" 233 set stat1 [catch {$env0db stat} ret1] 234 error_check_good stat1 $stat1 1 235 error_check_good dead1 [is_substr $ret1 DB_REP_HANDLE_DEAD] 1 236 237 set stat3 [catch {$env2db stat} ret3] 238 error_check_good stat3 $stat3 1 239 error_check_good dead3 [is_substr $ret3 DB_REP_HANDLE_DEAD] 1 240 241 if { $do_secondary } { 242 # 243 # Check both secondary get and close to detect DEAD_HANDLE. 244 # 245 puts "\tRep$tnum.f: Try to access secondary db handles after rollback" 246 set verbose_check_secondaries 1 247 check_secondaries $mpdb $msdb $niter \ 248 keys data "Rep$tnum.f" errp errs errsg 249 error_check_good deadp [is_substr $errp DB_REP_HANDLE_DEAD] 1 250 error_check_good deads [is_substr $errs DB_REP_HANDLE_DEAD] 1 251 error_check_good deadsg [is_substr $errsg DB_REP_HANDLE_DEAD] 1 252 puts "\tRep$tnum.g: Closing" 253 error_check_good mpdb [$mpdb close] 0 254 error_check_good msdb [$msdb close] 0 255 } else { 256 puts "\tRep$tnum.f: Closing" 257 } 258 259 error_check_good env0db [$env0db close] 0 260 error_check_good env1db [$env1db close] 0 261 error_check_good cl2db [$env2db close] 0 262 error_check_good env0_close [$env0 close] 0 263 error_check_good env1_close [$env1 close] 0 264 error_check_good cl2_close [$cl2env close] 0 265 replclose $testdir/MSGQUEUEDIR 266 set verbose_check_secondaries 0 267 set testdir $orig_tdir 268 return 269} 270 271proc rep012_sec {method pdb niter keysp datap} { 272 source ./include.tcl 273 274 upvar $keysp keys 275 upvar $datap data 276 set did [open $dict] 277 for { set n 0 } { [gets $did str] != -1 && $n < $niter } { incr n } { 278 if { [is_record_based $method] == 1 } { 279 set key [expr $n + 1] 280 set datum $str 281 } else { 282 set key $str 283 gets $did datum 284 } 285 set keys($n) $key 286 set data($n) [pad_data $method $datum] 287 288 set ret [$pdb put $key [chop_data $method $datum]] 289 error_check_good put($n) $ret 0 290 } 291 close $did 292} 293