1# See the file LICENSE for redistribution information. 2# 3# Copyright (c) 2005-2009 Oracle. All rights reserved. 4# 5# $Id$ 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 global databases_in_memory 29 global repfiles_in_memory 30 31 if { $is_windows9x_test == 1 } { 32 puts "Skipping replication test on Win 9x platform." 33 return 34 } 35 36 # Valid for all access methods. 37 if { $checking_valid_methods } { 38 return "ALL" 39 } 40 41 set args [convert_args $method $args] 42 set logsets [create_logsets 3] 43 44 # Set up for on-disk or in-memory databases. 45 set msg "using on-disk databases" 46 if { $databases_in_memory } { 47 set msg "using named in-memory databases" 48 if { [is_queueext $method] } { 49 puts -nonewline "Skipping rep$tnum for method " 50 puts "$method with named in-memory databases." 51 return 52 } 53 } 54 55 set msg2 "and on-disk replication files" 56 if { $repfiles_in_memory } { 57 set msg2 "and in-memory replication files" 58 } 59 60 foreach l $logsets { 61 set logindex [lsearch -exact $l "in-memory"] 62 puts "Rep$tnum ($method): Replication with version\ 63 databases $msg $msg2." 64 puts "Rep$tnum: Master logs are [lindex $l 0]" 65 puts "Rep$tnum: Client 0 logs are [lindex $l 1]" 66 puts "Rep$tnum: Client 1 logs are [lindex $l 2]" 67 rep045_sub $method $tnum $l $args 68 } 69} 70 71proc rep045_sub { method tnum logset largs } { 72 source ./include.tcl 73 set orig_tdir $testdir 74 global databases_in_memory 75 global repfiles_in_memory 76 global rep_verbose 77 global verbose_type 78 79 set verbargs "" 80 if { $rep_verbose == 1 } { 81 set verbargs " -verbose {$verbose_type on} " 82 } 83 84 set repmemargs "" 85 if { $repfiles_in_memory } { 86 set repmemargs "-rep_inmem_files " 87 } 88 89 set masterdir $testdir/MASTERDIR 90 set clientdir0 $testdir/CLIENTDIR0 91 set clientdir1 $testdir/CLIENTDIR1 92 93 env_cleanup $testdir 94 replsetup $testdir/MSGQUEUEDIR 95 file mkdir $masterdir 96 file mkdir $clientdir0 97 file mkdir $clientdir1 98 99 set m_logtype [lindex $logset 0] 100 set c_logtype [lindex $logset 1] 101 set c2_logtype [lindex $logset 2] 102 103 # In-memory logs require a large log buffer, and cannot 104 # be used with -txn nosync. 105 set m_logargs [adjust_logargs $m_logtype] 106 set c_logargs [adjust_logargs $c_logtype] 107 set c2_logargs [adjust_logargs $c2_logtype] 108 set m_txnargs [adjust_txnargs $m_logtype] 109 set c_txnargs [adjust_txnargs $c_logtype] 110 set c2_txnargs [adjust_txnargs $c2_logtype] 111 112 set omethod [convert_method $method] 113 114 # Open a master. 115 repladd 1 116 set envcmd(M0) "berkdb_env_noerr -create $m_txnargs \ 117 $m_logargs -errpfx ENV.M0 $verbargs $repmemargs \ 118 -errfile /dev/stderr -lock_detect default \ 119 -home $masterdir -rep_transport \[list 1 replsend\]" 120 set menv [eval $envcmd(M0) -rep_master] 121 122 # Open a client 123 repladd 2 124 set envcmd(C0) "berkdb_env_noerr -create $c_txnargs \ 125 $c_logargs -errpfx ENV.C0 $verbargs $repmemargs \ 126 -errfile /dev/stderr -lock_detect default \ 127 -home $clientdir0 -rep_transport \[list 2 replsend\]" 128 set cenv0 [eval $envcmd(C0) -rep_client] 129 130 # Open second client. 131 repladd 3 132 set envcmd(C1) "berkdb_env_noerr -create $c2_txnargs \ 133 $c2_logargs -errpfx ENV.C1 $verbargs $repmemargs \ 134 -errfile /dev/stderr -lock_detect default \ 135 -home $clientdir1 -rep_transport \[list 3 replsend\]" 136 set cenv1 [eval $envcmd(C1) -rep_client] 137 138 # Bring the clients online by processing the startup messages. 139 set envlist "{$menv 1} {$cenv0 2} {$cenv1 3}" 140 process_msgs $envlist 141 142 # Clobber replication's 30-second anti-archive timer, which will have 143 # been started by client sync-up internal init, so that we can do a 144 # db_remove in a moment. 145 # 146 $menv test force noarchive_timeout 147 148 puts "\tRep$tnum.a: Initialize version database." 149 # Set up variables so we cycle through version numbers 1 150 # through maxversion several times. 151 if { $databases_in_memory } { 152 set vname { "" "version.db" } 153 } else { 154 set vname "version.db" 155 } 156 set version 0 157 set maxversion 5 158 set iter 12 159 set nentries 100 160 set start 0 161 162 # The version db is always btree. 163 set vdb [eval {berkdb_open_noerr -env $menv -create \ 164 -auto_commit -mode 0644} -btree $vname] 165 error_check_good init_version [$vdb put VERSION $version] 0 166 error_check_good vdb_close [$vdb close] 0 167 process_msgs $envlist 168 169 # Start up a separate process that constantly reads data 170 # from the current official version. 171 puts "\tRep$tnum.b: Spawn a child tclsh to do client work." 172 set pid [exec $tclsh_path $test_path/wrap.tcl \ 173 rep045script.tcl $testdir/rep045script.log \ 174 $clientdir1 $vname $databases_in_memory &] 175 176 # Main loop: update query database, process messages (or don't, 177 # simulating a failure), announce the new version, process 178 # messages (or don't), and swap masters. 179 set version 1 180 for { set i 1 } { $i < $iter } { incr i } { 181 182 # If database.N exists on disk, clean it up. 183 if { $databases_in_memory } { 184 set dbname { "" "db.$version" } 185 } else { 186 set dbname "db.$version" 187 } 188 if { [file exists $masterdir/$dbname] == 1 } { 189 puts "\tRep$tnum.c.$i: Removing old version $version." 190 error_check_good dbremove \ 191 [$menv dbremove -auto_commit $dbname] 0 192 } 193 194 puts "\tRep$tnum.c.$i: Set up query database $version." 195 set db [eval berkdb_open_noerr -create -env $menv\ 196 -auto_commit -mode 0644 $largs $omethod $dbname] 197 error_check_good db_open [is_valid_db $db] TRUE 198 eval rep_test $method $menv $db $nentries $start $start 0 $largs 199 incr start $nentries 200 error_check_good db_close [$db close] 0 201 202 # We alternate between processing the messages and 203 # clearing the messages to simulate a failure. 204 205 set process [expr $i % 2] 206 if { $process == 1 } { 207 process_msgs $envlist 208 } else { 209 replclear 2 210 replclear 3 211 } 212 213 # Announce new version. 214 puts "\tRep$tnum.d.$i: Announce new version $version." 215 set vdb [eval {berkdb_open_noerr -env $menv \ 216 -auto_commit -mode 0644} $vname] 217 error_check_good update_version [$vdb put VERSION $version] 0 218 error_check_good vdb_close [$vdb close] 0 219 220 # Process messages or simulate failure. 221 if { $process == 1 } { 222 process_msgs $envlist 223 } else { 224 replclear 2 225 replclear 3 226 } 227 228 # Switch master, update envlist. 229 puts "\tRep$tnum.e.$i: Switch masters." 230 set envlist [switch_master $envlist] 231 232 # Update values for next iteration. 233 set menv [lindex [lindex $envlist 0] 0] 234 set cenv0 [lindex [lindex $envlist 1] 0] 235 incr version 236 if { $version > $maxversion } { 237 set version 1 238 } 239 } 240 241 # Signal to child that we are done. 242 set vdb [eval {berkdb_open_noerr -env $menv \ 243 -auto_commit -mode 0644} $vname] 244 error_check_good version_done [$vdb put VERSION DONE] 0 245 error_check_good vdb_close [$vdb close] 0 246 process_msgs $envlist 247 248 # Watch for child to finish. 249 watch_procs $pid 5 250 251 puts "\tRep$tnum.f: Clean up." 252 error_check_good menv_close [$menv close] 0 253 error_check_good cenv0_close [$cenv0 close] 0 254 error_check_good cenv1_close [$cenv1 close] 0 255 256 replclose $testdir/MSGQUEUEDIR 257 258 # Check for failures in child's log file. 259 set errstrings [eval findfail $testdir/rep045script.log] 260 foreach str $errstrings { 261 puts "FAIL: error message in log file: $str" 262 } 263 264 set testdir $orig_tdir 265 return 266} 267 268proc switch_master { envlist } { 269 # Find env handles and machine ids. 270 set menv [lindex [lindex $envlist 0] 0] 271 set mid [lindex [lindex $envlist 0] 1] 272 set cenv [lindex [lindex $envlist 1] 0] 273 set cid [lindex [lindex $envlist 1] 1] 274 set cenv1 [lindex [lindex $envlist 2] 0] 275 set cid1 [lindex [lindex $envlist 2] 1] 276 277 # Downgrade master, upgrade client. 278 error_check_good master_downgrade [$menv rep_start -client] 0 279 error_check_good client_upgrade [$cenv rep_start -master] 0 280 process_msgs $envlist 281 282 # Adjust envlist. The former client env is the new master, 283 # and vice versa. 284 set newenvlist "{$cenv $cid} {$menv $mid} {$cenv1 $cid1}" 285 return $newenvlist 286} 287