1# See the file LICENSE for redistribution information. 2# 3# Copyright (c) 2005,2008 Oracle. All rights reserved. 4# 5# $Id: rep045.tcl,v 12.19 2008/01/08 20:58:53 bostic Exp $ 6# 7# TEST rep045 8# TEST 9# TEST Replication with versions. 10# TEST 11# TEST Mimic an application where a database is set up in the 12# TEST background and then put into a replication group for use. 13# TEST The "version database" identifies the current live 14# TEST version, the database against which queries are made. 15# TEST For example, the version database might say the current 16# TEST version is 3, and queries would then be sent to db.3. 17# TEST Version 4 is prepared for use while version 3 is in use. 18# TEST When version 4 is complete, the version database is updated 19# TEST to point to version 4 so queries can be directed there. 20# TEST 21# TEST This test has a master and two clients. One client swaps 22# TEST roles with the master, and the other client runs constantly 23# TEST in another process. 24 25proc rep045 { method { tnum "045" } args } { 26 27 source ./include.tcl 28 if { $is_windows9x_test == 1 } { 29 puts "Skipping replication test on Win 9x platform." 30 return 31 } 32 33 # Valid for all access methods. 34 if { $checking_valid_methods } { 35 return "ALL" 36 } 37 38 set args [convert_args $method $args] 39 set logsets [create_logsets 3] 40 41 foreach l $logsets { 42 set logindex [lsearch -exact $l "in-memory"] 43 puts "Rep$tnum ($method): Replication with version\ 44 databases." 45 puts "Rep$tnum: Master logs are [lindex $l 0]" 46 puts "Rep$tnum: Client 0 logs are [lindex $l 1]" 47 puts "Rep$tnum: Client 1 logs are [lindex $l 2]" 48 rep045_sub $method $tnum $l $args 49 } 50} 51 52proc rep045_sub { method tnum logset largs } { 53 source ./include.tcl 54 set orig_tdir $testdir 55 global rep_verbose 56 global verbose_type 57 58 set verbargs "" 59 if { $rep_verbose == 1 } { 60 set verbargs " -verbose {$verbose_type on} " 61 } 62 63 set masterdir $testdir/MASTERDIR 64 set clientdir0 $testdir/CLIENTDIR0 65 set clientdir1 $testdir/CLIENTDIR1 66 67 env_cleanup $testdir 68 replsetup $testdir/MSGQUEUEDIR 69 file mkdir $masterdir 70 file mkdir $clientdir0 71 file mkdir $clientdir1 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 set omethod [convert_method $method] 87 88 # Open a master. 89 repladd 1 90 set envcmd(M0) "berkdb_env_noerr -create $m_txnargs \ 91 $m_logargs -errpfx ENV.M0 $verbargs \ 92 -errfile /dev/stderr -lock_detect default \ 93 -home $masterdir -rep_transport \[list 1 replsend\]" 94 set menv [eval $envcmd(M0) -rep_master] 95 96 # Open a client 97 repladd 2 98 set envcmd(C0) "berkdb_env_noerr -create $c_txnargs \ 99 $c_logargs -errpfx ENV.C0 $verbargs \ 100 -errfile /dev/stderr -lock_detect default \ 101 -home $clientdir0 -rep_transport \[list 2 replsend\]" 102 set cenv0 [eval $envcmd(C0) -rep_client] 103 104 # Open second client. 105 repladd 3 106 set envcmd(C1) "berkdb_env_noerr -create $c2_txnargs \ 107 $c2_logargs -errpfx ENV.C1 $verbargs \ 108 -errfile /dev/stderr -lock_detect default \ 109 -home $clientdir1 -rep_transport \[list 3 replsend\]" 110 set cenv1 [eval $envcmd(C1) -rep_client] 111 112 # Bring the clients online by processing the startup messages. 113 set envlist "{$menv 1} {$cenv0 2} {$cenv1 3}" 114 process_msgs $envlist 115 116 # Clobber replication's 30-second anti-archive timer, which will have 117 # been started by client sync-up internal init, so that we can do a 118 # db_remove in a moment. 119 # 120 $menv test force noarchive_timeout 121 122 puts "\tRep$tnum.a: Initialize version database." 123 # Set up variables so we cycle through version numbers 1 124 # through maxversion several times. 125 set vname "version.db" 126 set version 0 127 set maxversion 5 128 set iter 12 129 set nentries 100 130 set start 0 131 132 # The version db is always btree. 133 set vdb [eval {berkdb_open_noerr -env $menv -create \ 134 -auto_commit -mode 0644} -btree $vname] 135 error_check_good init_version [$vdb put VERSION $version] 0 136 error_check_good vdb_close [$vdb close] 0 137 process_msgs $envlist 138 139 # Start up a separate process that constantly reads data 140 # from the current official version. 141 puts "\tRep$tnum.b: Spawn a child tclsh to do client work." 142 set pid [exec $tclsh_path $test_path/wrap.tcl \ 143 rep045script.tcl $testdir/rep045script.log \ 144 $clientdir1 $vname &] 145 146 # Main loop: update query database, process messages (or don't, 147 # simulating a failure), announce the new version, process 148 # messages (or don't), and swap masters. 149 set version 1 150 for { set i 1 } { $i < $iter } { incr i } { 151 152 # If database.N exists, clean it up. 153 set dbname "db.$version" 154 if { [file exists $masterdir/$dbname] == 1 } { 155 puts "\tRep$tnum.c.$i: Removing old version $version." 156 error_check_good dbremove \ 157 [$menv dbremove -auto_commit $dbname] 0 158 } 159 160 puts "\tRep$tnum.c.$i: Set up query database $version." 161 set db [eval berkdb_open_noerr -create -env $menv\ 162 -auto_commit -mode 0644 $largs $omethod $dbname] 163 error_check_good db_open [is_valid_db $db] TRUE 164 eval rep_test $method $menv $db $nentries $start $start 0 0 $largs 165 incr start $nentries 166 error_check_good db_close [$db close] 0 167 168 # We alternate between processing the messages and 169 # clearing the messages to simulate a failure. 170 171 set process [expr $i % 2] 172 if { $process == 1 } { 173 process_msgs $envlist 174 } else { 175 replclear 2 176 replclear 3 177 } 178 179 # Announce new version. 180 puts "\tRep$tnum.d.$i: Announce new version $version." 181 set vdb [eval {berkdb_open_noerr -env $menv \ 182 -auto_commit -mode 0644} $vname] 183 error_check_good update_version [$vdb put VERSION $version] 0 184 error_check_good vdb_close [$vdb close] 0 185 186 # Process messages or simulate failure. 187 if { $process == 1 } { 188 process_msgs $envlist 189 } else { 190 replclear 2 191 replclear 3 192 } 193 194 # Switch master, update envlist. 195 puts "\tRep$tnum.e.$i: Switch masters." 196 set envlist [switch_master $envlist] 197 198 # Update values for next iteration. 199 set menv [lindex [lindex $envlist 0] 0] 200 set cenv0 [lindex [lindex $envlist 1] 0] 201 incr version 202 if { $version > $maxversion } { 203 set version 1 204 } 205 } 206 207 # Signal to child that we are done. 208 set vdb [eval {berkdb_open_noerr -env $menv \ 209 -auto_commit -mode 0644} $vname] 210 error_check_good version_done [$vdb put VERSION DONE] 0 211 error_check_good vdb_close [$vdb close] 0 212 process_msgs $envlist 213 214 # Watch for child to finish. 215 watch_procs $pid 5 216 217 puts "\tRep$tnum.f: Clean up." 218 error_check_good menv_close [$menv close] 0 219 error_check_good cenv0_close [$cenv0 close] 0 220 error_check_good cenv1_close [$cenv1 close] 0 221 222 replclose $testdir/MSGQUEUEDIR 223 224 # Check for failures in child's log file. 225 set errstrings [eval findfail $testdir/rep045script.log] 226 foreach str $errstrings { 227 puts "FAIL: error message in log file: $str" 228 } 229 230 set testdir $orig_tdir 231 return 232} 233 234proc switch_master { envlist } { 235 # Find env handles and machine ids. 236 set menv [lindex [lindex $envlist 0] 0] 237 set mid [lindex [lindex $envlist 0] 1] 238 set cenv [lindex [lindex $envlist 1] 0] 239 set cid [lindex [lindex $envlist 1] 1] 240 set cenv1 [lindex [lindex $envlist 2] 0] 241 set cid1 [lindex [lindex $envlist 2] 1] 242 243 # Downgrade master, upgrade client. 244 error_check_good master_downgrade [$menv rep_start -client] 0 245 error_check_good client_upgrade [$cenv rep_start -master] 0 246 process_msgs $envlist 247 248 # Adjust envlist. The former client env is the new master, 249 # and vice versa. 250 set newenvlist "{$cenv $cid} {$menv $mid} {$cenv1 $cid1}" 251 return $newenvlist 252} 253