1# See the file LICENSE for redistribution information. 2# 3# Copyright (c) 2004,2008 Oracle. All rights reserved. 4# 5# $Id: test107.tcl,v 12.9 2008/01/08 20:58:53 bostic Exp $ 6# 7# TEST test107 8# TEST Test of read-committed (degree 2 isolation). [#8689] 9# TEST 10# TEST We set up a database. Open a read-committed transactional cursor and 11# TEST a regular transactional cursor on it. Position each cursor on one page, 12# TEST and do a put to a different page. 13# TEST 14# TEST Make sure that: 15# TEST - the put succeeds if we are using degree 2 isolation. 16# TEST - the put deadlocks within a regular transaction with 17# TEST a regular cursor. 18# TEST 19proc test107 { method args } { 20 source ./include.tcl 21 global fixed_len 22 global passwd 23 set tnum "107" 24 25 # If we are using an env, then skip this test. It needs its own. 26 set eindex [lsearch -exact $args "-env"] 27 if { $eindex != -1 } { 28 incr eindex 29 set env [lindex $args $eindex] 30 puts "Test$tnum skipping for env $env" 31 return 32 } 33 34 # We'll make the data pretty good sized so we can easily 35 # move to a different page. Make the data size a little 36 # smaller for fixed-length methods so it works with 37 # pagesize 512 tests. 38 set data_size 512 39 set orig_fixed_len $fixed_len 40 set fixed_len [expr $data_size - [expr $data_size / 8]] 41 set args [convert_args $method $args] 42 set encargs "" 43 set ddargs "" 44 set args [split_encargs $args encargs] 45 if { $encargs != "" } { 46 set ddargs " -P $passwd " 47 } 48 set omethod [convert_method $method] 49 50 puts "Test$tnum: Degree 2 Isolation Test ($method $args)" 51 set testfile test$tnum.db 52 env_cleanup $testdir 53 54 # Create the environment. 55 set timeout 10 56 set env [eval {berkdb_env -create -mode 0644 -lock \ 57 -cachesize { 0 1048576 1 } \ 58 -lock_timeout $timeout -txn} $encargs -home $testdir] 59 error_check_good env_open [is_valid_env $env] TRUE 60 61 # Create the database. 62 set db [eval {berkdb_open -env $env -create -auto_commit\ 63 -mode 0644 $omethod} $args {$testfile}] 64 error_check_good dbopen [is_valid_db $db] TRUE 65 66 puts "\tTest$tnum.a: put loop" 67 # The data doesn't need to change from key to key. 68 # Use numerical keys so we don't need special handling for 69 # record-based methods. 70 set origdata "data" 71 set len [string length $origdata] 72 set data [repeat $origdata [expr $data_size / $len]] 73 set nentries 200 74 set txn [$env txn] 75 for { set i 1 } { $i <= $nentries } { incr i } { 76 set key $i 77 set ret [eval {$db put} \ 78 -txn $txn {$key [chop_data $method $data]}] 79 error_check_good put:$db $ret 0 80 } 81 error_check_good txn_commit [$txn commit] 0 82 83 puts "\tTest$tnum.b: Start deadlock detector." 84 # Start up a deadlock detector so we can break self-deadlocks. 85 set dpid [eval {exec $util_path/db_deadlock} -v -ae -t 1.0 \ 86 -h $testdir $ddargs >& $testdir/dd.out &] 87 88 puts "\tTest$tnum.c: Open txns and cursors." 89 # We can get degree 2 isolation with either a degree 2 90 # txn or a degree 2 cursor or both. However, the case 91 # of a regular txn and regular cursor should deadlock. 92 # We put this case last so it won't deadlock the cases 93 # which should succeed. 94 # 95 # Cursors and transactions are named according to 96 # whether they specify degree 2 (c2, t2) or not (c, t). 97 # Set up all four possibilities. 98 # 99 set t [$env txn] 100 error_check_good reg_txn_begin [is_valid_txn $t $env] TRUE 101 set t2 [$env txn -read_committed] 102 error_check_good deg2_txn_begin [is_valid_txn $t2 $env] TRUE 103 104 set c2t [$db cursor -txn $t -read_committed] 105 error_check_good valid_c2t [is_valid_cursor $c2t $db] TRUE 106 set ct2 [$db cursor -txn $t2] 107 error_check_good valid_ct2 [is_valid_cursor $ct2 $db] TRUE 108 set c2t2 [$db cursor -txn $t2 -read_committed] 109 error_check_good valid_c2t2 [is_valid_cursor $c2t2 $db] TRUE 110 set ct [$db cursor -txn $t] 111 error_check_good valid_ct [is_valid_cursor $ct $db] TRUE 112 113 set curslist [list $c2t $ct2 $c2t2 $ct] 114 set newdata newdata 115 set offpagekey [expr $nentries - 1] 116 117 # For one cursor at a time, read the first item in the 118 # database, then move to an item on a different page. 119 # Put a new value in the first item on the first page. This 120 # should work with degree 2 isolation and hang without it. 121 # 122 # Wrap the whole thing in a catch statement so we still get 123 # around to killing the deadlock detector and cleaning up 124 # even if the test fails. 125 # 126 puts "\tTest$tnum.d: Test for read-committed (degree 2 isolation)." 127 set status [catch { 128 foreach cursor $curslist { 129 set retfirst [$cursor get -first] 130 set firstkey [lindex [lindex $retfirst 0] 0] 131 set ret [$cursor get -set $offpagekey] 132 error_check_good cursor_off_page \ 133 [lindex [lindex $ret 0] 0] $offpagekey 134 if { [catch {eval {$db put} \ 135 $firstkey [chop_data $method $newdata]} res]} { 136 error_check_good error_is_deadlock \ 137 [is_substr $res DB_LOCK_DEADLOCK] 1 138 error_check_good right_cursor_failed $cursor $ct 139 } else { 140 set ret [lindex [lindex [$db get $firstkey] 0] 1] 141 error_check_good data_changed \ 142 $ret [pad_data $method $newdata] 143 error_check_bad right_cursor_succeeded $cursor $ct 144 } 145 error_check_good close_cursor [$cursor close] 0 146 } 147 } res] 148 if { $status != 0 } { 149 puts $res 150 } 151 152 # Smoke test for db_stat -txn -read_committed. 153 puts "\tTest$tnum.e: Smoke test for db_stat -txn -read_committed" 154 if { [catch {set statret [$db stat -txn $t -read_committed]} res] } { 155 puts "FAIL: db_stat -txn -read_committed returned $res" 156 } 157 158 # End deadlock detection and clean up handles 159 puts "\tTest$tnum.f: Clean up." 160 tclkill $dpid 161 set fixed_len $orig_fixed_len 162 error_check_good t_commit [$t commit] 0 163 error_check_good t2_commit [$t2 commit] 0 164 error_check_good dbclose [$db close] 0 165 error_check_good envclose [$env close] 0 166} 167