1# See the file LICENSE for redistribution information. 2# 3# Copyright (c) 2003,2008 Oracle. All rights reserved. 4# 5# $Id: rep010.tcl,v 12.16 2008/01/08 20:58:53 bostic Exp $ 6# 7# TEST rep010 8# TEST Replication and ISPERM 9# TEST 10# TEST With consecutive message processing, make sure every 11# TEST DB_REP_PERMANENT is responded to with an ISPERM when 12# TEST processed. With gaps in the processing, make sure 13# TEST every DB_REP_PERMANENT is responded to with an ISPERM 14# TEST or a NOTPERM. Verify in both cases that the LSN returned 15# TEST with ISPERM is found in the log. 16proc rep010 { method { niter 100 } { tnum "010" } args } { 17 18 source ./include.tcl 19 if { $is_windows9x_test == 1 } { 20 puts "Skipping replication test on Win 9x platform." 21 return 22 } 23 24 # Run for all access methods. 25 if { $checking_valid_methods } { 26 return "ALL" 27 } 28 29 set args [convert_args $method $args] 30 set logsets [create_logsets 2] 31 32 # Run the body of the test with and without recovery. 33 foreach r $test_recopts { 34 foreach l $logsets { 35 set logindex [lsearch -exact $l "in-memory"] 36 if { $r == "-recover" && $logindex != -1 } { 37 puts "Rep$tnum: Skipping\ 38 for in-memory logs with -recover." 39 continue 40 } 41 puts "Rep$tnum ($method $r): Replication and ISPERM." 42 puts "Rep$tnum: Master logs are [lindex $l 0]" 43 puts "Rep$tnum: Client logs are [lindex $l 1]" 44 rep010_sub $method $niter $tnum $l $r $args 45 } 46 } 47} 48 49proc rep010_sub { method niter tnum logset recargs largs } { 50 source ./include.tcl 51 global rand_init 52 berkdb srand $rand_init 53 global perm_sent_list 54 global rep_verbose 55 global verbose_type 56 57 set verbargs "" 58 if { $rep_verbose == 1 } { 59 set verbargs " -verbose {$verbose_type on} " 60 } 61 62 env_cleanup $testdir 63 set omethod [convert_method $method] 64 65 replsetup $testdir/MSGQUEUEDIR 66 set perm_sent_list {{}} 67 68 set masterdir $testdir/MASTERDIR 69 set clientdir $testdir/CLIENTDIR 70 71 file mkdir $masterdir 72 file mkdir $clientdir 73 74 set m_logtype [lindex $logset 0] 75 set c_logtype [lindex $logset 1] 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 m_txnargs [adjust_txnargs $m_logtype] 82 set c_txnargs [adjust_txnargs $c_logtype] 83 84 # Open a master. 85 repladd 1 86 set env_cmd(M) "berkdb_env_noerr -create -log_max 1000000 \ 87 $m_logargs $verbargs -errpfx MASTER \ 88 -home $masterdir $m_txnargs -rep_master \ 89 -rep_transport \[list 1 replsend\]" 90 set masterenv [eval $env_cmd(M) $recargs] 91 92 # Open a client 93 repladd 2 94 set env_cmd(C) "berkdb_env_noerr -create -home $clientdir \ 95 $c_txnargs $c_logargs $verbargs -rep_client -errpfx CLIENT \ 96 -rep_transport \[list 2 replsend\]" 97 set clientenv [eval $env_cmd(C) $recargs] 98 99 # Bring the client online. Since that now involves internal init, we 100 # have to avoid the special rep010_process_msgs here, because otherwise 101 # we would hang trying to open a log cursor. 102 # 103 process_msgs "{$masterenv 1} {$clientenv 2}" 104 105 # Open database in master, propagate to client. 106 set dbname rep010.db 107 set db1 [eval {berkdb_open_noerr -create} $omethod -auto_commit \ 108 -env $masterenv $largs $dbname] 109 rep010_process_msgs $masterenv $clientenv 1 110 111 puts "\tRep$tnum.a: Process messages with no gaps." 112 # Feed operations one at a time to master and immediately 113 # update client. 114 for { set i 1 } { $i <= $niter } { incr i } { 115 set t [$masterenv txn] 116 error_check_good db_put \ 117 [eval $db1 put -txn $t $i [chop_data $method data$i]] 0 118 error_check_good txn_commit [$t commit] 0 119 rep010_process_msgs $masterenv $clientenv 1 120 } 121 122 # Replace data. 123 for { set i 1 } { $i <= $niter } { incr i } { 124 set t [$masterenv txn] 125 set ret \ 126 [$db1 get -get_both -txn $t $i [pad_data $method data$i]] 127 error_check_good db_put \ 128 [$db1 put -txn $t $i [chop_data $method newdata$i]] 0 129 error_check_good txn_commit [$t commit] 0 130 rep010_process_msgs $masterenv $clientenv 1 131 } 132 133 # Try some aborts. These do not write permanent messages. 134 for { set i 1 } { $i <= $niter } { incr i } { 135 set t [$masterenv txn] 136 error_check_good db_put [$db1 put -txn $t $i abort$i] 0 137 error_check_good txn_abort [$t abort] 0 138 rep010_process_msgs $masterenv $clientenv 0 139 } 140 141 puts "\tRep$tnum.b: Process messages with gaps." 142 # To test gaps in message processing, run and commit a whole 143 # bunch of transactions, then process the messages with skips. 144 for { set i 1 } { $i <= $niter } { incr i } { 145 set t [$masterenv txn] 146 error_check_good db_put [$db1 put -txn $t $i data$i] 0 147 error_check_good txn_commit [$t commit] 0 148 } 149 set skip [berkdb random_int 2 8] 150 rep010_process_msgs $masterenv $clientenv 1 $skip 151 152 # Clean up. 153 error_check_good db1_close [$db1 close] 0 154 error_check_good masterenv_close [$masterenv close] 0 155 error_check_good clientenv_close [$clientenv close] 0 156 157 replclose $testdir/MSGQUEUEDIR 158} 159 160proc rep010_process_msgs { masterenv clientenv check {skip_interval 0} } { 161 global perm_response_list 162 global perm_sent_list 163 164 set perm_response_list {{}} 165 166 while { 1 } { 167 set nproced 0 168 169 incr nproced [replprocessqueue $masterenv 1 $skip_interval] 170 incr nproced [replprocessqueue $clientenv 2 $skip_interval] 171 172 # In this test, the ISPERM and NOTPERM messages are 173 # sent by the client back to the master. Verify that we 174 # get ISPERM when the client is caught up to the master 175 # (i.e. last client LSN in the log matches the LSN returned 176 # with the ISPERM), and that when we get NOTPERM, the client 177 # is not caught up. 178 179 # Create a list of the LSNs in the client log. 180 set lsnlist {} 181 set logc [$clientenv log_cursor] 182 error_check_good logc \ 183 [is_valid_logc $logc $clientenv] TRUE 184 for { set logrec [$logc get -first] } \ 185 { [llength $logrec] != 0 } \ 186 { set logrec [$logc get -next] } { 187 lappend lsnlist [lindex [lindex $logrec 0] 1] 188 } 189 set lastloglsn [lindex $lsnlist end] 190 191 # Parse perm_response_list to find the LSN returned with 192 # ISPERM or NOTPERM. 193 set response [lindex $perm_response_list end] 194 set permtype [lindex $response 0] 195 set messagelsn [lindex [lindex $response 1] 1] 196 197 if { [llength $response] != 0 } { 198 if { $permtype == "NOTPERM" } { 199 # If we got a NOTPERM, the returned LSN has to 200 # be greater than the last LSN in the log. 201 error_check_good notpermlsn \ 202 [expr $messagelsn > $lastloglsn] 1 203 } elseif { $permtype == "ISPERM" } { 204 # If we got an ISPERM, the returned LSN has to 205 # be in the log. 206 error_check_bad \ 207 ispermlsn [lsearch $lsnlist $messagelsn] -1 208 } else { 209 puts "FAIL: unexpected message type $permtype" 210 } 211 } 212 213 error_check_good logc_close [$logc close] 0 214 215 # If we've finished processing all the messages, check 216 # that the last received permanent message LSN matches the 217 # last sent permanent message LSN. 218 if { $nproced == 0 } { 219 if { $check != 0 } { 220 set last_sent [lindex $perm_sent_list end] 221 set last_rec_msg \ 222 [lindex $perm_response_list end] 223 set last_received [lindex $last_rec_msg 1] 224 error_check_good last_message \ 225 $last_sent $last_received 226 } 227 228 # If we check correctly; empty out the lists 229 set perm_response_list {{}} 230 set perm_sent_list {{}} 231 break 232 } 233 } 234} 235