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