1# See the file LICENSE for redistribution information. 2# 3# Copyright (c) 2004,2008 Oracle. All rights reserved. 4# 5# $Id: recd021.tcl,v 12.7 2008/01/08 20:58:53 bostic Exp $ 6# 7# TEST recd021 8# TEST Test of failed opens in recovery. 9# TEST 10# TEST If a file was deleted through the file system (and not 11# TEST within Berkeley DB), an error message should appear. 12# TEST Test for regular files and subdbs. 13 14proc recd021 { method args } { 15 source ./include.tcl 16 global util_path 17 18 set args [convert_args $method $args] 19 set omethod [convert_method $method] 20 set nentries 100 21 22 puts "\nRecd021: ($method)\ 23 Test failed opens in recovery." 24 25 # The file ops "remove" and "rename" are done within 26 # Berkeley DB. A "delete" is done directly on the file 27 # system (as if the user deleted the file). 28 # 29 # First test regular files. 30 # 31 foreach op { remove rename delete noop } { 32 env_cleanup $testdir 33 puts "\tRecd021: Test $op of file in recovery." 34 35 # Create transactional environment. 36 set env [berkdb_env -create -home $testdir -txn] 37 error_check_good is_valid_env [is_valid_env $env] TRUE 38 39 # Create database 40 puts "\t\tRecd021.a.1: Create and populate file." 41 42 if { $op == "rename" } { 43 set names {A B} 44 } else { 45 set names {A} 46 } 47 set name [lindex $names 0] 48 49 set db [eval {berkdb_open \ 50 -create} $omethod $args -env $env -auto_commit $name.db] 51 error_check_good dba_open [is_valid_db $db] TRUE 52 53 # Checkpoint. 54 error_check_good txn_checkpoint [$env txn_checkpoint] 0 55 for { set i 1 } { $i <= $nentries } { incr i } { 56 error_check_good dba_put [$db put $i data$i] 0 57 } 58 error_check_good dba_close [$db close] 0 59 60 # Do operation on file. 61 puts "\t\tRecd021.b: Do $op on file." 62 set txn [$env txn] 63 set ret [do_op $omethod $op $names $txn $env] 64 error_check_good do_op $ret 0 65 error_check_good txn_commit [$txn commit] 0 66 error_check_good env_close [$env close] 0 67 68 # Recover. 69 puts "\t\tRecd021.c: Recover." 70 set ret [catch {exec $util_path/db_recover -h $testdir} r] 71 if { $op == "delete" } { 72 error_check_good external_delete \ 73 [is_substr $r "Warning: open failed"] 1 74 } else { 75 error_check_good $op $ret 0 76 } 77 78 # Clean up. 79 error_check_good \ 80 env_remove [berkdb envremove -force -home $testdir] 0 81 fileremove -f $testdir/$name.db 82 } 83 84 # Test subdbs. 85 if { [is_queue $method] == 1 } { 86 puts "Recd021: Skipping test of subdbs for method $method." 87 return 88 } 89 90 # The first subdb test just does the op, and is comparable 91 # to the tests for regular files above. 92 set trunc 0 93 set special {} 94 foreach op { remove rename delete noop } { 95 recd021_testsubdb $method $op $nentries $special $trunc $args 96 } 97 98 # The remainder of the tests are executed first with the log intact, 99 # then with the log truncated at the __db_subdb_name record. 100 foreach trunc { 0 1 } { 101 # Test what happens if subdb2 reuses pages formerly in 102 # subdb1, after removing subdb1. 103 set special "reuse" 104 recd021_testsubdb $method remove $nentries $special $trunc $args 105 106 # Test what happens if a new subdb reuses pages formerly 107 # in subdb1, after removing subdb1. 108 set special "newdb" 109 recd021_testsubdb $method remove $nentries $special $trunc $args 110 111 # Now we test what happens if a new subdb if a different access 112 # method reuses pages formerly in subdb1, after removing subdb1. 113 set special "newtypedb" 114 recd021_testsubdb $method remove $nentries $special $trunc $args 115 } 116} 117 118proc recd021_testsubdb { method op nentries special trunc largs } { 119 source ./include.tcl 120 global util_path 121 122 set omethod [convert_method $method] 123 env_cleanup $testdir 124 125 puts "\tRecd021: \ 126 Test $op of subdb in recovery ($special trunc = $trunc)." 127 128 # Create transactional environment. 129 set env [berkdb_env -create -home $testdir -txn] 130 error_check_good is_valid_env [is_valid_env $env] TRUE 131 132 # Create database with 2 subdbs 133 puts "\t\tRecd021.d: Create and populate subdbs." 134 set sname1 S1 135 set sname2 S2 136 if { $op == "rename" } { 137 set names {A S1 NEW_S1} 138 } elseif { $op == "delete" } { 139 set names {A} 140 } else { 141 set names {A S1} 142 } 143 set name [lindex $names 0] 144 145 set sdb1 [eval {berkdb_open -create} $omethod \ 146 $largs -env $env -auto_commit $name.db $sname1] 147 error_check_good sdb1_open [is_valid_db $sdb1] TRUE 148 set sdb2 [eval {berkdb_open -create} $omethod \ 149 $largs -env $env -auto_commit $name.db $sname2] 150 error_check_good sdb2_open [is_valid_db $sdb2] TRUE 151 152 # Checkpoint. 153 error_check_good txn_checkpoint [$env txn_checkpoint] 0 154 for { set i 1 } { $i <= $nentries } { incr i } { 155 error_check_good sdb1_put [$sdb1 put $i data$i] 0 156 } 157 set dumpfile dump.s1.$trunc 158 set ret [exec $util_path/db_dump -dar -f $dumpfile -h $testdir A.db] 159 for { set i 1 } { $i <= $nentries } { incr i } { 160 error_check_good sdb2_put [$sdb2 put $i data$i] 0 161 } 162 error_check_good sdb1_close [$sdb1 close] 0 163 164 # Do operation on subdb. 165 puts "\t\tRecd021.e: Do $op on file." 166 set txn [$env txn] 167 168 if { $trunc == 1 } { 169 # Create a log cursor to mark where we are before 170 # doing the op. 171 set logc [$env log_cursor] 172 set ret [lindex [$logc get -last] 0] 173 file copy -force $testdir/log.0000000001 $testdir/log.sav 174 } 175 176 set ret [do_subdb_op $omethod $op $names $txn $env] 177 error_check_good do_subdb_op $ret 0 178 error_check_good txn_commit [$txn commit] 0 179 180 if { $trunc == 1 } { 181 # Walk the log and find the __db_subdb_name entry. 182 set found 0 183 while { $found == 0 } { 184 set lsn [lindex [$logc get -next] 0] 185 set lfile [lindex $lsn 0] 186 set loff [lindex $lsn 1] 187 set logrec [exec $util_path/db_printlog -h $testdir \ 188 -b $lfile/$loff -e $lfile/$loff] 189 if { [is_substr $logrec __db_subdb_name] == 1 } { 190 set found 1 191 } 192 } 193 # Create the truncated log, and save it for later. 194 catch [exec dd if=$testdir/log.0000000001 \ 195 of=$testdir/log.sav count=$loff bs=1 >& /dev/null ] res 196 } 197 198 # Here we do the "special" thing, if any. We always 199 # have to close sdb2, but when we do so varies. 200 switch -exact -- $special { 201 "" { 202 error_check_good sdb2_close [$sdb2 close] 0 203 } 204 reuse { 205 for { set i [expr $nentries + 1] } \ 206 { $i <= [expr $nentries * 2]} { incr i } { 207 error_check_good sdb2_put \ 208 [$sdb2 put $i data$i] 0 209 } 210 error_check_good sdb2_close [$sdb2 close] 0 211 set dumpfile dump.s2.$trunc 212 set ret [exec $util_path/db_dump -dar \ 213 -f $dumpfile -h $testdir A.db] 214 } 215 newdb { 216 error_check_good sdb2_close [$sdb2 close] 0 217 set sname3 S3 218 set sdb3 [eval {berkdb_open -create} $omethod \ 219 $largs -env $env -auto_commit $name.db $sname3] 220 error_check_good sdb3_open [is_valid_db $sdb3] TRUE 221 for { set i 1 } { $i <= $nentries } { incr i } { 222 error_check_good sdb3_put \ 223 [$sdb3 put $i data$i] 0 224 } 225 error_check_good sdb3_close [$sdb3 close] 0 226 } 227 newtypedb { 228 error_check_good sdb2_close [$sdb2 close] 0 229 set sname4 S4 230 set newmethod [different_method $method] 231 set args [convert_args $newmethod] 232 set omethod [convert_method $newmethod] 233 set sdb4 [eval {berkdb_open -create} $omethod \ 234 $args -env $env -auto_commit $name.db $sname4] 235 error_check_good sdb4_open [is_valid_db $sdb4] TRUE 236 for { set i 1 } { $i <= $nentries } { incr i } { 237 error_check_good sdb4_put \ 238 [$sdb4 put $i data$i] 0 239 } 240 error_check_good sdb4_close [$sdb4 close] 0 241 } 242 } 243 244 # Close the env. 245 error_check_good env_close [$env close] 0 246 247 if { $trunc == 1 } { 248 # Swap in the truncated log. 249 file rename -force $testdir/log.sav $testdir/log.0000000001 250 } 251 252 # Recover. 253 puts "\t\tRecd021.f: Recover." 254 set ret [catch {exec $util_path/db_recover -h $testdir} r] 255 if { $op == "delete" || $trunc == 1 && $special != "newdb" } { 256 error_check_good expect_warning \ 257 [is_substr $r "Warning: open failed"] 1 258 } else { 259 error_check_good subdb_$op $ret 0 260 } 261 262 # Clean up. 263 error_check_good env_remove [berkdb envremove -force -home $testdir] 0 264 fileremove -f $testdir/$name.db 265} 266 267proc different_method { method } { 268 # Queue methods are omitted, since this is for subdb testing. 269 set methodlist { -btree -rbtree -recno -frecno -rrecno -hash } 270 271 set method [convert_method $method] 272 set newmethod $method 273 while { $newmethod == $method } { 274 set index [berkdb random_int 0 [expr [llength $methodlist] - 1]] 275 set newmethod [lindex $methodlist $index] 276 } 277 return $newmethod 278} 279