1# See the file LICENSE for redistribution information. 2# 3# Copyright (c)-2009 Oracle. All rights reserved. 4# 5# $Id$ 6# 7# TEST rep081 8# TEST Test of internal initialization and missing database files. 9# TEST 10# TEST One master, one client, two databases. 11# TEST Generate several log files. 12# TEST Remove old master log files. 13# TEST Start up client. 14# TEST Remove or replace one master database file while client initialization 15# TEST is in progress, make sure other master database can keep processing. 16# 17proc rep081 { method { niter 200 } { tnum "081" } args } { 18 19 source ./include.tcl 20 global databases_in_memory 21 global repfiles_in_memory 22 23 if { $is_windows9x_test == 1 } { 24 puts "Skipping replication test on Win 9x platform." 25 return 26 } 27 28 # Valid for all access methods. 29 if { $checking_valid_methods } { 30 return "ALL" 31 } 32 33 set args [convert_args $method $args] 34 35 # This test needs to set its own pagesize. 36 set pgindex [lsearch -exact $args "-pagesize"] 37 if { $pgindex != -1 } { 38 puts "Rep$tnum: skipping for specific pagesizes" 39 return 40 } 41 42 set logsets [create_logsets 2] 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 # Run with options to remove or replace the master database file. 61 set testopts { removefile replacefile } 62 foreach t $testopts { 63 foreach l $logsets { 64 puts "Rep$tnum ($method $t $args): Test of\ 65 internal init with missing db file $msg $msg2." 66 puts "Rep$tnum: Master logs are [lindex $l 0]" 67 puts "Rep$tnum: Client logs are [lindex $l 1]" 68 rep081_sub $method $niter $tnum $l $t $args 69 } 70 } 71} 72 73proc rep081_sub { method niter tnum logset testopt largs } { 74 global testdir 75 global util_path 76 global databases_in_memory 77 global repfiles_in_memory 78 global rep_verbose 79 global verbose_type 80 81 set verbargs "" 82 if { $rep_verbose == 1 } { 83 set verbargs " -verbose {$verbose_type on} " 84 } 85 86 set repmemargs "" 87 if { $repfiles_in_memory } { 88 set repmemargs "-rep_inmem_files " 89 } 90 91 env_cleanup $testdir 92 93 replsetup $testdir/MSGQUEUEDIR 94 95 set masterdir $testdir/MASTERDIR 96 set clientdir $testdir/CLIENTDIR 97 98 file mkdir $masterdir 99 file mkdir $clientdir 100 101 # Log size is small so we quickly create more than one. 102 # The documentation says that the log file must be at least 103 # four times the size of the in-memory log buffer. 104 set pagesize 4096 105 append largs " -pagesize $pagesize " 106 set log_max [expr $pagesize * 8] 107 108 set m_logtype [lindex $logset 0] 109 set c_logtype [lindex $logset 1] 110 111 # In-memory logs cannot be used with -txn nosync. 112 set m_logargs [adjust_logargs $m_logtype] 113 set c_logargs [adjust_logargs $c_logtype] 114 set m_txnargs [adjust_txnargs $m_logtype] 115 set c_txnargs [adjust_txnargs $c_logtype] 116 117 # Open a master. 118 repladd 1 119 set ma_envcmd "berkdb_env_noerr -create $m_txnargs $repmemargs \ 120 $m_logargs -log_max $log_max -errpfx MASTER $verbargs \ 121 -home $masterdir -rep_transport \[list 1 replsend\]" 122 set masterenv [eval $ma_envcmd -rep_master] 123 $masterenv rep_limit 0 0 124 125 # Run rep_test in the master only. 126 puts "\tRep$tnum.a: Running rep_test in replicated env." 127 set start 0 128 if { $databases_in_memory } { 129 set testfile { "" "test.db" } 130 set testfile2 { "" "test2.db" } 131 } else { 132 set testfile "test.db" 133 set testfile2 "test2.db" 134 } 135 set omethod [convert_method $method] 136 set dbargs [convert_args $method $largs] 137 set mdb [eval {berkdb_open_noerr} -env $masterenv -auto_commit\ 138 -create -mode 0644 $omethod $dbargs $testfile ] 139 error_check_good reptest_db [is_valid_db $mdb] TRUE 140 set mdb2 [eval {berkdb_open_noerr} -env $masterenv -auto_commit\ 141 -create -mode 0644 $omethod $dbargs $testfile2 ] 142 error_check_good reptest_db2 [is_valid_db $mdb2] TRUE 143 144 set stop 0 145 while { $stop == 0 } { 146 # Run rep_test in the master beyond the first log file. 147 eval rep_test $method \ 148 $masterenv $mdb $niter $start $start 0 $largs 149 eval rep_test $method \ 150 $masterenv $mdb2 $niter $start $start 0 $largs 151 incr start $niter 152 153 puts "\tRep$tnum.a.1: Run db_archive on master." 154 if { $m_logtype == "on-disk" } { 155 set res \ 156 [eval exec $util_path/db_archive -d -h $masterdir] 157 } 158 # 159 # Make sure we have moved beyond the first log file. 160 # 161 set first_master_log [get_logfile $masterenv first] 162 if { $first_master_log > 1 } { 163 set stop 1 164 } 165 166 } 167 168 puts "\tRep$tnum.b: Open client." 169 repladd 2 170 set cl_envcmd "berkdb_env_noerr -create $c_txnargs $repmemargs \ 171 $c_logargs -log_max $log_max -errpfx CLIENT $verbargs \ 172 -home $clientdir -rep_transport \[list 2 replsend\]" 173 set clientenv [eval $cl_envcmd -rep_client] 174 $clientenv rep_limit 0 0 175 set envlist "{$masterenv 1} {$clientenv 2}" 176 177 # Check initial value for number of FILE_FAIL internal init cleanups. 178 error_check_good ff_cleanup \ 179 [stat_field $clientenv rep_stat "File fail cleanups done"] 0 180 181 # 182 # Process messages in a controlled manner until the update (internal 183 # init) starts and we can remove or replace the database file. 184 # 185 set loop 10 186 set i 0 187 set entries 100 188 set in_rec_page 0 189 set dbrem_init 0 190 if { $testopt == "replacefile" } { 191 set errstr "invalid argument" 192 } else { 193 set errstr "no such file or directory" 194 } 195 while { $i < $loop } { 196 set nproced 0 197 incr nproced [proc_msgs_once $envlist NONE err] 198 # 199 # Last time through the loop the mdb database file 200 # is gone. The master is processing the client's PAGE_REQ 201 # and not finding the database file it needs so it sends a 202 # FILE_FAIL and returns an error. Break out of loop if 203 # expected error seen. 204 # 205 if { [is_substr $err $errstr] } { 206 error_check_good nproced $nproced 0 207 break 208 } else { 209 error_check_bad nproced $nproced 0 210 error_check_good errchk $err 0 211 } 212 # Internal init file is very transient, but exists in 213 # the rep files on-disk case during the second iteration 214 # of this loop. Take this chance to make sure the internal 215 # init file doesn't exist when rep files are in-memory. 216 if { $i == 1 && $repfiles_in_memory == 1 } { 217 error_check_good noinit \ 218 [file exists "$clientdir/__db.rep.init"] 0 219 } 220 # 221 # When we are in internal init, remove the mdb database file. 222 # This causes the master to send a FILE_FAIL that will cause 223 # the client to clean up its internal init. 224 # 225 if { $in_rec_page == 0 } { 226 set clstat [exec $util_path/db_stat \ 227 -N -r -R A -h $clientdir] 228 if { $dbrem_init == 0 && \ 229 [is_substr $clstat "REP_F_RECOVER_PAGE"] } { 230 set in_rec_page 1 231 set dbrem_init 1 232 # 233 # Turn off timer so that client sync doesn't 234 # prevent db operations. 235 # 236 $masterenv test force noarchive_timeout 237 238 # Close and remove mdb. 239 puts "\tRep$tnum.c: Remove a database file." 240 error_check_good mdb_close [$mdb close] 0 241 error_check_good remove_x [$masterenv \ 242 dbremove -auto_commit $testfile] 0 243 244 # Make sure mdb file is really gone. 245 set dfname [file join $masterdir $testfile] 246 error_check_good gone [file exists $dfname] 0 247 248 # Replace mdb file with non-db content. 249 if { $testopt == "replacefile" } { 250 puts \ 251 "\tRep$tnum.c.1: Replace database file." 252 set repfileid [open $dfname w+] 253 puts -nonewline $repfileid \ 254 "This is not a database file." 255 close $repfileid 256 } 257 } 258 } 259 incr i 260 } 261 262 # 263 # Process two more batches of messages so client can process 264 # the FILE_FAIL message and the resulting new internal init. 265 # 266 puts "\tRep$tnum.d: Process messages including FILE_FAIL." 267 process_msgs $envlist 0 NONE err 268 if { $err != 0 } { 269 error_check_good errchk [is_substr $err $errstr] 1 270 } 271 puts "\tRep$tnum.d.1: Process messages including new internal init." 272 process_msgs $envlist 0 NONE err 273 error_check_good errchk $err 0 274 275 puts "\tRep$tnum.e: Verify logs and databases." 276 rep_verify $masterdir $masterenv $clientdir $clientenv 1 1 1 test2.db 277 278 # Make sure we have seen a FILE_FAIL internal init cleanup. 279 error_check_good ff_cleanup \ 280 [stat_field $clientenv rep_stat "File fail cleanups done"] 1 281 282 error_check_good mdb_close2 [$mdb2 close] 0 283 error_check_good masterenv_close [$masterenv close] 0 284 error_check_good clientenv_close [$clientenv close] 0 285 replclose $testdir/MSGQUEUEDIR 286} 287 288 289