summaryrefslogtreecommitdiff
path: root/test/testutils.tcl
diff options
context:
space:
mode:
Diffstat (limited to 'test/testutils.tcl')
-rw-r--r--test/testutils.tcl3908
1 files changed, 0 insertions, 3908 deletions
diff --git a/test/testutils.tcl b/test/testutils.tcl
deleted file mode 100644
index 98e16e2..0000000
--- a/test/testutils.tcl
+++ /dev/null
@@ -1,3908 +0,0 @@
-# See the file LICENSE for redistribution information.
-#
-# Copyright (c) 1996-2009 Oracle. All rights reserved.
-#
-# $Id$
-#
-# Test system utilities
-#
-# Timestamp -- print time along with elapsed time since last invocation
-# of timestamp.
-proc timestamp {{opt ""}} {
- global __timestamp_start
-
- set now [clock seconds]
-
- # -c accurate to the click, instead of the second.
- # -r seconds since the Epoch
- # -t current time in the format expected by db_recover -t.
- # -w wallclock time
- # else wallclock plus elapsed time.
- if {[string compare $opt "-r"] == 0} {
- return $now
- } elseif {[string compare $opt "-t"] == 0} {
- return [clock format $now -format "%y%m%d%H%M.%S"]
- } elseif {[string compare $opt "-w"] == 0} {
- return [clock format $now -format "%c"]
- } else {
- if {[string compare $opt "-c"] == 0} {
- set printclicks 1
- } else {
- set printclicks 0
- }
-
- if {[catch {set start $__timestamp_start}] != 0} {
- set __timestamp_start $now
- }
- set start $__timestamp_start
-
- set elapsed [expr $now - $start]
- set the_time [clock format $now -format ""]
- set __timestamp_start $now
-
- if { $printclicks == 1 } {
- set pc_print [format ".%08u" [__fix_num [clock clicks]]]
- } else {
- set pc_print ""
- }
-
- format "%02d:%02d:%02d$pc_print (%02d:%02d:%02d)" \
- [__fix_num [clock format $now -format "%H"]] \
- [__fix_num [clock format $now -format "%M"]] \
- [__fix_num [clock format $now -format "%S"]] \
- [expr $elapsed / 3600] \
- [expr ($elapsed % 3600) / 60] \
- [expr ($elapsed % 3600) % 60]
- }
-}
-
-proc __fix_num { num } {
- set num [string trimleft $num "0"]
- if {[string length $num] == 0} {
- set num "0"
- }
- return $num
-}
-
-# Add a {key,data} pair to the specified database where
-# key=filename and data=file contents.
-proc put_file { db txn flags file } {
- source ./include.tcl
-
- set fid [open $file r]
- fconfigure $fid -translation binary
- set data [read $fid]
- close $fid
-
- set ret [eval {$db put} $txn $flags {$file $data}]
- error_check_good put_file $ret 0
-}
-
-# Get a {key,data} pair from the specified database where
-# key=filename and data=file contents and then write the
-# data to the specified file.
-proc get_file { db txn flags file outfile } {
- source ./include.tcl
-
- set fid [open $outfile w]
- fconfigure $fid -translation binary
- if [catch {eval {$db get} $txn $flags {$file}} data] {
- puts -nonewline $fid $data
- } else {
- # Data looks like {{key data}}
- set data [lindex [lindex $data 0] 1]
- puts -nonewline $fid $data
- }
- close $fid
-}
-
-# Add a {key,data} pair to the specified database where
-# key=file contents and data=file name.
-proc put_file_as_key { db txn flags file } {
- source ./include.tcl
-
- set fid [open $file r]
- fconfigure $fid -translation binary
- set filecont [read $fid]
- close $fid
-
- # Use not the file contents, but the file name concatenated
- # before the file contents, as a key, to ensure uniqueness.
- set data $file$filecont
-
- set ret [eval {$db put} $txn $flags {$data $file}]
- error_check_good put_file $ret 0
-}
-
-# Get a {key,data} pair from the specified database where
-# key=file contents and data=file name
-proc get_file_as_key { db txn flags file} {
- source ./include.tcl
-
- set fid [open $file r]
- fconfigure $fid -translation binary
- set filecont [read $fid]
- close $fid
-
- set data $file$filecont
-
- return [eval {$db get} $txn $flags {$data}]
-}
-
-# open file and call dump_file to dumpkeys to tempfile
-proc open_and_dump_file {
- dbname env outfile checkfunc dump_func beg cont args} {
- global encrypt
- global passwd
- source ./include.tcl
-
- set encarg ""
- if { $encrypt > 0 && $env == "NULL" } {
- set encarg "-encryptany $passwd"
- }
- set envarg ""
- set txn ""
- set txnenv 0
- if { $env != "NULL" } {
- append envarg " -env $env "
- set txnenv [is_txnenv $env]
- if { $txnenv == 1 } {
- append envarg " -auto_commit "
- set t [$env txn]
- error_check_good txn [is_valid_txn $t $env] TRUE
- set txn "-txn $t"
- }
- }
- set db [eval {berkdb open} $envarg -rdonly -unknown $encarg $args $dbname]
- error_check_good dbopen [is_valid_db $db] TRUE
- $dump_func $db $txn $outfile $checkfunc $beg $cont
- if { $txnenv == 1 } {
- error_check_good txn [$t commit] 0
- }
- error_check_good db_close [$db close] 0
-}
-
-# open file and call dump_file to dumpkeys to tempfile
-proc open_and_dump_subfile {
- dbname env outfile checkfunc dump_func beg cont subdb} {
- global encrypt
- global passwd
- source ./include.tcl
-
- set encarg ""
- if { $encrypt > 0 && $env == "NULL" } {
- set encarg "-encryptany $passwd"
- }
- set envarg ""
- set txn ""
- set txnenv 0
- if { $env != "NULL" } {
- append envarg "-env $env"
- set txnenv [is_txnenv $env]
- if { $txnenv == 1 } {
- append envarg " -auto_commit "
- set t [$env txn]
- error_check_good txn [is_valid_txn $t $env] TRUE
- set txn "-txn $t"
- }
- }
- set db [eval {berkdb open -rdonly -unknown} \
- $envarg $encarg {$dbname $subdb}]
- error_check_good dbopen [is_valid_db $db] TRUE
- $dump_func $db $txn $outfile $checkfunc $beg $cont
- if { $txnenv == 1 } {
- error_check_good txn [$t commit] 0
- }
- error_check_good db_close [$db close] 0
-}
-
-# Sequentially read a file and call checkfunc on each key/data pair.
-# Dump the keys out to the file specified by outfile.
-proc dump_file { db txn outfile {checkfunc NONE} } {
- source ./include.tcl
-
- dump_file_direction $db $txn $outfile $checkfunc "-first" "-next"
-}
-
-proc dump_file_direction { db txn outfile checkfunc start continue } {
- source ./include.tcl
-
- # Now we will get each key from the DB and dump to outfile
- set c [eval {$db cursor} $txn]
- error_check_good db_cursor [is_valid_cursor $c $db] TRUE
- dump_file_walk $c $outfile $checkfunc $start $continue
- error_check_good curs_close [$c close] 0
-}
-
-proc dump_file_walk { c outfile checkfunc start continue {flag ""} } {
- set outf [open $outfile w]
- for {set d [eval {$c get} $flag $start] } \
- { [llength $d] != 0 } \
- {set d [eval {$c get} $flag $continue] } {
- set kd [lindex $d 0]
- set k [lindex $kd 0]
- set d2 [lindex $kd 1]
- if { $checkfunc != "NONE" } {
- $checkfunc $k $d2
- }
- puts $outf $k
- # XXX: Geoff Mainland
- # puts $outf "$k $d2"
- }
- close $outf
-}
-
-proc dump_binkey_file { db txn outfile checkfunc } {
- source ./include.tcl
-
- dump_binkey_file_direction $db $txn $outfile $checkfunc \
- "-first" "-next"
-}
-proc dump_bin_file { db txn outfile checkfunc } {
- source ./include.tcl
-
- dump_bin_file_direction $db $txn $outfile $checkfunc "-first" "-next"
-}
-
-# Note: the following procedure assumes that the binary-file-as-keys were
-# inserted into the database by put_file_as_key, and consist of the file
-# name followed by the file contents as key, to ensure uniqueness.
-proc dump_binkey_file_direction { db txn outfile checkfunc begin cont } {
- source ./include.tcl
-
- set d1 $testdir/d1
-
- set outf [open $outfile w]
-
- # Now we will get each key from the DB and dump to outfile
- set c [eval {$db cursor} $txn]
- error_check_good db_cursor [is_valid_cursor $c $db] TRUE
-
- set inf $d1
- for {set d [$c get $begin] } { [llength $d] != 0 } \
- {set d [$c get $cont] } {
- set kd [lindex $d 0]
- set keyfile [lindex $kd 0]
- set data [lindex $kd 1]
-
- set ofid [open $d1 w]
- fconfigure $ofid -translation binary
-
- # Chop off the first few bytes--that's the file name,
- # added for uniqueness in put_file_as_key, which we don't
- # want in the regenerated file.
- set namelen [string length $data]
- set keyfile [string range $keyfile $namelen end]
- puts -nonewline $ofid $keyfile
- close $ofid
-
- $checkfunc $data $d1
- puts $outf $data
- flush $outf
- }
- close $outf
- error_check_good curs_close [$c close] 0
- fileremove $d1
-}
-
-proc dump_bin_file_direction { db txn outfile checkfunc begin cont } {
- source ./include.tcl
-
- set d1 $testdir/d1
-
- set outf [open $outfile w]
-
- # Now we will get each key from the DB and dump to outfile
- set c [eval {$db cursor} $txn]
-
- for {set d [$c get $begin] } \
- { [llength $d] != 0 } {set d [$c get $cont] } {
- set k [lindex [lindex $d 0] 0]
- set data [lindex [lindex $d 0] 1]
- set ofid [open $d1 w]
- fconfigure $ofid -translation binary
- puts -nonewline $ofid $data
- close $ofid
-
- $checkfunc $k $d1
- puts $outf $k
- }
- close $outf
- error_check_good curs_close [$c close] 0
- fileremove -f $d1
-}
-
-proc make_data_str { key } {
- set datastr ""
- for {set i 0} {$i < 10} {incr i} {
- append datastr $key
- }
- return $datastr
-}
-
-proc error_check_bad { func result bad {txn 0}} {
- if { [binary_compare $result $bad] == 0 } {
- if { $txn != 0 } {
- $txn abort
- }
- flush stdout
- flush stderr
- error "FAIL:[timestamp] $func returned error value $bad"
- }
-}
-
-proc error_check_good { func result desired {txn 0} } {
- if { [binary_compare $desired $result] != 0 } {
- if { $txn != 0 } {
- $txn abort
- }
- flush stdout
- flush stderr
- error "FAIL:[timestamp]\
- $func: expected $desired, got $result"
- }
-}
-
-proc error_check_match { note result desired } {
- if { ![string match $desired $result] } {
- error "FAIL:[timestamp]\
- $note: expected $desired, got $result"
- }
-}
-
-# Locks have the prefix of their manager.
-proc is_substr { str sub } {
- if { [string first $sub $str] == -1 } {
- return 0
- } else {
- return 1
- }
-}
-
-proc is_serial { str } {
- global serial_tests
-
- foreach test $serial_tests {
- if { [is_substr $str $test] == 1 } {
- return 1
- }
- }
- return 0
-}
-
-proc release_list { l } {
-
- # Now release all the locks
- foreach el $l {
- catch { $el put } ret
- error_check_good lock_put $ret 0
- }
-}
-
-proc debug { {stop 0} } {
- global __debug_on
- global __debug_print
- global __debug_test
-
- set __debug_on 1
- set __debug_print 1
- set __debug_test $stop
-}
-
-# Check if each key appears exactly [llength dlist] times in the file with
-# the duplicate tags matching those that appear in dlist.
-proc dup_check { db txn tmpfile dlist {extra 0}} {
- source ./include.tcl
-
- set outf [open $tmpfile w]
- # Now we will get each key from the DB and dump to outfile
- set c [eval {$db cursor} $txn]
- set lastkey ""
- set done 0
- while { $done != 1} {
- foreach did $dlist {
- set rec [$c get "-next"]
- if { [string length $rec] == 0 } {
- set done 1
- break
- }
- set key [lindex [lindex $rec 0] 0]
- set fulldata [lindex [lindex $rec 0] 1]
- set id [id_of $fulldata]
- set d [data_of $fulldata]
- if { [string compare $key $lastkey] != 0 && \
- $id != [lindex $dlist 0] } {
- set e [lindex $dlist 0]
- error "FAIL: \tKey \
- $key, expected dup id $e, got $id"
- }
- error_check_good dupget.data $d $key
- error_check_good dupget.id $id $did
- set lastkey $key
- }
- #
- # Some tests add an extra dup (like overflow entries)
- # Check id if it exists.
- if { $extra != 0} {
- set okey $key
- set rec [$c get "-next"]
- if { [string length $rec] != 0 } {
- set key [lindex [lindex $rec 0] 0]
- #
- # If this key has no extras, go back for
- # next iteration.
- if { [string compare $key $lastkey] != 0 } {
- set key $okey
- set rec [$c get "-prev"]
- } else {
- set fulldata [lindex [lindex $rec 0] 1]
- set id [id_of $fulldata]
- set d [data_of $fulldata]
- error_check_bad dupget.data1 $d $key
- error_check_good dupget.id1 $id $extra
- }
- }
- }
- if { $done != 1 } {
- puts $outf $key
- }
- }
- close $outf
- error_check_good curs_close [$c close] 0
-}
-
-# Check if each key appears exactly [llength dlist] times in the file with
-# the duplicate tags matching those that appear in dlist.
-proc dup_file_check { db txn tmpfile dlist } {
- source ./include.tcl
-
- set outf [open $tmpfile w]
- # Now we will get each key from the DB and dump to outfile
- set c [eval {$db cursor} $txn]
- set lastkey ""
- set done 0
- while { $done != 1} {
- foreach did $dlist {
- set rec [$c get "-next"]
- if { [string length $rec] == 0 } {
- set done 1
- break
- }
- set key [lindex [lindex $rec 0] 0]
- if { [string compare $key $lastkey] != 0 } {
- #
- # If we changed files read in new contents.
- #
- set fid [open $key r]
- fconfigure $fid -translation binary
- set filecont [read $fid]
- close $fid
- }
- set fulldata [lindex [lindex $rec 0] 1]
- set id [id_of $fulldata]
- set d [data_of $fulldata]
- if { [string compare $key $lastkey] != 0 && \
- $id != [lindex $dlist 0] } {
- set e [lindex $dlist 0]
- error "FAIL: \tKey \
- $key, expected dup id $e, got $id"
- }
- error_check_good dupget.data $d $filecont
- error_check_good dupget.id $id $did
- set lastkey $key
- }
- if { $done != 1 } {
- puts $outf $key
- }
- }
- close $outf
- error_check_good curs_close [$c close] 0
-}
-
-# Parse duplicate data entries of the form N:data. Data_of returns
-# the data part; id_of returns the numerical part
-proc data_of {str} {
- set ndx [string first ":" $str]
- if { $ndx == -1 } {
- return ""
- }
- return [ string range $str [expr $ndx + 1] end]
-}
-
-proc id_of {str} {
- set ndx [string first ":" $str]
- if { $ndx == -1 } {
- return ""
- }
-
- return [ string range $str 0 [expr $ndx - 1]]
-}
-
-proc nop { {args} } {
- return
-}
-
-# Partial put test procedure.
-# Munges a data val through three different partial puts. Stores
-# the final munged string in the dvals array so that you can check
-# it later (dvals should be global). We take the characters that
-# are being replaced, make them capitals and then replicate them
-# some number of times (n_add). We do this at the beginning of the
-# data, at the middle and at the end. The parameters are:
-# db, txn, key -- as per usual. Data is the original data element
-# from which we are starting. n_replace is the number of characters
-# that we will replace. n_add is the number of times we will add
-# the replaced string back in.
-proc partial_put { method db txn gflags key data n_replace n_add } {
- global dvals
- source ./include.tcl
-
- # Here is the loop where we put and get each key/data pair
- # We will do the initial put and then three Partial Puts
- # for the beginning, middle and end of the string.
-
- eval {$db put} $txn {$key [chop_data $method $data]}
-
- # Beginning change
- set s [string range $data 0 [ expr $n_replace - 1 ] ]
- set repl [ replicate [string toupper $s] $n_add ]
-
- # This is gross, but necessary: if this is a fixed-length
- # method, and the chopped length of $repl is zero,
- # it's because the original string was zero-length and our data item
- # is all nulls. Set repl to something non-NULL.
- if { [is_fixed_length $method] && \
- [string length [chop_data $method $repl]] == 0 } {
- set repl [replicate "." $n_add]
- }
-
- set newstr [chop_data $method $repl[string range $data $n_replace end]]
- set ret [eval {$db put} $txn {-partial [list 0 $n_replace] \
- $key [chop_data $method $repl]}]
- error_check_good put $ret 0
-
- set ret [eval {$db get} $gflags $txn {$key}]
- error_check_good get $ret [list [list $key [pad_data $method $newstr]]]
-
- # End Change
- set len [string length $newstr]
- set spl [expr $len - $n_replace]
- # Handle case where $n_replace > $len
- if { $spl < 0 } {
- set spl 0
- }
-
- set s [string range $newstr [ expr $len - $n_replace ] end ]
- # Handle zero-length keys
- if { [string length $s] == 0 } { set s "A" }
-
- set repl [ replicate [string toupper $s] $n_add ]
- set newstr [chop_data $method \
- [string range $newstr 0 [expr $spl - 1 ] ]$repl]
-
- set ret [eval {$db put} $txn \
- {-partial [list $spl $n_replace] $key [chop_data $method $repl]}]
- error_check_good put $ret 0
-
- set ret [eval {$db get} $gflags $txn {$key}]
- error_check_good get $ret [list [list $key [pad_data $method $newstr]]]
-
- # Middle Change
- set len [string length $newstr]
- set mid [expr $len / 2 ]
- set beg [expr $mid - [expr $n_replace / 2] ]
- set end [expr $beg + $n_replace - 1]
- set s [string range $newstr $beg $end]
- set repl [ replicate [string toupper $s] $n_add ]
- set newstr [chop_data $method [string range $newstr 0 \
- [expr $beg - 1 ] ]$repl[string range $newstr [expr $end + 1] end]]
-
- set ret [eval {$db put} $txn {-partial [list $beg $n_replace] \
- $key [chop_data $method $repl]}]
- error_check_good put $ret 0
-
- set ret [eval {$db get} $gflags $txn {$key}]
- error_check_good get $ret [list [list $key [pad_data $method $newstr]]]
-
- set dvals($key) [pad_data $method $newstr]
-}
-
-proc replicate { str times } {
- set res $str
- for { set i 1 } { $i < $times } { set i [expr $i * 2] } {
- append res $res
- }
- return $res
-}
-
-proc repeat { str n } {
- set ret ""
- while { $n > 0 } {
- set ret $str$ret
- incr n -1
- }
- return $ret
-}
-
-proc isqrt { l } {
- set s [expr sqrt($l)]
- set ndx [expr [string first "." $s] - 1]
- return [string range $s 0 $ndx]
-}
-
-# If we run watch_procs multiple times without an intervening
-# testdir cleanup, it's possible that old sentinel files will confuse
-# us. Make sure they're wiped out before we spawn any other processes.
-proc sentinel_init { } {
- source ./include.tcl
-
- set filelist {}
- set ret [catch {glob $testdir/begin.*} result]
- if { $ret == 0 } {
- set filelist $result
- }
-
- set ret [catch {glob $testdir/end.*} result]
- if { $ret == 0 } {
- set filelist [concat $filelist $result]
- }
-
- foreach f $filelist {
- fileremove $f
- }
-}
-
-proc watch_procs { pidlist {delay 5} {max 3600} {quiet 0} } {
- source ./include.tcl
- global killed_procs
-
- set elapsed 0
- set killed_procs {}
-
- # Don't start watching the processes until a sentinel
- # file has been created for each one.
- foreach pid $pidlist {
- while { [file exists $testdir/begin.$pid] == 0 } {
- tclsleep $delay
- incr elapsed $delay
- # If pids haven't been created in one-fifth
- # of the time allowed for the whole test,
- # there's a problem. Report an error and fail.
- if { $elapsed > [expr {$max / 5}] } {
- puts "FAIL: begin.pid not created"
- break
- }
- }
- }
-
- while { 1 } {
-
- tclsleep $delay
- incr elapsed $delay
-
- # Find the list of processes with outstanding sentinel
- # files (i.e. a begin.pid and no end.pid).
- set beginlist {}
- set endlist {}
- set ret [catch {glob $testdir/begin.*} result]
- if { $ret == 0 } {
- set beginlist $result
- }
- set ret [catch {glob $testdir/end.*} result]
- if { $ret == 0 } {
- set endlist $result
- }
-
- set bpids {}
- catch {unset epids}
- foreach begfile $beginlist {
- lappend bpids [string range $begfile \
- [string length $testdir/begin.] end]
- }
- foreach endfile $endlist {
- set epids([string range $endfile \
- [string length $testdir/end.] end]) 1
- }
-
- # The set of processes that we still want to watch, $l,
- # is the set of pids that have begun but not ended
- # according to their sentinel files.
- set l {}
- foreach p $bpids {
- if { [info exists epids($p)] == 0 } {
- lappend l $p
- }
- }
-
- set rlist {}
- foreach i $l {
- set r [ catch { exec $KILL -0 $i } res ]
- if { $r == 0 } {
- lappend rlist $i
- }
- }
- if { [ llength $rlist] == 0 } {
- break
- } else {
- puts "[timestamp] processes running: $rlist"
- }
-
- if { $elapsed > $max } {
- # We have exceeded the limit; kill processes
- # and report an error
- foreach i $l {
- tclkill $i
- }
- set killed_procs $l
- }
- }
- if { $quiet == 0 } {
- puts "All processes have exited."
- }
-
- #
- # Once we are done, remove all old sentinel files.
- #
- set oldsent [glob -nocomplain $testdir/begin* $testdir/end*]
- foreach f oldsent {
- fileremove -f $f
- }
-
-}
-
-# These routines are all used from within the dbscript.tcl tester.
-proc db_init { dbp do_data } {
- global a_keys
- global l_keys
- source ./include.tcl
-
- set txn ""
- set nk 0
- set lastkey ""
-
- set a_keys() BLANK
- set l_keys ""
-
- set c [$dbp cursor]
- for {set d [$c get -first] } { [llength $d] != 0 } {
- set d [$c get -next] } {
- set k [lindex [lindex $d 0] 0]
- set d2 [lindex [lindex $d 0] 1]
- incr nk
- if { $do_data == 1 } {
- if { [info exists a_keys($k)] } {
- lappend a_keys($k) $d2]
- } else {
- set a_keys($k) $d2
- }
- }
-
- lappend l_keys $k
- }
- error_check_good curs_close [$c close] 0
-
- return $nk
-}
-
-proc pick_op { min max n } {
- if { $n == 0 } {
- return add
- }
-
- set x [berkdb random_int 1 12]
- if {$n < $min} {
- if { $x <= 4 } {
- return put
- } elseif { $x <= 8} {
- return get
- } else {
- return add
- }
- } elseif {$n > $max} {
- if { $x <= 4 } {
- return put
- } elseif { $x <= 8 } {
- return get
- } else {
- return del
- }
-
- } elseif { $x <= 3 } {
- return del
- } elseif { $x <= 6 } {
- return get
- } elseif { $x <= 9 } {
- return put
- } else {
- return add
- }
-}
-
-# random_data: Generate a string of random characters.
-# If recno is 0 - Use average to pick a length between 1 and 2 * avg.
-# If recno is non-0, generate a number between 1 and 2 ^ (avg * 2),
-# that will fit into a 32-bit integer.
-# If the unique flag is 1, then make sure that the string is unique
-# in the array "where".
-proc random_data { avg unique where {recno 0} } {
- upvar #0 $where arr
- global debug_on
- set min 1
- set max [expr $avg+$avg-1]
- if { $recno } {
- #
- # Tcl seems to have problems with values > 30.
- #
- if { $max > 30 } {
- set max 30
- }
- set maxnum [expr int(pow(2, $max))]
- }
- while {1} {
- set len [berkdb random_int $min $max]
- set s ""
- if {$recno} {
- set s [berkdb random_int 1 $maxnum]
- } else {
- for {set i 0} {$i < $len} {incr i} {
- append s [int_to_char [berkdb random_int 0 25]]
- }
- }
-
- if { $unique == 0 || [info exists arr($s)] == 0 } {
- break
- }
- }
-
- return $s
-}
-
-proc random_key { } {
- global l_keys
- global nkeys
- set x [berkdb random_int 0 [expr $nkeys - 1]]
- return [lindex $l_keys $x]
-}
-
-proc is_err { desired } {
- set x [berkdb random_int 1 100]
- if { $x <= $desired } {
- return 1
- } else {
- return 0
- }
-}
-
-proc pick_cursput { } {
- set x [berkdb random_int 1 4]
- switch $x {
- 1 { return "-keylast" }
- 2 { return "-keyfirst" }
- 3 { return "-before" }
- 4 { return "-after" }
- }
-}
-
-proc random_cursor { curslist } {
- global l_keys
- global nkeys
-
- set x [berkdb random_int 0 [expr [llength $curslist] - 1]]
- set dbc [lindex $curslist $x]
-
- # We want to randomly set the cursor. Pick a key.
- set k [random_key]
- set r [$dbc get "-set" $k]
- error_check_good cursor_get:$k [is_substr Error $r] 0
-
- # Now move forward or backward some hops to randomly
- # position the cursor.
- set dist [berkdb random_int -10 10]
-
- set dir "-next"
- set boundary "-first"
- if { $dist < 0 } {
- set dir "-prev"
- set boundary "-last"
- set dist [expr 0 - $dist]
- }
-
- for { set i 0 } { $i < $dist } { incr i } {
- set r [ record $dbc get $dir $k ]
- if { [llength $d] == 0 } {
- set r [ record $dbc get $k $boundary ]
- }
- error_check_bad dbcget [llength $r] 0
- }
- return { [linsert r 0 $dbc] }
-}
-
-proc record { args } {
-# Recording every operation makes tests ridiculously slow on
-# NT, so we are commenting this out; for debugging purposes,
-# it will undoubtedly be useful to uncomment this.
-# puts $args
-# flush stdout
- return [eval $args]
-}
-
-proc newpair { k data } {
- global l_keys
- global a_keys
- global nkeys
-
- set a_keys($k) $data
- lappend l_keys $k
- incr nkeys
-}
-
-proc rempair { k } {
- global l_keys
- global a_keys
- global nkeys
-
- unset a_keys($k)
- set n [lsearch $l_keys $k]
- error_check_bad rempair:$k $n -1
- set l_keys [lreplace $l_keys $n $n]
- incr nkeys -1
-}
-
-proc changepair { k data } {
- global l_keys
- global a_keys
- global nkeys
-
- set a_keys($k) $data
-}
-
-proc changedup { k olddata newdata } {
- global l_keys
- global a_keys
- global nkeys
-
- set d $a_keys($k)
- error_check_bad changedup:$k [llength $d] 0
-
- set n [lsearch $d $olddata]
- error_check_bad changedup:$k $n -1
-
- set a_keys($k) [lreplace $a_keys($k) $n $n $newdata]
-}
-
-# Insert a dup into the a_keys array with DB_KEYFIRST.
-proc adddup { k olddata newdata } {
- global l_keys
- global a_keys
- global nkeys
-
- set d $a_keys($k)
- if { [llength $d] == 0 } {
- lappend l_keys $k
- incr nkeys
- set a_keys($k) { $newdata }
- }
-
- set ndx 0
-
- set d [linsert d $ndx $newdata]
- set a_keys($k) $d
-}
-
-proc remdup { k data } {
- global l_keys
- global a_keys
- global nkeys
-
- set d [$a_keys($k)]
- error_check_bad changedup:$k [llength $d] 0
-
- set n [lsearch $d $olddata]
- error_check_bad changedup:$k $n -1
-
- set a_keys($k) [lreplace $a_keys($k) $n $n]
-}
-
-proc dump_full_file { db txn outfile checkfunc start continue } {
- source ./include.tcl
-
- set outf [open $outfile w]
- # Now we will get each key from the DB and dump to outfile
- set c [eval {$db cursor} $txn]
- error_check_good dbcursor [is_valid_cursor $c $db] TRUE
-
- for {set d [$c get $start] } { [string length $d] != 0 } {
- set d [$c get $continue] } {
- set k [lindex [lindex $d 0] 0]
- set d2 [lindex [lindex $d 0] 1]
- $checkfunc $k $d2
- puts $outf "$k\t$d2"
- }
- close $outf
- error_check_good curs_close [$c close] 0
-}
-
-proc int_to_char { i } {
- global alphabet
-
- return [string index $alphabet $i]
-}
-
-proc dbcheck { key data } {
- global l_keys
- global a_keys
- global nkeys
- global check_array
-
- if { [lsearch $l_keys $key] == -1 } {
- error "FAIL: Key |$key| not in list of valid keys"
- }
-
- set d $a_keys($key)
-
- if { [info exists check_array($key) ] } {
- set check $check_array($key)
- } else {
- set check {}
- }
-
- if { [llength $d] > 1 } {
- if { [llength $check] != [llength $d] } {
- # Make the check array the right length
- for { set i [llength $check] } { $i < [llength $d] } \
- {incr i} {
- lappend check 0
- }
- set check_array($key) $check
- }
-
- # Find this data's index
- set ndx [lsearch $d $data]
- if { $ndx == -1 } {
- error "FAIL: \
- Data |$data| not found for key $key. Found |$d|"
- }
-
- # Set the bit in the check array
- set check_array($key) [lreplace $check_array($key) $ndx $ndx 1]
- } elseif { [string compare $d $data] != 0 } {
- error "FAIL: \
- Invalid data |$data| for key |$key|. Expected |$d|."
- } else {
- set check_array($key) 1
- }
-}
-
-# Dump out the file and verify it
-proc filecheck { file txn args} {
- global check_array
- global l_keys
- global nkeys
- global a_keys
- source ./include.tcl
-
- if { [info exists check_array] == 1 } {
- unset check_array
- }
-
- eval open_and_dump_file $file NULL $file.dump dbcheck dump_full_file \
- "-first" "-next" $args
-
- # Check that everything we checked had all its data
- foreach i [array names check_array] {
- set count 0
- foreach j $check_array($i) {
- if { $j != 1 } {
- puts -nonewline "Key |$i| never found datum"
- puts " [lindex $a_keys($i) $count]"
- }
- incr count
- }
- }
-
- # Check that all keys appeared in the checked array
- set count 0
- foreach k $l_keys {
- if { [info exists check_array($k)] == 0 } {
- puts "filecheck: key |$k| not found. Data: $a_keys($k)"
- }
- incr count
- }
-
- if { $count != $nkeys } {
- puts "filecheck: Got $count keys; expected $nkeys"
- }
-}
-
-proc cleanup { dir env { quiet 0 } } {
- global gen_upgrade
- global gen_dump
- global is_qnx_test
- global is_je_test
- global old_encrypt
- global passwd
- source ./include.tcl
-
- if { $gen_upgrade == 1 || $gen_dump == 1 } {
- save_upgrade_files $dir
- }
-
-# check_handles
- set remfiles {}
- set ret [catch { glob $dir/* } result]
- if { $ret == 0 } {
- foreach fileorig $result {
- #
- # We:
- # - Ignore any env-related files, which are
- # those that have __db.* or log.* if we are
- # running in an env. Also ignore files whose
- # names start with REPDIR_; these are replication
- # subdirectories.
- # - Call 'dbremove' on any databases.
- # Remove any remaining temp files.
- #
- switch -glob -- $fileorig {
- */DIR_* -
- */__db.* -
- */log.* -
- */*.jdb {
- if { $env != "NULL" } {
- continue
- } else {
- if { $is_qnx_test } {
- catch {berkdb envremove -force \
- -home $dir} r
- }
- lappend remfiles $fileorig
- }
- }
- *.db {
- set envargs ""
- set encarg ""
- #
- # If in an env, it should be open crypto
- # or not already.
- #
- if { $env != "NULL"} {
- set file [file tail $fileorig]
- set envargs " -env $env "
- if { [is_txnenv $env] } {
- append envargs " -auto_commit "
- }
- } else {
- if { $old_encrypt != 0 } {
- set encarg "-encryptany $passwd"
- }
- set file $fileorig
- }
-
- # If a database is left in a corrupt
- # state, dbremove might not be able to handle
- # it (it does an open before the remove).
- # Be prepared for this, and if necessary,
- # just forcibly remove the file with a warning
- # message.
- set ret [catch \
- {eval {berkdb dbremove} $envargs $encarg \
- $file} res]
- # If dbremove failed and we're not in an env,
- # note that we don't have 100% certainty
- # about whether the previous run used
- # encryption. Try to remove with crypto if
- # we tried without, and vice versa.
- if { $ret != 0 } {
- if { $env == "NULL" && \
- $old_encrypt == 0} {
- set ret [catch \
- {eval {berkdb dbremove} \
- -encryptany $passwd \
- $file} res]
- }
- if { $env == "NULL" && \
- $old_encrypt == 1 } {
- set ret [catch \
- {eval {berkdb dbremove} \
- $file} res]
- }
- if { $ret != 0 } {
- if { $quiet == 0 } {
- puts \
- "FAIL: dbremove in cleanup failed: $res"
- }
- set file $fileorig
- lappend remfiles $file
- }
- }
- }
- default {
- lappend remfiles $fileorig
- }
- }
- }
- if {[llength $remfiles] > 0} {
- #
- # In the HFS file system there are cases where not
- # all files are removed on the first attempt. If
- # it fails, try again a few times.
- #
- # This bug has been compensated for in Tcl with a fix
- # checked into Tcl 8.4. When Berkeley DB requires
- # Tcl 8.5, we can remove this while loop and replace
- # it with a simple 'fileremove -f $remfiles'.
- #
- set count 0
- while { [catch {eval fileremove -f $remfiles}] == 1 \
- && $count < 5 } {
- incr count
- }
- }
-
- if { $is_je_test } {
- set rval [catch {eval {exec \
- $util_path/db_dump} -h $dir -l } res]
- if { $rval == 0 } {
- set envargs " -env $env "
- if { [is_txnenv $env] } {
- append envargs " -auto_commit "
- }
-
- foreach db $res {
- set ret [catch {eval \
- {berkdb dbremove} $envargs $db } res]
- }
- }
- }
- }
-}
-
-proc log_cleanup { dir } {
- source ./include.tcl
- global gen_upgrade_log
-
- if { $gen_upgrade_log == 1 } {
- save_upgrade_files $dir
- }
-
- set files [glob -nocomplain $dir/log.*]
- if { [llength $files] != 0} {
- foreach f $files {
- fileremove -f $f
- }
- }
-}
-
-proc env_cleanup { dir } {
- global old_encrypt
- global passwd
- source ./include.tcl
-
- set encarg ""
- if { $old_encrypt != 0 } {
- set encarg "-encryptany $passwd"
- }
- set stat [catch {eval {berkdb envremove -home} $dir $encarg} ret]
- #
- # If something failed and we are left with a region entry
- # in /dev/shmem that is zero-length, the envremove will
- # succeed, and the shm_unlink will succeed, but it will not
- # remove the zero-length entry from /dev/shmem. Remove it
- # using fileremove or else all other tests using an env
- # will immediately fail.
- #
- if { $is_qnx_test == 1 } {
- set region_files [glob -nocomplain /dev/shmem/$dir*]
- if { [llength $region_files] != 0 } {
- foreach f $region_files {
- fileremove -f $f
- }
- }
- }
- log_cleanup $dir
- cleanup $dir NULL
-}
-
-# Start an RPC server. Don't return to caller until the
-# server is up. Wait up to $maxwait seconds.
-proc rpc_server_start { { encrypted 0 } { maxwait 30 } { args "" } } {
- source ./include.tcl
- global rpc_svc
- global passwd
-
- set encargs ""
- # Set -v for verbose messages from the RPC server.
- # set encargs " -v "
-
- if { $encrypted == 1 } {
- set encargs " -P $passwd "
- }
-
- if { [string compare $rpc_server "localhost"] == 0 } {
- set dpid [eval {exec $util_path/$rpc_svc \
- -h $rpc_testdir} $args $encargs &]
- } else {
- set dpid [eval {exec rsh $rpc_server \
- $rpc_path/$rpc_svc -h $rpc_testdir $args} &]
- }
-
- # Wait a couple of seconds before we start looking for
- # the server.
- tclsleep 2
- set home [file tail $rpc_testdir]
- if { $encrypted == 1 } {
- set encargs " -encryptaes $passwd "
- }
- for { set i 0 } { $i < $maxwait } { incr i } {
- # Try an operation -- while it fails with NOSERVER, sleep for
- # a second and retry.
- if {[catch {berkdb envremove -force -home "$home.FAIL" \
- -server $rpc_server} res] && \
- [is_substr $res DB_NOSERVER:]} {
- tclsleep 1
- } else {
- # Server is up, clean up and return to caller
- break
- }
- if { $i >= $maxwait } {
- puts "FAIL: RPC server\
- not started after $maxwait seconds"
- }
- }
- return $dpid
-}
-
-proc remote_cleanup { server dir localdir } {
- set home [file tail $dir]
- error_check_good cleanup:remove [berkdb envremove -home $home \
- -server $server] 0
- catch {exec rsh $server rm -f $dir/*} ret
- cleanup $localdir NULL
-}
-
-proc help { cmd } {
- if { [info command $cmd] == $cmd } {
- set is_proc [lsearch [info procs $cmd] $cmd]
- if { $is_proc == -1 } {
- # Not a procedure; must be a C command
- # Let's hope that it takes some parameters
- # and that it prints out a message
- puts "Usage: [eval $cmd]"
- } else {
- # It is a tcl procedure
- puts -nonewline "Usage: $cmd"
- set args [info args $cmd]
- foreach a $args {
- set is_def [info default $cmd $a val]
- if { $is_def != 0 } {
- # Default value
- puts -nonewline " $a=$val"
- } elseif {$a == "args"} {
- # Print out flag values
- puts " options"
- args
- } else {
- # No default value
- puts -nonewline " $a"
- }
- }
- puts ""
- }
- } else {
- puts "$cmd is not a command"
- }
-}
-
-# Run a recovery test for a particular operation
-# Notice that we catch the return from CP and do not do anything with it.
-# This is because Solaris CP seems to exit non-zero on occasion, but
-# everything else seems to run just fine.
-#
-# We split it into two functions so that the preparation and command
-# could be executed in a different process than the recovery.
-#
-proc op_codeparse { encodedop op } {
- set op1 ""
- set op2 ""
- switch $encodedop {
- "abort" {
- set op1 $encodedop
- set op2 ""
- }
- "commit" {
- set op1 $encodedop
- set op2 ""
- }
- "prepare-abort" {
- set op1 "prepare"
- set op2 "abort"
- }
- "prepare-commit" {
- set op1 "prepare"
- set op2 "commit"
- }
- "prepare-discard" {
- set op1 "prepare"
- set op2 "discard"
- }
- }
-
- if { $op == "op" } {
- return $op1
- } else {
- return $op2
- }
-}
-
-proc op_recover { encodedop dir env_cmd dbfile cmd msg args} {
- source ./include.tcl
-
- set op [op_codeparse $encodedop "op"]
- set op2 [op_codeparse $encodedop "sub"]
- puts "\t$msg $encodedop"
- set gidf ""
- # puts "op_recover: $op $dir $env_cmd $dbfile $cmd $args"
- if { $op == "prepare" } {
- sentinel_init
-
- # Fork off a child to run the cmd
- # We append the gid, so start here making sure
- # we don't have old gid's around.
- set outfile $testdir/childlog
- fileremove -f $testdir/gidfile
- set gidf $testdir/gidfile
- set pidlist {}
- # puts "$tclsh_path $test_path/recdscript.tcl $testdir/recdout \
- # $op $dir $env_cmd $dbfile $gidf $cmd"
- set p [exec $tclsh_path $test_path/wrap.tcl recdscript.tcl \
- $testdir/recdout $op $dir $env_cmd $dbfile $gidf $cmd $args &]
- lappend pidlist $p
- watch_procs $pidlist 5
- set f1 [open $testdir/recdout r]
- set r [read $f1]
- puts -nonewline $r
- close $f1
- fileremove -f $testdir/recdout
- } else {
- eval {op_recover_prep $op $dir $env_cmd $dbfile $gidf $cmd} $args
- }
- eval {op_recover_rec $op $op2 $dir $env_cmd $dbfile $gidf} $args
-}
-
-proc op_recover_prep { op dir env_cmd dbfile gidf cmd args} {
- global log_log_record_types
- global recd_debug
- global recd_id
- global recd_op
- source ./include.tcl
-
- # puts "op_recover_prep: $op $dir $env_cmd $dbfile $cmd $args"
-
- set init_file $dir/t1
- set afterop_file $dir/t2
- set final_file $dir/t3
-
- set db_cursor ""
-
- # Keep track of the log types we've seen
- if { $log_log_record_types == 1} {
- logtrack_read $dir
- }
-
- # Save the initial file and open the environment and the file
- catch { file copy -force $dir/$dbfile $dir/$dbfile.init } res
- copy_extent_file $dir $dbfile init
-
- convert_encrypt $env_cmd
- set env [eval $env_cmd]
- error_check_good envopen [is_valid_env $env] TRUE
-
- eval set args $args
- set db [eval {berkdb open -auto_commit -env $env} $args {$dbfile}]
- error_check_good dbopen [is_valid_db $db] TRUE
-
- # Dump out file contents for initial case
- eval open_and_dump_file $dbfile $env $init_file nop \
- dump_file_direction "-first" "-next" $args
-
- set t [$env txn]
- error_check_bad txn_begin $t NULL
- error_check_good txn_begin [is_substr $t "txn"] 1
-
- # Now fill in the db, tmgr, and the txnid in the command
- set exec_cmd $cmd
-
- set items [lsearch -all $cmd ENV]
- foreach i $items {
- set exec_cmd [lreplace $exec_cmd $i $i $env]
- }
-
- set items [lsearch -all $cmd TXNID]
- foreach i $items {
- set exec_cmd [lreplace $exec_cmd $i $i $t]
- }
-
- set items [lsearch -all $cmd DB]
- foreach i $items {
- set exec_cmd [lreplace $exec_cmd $i $i $db]
- }
-
- set i [lsearch $cmd DBC]
- if { $i != -1 } {
- set db_cursor [$db cursor -txn $t]
- $db_cursor get -first
- }
- set adjust 0
- set items [lsearch -all $cmd DBC]
- foreach i $items {
- # make sure the cursor is pointing to something.
- set exec_cmd [lreplace $exec_cmd \
- [expr $i + $adjust] [expr $i + $adjust] $db_cursor]
- set txn_pos [lsearch $exec_cmd -txn]
- if { $txn_pos != -1} {
- # Strip out the txn parameter, we've applied it to the
- # cursor.
- set exec_cmd \
- [lreplace $exec_cmd $txn_pos [expr $txn_pos + 1]]
- # Now the offsets in the items list are out-of-whack,
- # keep track of how far.
- set adjust [expr $adjust - 2]
- }
- }
-
- # To test DB_CONSUME, we need to expect a record return, not "0".
- set i [lsearch $exec_cmd "-consume"]
- if { $i != -1 } {
- set record_exec_cmd_ret 1
- } else {
- set record_exec_cmd_ret 0
- }
-
- # For the DB_APPEND test, we need to expect a return other than
- # 0; set this flag to be more lenient in the error_check_good.
- set i [lsearch $exec_cmd "-append"]
- if { $i != -1 } {
- set lenient_exec_cmd_ret 1
- } else {
- set lenient_exec_cmd_ret 0
- }
-
- # For some partial tests we want to execute multiple commands. Pull
- # pull them out here.
- set last 0
- set exec_cmd2 ""
- set exec_cmds [list]
- set items [lsearch -all $exec_cmd NEW_CMD]
- foreach i $items {
- if { $last == 0 } {
- set exec_cmd2 [lrange $exec_cmd 0 [expr $i - 1]]
- } else {
- lappend exec_cmds [lrange $exec_cmd \
- [expr $last + 1] [expr $i - 1]]
- }
- set last $i
- }
- if { $last != 0 } {
- lappend exec_cmds [lrange $exec_cmd [expr $last + 1] end]
- set exec_cmd $exec_cmd2
- }
- #puts "exec_cmd: $exec_cmd"
- #puts "exec_cmds: $exec_cmds"
-
- # Execute command and commit/abort it.
- set ret [eval $exec_cmd]
- if { $record_exec_cmd_ret == 1 } {
- error_check_good "\"$exec_cmd\"" [llength [lindex $ret 0]] 2
- } elseif { $lenient_exec_cmd_ret == 1 } {
- error_check_good "\"$exec_cmd\"" [expr $ret > 0] 1
- } else {
- error_check_good "\"$exec_cmd\"" $ret 0
- }
- # If there are additional commands, run them.
- foreach curr_cmd $exec_cmds {
- error_check_good "\"$curr_cmd\"" $ret 0
- }
-
- # If a cursor was created, close it now.
- if {$db_cursor != ""} {
- error_check_good close:$db_cursor [$db_cursor close] 0
- }
-
- set record_exec_cmd_ret 0
- set lenient_exec_cmd_ret 0
-
- # Sync the file so that we can capture a snapshot to test recovery.
- error_check_good sync:$db [$db sync] 0
-
- catch { file copy -force $dir/$dbfile $dir/$dbfile.afterop } res
- copy_extent_file $dir $dbfile afterop
- eval open_and_dump_file $dir/$dbfile.afterop NULL \
- $afterop_file nop dump_file_direction "-first" "-next" $args
-
- #puts "\t\t\tExecuting txn_$op:$t"
- if { $op == "prepare" } {
- set gid [make_gid global:$t]
- set gfd [open $gidf w+]
- puts $gfd $gid
- close $gfd
- error_check_good txn_$op:$t [$t $op $gid] 0
- } else {
- error_check_good txn_$op:$t [$t $op] 0
- }
-
- switch $op {
- "commit" { puts "\t\tCommand executed and committed." }
- "abort" { puts "\t\tCommand executed and aborted." }
- "prepare" { puts "\t\tCommand executed and prepared." }
- }
-
- # Sync the file so that we can capture a snapshot to test recovery.
- error_check_good sync:$db [$db sync] 0
-
- catch { file copy -force $dir/$dbfile $dir/$dbfile.final } res
- copy_extent_file $dir $dbfile final
- eval open_and_dump_file $dir/$dbfile.final NULL \
- $final_file nop dump_file_direction "-first" "-next" $args
-
- # If this is an abort or prepare-abort, it should match the
- # original file.
- # If this was a commit or prepare-commit, then this file should
- # match the afterop file.
- # If this was a prepare without an abort or commit, we still
- # have transactions active, and peering at the database from
- # another environment will show data from uncommitted transactions.
- # Thus we just skip this in the prepare-only case; what
- # we care about are the results of a prepare followed by a
- # recovery, which we test later.
- if { $op == "commit" } {
- filesort $afterop_file $afterop_file.sort
- filesort $final_file $final_file.sort
- error_check_good \
- diff(post-$op,pre-commit):diff($afterop_file,$final_file) \
- [filecmp $afterop_file.sort $final_file.sort] 0
- } elseif { $op == "abort" } {
- filesort $init_file $init_file.sort
- filesort $final_file $final_file.sort
- error_check_good \
- diff(initial,post-$op):diff($init_file,$final_file) \
- [filecmp $init_file.sort $final_file.sort] 0
- } else {
- # Make sure this really is one of the prepare tests
- error_check_good assert:prepare-test $op "prepare"
- }
-
- # Running recovery on this database should not do anything.
- # Flush all data to disk, close the environment and save the
- # file.
- # XXX DO NOT CLOSE FILE ON PREPARE -- if you are prepared,
- # you really have an active transaction and you're not allowed
- # to close files that are being acted upon by in-process
- # transactions.
- if { $op != "prepare" } {
- error_check_good close:$db [$db close] 0
- }
-
- #
- # If we are running 'prepare' don't close the env with an
- # active transaction. Leave it alone so the close won't
- # quietly abort it on us.
- if { [is_substr $op "prepare"] != 1 } {
- error_check_good log_flush [$env log_flush] 0
- error_check_good envclose [$env close] 0
- }
- return
-}
-
-proc op_recover_rec { op op2 dir env_cmd dbfile gidf args} {
- global log_log_record_types
- global recd_debug
- global recd_id
- global recd_op
- global encrypt
- global passwd
- source ./include.tcl
-
- #puts "op_recover_rec: $op $op2 $dir $env_cmd $dbfile $gidf"
-
- set init_file $dir/t1
- set afterop_file $dir/t2
- set final_file $dir/t3
-
- # Keep track of the log types we've seen
- if { $log_log_record_types == 1} {
- logtrack_read $dir
- }
-
- berkdb debug_check
- puts -nonewline "\t\top_recover_rec: Running recovery ... "
- flush stdout
-
- set recargs "-h $dir -c "
- if { $encrypt > 0 } {
- append recargs " -P $passwd "
- }
- set stat [catch {eval exec $util_path/db_recover -e $recargs} result]
- if { $stat == 1 } {
- error "FAIL: Recovery error: $result."
- }
- puts -nonewline "complete ... "
-
- #
- # We cannot run db_recover here because that will open an env, run
- # recovery, then close it, which will abort the outstanding txns.
- # We want to do it ourselves.
- #
- set env [eval $env_cmd]
- error_check_good dbenv [is_valid_widget $env env] TRUE
-
- if {[is_partition_callback $args] == 1 } {
- set nodump 1
- } else {
- set nodump 0
- }
- error_check_good db_verify [verify_dir $testdir "\t\t" 0 1 $nodump] 0
- puts "verified"
-
- # If we left a txn as prepared, but not aborted or committed,
- # we need to do a txn_recover. Make sure we have the same
- # number of txns we want.
- if { $op == "prepare"} {
- set txns [$env txn_recover]
- error_check_bad txnrecover [llength $txns] 0
- set gfd [open $gidf r]
- set origgid [read -nonewline $gfd]
- close $gfd
- set txnlist [lindex $txns 0]
- set t [lindex $txnlist 0]
- set gid [lindex $txnlist 1]
- error_check_good gidcompare $gid $origgid
- puts "\t\t\tExecuting txn_$op2:$t"
- error_check_good txn_$op2:$t [$t $op2] 0
- #
- # If we are testing discard, we do need to resolve
- # the txn, so get the list again and now abort it.
- #
- if { $op2 == "discard" } {
- set txns [$env txn_recover]
- error_check_bad txnrecover [llength $txns] 0
- set txnlist [lindex $txns 0]
- set t [lindex $txnlist 0]
- set gid [lindex $txnlist 1]
- error_check_good gidcompare $gid $origgid
- puts "\t\t\tExecuting txn_abort:$t"
- error_check_good disc_txn_abort:$t [$t abort] 0
- }
- }
-
-
- eval set args $args
- eval open_and_dump_file $dir/$dbfile NULL $final_file nop \
- dump_file_direction "-first" "-next" $args
- if { $op == "commit" || $op2 == "commit" } {
- filesort $afterop_file $afterop_file.sort
- filesort $final_file $final_file.sort
- error_check_good \
- diff(post-$op,pre-commit):diff($afterop_file,$final_file) \
- [filecmp $afterop_file.sort $final_file.sort] 0
- } else {
- filesort $init_file $init_file.sort
- filesort $final_file $final_file.sort
- error_check_good \
- diff(initial,post-$op):diff($init_file,$final_file) \
- [filecmp $init_file.sort $final_file.sort] 0
- }
-
- # Now close the environment, substitute a file that will need
- # recovery and try running recovery again.
- reset_env $env
- if { $op == "commit" || $op2 == "commit" } {
- catch { file copy -force $dir/$dbfile.init $dir/$dbfile } res
- move_file_extent $dir $dbfile init copy
- } else {
- catch { file copy -force $dir/$dbfile.afterop $dir/$dbfile } res
- move_file_extent $dir $dbfile afterop copy
- }
-
- berkdb debug_check
- puts -nonewline "\t\tRunning recovery on pre-op database ... "
- flush stdout
-
- set stat [catch {eval exec $util_path/db_recover $recargs} result]
- if { $stat == 1 } {
- error "FAIL: Recovery error: $result."
- }
- puts -nonewline "complete ... "
-
- error_check_good db_verify_preop \
- [verify_dir $testdir "\t\t" 0 1 $nodump] 0
-
- puts "verified"
-
- set env [eval $env_cmd]
-
- eval open_and_dump_file $dir/$dbfile NULL $final_file nop \
- dump_file_direction "-first" "-next" $args
- if { $op == "commit" || $op2 == "commit" } {
- filesort $final_file $final_file.sort
- filesort $afterop_file $afterop_file.sort
- error_check_good \
- diff(post-$op,recovered):diff($afterop_file,$final_file) \
- [filecmp $afterop_file.sort $final_file.sort] 0
- } else {
- filesort $init_file $init_file.sort
- filesort $final_file $final_file.sort
- error_check_good \
- diff(initial,post-$op):diff($init_file,$final_file) \
- [filecmp $init_file.sort $final_file.sort] 0
- }
-
- # This should just close the environment, not blow it away.
- reset_env $env
-}
-
-proc populate { db method txn n dups bigdata } {
- source ./include.tcl
-
- # Handle non-transactional cases, too.
- set t ""
- if { [llength $txn] > 0 } {
- set t " -txn $txn "
- }
-
- set did [open $dict]
- set count 0
- while { [gets $did str] != -1 && $count < $n } {
- if { [is_record_based $method] == 1 } {
- set key [expr $count + 1]
- } elseif { $dups == 1 } {
- set key duplicate_key
- } else {
- set key $str
- }
- if { $bigdata == 1 && [berkdb random_int 1 3] == 1} {
- set str [replicate $str 1000]
- }
-
- set ret [eval {$db put} $t {$key [chop_data $method $str]}]
- error_check_good db_put:$key $ret 0
- incr count
- }
- close $did
- return 0
-}
-
-proc big_populate { db txn n } {
- source ./include.tcl
-
- set did [open $dict]
- set count 0
- while { [gets $did str] != -1 && $count < $n } {
- set key [replicate $str 50]
- set ret [$db put -txn $txn $key $str]
- error_check_good db_put:$key $ret 0
- incr count
- }
- close $did
- return 0
-}
-
-proc unpopulate { db txn num } {
- source ./include.tcl
-
- set c [eval {$db cursor} "-txn $txn"]
- error_check_bad $db:cursor $c NULL
- error_check_good $db:cursor [is_substr $c $db] 1
-
- set i 0
- for {set d [$c get -first] } { [llength $d] != 0 } {
- set d [$c get -next] } {
- $c del
- incr i
- if { $num != 0 && $i >= $num } {
- break
- }
- }
- error_check_good cursor_close [$c close] 0
- return 0
-}
-
-# Flush logs for txn envs only.
-proc reset_env { env } {
- if { [is_txnenv $env] } {
- error_check_good log_flush [$env log_flush] 0
- }
- error_check_good env_close [$env close] 0
-}
-
-proc maxlocks { myenv locker_id obj_id num } {
- return [countlocks $myenv $locker_id $obj_id $num ]
-}
-
-proc maxwrites { myenv locker_id obj_id num } {
- return [countlocks $myenv $locker_id $obj_id $num ]
-}
-
-proc minlocks { myenv locker_id obj_id num } {
- return [countlocks $myenv $locker_id $obj_id $num ]
-}
-
-proc minwrites { myenv locker_id obj_id num } {
- return [countlocks $myenv $locker_id $obj_id $num ]
-}
-
-proc countlocks { myenv locker_id obj_id num } {
- set locklist ""
- for { set i 0} {$i < [expr $obj_id * 4]} { incr i } {
- set r [catch {$myenv lock_get read $locker_id \
- [expr $obj_id * 1000 + $i]} l ]
- if { $r != 0 } {
- puts $l
- return ERROR
- } else {
- error_check_good lockget:$obj_id [is_substr $l $myenv] 1
- lappend locklist $l
- }
- }
-
- # Now acquire one write lock, except for obj_id 1, which doesn't
- # acquire any. We'll use obj_id 1 to test minwrites.
- if { $obj_id != 1 } {
- set r [catch {$myenv lock_get write $locker_id \
- [expr $obj_id * 1000 + 10]} l ]
- if { $r != 0 } {
- puts $l
- return ERROR
- } else {
- error_check_good lockget:$obj_id [is_substr $l $myenv] 1
- lappend locklist $l
- }
- }
-
- # Get one extra write lock for obj_id 2. We'll use
- # obj_id 2 to test maxwrites.
- #
- if { $obj_id == 2 } {
- set extra [catch {$myenv lock_get write \
- $locker_id [expr $obj_id * 1000 + 11]} l ]
- if { $extra != 0 } {
- puts $l
- return ERROR
- } else {
- error_check_good lockget:$obj_id [is_substr $l $myenv] 1
- lappend locklist $l
- }
- }
-
- set ret [ring $myenv $locker_id $obj_id $num]
-
- foreach l $locklist {
- error_check_good lockput:$l [$l put] 0
- }
-
- return $ret
-}
-
-# This routine will let us obtain a ring of deadlocks.
-# Each locker will get a lock on obj_id, then sleep, and
-# then try to lock (obj_id + 1) % num.
-# When the lock is finally granted, we release our locks and
-# return 1 if we got both locks and DEADLOCK if we deadlocked.
-# The results here should be that 1 locker deadlocks and the
-# rest all finish successfully.
-proc ring { myenv locker_id obj_id num } {
- source ./include.tcl
-
- if {[catch {$myenv lock_get write $locker_id $obj_id} lock1] != 0} {
- puts $lock1
- return ERROR
- } else {
- error_check_good lockget:$obj_id [is_substr $lock1 $myenv] 1
- }
-
- tclsleep 30
- set nextobj [expr ($obj_id + 1) % $num]
- set ret 1
- if {[catch {$myenv lock_get write $locker_id $nextobj} lock2] != 0} {
- if {[string match "*DEADLOCK*" $lock2] == 1} {
- set ret DEADLOCK
- } else {
- if {[string match "*NOTGRANTED*" $lock2] == 1} {
- set ret DEADLOCK
- } else {
- puts $lock2
- set ret ERROR
- }
- }
- } else {
- error_check_good lockget:$obj_id [is_substr $lock2 $myenv] 1
- }
-
- # Now release the first lock
- error_check_good lockput:$lock1 [$lock1 put] 0
-
- if {$ret == 1} {
- error_check_bad lockget:$obj_id $lock2 NULL
- error_check_good lockget:$obj_id [is_substr $lock2 $myenv] 1
- error_check_good lockput:$lock2 [$lock2 put] 0
- }
- return $ret
-}
-
-# This routine will create massive deadlocks.
-# Each locker will get a readlock on obj_id, then sleep, and
-# then try to upgrade the readlock to a write lock.
-# When the lock is finally granted, we release our first lock and
-# return 1 if we got both locks and DEADLOCK if we deadlocked.
-# The results here should be that 1 locker succeeds in getting all
-# the locks and everyone else deadlocks.
-proc clump { myenv locker_id obj_id num } {
- source ./include.tcl
-
- set obj_id 10
- if {[catch {$myenv lock_get read $locker_id $obj_id} lock1] != 0} {
- puts $lock1
- return ERROR
- } else {
- error_check_good lockget:$obj_id \
- [is_valid_lock $lock1 $myenv] TRUE
- }
-
- tclsleep 30
- set ret 1
- if {[catch {$myenv lock_get write $locker_id $obj_id} lock2] != 0} {
- if {[string match "*DEADLOCK*" $lock2] == 1} {
- set ret DEADLOCK
- } else {
- if {[string match "*NOTGRANTED*" $lock2] == 1} {
- set ret DEADLOCK
- } else {
- puts $lock2
- set ret ERROR
- }
- }
- } else {
- error_check_good \
- lockget:$obj_id [is_valid_lock $lock2 $myenv] TRUE
- }
-
- # Now release the first lock
- error_check_good lockput:$lock1 [$lock1 put] 0
-
- if {$ret == 1} {
- error_check_good \
- lockget:$obj_id [is_valid_lock $lock2 $myenv] TRUE
- error_check_good lockput:$lock2 [$lock2 put] 0
- }
- return $ret
-}
-
-proc dead_check { t procs timeout dead clean other } {
- error_check_good $t:$procs:other $other 0
- switch $t {
- ring {
- # With timeouts the number of deadlocks is
- # unpredictable: test for at least one deadlock.
- if { $timeout != 0 && $dead > 1 } {
- set clean [ expr $clean + $dead - 1]
- set dead 1
- }
- error_check_good $t:$procs:deadlocks $dead 1
- error_check_good $t:$procs:success $clean \
- [expr $procs - 1]
- }
- clump {
- # With timeouts the number of deadlocks is
- # unpredictable: test for no more than one
- # successful lock.
- if { $timeout != 0 && $dead == $procs } {
- set clean 1
- set dead [expr $procs - 1]
- }
- error_check_good $t:$procs:deadlocks $dead \
- [expr $procs - 1]
- error_check_good $t:$procs:success $clean 1
- }
- oldyoung {
- error_check_good $t:$procs:deadlocks $dead 1
- error_check_good $t:$procs:success $clean \
- [expr $procs - 1]
- }
- maxlocks {
- error_check_good $t:$procs:deadlocks $dead 1
- error_check_good $t:$procs:success $clean \
- [expr $procs - 1]
- }
- maxwrites {
- error_check_good $t:$procs:deadlocks $dead 1
- error_check_good $t:$procs:success $clean \
- [expr $procs - 1]
- }
- minlocks {
- error_check_good $t:$procs:deadlocks $dead 1
- error_check_good $t:$procs:success $clean \
- [expr $procs - 1]
- }
- minwrites {
- error_check_good $t:$procs:deadlocks $dead 1
- error_check_good $t:$procs:success $clean \
- [expr $procs - 1]
- }
- default {
- error "Test $t not implemented"
- }
- }
-}
-
-proc rdebug { id op where } {
- global recd_debug
- global recd_id
- global recd_op
-
- set recd_debug $where
- set recd_id $id
- set recd_op $op
-}
-
-proc rtag { msg id } {
- set tag [lindex $msg 0]
- set tail [expr [string length $tag] - 2]
- set tag [string range $tag $tail $tail]
- if { $id == $tag } {
- return 1
- } else {
- return 0
- }
-}
-
-proc zero_list { n } {
- set ret ""
- while { $n > 0 } {
- lappend ret 0
- incr n -1
- }
- return $ret
-}
-
-proc check_dump { k d } {
- puts "key: $k data: $d"
-}
-
-proc reverse { s } {
- set res ""
- for { set i 0 } { $i < [string length $s] } { incr i } {
- set res "[string index $s $i]$res"
- }
-
- return $res
-}
-
-#
-# This is a internal only proc. All tests should use 'is_valid_db' etc.
-#
-proc is_valid_widget { w expected } {
- # First N characters must match "expected"
- set l [string length $expected]
- incr l -1
- if { [string compare [string range $w 0 $l] $expected] != 0 } {
- return $w
- }
-
- # Remaining characters must be digits
- incr l 1
- for { set i $l } { $i < [string length $w] } { incr i} {
- set c [string index $w $i]
- if { $c < "0" || $c > "9" } {
- return $w
- }
- }
-
- return TRUE
-}
-
-proc is_valid_db { db } {
- return [is_valid_widget $db db]
-}
-
-proc is_valid_env { env } {
- return [is_valid_widget $env env]
-}
-
-proc is_valid_cursor { dbc db } {
- return [is_valid_widget $dbc $db.c]
-}
-
-proc is_valid_lock { lock env } {
- return [is_valid_widget $lock $env.lock]
-}
-
-proc is_valid_logc { logc env } {
- return [is_valid_widget $logc $env.logc]
-}
-
-proc is_valid_mpool { mpool env } {
- return [is_valid_widget $mpool $env.mp]
-}
-
-proc is_valid_page { page mpool } {
- return [is_valid_widget $page $mpool.pg]
-}
-
-proc is_valid_txn { txn env } {
- return [is_valid_widget $txn $env.txn]
-}
-
-proc is_valid_lock {l env} {
- return [is_valid_widget $l $env.lock]
-}
-
-proc is_valid_locker {l } {
- return [is_valid_widget $l ""]
-}
-
-proc is_valid_seq { seq } {
- return [is_valid_widget $seq seq]
-}
-
-proc send_cmd { fd cmd {sleep 2}} {
- source ./include.tcl
-
- puts $fd "if \[catch {set v \[$cmd\] ; puts \$v} ret\] { \
- puts \"FAIL: \$ret\" \
- }"
- puts $fd "flush stdout"
- flush $fd
- berkdb debug_check
- tclsleep $sleep
-
- set r [rcv_result $fd]
- return $r
-}
-
-proc rcv_result { fd } {
- global errorInfo
-
- set r [gets $fd result]
- if { $r == -1 } {
- puts "FAIL: gets returned -1 (EOF)"
- puts "FAIL: errorInfo is $errorInfo"
- }
-
- return $result
-}
-
-proc send_timed_cmd { fd rcv_too cmd } {
- set c1 "set start \[timestamp -r\]; "
- set c2 "puts \[expr \[timestamp -r\] - \$start\]"
- set full_cmd [concat $c1 $cmd ";" $c2]
-
- puts $fd $full_cmd
- puts $fd "flush stdout"
- flush $fd
- return 0
-}
-
-#
-# The rationale behind why we have *two* "data padding" routines is outlined
-# below:
-#
-# Both pad_data and chop_data truncate data that is too long. However,
-# pad_data also adds the pad character to pad data out to the fixed length
-# record length.
-#
-# Which routine you call does not depend on the length of the data you're
-# using, but on whether you're doing a put or a get. When we do a put, we
-# have to make sure the data isn't longer than the size of a record because
-# otherwise we'll get an error (use chop_data). When we do a get, we want to
-# check that db padded everything correctly (use pad_data on the value against
-# which we are comparing).
-#
-# We don't want to just use the pad_data routine for both purposes, because
-# we want to be able to test whether or not db is padding correctly. For
-# example, the queue access method had a bug where when a record was
-# overwritten (*not* a partial put), only the first n bytes of the new entry
-# were written, n being the new entry's (unpadded) length. So, if we did
-# a put with key,value pair (1, "abcdef") and then a put (1, "z"), we'd get
-# back (1,"zbcdef"). If we had used pad_data instead of chop_data, we would
-# have gotten the "correct" result, but we wouldn't have found this bug.
-proc chop_data {method data} {
- global fixed_len
-
- if {[is_fixed_length $method] == 1 && \
- [string length $data] > $fixed_len} {
- return [eval {binary format a$fixed_len $data}]
- } else {
- return $data
- }
-}
-
-proc pad_data {method data} {
- global fixed_len
-
- if {[is_fixed_length $method] == 1} {
- return [eval {binary format a$fixed_len $data}]
- } else {
- return $data
- }
-}
-
-#
-# The make_fixed_length proc is used in special circumstances where we
-# absolutely need to send in data that is already padded out to the fixed
-# length with a known pad character. Most tests should use chop_data and
-# pad_data, not this.
-#
-proc make_fixed_length {method data {pad 0}} {
- global fixed_len
-
- if {[is_fixed_length $method] == 1} {
- set data [chop_data $method $data]
- while { [string length $data] < $fixed_len } {
- set data [format $data%c $pad]
- }
- }
- return $data
-}
-
-proc make_gid {data} {
- while { [string length $data] < 128 } {
- set data [format ${data}0]
- }
- return $data
-}
-
-# shift data for partial
-# pad with fixed pad (which is NULL)
-proc partial_shift { data offset direction} {
- global fixed_len
-
- set len [expr $fixed_len - 1]
-
- if { [string compare $direction "right"] == 0 } {
- for { set i 1} { $i <= $offset } {incr i} {
- set data [binary format x1a$len $data]
- }
- } elseif { [string compare $direction "left"] == 0 } {
- for { set i 1} { $i <= $offset } {incr i} {
- set data [string range $data 1 end]
- set data [binary format a$len $data]
- }
- }
- return $data
-}
-
-# string compare does not always work to compare
-# this data, nor does expr (==)
-# specialized routine for comparison
-# (for use in fixed len recno and q)
-proc binary_compare { data1 data2 } {
- if { [string length $data1] != [string length $data2] || \
- [string compare -length \
- [string length $data1] $data1 $data2] != 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-# This is a comparison function used with the lsort command.
-# It treats its inputs as 32 bit signed integers for comparison,
-# and is coded to work with both 32 bit and 64 bit versions of tclsh.
-proc int32_compare { val1 val2 } {
- # Big is set to 2^32 on a 64 bit machine, or 0 on 32 bit machine.
- set big [expr 0xffffffff + 1]
- if { $val1 >= 0x80000000 } {
- set val1 [expr $val1 - $big]
- }
- if { $val2 >= 0x80000000 } {
- set val2 [expr $val2 - $big]
- }
- return [expr $val1 - $val2]
-}
-
-proc convert_method { method } {
- switch -- $method {
- -btree -
- -dbtree -
- dbtree -
- -ddbtree -
- ddbtree -
- -rbtree -
- BTREE -
- DB_BTREE -
- DB_RBTREE -
- RBTREE -
- bt -
- btree -
- db_btree -
- db_rbtree -
- rbt -
- rbtree { return "-btree" }
-
- -dhash -
- -ddhash -
- -hash -
- DB_HASH -
- HASH -
- dhash -
- ddhash -
- db_hash -
- h -
- hash { return "-hash" }
-
- -queue -
- DB_QUEUE -
- QUEUE -
- db_queue -
- q -
- qam -
- queue -
- -iqueue -
- DB_IQUEUE -
- IQUEUE -
- db_iqueue -
- iq -
- iqam -
- iqueue { return "-queue" }
-
- -queueextent -
- QUEUEEXTENT -
- qe -
- qamext -
- -queueext -
- queueextent -
- queueext -
- -iqueueextent -
- IQUEUEEXTENT -
- iqe -
- iqamext -
- -iqueueext -
- iqueueextent -
- iqueueext { return "-queue" }
-
- -frecno -
- -recno -
- -rrecno -
- DB_FRECNO -
- DB_RECNO -
- DB_RRECNO -
- FRECNO -
- RECNO -
- RRECNO -
- db_frecno -
- db_recno -
- db_rrecno -
- frec -
- frecno -
- rec -
- recno -
- rrec -
- rrecno { return "-recno" }
-
- default { error "FAIL:[timestamp] $method: unknown method" }
- }
-}
-
-proc split_partition_args { largs } {
-
- # First check for -partition_callback, in which case we
- # need to remove three args.
- set index [lsearch $largs "-partition_callback"]
- if { $index == -1 } {
- set newl $largs
- } else {
- set end [expr $index + 2]
- set newl [lreplace $largs $index $end]
- }
-
- # Then check for -partition, and remove two args.
- set index [lsearch $newl "-partition"]
- if { $index > -1 } {
- set end [expr $index + 1]
- set newl [lreplace $largs $index $end]
- }
-
- return $newl
-}
-
-# Strip "-compress" out of a string of args.
-proc strip_compression_args { largs } {
-
- set cindex [lsearch $largs "-compress"]
- if { $cindex == -1 } {
- set newargs $largs
- } else {
- set newargs [lreplace $largs $cindex $cindex]
- }
- return $newargs
-}
-
-proc split_encargs { largs encargsp } {
- global encrypt
- upvar $encargsp e
- set eindex [lsearch $largs "-encrypta*"]
- if { $eindex == -1 } {
- set e ""
- set newl $largs
- } else {
- set eend [expr $eindex + 1]
- set e [lrange $largs $eindex $eend]
- set newl [lreplace $largs $eindex $eend "-encrypt"]
- }
- return $newl
-}
-
-proc split_pageargs { largs pageargsp } {
- upvar $pageargsp e
- set eindex [lsearch $largs "-pagesize"]
- if { $eindex == -1 } {
- set e ""
- set newl $largs
- } else {
- set eend [expr $eindex + 1]
- set e [lrange $largs $eindex $eend]
- set newl [lreplace $largs $eindex $eend ""]
- }
- return $newl
-}
-
-proc convert_encrypt { largs } {
- global encrypt
- global old_encrypt
-
- set old_encrypt $encrypt
- set encrypt 0
- if { [lsearch $largs "-encrypt*"] != -1 } {
- set encrypt 1
- }
-}
-
-# If recno-with-renumbering or btree-with-renumbering is specified, then
-# fix the arguments to specify the DB_RENUMBER/DB_RECNUM option for the
-# -flags argument.
-proc convert_args { method {largs ""} } {
- global fixed_len
- global gen_upgrade
- global upgrade_be
- source ./include.tcl
-
- if { [string first - $largs] == -1 &&\
- [string compare $largs ""] != 0 &&\
- [string compare $largs {{}}] != 0 } {
- set errstring "args must contain a hyphen; does this test\
- have no numeric args?"
- puts "FAIL:[timestamp] $errstring (largs was $largs)"
- return -code return
- }
-
- convert_encrypt $largs
- if { $gen_upgrade == 1 && $upgrade_be == 1 } {
- append largs " -lorder 4321 "
- } elseif { $gen_upgrade == 1 && $upgrade_be != 1 } {
- append largs " -lorder 1234 "
- }
-
- if { [is_rrecno $method] == 1 } {
- append largs " -renumber "
- } elseif { [is_rbtree $method] == 1 } {
- append largs " -recnum "
- } elseif { [is_dbtree $method] == 1 } {
- append largs " -dup "
- } elseif { [is_ddbtree $method] == 1 } {
- append largs " -dup "
- append largs " -dupsort "
- } elseif { [is_dhash $method] == 1 } {
- append largs " -dup "
- } elseif { [is_ddhash $method] == 1 } {
- append largs " -dup "
- append largs " -dupsort "
- } elseif { [is_queueext $method] == 1 } {
- append largs " -extent 4 "
- }
-
- if { [is_iqueue $method] == 1 || [is_iqueueext $method] == 1 } {
- append largs " -inorder "
- }
-
- # Default padding character is ASCII nul.
- set fixed_pad 0
- if {[is_fixed_length $method] == 1} {
- append largs " -len $fixed_len -pad $fixed_pad "
- }
- return $largs
-}
-
-proc is_btree { method } {
- set names { -btree BTREE DB_BTREE bt btree }
- if { [lsearch $names $method] >= 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_dbtree { method } {
- set names { -dbtree dbtree }
- if { [lsearch $names $method] >= 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_ddbtree { method } {
- set names { -ddbtree ddbtree }
- if { [lsearch $names $method] >= 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_rbtree { method } {
- set names { -rbtree rbtree RBTREE db_rbtree DB_RBTREE rbt }
- if { [lsearch $names $method] >= 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_recno { method } {
- set names { -recno DB_RECNO RECNO db_recno rec recno}
- if { [lsearch $names $method] >= 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_rrecno { method } {
- set names { -rrecno rrecno RRECNO db_rrecno DB_RRECNO rrec }
- if { [lsearch $names $method] >= 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_frecno { method } {
- set names { -frecno frecno frec FRECNO db_frecno DB_FRECNO}
- if { [lsearch $names $method] >= 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_hash { method } {
- set names { -hash DB_HASH HASH db_hash h hash }
- if { [lsearch $names $method] >= 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_dhash { method } {
- set names { -dhash dhash }
- if { [lsearch $names $method] >= 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_ddhash { method } {
- set names { -ddhash ddhash }
- if { [lsearch $names $method] >= 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_queue { method } {
- if { [is_queueext $method] == 1 || [is_iqueue $method] == 1 || \
- [is_iqueueext $method] == 1 } {
- return 1
- }
-
- set names { -queue DB_QUEUE QUEUE db_queue q queue qam }
- if { [lsearch $names $method] >= 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_queueext { method } {
- if { [is_iqueueext $method] == 1 } {
- return 1
- }
-
- set names { -queueextent queueextent QUEUEEXTENT qe qamext \
- queueext -queueext }
- if { [lsearch $names $method] >= 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_iqueue { method } {
- if { [is_iqueueext $method] == 1 } {
- return 1
- }
-
- set names { -iqueue DB_IQUEUE IQUEUE db_iqueue iq iqueue iqam }
- if { [lsearch $names $method] >= 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_iqueueext { method } {
- set names { -iqueueextent iqueueextent IQUEUEEXTENT iqe iqamext \
- iqueueext -iqueueext }
- if { [lsearch $names $method] >= 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_record_based { method } {
- if { [is_recno $method] || [is_frecno $method] ||
- [is_rrecno $method] || [is_queue $method] } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_fixed_length { method } {
- if { [is_queue $method] || [is_frecno $method] } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_compressed { args } {
- if { [string first "-compress" $args] >= 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_partitioned { args } {
- if { [string first "-partition" $args] >= 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_partition_callback { args } {
- if { [string first "-partition_callback" $args] >= 0 } {
- return 1
- } else {
- return 0
- }
-}
-
-# Sort lines in file $in and write results to file $out.
-# This is a more portable alternative to execing the sort command,
-# which has assorted issues on NT [#1576].
-# The addition of a "-n" argument will sort numerically.
-proc filesort { in out { arg "" } } {
- set i [open $in r]
-
- set ilines {}
- while { [gets $i line] >= 0 } {
- lappend ilines $line
- }
-
- if { [string compare $arg "-n"] == 0 } {
- set olines [lsort -integer $ilines]
- } else {
- set olines [lsort $ilines]
- }
-
- close $i
-
- set o [open $out w]
- foreach line $olines {
- puts $o $line
- }
-
- close $o
-}
-
-# Print lines up to the nth line of infile out to outfile, inclusive.
-# The optional beg argument tells us where to start.
-proc filehead { n infile outfile { beg 0 } } {
- set in [open $infile r]
- set out [open $outfile w]
-
- # Sed uses 1-based line numbers, and so we do too.
- for { set i 1 } { $i < $beg } { incr i } {
- if { [gets $in junk] < 0 } {
- break
- }
- }
-
- for { } { $i <= $n } { incr i } {
- if { [gets $in line] < 0 } {
- break
- }
- puts $out $line
- }
-
- close $in
- close $out
-}
-
-# Remove file (this replaces $RM).
-# Usage: fileremove filenames =~ rm; fileremove -f filenames =~ rm -rf.
-proc fileremove { args } {
- set forceflag ""
- foreach a $args {
- if { [string first - $a] == 0 } {
- # It's a flag. Better be f.
- if { [string first f $a] != 1 } {
- return -code error "bad flag to fileremove"
- } else {
- set forceflag "-force"
- }
- } else {
- eval {file delete $forceflag $a}
- }
- }
-}
-
-proc findfail { args } {
- set errstring {}
- foreach a $args {
- if { [file exists $a] == 0 } {
- continue
- }
- set f [open $a r]
- while { [gets $f line] >= 0 } {
- if { [string first FAIL $line] == 0 } {
- lappend errstring $a:$line
- }
- }
- close $f
- }
- return $errstring
-}
-
-# Sleep for s seconds.
-proc tclsleep { s } {
- # On Windows, the system time-of-day clock may update as much
- # as 55 ms late due to interrupt timing. Don't take any
- # chances; sleep extra-long so that when tclsleep 1 returns,
- # it's guaranteed to be a new second.
- after [expr $s * 1000 + 56]
-}
-
-# Kill a process.
-proc tclkill { id } {
- source ./include.tcl
-
- while { [ catch {exec $KILL -0 $id} ] == 0 } {
- catch {exec $KILL -9 $id}
- tclsleep 5
- }
-}
-
-# Compare two files, a la diff. Returns 1 if non-identical, 0 if identical.
-proc filecmp { file_a file_b } {
- set fda [open $file_a r]
- set fdb [open $file_b r]
-
- fconfigure $fda -translation binary
- fconfigure $fdb -translation binary
-
- set nra 0
- set nrb 0
-
- # The gets can't be in the while condition because we'll
- # get short-circuit evaluated.
- while { $nra >= 0 && $nrb >= 0 } {
- set nra [gets $fda aline]
- set nrb [gets $fdb bline]
-
- if { $nra != $nrb || [string compare $aline $bline] != 0} {
- close $fda
- close $fdb
- return 1
- }
- }
-
- close $fda
- close $fdb
- return 0
-}
-
-# Compare the log files from 2 envs. Returns 1 if non-identical,
-# 0 if identical.
-proc logcmp { env1 env2 { compare_shared_portion 0 } } {
- set lc1 [$env1 log_cursor]
- set lc2 [$env2 log_cursor]
-
- # If we're comparing the full set of logs in both envs,
- # set the starting point by looking at the first LSN in the
- # first env's logs.
- #
- # If we are comparing only the shared portion, look at the
- # starting LSN of the second env as well, and select the
- # LSN that is larger.
-
- set start [lindex [$lc1 get -first] 0]
-
- if { $compare_shared_portion } {
- set e2_lsn [lindex [$lc2 get -first] 0]
- if { [$env1 log_compare $start $e2_lsn] < 0 } {
- set start $e2_lsn
- }
- }
-
- # Read through and compare the logs record by record.
- for { set l1 [$lc1 get -set $start] ; set l2 [$lc2 get -set $start] }\
- { [llength $l1] > 0 && [llength $l2] > 0 }\
- { set l1 [$lc1 get -next] ; set l2 [$lc2 get -next] } {
- if { [string equal $l1 $l2] != 1 } {
- $lc1 close
- $lc2 close
-#puts "l1 is $l1"
-#puts "l2 is $l2"
- return 1
- }
- }
- $lc1 close
- $lc2 close
- return 0
-}
-
-# Give two SORTED files, one of which is a complete superset of the other,
-# extract out the unique portions of the superset and put them in
-# the given outfile.
-proc fileextract { superset subset outfile } {
- set sup [open $superset r]
- set sub [open $subset r]
- set outf [open $outfile w]
-
- # The gets can't be in the while condition because we'll
- # get short-circuit evaluated.
- set nrp [gets $sup pline]
- set nrb [gets $sub bline]
- while { $nrp >= 0 } {
- if { $nrp != $nrb || [string compare $pline $bline] != 0} {
- puts $outf $pline
- } else {
- set nrb [gets $sub bline]
- }
- set nrp [gets $sup pline]
- }
-
- close $sup
- close $sub
- close $outf
- return 0
-}
-
-# Verify all .db files in the specified directory.
-proc verify_dir { {directory $testdir} { pref "" } \
- { noredo 0 } { quiet 0 } { nodump 0 } { cachesize 0 } { unref 1 } } {
- global encrypt
- global passwd
-
- # If we're doing database verification between tests, we don't
- # want to do verification twice without an intervening cleanup--some
- # test was skipped. Always verify by default (noredo == 0) so
- # that explicit calls to verify_dir during tests don't require
- # cleanup commands.
- if { $noredo == 1 } {
- if { [file exists $directory/NOREVERIFY] == 1 } {
- if { $quiet == 0 } {
- puts "Skipping verification."
- }
- return 0
- }
- set f [open $directory/NOREVERIFY w]
- close $f
- }
-
- if { [catch {glob $directory/*.db} dbs] != 0 } {
- # No files matched
- return 0
- }
- set ret 0
-
- # Open an env, so that we have a large enough cache. Pick
- # a fairly generous default if we haven't specified something else.
-
- if { $cachesize == 0 } {
- set cachesize [expr 1024 * 1024]
- }
- set encarg ""
- if { $encrypt != 0 } {
- set encarg "-encryptaes $passwd"
- }
-
- set env [eval {berkdb_env -create -private} $encarg \
- {-cachesize [list 0 $cachesize 0]}]
- set earg " -env $env "
-
- # The 'unref' flag means that we report unreferenced pages
- # at all times. This is the default behavior.
- # If we have a test which leaves unreferenced pages on systems
- # where HAVE_FTRUNCATE is not on, then we call verify_dir with
- # unref == 0.
- set uflag "-unref"
- if { $unref == 0 } {
- set uflag ""
- }
-
- foreach db $dbs {
- # Replication's temp db uses a custom comparison function,
- # so we can't verify it.
- #
- if { [file tail $db] == "__db.rep.db" } {
- continue
- }
- if { [catch \
- {eval {berkdb dbverify} $uflag $earg $db} res] != 0 } {
- puts $res
- puts "FAIL:[timestamp] Verification of $db failed."
- set ret 1
- continue
- } else {
- error_check_good verify:$db $res 0
- if { $quiet == 0 } {
- puts "${pref}Verification of $db succeeded."
- }
- }
-
- # Skip the dump if it's dangerous to do it.
- if { $nodump == 0 } {
- if { [catch {eval dumploadtest $db} res] != 0 } {
- puts $res
- puts "FAIL:[timestamp] Dump/load of $db failed."
- set ret 1
- continue
- } else {
- error_check_good dumpload:$db $res 0
- if { $quiet == 0 } {
- puts \
- "${pref}Dump/load of $db succeeded."
- }
- }
- }
- }
-
- error_check_good vrfyenv_close [$env close] 0
-
- return $ret
-}
-
-# Is the database handle in $db a master database containing subdbs?
-proc check_for_subdbs { db } {
- set stat [$db stat]
- for { set i 0 } { [string length [lindex $stat $i]] > 0 } { incr i } {
- set elem [lindex $stat $i]
- if { [string compare [lindex $elem 0] Flags] == 0 } {
- # This is the list of flags; look for
- # "subdatabases".
- if { [is_substr [lindex $elem 1] subdatabases] } {
- return 1
- }
- }
- }
- return 0
-}
-
-proc db_compare { olddb newdb olddbname newdbname } {
- # Walk through olddb and newdb and make sure their contents
- # are identical.
- set oc [$olddb cursor]
- set nc [$newdb cursor]
- error_check_good orig_cursor($olddbname) \
- [is_valid_cursor $oc $olddb] TRUE
- error_check_good new_cursor($olddbname) \
- [is_valid_cursor $nc $newdb] TRUE
-
- for { set odbt [$oc get -first -nolease] } { [llength $odbt] > 0 } \
- { set odbt [$oc get -next -nolease] } {
- set ndbt [$nc get -get_both -nolease \
- [lindex [lindex $odbt 0] 0] [lindex [lindex $odbt 0] 1]]
- if { [binary_compare $ndbt $odbt] == 1 } {
- error_check_good oc_close [$oc close] 0
- error_check_good nc_close [$nc close] 0
-# puts "FAIL: $odbt does not match $ndbt"
- return 1
- }
- }
-
- for { set ndbt [$nc get -first -nolease] } { [llength $ndbt] > 0 } \
- { set ndbt [$nc get -next -nolease] } {
- set odbt [$oc get -get_both -nolease \
- [lindex [lindex $ndbt 0] 0] [lindex [lindex $ndbt 0] 1]]
- if { [binary_compare $ndbt $odbt] == 1 } {
- error_check_good oc_close [$oc close] 0
- error_check_good nc_close [$nc close] 0
-# puts "FAIL: $odbt does not match $ndbt"
- return 1
- }
- }
-
- error_check_good orig_cursor_close($olddbname) [$oc close] 0
- error_check_good new_cursor_close($newdbname) [$nc close] 0
-
- return 0
-}
-
-proc dumploadtest { db } {
- global util_path
- global encrypt
- global passwd
-
- set newdbname $db-dumpload.db
-
- set dbarg ""
- set utilflag ""
- if { $encrypt != 0 } {
- set dbarg "-encryptany $passwd"
- set utilflag "-P $passwd"
- }
-
- # Dump/load the whole file, including all subdbs.
-
- set rval [catch {eval {exec $util_path/db_dump} $utilflag -k \
- $db | $util_path/db_load $utilflag $newdbname} res]
- error_check_good db_dump/db_load($db:$res) $rval 0
-
- # If the old file was empty, there's no new file and we're done.
- if { [file exists $newdbname] == 0 } {
- return 0
- }
-
- # Open original database.
- set olddb [eval {berkdb_open -rdonly} $dbarg $db]
- error_check_good olddb($db) [is_valid_db $olddb] TRUE
-
- if { [check_for_subdbs $olddb] } {
- # If $db has subdatabases, compare each one separately.
- set oc [$olddb cursor]
- error_check_good orig_cursor($db) \
- [is_valid_cursor $oc $olddb] TRUE
-
- for { set dbt [$oc get -first] } \
- { [llength $dbt] > 0 } \
- { set dbt [$oc get -next] } {
- set subdb [lindex [lindex $dbt 0] 0]
-
- set oldsubdb \
- [eval {berkdb_open -rdonly} $dbarg {$db $subdb}]
- error_check_good olddb($db) [is_valid_db $oldsubdb] TRUE
-
- # Open the new database.
- set newdb \
- [eval {berkdb_open -rdonly} $dbarg {$newdbname $subdb}]
- error_check_good newdb($db) [is_valid_db $newdb] TRUE
-
- db_compare $oldsubdb $newdb $db $newdbname
- error_check_good new_db_close($db) [$newdb close] 0
- error_check_good old_subdb_close($oldsubdb) [$oldsubdb close] 0
- }
-
- error_check_good oldcclose [$oc close] 0
- } else {
- # Open the new database.
- set newdb [eval {berkdb_open -rdonly} $dbarg $newdbname]
- error_check_good newdb($db) [is_valid_db $newdb] TRUE
-
- db_compare $olddb $newdb $db $newdbname
- error_check_good new_db_close($db) [$newdb close] 0
- }
-
- error_check_good orig_db_close($db) [$olddb close] 0
- eval berkdb dbremove $dbarg $newdbname
-}
-
-# Test regular and aggressive salvage procedures for all databases
-# in a directory.
-proc salvage_dir { dir { noredo 0 } { quiet 0 } } {
- global util_path
- global encrypt
- global passwd
-
- # If we're doing salvage testing between tests, don't do it
- # twice without an intervening cleanup.
- if { $noredo == 1 } {
- if { [file exists $dir/NOREDO] == 1 } {
- if { $quiet == 0 } {
- puts "Skipping salvage testing."
- }
- return 0
- }
- set f [open $dir/NOREDO w]
- close $f
- }
-
- if { [catch {glob $dir/*.db} dbs] != 0 } {
- # No files matched
- return 0
- }
-
- foreach db $dbs {
- set dumpfile $db-dump
- set sorteddump $db-dump-sorted
- set salvagefile $db-salvage
- set sortedsalvage $db-salvage-sorted
- set aggsalvagefile $db-aggsalvage
-
- set dbarg ""
- set utilflag ""
- if { $encrypt != 0 } {
- set dbarg "-encryptany $passwd"
- set utilflag "-P $passwd"
- }
-
- # Dump the database with salvage, with aggressive salvage,
- # and without salvage.
- #
- set rval [catch {eval {exec $util_path/db_dump} $utilflag -r \
- -f $salvagefile $db} res]
- error_check_good salvage($db:$res) $rval 0
- filesort $salvagefile $sortedsalvage
-
- # We can't avoid occasional verify failures in aggressive
- # salvage. Make sure it's the expected failure.
- set rval [catch {eval {exec $util_path/db_dump} $utilflag -R \
- -f $aggsalvagefile $db} res]
- if { $rval == 1 } {
-#puts "res is $res"
- error_check_good agg_failure \
- [is_substr $res "DB_VERIFY_BAD"] 1
- } else {
- error_check_good aggressive_salvage($db:$res) $rval 0
- }
-
- # Queue databases must be dumped with -k to display record
- # numbers if we're not in salvage mode.
- if { [isqueuedump $salvagefile] == 1 } {
- append utilflag " -k "
- }
-
- # Discard db_pagesize lines from file dumped with ordinary
- # db_dump -- they are omitted from a salvage dump.
- set rval [catch {eval {exec $util_path/db_dump} $utilflag \
- -f $dumpfile $db} res]
- error_check_good dump($db:$res) $rval 0
- filesort $dumpfile $sorteddump
- discardline $sorteddump TEMPFILE "db_pagesize="
- file copy -force TEMPFILE $sorteddump
-
- # A non-aggressively salvaged file should match db_dump.
- error_check_good compare_dump_and_salvage \
- [filecmp $sorteddump $sortedsalvage] 0
-
- puts "Salvage tests of $db succeeded."
- }
-}
-
-# Reads infile, writes to outfile, discarding any line whose
-# beginning matches the given string.
-proc discardline { infile outfile discard } {
- set fdin [open $infile r]
- set fdout [open $outfile w]
-
- while { [gets $fdin str] >= 0 } {
- if { [string match $discard* $str] != 1 } {
- puts $fdout $str
- }
- }
- close $fdin
- close $fdout
-}
-
-# Inspects dumped file for "type=" line. Returns 1 if type=queue.
-proc isqueuedump { file } {
- set fd [open $file r]
-
- while { [gets $fd str] >= 0 } {
- if { [string match type=* $str] == 1 } {
- if { [string match "type=queue" $str] == 1 } {
- close $fd
- return 1
- } else {
- close $fd
- return 0
- }
- }
- }
- close $fd
-}
-
-# Generate randomly ordered, guaranteed-unique four-character strings that can
-# be used to differentiate duplicates without creating duplicate duplicates.
-# (test031 & test032) randstring_init is required before the first call to
-# randstring and initializes things for up to $i distinct strings; randstring
-# gets the next string.
-proc randstring_init { i } {
- global rs_int_list alphabet
-
- # Fail if we can't generate sufficient unique strings.
- if { $i > [expr 26 * 26 * 26 * 26] } {
- set errstring\
- "Duplicate set too large for random string generator"
- puts "FAIL:[timestamp] $errstring"
- return -code return $errstring
- }
-
- set rs_int_list {}
-
- # generate alphabet array
- for { set j 0 } { $j < 26 } { incr j } {
- set a($j) [string index $alphabet $j]
- }
-
- # Generate a list with $i elements, { aaaa, aaab, ... aaaz, aaba ...}
- for { set d1 0 ; set j 0 } { $d1 < 26 && $j < $i } { incr d1 } {
- for { set d2 0 } { $d2 < 26 && $j < $i } { incr d2 } {
- for { set d3 0 } { $d3 < 26 && $j < $i } { incr d3 } {
- for { set d4 0 } { $d4 < 26 && $j < $i } \
- { incr d4 } {
- lappend rs_int_list \
- $a($d1)$a($d2)$a($d3)$a($d4)
- incr j
- }
- }
- }
- }
-
- # Randomize the list.
- set rs_int_list [randomize_list $rs_int_list]
-}
-
-# Randomize a list. Returns a randomly-reordered copy of l.
-proc randomize_list { l } {
- set i [llength $l]
-
- for { set j 0 } { $j < $i } { incr j } {
- # Pick a random element from $j to the end
- set k [berkdb random_int $j [expr $i - 1]]
-
- # Swap it with element $j
- set t1 [lindex $l $j]
- set t2 [lindex $l $k]
-
- set l [lreplace $l $j $j $t2]
- set l [lreplace $l $k $k $t1]
- }
-
- return $l
-}
-
-proc randstring {} {
- global rs_int_list
-
- if { [info exists rs_int_list] == 0 || [llength $rs_int_list] == 0 } {
- set errstring "randstring uninitialized or used too often"
- puts "FAIL:[timestamp] $errstring"
- return -code return $errstring
- }
-
- set item [lindex $rs_int_list 0]
- set rs_int_list [lreplace $rs_int_list 0 0]
-
- return $item
-}
-
-# Takes a variable-length arg list, and returns a list containing the list of
-# the non-hyphenated-flag arguments, followed by a list of each alphanumeric
-# flag it finds.
-proc extractflags { args } {
- set inflags 1
- set flags {}
- while { $inflags == 1 } {
- set curarg [lindex $args 0]
- if { [string first "-" $curarg] == 0 } {
- set i 1
- while {[string length [set f \
- [string index $curarg $i]]] > 0 } {
- incr i
- if { [string compare $f "-"] == 0 } {
- set inflags 0
- break
- } else {
- lappend flags $f
- }
- }
- set args [lrange $args 1 end]
- } else {
- set inflags 0
- }
- }
- return [list $args $flags]
-}
-
-# Wrapper for berkdb open, used throughout the test suite so that we can
-# set an errfile/errpfx as appropriate.
-proc berkdb_open { args } {
- global is_envmethod
-
- if { [info exists is_envmethod] == 0 } {
- set is_envmethod 0
- }
-
- set errargs {}
- if { $is_envmethod == 0 } {
- append errargs " -errfile /dev/stderr "
- append errargs " -errpfx \\F\\A\\I\\L"
- }
-
- eval {berkdb open} $errargs $args
-}
-
-# Version without errpfx/errfile, used when we're expecting a failure.
-proc berkdb_open_noerr { args } {
- eval {berkdb open} $args
-}
-
-# Wrapper for berkdb env, used throughout the test suite so that we can
-# set an errfile/errpfx as appropriate.
-proc berkdb_env { args } {
- global is_envmethod
-
- if { [info exists is_envmethod] == 0 } {
- set is_envmethod 0
- }
-
- set errargs {}
- if { $is_envmethod == 0 } {
- append errargs " -errfile /dev/stderr "
- append errargs " -errpfx \\F\\A\\I\\L"
- }
-
- eval {berkdb env} $errargs $args
-}
-
-# Version without errpfx/errfile, used when we're expecting a failure.
-proc berkdb_env_noerr { args } {
- eval {berkdb env} $args
-}
-
-proc check_handles { {outf stdout} } {
- global ohandles
-
- set handles [berkdb handles]
- if {[llength $handles] != [llength $ohandles]} {
- puts $outf "WARNING: Open handles during cleanup: $handles"
- }
- set ohandles $handles
-}
-
-proc open_handles { } {
- return [llength [berkdb handles]]
-}
-
-# Will close any database and cursor handles, cursors first.
-# Ignores other handles, like env handles.
-proc close_db_handles { } {
- set handles [berkdb handles]
- set db_handles {}
- set cursor_handles {}
-
- # Find the handles we want to process. We can't use
- # is_valid_cursor to find cursors because we don't know
- # the cursor's parent database handle.
- foreach handle $handles {
- if {[string range $handle 0 1] == "db"} {
- if { [string first "c" $handle] != -1} {
- lappend cursor_handles $handle
- } else {
- lappend db_handles $handle
- }
- }
- }
-
- foreach handle $cursor_handles {
- error_check_good cursor_close [$handle close] 0
- }
- foreach handle $db_handles {
- error_check_good db_close [$handle close] 0
- }
-}
-
-proc move_file_extent { dir dbfile tag op } {
- set curfiles [get_extfiles $dir $dbfile ""]
- set tagfiles [get_extfiles $dir $dbfile $tag]
- #
- # We want to copy or rename only those that have been saved,
- # so delete all the current extent files so that we don't
- # end up with extra ones we didn't restore from our saved ones.
- foreach extfile $curfiles {
- file delete -force $extfile
- }
- foreach extfile $tagfiles {
- set dbq [make_ext_filename $dir $dbfile $extfile]
- #
- # We can either copy or rename
- #
- file $op -force $extfile $dbq
- }
-}
-
-proc copy_extent_file { dir dbfile tag { op copy } } {
- set files [get_extfiles $dir $dbfile ""]
- foreach extfile $files {
- set dbq [make_ext_filename $dir $dbfile $extfile $tag]
- file $op -force $extfile $dbq
- }
-}
-
-proc get_extfiles { dir dbfile tag } {
- if { $tag == "" } {
- set filepat $dir/__db?.$dbfile.\[0-9\]*
- } else {
- set filepat $dir/__db?.$dbfile.$tag.\[0-9\]*
- }
- return [glob -nocomplain -- $filepat]
-}
-
-proc make_ext_filename { dir dbfile extfile {tag ""}} {
- set i [string last "." $extfile]
- incr i
- set extnum [string range $extfile $i end]
- set j [string last "/" $extfile]
- incr j
- set i [string first "." [string range $extfile $j end]]
- incr i $j
- incr i -1
- set prefix [string range $extfile $j $i]
- if {$tag == "" } {
- return $dir/$prefix.$dbfile.$extnum
- } else {
- return $dir/$prefix.$dbfile.$tag.$extnum
- }
-}
-
-# All pids for Windows 9X are negative values. When we want to have
-# unsigned int values, unique to the process, we'll take the absolute
-# value of the pid. This avoids unsigned/signed mistakes, yet
-# guarantees uniqueness, since each system has pids that are all
-# either positive or negative.
-#
-proc sanitized_pid { } {
- set mypid [pid]
- if { $mypid < 0 } {
- set mypid [expr - $mypid]
- }
- puts "PID: [pid] $mypid\n"
- return $mypid
-}
-
-#
-# Extract the page size field from a stat record. Return -1 if
-# none is found.
-#
-proc get_pagesize { stat } {
- foreach field $stat {
- set title [lindex $field 0]
- if {[string compare $title "Page size"] == 0} {
- return [lindex $field 1]
- }
- }
- return -1
-}
-
-# Get a globbed list of source files and executables to use as large
-# data items in overflow page tests.
-proc get_file_list { {small 0} } {
- global is_windows_test
- global is_qnx_test
- global is_je_test
- global src_root
-
- # Skip libraries if we have a debug build.
- if { $is_qnx_test || $is_je_test || [is_debug] == 1 } {
- set small 1
- }
-
- if { $small && $is_windows_test } {
- set templist [glob $src_root/*/*.c */env*.obj]
- } elseif { $small } {
- set templist [glob $src_root/*/*.c ./env*.o]
- } elseif { $is_windows_test } {
- set templist \
- [glob $src_root/*/*.c */*.obj */libdb??.dll */libdb??d.dll]
- } else {
- set templist [glob $src_root/*/*.c ./*.o ./.libs/libdb-?.?.s?]
- }
-
- # We don't want a huge number of files, but we do want a nice
- # variety. If there are more than nfiles files, pick out a list
- # by taking every other, or every third, or every nth file.
- set filelist {}
- set nfiles 500
- if { [llength $templist] > $nfiles } {
- set skip \
- [expr [llength $templist] / [expr [expr $nfiles / 3] * 2]]
- set i $skip
- while { $i < [llength $templist] } {
- lappend filelist [lindex $templist $i]
- incr i $skip
- }
- } else {
- set filelist $templist
- }
- return $filelist
-}
-
-proc is_cdbenv { env } {
- set sys [$env attributes]
- if { [lsearch $sys -cdb] != -1 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_lockenv { env } {
- set sys [$env attributes]
- if { [lsearch $sys -lock] != -1 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_logenv { env } {
- set sys [$env attributes]
- if { [lsearch $sys -log] != -1 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_mpoolenv { env } {
- set sys [$env attributes]
- if { [lsearch $sys -mpool] != -1 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_repenv { env } {
- set sys [$env attributes]
- if { [lsearch $sys -rep] != -1 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_rpcenv { env } {
- set sys [$env attributes]
- if { [lsearch $sys -rpc] != -1 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_secenv { env } {
- set sys [$env attributes]
- if { [lsearch $sys -crypto] != -1 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc is_txnenv { env } {
- set sys [$env attributes]
- if { [lsearch $sys -txn] != -1 } {
- return 1
- } else {
- return 0
- }
-}
-
-proc get_home { env } {
- set sys [$env attributes]
- set h [lsearch $sys -home]
- if { $h == -1 } {
- return NULL
- }
- incr h
- return [lindex $sys $h]
-}
-
-proc reduce_dups { nent ndp } {
- upvar $nent nentries
- upvar $ndp ndups
-
- # If we are using a txnenv, assume it is using
- # the default maximum number of locks, cut back
- # so that we don't run out of locks. Reduce
- # by 25% until we fit.
- #
- while { [expr $nentries * $ndups] > 5000 } {
- set nentries [expr ($nentries / 4) * 3]
- set ndups [expr ($ndups / 4) * 3]
- }
-}
-
-proc getstats { statlist field } {
- foreach pair $statlist {
- set txt [lindex $pair 0]
- if { [string equal $txt $field] == 1 } {
- return [lindex $pair 1]
- }
- }
- return -1
-}
-
-# Return the value for a particular field in a set of statistics.
-# Works for regular db stat as well as env stats (log_stat,
-# lock_stat, txn_stat, rep_stat, etc.).
-proc stat_field { handle which_stat field } {
- set stat [$handle $which_stat]
- return [getstats $stat $field ]
-}
-
-proc big_endian { } {
- global tcl_platform
- set e $tcl_platform(byteOrder)
- if { [string compare $e littleEndian] == 0 } {
- return 0
- } elseif { [string compare $e bigEndian] == 0 } {
- return 1
- } else {
- error "FAIL: Unknown endianness $e"
- }
-}
-
-# Check if this is a debug build. Use 'string equal' so we
-# don't get fooled by debug_rop and debug_wop.
-proc is_debug { } {
-
- set conf [berkdb getconfig]
- foreach item $conf {
- if { [string equal $item "debug"] } {
- return 1
- }
- }
- return 0
-}
-
-proc adjust_logargs { logtype {lbufsize 0} } {
- if { $logtype == "in-memory" } {
- if { $lbufsize == 0 } {
- set lbuf [expr 1 * [expr 1024 * 1024]]
- set logargs " -log_inmemory -log_buffer $lbuf "
- } else {
- set logargs " -log_inmemory -log_buffer $lbufsize "
- }
- } elseif { $logtype == "on-disk" } {
- set logargs ""
- } else {
- error "FAIL: unrecognized log type $logtype"
- }
- return $logargs
-}
-
-proc adjust_txnargs { logtype } {
- if { $logtype == "in-memory" } {
- set txnargs " -txn "
- } elseif { $logtype == "on-disk" } {
- set txnargs " -txn nosync "
- } else {
- error "FAIL: unrecognized log type $logtype"
- }
- return $txnargs
-}
-
-proc get_logfile { env where } {
- # Open a log cursor.
- set m_logc [$env log_cursor]
- error_check_good m_logc [is_valid_logc $m_logc $env] TRUE
-
- # Check that we're in the expected virtual log file.
- if { $where == "first" } {
- set rec [$m_logc get -first]
- } else {
- set rec [$m_logc get -last]
- }
- error_check_good cursor_close [$m_logc close] 0
- set lsn [lindex $rec 0]
- set log [lindex $lsn 0]
- return $log
-}
-
-# Determine whether logs are in-mem or on-disk.
-# This requires the existence of logs to work correctly.
-proc check_log_location { env } {
- if { [catch {get_logfile $env first} res] } {
- puts "FAIL: env $env not configured for logging"
- }
- set inmemory [$env log_get_config inmemory]
-
- set env_home [get_home $env]
- set logfiles [glob -nocomplain $env_home/log.*]
- if { $inmemory == 1 } {
- error_check_good no_logs_on_disk [llength $logfiles] 0
- } else {
- error_check_bad logs_on_disk [llength $logfiles] 0
- }
-}
-
-# Given the env and file name, verify that a given database is on-disk
-# or in-memory as expected. If "db_on_disk" is 1, "databases_in_memory"
-# is 0 and vice versa, so we use error_check_bad.
-proc check_db_location { env { dbname "test.db" } { datadir "" } } {
- global databases_in_memory
-
- if { $datadir != "" } {
- set env_home $datadir
- } else {
- set env_home [get_home $env]
- }
- set db_on_disk [file exists $env_home/$dbname]
-
- error_check_bad db_location $db_on_disk $databases_in_memory
-}
-
-# If we have a private env, check that no region files are found on-disk.
-proc no_region_files_on_disk { dir } {
- set regionfiles [glob -nocomplain $dir/__db.???]
- error_check_good regionfiles [llength $regionfiles] 0
- global env_private
- if { $env_private } {
- set regionfiles [glob -nocomplain $dir/__db.???]
- error_check_good regionfiles [llength $regionfiles] 0
- }
-}
-
-proc find_valid_methods { test } {
- global checking_valid_methods
- global valid_methods
-
- # To find valid methods, call the test with checking_valid_methods
- # on. It doesn't matter what method we use for this call, so we
- # arbitrarily pick btree.
- #
- set checking_valid_methods 1
- set test_methods [$test btree]
- set checking_valid_methods 0
- if { $test_methods == "ALL" } {
- return $valid_methods
- } else {
- return $test_methods
- }
-}
-
-proc part {data} {
- if { [string length $data] < 2 } {
- return 0
- }
- binary scan $data s res
- return $res
-}
-
-proc my_isalive { pid } {
- source ./include.tcl
-
- if {[catch {exec $KILL -0 $pid}]} {
- return 0
- }
- return 1
-}