# See the file LICENSE for redistribution information. # # Copyright (c) 2004,2008 Oracle. All rights reserved. # # $Id: rep069.tcl,v 12.8 2008/01/23 16:40:51 carol Exp $ # # TEST rep069 # TEST Test of internal initialization and elections. # TEST # TEST If a client is in a recovery mode of any kind, it # TEST participates in elections at priority 0 so it can # TEST never be elected master. # proc rep069 { method { niter 200 } { tnum "069" } args } { source ./include.tcl if { $is_windows9x_test == 1 } { puts "Skipping replication test on Win 9x platform." return } if { $checking_valid_methods } { set test_methods { btree } return $test_methods } if { [is_btree $method] == 0 } { puts "Rep$tnum: Skipping for method $method." return } set args [convert_args $method $args] set saved_args $args set logsets [create_logsets 2] foreach l $logsets { set args $saved_args puts "Rep$tnum ($method $args):\ Test internal initialization and elections." puts "Rep$tnum: Master logs are [lindex $l 0]" puts "Rep$tnum: Client logs are [lindex $l 1]" rep069_sub $method $niter $tnum $l $args } } proc rep069_sub { method niter tnum logset largs } { global testdir global util_path global rep_verbose global verbose_type global timeout_ok env_cleanup $testdir set qdir $testdir/MSGQUEUEDIR replsetup $qdir set verbargs "" if { $rep_verbose == 1 } { set verbargs " -verbose {$verbose_type on} " } set masterdir $testdir/MASTERDIR file mkdir $masterdir set nclients 2 for { set i 0 } { $i < $nclients } { incr i } { set clientdir($i) $testdir/CLIENTDIR.$i file mkdir $clientdir($i) } # Log size is small so we quickly create more than one, and # can easily force internal initialization. set pagesize 4096 append largs " -pagesize $pagesize " set log_max [expr $pagesize * 8] set m_logtype [lindex $logset 0] set c_logtype [lindex $logset 1] # In-memory logs cannot be used with -txn nosync. set m_logargs [adjust_logargs $m_logtype] set c_logargs [adjust_logargs $c_logtype] set m_txnargs [adjust_txnargs $m_logtype] set c_txnargs [adjust_txnargs $c_logtype] # Open a master. set envlist {} repladd 1 set ma_envcmd "berkdb_env_noerr -create $m_txnargs \ $m_logargs -log_max $log_max -event rep_event $verbargs \ -home $masterdir -rep_transport \[list 1 replsend\]" set masterenv [eval $ma_envcmd -recover -rep_master] lappend envlist "$masterenv 1" # Open clients. for { set i 0 } { $i < $nclients } { incr i } { set envid [expr $i + 2] repladd $envid set envcmd($i) "berkdb_env_noerr -create \ $c_txnargs $c_logargs -log_max $log_max \ -home $clientdir($i) -event rep_event $verbargs \ -rep_transport \[list $envid replsend\]" set clientenv($i) [eval $envcmd($i) -recover -rep_client] lappend envlist "$clientenv($i) $envid" } # Bring the clients online by processing the startup messages. process_msgs $envlist # Clobber replication's 30-second anti-archive timer, which will have # been started by client sync-up internal init, so that we can do a # db_archive in a moment. # $masterenv test force noarchive_timeout # Run rep_test in the master and update clients. puts "\tRep$tnum.a: Running rep_test in replicated env." set start 0 eval rep_test \ $method $masterenv NULL $niter $start $start 0 0 $largs incr start $niter process_msgs $envlist 0 NONE err error_check_good process_msgs $err 0 # Find out what exists on the client. We need to loop until # the first master log file > last client log file. The two # clients should be the same, so just inspect one. puts "\tRep$tnum.b: Close clients." if { $c_logtype != "in-memory" } { set res [eval exec $util_path/db_archive -l -h $clientdir(0)] set res [eval exec $util_path/db_archive -l -h $clientdir(1)] } set last_client_log [get_logfile $clientenv(1) last] for { set i 0 } { $i < $nclients } { incr i } { error_check_good client_close [$clientenv($i) close] 0 } set envlist [lreplace $envlist 1 2] # Run the master forward. set stop 0 while { $stop == 0 } { puts "\tRep$tnum.c: Running rep_test in replicated env." eval rep_test \ $method $masterenv NULL $niter $start $start 0 0 $largs incr start $niter puts "\tRep$tnum.d: Run db_archive on master." if { $m_logtype != "in-memory"} { set res [eval \ exec $util_path/db_archive -d -h $masterdir] } set first_master_log [get_logfile $masterenv first] if { $first_master_log > $last_client_log } { set stop 1 } } for { set i 0 } { $i < $nclients } { incr i } { set envid [expr $i + 2] replclear $envid } # Reopen clients. puts "\tRep$tnum.e: Reopen clients." for { set i 0 } { $i < $nclients } { incr i } { env_cleanup $clientdir($i) set clientenv($i) [eval $envcmd($i) -recover -rep_client] set envid [expr $i + 2] lappend envlist "$clientenv($i) $envid" } # Run proc_msgs_once until both clients are in internal # initialization. # # We figure out whether each client is in initialization # by searching for any of the flags REP_F_RECOVER_UPDATE, # REP_F_RECOVER_PAGE, and REP_F_RECOVER_LOG. As soon as # a client produces one of these, it's marked as being # in initialization, and stays that way even if it proceeds # further, but we don't exit the loop until all clients # have gotten into initialization. # puts "\tRep$tnum.f:\ Run proc_msgs_once until all clients enter internal init." set in_init 0 for { set i 0 } { $i < $nclients } { incr i } { set initializing($i) 0 } while { $in_init != 1 } { set nproced [proc_msgs_once $envlist NONE err] for { set i 0 } { $i < $nclients } { incr i } { set stat($i) \ [exec $util_path/db_stat -r -R A -h $clientdir(1)] if {[is_substr $stat($i) "REP_F_RECOVER_UPDATE"] } { set initializing($i) 1 } if {[is_substr $stat($i) "REP_F_RECOVER_PAGE"] } { set initializing($i) 1 } if {[is_substr $stat($i) "REP_F_RECOVER_LOG"] } { set initializing($i) 1 } } set in_init 1 for { set i 0 } { $i < $nclients } { incr i } { if { $initializing($i) == 0 } { set in_init 0 } } } # Call an election. It should fail, because both clients # are in internal initialization and therefore not electable. # Indicate failure with winner = -2. # First, close the master. error_check_good masterenv_close [$masterenv close] 0 set envlist [lreplace $envlist 0 0] puts "\tRep$tnum.g: Run election; no one will get elected." set m "Rep$tnum.g" set nsites $nclients set nvotes $nclients set winner -2 set elector 0 for { set i 0 } { $i < $nclients } { incr i } { set err_cmd($i) "none" set crash($i) 0 set pri($i) 10 } # This election will time out instead of succeeding. set timeout_ok 1 run_election envcmd envlist err_cmd pri crash \ $qdir $m $elector $nsites $nvotes $nclients $winner \ 0 "test.db" 0 $timeout_ok # Verify that each client saw the message that no # electable site was found. puts "\tRep$tnum.h: Check for right error message." for { set i 0 } { $i < $nclients } { incr i } { set none_electable 0 set id [expr $i + 1] set fd [open $testdir/ELECTION_RESULT.$id r] while { [gets $fd str] != -1 } { if { [is_substr $str "Unable to elect a master"] == 1 } { set none_electable 1 break } } close $fd error_check_good none_electable $none_electable 1 } # Clean up for the next pass. for { set i 0 } { $i < $nclients } { incr i } { $clientenv($i) close } replclose $testdir/MSGQUEUEDIR }