📄 reputils.tcl
字号:
# In order to make sure that we have fully-synced and ready-to-verify # databases on all the clients, do a checkpoint on the master and # process messages in order to flush all the clients. set drop 0 set do_check 0 set name [format "Repl%03d" $tnum] berkdb debug_check puts "\t$name: Checkpointing master." error_check_good masterenv_ckp [$repenv(master) txn_checkpoint] 0 # Count clients. for { set ncli 0 } { 1 } { incr ncli } { if { $repenv($ncli) == "NULL" } { break } } repl_envprocq $tnum $ncli error_check_good masterenv_close [$repenv(master) close] 0 verify_dir $masterdir "\t$name: " 0 0 1 for { set i 0 } { $i < $ncli } { incr i } { error_check_good client($i)_close [$repenv($i) close] 0 verify_dir $clientdir($i) "\t$name: " 0 0 1 } replclose $testdir/MSGQUEUEDIR}# Close up a replication groupproc replclose { queuedir } { global queueenv queuedbs machids foreach m $machids { set db $queuedbs($m) error_check_good dbr_close [$db close] 0 } error_check_good qenv_close [$queueenv close] 0 set machids {}}# Create a replication group for testing.proc replsetup { queuedir } { global queueenv queuedbs machids file mkdir $queuedir set queueenv \ [berkdb_env -create -txn -lock_max 20000 -home $queuedir] error_check_good queueenv [is_valid_env $queueenv] TRUE if { [info exists queuedbs] } { unset queuedbs } set machids {} return $queueenv}# Send function for replication.proc replsend { control rec fromid toid } { global queuedbs queueenv machids global drop drop_msg # # If we are testing with dropped messages, then we drop every # $drop_msg time. If we do that just return 0 and don't do # anything. # if { $drop != 0 } { incr drop if { $drop == $drop_msg } { set drop 1 return 0 } } # XXX # -1 is DB_BROADCAST_MID if { $toid == -1 } { set machlist $machids } else { if { [info exists queuedbs($toid)] != 1 } { error "replsend: machid $toid not found" } set machlist [list $toid] } foreach m $machlist { # XXX should a broadcast include to "self"? if { $m == $fromid } { continue } set db $queuedbs($m) set txn [$queueenv txn] $db put -txn $txn -append [list $control $rec $fromid] error_check_good replsend_commit [$txn commit] 0 } return 0}# Nuke all the pending messages for a particular site.proc replclear { machid } { global queuedbs queueenv if { [info exists queuedbs($machid)] != 1 } { error "FAIL: replclear: machid $machid not found" } set db $queuedbs($machid) set txn [$queueenv txn] set dbc [$db cursor -txn $txn] for { set dbt [$dbc get -rmw -first] } { [llength $dbt] > 0 } \ { set dbt [$dbc get -rmw -next] } { error_check_good replclear($machid)_del [$dbc del] 0 } error_check_good replclear($machid)_dbc_close [$dbc close] 0 error_check_good replclear($machid)_txn_commit [$txn commit] 0}# Add a machine to a replication environment.proc repladd { machid } { global queueenv queuedbs machids if { [info exists queuedbs($machid)] == 1 } { error "FAIL: repladd: machid $machid already exists" } set queuedbs($machid) [berkdb open -auto_commit \ -env $queueenv -create -recno -renumber repqueue$machid.db] error_check_good repqueue_create [is_valid_db $queuedbs($machid)] TRUE lappend machids $machid}# Process a queue of messages, skipping every "skip_interval" entry.# We traverse the entire queue, but since we skip some messages, we# may end up leaving things in the queue, which should get picked up# on a later run.proc replprocessqueue { dbenv machid { skip_interval 0 } \ { hold_electp NONE } { newmasterp NONE } } { global queuedbs queueenv errorCode # hold_electp is a call-by-reference variable which lets our caller # know we need to hold an election. if { [string compare $hold_electp NONE] != 0 } { upvar $hold_electp hold_elect } set hold_elect 0 # newmasterp is the same idea, only returning the ID of a master # given in a DB_REP_NEWMASTER return. if { [string compare $newmasterp NONE] != 0 } { upvar $newmasterp newmaster } set newmaster 0 set nproced 0 set txn [$queueenv txn] set dbc [$queuedbs($machid) cursor -txn $txn] error_check_good process_dbc($machid) \ [is_valid_cursor $dbc $queuedbs($machid)] TRUE for { set dbt [$dbc get -first] } \ { [llength $dbt] != 0 } \ { set dbt [$dbc get -next] } { set data [lindex [lindex $dbt 0] 1] # If skip_interval is nonzero, we want to process messages # out of order. We do this in a simple but slimy way-- # continue walking with the cursor without processing the # message or deleting it from the queue, but do increment # "nproced". The way this proc is normally used, the # precise value of nproced doesn't matter--we just don't # assume the queues are empty if it's nonzero. Thus, # if we contrive to make sure it's nonzero, we'll always # come back to records we've skipped on a later call # to replprocessqueue. (If there really are no records, # we'll never get here.) # # Skip every skip_interval'th record (and use a remainder other # than zero so that we're guaranteed to really process at least # one record on every call). if { $skip_interval != 0 } { if { $nproced % $skip_interval == 1 } { incr nproced continue } } # We have to play an ugly cursor game here: we currently # hold a lock on the page of messages, but rep_process_message # might need to lock the page with a different cursor in # order to send a response. So save our recno, close # the cursor, and then reopen and reset the cursor. set recno [lindex [lindex $dbt 0] 0] error_check_good dbc_process_close [$dbc close] 0 error_check_good txn_commit [$txn commit] 0 set ret [catch {$dbenv rep_process_message \ [lindex $data 2] [lindex $data 0] [lindex $data 1]} res] set txn [$queueenv txn] set dbc [$queuedbs($machid) cursor -txn $txn] set dbt [$dbc get -set $recno] if { $ret != 0 } { if { [is_substr $res DB_REP_HOLDELECTION] } { set hold_elect 1 } else { error "FAIL:[timestamp]\ rep_process_message returned $res" } } incr nproced $dbc del if { $ret == 0 && $res != 0 } { if { [is_substr $res DB_REP_NEWSITE] } { # NEWSITE; do nothing. } else { set newmaster $res # Break as soon as we get a NEWMASTER message; # our caller needs to handle it. break } } if { $hold_elect == 1 } { # Break also on a HOLDELECTION, for the same reason. break } } error_check_good dbc_close [$dbc close] 0 error_check_good txn_commit [$txn commit] 0 # Return the number of messages processed. return $nproced}set run_repl_flag "-run_repl"proc extract_repl_args { args } { global run_repl_flag for { set arg [lindex $args [set i 0]] } \ { [string length $arg] > 0 } \ { set arg [lindex $args [incr i]] } { if { [string compare $arg $run_repl_flag] == 0 } { return [lindex $args [expr $i + 1]] } } return ""}proc delete_repl_args { args } { global run_repl_flag set ret {} for { set arg [lindex $args [set i 0]] } \ { [string length $arg] > 0 } \ { set arg [lindex $args [incr i]] } { if { [string compare $arg $run_repl_flag] != 0 } { lappend ret $arg } else { incr i } } return $ret}global elect_serialglobal elections_in_progressset elect_serial 0# Start an election in a sub-process.proc start_election { qdir envstring nsites pri timeout {err "none"}} { source ./include.tcl global elect_serial elect_timeout elections_in_progress machids incr elect_serial set t [open "|$tclsh_path >& $testdir/ELECTION_OUTPUT.$elect_serial" w] puts $t "source $test_path/test.tcl" puts $t "replsetup $qdir" foreach i $machids { puts $t "repladd $i" } puts $t "set env_cmd \{$envstring\}" puts $t "set dbenv \[eval \$env_cmd -errfile \ $testdir/ELECTION_ERRFILE.$elect_serial -errpfx FAIL: \]"# puts "Start election err $err, env $envstring" puts $t "\$dbenv test abort $err" puts $t "set res \[catch \{\$dbenv rep_elect $nsites $pri \ $elect_timeout\} ret\]" if { $err != "none" } { puts $t "\$dbenv test abort none" puts $t "set res \[catch \{\$dbenv rep_elect $nsites $pri \ $elect_timeout\} ret\]" } flush $t set elections_in_progress($elect_serial) $t return $elect_serial}proc close_election { i } { global elections_in_progress set t $elections_in_progress($i) puts $t "\$dbenv close" close $t unset elections_in_progress($i)}proc cleanup_elections { } { global elect_serial elections_in_progress for { set i 0 } { $i <= $elect_serial } { incr i } { if { [info exists elections_in_progress($i)] != 0 } { close_election $i } } set elect_serial 0}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -