1# See the file LICENSE for redistribution information. 2# 3# Copyright (c) 2000,2008 Oracle. All rights reserved. 4# 5# $Id: recd013.tcl,v 12.7 2008/01/08 20:58:53 bostic Exp $ 6# 7# TEST recd013 8# TEST Test of cursor adjustment on child transaction aborts. [#2373] 9# 10# XXX 11# Other tests that cover more specific variants of the same issue 12# are in the access method tests for now. This is probably wrong; we 13# put this one here because they're closely based on and intertwined 14# with other, non-transactional cursor stability tests that are among 15# the access method tests, and because we need at least one test to 16# fit under recd and keep logtrack from complaining. We'll sort out the mess 17# later; the important thing, for now, is that everything that needs to gets 18# tested. (This really shouldn't be under recd at all, since it doesn't 19# run recovery!) 20proc recd013 { method { nitems 100 } args } { 21 source ./include.tcl 22 global alphabet log_log_record_types 23 24 set args [convert_args $method $args] 25 set omethod [convert_method $method] 26 set tnum "013" 27 set pgsz 512 28 29 puts "Recd$tnum $method ($args): Test of aborted cursor adjustments." 30 set pgindex [lsearch -exact $args "-pagesize"] 31 if { $pgindex != -1 } { 32 puts "Recd013: skipping for specific pagesizes" 33 return 34 } 35 36 set testfile recd$tnum.db 37 env_cleanup $testdir 38 39 set i 0 40 if { [is_record_based $method] == 1 } { 41 set keybase "" 42 } else { 43 set keybase "key" 44 } 45 46 puts "\tRecd$tnum.a:\ 47 Create environment, database, and parent transaction." 48 set flags "-create -txn -home $testdir" 49 50 set env_cmd "berkdb_env $flags" 51 set env [eval $env_cmd] 52 error_check_good dbenv [is_valid_env $env] TRUE 53 54 set oflags \ 55 "-auto_commit -env $env -create -mode 0644 -pagesize $pgsz $args $omethod" 56 set db [eval {berkdb_open} $oflags $testfile] 57 error_check_good dbopen [is_valid_db $db] TRUE 58 59 # Create a database containing $nitems items, numbered with odds. 60 # We'll then put the even numbers during the body of the test. 61 set txn [$env txn] 62 error_check_good init_txn [is_valid_txn $txn $env] TRUE 63 for { set i 1 } { $i <= 2 * $nitems } { incr i 2 } { 64 set key $keybase$i 65 set data [chop_data $method $i$alphabet] 66 67 # First, try to put the item in a child transaction, 68 # then abort and verify all the cursors we've done up until 69 # now. 70 set ctxn [$env txn -parent $txn] 71 error_check_good child_txn($i) [is_valid_txn $ctxn $env] TRUE 72 error_check_good fake_put($i) [$db put -txn $ctxn $key $data] 0 73 error_check_good ctxn_abort($i) [$ctxn abort] 0 74 for { set j 1 } { $j < $i } { incr j 2 } { 75 error_check_good dbc_get($j):1 [$dbc($j) get -current] \ 76 [list [list $keybase$j \ 77 [pad_data $method $j$alphabet]]] 78 } 79 80 # Then put for real. 81 error_check_good init_put($i) [$db put -txn $txn $key $data] 0 82 83 # Set a cursor of the parent txn to each item. 84 set dbc($i) [$db cursor -txn $txn] 85 error_check_good dbc_getset($i) \ 86 [$dbc($i) get -set $key] \ 87 [list [list $keybase$i [pad_data $method $i$alphabet]]] 88 89 # And verify all the cursors, including the one we just 90 # created. 91 for { set j 1 } { $j <= $i } { incr j 2 } { 92 error_check_good dbc_get($j):2 [$dbc($j) get -current] \ 93 [list [list $keybase$j \ 94 [pad_data $method $j$alphabet]]] 95 } 96 } 97 98 puts "\t\tRecd$tnum.a.1: Verify cursor stability after init." 99 for { set i 1 } { $i <= 2 * $nitems } { incr i 2 } { 100 error_check_good dbc_get($i):3 [$dbc($i) get -current] \ 101 [list [list $keybase$i [pad_data $method $i$alphabet]]] 102 } 103 104 puts "\tRecd$tnum.b: Put test." 105 puts "\t\tRecd$tnum.b.1: Put items." 106 set ctxn [$env txn -parent $txn] 107 error_check_good txn [is_valid_txn $ctxn $env] TRUE 108 for { set i 2 } { $i <= 2 * $nitems } { incr i 2 } { 109 set key $keybase$i 110 set data [chop_data $method $i$alphabet] 111 error_check_good child_put($i) [$db put -txn $ctxn $key $data] 0 112 113 # If we're a renumbering recno, this is uninteresting. 114 # Stir things up by putting a few additional records at 115 # the beginning. 116 if { [is_rrecno $method] == 1 } { 117 set curs [$db cursor -txn $ctxn] 118 error_check_bad llength_get_first \ 119 [llength [$curs get -first]] 0 120 error_check_good cursor [is_valid_cursor $curs $db] TRUE 121 # expect a recno! 122 error_check_good rrecno_put($i) \ 123 [$curs put -before ADDITIONAL.$i] 1 124 error_check_good curs_close [$curs close] 0 125 } 126 } 127 128 puts "\t\tRecd$tnum.b.2: Verify cursor stability after abort." 129 error_check_good ctxn_abort [$ctxn abort] 0 130 131 for { set i 1 } { $i <= 2 * $nitems } { incr i 2 } { 132 error_check_good dbc_get($i):4 [$dbc($i) get -current] \ 133 [list [list $keybase$i [pad_data $method $i$alphabet]]] 134 } 135 136 # Clean up cursors. 137 for { set i 1 } { $i <= 2 * $nitems } { incr i 2 } { 138 error_check_good dbc($i)_close [$dbc($i) close] 0 139 } 140 141 # Sync and verify. 142 error_check_good txn_commit [$txn commit] 0 143 set txn [$env txn] 144 error_check_good txn [is_valid_txn $txn $env] TRUE 145 146 error_check_good db_sync [$db sync] 0 147 error_check_good db_verify \ 148 [verify_dir $testdir "\t\tRecd$tnum.b.3: "] 0 149 150 # Now put back all the even records, this time in the parent. 151 # Commit and re-begin the transaction so we can abort and 152 # get back to a nice full database. 153 for { set i 2 } { $i <= 2 * $nitems } { incr i 2 } { 154 set key $keybase$i 155 set data [chop_data $method $i$alphabet] 156 error_check_good child_put($i) [$db put -txn $txn $key $data] 0 157 } 158 error_check_good txn_commit [$txn commit] 0 159 set txn [$env txn] 160 error_check_good txn [is_valid_txn $txn $env] TRUE 161 162 # Delete test. Set a cursor to each record. Delete the even ones 163 # in the parent and check cursor stability. Then open a child 164 # transaction, and delete the odd ones. Verify that the database 165 # is empty. 166 puts "\tRecd$tnum.c: Delete test." 167 unset dbc 168 169 # Create cursors pointing at each item. 170 for { set i 1 } { $i <= 2 * $nitems } { incr i } { 171 set dbc($i) [$db cursor -txn $txn] 172 error_check_good dbc($i)_create [is_valid_cursor $dbc($i) $db] \ 173 TRUE 174 error_check_good dbc_getset($i) [$dbc($i) get -set $keybase$i] \ 175 [list [list $keybase$i [pad_data $method $i$alphabet]]] 176 } 177 178 puts "\t\tRecd$tnum.c.1: Delete even items in child txn and abort." 179 180 if { [is_rrecno $method] != 1 } { 181 set init 2 182 set bound [expr 2 * $nitems] 183 set step 2 184 } else { 185 # In rrecno, deletes will renumber the items, so we have 186 # to take that into account when we delete by recno. 187 set init 2 188 set bound [expr $nitems + 1] 189 set step 1 190 } 191 192 set ctxn [$env txn -parent $txn] 193 for { set i $init } { $i <= $bound } { incr i $step } { 194 error_check_good del($i) [$db del -txn $ctxn $keybase$i] 0 195 } 196 error_check_good ctxn_abort [$ctxn abort] 0 197 198 # Verify that no items are deleted. 199 for { set i 1 } { $i <= 2 * $nitems } { incr i } { 200 error_check_good dbc_get($i):5 [$dbc($i) get -current] \ 201 [list [list $keybase$i [pad_data $method $i$alphabet]]] 202 } 203 204 puts "\t\tRecd$tnum.c.2: Delete even items in child txn and commit." 205 set ctxn [$env txn -parent $txn] 206 for { set i $init } { $i <= $bound } { incr i $step } { 207 error_check_good del($i) [$db del -txn $ctxn $keybase$i] 0 208 } 209 error_check_good ctxn_commit [$ctxn commit] 0 210 211 # Verify that even items are deleted and odd items are not. 212 for { set i 1 } { $i <= 2 * $nitems } { incr i 2 } { 213 if { [is_rrecno $method] != 1 } { 214 set j $i 215 } else { 216 set j [expr ($i - 1) / 2 + 1] 217 } 218 error_check_good dbc_get($i):6 [$dbc($i) get -current] \ 219 [list [list $keybase$j [pad_data $method $i$alphabet]]] 220 } 221 for { set i 2 } { $i <= 2 * $nitems } { incr i 2 } { 222 error_check_good dbc_get($i):7 [$dbc($i) get -current] "" 223 } 224 225 puts "\t\tRecd$tnum.c.3: Delete odd items in child txn." 226 227 set ctxn [$env txn -parent $txn] 228 229 for { set i 1 } { $i <= 2 * $nitems } { incr i 2 } { 230 if { [is_rrecno $method] != 1 } { 231 set j $i 232 } else { 233 # If this is an rrecno, just delete the first 234 # item repeatedly--the renumbering will make 235 # that delete everything. 236 set j 1 237 } 238 error_check_good del($i) [$db del -txn $ctxn $keybase$j] 0 239 } 240 241 # Verify that everyone's deleted. 242 for { set i 1 } { $i <= 2 * $nitems } { incr i } { 243 error_check_good get_deleted($i) \ 244 [llength [$db get -txn $ctxn $keybase$i]] 0 245 } 246 247 puts "\t\tRecd$tnum.c.4: Verify cursor stability after abort." 248 error_check_good ctxn_abort [$ctxn abort] 0 249 250 # Verify that even items are deleted and odd items are not. 251 for { set i 1 } { $i <= 2 * $nitems } { incr i 2 } { 252 if { [is_rrecno $method] != 1 } { 253 set j $i 254 } else { 255 set j [expr ($i - 1) / 2 + 1] 256 } 257 error_check_good dbc_get($i):8 [$dbc($i) get -current] \ 258 [list [list $keybase$j [pad_data $method $i$alphabet]]] 259 } 260 for { set i 2 } { $i <= 2 * $nitems } { incr i 2 } { 261 error_check_good dbc_get($i):9 [$dbc($i) get -current] "" 262 } 263 264 # Clean up cursors. 265 for { set i 1 } { $i <= 2 * $nitems } { incr i } { 266 error_check_good dbc($i)_close [$dbc($i) close] 0 267 } 268 269 # Sync and verify. 270 error_check_good db_sync [$db sync] 0 271 error_check_good db_verify \ 272 [verify_dir $testdir "\t\tRecd$tnum.c.5: "] 0 273 274 puts "\tRecd$tnum.d: Clean up." 275 error_check_good txn_commit [$txn commit] 0 276 error_check_good db_close [$db close] 0 277 error_check_good log_flush [$env log_flush] 0 278 error_check_good env_close [$env close] 0 279 error_check_good verify_dir \ 280 [verify_dir $testdir "\t\tRecd$tnum.d.1: "] 0 281 282 if { $log_log_record_types == 1 } { 283 logtrack_read $testdir 284 } 285} 286