1# See the file LICENSE for redistribution information. 2# 3# Copyright (c) 1999,2008 Oracle. All rights reserved. 4# 5# $Id: recd014.tcl,v 12.6 2008/01/08 20:58:53 bostic Exp $ 6# 7# TEST recd014 8# TEST This is a recovery test for create/delete of queue extents. We 9# TEST then need to recover and make sure the file is correctly existing 10# TEST or not, as the case may be. 11proc recd014 { method args} { 12 global fixed_len 13 source ./include.tcl 14 15 if { ![is_queueext $method] == 1 } { 16 puts "Recd014: Skipping for method $method" 17 return 18 } 19 set pgindex [lsearch -exact $args "-pagesize"] 20 if { $pgindex != -1 } { 21 puts "Recd014: skipping for specific pagesizes" 22 return 23 } 24 25 set orig_fixed_len $fixed_len 26 # 27 # We will use 512-byte pages, to be able to control 28 # when extents get created/removed. 29 # 30 set fixed_len 300 31 32 set opts [convert_args $method $args] 33 set omethod [convert_method $method] 34 # 35 # We want to set -extent 1 instead of what 36 # convert_args gave us. 37 # 38 set exti [lsearch -exact $opts "-extent"] 39 incr exti 40 set opts [lreplace $opts $exti $exti 1] 41 42 puts "Recd014: $method extent creation/deletion tests" 43 44 # Create the database and environment. 45 env_cleanup $testdir 46 47 set testfile recd014.db 48 set flags "-create -txn -home $testdir" 49 50 puts "\tRecd014.a: creating environment" 51 set env_cmd "berkdb_env $flags" 52 53 puts "\tRecd014.b: Create test commit" 54 ext_recover_create $testdir $env_cmd $omethod \ 55 $opts $testfile commit 56 puts "\tRecd014.b: Create test abort" 57 ext_recover_create $testdir $env_cmd $omethod \ 58 $opts $testfile abort 59 60 puts "\tRecd014.c: Consume test commit" 61 ext_recover_consume $testdir $env_cmd $omethod \ 62 $opts $testfile commit 63 puts "\tRecd014.c: Consume test abort" 64 ext_recover_consume $testdir $env_cmd $omethod \ 65 $opts $testfile abort 66 67 set fixed_len $orig_fixed_len 68 puts "\tRecd014.d: Verify db_printlog can read logfile" 69 set tmpfile $testdir/printlog.out 70 set stat [catch {exec $util_path/db_printlog -h $testdir \ 71 > $tmpfile} ret] 72 error_check_good db_printlog $stat 0 73 fileremove $tmpfile 74} 75 76proc ext_recover_create { dir env_cmd method opts dbfile txncmd } { 77 global log_log_record_types 78 global fixed_len 79 global alphabet 80 source ./include.tcl 81 82 # Keep track of the log types we've seen 83 if { $log_log_record_types == 1} { 84 logtrack_read $dir 85 } 86 87 env_cleanup $dir 88 # Open the environment and set the copy/abort locations 89 set env [eval $env_cmd] 90 91 set init_file $dir/$dbfile.init 92 set noenvflags "-create $method -mode 0644 -pagesize 512 $opts $dbfile" 93 set oflags "-env $env $noenvflags" 94 95 set t [$env txn] 96 error_check_good txn_begin [is_valid_txn $t $env] TRUE 97 98 set ret [catch {eval {berkdb_open} -txn $t $oflags} db] 99 error_check_good txn_commit [$t commit] 0 100 101 set t [$env txn] 102 error_check_good txn_begin [is_valid_txn $t $env] TRUE 103 104 # 105 # The command to execute to create an extent is a put. 106 # We are just creating the first one, so our extnum is 0. 107 # 108 set extnum 0 109 set data [chop_data $method [replicate $alphabet 512]] 110 puts "\t\tExecuting command" 111 set putrecno [$db put -txn $t -append $data] 112 error_check_good db_put $putrecno 1 113 114 # Sync the db so any changes to the file that are 115 # in mpool get written to the disk file before the 116 # diff. 117 puts "\t\tSyncing" 118 error_check_good db_sync [$db sync] 0 119 120 catch { file copy -force $dir/$dbfile $dir/$dbfile.afterop } res 121 copy_extent_file $dir $dbfile afterop 122 123 error_check_good txn_$txncmd:$t [$t $txncmd] 0 124 # 125 # If we don't abort, then we expect success. 126 # If we abort, we expect no file created. 127 # 128 set dbq [make_ext_filename $dir $dbfile $extnum] 129 error_check_good extput:exists1 [file exists $dbq] 1 130 set ret [$db get $putrecno] 131 if {$txncmd == "abort"} { 132 # 133 # Operation was aborted. Verify our entry is not there. 134 # 135 puts "\t\tCommand executed and aborted." 136 error_check_good db_get [llength $ret] 0 137 } else { 138 # 139 # Operation was committed, verify it exists. 140 # 141 puts "\t\tCommand executed and committed." 142 error_check_good db_get [llength $ret] 1 143 catch { file copy -force $dir/$dbfile $init_file } res 144 copy_extent_file $dir $dbfile init 145 } 146 set t [$env txn] 147 error_check_good txn_begin [is_valid_txn $t $env] TRUE 148 error_check_good db_close [$db close] 0 149 error_check_good txn_commit [$t commit] 0 150 error_check_good env_close [$env close] 0 151 152 # 153 # Run recovery here. Should be a no-op. Verify that 154 # the file still does/n't exist when we are done. 155 # 156 berkdb debug_check 157 puts -nonewline "\t\tAbout to run recovery (no-op) ... " 158 flush stdout 159 160 set stat [catch {exec $util_path/db_recover -h $dir -c} result] 161 if { $stat == 1 } { 162 error "FAIL: Recovery error: $result." 163 return 164 } 165 puts "complete" 166 # 167 # Verify it did not change. 168 # 169 error_check_good extput:exists2 [file exists $dbq] 1 170 ext_create_check $dir $txncmd $init_file $dbfile $noenvflags $putrecno 171 172 # 173 # Need a new copy to get the right LSN into the file. 174 # 175 catch { file copy -force $dir/$dbfile $init_file } res 176 copy_extent_file $dir $dbfile init 177 178 # 179 # Undo. 180 # Now move the .afterop file to $dbfile. Run recovery again. 181 # 182 file copy -force $dir/$dbfile.afterop $dir/$dbfile 183 move_file_extent $dir $dbfile afterop copy 184 185 berkdb debug_check 186 puts -nonewline "\t\tAbout to run recovery (afterop) ... " 187 flush stdout 188 189 set stat [catch {exec $util_path/db_recover -h $dir -c} result] 190 if { $stat == 1 } { 191 error "FAIL: Recovery error: $result." 192 return 193 } 194 puts "complete" 195 ext_create_check $dir $txncmd $init_file $dbfile $noenvflags $putrecno 196 197 # 198 # To redo, remove the dbfiles. Run recovery again. 199 # 200 catch { file rename -force $dir/$dbfile $dir/$dbfile.renamed } res 201 copy_extent_file $dir $dbfile renamed rename 202 203 berkdb debug_check 204 puts -nonewline "\t\tAbout to run recovery (init) ... " 205 flush stdout 206 207 set stat [catch {exec $util_path/db_recover -h $dir -c} result] 208 # 209 # !!! 210 # Even though db_recover exits with status 0, it should print out 211 # a warning because the file didn't exist. Db_recover writes this 212 # to stderr. Tcl assumes that ANYTHING written to stderr is an 213 # error, so even though we exit with 0 status, we still get an 214 # error back from 'catch'. Look for the warning. 215 # 216 if { $stat == 1 && [is_substr $result "warning"] == 0 } { 217 error "FAIL: Recovery error: $result." 218 return 219 } 220 puts "complete" 221 222 # 223 # Verify it was redone. However, since we removed the files 224 # to begin with, recovery with abort will not recreate the 225 # extent. Recovery with commit will. 226 # 227 if {$txncmd == "abort"} { 228 error_check_good extput:exists3 [file exists $dbq] 0 229 } else { 230 error_check_good extput:exists3 [file exists $dbq] 1 231 } 232} 233 234proc ext_create_check { dir txncmd init_file dbfile oflags putrecno } { 235 if { $txncmd == "commit" } { 236 # 237 # Operation was committed. Verify it did not change. 238 # 239 error_check_good \ 240 diff(initial,post-recover2):diff($init_file,$dir/$dbfile) \ 241 [dbdump_diff "-dar" $init_file $dir $dbfile] 0 242 } else { 243 # 244 # Operation aborted. The file is there, but make 245 # sure the item is not. 246 # 247 set xdb [eval {berkdb_open} $oflags] 248 error_check_good db_open [is_valid_db $xdb] TRUE 249 set ret [$xdb get $putrecno] 250 error_check_good db_get [llength $ret] 0 251 error_check_good db_close [$xdb close] 0 252 } 253} 254 255proc ext_recover_consume { dir env_cmd method opts dbfile txncmd} { 256 global log_log_record_types 257 global alphabet 258 source ./include.tcl 259 260 # Keep track of the log types we've seen 261 if { $log_log_record_types == 1} { 262 logtrack_read $dir 263 } 264 265 env_cleanup $dir 266 # Open the environment and set the copy/abort locations 267 set env [eval $env_cmd] 268 269 set oflags "-create -auto_commit $method -mode 0644 -pagesize 512 \ 270 -env $env $opts $dbfile" 271 272 # 273 # Open our db, add some data, close and copy as our 274 # init file. 275 # 276 set db [eval {berkdb_open} $oflags] 277 error_check_good db_open [is_valid_db $db] TRUE 278 279 set extnum 0 280 set data [chop_data $method [replicate $alphabet 512]] 281 282 set txn [$env txn] 283 error_check_good txn_begin [is_valid_txn $txn $env] TRUE 284 set putrecno [$db put -txn $txn -append $data] 285 error_check_good db_put $putrecno 1 286 error_check_good commit [$txn commit] 0 287 error_check_good db_close [$db close] 0 288 289 puts "\t\tExecuting command" 290 291 set init_file $dir/$dbfile.init 292 catch { file copy -force $dir/$dbfile $init_file } res 293 copy_extent_file $dir $dbfile init 294 295 # 296 # If we don't abort, then we expect success. 297 # If we abort, we expect no file removed until recovery is run. 298 # 299 set db [eval {berkdb_open} $oflags] 300 error_check_good db_open [is_valid_db $db] TRUE 301 302 set t [$env txn] 303 error_check_good txn_begin [is_valid_txn $t $env] TRUE 304 305 set dbcmd "$db get -txn $t -consume" 306 set ret [eval $dbcmd] 307 error_check_good db_sync [$db sync] 0 308 309 catch { file copy -force $dir/$dbfile $dir/$dbfile.afterop } res 310 copy_extent_file $dir $dbfile afterop 311 312 error_check_good txn_$txncmd:$t [$t $txncmd] 0 313 error_check_good db_sync [$db sync] 0 314 set dbq [make_ext_filename $dir $dbfile $extnum] 315 if {$txncmd == "abort"} { 316 # 317 # Operation was aborted, verify ext did not change. 318 # 319 puts "\t\tCommand executed and aborted." 320 321 # 322 # Check that the file exists. Final state. 323 # Since we aborted the txn, we should be able 324 # to get to our original entry. 325 # 326 error_check_good postconsume.1 [file exists $dbq] 1 327 error_check_good \ 328 diff(init,postconsume.2):diff($init_file,$dir/$dbfile)\ 329 [dbdump_diff "-dar" $init_file $dir $dbfile] 0 330 } else { 331 # 332 # Operation was committed, verify it does 333 # not exist. 334 # 335 puts "\t\tCommand executed and committed." 336 # 337 # Check file existence. Consume operations remove 338 # the extent when we move off, which we should have 339 # done. 340 error_check_good consume_exists [file exists $dbq] 0 341 } 342 error_check_good db_close [$db close] 0 343 error_check_good env_close [$env close] 0 344 345 # 346 # Run recovery here on what we ended up with. Should be a no-op. 347 # 348 berkdb debug_check 349 puts -nonewline "\t\tAbout to run recovery (no-op) ... " 350 flush stdout 351 352 set stat [catch {exec $util_path/db_recover -h $dir -c} result] 353 if { $stat == 1 } { 354 error "FAIL: Recovery error: $result." 355 return 356 } 357 puts "complete" 358 if { $txncmd == "abort"} { 359 # 360 # Operation was aborted, verify it did not change. 361 # 362 error_check_good \ 363 diff(initial,post-recover1):diff($init_file,$dir/$dbfile) \ 364 [dbdump_diff "-dar" $init_file $dir $dbfile] 0 365 } else { 366 # 367 # Operation was committed, verify it does 368 # not exist. Both operations should result 369 # in no file existing now that we've run recovery. 370 # 371 error_check_good after_recover1 [file exists $dbq] 0 372 } 373 374 # 375 # Run recovery here. Re-do the operation. 376 # Verify that the file doesn't exist 377 # (if we committed) or change (if we aborted) 378 # when we are done. 379 # 380 catch { file copy -force $dir/$dbfile $init_file } res 381 copy_extent_file $dir $dbfile init 382 berkdb debug_check 383 puts -nonewline "\t\tAbout to run recovery (init) ... " 384 flush stdout 385 386 set stat [catch {exec $util_path/db_recover -h $dir -c} result] 387 if { $stat == 1 } { 388 error "FAIL: Recovery error: $result." 389 return 390 } 391 puts "complete" 392 if { $txncmd == "abort"} { 393 # 394 # Operation was aborted, verify it did not change. 395 # 396 error_check_good \ 397 diff(initial,post-recover1):diff($init_file,$dir/$dbfile) \ 398 [dbdump_diff "-dar" $init_file $dir $dbfile] 0 399 } else { 400 # 401 # Operation was committed, verify it does 402 # not exist. Both operations should result 403 # in no file existing now that we've run recovery. 404 # 405 error_check_good after_recover2 [file exists $dbq] 0 406 } 407 408 # 409 # Now move the .afterop file to $dbfile. Run recovery again. 410 # 411 set filecopy [glob $dir/*.afterop] 412 set afterop [lindex $filecopy 0] 413 file rename -force $afterop $dir/$dbfile 414 set afterop [string range $afterop \ 415 [expr [string last "/" $afterop] + 1] \ 416 [string last "." $afterop]] 417 move_file_extent $dir $dbfile afterop rename 418 419 berkdb debug_check 420 puts -nonewline "\t\tAbout to run recovery (afterop) ... " 421 flush stdout 422 423 set stat [catch {exec $util_path/db_recover -h $dir -c} result] 424 if { $stat == 1 } { 425 error "FAIL: Recovery error: $result." 426 return 427 } 428 puts "complete" 429 430 if { $txncmd == "abort"} { 431 # 432 # Operation was aborted, verify it did not change. 433 # 434 error_check_good \ 435 diff(initial,post-recover2):diff($init_file,$dir/$dbfile) \ 436 [dbdump_diff "-dar" $init_file $dir $dbfile] 0 437 } else { 438 # 439 # Operation was committed, verify it still does 440 # not exist. 441 # 442 error_check_good after_recover3 [file exists $dbq] 0 443 } 444} 445