1# Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved. 2# 3# See the file LICENSE for license information. 4# 5# $Id$ 6# 7# TEST rep105 8# TEST Replication and rollback on sync over multiple log files. 9# TEST 10# TEST Run rep_test in a replicated master env. 11# TEST Hold open various txns in various log files and make sure 12# TEST that when synchronization happens, we rollback the correct set 13# TEST of log files. 14proc rep105 { method { niter 4 } { tnum "105" } args } { 15 source ./include.tcl 16 global repfiles_in_memory 17 18 # Only Btree is needed. 19 if { $checking_valid_methods } { 20 set test_methods { btree } 21 return $test_methods 22 } 23 24 if { [is_btree $method] == 0 } { 25 puts "Skipping for method $method." 26 return 27 } 28 29 set msg2 "and on-disk replication files" 30 if { $repfiles_in_memory } { 31 set msg2 "and in-memory replication files" 32 } 33 34 set args [convert_args $method $args] 35 set logsets [create_logsets 3] 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 for\ 43 in-memory logs with -recover." 44 continue 45 } 46 puts "Rep$tnum ($method $r): \ 47 Replication and multi-logfile rollback $msg2." 48 puts "Rep$tnum: Master logs are [lindex $l 0]" 49 puts "Rep$tnum: Client1 logs are [lindex $l 1]" 50 puts "Rep$tnum: Client2 logs are [lindex $l 2]" 51 rep105_sub $method $niter $tnum $l $r $args 52 } 53 } 54} 55 56proc rep105_sub { method niter tnum logset recargs largs } { 57 global repfiles_in_memory 58 global rep_verbose 59 global testdir 60 global verbose_type 61 62 set verbargs "" 63 if { $rep_verbose == 1 } { 64 set verbargs " -verbose {$verbose_type on} " 65 } 66 67 set repmemargs "" 68 if { $repfiles_in_memory } { 69 set repmemargs "-rep_inmem_files " 70 } 71 72 env_cleanup $testdir 73 74 set orig_tdir $testdir 75 set omethod [convert_method $method] 76 77 replsetup $testdir/MSGQUEUEDIR 78 79 set masterdir $testdir/MASTERDIR 80 set clientdir $testdir/CLIENTDIR 81 set clientdir2 $testdir/CLIENTDIR.2 82 file mkdir $masterdir 83 file mkdir $clientdir 84 file mkdir $clientdir2 85 86 set pagesize 4096 87 append largs " -pagesize $pagesize " 88 set log_max [expr $pagesize * 8] 89 90 set m_logtype [lindex $logset 0] 91 set m_logargs [adjust_logargs $m_logtype] 92 set m_txnargs [adjust_txnargs $m_logtype] 93 94 set c_logtype [lindex $logset 1] 95 set c_logargs [adjust_logargs $c_logtype] 96 set c_txnargs [adjust_txnargs $c_logtype] 97 98 set c2_logtype [lindex $logset 2] 99 set c2_logargs [adjust_logargs $c2_logtype] 100 set c2_txnargs [adjust_txnargs $c2_logtype] 101 102 # Open a master. 103 repladd 1 104 set ma_envcmd "berkdb_env_noerr -create $m_txnargs $m_logargs \ 105 -home $masterdir $verbargs -errpfx MASTER -log_max $log_max \ 106 -rep_transport \[list 1 replsend\] $repmemargs" 107 set masterenv [eval $ma_envcmd $recargs -rep_master] 108 109 # Open two clients 110 repladd 2 111 set cl_envcmd "berkdb_env_noerr -create $c_txnargs $c_logargs \ 112 -home $clientdir $verbargs -errpfx CLIENT1 -log_max $log_max \ 113 -rep_transport \[list 2 replsend\] $repmemargs" 114 set clientenv [eval $cl_envcmd $recargs -rep_client] 115 116 repladd 3 117 set cl2_envcmd "berkdb_env_noerr -create $c2_txnargs $c2_logargs \ 118 -home $clientdir2 $verbargs -errpfx CLIENT2 -log_max $log_max \ 119 -rep_transport \[list 3 replsend\] $repmemargs" 120 set cl2env [eval $cl2_envcmd $recargs -rep_client] 121 122 # Bring the clients online by processing the startup messages. 123 set envlist "{$masterenv 1} {$clientenv 2} {$cl2env 3}" 124 process_msgs $envlist 125 126 # Run rep_test in the master (and update clients). 127 # 128 # Set niter small so that no checkpoints are performed in 129 # rep_test. We want to control when checkpoints happen. 130 # 131 set niter 4 132 puts "\tRep$tnum.a: Running rep_test in replicated env." 133 eval rep_test $method $masterenv NULL $niter 0 0 0 $largs 134 process_msgs $envlist 135 136 # 137 # We want to start several transactions and make sure 138 # that the correct log files are left based on outstanding 139 # txns after sync. 140 # 141 # The logfile sync LSN is in log file S. Transactions 142 # are noted with T and their commit with #. 143 # We want: 144 # SYNC_LSN 145 # S-2.... S-1.... S......|...... S+1.... S+2.... 146 # T1.................# | 147 # T2...................|..# 148 # T3............|.........# 149 # T4..|..# 150 # | T5.# 151 # | T6........# 152 # 153 # 154 # Create a few extra databases so we can hold these txns 155 # open and have operations on them outstanding. 156 # 157 # We close 'client' at the SYNC_LSN point. Then run with 158 # the master and client2 only. Then in S+2, we close the 159 # master and reopen 'client' as the master so that client2 160 # needs to rollback all the way to the SYNC_LSN. 161 # 162 set t1db "txn1.db" 163 set t2db "txn2.db" 164 set t3db "txn3.db" 165 set key1 "KEY1" 166 set key2 "KEY2" 167 set key3 "KEY3" 168 set key4 "KEY4" 169 set data1 "DATA1" 170 set data2 "DATA2" 171 set data3 "DATA3" 172 set data4 "DATA4" 173 set db1 [eval {berkdb_open_noerr} -env $masterenv -auto_commit\ 174 -create -mode 0644 $omethod $largs $t1db] 175 set db2 [eval {berkdb_open_noerr} -env $masterenv -auto_commit\ 176 -create -mode 0644 $omethod $largs $t2db] 177 set db3 [eval {berkdb_open_noerr} -env $masterenv -auto_commit\ 178 -create -mode 0644 $omethod $largs $t3db] 179 process_msgs $envlist 180 181 puts "\tRep$tnum.b: Set up T1 and T2 long running txns." 182 set t1 [$masterenv txn] 183 set ret [$db1 put -txn $t1 $key1 $data1] 184 error_check_good put $ret 0 185 set t2 [$masterenv txn] 186 set ret [$db2 put -txn $t2 $key1 $data1] 187 error_check_good put $ret 0 188 189 set logminus2 [get_logfile $masterenv last] 190 set start $niter 191 192 rep105_moveonelog $tnum $masterenv $method $niter $start $envlist \ 193 $logminus2 $largs 194 195 puts "\tRep$tnum.d: Set up T3 long running txn." 196 set t3 [$masterenv txn] 197 set ret [$db3 put -txn $t3 $key1 $data1] 198 error_check_good put $ret 0 199 200 set logminus1 [get_logfile $masterenv last] 201 set start [expr $niter * 10] 202 rep105_moveonelog $tnum $masterenv $method $niter $start $envlist \ 203 $logminus1 $largs 204 205 set logsync [get_logfile $masterenv last] 206 # 207 # We want to resolve T1 before the sync point. 208 # Write another part of that txn and then commit. 209 # 210 puts "\tRep$tnum.e: Resolve T1 and start T4." 211 set ret [$db1 put -txn $t1 $key2 $data2] 212 error_check_good put $ret 0 213 error_check_good commit [$t1 commit] 0 214 set t4 [$masterenv txn] 215 set ret [$db1 put -txn $t4 $key3 $data3] 216 error_check_good put $ret 0 217 218 # Run a couple more txns to get a sync point 219 set start [expr $niter * 20] 220 eval rep_test $method $masterenv NULL $niter $start $start 0 $largs 221 process_msgs $envlist 222 223 puts "\tRep$tnum.f: Close client 1 and make master changes." 224 error_check_good client_close [$clientenv close] 0 225 set envlist "{$masterenv 1} {$cl2env 3}" 226 227 puts "\tRep$tnum.g: Resolve T2 and T4. Start and resolve T5." 228 set ret [$db2 put -txn $t2 $key2 $data2] 229 error_check_good put $ret 0 230 error_check_good commit [$t2 commit] 0 231 set ret [$db1 put -txn $t4 $key4 $data4] 232 error_check_good put $ret 0 233 error_check_good commit [$t4 commit] 0 234 set t5 [$masterenv txn] 235 set ret [$db2 put -txn $t5 $key3 $data3] 236 error_check_good put $ret 0 237 error_check_good commit [$t5 commit] 0 238 239 set start [expr $niter * 20] 240 rep105_moveonelog $tnum $masterenv $method $niter $start $envlist \ 241 $logsync $largs 242 243 set logplus1 [get_logfile $masterenv last] 244 puts "\tRep$tnum.h: Resolve T3. Start T6." 245 set ret [$db3 put -txn $t3 $key2 $data2] 246 error_check_good put $ret 0 247 error_check_good commit [$t3 commit] 0 248 set t6 [$masterenv txn] 249 set ret [$db3 put -txn $t6 $key3 $data3] 250 error_check_good put $ret 0 251 252 set start [expr $niter * 30] 253 rep105_moveonelog $tnum $masterenv $method $niter $start $envlist \ 254 $logplus1 $largs 255 256 puts "\tRep$tnum.i: Resolve T6. Close dbs" 257 set ret [$db3 put -txn $t6 $key4 $data4] 258 error_check_good put $ret 0 259 error_check_good commit [$t6 commit] 0 260 261 $db1 close 262 $db2 close 263 $db3 close 264 process_msgs $envlist 265 266 # Delete messages for closed client 267 replclear 2 268 269 puts "\tRep$tnum.j: Close master, reopen client as master." 270 error_check_good master_close [$masterenv close] 0 271 272 set newmasterenv [eval $cl_envcmd $recargs -rep_master] 273 274 puts "\tRep$tnum.k: Process messages to cause rollback in client2." 275 set lastlog [get_logfile $cl2env last] 276 set envlist "{$newmasterenv 2} {$cl2env 3}" 277 process_msgs $envlist 278 replclear 1 279 280 # 281 # Verify we rolled back to the expected log file. 282 # We know we're dealing with single digit log files nums so 283 # do the easy thing using lfname. If that ever changes, 284 # this will need to be fixed. 285 # 286 # We expect to rollback to $logsync, and that $logplus1 287 # through $lastlog are gone after processing messages. 288 # All of the rollback verification is in clientdir2. 289 # 290 set cwd [pwd] 291 cd $clientdir2 292 set saved_lf [glob -nocomplain log.*] 293 cd $cwd 294 set lfname log.000000000 295 296 # For in-memory logs we just check the log file 297 # number of the first and last logs and assume that 298 # the logs in the middle are available. For on-disk 299 # logs we check for physical existence of all logs. 300 if { $c2_logtype == "in-memory" } { 301 set last_lf [get_logfile $cl2env last] 302 set first_lf [get_logfile $cl2env first] 303 error_check_good first_inmem_log\ 304 [expr $first_lf <= $logminus2] 1 305 error_check_good last_inmem_log $last_lf $logsync 306 } else { 307 for { set i $logminus2 } { $i <= $logsync } { incr i } { 308 set lf $lfname$i 309 set present [lsearch -exact $saved_lf $lf] 310 error_check_bad lf.present.$i $present -1 311 } 312 for { set i $logplus1 } { $i <= $lastlog } { incr i } { 313 set lf $lfname$i 314 set present [lsearch -exact $saved_lf $lf] 315 error_check_good lf.notpresent.$i $present -1 316 } 317 } 318 error_check_good newmasterenv_close [$newmasterenv close] 0 319 error_check_good cl2_close [$cl2env close] 0 320 replclose $testdir/MSGQUEUEDIR 321 set testdir $orig_tdir 322 return 323} 324 325proc rep105_moveonelog { tnum env method niter start envlist lognum largs } { 326 set stop 0 327 while { $stop == 0 } { 328 puts "\t\tRep$tnum: Running rep_test until past log $lognum." 329 eval rep_test $method $env NULL $niter $start $start \ 330 0 $largs 331 process_msgs $envlist 332 incr start $niter 333 set newlog [get_logfile $env last] 334 if { $newlog > $lognum } { 335 set stop 1 336 } 337 } 338} 339