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