227 lines
5.8 KiB
Tcl
227 lines
5.8 KiB
Tcl
# See the file LICENSE for redistribution information.
|
|
#
|
|
# Copyright (c) 1996-2004
|
|
# Sleepycat Software. All rights reserved.
|
|
#
|
|
# $Id: recd008.tcl,v 1.30 2004/11/05 00:59:01 mjc Exp $
|
|
#
|
|
# TEST recd008
|
|
# TEST Test deeply nested transactions and many-child transactions.
|
|
proc recd008 { method {breadth 4} {depth 4} args} {
|
|
global kvals
|
|
source ./include.tcl
|
|
|
|
set args [convert_args $method $args]
|
|
set omethod [convert_method $method]
|
|
|
|
puts "Recd008: $method $breadth X $depth deeply nested transactions"
|
|
|
|
# Create the database and environment.
|
|
env_cleanup $testdir
|
|
|
|
set dbfile recd008.db
|
|
|
|
puts "\tRecd008.a: create database"
|
|
set db [eval {berkdb_open -create} $args $omethod $testdir/$dbfile]
|
|
error_check_good dbopen [is_valid_db $db] TRUE
|
|
|
|
# Make sure that we have enough entries to span a couple of
|
|
# different pages.
|
|
set did [open $dict]
|
|
set count 0
|
|
while { [gets $did str] != -1 && $count < 1000 } {
|
|
if { [is_record_based $method] == 1 } {
|
|
set key [expr $count + 1]
|
|
} else {
|
|
set key $str
|
|
}
|
|
if { $count == 500} {
|
|
set p1 $key
|
|
set kvals($p1) $str
|
|
}
|
|
set ret [$db put $key [chop_data $method $str]]
|
|
error_check_good put $ret 0
|
|
|
|
incr count
|
|
}
|
|
close $did
|
|
error_check_good db_close [$db close] 0
|
|
|
|
set txn_max [expr int([expr pow($breadth,$depth)])]
|
|
if { $txn_max < 20 } {
|
|
set txn_max 20
|
|
}
|
|
puts "\tRecd008.b: create environment for $txn_max transactions"
|
|
|
|
set lock_max 2500
|
|
set eflags "-mode 0644 -create -lock_max $lock_max -txn_max $txn_max \
|
|
-txn -home $testdir"
|
|
set env_cmd "berkdb_env $eflags"
|
|
set dbenv [eval $env_cmd]
|
|
error_check_good env_open [is_valid_env $dbenv] TRUE
|
|
|
|
reset_env $dbenv
|
|
|
|
set rlist {
|
|
{ {recd008_parent abort ENV DB $method $p1 TXNID 1 1 $breadth $depth}
|
|
"Recd008.c: child abort parent" }
|
|
{ {recd008_parent commit ENV DB $method $p1 TXNID 1 1 $breadth $depth}
|
|
"Recd008.d: child commit parent" }
|
|
}
|
|
foreach pair $rlist {
|
|
set cmd [subst [lindex $pair 0]]
|
|
set msg [lindex $pair 1]
|
|
op_recover abort $testdir $env_cmd $dbfile $cmd $msg
|
|
recd008_setkval $dbfile $p1
|
|
op_recover commit $testdir $env_cmd $dbfile $cmd $msg
|
|
recd008_setkval $dbfile $p1
|
|
}
|
|
|
|
puts "\tRecd008.e: Verify db_printlog can read logfile"
|
|
set tmpfile $testdir/printlog.out
|
|
set stat [catch {exec $util_path/db_printlog -h $testdir \
|
|
> $tmpfile} ret]
|
|
error_check_good db_printlog $stat 0
|
|
fileremove $tmpfile
|
|
}
|
|
|
|
proc recd008_setkval { dbfile p1 } {
|
|
global kvals
|
|
source ./include.tcl
|
|
|
|
set db [berkdb_open $testdir/$dbfile]
|
|
error_check_good dbopen [is_valid_db $db] TRUE
|
|
set ret [$db get $p1]
|
|
error_check_good dbclose [$db close] 0
|
|
set kvals($p1) [lindex [lindex $ret 0] 1]
|
|
}
|
|
|
|
# This is a lot like the op_recover procedure. We cannot use that
|
|
# because it was not meant to be called recursively. This proc
|
|
# knows about depth/breadth and file naming so that recursive calls
|
|
# don't overwrite various initial and afterop files, etc.
|
|
#
|
|
# The basic flow of this is:
|
|
# (Initial file)
|
|
# Parent begin transaction (in op_recover)
|
|
# Parent starts children
|
|
# Recursively call recd008_recover
|
|
# (children modify p1)
|
|
# Parent modifies p1
|
|
# (Afterop file)
|
|
# Parent commit/abort (in op_recover)
|
|
# (Final file)
|
|
# Recovery test (in op_recover)
|
|
proc recd008_parent { op env db method p1key parent b0 d0 breadth depth } {
|
|
global kvals
|
|
source ./include.tcl
|
|
|
|
#
|
|
# Save copy of original data
|
|
# Acquire lock on data
|
|
#
|
|
set olddata [pad_data $method $kvals($p1key)]
|
|
set ret [$db get -rmw -txn $parent $p1key]
|
|
set Dret [lindex [lindex $ret 0] 1]
|
|
error_check_good get_parent_RMW $Dret $olddata
|
|
|
|
#
|
|
# Parent spawns off children
|
|
#
|
|
set ret [recd008_txn $op $env $db $method $p1key $parent \
|
|
$b0 $d0 $breadth $depth]
|
|
|
|
puts "Child runs complete. Parent modifies data."
|
|
|
|
#
|
|
# Parent modifies p1
|
|
#
|
|
set newdata $olddata.parent
|
|
set ret [$db put -txn $parent $p1key [chop_data $method $newdata]]
|
|
error_check_good db_put $ret 0
|
|
|
|
#
|
|
# Save value in kvals for later comparison
|
|
#
|
|
switch $op {
|
|
"commit" {
|
|
set kvals($p1key) $newdata
|
|
}
|
|
"abort" {
|
|
set kvals($p1key) $olddata
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
proc recd008_txn { op env db method p1key parent b0 d0 breadth depth } {
|
|
global log_log_record_types
|
|
global kvals
|
|
source ./include.tcl
|
|
|
|
for {set d 1} {$d < $d0} {incr d} {
|
|
puts -nonewline "\t"
|
|
}
|
|
puts "Recd008_txn: $op parent:$parent $breadth $depth ($b0 $d0)"
|
|
|
|
# Save the initial file and open the environment and the file
|
|
for {set b $b0} {$b <= $breadth} {incr b} {
|
|
#
|
|
# Begin child transaction
|
|
#
|
|
set t [$env txn -parent $parent]
|
|
error_check_bad txn_begin $t NULL
|
|
error_check_good txn_begin [is_valid_txn $t $env] TRUE
|
|
set startd [expr $d0 + 1]
|
|
set child $b:$startd:$t
|
|
set olddata [pad_data $method $kvals($p1key)]
|
|
set newdata $olddata.$child
|
|
set ret [$db get -rmw -txn $t $p1key]
|
|
set Dret [lindex [lindex $ret 0] 1]
|
|
error_check_good get_parent_RMW $Dret $olddata
|
|
|
|
#
|
|
# Recursively call to set up nested transactions/children
|
|
#
|
|
for {set d $startd} {$d <= $depth} {incr d} {
|
|
set ret [recd008_txn commit $env $db $method $p1key $t \
|
|
$b $d $breadth $depth]
|
|
set ret [recd008_txn abort $env $db $method $p1key $t \
|
|
$b $d $breadth $depth]
|
|
}
|
|
#
|
|
# Modifies p1.
|
|
#
|
|
set ret [$db put -txn $t $p1key [chop_data $method $newdata]]
|
|
error_check_good db_put $ret 0
|
|
|
|
#
|
|
# Commit or abort
|
|
#
|
|
for {set d 1} {$d < $startd} {incr d} {
|
|
puts -nonewline "\t"
|
|
}
|
|
puts "Executing txn_$op:$t"
|
|
error_check_good txn_$op:$t [$t $op] 0
|
|
for {set d 1} {$d < $startd} {incr d} {
|
|
puts -nonewline "\t"
|
|
}
|
|
set ret [$db get -rmw -txn $parent $p1key]
|
|
set Dret [lindex [lindex $ret 0] 1]
|
|
set newdata [pad_data $method $newdata]
|
|
switch $op {
|
|
"commit" {
|
|
puts "Command executed and committed."
|
|
error_check_good get_parent_RMW $Dret $newdata
|
|
set kvals($p1key) $newdata
|
|
}
|
|
"abort" {
|
|
puts "Command executed and aborted."
|
|
error_check_good get_parent_RMW $Dret $olddata
|
|
set kvals($p1key) $olddata
|
|
}
|
|
}
|
|
}
|
|
return 0
|
|
}
|