1# See the file LICENSE for redistribution information. 2# 3# Copyright (c) 1999,2008 Oracle. All rights reserved. 4# 5# $Id: test096.tcl,v 12.10 2008/01/08 20:58:53 bostic Exp $ 6# 7# TEST test096 8# TEST Db->truncate test. 9# TEST For all methods: 10# TEST Test that truncate empties an existing database. 11# TEST Test that truncate-write in an aborted txn doesn't 12# TEST change the original contents. 13# TEST Test that truncate-write in a committed txn does 14# TEST overwrite the original contents. 15# TEST For btree and hash, do the same in a database with offpage dups. 16proc test096 { method {pagesize 512} {nentries 1000} {ndups 19} args} { 17 global fixed_len 18 global alphabet 19 source ./include.tcl 20 21 set orig_tdir $testdir 22 set orig_fixed_len $fixed_len 23 set args [convert_args $method $args] 24 set encargs "" 25 set args [split_encargs $args encargs] 26 set omethod [convert_method $method] 27 28 puts "Test096: $method db truncate method test" 29 set pgindex [lsearch -exact $args "-pagesize"] 30 if { $pgindex != -1 } { 31 puts "Test096: Skipping for specific pagesizes" 32 return 33 } 34 35 # Create the database and open the dictionary 36 set eindex [lsearch -exact $args "-env"] 37 set testfile test096.db 38 if { $eindex != -1 } { 39 incr eindex 40 set env [lindex $args $eindex] 41 set txnenv [is_txnenv $env] 42 if { $txnenv == 0 } { 43 puts "Environment w/o txns specified; skipping." 44 return 45 } 46 if { $nentries == 1000 } { 47 set nentries 100 48 } 49 reduce_dups nentries ndups 50 set testdir [get_home $env] 51 set closeenv 0 52 } else { 53 env_cleanup $testdir 54 55 # We need an env for exclusive-use testing. Since we are 56 # using txns, we need at least 1 lock per record for queue. 57 set lockmax [expr $nentries * 2] 58 set env [eval {berkdb_env -create -home $testdir \ 59 -lock_max_locks $lockmax -lock_max_objects $lockmax -txn} $encargs] 60 error_check_good env_create [is_valid_env $env] TRUE 61 set closeenv 1 62 } 63 64 set t1 $testdir/t1 65 66 puts "\tTest096.a: Create database with $nentries entries" 67 set db [eval {berkdb_open -create -auto_commit \ 68 -env $env $omethod -mode 0644} $args $testfile] 69 error_check_good db_open [is_valid_db $db] TRUE 70 t96_populate $db $omethod $env $nentries 71 error_check_good dbclose [$db close] 0 72 73 puts "\tTest096.b: Truncate database" 74 set dbtr [eval {berkdb_open -create -auto_commit \ 75 -env $env $omethod -mode 0644} $args $testfile] 76 error_check_good db_open [is_valid_db $dbtr] TRUE 77 78 set ret [$dbtr truncate] 79 error_check_good dbtrunc $ret $nentries 80 error_check_good db_close [$dbtr close] 0 81 82 set db [eval {berkdb_open -env $env} $args $testfile] 83 error_check_good dbopen [is_valid_db $db] TRUE 84 set number [number_of_entries $db $method] 85 error_check_good number_of_entries $number 0 86 error_check_good dbclose [$db close] 0 87 error_check_good dbverify [verify_dir $testdir "\tTest096.c: "] 0 88 89 # Remove and recreate database. 90 puts "\tTest096.d: Recreate database with $nentries entries" 91 set db [eval {berkdb_open -create -auto_commit \ 92 -env $env $omethod -mode 0644} $args $testfile] 93 error_check_good db_open [is_valid_db $db] TRUE 94 t96_populate $db $omethod $env $nentries 95 error_check_good dbclose [$db close] 0 96 97 puts "\tTest096.e: Truncate and write in a txn, then abort" 98 txn_truncate $env $omethod $testfile $nentries abort 1 99 100 set db [eval {berkdb_open -env $env} $args $testfile] 101 error_check_good dbopen [is_valid_db $db] TRUE 102 103 # Database should have original contents since both the truncate 104 # and the write were aborted 105 set number [number_of_entries $db $method] 106 error_check_good number_of_entries $number $nentries 107 error_check_good dbclose [$db close] 0 108 109 error_check_good dbverify [verify_dir $testdir "\tTest096.f: "] 0 110 111 puts "\tTest096.g: Truncate and write in a txn, then commit" 112 txn_truncate $env $omethod $testfile $nentries commit 1 113 114 set db [eval {berkdb_open -env $env} $args $testfile] 115 error_check_good dbopen [is_valid_db $db] TRUE 116 117 # Database should contain only the new items 118 set number [number_of_entries $db $method] 119 error_check_good number_of_entries $number [expr $nentries / 2] 120 error_check_good dbclose [$db close] 0 121 error_check_good dbverify [verify_dir $testdir "\tTest096.h: "] 0 122 123 puts "\tTest096.i: Check proper handling of overflow pages." 124 # Large keys and data compared to page size guarantee 125 # overflow pages. 126 if { [is_fixed_length $method] == 1 } { 127 puts "Skipping overflow test for fixed-length method." 128 } else { 129 set overflowfile overflow096.db 130 set data [repeat $alphabet 600] 131 set db [eval {berkdb_open -create -auto_commit -pagesize 512 \ 132 -env $env $omethod -mode 0644} $args $overflowfile] 133 error_check_good db_open [is_valid_db $db] TRUE 134 135 set noverflows 100 136 for { set i 1 } { $i <= $noverflows } { incr i } { 137 set ret [eval {$db put} \ 138 $i [chop_data $method "$i$data"]] 139 } 140 141 set stat [$db stat] 142 error_check_bad stat:overflow [is_substr $stat \ 143 "{{Overflow pages} 0}"] 1 144 145 error_check_good overflow_truncate [$db truncate] $noverflows 146 error_check_good overflow_close [$db close] 0 147 } 148 149 # Remove database and create a new one with dups. Skip 150 # the rest of the test for methods not supporting dups. 151 if { [is_record_based $method] == 1 || \ 152 [is_rbtree $method] == 1 } { 153 puts "Skipping remainder of test096 for method $method" 154 if { $closeenv == 1 } { 155 error_check_good envclose [$env close] 0 156 } 157 return 158 } 159 set ret [berkdb dbremove -env $env -auto_commit $testfile] 160 set ret [berkdb dbremove -env $env -auto_commit $overflowfile] 161 162 puts "\tTest096.j: Create $nentries entries with $ndups duplicates" 163 set db [eval {berkdb_open -pagesize $pagesize -dup -auto_commit \ 164 -create -env $env $omethod -mode 0644} $args $testfile] 165 error_check_good db_open [is_valid_db $db] TRUE 166 167 t96_populate $db $omethod $env $nentries $ndups 168 169 set dlist "" 170 for { set i 1 } {$i <= $ndups} {incr i} { 171 lappend dlist $i 172 } 173 set t [$env txn] 174 error_check_good txn [is_valid_txn $t $env] TRUE 175 set txn "-txn $t" 176 dup_check $db $txn $t1 $dlist 177 error_check_good txn [$t commit] 0 178 puts "\tTest096.k: Verify off page duplicates status" 179 set stat [$db stat] 180 error_check_bad stat:offpage [is_substr $stat \ 181 "{{Duplicate pages} 0}"] 1 182 183 set recs [expr $ndups * $nentries] 184 error_check_good dbclose [$db close] 0 185 186 puts "\tTest096.l: Truncate database in a txn then abort" 187 txn_truncate $env $omethod $testfile $recs abort 188 189 set db [eval {berkdb_open -auto_commit -env $env} $args $testfile] 190 error_check_good dbopen [is_valid_db $db] TRUE 191 192 set number [number_of_entries $db $method] 193 error_check_good number_of_entries $number $recs 194 error_check_good dbclose [$db close] 0 195 196 puts "\tTest096.m: Truncate database in a txn then commit" 197 txn_truncate $env $omethod $testfile $recs commit 198 199 set db [berkdb_open -auto_commit -env $env $testfile] 200 error_check_good dbopen [is_valid_db $db] TRUE 201 set number [number_of_entries $db $method] 202 error_check_good number_of_entries $number 0 203 error_check_good dbclose [$db close] 0 204 205 set testdir [get_home $env] 206 error_check_good dbverify [verify_dir $testdir "\tTest096.n: "] 0 207 208 # Remove database, and create a new one with dups. Test 209 # truncate + write within a transaction. 210 puts "\tTest096.o: Create $nentries entries with $ndups duplicates" 211 set ret [berkdb dbremove -env $env -auto_commit $testfile] 212 set db [eval {berkdb_open -pagesize $pagesize -dup -auto_commit \ 213 -create -env $env $omethod -mode 0644} $args $testfile] 214 error_check_good db_open [is_valid_db $db] TRUE 215 216 t96_populate $db $omethod $env $nentries $ndups 217 218 set dlist "" 219 for { set i 1 } {$i <= $ndups} {incr i} { 220 lappend dlist $i 221 } 222 set t [$env txn] 223 error_check_good txn [is_valid_txn $t $env] TRUE 224 set txn "-txn $t" 225 dup_check $db $txn $t1 $dlist 226 error_check_good txn [$t commit] 0 227 puts "\tTest096.p: Verify off page duplicates status" 228 set stat [$db stat] 229 error_check_bad stat:offpage [is_substr $stat \ 230 "{{Duplicate pages} 0}"] 1 231 232 set recs [expr $ndups * $nentries] 233 error_check_good dbclose [$db close] 0 234 235 puts "\tTest096.q: Truncate and write in a txn, then abort" 236 txn_truncate $env $omethod $testfile $recs abort 1 237 238 set db [eval {berkdb_open -auto_commit -env $env} $args $testfile] 239 error_check_good dbopen [is_valid_db $db] TRUE 240 set number [number_of_entries $db $method] 241 error_check_good number_of_entries $number $recs 242 error_check_good dbclose [$db close] 0 243 244 puts "\tTest096.r: Truncate and write in a txn, then commit" 245 txn_truncate $env $omethod $testfile $recs commit 1 246 247 set db [berkdb_open -auto_commit -env $env $testfile] 248 error_check_good dbopen [is_valid_db $db] TRUE 249 set number [number_of_entries $db $method] 250 error_check_good number_of_entries $number [expr $recs / 2] 251 error_check_good dbclose [$db close] 0 252 253 puts "\tTest096.s: Check overflow pages with dups." 254 set ndups 3 255 set db [eval {berkdb_open -create -auto_commit -pagesize 512 \ 256 -env $env $omethod -dup -mode 0644} $args $overflowfile] 257 error_check_good db_open [is_valid_db $db] TRUE 258 259 for { set i 1 } { $i <= $noverflows } { incr i } { 260 for { set j 0 } { $j < $ndups } { incr j } { 261 set ret [eval {$db put} \ 262 $i [chop_data $method "$i.$j$data"]] 263 } 264 } 265 266 set stat [$db stat] 267 error_check_bad stat:overflow [is_substr $stat \ 268 "{{Overflow pages} 0}"] 1 269 270 set nentries [expr $noverflows * $ndups] 271 error_check_good overflow_truncate [$db truncate] $nentries 272 error_check_good overflow_close [$db close] 0 273 274 set testdir [get_home $env] 275 error_check_good dbverify [verify_dir $testdir "\tTest096.t: "] 0 276 277 if { $closeenv == 1 } { 278 error_check_good envclose [$env close] 0 279 } 280 set testdir $orig_tdir 281} 282 283proc t96_populate {db method env nentries {ndups 1}} { 284 source ./include.tcl 285 286 set did [open $dict] 287 set count 0 288 set txn "" 289 set pflags "" 290 set gflags "" 291 292 if { [is_record_based $method] == 1 } { 293 append gflags "-recno" 294 } 295 while { [gets $did str] != -1 && $count < $nentries } { 296 if { [is_record_based $method] == 1 } { 297 set key [expr $count + 1] 298 } else { 299 set key $str 300 } 301 if { $ndups > 1 } { 302 for { set i 1 } { $i <= $ndups } { incr i } { 303 set datastr $i:$str 304 set t [$env txn] 305 error_check_good txn [is_valid_txn $t $env] TRUE 306 set txn "-txn $t" 307 set ret [eval {$db put} $txn $pflags \ 308 {$key [chop_data $method $datastr]}] 309 error_check_good put $ret 0 310 error_check_good txn [$t commit] 0 311 } 312 } else { 313 set datastr [reverse $str] 314 set t [$env txn] 315 error_check_good txn [is_valid_txn $t $env] TRUE 316 set txn "-txn $t" 317 set ret [eval {$db put} \ 318 $txn $pflags {$key [chop_data $method $datastr]}] 319 error_check_good put $ret 0 320 error_check_good txn [$t commit] 0 321 } 322 set ret [eval {$db get} $gflags {$key}] 323 error_check_good $key:dbget [llength $ret] $ndups 324 incr count 325 } 326 close $did 327} 328 329proc number_of_entries { db method } { 330 if { [is_record_based $method] == 1 } { 331 set dbc [$db cursor] 332 set last [$dbc get -last] 333 if {[llength $last] == 0} { 334 set number 0 335 } else { 336 set number [lindex [lindex $last 0] 0] 337 } 338 } else { 339 set ret [$db get -glob *] 340 set number [llength $ret] 341 } 342 return $number 343} 344 345# Open database. Truncate in a transaction, optionally with a write 346# included in the transaction as well, then abort or commit. Close database. 347 348proc txn_truncate { env method testfile nentries op {write 0}} { 349 set db [eval {berkdb_open -create -auto_commit \ 350 -env $env $method -mode 0644} $testfile] 351 error_check_good db_open [is_valid_db $db] TRUE 352 353 set txn [$env txn] 354 error_check_good txnbegin [is_valid_txn $txn $env] TRUE 355 356 set ret [$db truncate -txn $txn] 357 error_check_good dbtrunc $ret $nentries 358 if { $write == 1 } { 359 for {set i 1} {$i <= [expr $nentries / 2]} {incr i} { 360 set ret [eval {$db put} -txn $txn \ 361 {$i [chop_data $method "aaaaaaaaaa"]}] 362 error_check_good write $ret 0 363 } 364 } 365 366 error_check_good txn$op [$txn $op] 0 367 error_check_good db_close [$db close] 0 368} 369 370