1# See the file LICENSE for redistribution information. 2# 3# Copyright (c) 1996-2009 Oracle. All rights reserved. 4# 5# $Id$ 6# 7# TEST rpc001 8# TEST Test RPC server timeouts for cursor, txn and env handles. 9proc rpc001 { } { 10 global __debug_on 11 global __debug_print 12 global errorInfo 13 global is_je_test 14 global rpc_svc 15 source ./include.tcl 16 17 # 18 # First test timeouts on server. 19 # 20 set ttime 5 21 set itime 10 22 puts "Rpc001: Server timeouts: resource $ttime sec, idle $itime sec" 23 puts "Rpc001: Using $rpc_svc" 24 set dpid [rpc_server_start 0 30 -t $ttime -I $itime] 25 puts "\tRpc001.a: Started server, pid $dpid" 26 27 # 28 # Wrap the whole test in a catch statement so we can still kill 29 # the rpc server even if the test fails. 30 # 31 set status [catch { 32 tclsleep 2 33 remote_cleanup $rpc_server $rpc_testdir $testdir 34 35 puts "\tRpc001.b: Creating environment" 36 37 set testfile "rpc001.db" 38 set home [file tail $rpc_testdir] 39 40 set env [eval {berkdb_env -create -mode 0644 -home $home \ 41 -server $rpc_server -client_timeout 10000 -txn}] 42 error_check_good lock_env:open [is_valid_env $env] TRUE 43 44 puts "\tRpc001.c: Opening a database" 45 # 46 # NOTE: the type of database doesn't matter, just use btree. 47 set db [eval {berkdb_open -auto_commit -create -btree \ 48 -mode 0644} -env $env $testfile] 49 error_check_good dbopen [is_valid_db $db] TRUE 50 51 set curs_list {} 52 set txn_list {} 53 puts "\tRpc001.d: Basic timeout test" 54 puts "\tRpc001.d1: Starting a transaction" 55 set txn [$env txn] 56 error_check_good txn_begin [is_valid_txn $txn $env] TRUE 57 lappend txn_list $txn 58 59 puts "\tRpc001.d2: Open a cursor in that transaction" 60 set dbc [$db cursor -txn $txn] 61 error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE 62 lappend curs_list $dbc 63 64 puts "\tRpc001.d3: Duplicate that cursor" 65 set dbc [$dbc dup] 66 error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE 67 lappend curs_list $dbc 68 69 if { !$is_je_test } { 70 puts "\tRpc001.d4: Starting a nested transaction" 71 set txn [$env txn -parent $txn] 72 error_check_good txn_begin [is_valid_txn $txn $env] TRUE 73 set txn_list [linsert $txn_list 0 $txn] 74 } 75 76 puts "\tRpc001.d5: Create a cursor, no transaction" 77 set dbc [$db cursor] 78 error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE 79 lappend curs_list $dbc 80 81 puts "\tRpc001.d6: Timeout cursor and transactions" 82 set sleeptime [expr $ttime + 2] 83 tclsleep $sleeptime 84 85 # 86 # Perform a generic db operations to cause the timeout routine 87 # to trigger. 88 # 89 set stat [catch {$db stat} ret] 90 error_check_good dbstat $stat 0 91 92 # 93 # Check that every handle we opened above is timed out 94 # 95 foreach c $curs_list { 96 set stat [catch {$c close} ret] 97 error_check_good dbc_close:$c $stat 1 98 error_check_good dbc_timeout:$c \ 99 [is_substr $errorInfo "DB_NOSERVER_ID"] 1 100 } 101 foreach t $txn_list { 102 set stat [catch {$t commit} ret] 103 error_check_good txn_commit:$t $stat 1 104 error_check_good txn_timeout:$t \ 105 [is_substr $errorInfo "DB_NOSERVER_ID"] 1 106 } 107 108 set txn_list {} 109 110 if { !$is_je_test } { 111 set ntxns 8 112 puts "\tRpc001.e: Nested ($ntxns x $ntxns) txn activity test" 113 puts "\tRpc001.e1: Starting parent transaction" 114 set txn [$env txn] 115 error_check_good txn_begin [is_valid_txn $txn $env] TRUE 116 set txn_list [linsert $txn_list 0 $txn] 117 set last_txn $txn 118 set parent_txn $txn 119 120 # 121 # First set a breadth of 'ntxns' 122 # We need 2 from this set for testing later on. Just 123 # set them up separately first. 124 # 125 puts "\tRpc001.e2: Creating $ntxns child transactions" 126 set child0 [$env txn -parent $parent_txn] 127 error_check_good txn_begin \ 128 [is_valid_txn $child0 $env] TRUE 129 set child1 [$env txn -parent $parent_txn] 130 error_check_good txn_begin \ 131 [is_valid_txn $child1 $env] TRUE 132 133 for {set i 2} {$i < $ntxns} {incr i} { 134 set txn [$env txn -parent $parent_txn] 135 error_check_good txn_begin \ 136 [is_valid_txn $txn $env] TRUE 137 set txn_list [linsert $txn_list 0 $txn] 138 } 139 140 # 141 # Now make one 'ntxns' deeply nested. 142 # Add one more for testing later on separately. 143 # 144 puts "\tRpc001.e3: Creating $ntxns nested child transactions" 145 for {set i 0} {$i < $ntxns} {incr i} { 146 set txn [$env txn -parent $last_txn] 147 error_check_good txn_begin \ 148 [is_valid_txn $txn $env] TRUE 149 set txn_list [linsert $txn_list 0 $txn] 150 set last_txn $txn 151 } 152 set last_parent $last_txn 153 set last_txn [$env txn -parent $last_parent] 154 error_check_good txn_begin \ 155 [is_valid_txn $last_txn $env] TRUE 156 157 puts "\tRpc001.e4: Open a cursor in deepest transaction" 158 set dbc [$db cursor -txn $last_txn] 159 error_check_good db_cursor \ 160 [is_valid_cursor $dbc $db] TRUE 161 162 puts "\tRpc001.e5: Duplicate that cursor" 163 set dbcdup [$dbc dup] 164 error_check_good db_cursor \ 165 [is_valid_cursor $dbcdup $db] TRUE 166 lappend curs_list $dbcdup 167 168 puts "\tRpc001.f: Timeout then activate duplicate cursor" 169 tclsleep $sleeptime 170 set stat [catch {$dbcdup close} ret] 171 error_check_good dup_close:$dbcdup $stat 0 172 error_check_good dup_close:$dbcdup $ret 0 173 174 # 175 # Make sure that our parent txn is not timed out. We 176 # will try to begin another child tnx using the parent. 177 # We expect that to succeed. Immediately commit that 178 # txn. 179 # 180 set stat [catch {$env txn -parent $parent_txn} newchild] 181 error_check_good newchildtxn $stat 0 182 error_check_good newcommit [$newchild commit] 0 183 184 puts "\tRpc001.g: Timeout, then activate cursor" 185 tclsleep $sleeptime 186 set stat [catch {$dbc close} ret] 187 error_check_good dbc_close:$dbc $stat 0 188 error_check_good dbc_close:$dbc $ret 0 189 190 # 191 # Make sure that our parent txn is not timed out. We 192 # will try to begin another child tnx using the parent. 193 # We expect that to succeed. Immediately commit that 194 # txn. 195 # 196 set stat [catch {$env txn -parent $parent_txn} newchild] 197 error_check_good newchildtxn $stat 0 198 error_check_good newcommit [$newchild commit] 0 199 200 puts "\tRpc001.h: Timeout, then activate child txn" 201 tclsleep $sleeptime 202 set stat [catch {$child0 commit} ret] 203 error_check_good child_commit $stat 0 204 error_check_good child_commit:$child0 $ret 0 205 206 # 207 # Make sure that our nested txn is not timed out. We 208 # will try to begin another child tnx using the parent. 209 # We expect that to succeed. Immediately commit that 210 # txn. 211 # 212 set stat \ 213 [catch {$env txn -parent $last_parent} newchild] 214 error_check_good newchildtxn $stat 0 215 error_check_good newcommit [$newchild commit] 0 216 217 puts "\tRpc001.i: Timeout, then activate nested txn" 218 tclsleep $sleeptime 219 set stat [catch {$last_txn commit} ret] 220 error_check_good lasttxn_commit $stat 0 221 error_check_good lasttxn_commit:$child0 $ret 0 222 223 # 224 # Make sure that our child txn is not timed out. We 225 # should be able to commit it. 226 # 227 set stat [catch {$child1 commit} ret] 228 error_check_good child_commit:$child1 $stat 0 229 error_check_good child_commit:$child1 $ret 0 230 231 # 232 # Clean up. They were inserted in LIFO order, so we 233 # should just be able to commit them all. 234 # 235 foreach t $txn_list { 236 set stat [catch {$t commit} ret] 237 error_check_good txn_commit:$t $stat 0 238 error_check_good txn_commit:$t $ret 0 239 } 240 } 241 242 set stat [catch {$db close} ret] 243 error_check_good db_close $stat 0 244 245 rpc_timeoutjoin $env "Rpc001.j" $sleeptime 0 246 rpc_timeoutjoin $env "Rpc001.k" $sleeptime 1 247 248 puts "\tRpc001.l: Timeout idle env handle" 249 set sleeptime [expr $itime + 2] 250 tclsleep $sleeptime 251 252 # 253 # We need to do another operation to time out the environment 254 # handle. Open another environment, with an invalid home 255 # directory. 256 # 257 set stat [catch {eval {berkdb_env_noerr -home "$home.fail" \ 258 -server $rpc_server}} ret] 259 error_check_good env_open $stat 1 260 261 set stat [catch {$env close} ret] 262 error_check_good env_close $stat 1 263 error_check_good env_timeout \ 264 [is_substr $errorInfo "DB_NOSERVER_ID"] 1 265 } res] 266 if { $status != 0 } { 267 puts $res 268 } 269 tclkill $dpid 270} 271 272proc rpc_timeoutjoin {env msg sleeptime use_txn} { 273 # 274 # Check join cursors now. 275 # 276 puts -nonewline "\t$msg: Test join cursors and timeouts" 277 if { $use_txn } { 278 puts " (using txns)" 279 set txnflag "-auto_commit" 280 } else { 281 puts " (without txns)" 282 set txnflag "" 283 } 284 # 285 # Set up a simple set of join databases 286 # 287 puts "\t${msg}0: Set up join databases" 288 set fruit { 289 {blue blueberry} 290 {red apple} {red cherry} {red raspberry} 291 {yellow lemon} {yellow pear} 292 } 293 set price { 294 {expen blueberry} {expen cherry} {expen raspberry} 295 {inexp apple} {inexp lemon} {inexp pear} 296 } 297 set dessert { 298 {blueberry cobbler} {cherry cobbler} {pear cobbler} 299 {apple pie} {raspberry pie} {lemon pie} 300 } 301 set fdb [eval {berkdb_open -create -btree -mode 0644} \ 302 $txnflag -env $env -dup -dupsort fruit.db] 303 error_check_good dbopen [is_valid_db $fdb] TRUE 304 set pdb [eval {berkdb_open -create -btree -mode 0644} \ 305 $txnflag -env $env -dup -dupsort price.db] 306 error_check_good dbopen [is_valid_db $pdb] TRUE 307 set ddb [eval {berkdb_open -create -btree -mode 0644} \ 308 $txnflag -env $env -dup -dupsort dessert.db] 309 error_check_good dbopen [is_valid_db $ddb] TRUE 310 foreach kd $fruit { 311 set k [lindex $kd 0] 312 set d [lindex $kd 1] 313 set ret [eval {$fdb put} {$k $d}] 314 error_check_good fruit_put $ret 0 315 } 316 error_check_good sync [$fdb sync] 0 317 foreach kd $price { 318 set k [lindex $kd 0] 319 set d [lindex $kd 1] 320 set ret [eval {$pdb put} {$k $d}] 321 error_check_good price_put $ret 0 322 } 323 error_check_good sync [$pdb sync] 0 324 foreach kd $dessert { 325 set k [lindex $kd 0] 326 set d [lindex $kd 1] 327 set ret [eval {$ddb put} {$k $d}] 328 error_check_good dessert_put $ret 0 329 } 330 error_check_good sync [$ddb sync] 0 331 332 rpc_join $env $msg $sleeptime $fdb $pdb $ddb $use_txn 0 333 rpc_join $env $msg $sleeptime $fdb $pdb $ddb $use_txn 1 334 335 error_check_good ddb:close [$ddb close] 0 336 error_check_good pdb:close [$pdb close] 0 337 error_check_good fdb:close [$fdb close] 0 338 error_check_good ddb:remove [$env dbremove dessert.db] 0 339 error_check_good pdb:remove [$env dbremove price.db] 0 340 error_check_good fdb:remove [$env dbremove fruit.db] 0 341} 342 343proc rpc_join {env msg sleep fdb pdb ddb use_txn op} { 344 global errorInfo 345 global is_je_test 346 347 # 348 # Start a parent and child transaction. We'll do our join in 349 # the child transaction just to make sure everything gets timed 350 # out correctly. 351 # 352 set curs_list {} 353 set txn_list {} 354 set msgnum [expr $op * 2 + 1] 355 if { $use_txn } { 356 puts "\t$msg$msgnum: Set up txns and join cursor" 357 set txn [$env txn] 358 error_check_good txn_begin [is_valid_txn $txn $env] TRUE 359 set txn_list [linsert $txn_list 0 $txn] 360 if { !$is_je_test } { 361 set child0 [$env txn -parent $txn] 362 error_check_good txn_begin \ 363 [is_valid_txn $child0 $env] TRUE 364 set txn_list [linsert $txn_list 0 $child0] 365 set child1 [$env txn -parent $txn] 366 error_check_good txn_begin \ 367 [is_valid_txn $child1 $env] TRUE 368 set txn_list [linsert $txn_list 0 $child1] 369 } else { 370 set child0 $txn 371 set child1 $txn 372 } 373 set txncmd "-txn $child0" 374 } else { 375 puts "\t$msg$msgnum: Set up join cursor" 376 set txncmd "" 377 } 378 379 # 380 # Start a cursor, (using txn child0 in the fruit and price dbs, if 381 # needed). # Just pick something simple to join on. 382 # Then call join on the dessert db. 383 # 384 set fkey yellow 385 set pkey inexp 386 set fdbc [eval $fdb cursor $txncmd] 387 error_check_good fdb_cursor [is_valid_cursor $fdbc $fdb] TRUE 388 set ret [$fdbc get -set $fkey] 389 error_check_bad fget:set [llength $ret] 0 390 set k [lindex [lindex $ret 0] 0] 391 error_check_good fget:set:key $k $fkey 392 set curs_list [linsert $curs_list 0 $fdbc] 393 394 set pdbc [eval $pdb cursor $txncmd] 395 error_check_good pdb_cursor [is_valid_cursor $pdbc $pdb] TRUE 396 set ret [$pdbc get -set $pkey] 397 error_check_bad pget:set [llength $ret] 0 398 set k [lindex [lindex $ret 0] 0] 399 error_check_good pget:set:key $k $pkey 400 set curs_list [linsert $curs_list 0 $pdbc] 401 402 set jdbc [$ddb join $fdbc $pdbc] 403 error_check_good join_cursor [is_valid_cursor $jdbc $ddb] TRUE 404 set ret [$jdbc get] 405 error_check_bad jget [llength $ret] 0 406 407 set msgnum [expr $op * 2 + 2] 408 if { $op == 1 } { 409 puts -nonewline "\t$msg$msgnum: Timeout all cursors" 410 if { $use_txn } { 411 puts " and txns" 412 } else { 413 puts "" 414 } 415 } else { 416 puts "\t$msg$msgnum: Timeout, then activate join cursor" 417 } 418 419 tclsleep $sleep 420 421 if { $op == 1 } { 422 # 423 # Perform a generic db operations to cause the timeout routine 424 # to trigger. 425 # 426 set stat [catch {$fdb stat} ret] 427 error_check_good fdbstat $stat 0 428 429 # 430 # Check that join cursor is timed out. 431 # 432 set stat [catch {$jdbc close} ret] 433 error_check_good dbc_close:$jdbc $stat 1 434 error_check_good dbc_timeout:$jdbc \ 435 [is_substr $errorInfo "DB_NOSERVER_ID"] 1 436 437 # 438 # Now the server may or may not timeout constituent 439 # cursors when it times out the join cursor. So, just 440 # sleep again and then they should timeout. 441 # 442 tclsleep $sleep 443 set stat [catch {$fdb stat} ret] 444 error_check_good fdbstat $stat 0 445 446 foreach c $curs_list { 447 set stat [catch {$c close} ret] 448 error_check_good dbc_close:$c $stat 1 449 error_check_good dbc_timeout:$c \ 450 [is_substr $errorInfo "DB_NOSERVER_ID"] 1 451 } 452 453 foreach t $txn_list { 454 set stat [catch {$t commit} ret] 455 error_check_good txn_commit:$t $stat 1 456 error_check_good txn_timeout:$t \ 457 [is_substr $errorInfo "DB_NOSERVER_ID"] 1 458 } 459 } else { 460 set stat [catch {$jdbc get} ret] 461 error_check_good jget.stat $stat 0 462 error_check_bad jget [llength $ret] 0 463 set curs_list [linsert $curs_list 0 $jdbc] 464 foreach c $curs_list { 465 set stat [catch {$c close} ret] 466 error_check_good dbc_close:$c $stat 0 467 error_check_good dbc_close:$c $ret 0 468 } 469 470 foreach t $txn_list { 471 set stat [catch {$t commit} ret] 472 error_check_good txn_commit:$t $stat 0 473 error_check_good txn_commit:$t $ret 0 474 } 475 } 476} 477