1# See the file LICENSE for redistribution information. 2# 3# Copyright (c) 2003,2008 Oracle. All rights reserved. 4# 5# $Id: fop006.tcl,v 12.14 2008/01/08 20:58:53 bostic Exp $ 6# 7# TEST fop006 8# TEST Test file system operations in multiple simultaneous 9# TEST transactions. Start one transaction, do a file operation. 10# TEST Start a second transaction, do a file operation. Abort 11# TEST or commit txn1, then abort or commit txn2, and check for 12# TEST appropriate outcome. 13proc fop006 { method { inmem 0 } args } { 14 source ./include.tcl 15 16 # The variable inmem determines whether the test is being 17 # run on regular named databases or named in-memory databases. 18 if { $inmem == 0 } { 19 set tnum "006" 20 set string "regular named databases" 21 set operator do_op 22 } else { 23 set tnum "008" 24 set string "in-memory named databases" 25 set operator do_inmem_op 26 } 27 28 if { [is_btree $method] != 1 } { 29 puts "Skipping fop$tnum for method $method" 30 return 31 } 32 33 set args [convert_args $method $args] 34 set omethod [convert_method $method] 35 36 env_cleanup $testdir 37 puts "\nFop$tnum ($method): Two file system ops,\ 38 each in its own transaction, for $string." 39 40 set exists {a b} 41 set noexist {foo bar} 42 set open {} 43 set cases {} 44 set ops {open open_create open_excl rename remove truncate} 45 46 # Set up cases where op1 is successful. 47 foreach retval { 0 "file exists" "no such file" } { 48 foreach end1 {abort commit} { 49 foreach op1 $ops { 50 foreach op2 $ops { 51 append cases " " [create_tests\ 52 $op1 $op2 $exists $noexist\ 53 $open $retval $end1] 54 } 55 } 56 } 57 } 58 59 # Set up evil two-op cases (op1 fails). Omit open_create 60 # and truncate from op1 list -- open_create always succeeds 61 # and truncate requires a successful open. 62 foreach retval { 0 "file exists" "no such file" } { 63 foreach op1 { rename remove open open_excl } { 64 foreach op2 $ops { 65 append cases " " [create_badtests $op1 $op2 \ 66 $exists $noexist $open $retval $end1] 67 } 68 } 69 } 70 71 # The structure of each case is: 72 # {{op1 {args} result end} {op2 {args} result}} 73 # A result of "0" indicates no error is expected. Otherwise, 74 # the result is the expected error message. The value of "end" 75 # indicates whether the transaction will be aborted or committed. 76 # 77 # Comment this loop out to remove the list of cases. 78# set i 1 79# foreach case $cases { 80# puts "\tFop$tnum.$i: $case" 81# incr i 82# } 83 84 # To run a particular case, add the case in this format and 85 # uncomment. 86# set cases { 87# {{open_excl {foo} 0 abort} {rename {b foo} 0}} 88# } 89 90 set testid 0 91 92 # Run all the cases 93 foreach case $cases { 94 incr testid 95 96 # Extract elements of the case 97 set op1 [lindex [lindex $case 0] 0] 98 set names1 [lindex [lindex $case 0] 1] 99 set res1 [lindex [lindex $case 0] 2] 100 set end1 [lindex [lindex $case 0] 3] 101 102 set op2 [lindex [lindex $case 1] 0] 103 set names2 [lindex [lindex $case 1] 1] 104 set res2 [lindex [lindex $case 1] 2] 105 106 puts "\tFop$tnum.$testid: $op1 ($names1) $res1 $end1;\ 107 $op2 ($names2) $res2." 108 109 foreach end2 { abort commit } { 110 # Create transactional environment. 111 set env [berkdb_env -create -home $testdir -txn] 112 error_check_good is_valid_env [is_valid_env $env] TRUE 113 114 # Create databases 115 if { $inmem == 0 } { 116 set db [eval {berkdb_open -create} \ 117 $omethod $args -env $env -auto_commit a] 118 } else { 119 set db [eval {berkdb_open -create} \ 120 $omethod $args -env $env -auto_commit {""} a] 121 } 122 error_check_good db_open [is_valid_db $db] TRUE 123 error_check_good db_put \ 124 [$db put 1 [chop_data $method a]] 0 125 error_check_good db_close [$db close] 0 126 127 if { $inmem == 0 } { 128 set db [eval {berkdb_open -create} \ 129 $omethod $args -env $env -auto_commit b] 130 } else { 131 set db [eval {berkdb_open -create} \ 132 $omethod $args -env $env -auto_commit {""} b] 133 } 134 error_check_good db_open [is_valid_db $db] TRUE 135 error_check_good db_put \ 136 [$db put 1 [chop_data $method a]] 0 137 error_check_good db_close [$db close] 0 138 139 # Start transaction 1 and perform a file op. 140 set txn1 [$env txn] 141 error_check_good \ 142 txn_begin [is_valid_txn $txn1 $env] TRUE 143 set result1 [$operator $omethod $op1 $names1 $txn1 $env $args] 144 if { $res1 == 0 } { 145 error_check_good \ 146 op1_should_succeed $result1 $res1 147 } else { 148 set error [extract_error $result1] 149 error_check_good op1_wrong_failure $error $res1 150 } 151 152 # Start transaction 2 before ending transaction 1. 153 set pid [exec $tclsh_path $test_path/wrap.tcl \ 154 fopscript.tcl $testdir/fop$tnum.log \ 155 $operator $omethod $op2 $end2 $res2 $names2 &] 156 157 # Sleep a bit to give txn2 a chance to block. 158 tclsleep 2 159 160 # End transaction 1 and close any open db handles. 161 # Txn2 will now unblock and finish. 162 error_check_good txn1_$end1 [$txn1 $end1] 0 163 set handles [berkdb handles] 164 foreach handle $handles { 165 if {[string range $handle 0 1] == "db" } { 166 error_check_good \ 167 db_close [$handle close] 0 168 } 169 } 170 watch_procs $pid 1 60 1 171 172 # Clean up for next case 173 error_check_good env_close [$env close] 0 174 catch { [berkdb envremove -home $testdir] } res 175 176 # Check for errors in log file. 177 set errstrings [eval findfail $testdir/fop$tnum.log] 178 foreach str $errstrings { 179 puts "FAIL: error message in log file: $str" 180 } 181 env_cleanup $testdir 182 } 183 } 184} 185 186