recd012.tcl
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:13k
- # See the file LICENSE for redistribution information.
- #
- # Copyright (c) 2000
- # Sleepycat Software. All rights reserved.
- #
- # $Id: recd012.tcl,v 11.14 2000/12/11 17:24:55 sue Exp $
- #
- # Recovery Test 12.
- # Test recovery handling of file opens and closes.
- proc recd012 { method {start 0}
- {niter 49} {noutiter 25} {niniter 100} {ndbs 5} args } {
- source ./include.tcl
- set tnum 12
- set pagesize 512
- if { $is_qnx_test } {
- set niter 40
- }
- puts "Recd0$tnum $method ($args): Test recovery file management."
- set pgindex [lsearch -exact $args "-pagesize"]
- if { $pgindex != -1 } {
- puts "Recd012: skipping for specific pagesizes"
- return
- }
-
- for { set i $start } { $i <= $niter } { incr i } {
-
- env_cleanup $testdir
- # For repeatability, we pass in the iteration number
- # as a parameter and use that in recd012_body to seed
- # the random number generator to randomize our operations.
- # This lets us re-run a potentially failing iteration
- # without having to start from the beginning and work
- # our way to it.
- #
- # The number of databases ranges from 4 to 8 and is
- # a function of $niter
- # set ndbs [expr ($i % 5) + 4]
-
- recd012_body
- $method $ndbs $i $noutiter $niniter $pagesize $tnum $args
- }
- }
- proc recd012_body { method {ndbs 5} iter noutiter niniter psz tnum {largs ""} } {
- global alphabet rand_init fixed_len recd012_ofkey recd012_ofckptkey
- source ./include.tcl
- set largs [convert_args $method $largs]
- set omethod [convert_method $method]
- puts "tRecd0$tnum $method ($largs): Iteration $iter"
- puts "ttRecd0$tnum.a: Create environment and $ndbs databases."
- set flags "-create -txn -home $testdir"
- set env_cmd "berkdb env $flags"
- error_check_good env_remove [berkdb envremove -home $testdir] 0
- set dbenv [eval $env_cmd]
- error_check_good dbenv [is_valid_env $dbenv] TRUE
- # Initialize random number generator based on $iter.
- berkdb srand [expr $iter + $rand_init]
- # Initialize database that keeps track of number of open files (so
- # we don't run out of descriptors).
- set ofname of.db
- set ofdb [berkdb_open -env $dbenv
- -create -dup -mode 0644 -btree -pagesize 512 $ofname]
- error_check_good of_open [is_valid_db $ofdb] TRUE
- set oftxn [$dbenv txn]
- error_check_good of_txn [is_valid_txn $oftxn $dbenv] TRUE
- error_check_good of_put [$ofdb put -txn $oftxn $recd012_ofkey 1] 0
- error_check_good of_put2 [$ofdb put -txn $oftxn $recd012_ofckptkey 0] 0
- error_check_good of_put3 [$ofdb put -txn $oftxn $recd012_ofckptkey 0] 0
- error_check_good of_txn_commit [$oftxn commit] 0
- error_check_good of_close [$ofdb close] 0
- # Create ndbs databases to work in, and a file listing db names to
- # pick from.
- set f [open TESTDIR/dblist w]
- set oflags
- "-env $dbenv -create -mode 0644 -pagesize $psz $largs $omethod"
- for { set i 0 } { $i < $ndbs } { incr i } {
- # 50-50 chance of being a subdb, unless we're a queue.
- if { [berkdb random_int 0 1] || [is_queue $method] } {
- # not a subdb
- set dbname recd0$tnum-$i.db
- } else {
- # subdb
- set dbname "recd0$tnum-subdb.db s$i"
- }
- puts $f $dbname
- set db [eval berkdb_open $oflags $dbname]
- error_check_good db($i) [is_valid_db $db] TRUE
- error_check_good db($i)_close [$db close] 0
- }
- close $f
- error_check_good env_close [$dbenv close] 0
-
- # Now we get to the meat of things. Our goal is to do some number
- # of opens, closes, updates, and shutdowns (simulated here by a
- # close of all open handles and a close/reopen of the environment,
- # with or without an envremove), matching the regular expression
- #
- # ((O[OUC]+S)+R+V)
- #
- # We'll repeat the inner + a random number up to $niniter times,
- # and the outer + a random number up to $noutiter times.
- #
- # In order to simulate shutdowns, we'll perform the opens, closes,
- # and updates in a separate process, which we'll exit without closing
- # all handles properly. The environment will be left lying around
- # before we run recovery 50% of the time.
- set out [berkdb random_int 1 $noutiter]
- puts "ttRecd0$tnum.b: Performing $out recoveries of up to $niniter
- ops."
- for { set i 0 } { $i < $out } { incr i } {
- set child [open "|$tclsh_path" w]
-
- # For performance, don't source everything,
- # just what we'll need.
- puts $child "load $tcllib"
- puts $child "set fixed_len $fixed_len"
- puts $child "source ../test/testutils.tcl"
- puts $child "source ../test/recd0$tnum.tcl"
- set rnd [expr $iter * 10000 + $i * 100 + $rand_init]
- # Go.
- # puts "recd012_dochild {$env_cmd} $rnd $i $niniter
- # $ndbs $tnum $method $ofname $largs"
- puts $child "recd012_dochild {$env_cmd} $rnd $i $niniter
- $ndbs $tnum $method $ofname $largs"
- close $child
- # Run recovery 0-3 times.
- set nrecs [berkdb random_int 0 3]
- for { set j 0 } { $j < $nrecs } { incr j } {
- set ret [catch {exec $util_path/db_recover
- -h $testdir} res]
- if { $ret != 0 } {
- puts "FAIL: db_recover returned with nonzero
- exit status, output as follows:"
- file mkdir /tmp/12out
- set fd [open /tmp/12out/[pid] w]
- puts $fd $res
- close $fd
- }
- error_check_good recover($j) $ret 0
- }
-
- }
- # Run recovery one final time; it doesn't make sense to
- # check integrity if we do not.
- set ret [catch {exec $util_path/db_recover -h $testdir} res]
- if { $ret != 0 } {
- puts "FAIL: db_recover returned with nonzero
- exit status, output as follows:"
- puts $res
- }
- # Make sure each datum is the correct filename.
- puts "ttRecd0$tnum.c: Checking data integrity."
- set dbenv [berkdb env -create -private -home $testdir]
- error_check_good env_open_integrity [is_valid_env $dbenv] TRUE
- set f [open TESTDIR/dblist r]
- set i 0
- while { [gets $f dbinfo] > 0 } {
- set db [eval berkdb_open -env $dbenv $dbinfo]
- error_check_good dbopen($dbinfo) [is_valid_db $db] TRUE
- set dbc [$db cursor]
- error_check_good cursor [is_valid_cursor $dbc $db] TRUE
- for { set dbt [$dbc get -first] } { [llength $dbt] > 0 }
- { set dbt [$dbc get -next] } {
- error_check_good integrity [lindex [lindex $dbt 0] 1]
- [pad_data $method $dbinfo]
- }
- error_check_good dbc_close [$dbc close] 0
- error_check_good db_close [$db close] 0
- }
- close $f
- error_check_good env_close_integrity [$dbenv close] 0
-
- # Verify
- error_check_good verify [verify_dir $testdir "ttRecd0$tnum.d: "] 0
- }
- proc recd012_dochild { env_cmd rnd outiter niniter ndbs tnum method
- ofname args } {
- global recd012_ofkey
- if { [is_record_based $method] } {
- set keybase ""
- } else {
- set keybase .[repeat abcdefghijklmnopqrstuvwxyz 4]
- }
-
- # Initialize our random number generator, repeatably based on an arg.
- berkdb srand $rnd
- # Open our env.
- set dbenv [eval $env_cmd]
- error_check_good env_open [is_valid_env $dbenv] TRUE
- # Find out how many databases appear to be open in the log--we
- # don't want recovery to run out of filehandles.
- set ofdb [berkdb_open -env $dbenv $ofname]
- set oftxn [$dbenv txn]
- error_check_good of_txn [is_valid_txn $oftxn $dbenv] TRUE
- set dbt [$ofdb get -txn $oftxn $recd012_ofkey]
- error_check_good of_get [lindex [lindex $dbt 0] 0] $recd012_ofkey
- set nopenfiles [lindex [lindex $dbt 0] 1]
- error_check_good of_commit [$oftxn commit] 0
- # Read our dbnames
- set f [open TESTDIR/dblist r]
- set i 0
- while { [gets $f dbname($i)] > 0 } {
- incr i
- }
- close $f
- # We now have $ndbs extant databases.
- # Open one of them, just to get us started.
- set opendbs {}
- set oflags "-env $dbenv $args"
- # Start a transaction, just to get us started.
- set curtxn [$dbenv txn]
- error_check_good txn [is_valid_txn $curtxn $dbenv] TRUE
- # Inner loop. Do $in iterations of a random open, close, or
- # update, where $in is between 1 and $niniter.
- set in [berkdb random_int 1 $niniter]
- for { set j 0 } { $j < $in } { incr j } {
- set op [berkdb random_int 0 2]
- switch $op {
- 0 {
- # Open.
- recd012_open
- }
- 1 {
- # Update. Put random-number$keybase as key,
- # filename as data, into random database.
- set num_open [llength $opendbs]
- if { $num_open == 0 } {
- # If none are open, do an open first.
- recd012_open
- }
- set n [berkdb random_int 0 [expr $num_open - 1]]
- set pair [lindex $opendbs $n]
- set udb [lindex $pair 0]
- set uname [lindex $pair 1]
-
- set key [berkdb random_int 1000 1999]$keybase
- set data [chop_data $method $uname]
- error_check_good put($uname,$udb,$key,$data)
- [$udb put -txn $curtxn $key $data] 0
- # One time in four, commit the transaction.
- if { [berkdb random_int 0 3] == 0 && 0 } {
- error_check_good txn_recommit
- [$curtxn commit] 0
- set curtxn [$dbenv txn]
- error_check_good txn_reopen
- [is_valid_txn $curtxn $dbenv] TRUE
- }
- }
- 2 {
- # Close.
-
- if { [llength $opendbs] == 0 } {
- # If none are open, open instead of closing.
- recd012_open
- continue
- }
- # Commit curtxn first, lest we self-deadlock.
- error_check_good txn_recommit
- [$curtxn commit] 0
- # Do it.
- set which [berkdb random_int 0
- [expr [llength $opendbs] - 1]]
-
- set db [lindex [lindex $opendbs $which] 0]
- error_check_good db_choice [is_valid_db $db] TRUE
- global errorCode errorInfo
- error_check_good db_close
- [[lindex [lindex $opendbs $which] 0] close] 0
- set opendbs [lreplace $opendbs $which $which]
- incr nopenfiles -1
-
-
- # Reopen txn.
- set curtxn [$dbenv txn]
- error_check_good txn_reopen
- [is_valid_txn $curtxn $dbenv] TRUE
- }
- }
- # One time in two hundred, checkpoint.
- if { [berkdb random_int 0 199] == 0 } {
- puts "tttRecd0$tnum:
- Random checkpoint after operation $outiter.$j."
- error_check_good txn_ckpt
- [$dbenv txn_checkpoint] 0
- set nopenfiles
- [recd012_nopenfiles_ckpt $dbenv $ofdb $nopenfiles]
- }
- }
- # We have to commit curtxn. It'd be kind of nice not to, but
- # if we start in again without running recovery, we may block
- # ourselves.
- error_check_good curtxn_commit [$curtxn commit] 0
- # Put back the new number of open files.
- set oftxn [$dbenv txn]
- error_check_good of_txn [is_valid_txn $oftxn $dbenv] TRUE
- error_check_good of_del [$ofdb del -txn $oftxn $recd012_ofkey] 0
- error_check_good of_put
- [$ofdb put -txn $oftxn $recd012_ofkey $nopenfiles] 0
- error_check_good of_commit [$oftxn commit] 0
- error_check_good ofdb_close [$ofdb close] 0
- }
- proc recd012_open { } {
- # This is basically an inline and has to modify curtxn,
- # so use upvars.
- upvar curtxn curtxn
- upvar ndbs ndbs
- upvar dbname dbname
- upvar dbenv dbenv
- upvar oflags oflags
- upvar opendbs opendbs
- upvar nopenfiles nopenfiles
- # Return without an open if we've already opened too many files--
- # we don't want to make recovery run out of filehandles.
- if { $nopenfiles > 30 } {
- #puts "skipping--too many open files"
- return -code break
- }
- # Commit curtxn first, lest we self-deadlock.
- error_check_good txn_recommit
- [$curtxn commit] 0
- # Do it.
- set which [berkdb random_int 0 [expr $ndbs - 1]]
- set db [eval berkdb_open
- $oflags $dbname($which)]
- lappend opendbs [list $db $dbname($which)]
- # Reopen txn.
- set curtxn [$dbenv txn]
- error_check_good txn_reopen
- [is_valid_txn $curtxn $dbenv] TRUE
- incr nopenfiles
- }
- # Update the database containing the number of files that db_recover has
- # to contend with--we want to avoid letting it run out of file descriptors.
- # We do this by keeping track of the number of unclosed opens since the
- # checkpoint before last.
- # $recd012_ofkey stores this current value; the two dups available
- # at $recd012_ofckptkey store the number of opens since the last checkpoint
- # previous.
- # Thus, if the current value is 17 when we do a checkpoint, and the
- # stored values are 3 and 8, the new current value (which we return)
- # is 14, and the new stored values are 8 and 6.
- proc recd012_nopenfiles_ckpt { env db nopenfiles } {
- global recd012_ofckptkey
- set txn [$env txn]
- error_check_good nopenfiles_ckpt_txn [is_valid_txn $txn $env] TRUE
- set dbc [$db cursor -txn $txn]
- error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE
- # Get the first ckpt value and delete it.
- set dbt [$dbc get -set $recd012_ofckptkey]
- error_check_good set [llength $dbt] 1
- set discard [lindex [lindex $dbt 0] 1]
- error_check_good del [$dbc del] 0
- set nopenfiles [expr $nopenfiles - $discard]
-
- # Get the next ckpt value
- set dbt [$dbc get -nextdup]
- error_check_good set2 [llength $dbt] 1
- # Calculate how many opens we've had since this checkpoint before last.
- set onlast [lindex [lindex $dbt 0] 1]
- set sincelast [expr $nopenfiles - $onlast]
- # Put this new number at the end of the dup set.
- error_check_good put [$dbc put -keylast $recd012_ofckptkey $sincelast] 0
-
- # We should never deadlock since we're the only one in this db.
- error_check_good dbc_close [$dbc close] 0
- error_check_good txn_commit [$txn commit] 0
- return $nopenfiles
- }
- # globals -- it's not worth passing these around, as they're constants
- set recd012_ofkey OPENFILES
- set recd012_ofckptkey CKPTS