1# See the file LICENSE for redistribution information. 2# 3# Copyright (c) 2001-2009 Oracle. All rights reserved. 4# 5# $Id$ 6# 7# TEST rep066 8# TEST Replication and dead log handles. 9# TEST 10# TEST Run rep_test on master and a client. 11# TEST Simulate client crashes (master continues) until log 2. 12# TEST Open 2nd master env handle and put something in log and flush. 13# TEST Downgrade master, restart client as master. 14# TEST Run rep_test on newmaster until log 2. 15# TEST New master writes log records, newclient processes records 16# TEST and 2nd newclient env handle calls log_flush. 17# TEST New master commits, newclient processes and should succeed. 18# TEST Make sure 2nd handle detects the old log handle and doesn't 19# TEST write to a stale handle (if it does, the processing of the 20# TEST commit will fail). 21# 22proc rep066 { method { niter 10 } { tnum "066" } args } { 23 24 source ./include.tcl 25 global databases_in_memory 26 global repfiles_in_memory 27 28 if { $is_windows9x_test == 1 } { 29 puts "Skipping replication test on Win 9x platform." 30 return 31 } 32 33 # Run for all access methods. 34 if { $checking_valid_methods } { 35 return "ALL" 36 } 37 38 # This test requires a second handle on an env, and HP-UX 39 # doesn't support that. 40 if { $is_hp_test } { 41 puts "Skipping rep$tnum for HP-UX." 42 return 43 } 44 45 set args [convert_args $method $args] 46 set logsets [create_logsets 2] 47 48 # Set up for on-disk or in-memory databases. 49 set msg "using on-disk databases" 50 if { $databases_in_memory } { 51 set msg "using named in-memory databases" 52 if { [is_queueext $method] } { 53 puts -nonewline "Skipping rep$tnum for method " 54 puts "$method with named in-memory databases." 55 return 56 } 57 } 58 59 set msg2 "and on-disk replication files" 60 if { $repfiles_in_memory } { 61 set msg2 "and in-memory replication files" 62 } 63 64 # Run the body of the test with and without recovery. 65 foreach r $test_recopts { 66 foreach l $logsets { 67 set logindex [lsearch -exact $l "in-memory"] 68 if { $r == "-recover" && $logindex != -1 } { 69 puts "Rep$tnum: Skipping\ 70 for in-memory logs with -recover." 71 continue 72 } 73 puts "Rep$tnum ($method $r):\ 74 Replication and dead log handles $msg $msg2." 75 puts "Rep$tnum: Master logs are [lindex $l 0]" 76 puts "Rep$tnum: Client logs are [lindex $l 1]" 77 rep066_sub $method $niter $tnum $l $r $args 78 } 79 } 80} 81 82proc rep066_sub { method niter tnum logset recargs largs } { 83 global testdir 84 global databases_in_memory 85 global repfiles_in_memory 86 global rep_verbose 87 global verbose_type 88 89 set verbargs "" 90 if { $rep_verbose == 1 } { 91 set verbargs " -verbose {$verbose_type on} " 92 } 93 94 set repmemargs "" 95 if { $repfiles_in_memory } { 96 set repmemargs "-rep_inmem_files " 97 } 98 99 env_cleanup $testdir 100 101 replsetup $testdir/MSGQUEUEDIR 102 103 set masterdir $testdir/MASTERDIR 104 set clientdir $testdir/CLIENTDIR 105 file mkdir $masterdir 106 file mkdir $clientdir 107 108 # Log size is small so we quickly create more than one. 109 # The documentation says that the log file must be at least 110 # four times the size of the in-memory log buffer. 111 set pagesize 4096 112 append largs " -pagesize $pagesize " 113 set log_max [expr $pagesize * 8] 114 115 set m_logtype [lindex $logset 0] 116 set c_logtype [lindex $logset 1] 117 118 # In-memory logs require a large log buffer, and cannot 119 # be used with -txn nosync. 120 set m_logargs [adjust_logargs $m_logtype] 121 set c_logargs [adjust_logargs $c_logtype] 122 set m_txnargs [adjust_txnargs $m_logtype] 123 set c_txnargs [adjust_txnargs $c_logtype] 124 125 # Open a master. 126 # Later we'll open a 2nd handle to this env. 127 repladd 1 128 set ma_envcmd "berkdb_env_noerr -create $m_txnargs \ 129 $repmemargs \ 130 $m_logargs -errpfx ENV0 -log_max $log_max $verbargs \ 131 -home $masterdir -rep_transport \[list 1 replsend\]" 132 set env0 [eval $ma_envcmd $recargs -rep_master] 133 set masterenv $env0 134 135 # Open a client. 136 repladd 2 137 set cl_envcmd "berkdb_env_noerr -create $c_txnargs \ 138 $repmemargs \ 139 $c_logargs -errpfx ENV1 -log_max $log_max $verbargs \ 140 -home $clientdir -rep_transport \[list 2 replsend\]" 141 set env1 [eval $cl_envcmd $recargs -rep_client] 142 set clientenv $env1 143 144 # Bring the clients online by processing the startup messages. 145 set envlist "{$env0 1} {$env1 2}" 146 process_msgs $envlist 147 148 # Run a modified test001 in the master (and update clients). 149 puts "\tRep$tnum.a.0: Running rep_test in replicated env." 150 eval rep_test $method $masterenv NULL $niter 0 0 0 $largs 151 process_msgs $envlist 152 153 set nstart $niter 154 set last_client_log [get_logfile $env1 last] 155 set stop 0 156 while { $stop == 0 } { 157 puts "\tRep$tnum.b: Run test on master until log file changes." 158 eval rep_test\ 159 $method $masterenv NULL $niter $nstart $nstart 0 $largs 160 incr nstart $niter 161 replclear 2 162 set last_master_log [get_logfile $masterenv last] 163 if { $last_master_log > $last_client_log } { 164 set stop 1 165 } 166 } 167 168 # Open a 2nd env handle on the master. 169 # We want to have some operations happen on the normal 170 # handle and then flush them with this handle. 171 puts "\tRep$tnum.c: Open 2nd master env and flush log." 172 set 2ndenv [eval $ma_envcmd -rep_master -errpfx 2NDENV] 173 error_check_good master_env [is_valid_env $2ndenv] TRUE 174 175 176 # Set up databases as in-memory or on-disk. 177 if { $databases_in_memory } { 178 set testfile { "" "test.db" } 179 } else { 180 set testfile "test.db" 181 } 182 183 set omethod [convert_method $method] 184 set txn [$masterenv txn] 185 error_check_good txn [is_valid_txn $txn $masterenv] TRUE 186 set db [eval {berkdb_open_noerr -env $masterenv -errpfx MASTER \ 187 -txn $txn -create -mode 0644} $largs $omethod $testfile] 188 error_check_good dbopen [is_valid_db $db] TRUE 189 190 # Flush on the 2nd handle 191 set lf [stat_field $2ndenv log_stat "Times log flushed to disk"] 192 error_check_good flush [$2ndenv log_flush] 0 193 set lf2 [stat_field $2ndenv log_stat "Times log flushed to disk"] 194 error_check_bad log_flush $lf $lf2 195 196 # The detection of dead log handle is based on a 1-second resolution 197 # timestamp comparison. Now that we've established the threatening 198 # source of the dead handle in $2ndenv, wait a moment to make sure that 199 # the fresh handle that we're about to create gets a later timestamp. 200 tclsleep 1 201 202 # Resolve the txn and close the database 203 error_check_good commit [$txn commit] 0 204 error_check_good close [$db close] 0 205 206 # Nuke those messages for client about to become master. 207 replclear 2 208 209 puts "\tRep$tnum.d: Swap envs" 210 set masterenv $env1 211 set clientenv $env0 212 error_check_good downgrade [$clientenv rep_start -client] 0 213 error_check_good upgrade [$masterenv rep_start -master] 0 214 set envlist "{$env0 1} {$env1 2}" 215 process_msgs $envlist 216 217 # 218 # At this point, env0 should have rolled back across the log file. 219 # We need to do some operations on the master, process them on 220 # the client (but not a commit because that flushes). We want 221 # the message processing client env (env0) to put records in 222 # the log buffer and the 2nd env handle to flush the log. 223 # 224 puts "\tRep$tnum.e: Run test until create new log file." 225 # 226 # Set this to the last log file the old master had. 227 # 228 set last_client_log $last_master_log 229 set last_master_log [get_logfile $masterenv last] 230 set stop 0 231 while { $stop == 0 } { 232 puts "\tRep$tnum.e: Run test on master until log file changes." 233 eval rep_test\ 234 $method $masterenv NULL $niter $nstart $nstart 0 $largs 235 process_msgs $envlist 236 incr nstart $niter 237 set last_master_log [get_logfile $masterenv last] 238 if { $last_master_log == $last_client_log } { 239 set stop 1 240 } 241 } 242 puts "\tRep$tnum.f: Create some log records." 243 set txn [$masterenv txn] 244 error_check_good txn [is_valid_txn $txn $masterenv] TRUE 245 set db [eval {berkdb_open_noerr -env $masterenv -errpfx MASTER \ 246 -txn $txn -create -mode 0644} $largs $omethod $testfile] 247 error_check_good dbopen [is_valid_db $db] TRUE 248 249 process_msgs $envlist 250 # Flush on the 2nd handle 251 puts "\tRep$tnum.g: Flush on 2nd env handle." 252 set lf [stat_field $2ndenv log_stat "Times log flushed to disk"] 253 error_check_good flush [$2ndenv log_flush] 0 254 set lf2 [stat_field $2ndenv log_stat "Times log flushed to disk"] 255 error_check_bad log_flush2 $lf $lf2 256 257 # Resolve the txn and close the database 258 puts "\tRep$tnum.h: Process commit on client env handle." 259 error_check_good commit [$txn commit] 0 260 error_check_good close [$db close] 0 261 process_msgs $envlist 262 263 error_check_good cl2_close [$2ndenv close] 0 264 error_check_good env0_close [$env0 close] 0 265 error_check_good env1_close [$env1 close] 0 266 replclose $testdir/MSGQUEUEDIR 267 return 268} 269 270