1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
|
# See the file LICENSE for redistribution information.
#
# Copyright (c) 1999, 2013 Oracle and/or its affiliates. All rights reserved.
#
# $Id$
#
proc t106_initial { nitems nprod id tnum dbenv order args } {
source ./include.tcl
set pid [pid]
puts "\tTest$tnum: Producer $pid initializing DBs"
# Each producer initially loads a small number of items to
# each btree database, then enters a RMW loop where it randomly
# selects and executes a cursor operations which either:
# 1. Read-modify-write an item in db2; or
# 2. Read-modify-write an item in both db2 and db3, randomly
# selecting between db2 and db3 on which to open first, which to
# read first, which to write first, which to close first. This
# may create deadlocks so keep trying until it's successful.
# Open queue database
set dbq [eval {berkdb_open -create -queue -env $dbenv\
-auto_commit -len 32 queue.db} ]
error_check_good dbq_open [is_valid_db $dbq] TRUE
# Open four btree databases
set db1 [berkdb_open \
-create -btree -env $dbenv -auto_commit testfile1.db]
error_check_good db1_open [is_valid_db $db1] TRUE
set db2 [berkdb_open \
-create -btree -env $dbenv -auto_commit testfile2.db]
error_check_good db2_open [is_valid_db $db2] TRUE
set db3 [berkdb_open \
-create -btree -env $dbenv -auto_commit testfile3.db]
error_check_good db3_open [is_valid_db $db3] TRUE
set db4 [berkdb_open \
-create -btree -env $dbenv -auto_commit testfile4.db]
error_check_good db4_open [is_valid_db $db4] TRUE
# Initialize databases with $nitems items from each producer.
set did [open $dict]
for { set i 1 } { $i <= $nitems } { incr i } {
set db2data [read $did [berkdb random_int 300 700]]
set db3data [read $did [berkdb random_int 500 1000]]
set qdata [read $did 32]
set suffix _0_$i
set db23key "testclient$id$suffix"
set suffix _$i
set db4key key$id$suffix
set t [$dbenv txn]
set txn "-txn $t"
error_check_good db2_put [eval {$db2 put} $txn\
{$db23key $db2data}] 0
error_check_good db3_put [eval {$db3 put} $txn\
{$db23key $db3data}] 0
error_check_good db4_put [eval {$db4 put} $txn\
{$db4key $db23key}] 0
set c [$dbenv txn -parent $t]
set ctxn "-txn $c"
set qrecno [eval {$dbq put -append} $ctxn {$qdata}]
error_check_good db1_put [eval {$db1 put} $ctxn\
{$qrecno $db2data}] 0
error_check_good commit_child [$c commit] 0
error_check_good commit_parent [$t commit] 0
}
close $did
set ret [catch {$dbq close} res]
error_check_good dbq_close:$pid $ret 0
set ret [catch {$db1 close} res]
error_check_good db1_close:$pid $ret 0
set ret [catch {$db2 close} res]
error_check_good db2_close:$pid $ret 0
set ret [catch {$db3 close} res]
error_check_good db3_close:$pid $ret 0
set ret [catch {$db4 close} res]
error_check_good db4_close:$pid $ret 0
puts "\t\tTest$tnum: Initializer $pid finished."
}
proc t106_produce { nitems nprod id tnum dbenv order niter args } {
source ./include.tcl
set pid [pid]
set did [open $dict]
puts "\tTest$tnum: Producer $pid initializing DBs"
# Open queue database
set dbq [eval {berkdb_open -create -queue -env $dbenv\
-auto_commit -len 32 queue.db} ]
error_check_good dbq_open [is_valid_db $dbq] TRUE
# Open four btree databases
set db1 [berkdb_open \
-create -btree -env $dbenv -auto_commit testfile1.db]
error_check_good db1_open [is_valid_db $db1] TRUE
set db2 [berkdb_open \
-create -btree -env $dbenv -auto_commit testfile2.db]
error_check_good db2_open [is_valid_db $db2] TRUE
set db3 [berkdb_open \
-create -btree -env $dbenv -auto_commit testfile3.db]
error_check_good db3_open [is_valid_db $db3] TRUE
set db4 [berkdb_open \
-create -btree -env $dbenv -auto_commit testfile4.db]
error_check_good db4_open [is_valid_db $db4] TRUE
# Now go into RMW phase.
for { set i 1 } { $i <= $niter } { incr i } {
set op [berkdb random_int 1 2]
set newdb2data [read $did [berkdb random_int 300 700]]
set qdata [read $did 32]
if { $order == "ordered" } {
set n [expr $i % $nitems]
if { $n == 0 } {
set n $nitems
}
set suffix _0_$n
} else {
# Retrieve a random key from the list
set suffix _0_[berkdb random_int 1 $nitems]
}
set key "testclient$id$suffix"
set t [$dbenv txn]
set txn "-txn $t"
# Now execute op1 or op2
if { $op == 1 } {
op1 $db2 $key $newdb2data $txn
} elseif { $op == 2 } {
set newdb3data [read $did [berkdb random_int 500 1000]]
op2 $db2 $db3 $key $newdb2data $newdb3data $txn $dbenv
} else {
puts "FAIL: unrecogized op $op"
}
set c [$dbenv txn -parent $t]
set ctxn "-txn $c"
set qrecno [eval {$dbq put -append} $ctxn {$qdata}]
error_check_good db1_put [eval {$db1 put} $ctxn\
{$qrecno $newdb2data}] 0
error_check_good child_commit [$c commit] 0
error_check_good parent_commit [$t commit] 0
}
close $did
set ret [catch {$dbq close} res]
error_check_good dbq_close:$pid $ret 0
set ret [catch {$db1 close} res]
error_check_good db1_close:$pid $ret 0
set ret [catch {$db2 close} res]
error_check_good db2_close:$pid $ret 0
set ret [catch {$db3 close} res]
error_check_good db3_close:$pid $ret 0
set ret [catch {$db4 close} res]
error_check_good db4_close:$pid $ret 0
puts "\t\tTest$tnum: Producer $pid finished."
}
proc t106_consume { nitems tnum outputfile mode dbenv niter args } {
source ./include.tcl
set pid [pid]
puts "\tTest$tnum: Consumer $pid starting ($niter iterations)."
# Open queue database and btree database 1.
set dbq [eval {berkdb_open \
-create -queue -env $dbenv -auto_commit -len 32 queue.db} ]
error_check_good dbq_open:$pid [is_valid_db $dbq] TRUE
set db1 [eval {berkdb_open \
-create -btree -env $dbenv -auto_commit testfile1.db} ]
error_check_good db1_open:$pid [is_valid_db $db1] TRUE
set oid [open $outputfile a]
for { set i 1 } { $i <= $nitems } {incr i } {
set t [$dbenv txn]
set txn "-txn $t"
set ret [eval {$dbq get $mode} $txn]
set qrecno [lindex [lindex $ret 0] 0]
set db1curs [eval {$db1 cursor} $txn]
if {[catch {eval $db1curs get -set -rmw $qrecno} res]} {
puts "FAIL: $db1curs get: $res"
}
error_check_good db1curs_del [$db1curs del] 0
error_check_good db1curs_close [$db1curs close] 0
error_check_good txn_commit [$t commit] 0
}
error_check_good output_close:$pid [close $oid] ""
set ret [catch {$dbq close} res]
error_check_good dbq_close:$pid $ret 0
set ret [catch {$db1 close} res]
error_check_good db1_close:$pid $ret 0
puts "\t\tTest$tnum: Consumer $pid finished."
}
# op1 overwrites one data item in db2.
proc op1 { db2 key newdata txn } {
set db2c [eval {$db2 cursor} $txn]
puts "in op1, key is $key"
set ret [eval {$db2c get -set -rmw $key}]
# Make sure we retrieved something
error_check_good db2c_get [llength $ret] 1
error_check_good db2c_put [eval {$db2c put} -current {$newdata}] 0
error_check_good db2c_close [$db2c close] 0
}
# op 2
proc op2 { db2 db3 key newdata2 newdata3 txn dbenv } {
# Randomly choose whether to work on db2 or db3 first for
# each operation: open cursor, get, put, close.
set open1 [berkdb random_int 0 1]
set get1 [berkdb random_int 0 1]
set put1 [berkdb random_int 0 1]
set close1 [berkdb random_int 0 1]
puts "open [expr $open1 + 2] first, get [expr $get1 + 2] first,\
put [expr $put1 + 2] first, close [expr $close1 + 2] first"
puts "in op2, key is $key"
# Open cursor
if { $open1 == 0 } {
set db2c [eval {$db2 cursor} $txn]
set db3c [eval {$db3 cursor} $txn]
} else {
set db3c [eval {$db3 cursor} $txn]
set db2c [eval {$db2 cursor} $txn]
}
error_check_good db2_cursor [is_valid_cursor $db2c $db2] TRUE
error_check_good db3_cursor [is_valid_cursor $db3c $db3] TRUE
# Do the following until we succeed and don't get DB_DEADLOCK:
if { $get1 == 0 } {
get_set_rmw $db2c $key $dbenv
get_set_rmw $db3c $key $dbenv
} else {
get_set_rmw $db3c $key $dbenv
get_set_rmw $db2c $key $dbenv
}
# Put new data.
if { $put1 == 0 } {
error_check_good db2c_put [eval {$db2c put} \
-current {$newdata2}] 0
error_check_good db3c_put [eval {$db3c put} \
-current {$newdata3}] 0
} else {
error_check_good db3c_put [eval {$db3c put} \
-current {$newdata3}] 0
error_check_good db2c_put [eval {$db2c put} \
-current {$newdata2}] 0
}
if { $close1 == 0 } {
error_check_good db2c_close [$db2c close] 0
error_check_good db3c_close [$db3c close] 0
} else {
error_check_good db3c_close [$db3c close] 0
error_check_good db2c_close [$db2c close] 0
}
}
proc get_set_rmw { dbcursor key dbenv } {
while { 1 } {
if {[catch {set ret [eval {$dbcursor get -set -rmw} $key]}\
res ]} {
# If the get failed, break if it failed for any
# reason other than deadlock. If we have deadlock,
# the deadlock detector should break the deadlock
# as we keep trying.
if { [is_substr $res DB_LOCK_DEADLOCK] != 1 } {
puts "FAIL: get_set_rmw: $res"
break
}
} else {
# We succeeded. Go back to the body of the test.
break
}
}
}
source ./include.tcl
source $test_path/test.tcl
# Verify usage
set usage "t106script.tcl dir runtype nitems nprod outputfile id tnum order"
if { $argc < 10 } {
puts stderr "FAIL:[timestamp] Usage: $usage"
exit
}
# Initialize arguments
set dir [lindex $argv 0]
set runtype [lindex $argv 1]
set nitems [lindex $argv 2]
set nprod [lindex $argv 3]
set outputfile [lindex $argv 4]
set id [lindex $argv 5]
set tnum [lindex $argv 6]
set order [lindex $argv 7]
set niter [lindex $argv 8]
# args is the string "{ -len 20 -pad 0}", so we need to extract the
# " -len 20 -pad 0" part.
set args [lindex [lrange $argv 9 end] 0]
# Open env
set dbenv [berkdb_env -home $dir -txn]
error_check_good dbenv_open [is_valid_env $dbenv] TRUE
# Invoke initial, produce or consume based on $runtype
if { $runtype == "INITIAL" } {
t106_initial $nitems $nprod $id $tnum $dbenv $order $args
} elseif { $runtype == "PRODUCE" } {
t106_produce $nitems $nprod $id $tnum $dbenv $order $niter $args
} elseif { $runtype == "WAIT" } {
t106_consume $nitems $tnum $outputfile -consume_wait $dbenv $args
} else {
error_check_good bad_args $runtype "either PRODUCE, or WAIT"
}
error_check_good env_close [$dbenv close] 0
exit
|