# See the file LICENSE for redistribution information. # # Copyright (c) 2010, 2012 Oracle and/or its affiliates. All rights reserved. # # TEST rep092 # TEST Read-your-writes consistency. # TEST Test events in one thread (process) waking up another sleeping thread, # TEST before a timeout expires. # proc rep092 { method { niter 20 } { tnum "092" } args } { source ./include.tcl global repfiles_in_memory # Skip for all methods except btree. if { $checking_valid_methods } { set test_methods { btree } return $test_methods } if { [is_btree $method] == 0 } { puts "Rep005: Skipping for method $method." return } puts "Rep$tnum: read-your-writes consistency, multi-thread wake-up" foreach pad_flag { no yes } { foreach txn_flag { no yes } { rep092a_sub $method $niter \ $tnum $pad_flag $txn_flag $args rep092b_sub $method $niter \ $tnum $pad_flag $txn_flag $args } } } proc rep092a_sub { method niter tnum pad in_txn largs } { source ./include.tcl global rep_verbose global testdir global verbose_type global repfiles_in_memory set verbargs "" if { $rep_verbose == 1 } { set verbargs " -verbose {$verbose_type on} " } set repmemargs "" if { $repfiles_in_memory } { set repmemargs "-rep_inmem_files " } env_cleanup $testdir replsetup $testdir/MSGQUEUEDIR set masterdir $testdir/MASTERDIR set clientdir $testdir/CLIENTDIR file mkdir $masterdir file mkdir $clientdir puts "\tRep$tnum.a: Create master and client." repladd 1 set ma_envcmd "berkdb_env_noerr -create -txn -errpfx MASTER \ $repmemargs \ $verbargs -home $masterdir -rep_transport \[list 1 replsend\]" set masterenv [eval $ma_envcmd -rep_master] repladd 2 set cl_envcmd "berkdb_env_noerr -create -txn -errpfx CLIENT \ $repmemargs -errfile /dev/stderr \ $verbargs -home $clientdir -rep_transport \[list 2 replsend\]" set clientenv [eval $cl_envcmd -rep_client] set envlist "{$masterenv 1} {$clientenv 2}" process_msgs $envlist puts "\tRep$tnum.b: Create and replicate a few warm-up txns." set start 0 eval rep_test $method $masterenv NULL $niter $start $start 0 $largs incr start $niter process_msgs $envlist puts "\tRep$tnum.c: Write txn and get its commit token." if { $pad } { eval rep_test $method $masterenv \ NULL $niter $start $start 0 $largs incr start $niter } set omethod [convert_method $method] set dbargs [convert_args $method $largs] set db [eval berkdb_open_noerr -env $masterenv -auto_commit \ -create $omethod $dbargs test.db ] set txn [$masterenv txn -token] $db put -txn $txn "key1" "data1" set token [$txn commit] $db close if { $pad } { eval rep_test $method $masterenv \ NULL $niter $start $start 0 $largs incr start $niter } # Don't process msgs just yet. We want to test the behavior when the # client checks/waits for the transaction more quickly than the client # receives it. In order to do that in a test, we simulate the # replication being rather slow, by pausing for a moment after starting # up the txn_applied thread (in a separate child Tcl process). # set pause 5 # Define an emergency upper limit on the sleeping time, so that in case # the code is broken the test won't hang forever. The child process # should complete promptly, as soon as we apply the transaction. # set limit 60 set tolerance 1 # Spawn a process to call txn_applied # puts "\tRep$tnum.d: Spawn child process, and pause to let it get started." set timeout [expr $limit * 1000000] error_check_good binary_scan [binary scan $token H40 token_chars] 1 set listing $testdir/repscript.log set pid [exec $tclsh_path $test_path/wrap.tcl \ rep092script.tcl $listing $clientdir \ $token_chars $timeout $in_txn $rep_verbose $verbose_type &] tclsleep $pause puts "\tRep$tnum.e: Apply the transaction at the client." process_msgs $envlist watch_procs $pid 1 set fd [open $listing] puts "\tRep$tnum.f: Examine the sub-process results." set report [split [read $fd] "\n"] close $fd set result [lindex [lsearch -inline $report RESULT*] 1] error_check_good wait_result $result 0 set duration [lindex [lsearch -inline $report DURATION*] 1] error_check_good no_timeout \ [expr $duration < $limit - $tolerance] 1 # Add a third client. # set clientdir2 $testdir/CLIENTDIR2 file mkdir $clientdir2 puts "\tRep$tnum.g: Add another client, and make it master." repladd 3 set cl_envcmd2 "berkdb_env_noerr -create -txn -errpfx CLIENT2 \ $repmemargs \ $verbargs -home $clientdir2 -rep_transport \[list 3 replsend\]" set clientenv2 [eval $cl_envcmd2 -rep_client] lappend envlist "$clientenv2 3" process_msgs $envlist # Swap roles between master and client2. First client will eventually # see a gen change, while waiting. # $masterenv rep_start -client $clientenv2 rep_start -master if { $pad } { eval rep_test $method $clientenv2 \ NULL $niter $start $start 0 $largs incr start $niter } set db [eval berkdb_open_noerr -env $clientenv2 -auto_commit \ -create $omethod $dbargs test.db ] set txn [$clientenv2 txn -token] $db put -txn $txn "key2" "data2" set token [$txn commit] $db close if { $pad } { eval rep_test $method $clientenv2 \ NULL $niter $start $start 0 $largs incr start $niter } puts "\tRep$tnum.h: Spawn another child process." error_check_good binary_scan [binary scan $token H40 token_chars] 1 set pid [exec $tclsh_path $test_path/wrap.tcl \ rep092script.tcl $listing $clientdir \ $token_chars $timeout $in_txn $rep_verbose $verbose_type &] tclsleep 5 puts "\tRep$tnum.i: Apply the transaction at the client." process_msgs $envlist watch_procs $pid 1 set fd [open $listing] puts "\tRep$tnum.j: Examine the sub-process results." set report [split [read $fd] "\n"] close $fd set result [lindex [lsearch -inline $report RESULT*] 1] error_check_good wait_result $result 0 set duration [lindex [lsearch -inline $report DURATION*] 1] error_check_good no_timeout2 \ [expr $duration < $limit - $tolerance] 1 $clientenv close $masterenv close $clientenv2 close replclose $testdir/MSGQUEUEDIR } proc rep092b_sub { method niter tnum pad in_txn largs } { source ./include.tcl global rep_verbose global testdir global verbose_type set verbargs "" if { $rep_verbose == 1 } { set verbargs " -verbose {$verbose_type on} " } # This part of the test only makes sense with INMEM # set repmemargs "-rep_inmem_files " env_cleanup $testdir replsetup $testdir/MSGQUEUEDIR set masterdir $testdir/MASTERDIR set clientdir $testdir/CLIENTDIR file mkdir $masterdir file mkdir $clientdir puts "\tRep$tnum.a: Create master and client." repladd 1 set ma_envcmd "berkdb_env_noerr -create -txn -errpfx MASTER \ $repmemargs \ $verbargs -home $masterdir -rep_transport \[list 1 replsend\]" set masterenv [eval $ma_envcmd -rep_master] repladd 2 set cl_envcmd "berkdb_env_noerr -create -txn -errpfx CLIENT \ $repmemargs -errfile /dev/stderr \ $verbargs -home $clientdir -rep_transport \[list 2 replsend\]" set clientenv [eval $cl_envcmd -rep_client] set envlist "{$masterenv 1} {$clientenv 2}" process_msgs $envlist puts "\tRep$tnum.b: Create and replicate a few warm-up txns." set start 0 eval rep_test $method $masterenv NULL $niter $start $start 0 $largs incr start $niter process_msgs $envlist puts "\tRep$tnum.x: Shut down client." $clientenv close puts "\tRep$tnum.c: Write txn and get its commit token." if { $pad } { eval rep_test $method $masterenv \ NULL $niter $start $start 0 $largs incr start $niter } set omethod [convert_method $method] set dbargs [convert_args $method $largs] set db [eval berkdb_open_noerr -env $masterenv -auto_commit \ -create $omethod $dbargs test.db ] set txn [$masterenv txn -token] $db put -txn $txn "key1" "data1" set token [$txn commit] $db close if { $pad } { eval rep_test $method $masterenv \ NULL $niter $start $start 0 $largs incr start $niter } puts "\tRep$tnum.x: Restart client, get partway through sync." set clientenv [eval $cl_envcmd -rep_client -recover] set envlist "{$masterenv 1} {$clientenv 2}" # This will put the client into a state where it doesn't have the LSN # history database, at a time when it needs to read it. Therefore, it # will wait for it to be materialized in the "abbreviated internal init" # cycle that is needed when in-memory databases are involved. # proc_msgs_once $envlist proc_msgs_once $envlist set pause 5 set limit 60 set tolerance 1 # Spawn a process to call txn_applied # puts "\tRep$tnum.d: Spawn child process, and pause to let it get started." set timeout [expr $limit * 1000000] error_check_good binary_scan [binary scan $token H40 token_chars] 1 set listing $testdir/repscript.log set pid [exec $tclsh_path $test_path/wrap.tcl \ rep092script.tcl $listing $clientdir \ $token_chars $timeout $in_txn $rep_verbose $verbose_type &] tclsleep $pause puts "\tRep$tnum.e: Apply the transaction at the client." process_msgs $envlist watch_procs $pid 1 set fd [open $listing] puts "\tRep$tnum.f: Examine the sub-process results." set report [split [read $fd] "\n"] close $fd set result [lindex [lsearch -inline $report RESULT*] 1] error_check_good wait_result $result 0 set duration [lindex [lsearch -inline $report DURATION*] 1] error_check_good no_timeout \ [expr $duration < $limit - $tolerance] 1 $clientenv close $masterenv close replclose $testdir/MSGQUEUEDIR }